Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / dom / base / nsGlobalWindow.cpp
blob6414f272bf0752436a7985894ba86db66614f735
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 "nsJSEnvironment.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 "nsDesktopNotification.h"
82 #include "nsContentCID.h"
83 #include "nsLayoutStatics.h"
84 #include "nsCycleCollector.h"
85 #include "nsCCUncollectableMarker.h"
86 #include "nsDOMThreadService.h"
87 #include "nsAutoJSValHolder.h"
89 // Interfaces Needed
90 #include "nsIFrame.h"
91 #include "nsCanvasFrame.h"
92 #include "nsIWidget.h"
93 #include "nsIBaseWindow.h"
94 #include "nsAccelerometer.h"
95 #include "nsIContent.h"
96 #include "nsIContentViewerEdit.h"
97 #include "nsIDocShell.h"
98 #include "nsIDocShellLoadInfo.h"
99 #include "nsIDocShellTreeItem.h"
100 #include "nsIDocShellTreeNode.h"
101 #include "nsIEditorDocShell.h"
102 #include "nsIDocCharset.h"
103 #include "nsIDocument.h"
104 #include "nsIHTMLDocument.h"
105 #include "nsIDOMHTMLDocument.h"
106 #include "nsIDOMHTMLElement.h"
107 #ifndef MOZ_DISABLE_DOMCRYPTO
108 #include "nsIDOMCrypto.h"
109 #endif
110 #include "nsIDOMDocument.h"
111 #include "nsIDOM3Document.h"
112 #include "nsIDOMNSDocument.h"
113 #include "nsIDOMDocumentView.h"
114 #include "nsIDOMElement.h"
115 #include "nsIDOMDocumentEvent.h"
116 #include "nsIDOMEvent.h"
117 #include "nsIDOMHTMLAnchorElement.h"
118 #include "nsIDOMKeyEvent.h"
119 #include "nsIDOMMessageEvent.h"
120 #include "nsIDOMPopupBlockedEvent.h"
121 #include "nsIDOMPopStateEvent.h"
122 #include "nsIDOMPopStateEvent_MOZILLA_2_BRANCH.h"
123 #include "nsIDOMOfflineResourceList.h"
124 #include "nsIDOMGeoGeolocation.h"
125 #include "nsIDOMDesktopNotification.h"
126 #include "nsPIDOMStorage.h"
127 #include "nsDOMString.h"
128 #include "nsIEmbeddingSiteWindow2.h"
129 #include "nsThreadUtils.h"
130 #include "nsIEventStateManager.h"
131 #include "nsIHttpProtocolHandler.h"
132 #include "nsIJSContextStack.h"
133 #include "nsIJSRuntimeService.h"
134 #include "nsIMarkupDocumentViewer.h"
135 #include "nsIPrefBranch.h"
136 #include "nsIPresShell.h"
137 #include "nsIPrivateDOMEvent.h"
138 #include "nsIProgrammingLanguage.h"
139 #include "nsIServiceManager.h"
140 #include "nsIScriptGlobalObjectOwner.h"
141 #include "nsIScriptSecurityManager.h"
142 #include "nsIScrollableFrame.h"
143 #include "nsIView.h"
144 #include "nsIViewManager.h"
145 #include "nsISelectionController.h"
146 #include "nsISelection.h"
147 #include "nsIPrompt.h"
148 #include "nsIPromptService.h"
149 #include "nsIPromptFactory.h"
150 #include "nsIWritablePropertyBag2.h"
151 #include "nsIWebNavigation.h"
152 #include "nsIWebBrowser.h"
153 #include "nsIWebBrowserChrome.h"
154 #include "nsIWebBrowserFind.h" // For window.find()
155 #include "nsIWebContentHandlerRegistrar.h"
156 #include "nsIWindowMediator.h" // For window.find()
157 #include "nsComputedDOMStyle.h"
158 #include "nsIEntropyCollector.h"
159 #include "nsDOMCID.h"
160 #include "nsDOMError.h"
161 #include "nsDOMWindowUtils.h"
162 #include "nsIWindowWatcher.h"
163 #include "nsPIWindowWatcher.h"
164 #include "nsIContentViewer.h"
165 #include "nsDOMClassInfo.h"
166 #include "nsIJSNativeInitializer.h"
167 #include "nsIScriptError.h"
168 #include "nsIScriptEventManager.h" // For GetInterface()
169 #include "nsIConsoleService.h"
170 #include "nsIControllers.h"
171 #include "nsIControllerContext.h"
172 #include "nsGlobalWindowCommands.h"
173 #include "nsAutoPtr.h"
174 #include "nsContentUtils.h"
175 #include "nsCSSProps.h"
176 #include "nsFileDataProtocolHandler.h"
177 #include "nsIDOMFile.h"
178 #include "nsIURIFixup.h"
179 #include "mozilla/FunctionTimer.h"
180 #include "nsCDefaultURIFixup.h"
181 #include "nsEventDispatcher.h"
182 #include "nsIObserverService.h"
183 #include "nsIXULAppInfo.h"
184 #include "nsNetUtil.h"
185 #include "nsFocusManager.h"
186 #include "nsIXULWindow.h"
187 #include "nsEventStateManager.h"
188 #ifdef MOZ_XUL
189 #include "nsXULPopupManager.h"
190 #include "nsIDOMXULControlElement.h"
191 #include "nsIFrame.h"
192 #endif
194 #include "xpcprivate.h"
196 #ifdef NS_PRINTING
197 #include "nsIPrintSettings.h"
198 #include "nsIPrintSettingsService.h"
199 #include "nsIWebBrowserPrint.h"
200 #endif
202 #include "nsWindowRoot.h"
203 #include "nsNetCID.h"
204 #include "nsIArray.h"
205 #include "nsIScriptRuntime.h"
207 // XXX An unfortunate dependency exists here (two XUL files).
208 #include "nsIDOMXULDocument.h"
209 #include "nsIDOMXULCommandDispatcher.h"
211 #include "nsBindingManager.h"
212 #include "nsIXBLService.h"
214 // used for popup blocking, needs to be converted to something
215 // belonging to the back-end like nsIContentPolicy
216 #include "nsIPopupWindowManager.h"
218 #include "nsIDragService.h"
219 #include "mozilla/dom/Element.h"
220 #include "nsFrameLoader.h"
221 #include "nsISupportsPrimitives.h"
222 #include "nsXPCOMCID.h"
224 #include "mozilla/FunctionTimer.h"
225 #include "mozIThirdPartyUtil.h"
227 #ifdef MOZ_LOGGING
228 // so we can get logging even in release builds
229 #define FORCE_PR_LOG 1
230 #endif
231 #include "prlog.h"
233 #include "mozilla/dom/indexedDB/IDBFactory.h"
234 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
236 #include "nsRefreshDriver.h"
238 #ifdef PR_LOGGING
239 static PRLogModuleInfo* gDOMLeakPRLog;
240 #endif
242 static const char kStorageEnabled[] = "dom.storage.enabled";
244 using namespace mozilla::dom;
245 using mozilla::TimeStamp;
246 using mozilla::TimeDuration;
248 nsIDOMStorageList *nsGlobalWindow::sGlobalStorageList = nsnull;
249 nsGlobalWindow::WindowByIdTable *nsGlobalWindow::sOuterWindowsById = nsnull;
251 static nsIEntropyCollector *gEntropyCollector = nsnull;
252 static PRInt32 gRefCnt = 0;
253 static PRInt32 gOpenPopupSpamCount = 0;
254 static PopupControlState gPopupControlState = openAbused;
255 static PRInt32 gRunningTimeoutDepth = 0;
256 static PRPackedBool gMouseDown = PR_FALSE;
257 static PRPackedBool gDragServiceDisabled = PR_FALSE;
258 static FILE *gDumpFile = nsnull;
259 static PRUint64 gNextWindowID = 0;
260 static PRUint32 gSerialCounter = 0;
262 #ifdef DEBUG_jst
263 PRInt32 gTimeoutCnt = 0;
264 #endif
266 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
267 static PRBool gDOMWindowDumpEnabled = PR_FALSE;
268 #endif
270 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
271 #define DEBUG_PAGE_CACHE
272 #endif
274 // The default shortest interval/timeout we permit
275 #define DEFAULT_MIN_TIMEOUT_VALUE 10 // 10ms
276 static PRInt32 gMinTimeoutValue;
277 static inline PRInt32 DOMMinTimeoutValue() {
278 return NS_MAX(gMinTimeoutValue, 0);
281 // The number of nested timeouts before we start clamping. HTML5 says 1, WebKit
282 // uses 5.
283 #define DOM_CLAMP_TIMEOUT_NESTING_LEVEL 5
285 // The longest interval (as PRIntervalTime) we permit, or that our
286 // timer code can handle, really. See DELAY_INTERVAL_LIMIT in
287 // nsTimerImpl.h for details.
288 #define DOM_MAX_TIMEOUT_VALUE PR_BIT(8 * sizeof(PRIntervalTime) - 1)
290 #define FORWARD_TO_OUTER(method, args, err_rval) \
291 PR_BEGIN_MACRO \
292 if (IsInnerWindow()) { \
293 nsGlobalWindow *outer = GetOuterWindowInternal(); \
294 if (!outer) { \
295 NS_WARNING("No outer window available!"); \
296 return err_rval; \
298 return outer->method args; \
300 PR_END_MACRO
302 #define FORWARD_TO_OUTER_VOID(method, args) \
303 PR_BEGIN_MACRO \
304 if (IsInnerWindow()) { \
305 nsGlobalWindow *outer = GetOuterWindowInternal(); \
306 if (!outer) { \
307 NS_WARNING("No outer window available!"); \
308 return; \
310 outer->method args; \
311 return; \
313 PR_END_MACRO
315 #define FORWARD_TO_OUTER_CHROME(method, args, err_rval) \
316 PR_BEGIN_MACRO \
317 if (IsInnerWindow()) { \
318 nsGlobalWindow *outer = GetOuterWindowInternal(); \
319 if (!outer) { \
320 NS_WARNING("No outer window available!"); \
321 return err_rval; \
323 return ((nsGlobalChromeWindow *)outer)->method args; \
325 PR_END_MACRO
327 #define FORWARD_TO_INNER_CHROME(method, args, err_rval) \
328 PR_BEGIN_MACRO \
329 if (IsOuterWindow()) { \
330 if (!mInnerWindow) { \
331 NS_WARNING("No inner window available!"); \
332 return err_rval; \
334 return ((nsGlobalChromeWindow *)mInnerWindow)->method args; \
336 PR_END_MACRO
338 #define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
339 PR_BEGIN_MACRO \
340 if (IsInnerWindow()) { \
341 nsGlobalWindow *outer = GetOuterWindowInternal(); \
342 if (!outer) { \
343 NS_WARNING("No outer window available!"); \
344 return err_rval; \
346 return ((nsGlobalModalWindow *)outer)->method args; \
348 PR_END_MACRO
350 #define FORWARD_TO_INNER(method, args, err_rval) \
351 PR_BEGIN_MACRO \
352 if (IsOuterWindow()) { \
353 if (!mInnerWindow) { \
354 NS_WARNING("No inner window available!"); \
355 return err_rval; \
357 return GetCurrentInnerWindowInternal()->method args; \
359 PR_END_MACRO
361 #define FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
362 PR_BEGIN_MACRO \
363 if (IsOuterWindow()) { \
364 if (!mInnerWindow) { \
365 NS_WARNING("No inner window available!"); \
366 return err_rval; \
368 return ((nsGlobalModalWindow*)GetCurrentInnerWindowInternal())->method args; \
370 PR_END_MACRO
372 #define FORWARD_TO_INNER_VOID(method, args) \
373 PR_BEGIN_MACRO \
374 if (IsOuterWindow()) { \
375 if (!mInnerWindow) { \
376 NS_WARNING("No inner window available!"); \
377 return; \
379 GetCurrentInnerWindowInternal()->method args; \
380 return; \
382 PR_END_MACRO
384 // Same as FORWARD_TO_INNER, but this will create a fresh inner if an
385 // inner doesn't already exists.
386 #define FORWARD_TO_INNER_CREATE(method, args, err_rval) \
387 PR_BEGIN_MACRO \
388 if (IsOuterWindow()) { \
389 if (!mInnerWindow) { \
390 if (mIsClosed) { \
391 return err_rval; \
393 nsCOMPtr<nsIDOMDocument> doc; \
394 nsresult fwdic_nr = GetDocument(getter_AddRefs(doc)); \
395 NS_ENSURE_SUCCESS(fwdic_nr, err_rval); \
396 if (!mInnerWindow) { \
397 return err_rval; \
400 return GetCurrentInnerWindowInternal()->method args; \
402 PR_END_MACRO
404 // CIDs
405 static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
407 static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
408 #ifndef MOZ_DISABLE_DOMCRYPTO
409 static const char kCryptoContractID[] = NS_CRYPTO_CONTRACTID;
410 static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID;
411 #endif
412 static const char sPopStatePrefStr[] = "browser.history.allowPopState";
414 static PRBool
415 IsAboutBlank(nsIURI* aURI)
417 NS_PRECONDITION(aURI, "Must have URI");
419 // GetSpec can be expensive for some URIs, so check the scheme first.
420 PRBool isAbout = PR_FALSE;
421 if (NS_FAILED(aURI->SchemeIs("about", &isAbout)) || !isAbout) {
422 return PR_FALSE;
425 nsCAutoString str;
426 aURI->GetSpec(str);
427 return str.EqualsLiteral("about:blank");
430 class nsDummyJavaPluginOwner : public nsIPluginInstanceOwner
432 public:
433 nsDummyJavaPluginOwner(nsIDocument *aDocument)
434 : mDocument(aDocument)
438 void Destroy();
440 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
441 NS_DECL_NSIPLUGININSTANCEOWNER
443 NS_IMETHOD GetURL(const char *aURL, const char *aTarget,
444 nsIInputStream *aPostStream,
445 void *aHeadersData, PRUint32 aHeadersDataLen);
446 NS_IMETHOD ShowStatus(const PRUnichar *aStatusMsg);
447 NPError ShowNativeContextMenu(NPMenu* menu, void* event);
448 NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
449 double *destX, double *destY, NPCoordinateSpace destSpace);
450 void SendIdleEvent();
452 NS_DECL_CYCLE_COLLECTION_CLASS(nsDummyJavaPluginOwner)
454 private:
455 nsCOMPtr<nsIPluginInstance> mInstance;
456 nsCOMPtr<nsIDocument> mDocument;
459 NS_IMPL_CYCLE_COLLECTION_2(nsDummyJavaPluginOwner, mDocument, mInstance)
461 // QueryInterface implementation for nsDummyJavaPluginOwner
462 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDummyJavaPluginOwner)
463 NS_INTERFACE_MAP_ENTRY(nsISupports)
464 NS_INTERFACE_MAP_ENTRY(nsIPluginInstanceOwner)
465 NS_INTERFACE_MAP_END
467 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDummyJavaPluginOwner)
468 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDummyJavaPluginOwner)
471 void
472 nsDummyJavaPluginOwner::Destroy()
474 // If we have a plugin instance, stop it and destroy it now.
475 if (mInstance) {
476 mInstance->Stop();
477 mInstance->InvalidateOwner();
478 mInstance = nsnull;
481 mDocument = nsnull;
484 NS_IMETHODIMP
485 nsDummyJavaPluginOwner::SetInstance(nsIPluginInstance *aInstance)
487 // If we're going to null out mInstance after use, be sure to call
488 // mInstance->InvalidateOwner() here, since it now won't be called
489 // from nsDummyJavaPluginOwner::Destroy().
490 if (mInstance && !aInstance)
491 mInstance->InvalidateOwner();
493 mInstance = aInstance;
495 return NS_OK;
498 NS_IMETHODIMP
499 nsDummyJavaPluginOwner::GetInstance(nsIPluginInstance *&aInstance)
501 NS_IF_ADDREF(aInstance = mInstance);
503 return NS_OK;
506 NS_IMETHODIMP
507 nsDummyJavaPluginOwner::GetWindow(NPWindow *&aWindow)
509 aWindow = nsnull;
511 return NS_OK;
514 NS_IMETHODIMP
515 nsDummyJavaPluginOwner::GetMode(PRInt32 *aMode)
517 // This is wrong, but there's no better alternative.
518 *aMode = NP_EMBED;
520 return NS_ERROR_NOT_IMPLEMENTED;
523 NS_IMETHODIMP
524 nsDummyJavaPluginOwner::CreateWidget(void)
526 return NS_ERROR_NOT_IMPLEMENTED;
529 NS_IMETHODIMP
530 nsDummyJavaPluginOwner::GetURL(const char *aURL, const char *aTarget,
531 nsIInputStream *aPostStream,
532 void *aHeadersData, PRUint32 aHeadersDataLen)
534 return NS_ERROR_NOT_IMPLEMENTED;
537 NS_IMETHODIMP
538 nsDummyJavaPluginOwner::ShowStatus(const char *aStatusMsg)
540 return NS_ERROR_NOT_IMPLEMENTED;
543 NS_IMETHODIMP
544 nsDummyJavaPluginOwner::ShowStatus(const PRUnichar *aStatusMsg)
546 return NS_ERROR_NOT_IMPLEMENTED;
549 NPError
550 nsDummyJavaPluginOwner::ShowNativeContextMenu(NPMenu* menu, void* event)
552 return NPERR_GENERIC_ERROR;
555 NPBool
556 nsDummyJavaPluginOwner::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
557 double *destX, double *destY, NPCoordinateSpace destSpace)
559 return PR_FALSE;
562 NS_IMETHODIMP
563 nsDummyJavaPluginOwner::GetDocument(nsIDocument **aDocument)
565 NS_IF_ADDREF(*aDocument = mDocument);
567 return NS_OK;
570 NS_IMETHODIMP
571 nsDummyJavaPluginOwner::InvalidateRect(NPRect *invalidRect)
573 return NS_ERROR_NOT_IMPLEMENTED;
576 NS_IMETHODIMP
577 nsDummyJavaPluginOwner::InvalidateRegion(NPRegion invalidRegion)
579 return NS_ERROR_NOT_IMPLEMENTED;
582 NS_IMETHODIMP
583 nsDummyJavaPluginOwner::ForceRedraw()
585 return NS_ERROR_NOT_IMPLEMENTED;
588 NS_IMETHODIMP
589 nsDummyJavaPluginOwner::GetNetscapeWindow(void *value)
591 return NS_ERROR_NOT_IMPLEMENTED;
594 NS_IMETHODIMP
595 nsDummyJavaPluginOwner::SetEventModel(PRInt32 eventModel)
597 return NS_ERROR_NOT_IMPLEMENTED;
600 void
601 nsDummyJavaPluginOwner::SendIdleEvent()
606 * An object implementing the window.URL property.
608 class nsDOMMozURLProperty : public nsIDOMMozURLProperty
610 public:
611 nsDOMMozURLProperty(nsGlobalWindow* aWindow)
612 : mWindow(aWindow)
616 NS_DECL_ISUPPORTS
617 NS_DECL_NSIDOMMOZURLPROPERTY
619 void ClearWindowReference() {
620 mWindow = nsnull;
622 private:
623 nsGlobalWindow* mWindow;
626 DOMCI_DATA(MozURLProperty, nsDOMMozURLProperty)
627 NS_IMPL_ADDREF(nsDOMMozURLProperty)
628 NS_IMPL_RELEASE(nsDOMMozURLProperty)
629 NS_INTERFACE_MAP_BEGIN(nsDOMMozURLProperty)
630 NS_INTERFACE_MAP_ENTRY(nsIDOMMozURLProperty)
631 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozURLProperty)
632 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozURLProperty)
633 NS_INTERFACE_MAP_END
635 NS_IMETHODIMP
636 nsDOMMozURLProperty::CreateObjectURL(nsIDOMBlob* aBlob, nsAString& aURL)
638 NS_PRECONDITION(!mWindow || mWindow->IsInnerWindow(),
639 "Should be inner window");
641 NS_ENSURE_STATE(mWindow && mWindow->mDoc);
642 NS_ENSURE_ARG_POINTER(aBlob);
644 nsIDocument* doc = mWindow->mDoc;
646 nsresult rv = aBlob->GetInternalUrl(doc->NodePrincipal(), aURL);
647 NS_ENSURE_SUCCESS(rv, rv);
649 doc->RegisterFileDataUri(NS_LossyConvertUTF16toASCII(aURL));
651 return NS_OK;
654 NS_IMETHODIMP
655 nsDOMMozURLProperty::RevokeObjectURL(const nsAString& aURL)
657 NS_PRECONDITION(!mWindow || mWindow->IsInnerWindow(),
658 "Should be inner window");
660 NS_ENSURE_STATE(mWindow);
662 NS_LossyConvertUTF16toASCII asciiurl(aURL);
664 nsIPrincipal* winPrincipal = mWindow->GetPrincipal();
665 if (!winPrincipal) {
666 return NS_OK;
669 nsIPrincipal* principal =
670 nsFileDataProtocolHandler::GetFileDataEntryPrincipal(asciiurl);
671 PRBool subsumes;
672 if (principal && winPrincipal &&
673 NS_SUCCEEDED(winPrincipal->Subsumes(principal, &subsumes)) &&
674 subsumes) {
675 if (mWindow->mDoc) {
676 mWindow->mDoc->UnregisterFileDataUri(asciiurl);
678 nsFileDataProtocolHandler::RemoveFileDataEntry(asciiurl);
681 return NS_OK;
685 * An indirect observer object that means we don't have to implement nsIObserver
686 * on nsGlobalWindow, where any script could see it.
688 class nsGlobalWindowObserver : public nsIObserver {
689 public:
690 nsGlobalWindowObserver(nsGlobalWindow* aWindow) : mWindow(aWindow) {}
691 NS_DECL_ISUPPORTS
692 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aData)
694 if (!mWindow)
695 return NS_OK;
696 return mWindow->Observe(aSubject, aTopic, aData);
698 void Forget() { mWindow = nsnull; }
699 private:
700 nsGlobalWindow* mWindow;
703 NS_IMPL_ISUPPORTS1(nsGlobalWindowObserver, nsIObserver)
705 nsTimeout::nsTimeout()
707 #ifdef DEBUG_jst
709 extern int gTimeoutCnt;
711 ++gTimeoutCnt;
713 #endif
715 memset(this, 0, sizeof(*this));
717 MOZ_COUNT_CTOR(nsTimeout);
720 nsTimeout::~nsTimeout()
722 #ifdef DEBUG_jst
724 extern int gTimeoutCnt;
726 --gTimeoutCnt;
728 #endif
730 MOZ_COUNT_DTOR(nsTimeout);
733 NS_IMPL_CYCLE_COLLECTION_CLASS(nsTimeout)
734 NS_IMPL_CYCLE_COLLECTION_UNLINK_NATIVE_0(nsTimeout)
735 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsTimeout)
736 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mWindow,
737 nsIScriptGlobalObject)
738 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrincipal)
739 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptHandler)
740 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
741 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout, AddRef)
742 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTimeout, Release)
744 nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
745 : mFrameElement(nsnull), mDocShell(nsnull), mModalStateDepth(0),
746 mRunningTimeout(nsnull), mMutationBits(0), mIsDocumentLoaded(PR_FALSE),
747 mIsHandlingResizeEvent(PR_FALSE), mIsInnerWindow(aOuterWindow != nsnull),
748 mMayHavePaintEventListener(PR_FALSE), mMayHaveTouchEventListener(PR_FALSE),
749 mMayHaveAudioAvailableEventListener(PR_FALSE), mIsModalContentWindow(PR_FALSE),
750 mIsActive(PR_FALSE), mInnerWindow(nsnull), mOuterWindow(aOuterWindow),
751 // Make sure no actual window ends up with mWindowID == 0
752 mWindowID(++gNextWindowID), mHasNotifiedGlobalCreated(PR_FALSE)
755 nsPIDOMWindow::~nsPIDOMWindow() {}
757 //*****************************************************************************
758 // nsOuterWindowProxy: Outer Window Proxy
759 //*****************************************************************************
761 JSString *
762 nsOuterWindowProxy::obj_toString(JSContext *cx, JSObject *proxy)
764 JS_ASSERT(proxy->isProxy());
766 return JS_NewStringCopyZ(cx, "[object Window]");
769 nsOuterWindowProxy
770 nsOuterWindowProxy::singleton;
772 JSObject *
773 NS_NewOuterWindowProxy(JSContext *cx, JSObject *parent)
775 JSAutoEnterCompartment ac;
776 if (!ac.enter(cx, parent)) {
777 return nsnull;
780 JSObject *obj = JSWrapper::New(cx, parent, parent->getProto(), parent,
781 &nsOuterWindowProxy::singleton);
782 NS_ASSERTION(obj->getClass()->ext.innerObject, "bad class");
783 return obj;
786 //*****************************************************************************
787 //*** nsGlobalWindow: Object Management
788 //*****************************************************************************
790 nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
791 : nsPIDOMWindow(aOuterWindow),
792 mIsFrozen(PR_FALSE),
793 mDidInitJavaProperties(PR_FALSE),
794 mFullScreen(PR_FALSE),
795 mIsClosed(PR_FALSE),
796 mInClose(PR_FALSE),
797 mHavePendingClose(PR_FALSE),
798 mHadOriginalOpener(PR_FALSE),
799 mIsPopupSpam(PR_FALSE),
800 mBlockScriptedClosingFlag(PR_FALSE),
801 mFireOfflineStatusChangeEventOnThaw(PR_FALSE),
802 mCreatingInnerWindow(PR_FALSE),
803 mIsChrome(PR_FALSE),
804 mCleanMessageManager(PR_FALSE),
805 mNeedsFocus(PR_TRUE),
806 mHasFocus(PR_FALSE),
807 #if defined(XP_MAC) || defined(XP_MACOSX)
808 mShowAccelerators(PR_FALSE),
809 mShowFocusRings(PR_FALSE),
810 #else
811 mShowAccelerators(PR_TRUE),
812 mShowFocusRings(PR_TRUE),
813 #endif
814 mShowFocusRingForContent(PR_FALSE),
815 mFocusByKeyOccurred(PR_FALSE),
816 mHasAcceleration(PR_FALSE),
817 mNotifiedIDDestroyed(PR_FALSE),
818 mTimeoutInsertionPoint(nsnull),
819 mTimeoutPublicIdCounter(1),
820 mTimeoutFiringDepth(0),
821 mJSObject(nsnull),
822 mPendingStorageEventsObsolete(nsnull),
823 mTimeoutsSuspendDepth(0),
824 mFocusMethod(0),
825 mSerial(0),
826 #ifdef DEBUG
827 mSetOpenerWindowCalled(PR_FALSE),
828 #endif
829 mCleanedUp(PR_FALSE),
830 mCallCleanUpAfterModalDialogCloses(PR_FALSE),
831 mDialogAbuseCount(0),
832 mDialogDisabled(PR_FALSE)
834 nsLayoutStatics::AddRef();
836 // Initialize the PRCList (this).
837 PR_INIT_CLIST(this);
839 // Initialize timeout storage
840 PR_INIT_CLIST(&mTimeouts);
842 if (aOuterWindow) {
843 // |this| is an inner window, add this inner window to the outer
844 // window list of inners.
845 PR_INSERT_AFTER(this, aOuterWindow);
847 mObserver = new nsGlobalWindowObserver(this);
848 if (mObserver) {
849 NS_ADDREF(mObserver);
850 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
851 if (os) {
852 // Watch for online/offline status changes so we can fire events. Use
853 // a strong reference.
854 os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
855 PR_FALSE);
857 // Watch for dom-storage-changed so we can fire storage
858 // events. Use a strong reference.
859 os->AddObserver(mObserver, "dom-storage2-changed", PR_FALSE);
860 os->AddObserver(mObserver, "dom-storage-changed", PR_FALSE);
863 } else {
864 // |this| is an outer window. Outer windows start out frozen and
865 // remain frozen until they get an inner window, so freeze this
866 // outer window here.
867 Freeze();
869 mObserver = nsnull;
870 SetIsProxy();
872 if (!sOuterWindowsById) {
873 sOuterWindowsById = new WindowByIdTable();
874 if (!sOuterWindowsById->Init()) {
875 delete sOuterWindowsById;
876 sOuterWindowsById = nsnull;
880 if (sOuterWindowsById) {
881 sOuterWindowsById->Put(mWindowID, this);
885 // We could have failed the first time through trying
886 // to create the entropy collector, so we should
887 // try to get one until we succeed.
889 gRefCnt++;
891 if (gRefCnt == 1) {
892 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
893 nsContentUtils::AddBoolPrefVarCache("browser.dom.window.dump.enabled",
894 &gDOMWindowDumpEnabled);
895 #endif
896 nsContentUtils::AddIntPrefVarCache("dom.min_timeout_value",
897 &gMinTimeoutValue,
898 DEFAULT_MIN_TIMEOUT_VALUE);
901 if (gDumpFile == nsnull) {
902 const nsAdoptingCString& fname =
903 nsContentUtils::GetCharPref("browser.dom.window.dump.file");
904 if (!fname.IsEmpty()) {
905 // if this fails to open, Dump() knows to just go to stdout
906 // on null.
907 gDumpFile = fopen(fname, "wb+");
908 } else {
909 gDumpFile = stdout;
913 if (!gEntropyCollector) {
914 CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
917 mSerial = ++gSerialCounter;
919 #ifdef DEBUG
920 printf("++DOMWINDOW == %d (%p) [serial = %d] [outer = %p]\n", gRefCnt,
921 static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
922 gSerialCounter, static_cast<void*>(aOuterWindow));
923 #endif
925 #ifdef PR_LOGGING
926 if (!gDOMLeakPRLog)
927 gDOMLeakPRLog = PR_NewLogModule("DOMLeak");
929 if (gDOMLeakPRLog)
930 PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
931 ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
932 #endif
935 nsGlobalWindow::~nsGlobalWindow()
937 if (sOuterWindowsById) {
938 sOuterWindowsById->Remove(mWindowID);
940 if (!--gRefCnt) {
941 NS_IF_RELEASE(gEntropyCollector);
942 delete sOuterWindowsById;
943 sOuterWindowsById = nsnull;
945 #ifdef DEBUG
946 nsCAutoString url;
947 if (mLastOpenedURI) {
948 mLastOpenedURI->GetSpec(url);
951 printf("--DOMWINDOW == %d (%p) [serial = %d] [outer = %p] [url = %s]\n",
952 gRefCnt, static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
953 mSerial, static_cast<void*>(mOuterWindow.get()), url.get());
954 #endif
956 #ifdef PR_LOGGING
957 if (gDOMLeakPRLog)
958 PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
959 ("DOMWINDOW %p destroyed", this));
960 #endif
962 if (IsOuterWindow()) {
963 // An outer window is destroyed with inner windows still possibly
964 // alive, iterate through the inner windows and null out their
965 // back pointer to this outer, and pull them out of the list of
966 // inner windows.
968 nsGlobalWindow *w;
969 while ((w = (nsGlobalWindow *)PR_LIST_HEAD(this)) != this) {
970 PR_REMOVE_AND_INIT_LINK(w);
972 } else {
973 if (mListenerManager) {
974 mListenerManager->Disconnect();
975 mListenerManager = nsnull;
978 // An inner window is destroyed, pull it out of the outer window's
979 // list if inner windows.
981 PR_REMOVE_LINK(this);
983 // If our outer window's inner window is this window, null out the
984 // outer window's reference to this window that's being deleted.
985 nsGlobalWindow *outer = GetOuterWindowInternal();
986 if (outer && outer->mInnerWindow == this) {
987 outer->mInnerWindow = nsnull;
991 mDocument = nsnull; // Forces Release
992 mDoc = nsnull;
994 NS_ASSERTION(!mArguments, "mArguments wasn't cleaned up properly!");
996 CleanUp(PR_TRUE);
998 #ifdef DEBUG
999 nsCycleCollector_DEBUG_wasFreed(static_cast<nsIScriptGlobalObject*>(this));
1000 #endif
1002 if (mURLProperty) {
1003 mURLProperty->ClearWindowReference();
1006 nsLayoutStatics::Release();
1009 // static
1010 void
1011 nsGlobalWindow::ShutDown()
1013 NS_IF_RELEASE(sGlobalStorageList);
1015 if (gDumpFile && gDumpFile != stdout) {
1016 fclose(gDumpFile);
1018 gDumpFile = nsnull;
1021 // static
1022 void
1023 nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow)
1025 if (aWindow->mCachedXBLPrototypeHandlers.IsInitialized() &&
1026 aWindow->mCachedXBLPrototypeHandlers.Count() > 0) {
1027 aWindow->mCachedXBLPrototypeHandlers.Clear();
1029 nsISupports* supports;
1030 aWindow->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
1031 reinterpret_cast<void**>(&supports));
1032 NS_ASSERTION(supports, "Failed to QI to nsCycleCollectionISupports?!");
1034 nsContentUtils::DropJSObjects(supports);
1038 void
1039 nsGlobalWindow::MaybeForgiveSpamCount()
1041 if (IsOuterWindow() &&
1042 IsPopupSpamWindow())
1044 SetPopupSpamWindow(PR_FALSE);
1045 --gOpenPopupSpamCount;
1046 NS_ASSERTION(gOpenPopupSpamCount >= 0,
1047 "Unbalanced decrement of gOpenPopupSpamCount");
1051 void
1052 nsGlobalWindow::CleanUp(PRBool aIgnoreModalDialog)
1054 if (IsOuterWindow() && !aIgnoreModalDialog) {
1055 nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
1056 nsCOMPtr<nsIDOMModalContentWindow>
1057 dlg(do_QueryInterface(static_cast<nsPIDOMWindow*>(inner)));
1058 if (dlg) {
1059 // The window we're trying to clean up is the outer window of a
1060 // modal dialog. Defer cleanup until the window closes, and let
1061 // ShowModalDialog take care of calling CleanUp.
1062 mCallCleanUpAfterModalDialogCloses = PR_TRUE;
1063 return;
1067 // Guarantee idempotence.
1068 if (mCleanedUp)
1069 return;
1070 mCleanedUp = PR_TRUE;
1072 if (mObserver) {
1073 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1074 if (os) {
1075 os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
1076 os->RemoveObserver(mObserver, "dom-storage2-changed");
1077 os->RemoveObserver(mObserver, "dom-storage-changed");
1080 // Drop its reference to this dying window, in case for some bogus reason
1081 // the object stays around.
1082 mObserver->Forget();
1083 NS_RELEASE(mObserver);
1086 mNavigator = nsnull;
1087 mScreen = nsnull;
1088 mMenubar = nsnull;
1089 mToolbar = nsnull;
1090 mLocationbar = nsnull;
1091 mPersonalbar = nsnull;
1092 mStatusbar = nsnull;
1093 mScrollbars = nsnull;
1094 mLocation = nsnull;
1095 mHistory = nsnull;
1096 mFrames = nsnull;
1097 mApplicationCache = nsnull;
1098 mIndexedDB = nsnull;
1099 mPendingStorageEventsObsolete = nsnull;
1102 ClearControllers();
1104 mOpener = nsnull; // Forces Release
1105 if (mContext) {
1106 #ifdef DEBUG
1107 nsCycleCollector_DEBUG_shouldBeFreed(mContext);
1108 #endif
1109 mContext = nsnull; // Forces Release
1111 mChromeEventHandler = nsnull; // Forces Release
1112 mParentTarget = nsnull;
1114 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
1116 if (inner) {
1117 inner->CleanUp(aIgnoreModalDialog);
1120 DisableAccelerationUpdates();
1121 mHasAcceleration = PR_FALSE;
1123 if (mCleanMessageManager) {
1124 NS_ABORT_IF_FALSE(mIsChrome, "only chrome should have msg manager cleaned");
1125 nsGlobalChromeWindow *asChrome = static_cast<nsGlobalChromeWindow*>(this);
1126 if (asChrome->mMessageManager) {
1127 static_cast<nsFrameMessageManager*>(
1128 asChrome->mMessageManager.get())->Disconnect();
1132 mInnerWindowHolder = nsnull;
1133 mArguments = nsnull;
1134 mArgumentsLast = nsnull;
1135 mArgumentsOrigin = nsnull;
1137 CleanupCachedXBLHandlers(this);
1139 #ifdef DEBUG
1140 nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
1141 #endif
1144 void
1145 nsGlobalWindow::ClearControllers()
1147 if (mControllers) {
1148 PRUint32 count;
1149 mControllers->GetControllerCount(&count);
1151 while (count--) {
1152 nsCOMPtr<nsIController> controller;
1153 mControllers->GetControllerAt(count, getter_AddRefs(controller));
1155 nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
1156 if (context)
1157 context->SetCommandContext(nsnull);
1160 mControllers = nsnull;
1164 // static
1165 void
1166 nsGlobalWindow::TryClearWindowScope(nsISupports *aWindow)
1168 nsGlobalWindow *window =
1169 static_cast<nsGlobalWindow *>(static_cast<nsIDOMWindow*>(aWindow));
1171 // This termination function might be called when any script evaluation in our
1172 // context terminated, even if there are other scripts in the stack. Thus, we
1173 // have to check again if a script is executing and post a new termination
1174 // function if necessary.
1175 window->ClearScopeWhenAllScriptsStop();
1178 void
1179 nsGlobalWindow::ClearScopeWhenAllScriptsStop()
1181 NS_ASSERTION(IsInnerWindow(), "Must be an inner window");
1183 // We cannot clear scope safely until all the scripts in our script context
1184 // stopped. This might be a long wait, for example if one script is busy
1185 // because it started a nested event loop for a modal dialog.
1186 nsIScriptContext *jsscx = GetContextInternal();
1187 if (jsscx && jsscx->GetExecutingScript()) {
1188 // We ignore the return value because the only reason that we clear scope
1189 // here is to try to prevent leaks. Failing to clear scope might mean that
1190 // we'll leak more but if we don't have enough memory to allocate a
1191 // termination function we probably don't have to worry about this anyway.
1192 jsscx->SetTerminationFunction(TryClearWindowScope,
1193 static_cast<nsIDOMWindow *>(this));
1194 return;
1197 NotifyWindowIDDestroyed("inner-window-destroyed");
1198 nsIScriptContext *scx = GetContextInternal();
1199 if (scx) {
1200 scx->ClearScope(mJSObject, PR_TRUE);
1204 void
1205 nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
1207 NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
1209 // Kill all of the workers for this window.
1210 nsDOMThreadService* dts = nsDOMThreadService::get();
1211 if (dts) {
1212 nsIScriptContext *scx = GetContextInternal();
1214 JSContext *cx = scx ? (JSContext *)scx->GetNativeContext() : nsnull;
1216 // Have to suspend this request here because CancelWorkersForGlobal will
1217 // lock until the worker has died and that could cause a deadlock.
1218 JSAutoSuspendRequest asr(cx);
1220 dts->CancelWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
1223 // Close all IndexedDB databases for this window.
1224 indexedDB::IndexedDatabaseManager* idbManager =
1225 indexedDB::IndexedDatabaseManager::Get();
1226 if (idbManager) {
1227 idbManager->AbortCloseDatabasesForWindow(this);
1230 ClearAllTimeouts();
1232 mChromeEventHandler = nsnull;
1234 if (mListenerManager) {
1235 mListenerManager->Disconnect();
1236 mListenerManager = nsnull;
1239 mLocation = nsnull;
1240 mHistory = nsnull;
1242 if (mDocument) {
1243 NS_ASSERTION(mDoc, "Why is mDoc null?");
1245 // Remember the document's principal.
1246 mDocumentPrincipal = mDoc->NodePrincipal();
1249 #ifdef DEBUG
1250 if (mDocument)
1251 nsCycleCollector_DEBUG_shouldBeFreed(nsCOMPtr<nsISupports>(do_QueryInterface(mDocument)));
1252 #endif
1254 // Make sure that this is called before we null out the document.
1255 NotifyDOMWindowDestroyed(this);
1257 // Remove our reference to the document and the document principal.
1258 mDocument = nsnull;
1259 mDoc = nsnull;
1261 if (mApplicationCache) {
1262 static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
1263 mApplicationCache = nsnull;
1266 mIndexedDB = nsnull;
1268 if (aClearScope) {
1269 ClearScopeWhenAllScriptsStop();
1272 if (mDummyJavaPluginOwner) {
1273 // Tear down the dummy java plugin.
1275 // XXXjst: On a general note, should windows with java stuff in
1276 // them ever even make it into the fast-back cache?
1278 mDummyJavaPluginOwner->Destroy();
1280 mDummyJavaPluginOwner = nsnull;
1283 CleanupCachedXBLHandlers(this);
1285 #ifdef DEBUG
1286 nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
1287 #endif
1290 //*****************************************************************************
1291 // nsGlobalWindow::nsISupports
1292 //*****************************************************************************
1294 #define OUTER_WINDOW_ONLY \
1295 if (IsOuterWindow()) {
1297 #define END_OUTER_WINDOW_ONLY \
1298 foundInterface = 0; \
1299 } else
1301 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
1303 DOMCI_DATA(Window, nsGlobalWindow)
1305 // QueryInterface implementation for nsGlobalWindow
1306 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
1307 // Make sure this matches the cast in nsGlobalWindow::FromWrapper()
1308 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptGlobalObject)
1309 NS_INTERFACE_MAP_ENTRY(nsIDOMWindowInternal)
1310 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
1311 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow2)
1312 NS_INTERFACE_MAP_ENTRY(nsIDOMJSWindow)
1313 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
1314 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
1315 NS_INTERFACE_MAP_ENTRY(nsPIDOMEventTarget)
1316 NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
1317 NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
1318 NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
1319 NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow)
1320 NS_INTERFACE_MAP_ENTRY(nsIDOMViewCSS)
1321 NS_INTERFACE_MAP_ENTRY(nsIDOMAbstractView)
1322 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageWindow)
1323 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageIndexedDB)
1324 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
1325 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
1326 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow_2_0_BRANCH)
1327 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
1328 OUTER_WINDOW_ONLY
1329 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1330 END_OUTER_WINDOW_ONLY
1331 NS_INTERFACE_MAP_END
1334 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsGlobalWindow, nsIScriptGlobalObject)
1335 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsGlobalWindow,
1336 nsIScriptGlobalObject)
1339 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGlobalWindow)
1340 if (tmp->mDoc && nsCCUncollectableMarker::InGeneration(
1341 cb, tmp->mDoc->GetMarkedCCGeneration())) {
1342 return NS_SUCCESS_INTERRUPTED_TRAVERSE;
1345 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
1347 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mControllers)
1348 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArguments)
1349 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArgumentsLast)
1351 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInnerWindowHolder)
1352 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOuterWindow)
1354 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOpenerScriptPrincipal)
1355 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mListenerManager)
1357 for (nsTimeout* timeout = tmp->FirstTimeout();
1358 tmp->IsTimeout(timeout);
1359 timeout = timeout->Next()) {
1360 cb.NoteNativeChild(timeout, &NS_CYCLE_COLLECTION_NAME(nsTimeout));
1363 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSessionStorage)
1364 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mApplicationCache)
1365 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocumentPrincipal)
1366 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDoc)
1368 // Traverse stuff from nsPIDOMWindow
1369 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChromeEventHandler)
1370 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParentTarget)
1371 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
1372 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFrameElement)
1374 // Traverse mDummyJavaPluginOwner
1375 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDummyJavaPluginOwner)
1377 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFocusedNode)
1379 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPendingStorageEvents)
1381 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1383 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
1384 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
1386 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mControllers)
1387 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArguments)
1388 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArgumentsLast)
1390 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInnerWindowHolder)
1391 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOuterWindow)
1393 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOpenerScriptPrincipal)
1394 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListenerManager)
1395 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSessionStorage)
1396 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mApplicationCache)
1397 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocumentPrincipal)
1399 // Unlink stuff from nsPIDOMWindow
1400 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChromeEventHandler)
1401 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParentTarget)
1402 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
1403 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFrameElement)
1405 // Unlink mDummyJavaPluginOwner
1406 if (tmp->mDummyJavaPluginOwner) {
1407 tmp->mDummyJavaPluginOwner->Destroy();
1408 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDummyJavaPluginOwner)
1411 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFocusedNode)
1413 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPendingStorageEvents)
1415 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1417 struct TraceData
1419 TraceData(TraceCallback& aCallback, void* aClosure) :
1420 callback(aCallback), closure(aClosure) {}
1422 TraceCallback& callback;
1423 void* closure;
1426 static PLDHashOperator
1427 TraceXBLHandlers(const void* aKey, void* aData, void* aClosure)
1429 TraceData* data = static_cast<TraceData*>(aClosure);
1430 data->callback(nsIProgrammingLanguage::JAVASCRIPT, aData, data->closure);
1431 return PL_DHASH_NEXT;
1434 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
1435 if (tmp->mCachedXBLPrototypeHandlers.IsInitialized()) {
1436 TraceData data(aCallback, aClosure);
1437 tmp->mCachedXBLPrototypeHandlers.EnumerateRead(TraceXBLHandlers, &data);
1439 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1441 NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsGlobalWindow)
1442 nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
1443 NS_IMPL_CYCLE_COLLECTION_ROOT_END
1445 //*****************************************************************************
1446 // nsGlobalWindow::nsIScriptGlobalObject
1447 //*****************************************************************************
1449 nsresult
1450 nsGlobalWindow::SetScriptContext(PRUint32 lang_id, nsIScriptContext *aScriptContext)
1452 NS_ASSERTION(lang_id == nsIProgrammingLanguage::JAVASCRIPT,
1453 "We don't support this language ID");
1454 NS_ASSERTION(IsOuterWindow(), "Uh, SetScriptContext() called on inner window!");
1456 NS_ASSERTION(!aScriptContext || !mContext, "Bad call to SetContext()!");
1458 if (aScriptContext) {
1459 // should probably assert the context is clean???
1460 aScriptContext->WillInitializeContext();
1462 nsresult rv = aScriptContext->InitContext();
1463 NS_ENSURE_SUCCESS(rv, rv);
1465 if (IsFrame()) {
1466 // This window is a [i]frame, don't bother GC'ing when the
1467 // frame's context is destroyed since a GC will happen when the
1468 // frameset or host document is destroyed anyway.
1470 aScriptContext->SetGCOnDestruction(PR_FALSE);
1474 mContext = aScriptContext;
1475 return NS_OK;
1478 nsresult
1479 nsGlobalWindow::EnsureScriptEnvironment(PRUint32 aLangID)
1481 NS_ASSERTION(aLangID == nsIProgrammingLanguage::JAVASCRIPT,
1482 "We don't support this language ID");
1483 FORWARD_TO_OUTER(EnsureScriptEnvironment, (aLangID), NS_ERROR_NOT_INITIALIZED);
1485 if (mJSObject)
1486 return NS_OK;
1488 NS_ASSERTION(!GetCurrentInnerWindowInternal(),
1489 "mJSObject is null, but we have an inner window?");
1491 nsCOMPtr<nsIScriptRuntime> scriptRuntime;
1492 nsresult rv = NS_GetScriptRuntimeByID(aLangID, getter_AddRefs(scriptRuntime));
1493 NS_ENSURE_SUCCESS(rv, rv);
1495 nsCOMPtr<nsIScriptContext> context;
1496 rv = scriptRuntime->CreateContext(getter_AddRefs(context));
1497 NS_ENSURE_SUCCESS(rv, rv);
1499 return SetScriptContext(aLangID, context);
1502 nsIScriptContext *
1503 nsGlobalWindow::GetScriptContext(PRUint32 lang)
1505 NS_ASSERTION(lang == nsIProgrammingLanguage::JAVASCRIPT,
1506 "We don't support this language ID");
1508 FORWARD_TO_OUTER(GetScriptContext, (lang), nsnull);
1509 return mContext;
1512 void *
1513 nsGlobalWindow::GetScriptGlobal(PRUint32 lang)
1515 NS_ASSERTION(lang == nsIProgrammingLanguage::JAVASCRIPT,
1516 "We don't support this language ID");
1517 return mJSObject;
1520 nsIScriptContext *
1521 nsGlobalWindow::GetContext()
1523 FORWARD_TO_OUTER(GetContext, (), nsnull);
1525 // check GetContext is indeed identical to GetScriptContext()
1526 NS_ASSERTION(mContext == GetScriptContext(nsIProgrammingLanguage::JAVASCRIPT),
1527 "GetContext confused?");
1528 return mContext;
1531 JSObject *
1532 nsGlobalWindow::GetGlobalJSObject()
1534 NS_ASSERTION(mJSObject == GetScriptGlobal(nsIProgrammingLanguage::JAVASCRIPT),
1535 "GetGlobalJSObject confused?");
1536 return FastGetGlobalJSObject();
1539 PRBool
1540 nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument)
1542 // We reuse the inner window when:
1543 // a. We are currently at our original document.
1544 // b. At least one of the following conditions are true:
1545 // -- We are not currently a content window (i.e., we're currently a chrome
1546 // window).
1547 // -- The new document is the same as the old document. This means that we're
1548 // getting called from document.open().
1549 // -- The new document has the same origin as what we have loaded right now.
1551 if (!mDoc || !aNewDocument) {
1552 return PR_FALSE;
1555 if (!mDoc->IsInitialDocument()) {
1556 return PR_FALSE;
1559 NS_ASSERTION(IsAboutBlank(mDoc->GetDocumentURI()),
1560 "How'd this happen?");
1562 // Great, we're the original document, check for one of the other
1563 // conditions.
1564 if (mDoc == aNewDocument) {
1565 // aClearScopeHint is false.
1566 return PR_TRUE;
1569 PRBool equal;
1570 if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),
1571 &equal)) &&
1572 equal) {
1573 // The origin is the same.
1574 return PR_TRUE;
1577 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
1579 if (treeItem) {
1580 PRInt32 itemType = nsIDocShellTreeItem::typeContent;
1581 treeItem->GetItemType(&itemType);
1583 // If we're a chrome window, then we want to reuse the inner window.
1584 return itemType == nsIDocShellTreeItem::typeChrome;
1587 // No treeItem: don't reuse the current inner window.
1588 return PR_FALSE;
1591 void
1592 nsGlobalWindow::SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal)
1594 FORWARD_TO_OUTER_VOID(SetOpenerScriptPrincipal, (aPrincipal));
1596 if (mDoc) {
1597 if (!mDoc->IsInitialDocument()) {
1598 // We have a document already, and it's not the original one. Bail out.
1599 // Do NOT set mOpenerScriptPrincipal in this case, just to be safe.
1600 return;
1603 #ifdef DEBUG
1604 // We better have an about:blank document loaded at this point. Otherwise,
1605 // something is really weird.
1606 nsCOMPtr<nsIURI> uri;
1607 mDoc->NodePrincipal()->GetURI(getter_AddRefs(uri));
1608 NS_ASSERTION(uri && IsAboutBlank(uri) &&
1609 IsAboutBlank(mDoc->GetDocumentURI()),
1610 "Unexpected original document");
1611 #endif
1613 nsCOMPtr<nsIDocShell_MOZILLA_2_0_BRANCH> ds(do_QueryInterface(GetDocShell()));
1614 ds->CreateAboutBlankContentViewer(aPrincipal);
1615 mDoc->SetIsInitialDocument(PR_TRUE);
1619 nsIPrincipal*
1620 nsGlobalWindow::GetOpenerScriptPrincipal()
1622 FORWARD_TO_OUTER(GetOpenerScriptPrincipal, (), nsnull);
1624 return mOpenerScriptPrincipal;
1627 PopupControlState
1628 PushPopupControlState(PopupControlState aState, PRBool aForce)
1630 PopupControlState oldState = gPopupControlState;
1632 if (aState < gPopupControlState || aForce) {
1633 gPopupControlState = aState;
1636 return oldState;
1639 void
1640 PopPopupControlState(PopupControlState aState)
1642 gPopupControlState = aState;
1645 PopupControlState
1646 nsGlobalWindow::PushPopupControlState(PopupControlState aState,
1647 PRBool aForce) const
1649 return ::PushPopupControlState(aState, aForce);
1652 void
1653 nsGlobalWindow::PopPopupControlState(PopupControlState aState) const
1655 ::PopPopupControlState(aState);
1658 PopupControlState
1659 nsGlobalWindow::GetPopupControlState() const
1661 return gPopupControlState;
1664 #define WINDOWSTATEHOLDER_IID \
1665 {0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}
1667 class WindowStateHolder : public nsISupports
1669 public:
1670 NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
1671 NS_DECL_ISUPPORTS
1673 WindowStateHolder(nsGlobalWindow *aWindow,
1674 nsIXPConnectJSObjectHolder *aHolder,
1675 nsNavigator *aNavigator,
1676 nsIXPConnectJSObjectHolder *aOuterProto,
1677 nsIXPConnectJSObjectHolder *aOuterRealProto);
1679 nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
1680 nsIXPConnectJSObjectHolder *GetInnerWindowHolder()
1681 { return mInnerWindowHolder; }
1683 nsNavigator* GetNavigator() { return mNavigator; }
1684 nsIXPConnectJSObjectHolder* GetOuterProto() { return mOuterProto; }
1685 nsIXPConnectJSObjectHolder* GetOuterRealProto() { return mOuterRealProto; }
1687 void DidRestoreWindow()
1689 mInnerWindow = nsnull;
1691 mInnerWindowHolder = nsnull;
1692 mNavigator = nsnull;
1693 mOuterProto = nsnull;
1694 mOuterRealProto = nsnull;
1697 protected:
1698 ~WindowStateHolder();
1700 nsGlobalWindow *mInnerWindow;
1701 // We hold onto this to make sure the inner window doesn't go away. The outer
1702 // window ends up recalculating it anyway.
1703 nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
1704 nsRefPtr<nsNavigator> mNavigator;
1705 nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterProto;
1706 nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterRealProto;
1709 NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
1711 WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
1712 nsIXPConnectJSObjectHolder *aHolder,
1713 nsNavigator *aNavigator,
1714 nsIXPConnectJSObjectHolder *aOuterProto,
1715 nsIXPConnectJSObjectHolder *aOuterRealProto)
1716 : mInnerWindow(aWindow),
1717 mNavigator(aNavigator),
1718 mOuterProto(aOuterProto),
1719 mOuterRealProto(aOuterRealProto)
1721 NS_PRECONDITION(aWindow, "null window");
1722 NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
1724 mInnerWindowHolder = aHolder;
1726 aWindow->SuspendTimeouts();
1729 WindowStateHolder::~WindowStateHolder()
1731 if (mInnerWindow) {
1732 // This window was left in the bfcache and is now going away. We need to
1733 // free it up.
1734 // Note that FreeInnerObjects may already have been called on the
1735 // inner window if its outer has already had SetDocShell(null)
1736 // called. In this case the contexts will all be null and the
1737 // PR_TRUE for aClearScope won't do anything; this is OK since
1738 // SetDocShell(null) already did it.
1739 mInnerWindow->FreeInnerObjects(PR_TRUE);
1743 NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder)
1745 nsresult
1746 nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
1747 nsISupports* aState,
1748 PRBool aForceReuseInnerWindow)
1750 NS_TIME_FUNCTION;
1752 NS_PRECONDITION(mDocumentPrincipal == nsnull,
1753 "mDocumentPrincipal prematurely set!");
1755 if (!aDocument) {
1756 NS_ERROR("SetNewDocument(null) called!");
1758 return NS_ERROR_INVALID_ARG;
1761 if (IsInnerWindow()) {
1762 if (!mOuterWindow) {
1763 return NS_ERROR_NOT_INITIALIZED;
1766 // Refuse to set a new document if the call came from an inner
1767 // window that's not the current inner window.
1768 if (mOuterWindow->GetCurrentInnerWindow() != this) {
1769 return NS_ERROR_NOT_AVAILABLE;
1772 return GetOuterWindowInternal()->SetNewDocument(aDocument, aState,
1773 aForceReuseInnerWindow);
1776 NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
1778 if (IsFrozen()) {
1779 // This outer is now getting its first inner, thaw the outer now
1780 // that it's ready and is getting an inner window.
1782 Thaw();
1785 NS_ASSERTION(!GetCurrentInnerWindow() ||
1786 GetCurrentInnerWindow()->GetExtantDocument() == mDocument,
1787 "Uh, mDocument doesn't match the current inner window "
1788 "document!");
1790 PRBool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
1791 if (aForceReuseInnerWindow &&
1792 !wouldReuseInnerWindow &&
1793 mDoc &&
1794 mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
1795 NS_ERROR("Attempted forced inner window reuse while changing principal");
1796 return NS_ERROR_UNEXPECTED;
1799 nsresult rv = NS_OK;
1801 nsCOMPtr<nsIDocument> oldDoc(do_QueryInterface(mDocument));
1803 nsIScriptContext *scx = GetContextInternal();
1804 NS_ENSURE_TRUE(scx, NS_ERROR_NOT_INITIALIZED);
1806 JSContext *cx = (JSContext *)scx->GetNativeContext();
1807 #ifndef MOZ_DISABLE_DOMCRYPTO
1808 // clear smartcard events, our document has gone away.
1809 if (mCrypto) {
1810 mCrypto->SetEnableSmartCardEvents(PR_FALSE);
1812 #endif
1813 if (!mDocument) {
1814 // First document load.
1816 // Get our private root. If it is equal to us, then we need to
1817 // attach our global key bindings that handles browser scrolling
1818 // and other browser commands.
1819 nsIDOMWindowInternal *internal = nsGlobalWindow::GetPrivateRoot();
1821 if (internal == static_cast<nsIDOMWindowInternal *>(this)) {
1822 nsCOMPtr<nsIXBLService> xblService = do_GetService("@mozilla.org/xbl;1");
1823 if (xblService) {
1824 nsCOMPtr<nsPIDOMEventTarget> piTarget =
1825 do_QueryInterface(mChromeEventHandler);
1826 xblService->AttachGlobalKeyHandler(piTarget);
1831 /* No mDocShell means we're already been partially closed down. When that
1832 happens, setting status isn't a big requirement, so don't. (Doesn't happen
1833 under normal circumstances, but bug 49615 describes a case.) */
1835 nsContentUtils::AddScriptRunner(
1836 NS_NewRunnableMethod(this, &nsGlobalWindow::ClearStatus));
1838 PRBool reUseInnerWindow = aForceReuseInnerWindow || wouldReuseInnerWindow;
1840 // Remember the old document's principal.
1841 nsIPrincipal *oldPrincipal = nsnull;
1842 if (oldDoc) {
1843 oldPrincipal = oldDoc->NodePrincipal();
1846 // Drop our reference to the navigator object unless we're reusing
1847 // the existing inner window or the new document is from the same
1848 // origin as the old document.
1849 if (!reUseInnerWindow && mNavigator && oldPrincipal) {
1850 PRBool equal;
1851 rv = oldPrincipal->Equals(aDocument->NodePrincipal(), &equal);
1853 if (NS_FAILED(rv) || !equal) {
1854 // Different origins. Release the navigator object so it gets
1855 // recreated for the new document. The plugins or mime types
1856 // arrays may have changed. See bug 150087.
1857 mNavigator->SetDocShell(nsnull);
1859 mNavigator = nsnull;
1863 if (mNavigator && aDocument != oldDoc) {
1864 // We didn't drop our reference to our old navigator object and
1865 // we're loading a new document. Notify the navigator object about
1866 // the new document load so that it can make sure it is ready for
1867 // the new document.
1869 mNavigator->LoadingNewDocument();
1872 // Set mDocument even if this is an outer window to avoid
1873 // having to *always* reach into the inner window to find the
1874 // document.
1875 mDocument = do_QueryInterface(aDocument);
1876 mDoc = aDocument;
1878 #ifdef DEBUG
1879 mLastOpenedURI = aDocument->GetDocumentURI();
1880 #endif
1882 mContext->WillInitializeContext();
1884 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
1886 nsRefPtr<nsGlobalWindow> newInnerWindow;
1888 PRBool thisChrome = IsChromeWindow();
1889 nsCOMPtr<nsIXPConnectJSObjectHolder> navigatorHolder;
1890 jsval nav;
1892 PRBool isChrome = PR_FALSE;
1894 nsCxPusher cxPusher;
1895 if (!cxPusher.Push(cx)) {
1896 return NS_ERROR_FAILURE;
1899 JSAutoRequest ar(cx);
1901 nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
1902 NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
1904 // Make sure to clear scope on the outer window *before* we
1905 // initialize the new inner window. If we don't, things
1906 // (Object.prototype etc) could leak from the old outer to the new
1907 // inner scope.
1908 mContext->ClearScope(mJSObject, PR_FALSE);
1910 // This code should not be called during shutdown any more (now that
1911 // we don't ever call SetNewDocument(nsnull), so no need to null
1912 // check xpc here.
1913 nsIXPConnect *xpc = nsContentUtils::XPConnect();
1914 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
1915 if (reUseInnerWindow) {
1916 // We're reusing the current inner window.
1917 NS_ASSERTION(!currentInner->IsFrozen(),
1918 "We should never be reusing a shared inner window");
1919 newInnerWindow = currentInner;
1921 if (aDocument != oldDoc) {
1922 nsWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject);
1925 // The API we're really looking for here is to go clear all of the
1926 // Xray wrappers associated with our outer window. However, we
1927 // don't expose that API because the implementation would be
1928 // identical to that of JS_TransplantObject, so we just call that
1929 // instead.
1930 if (!JS_TransplantObject(cx, mJSObject, mJSObject)) {
1931 return NS_ERROR_FAILURE;
1933 } else {
1934 if (aState) {
1935 newInnerWindow = wsh->GetInnerWindow();
1936 mInnerWindowHolder = wsh->GetInnerWindowHolder();
1938 NS_ASSERTION(newInnerWindow, "Got a state without inner window");
1940 // These assignments addref.
1941 mNavigator = wsh->GetNavigator();
1943 if (mNavigator) {
1944 // Update mNavigator's docshell pointer now.
1945 mNavigator->SetDocShell(mDocShell);
1946 mNavigator->LoadingNewDocument();
1948 } else if (thisChrome) {
1949 newInnerWindow = new nsGlobalChromeWindow(this);
1950 isChrome = PR_TRUE;
1951 } else if (mIsModalContentWindow) {
1952 newInnerWindow = new nsGlobalModalWindow(this);
1953 } else {
1954 newInnerWindow = new nsGlobalWindow(this);
1957 if (currentInner && currentInner->mJSObject) {
1958 if (mNavigator && !aState) {
1959 // Hold on to the navigator wrapper so that we can set
1960 // window.navigator in the new window to point to the same
1961 // object (assuming we didn't change origins etc). See bug
1962 // 163645 for more on why we need this.
1964 nsIDOMNavigator* navigator =
1965 static_cast<nsIDOMNavigator*>(mNavigator.get());
1966 nsContentUtils::WrapNative(cx, currentInner->mJSObject, navigator,
1967 &NS_GET_IID(nsIDOMNavigator), &nav,
1968 getter_AddRefs(navigatorHolder));
1972 if (!aState) {
1973 // This is redundant if we're restoring from a previous inner window.
1974 nsIScriptGlobalObject *sgo =
1975 (nsIScriptGlobalObject *)newInnerWindow.get();
1977 // Freeze the outer window and null out the inner window so
1978 // that initializing classes on the new inner doesn't end up
1979 // reaching into the old inner window for classes etc.
1981 // [This happens with Object.prototype when XPConnect creates
1982 // a temporary global while initializing classes; the reason
1983 // being that xpconnect creates the temp global w/o a parent
1984 // and proto, which makes the JS engine look up classes in
1985 // cx->globalObject, i.e. this outer window].
1987 mInnerWindow = nsnull;
1989 Freeze();
1990 mCreatingInnerWindow = PR_TRUE;
1991 // Every script context we are initialized with must create a
1992 // new global.
1993 void *&newGlobal = (void *&)newInnerWindow->mJSObject;
1994 nsCOMPtr<nsIXPConnectJSObjectHolder> &holder = mInnerWindowHolder;
1995 rv = mContext->CreateNativeGlobalForInner(sgo, isChrome,
1996 aDocument->NodePrincipal(),
1997 &newGlobal,
1998 getter_AddRefs(holder));
1999 NS_ASSERTION(NS_SUCCEEDED(rv) && newGlobal && holder,
2000 "Failed to get script global and holder");
2002 mCreatingInnerWindow = PR_FALSE;
2003 Thaw();
2005 NS_ENSURE_SUCCESS(rv, rv);
2008 if (currentInner && currentInner->mJSObject) {
2009 PRBool termFuncSet = PR_FALSE;
2011 if (oldDoc == aDocument) {
2012 // Suspend the current context's request before Pop() resumes the old
2013 // context's request.
2014 JSAutoSuspendRequest asr(cx);
2016 // Pop our context here so that we get the correct one for the
2017 // termination function.
2018 cxPusher.Pop();
2020 JSContext *oldCx = nsContentUtils::GetCurrentJSContext();
2022 nsIScriptContext *callerScx;
2023 if (oldCx && (callerScx = GetScriptContextFromJSContext(oldCx))) {
2024 // We're called from document.open() (and document.open() is
2025 // called from JS), clear the scope etc in a termination
2026 // function on the calling context to prevent clearing the
2027 // calling scope.
2028 NS_ASSERTION(!currentInner->IsFrozen(),
2029 "How does this opened window get into session history");
2031 JSAutoRequest ar(oldCx);
2033 callerScx->SetTerminationFunction(ClearWindowScope,
2034 static_cast<nsIDOMWindow *>
2035 (currentInner));
2037 termFuncSet = PR_TRUE;
2040 // Re-push our context.
2041 cxPusher.Push(cx);
2044 // Don't clear scope on our current inner window if it's going to be
2045 // held in the bfcache.
2046 if (!currentInner->IsFrozen()) {
2047 // Skip the ClearScope if we set a termination function to do
2048 // it ourselves, later.
2049 currentInner->FreeInnerObjects(!termFuncSet);
2053 mInnerWindow = newInnerWindow;
2055 if (!mJSObject) {
2056 mContext->CreateOuterObject(this, newInnerWindow);
2057 mContext->DidInitializeContext();
2059 mJSObject = (JSObject *)mContext->GetNativeGlobal();
2060 SetWrapper(mJSObject);
2061 } else {
2062 JSObject *outerObject =
2063 NS_NewOuterWindowProxy(cx, newInnerWindow->mJSObject);
2064 if (!outerObject) {
2065 NS_ERROR("out of memory");
2066 return NS_ERROR_FAILURE;
2069 outerObject = JS_TransplantObject(cx, mJSObject, outerObject);
2070 if (!outerObject) {
2071 NS_ERROR("unable to transplant wrappers, probably OOM");
2072 return NS_ERROR_FAILURE;
2075 mJSObject = outerObject;
2076 SetWrapper(mJSObject);
2079 JSAutoEnterCompartment ac;
2080 if (!ac.enter(cx, mJSObject)) {
2081 NS_ERROR("unable to enter a compartment");
2082 return NS_ERROR_FAILURE;
2085 JS_SetParent(cx, mJSObject, newInnerWindow->mJSObject);
2087 mContext->SetOuterObject(mJSObject);
2091 JSAutoEnterCompartment ac;
2092 if (!ac.enter(cx, mJSObject)) {
2093 NS_ERROR("unable to enter a compartment");
2094 return NS_ERROR_FAILURE;
2097 // XXX Not sure if this is needed.
2098 if (aState) {
2099 JSObject *proto;
2100 if (nsIXPConnectJSObjectHolder *holder = wsh->GetOuterRealProto()) {
2101 holder->GetJSObject(&proto);
2102 } else {
2103 proto = nsnull;
2106 if (!JS_SetPrototype(cx, mJSObject, proto)) {
2107 NS_ERROR("can't set prototype");
2108 return NS_ERROR_FAILURE;
2110 } else {
2111 if (!JS_DefineProperty(cx, newInnerWindow->mJSObject, "window",
2112 OBJECT_TO_JSVAL(mJSObject),
2113 JS_PropertyStub, JS_StrictPropertyStub,
2114 JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
2115 NS_ERROR("can't create the 'window' property");
2116 return NS_ERROR_FAILURE;
2121 JSAutoEnterCompartment ac;
2122 if (!ac.enter(cx, mJSObject)) {
2123 NS_ERROR("unable to enter a compartment");
2124 return NS_ERROR_FAILURE;
2127 if (!aState && !reUseInnerWindow) {
2128 // Loading a new page and creating a new inner window, *not*
2129 // restoring from session history.
2131 // Now that both the the inner and outer windows are initialized
2132 // let the script context do its magic to hook them together.
2133 mContext->ConnectToInner(newInnerWindow, mJSObject);
2135 nsCOMPtr<nsIContent> frame = do_QueryInterface(GetFrameElementInternal());
2136 if (frame && frame->GetOwnerDoc()) {
2137 nsPIDOMWindow* parentWindow = frame->GetOwnerDoc()->GetWindow();
2138 if (parentWindow && parentWindow->TimeoutSuspendCount()) {
2139 SuspendTimeouts(parentWindow->TimeoutSuspendCount());
2144 // Tell the contexts we have completed setting up the doc.
2145 // Add an extra ref in case we release mContext during GC.
2146 nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
2147 nsCOMPtr<nsIDOMDocument> dd(do_QueryInterface(aDocument));
2148 mContext->DidSetDocument(dd, newInnerWindow->mJSObject);
2150 // Now that the prototype is all set up, install the global scope
2151 // polluter. This must happen after the above prototype fixup. If
2152 // the GSP was to be installed on the inner window's real
2153 // prototype (as it would be if this was done before the prototype
2154 // fixup above) we would end up holding the GSP alive (through
2155 // XPConnect's internal marking of wrapper prototypes) as long as
2156 // the inner window was around, and if the GSP had properties on
2157 // it that held an element alive we'd hold the document alive,
2158 // which could hold event handlers alive, which hold the context
2159 // alive etc.
2161 if ((!reUseInnerWindow || aDocument != oldDoc) && !aState) {
2162 nsCOMPtr<nsIHTMLDocument> html_doc(do_QueryInterface(mDocument));
2163 nsWindowSH::InstallGlobalScopePolluter(cx, newInnerWindow->mJSObject,
2164 html_doc);
2167 if (aDocument) {
2168 aDocument->SetScriptGlobalObject(newInnerWindow);
2171 if (!aState) {
2172 if (reUseInnerWindow) {
2173 if (newInnerWindow->mDoc != aDocument) {
2174 newInnerWindow->mDocument = do_QueryInterface(aDocument);
2175 newInnerWindow->mDoc = aDocument;
2177 // We're reusing the inner window for a new document. In this
2178 // case we don't clear the inner window's scope, but we must
2179 // make sure the cached document property gets updated.
2181 // XXXmarkh - tell other languages about this?
2182 ::JS_DeleteProperty(cx, currentInner->mJSObject, "document");
2184 } else {
2185 rv = newInnerWindow->InnerSetNewDocument(aDocument);
2186 NS_ENSURE_SUCCESS(rv, rv);
2188 // Initialize DOM classes etc on the inner window.
2189 rv = mContext->InitClasses(newInnerWindow->mJSObject);
2190 NS_ENSURE_SUCCESS(rv, rv);
2192 if (navigatorHolder) {
2193 JS_ASSERT(JSVAL_IS_OBJECT(nav));
2195 if (JSVAL_TO_OBJECT(nav)->compartment() == newInnerWindow->mJSObject->compartment()) {
2196 // Restore window.navigator onto the new inner window.
2198 ::JS_DefineProperty(cx, newInnerWindow->mJSObject, "navigator",
2199 nav, nsnull, nsnull,
2200 JSPROP_ENUMERATE | JSPROP_PERMANENT |
2201 JSPROP_READONLY);
2203 // The Navigator's prototype object keeps a reference to the
2204 // window in which it was first created and can thus cause that
2205 // window to stay alive for too long. Reparenting it here allows
2206 // the window to be collected sooner.
2207 nsIDOMNavigator* navigator =
2208 static_cast<nsIDOMNavigator*>(mNavigator);
2210 xpc->
2211 ReparentWrappedNativeIfFound(cx, JSVAL_TO_OBJECT(nav),
2212 newInnerWindow->mJSObject,
2213 navigator,
2214 getter_AddRefs(navigatorHolder));
2219 if (mArguments) {
2220 newInnerWindow->DefineArgumentsProperty(mArguments);
2221 newInnerWindow->mArguments = mArguments;
2222 newInnerWindow->mArgumentsOrigin = mArgumentsOrigin;
2224 mArguments = nsnull;
2225 mArgumentsOrigin = nsnull;
2228 // Give the new inner window our chrome event handler (since it
2229 // doesn't have one).
2230 newInnerWindow->mChromeEventHandler = mChromeEventHandler;
2233 mContext->GC();
2234 mContext->DidInitializeContext();
2236 if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
2237 // We should probably notify. However if this is the, arguably bad,
2238 // situation when we're creating a temporary non-chrome-about-blank
2239 // document in a chrome docshell, don't notify just yet. Instead wait
2240 // until we have a real chrome doc.
2241 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
2242 PRInt32 itemType = nsIDocShellTreeItem::typeContent;
2243 if (treeItem) {
2244 treeItem->GetItemType(&itemType);
2247 if (itemType != nsIDocShellTreeItem::typeChrome ||
2248 nsContentUtils::IsSystemPrincipal(mDoc->NodePrincipal())) {
2249 newInnerWindow->mHasNotifiedGlobalCreated = PR_TRUE;
2250 nsContentUtils::AddScriptRunner(
2251 NS_NewRunnableMethod(this, &nsGlobalWindow::DispatchDOMWindowCreated));
2255 return NS_OK;
2258 void
2259 nsGlobalWindow::DispatchDOMWindowCreated()
2261 if (!mDoc || !mDocument) {
2262 return;
2265 // Fire DOMWindowCreated at chrome event listeners
2266 nsContentUtils::DispatchChromeEvent(mDoc, mDocument, NS_LITERAL_STRING("DOMWindowCreated"),
2267 PR_TRUE /* bubbles */,
2268 PR_FALSE /* not cancellable */);
2270 nsCOMPtr<nsIObserverService> observerService =
2271 mozilla::services::GetObserverService();
2272 if (observerService) {
2273 nsAutoString origin;
2274 nsIPrincipal* principal = mDoc->NodePrincipal();
2275 nsContentUtils::GetUTFOrigin(principal, origin);
2276 observerService->
2277 NotifyObservers(static_cast<nsIDOMWindow*>(this),
2278 nsContentUtils::IsSystemPrincipal(principal) ?
2279 "chrome-document-global-created" :
2280 "content-document-global-created",
2281 origin.get());
2285 void
2286 nsGlobalWindow::ClearStatus()
2288 SetStatus(EmptyString());
2289 SetDefaultStatus(EmptyString());
2292 nsresult
2293 nsGlobalWindow::InnerSetNewDocument(nsIDocument* aDocument)
2295 NS_PRECONDITION(IsInnerWindow(), "Must only be called on inner windows");
2297 #ifdef PR_LOGGING
2298 if (aDocument && gDOMLeakPRLog &&
2299 PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
2300 nsIURI *uri = aDocument->GetDocumentURI();
2301 nsCAutoString spec;
2302 if (uri)
2303 uri->GetSpec(spec);
2304 PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get());
2306 #endif
2308 mDocument = do_QueryInterface(aDocument);
2309 mDoc = aDocument;
2310 mLocalStorage = nsnull;
2311 mSessionStorage = nsnull;
2313 #ifdef DEBUG
2314 mLastOpenedURI = aDocument->GetDocumentURI();
2315 #endif
2317 // Clear our mutation bitfield.
2318 mMutationBits = 0;
2320 return NS_OK;
2323 void
2324 nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
2326 NS_ASSERTION(IsOuterWindow(), "Uh, SetDocShell() called on inner window!");
2328 if (aDocShell == mDocShell)
2329 return;
2331 // SetDocShell(nsnull) means the window is being torn down. Drop our
2332 // reference to the script context, allowing it to be deleted
2333 // later. Meanwhile, keep our weak reference to the script object
2334 // (mJSObject) so that it can be retrieved later (until it is
2335 // finalized by the JS GC).
2337 if (!aDocShell) {
2338 NS_ASSERTION(PR_CLIST_IS_EMPTY(&mTimeouts),
2339 "Uh, outer window holds timeouts!");
2341 // Call FreeInnerObjects on all inner windows, not just the current
2342 // one, since some could be held by WindowStateHolder objects that
2343 // are GC-owned.
2344 for (nsRefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
2345 inner != this;
2346 inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
2347 NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
2348 "bad outer window pointer");
2349 inner->FreeInnerObjects(PR_TRUE);
2352 // Make sure that this is called before we null out the document.
2353 NotifyDOMWindowDestroyed(this);
2355 NotifyWindowIDDestroyed("outer-window-destroyed");
2357 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
2359 if (currentInner) {
2360 NS_ASSERTION(mDoc, "Must have doc!");
2362 // Remember the document's principal.
2363 mDocumentPrincipal = mDoc->NodePrincipal();
2365 // Release our document reference
2366 mDocument = nsnull;
2367 mDoc = nsnull;
2370 if (mContext) {
2371 mContext->ClearScope(mJSObject, PR_TRUE);
2374 ClearControllers();
2376 mChromeEventHandler = nsnull; // force release now
2378 if (mArguments) {
2379 // We got no new document after someone called
2380 // SetArguments(), drop our reference to the arguments.
2381 mArguments = nsnull;
2382 mArgumentsLast = nsnull;
2383 mArgumentsOrigin = nsnull;
2386 if (mContext) {
2387 mContext->GC();
2388 mContext->FinalizeContext();
2389 mContext = nsnull;
2392 #ifdef DEBUG
2393 nsCycleCollector_DEBUG_shouldBeFreed(mContext);
2394 nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
2395 #endif
2398 mDocShell = aDocShell; // Weak Reference
2400 if (mNavigator)
2401 mNavigator->SetDocShell(aDocShell);
2402 if (mFrames)
2403 mFrames->SetDocShell(aDocShell);
2404 if (mScreen)
2405 mScreen->SetDocShell(aDocShell);
2407 // tell our member elements about the new browserwindow
2408 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2409 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2410 if (mMenubar) {
2411 mMenubar->SetWebBrowserChrome(browserChrome);
2413 if (mToolbar) {
2414 mToolbar->SetWebBrowserChrome(browserChrome);
2416 if (mLocationbar) {
2417 mLocationbar->SetWebBrowserChrome(browserChrome);
2419 if (mPersonalbar) {
2420 mPersonalbar->SetWebBrowserChrome(browserChrome);
2422 if (mStatusbar) {
2423 mStatusbar->SetWebBrowserChrome(browserChrome);
2425 if (mScrollbars) {
2426 mScrollbars->SetWebBrowserChrome(browserChrome);
2429 if (!mDocShell) {
2430 MaybeForgiveSpamCount();
2431 CleanUp(PR_FALSE);
2432 } else {
2433 // Get our enclosing chrome shell and retrieve its global window impl, so
2434 // that we can do some forwarding to the chrome document.
2435 nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
2436 mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
2437 mChromeEventHandler = do_QueryInterface(chromeEventHandler);
2438 if (!mChromeEventHandler) {
2439 // We have no chrome event handler. If we have a parent,
2440 // get our chrome event handler from the parent. If
2441 // we don't have a parent, then we need to make a new
2442 // window root object that will function as a chrome event
2443 // handler and receive all events that occur anywhere inside
2444 // our window.
2445 nsCOMPtr<nsIDOMWindow> parentWindow;
2446 GetParent(getter_AddRefs(parentWindow));
2447 if (parentWindow.get() != static_cast<nsIDOMWindow*>(this)) {
2448 nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(parentWindow));
2449 mChromeEventHandler = piWindow->GetChromeEventHandler();
2451 else NS_NewWindowRoot(this, getter_AddRefs(mChromeEventHandler));
2456 void
2457 nsGlobalWindow::SetOpenerWindow(nsIDOMWindowInternal* aOpener,
2458 PRBool aOriginalOpener)
2460 FORWARD_TO_OUTER_VOID(SetOpenerWindow, (aOpener, aOriginalOpener));
2462 NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
2463 "aOriginalOpener is true, but not first call to "
2464 "SetOpenerWindow!");
2465 NS_ASSERTION(aOpener || !aOriginalOpener,
2466 "Shouldn't set mHadOriginalOpener if aOpener is null");
2468 mOpener = do_GetWeakReference(aOpener);
2469 NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!");
2471 if (aOriginalOpener) {
2472 mHadOriginalOpener = PR_TRUE;
2475 #ifdef DEBUG
2476 mSetOpenerWindowCalled = PR_TRUE;
2477 #endif
2480 void
2481 nsGlobalWindow::UpdateParentTarget()
2483 nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(mChromeEventHandler);
2484 if (flo) {
2485 nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
2486 if (fl) {
2487 mParentTarget = fl->GetTabChildGlobalAsEventTarget();
2490 if (!mParentTarget) {
2491 mParentTarget = mChromeEventHandler;
2495 PRBool
2496 nsGlobalWindow::GetIsTabModalPromptAllowed()
2498 PRBool allowTabModal = PR_TRUE;
2499 if (mDocShell) {
2500 nsCOMPtr<nsIContentViewer> cv;
2501 mDocShell->GetContentViewer(getter_AddRefs(cv));
2502 nsCOMPtr<nsIContentViewer_MOZILLA_2_0_BRANCH> cv2 = do_QueryInterface(cv);
2503 if (cv2)
2504 cv2->GetIsTabModalPromptAllowed(&allowTabModal);
2507 return allowTabModal;
2510 nsresult
2511 nsGlobalWindow::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
2513 NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
2514 static PRUint32 count = 0;
2515 PRUint32 msg = aVisitor.mEvent->message;
2517 aVisitor.mCanHandle = PR_TRUE;
2518 aVisitor.mForceContentDispatch = PR_TRUE; //FIXME! Bug 329119
2519 if ((msg == NS_MOUSE_MOVE) && gEntropyCollector) {
2520 //Chances are this counter will overflow during the life of the
2521 //process, but that's OK for our case. Means we get a little
2522 //more entropy.
2523 if (count++ % 100 == 0) {
2524 //Since the high bits seem to be zero's most of the time,
2525 //let's only take the lowest half of the point structure.
2526 PRInt16 myCoord[2];
2528 myCoord[0] = aVisitor.mEvent->refPoint.x;
2529 myCoord[1] = aVisitor.mEvent->refPoint.y;
2530 gEntropyCollector->RandomUpdate((void*)myCoord, sizeof(myCoord));
2531 gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
2532 sizeof(PRUint32));
2534 } else if (msg == NS_RESIZE_EVENT) {
2535 mIsHandlingResizeEvent = PR_TRUE;
2536 } else if (msg == NS_MOUSE_BUTTON_DOWN &&
2537 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2538 gMouseDown = PR_TRUE;
2539 } else if (msg == NS_MOUSE_BUTTON_UP &&
2540 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2541 gMouseDown = PR_FALSE;
2542 if (gDragServiceDisabled) {
2543 nsCOMPtr<nsIDragService> ds =
2544 do_GetService("@mozilla.org/widget/dragservice;1");
2545 if (ds) {
2546 gDragServiceDisabled = PR_FALSE;
2547 ds->Unsuppress();
2552 aVisitor.mParentTarget = GetParentTarget();
2553 return NS_OK;
2556 bool
2557 nsGlobalWindow::DialogOpenAttempted()
2559 nsGlobalWindow *topWindow = GetTop();
2560 if (!topWindow) {
2561 NS_ERROR("DialogOpenAttempted() called without a top window?");
2563 return false;
2566 topWindow = topWindow->GetCurrentInnerWindowInternal();
2567 if (!topWindow ||
2568 topWindow->mLastDialogQuitTime.IsNull() ||
2569 nsContentUtils::IsCallerTrustedForCapability("UniversalXPConnect")) {
2570 return false;
2573 TimeDuration dialogDuration(TimeStamp::Now() -
2574 topWindow->mLastDialogQuitTime);
2576 if (dialogDuration.ToSeconds() <
2577 nsContentUtils::GetIntPref("dom.successive_dialog_time_limit",
2578 SUCCESSIVE_DIALOG_TIME_LIMIT)) {
2579 topWindow->mDialogAbuseCount++;
2581 return (topWindow->GetPopupControlState() > openAllowed ||
2582 topWindow->mDialogAbuseCount > MAX_DIALOG_COUNT);
2585 topWindow->mDialogAbuseCount = 0;
2587 return false;
2590 bool
2591 nsGlobalWindow::AreDialogsBlocked()
2593 nsGlobalWindow *topWindow = GetTop();
2594 if (!topWindow) {
2595 NS_ASSERTION(!mDocShell, "AreDialogsBlocked() called without a top window?");
2597 return true;
2600 topWindow = topWindow->GetCurrentInnerWindowInternal();
2602 return !topWindow ||
2603 (topWindow->mDialogDisabled &&
2604 (topWindow->GetPopupControlState() > openAllowed ||
2605 topWindow->mDialogAbuseCount >= MAX_DIALOG_COUNT));
2608 bool
2609 nsGlobalWindow::ConfirmDialogAllowed()
2611 FORWARD_TO_OUTER(ConfirmDialogAllowed, (), NS_ERROR_NOT_INITIALIZED);
2613 NS_ENSURE_TRUE(mDocShell, false);
2614 nsCOMPtr<nsIPromptService> promptSvc =
2615 do_GetService("@mozilla.org/embedcomp/prompt-service;1");
2617 if (!DialogOpenAttempted() || !promptSvc) {
2618 return true;
2621 // Reset popup state while opening a modal dialog, and firing events
2622 // about the dialog, to prevent the current state from being active
2623 // the whole time a modal dialog is open.
2624 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
2626 PRBool disableDialog = PR_FALSE;
2627 nsXPIDLString label, title;
2628 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2629 "ScriptDialogLabel", label);
2630 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2631 "ScriptDialogPreventTitle", title);
2632 promptSvc->Confirm(this, title.get(), label.get(), &disableDialog);
2633 if (disableDialog) {
2634 PreventFurtherDialogs();
2635 return false;
2638 return true;
2641 void
2642 nsGlobalWindow::PreventFurtherDialogs()
2644 nsGlobalWindow *topWindow = GetTop();
2645 if (!topWindow) {
2646 NS_ERROR("PreventFurtherDialogs() called without a top window?");
2648 return;
2651 topWindow = topWindow->GetCurrentInnerWindowInternal();
2653 if (topWindow)
2654 topWindow->mDialogDisabled = PR_TRUE;
2657 nsresult
2658 nsGlobalWindow::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
2660 NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
2662 // Return early if there is nothing to do.
2663 switch (aVisitor.mEvent->message) {
2664 case NS_RESIZE_EVENT:
2665 case NS_PAGE_UNLOAD:
2666 case NS_LOAD:
2667 break;
2668 default:
2669 return NS_OK;
2672 /* mChromeEventHandler and mContext go dangling in the middle of this
2673 function under some circumstances (events that destroy the window)
2674 without this addref. */
2675 nsCOMPtr<nsPIDOMEventTarget> kungFuDeathGrip1(mChromeEventHandler);
2676 nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
2678 if (aVisitor.mEvent->message == NS_RESIZE_EVENT) {
2679 mIsHandlingResizeEvent = PR_FALSE;
2680 } else if (aVisitor.mEvent->message == NS_PAGE_UNLOAD &&
2681 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2682 // Execute bindingdetached handlers before we tear ourselves
2683 // down.
2684 if (mDocument) {
2685 NS_ASSERTION(mDoc, "Must have doc");
2686 mDoc->BindingManager()->ExecuteDetachedHandlers();
2688 mIsDocumentLoaded = PR_FALSE;
2689 } else if (aVisitor.mEvent->message == NS_LOAD &&
2690 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2691 // This is page load event since load events don't propagate to |window|.
2692 // @see nsDocument::PreHandleEvent.
2693 mIsDocumentLoaded = PR_TRUE;
2695 nsCOMPtr<nsIContent> content(do_QueryInterface(GetFrameElementInternal()));
2696 nsCOMPtr<nsIDocShellTreeItem> treeItem =
2697 do_QueryInterface(GetDocShell());
2699 PRInt32 itemType = nsIDocShellTreeItem::typeChrome;
2701 if (treeItem) {
2702 treeItem->GetItemType(&itemType);
2705 if (content && GetParentInternal() &&
2706 itemType != nsIDocShellTreeItem::typeChrome) {
2707 // If we're not in chrome, or at a chrome boundary, fire the
2708 // onload event for the frame element.
2710 nsEventStatus status = nsEventStatus_eIgnore;
2711 nsEvent event(NS_IS_TRUSTED_EVENT(aVisitor.mEvent), NS_LOAD);
2712 event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
2714 // Most of the time we could get a pres context to pass in here,
2715 // but not always (i.e. if this window is not shown there won't
2716 // be a pres context available). Since we're not firing a GUI
2717 // event we don't need a pres context anyway so we just pass
2718 // null as the pres context all the time here.
2720 nsEventDispatcher::Dispatch(content, nsnull, &event, nsnull, &status);
2724 return NS_OK;
2727 nsresult
2728 nsGlobalWindow::DispatchDOMEvent(nsEvent* aEvent,
2729 nsIDOMEvent* aDOMEvent,
2730 nsPresContext* aPresContext,
2731 nsEventStatus* aEventStatus)
2733 return
2734 nsEventDispatcher::DispatchDOMEvent(static_cast<nsPIDOMWindow*>(this),
2735 aEvent, aDOMEvent, aPresContext,
2736 aEventStatus);
2739 void
2740 nsGlobalWindow::OnFinalize(PRUint32 aLangID, void *aObject)
2742 NS_ASSERTION(aLangID == nsIProgrammingLanguage::JAVASCRIPT,
2743 "We don't support this language ID");
2745 if (aObject == mJSObject) {
2746 mJSObject = nsnull;
2750 void
2751 nsGlobalWindow::SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts)
2753 FORWARD_TO_INNER_VOID(SetScriptsEnabled, (aEnabled, aFireTimeouts));
2755 if (aEnabled && aFireTimeouts) {
2756 // Scripts are enabled (again?) on this context, run timeouts that
2757 // fired on this context while scripts were disabled.
2758 void (nsGlobalWindow::*run)() = &nsGlobalWindow::RunTimeout;
2759 NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, run));
2763 nsresult
2764 nsGlobalWindow::SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin)
2766 FORWARD_TO_OUTER(SetArguments, (aArguments, aOrigin),
2767 NS_ERROR_NOT_INITIALIZED);
2769 // Hold on to the arguments so that we can re-set them once the next
2770 // document is loaded.
2771 mArguments = aArguments;
2772 mArgumentsOrigin = aOrigin;
2774 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
2776 if (!mIsModalContentWindow) {
2777 mArgumentsLast = aArguments;
2778 } else if (currentInner) {
2779 // SetArguments() is being called on a modal content window that
2780 // already has an inner window. This can happen when loading
2781 // javascript: URIs as modal content dialogs. In this case, we'll
2782 // set up the dialog window, both inner and outer, before we call
2783 // SetArguments() on the window, so to deal with that, make sure
2784 // here that the arguments are propagated to the inner window.
2786 currentInner->mArguments = aArguments;
2787 currentInner->mArgumentsOrigin = aOrigin;
2790 return currentInner ?
2791 currentInner->DefineArgumentsProperty(aArguments) : NS_OK;
2794 nsresult
2795 nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments)
2797 JSContext *cx;
2798 nsIScriptContext *ctx = GetOuterWindowInternal()->mContext;
2799 NS_ENSURE_TRUE(aArguments && ctx &&
2800 (cx = (JSContext *)ctx->GetNativeContext()),
2801 NS_ERROR_NOT_INITIALIZED);
2803 if (mIsModalContentWindow) {
2804 // Modal content windows don't have an "arguments" property, they
2805 // have a "dialogArguments" property which is handled
2806 // separately. See nsWindowSH::NewResolve().
2808 return NS_OK;
2811 return GetContextInternal()->SetProperty(mJSObject, "arguments", aArguments);
2814 //*****************************************************************************
2815 // nsGlobalWindow::nsIScriptObjectPrincipal
2816 //*****************************************************************************
2818 nsIPrincipal*
2819 nsGlobalWindow::GetPrincipal()
2821 if (mDoc) {
2822 // If we have a document, get the principal from the document
2823 return mDoc->NodePrincipal();
2826 if (mDocumentPrincipal) {
2827 return mDocumentPrincipal;
2830 // If we don't have a principal and we don't have a document we
2831 // ask the parent window for the principal. This can happen when
2832 // loading a frameset that has a <frame src="javascript:xxx">, in
2833 // that case the global window is used in JS before we've loaded
2834 // a document into the window.
2836 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2837 do_QueryInterface(GetParentInternal());
2839 if (objPrincipal) {
2840 return objPrincipal->GetPrincipal();
2843 return nsnull;
2846 //*****************************************************************************
2847 // nsGlobalWindow::nsIDOMWindow
2848 //*****************************************************************************
2850 NS_IMETHODIMP
2851 nsGlobalWindow::GetDocument(nsIDOMDocument** aDocument)
2853 // This method *should* forward calls to the outer window, but since
2854 // there's nothing here that *depends* on anything in the outer
2855 // (GetDocShell() eliminates that dependency), we won't do that to
2856 // avoid the extra virtual function call.
2858 // lazily instantiate an about:blank document if necessary, and if
2859 // we have what it takes to do so. Note that domdoc here is the same
2860 // thing as our mDocument, but we don't have to explicitly set the
2861 // member variable because the docshell has already called
2862 // SetNewDocument().
2863 nsIDocShell *docShell;
2864 if (!mDocument && (docShell = GetDocShell()))
2865 nsCOMPtr<nsIDOMDocument> domdoc(do_GetInterface(docShell));
2867 NS_IF_ADDREF(*aDocument = mDocument);
2869 return NS_OK;
2872 //*****************************************************************************
2873 // nsGlobalWindow::nsIDOMWindowInternal
2874 //*****************************************************************************
2876 NS_IMETHODIMP
2877 nsGlobalWindow::GetWindow(nsIDOMWindowInternal** aWindow)
2879 FORWARD_TO_OUTER(GetWindow, (aWindow), NS_ERROR_NOT_INITIALIZED);
2881 *aWindow = static_cast<nsIDOMWindowInternal *>(this);
2882 NS_ADDREF(*aWindow);
2883 return NS_OK;
2886 NS_IMETHODIMP
2887 nsGlobalWindow::GetSelf(nsIDOMWindowInternal** aWindow)
2889 FORWARD_TO_OUTER(GetSelf, (aWindow), NS_ERROR_NOT_INITIALIZED);
2891 *aWindow = static_cast<nsIDOMWindowInternal *>(this);
2892 NS_ADDREF(*aWindow);
2893 return NS_OK;
2896 NS_IMETHODIMP
2897 nsGlobalWindow::GetNavigator(nsIDOMNavigator** aNavigator)
2899 FORWARD_TO_OUTER(GetNavigator, (aNavigator), NS_ERROR_NOT_INITIALIZED);
2901 *aNavigator = nsnull;
2903 if (!mNavigator) {
2904 mNavigator = new nsNavigator(mDocShell);
2905 if (!mNavigator) {
2906 return NS_ERROR_OUT_OF_MEMORY;
2910 NS_ADDREF(*aNavigator = mNavigator);
2912 return NS_OK;
2915 NS_IMETHODIMP
2916 nsGlobalWindow::GetScreen(nsIDOMScreen** aScreen)
2918 FORWARD_TO_OUTER(GetScreen, (aScreen), NS_ERROR_NOT_INITIALIZED);
2920 *aScreen = nsnull;
2922 if (!mScreen && mDocShell) {
2923 mScreen = new nsScreen(mDocShell);
2924 if (!mScreen) {
2925 return NS_ERROR_OUT_OF_MEMORY;
2929 NS_IF_ADDREF(*aScreen = mScreen);
2931 return NS_OK;
2934 NS_IMETHODIMP
2935 nsGlobalWindow::GetHistory(nsIDOMHistory** aHistory)
2937 FORWARD_TO_INNER(GetHistory, (aHistory), NS_ERROR_NOT_INITIALIZED);
2939 *aHistory = nsnull;
2941 if (!mHistory) {
2942 mHistory = new nsHistory(this);
2943 if (!mHistory) {
2944 return NS_ERROR_OUT_OF_MEMORY;
2948 NS_IF_ADDREF(*aHistory = mHistory);
2949 return NS_OK;
2952 NS_IMETHODIMP
2953 nsGlobalWindow::GetParent(nsIDOMWindow** aParent)
2955 FORWARD_TO_OUTER(GetParent, (aParent), NS_ERROR_NOT_INITIALIZED);
2957 *aParent = nsnull;
2958 if (!mDocShell)
2959 return NS_OK;
2961 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
2962 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
2964 nsCOMPtr<nsIDocShellTreeItem> parent;
2965 docShellAsItem->GetSameTypeParent(getter_AddRefs(parent));
2967 if (parent) {
2968 nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(parent));
2969 NS_ENSURE_SUCCESS(CallQueryInterface(globalObject.get(), aParent),
2970 NS_ERROR_FAILURE);
2972 else {
2973 *aParent = static_cast<nsIDOMWindowInternal *>(this);
2974 NS_ADDREF(*aParent);
2976 return NS_OK;
2979 NS_IMETHODIMP
2980 nsGlobalWindow::GetTop(nsIDOMWindow** aTop)
2982 FORWARD_TO_OUTER(GetTop, (aTop), NS_ERROR_NOT_INITIALIZED);
2984 *aTop = nsnull;
2985 if (mDocShell) {
2986 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
2987 nsCOMPtr<nsIDocShellTreeItem> root;
2988 docShellAsItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
2990 if (root) {
2991 nsCOMPtr<nsIDOMWindow> top(do_GetInterface(root));
2992 top.swap(*aTop);
2996 return NS_OK;
2999 NS_IMETHODIMP
3000 nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
3002 FORWARD_TO_OUTER(GetContent, (aContent), NS_ERROR_NOT_INITIALIZED);
3004 *aContent = nsnull;
3006 nsCOMPtr<nsIDocShellTreeItem> primaryContent;
3008 if (!nsContentUtils::IsCallerChrome()) {
3009 // If we're called by non-chrome code, make sure we don't return
3010 // the primary content window if the calling tab is hidden. In
3011 // such a case we return the same-type root in the hidden tab,
3012 // which is "good enough", for now.
3013 nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mDocShell));
3015 if (baseWin) {
3016 PRBool visible = PR_FALSE;
3017 baseWin->GetVisibility(&visible);
3019 if (!visible) {
3020 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
3022 treeItem->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));
3027 if (!primaryContent) {
3028 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
3029 GetTreeOwner(getter_AddRefs(treeOwner));
3030 NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
3032 treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
3035 nsCOMPtr<nsIDOMWindowInternal> domWindow(do_GetInterface(primaryContent));
3036 NS_IF_ADDREF(*aContent = domWindow);
3038 return NS_OK;
3041 NS_IMETHODIMP
3042 nsGlobalWindow::GetPrompter(nsIPrompt** aPrompt)
3044 FORWARD_TO_OUTER(GetPrompter, (aPrompt), NS_ERROR_NOT_INITIALIZED);
3046 if (!mDocShell)
3047 return NS_ERROR_FAILURE;
3049 nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
3050 NS_ENSURE_TRUE(prompter, NS_ERROR_NO_INTERFACE);
3052 NS_ADDREF(*aPrompt = prompter);
3053 return NS_OK;
3056 NS_IMETHODIMP
3057 nsGlobalWindow::GetMenubar(nsIDOMBarProp** aMenubar)
3059 FORWARD_TO_OUTER(GetMenubar, (aMenubar), NS_ERROR_NOT_INITIALIZED);
3061 *aMenubar = nsnull;
3063 if (!mMenubar) {
3064 mMenubar = new nsMenubarProp();
3065 if (!mMenubar) {
3066 return NS_ERROR_OUT_OF_MEMORY;
3069 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3070 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3072 mMenubar->SetWebBrowserChrome(browserChrome);
3075 NS_ADDREF(*aMenubar = mMenubar);
3077 return NS_OK;
3080 NS_IMETHODIMP
3081 nsGlobalWindow::GetToolbar(nsIDOMBarProp** aToolbar)
3083 FORWARD_TO_OUTER(GetToolbar, (aToolbar), NS_ERROR_NOT_INITIALIZED);
3085 *aToolbar = nsnull;
3087 if (!mToolbar) {
3088 mToolbar = new nsToolbarProp();
3089 if (!mToolbar) {
3090 return NS_ERROR_OUT_OF_MEMORY;
3093 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3094 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3096 mToolbar->SetWebBrowserChrome(browserChrome);
3099 NS_ADDREF(*aToolbar = mToolbar);
3101 return NS_OK;
3104 NS_IMETHODIMP
3105 nsGlobalWindow::GetLocationbar(nsIDOMBarProp** aLocationbar)
3107 FORWARD_TO_OUTER(GetLocationbar, (aLocationbar), NS_ERROR_NOT_INITIALIZED);
3109 *aLocationbar = nsnull;
3111 if (!mLocationbar) {
3112 mLocationbar = new nsLocationbarProp();
3113 if (!mLocationbar) {
3114 return NS_ERROR_OUT_OF_MEMORY;
3117 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3118 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3120 mLocationbar->SetWebBrowserChrome(browserChrome);
3123 NS_ADDREF(*aLocationbar = mLocationbar);
3125 return NS_OK;
3128 NS_IMETHODIMP
3129 nsGlobalWindow::GetPersonalbar(nsIDOMBarProp** aPersonalbar)
3131 FORWARD_TO_OUTER(GetPersonalbar, (aPersonalbar), NS_ERROR_NOT_INITIALIZED);
3133 *aPersonalbar = nsnull;
3135 if (!mPersonalbar) {
3136 mPersonalbar = new nsPersonalbarProp();
3137 if (!mPersonalbar) {
3138 return NS_ERROR_OUT_OF_MEMORY;
3141 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3142 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3144 mPersonalbar->SetWebBrowserChrome(browserChrome);
3147 NS_ADDREF(*aPersonalbar = mPersonalbar);
3149 return NS_OK;
3152 NS_IMETHODIMP
3153 nsGlobalWindow::GetStatusbar(nsIDOMBarProp** aStatusbar)
3155 FORWARD_TO_OUTER(GetStatusbar, (aStatusbar), NS_ERROR_NOT_INITIALIZED);
3157 *aStatusbar = nsnull;
3159 if (!mStatusbar) {
3160 mStatusbar = new nsStatusbarProp();
3161 if (!mStatusbar) {
3162 return NS_ERROR_OUT_OF_MEMORY;
3165 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3166 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3168 mStatusbar->SetWebBrowserChrome(browserChrome);
3171 NS_ADDREF(*aStatusbar = mStatusbar);
3173 return NS_OK;
3176 NS_IMETHODIMP
3177 nsGlobalWindow::GetScrollbars(nsIDOMBarProp** aScrollbars)
3179 FORWARD_TO_OUTER(GetScrollbars, (aScrollbars), NS_ERROR_NOT_INITIALIZED);
3181 *aScrollbars = nsnull;
3183 if (!mScrollbars) {
3184 mScrollbars = new nsScrollbarsProp(this);
3185 if (!mScrollbars) {
3186 return NS_ERROR_OUT_OF_MEMORY;
3189 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3190 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3192 mScrollbars->SetWebBrowserChrome(browserChrome);
3195 NS_ADDREF(*aScrollbars = mScrollbars);
3197 return NS_OK;
3200 NS_IMETHODIMP
3201 nsGlobalWindow::GetClosed(PRBool* aClosed)
3203 FORWARD_TO_OUTER(GetClosed, (aClosed), NS_ERROR_NOT_INITIALIZED);
3205 // If someone called close(), or if we don't have a docshell, we're
3206 // closed.
3207 *aClosed = mIsClosed || !mDocShell;
3209 return NS_OK;
3212 NS_IMETHODIMP
3213 nsGlobalWindow::GetFrames(nsIDOMWindowCollection** aFrames)
3215 FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
3217 *aFrames = nsnull;
3219 if (!mFrames && mDocShell) {
3220 mFrames = new nsDOMWindowList(mDocShell);
3221 if (!mFrames) {
3222 return NS_ERROR_OUT_OF_MEMORY;
3226 *aFrames = static_cast<nsIDOMWindowCollection *>(mFrames);
3227 NS_IF_ADDREF(*aFrames);
3228 return NS_OK;
3231 NS_IMETHODIMP
3232 nsGlobalWindow::GetApplicationCache(nsIDOMOfflineResourceList **aApplicationCache)
3234 FORWARD_TO_INNER(GetApplicationCache, (aApplicationCache), NS_ERROR_UNEXPECTED);
3236 NS_ENSURE_ARG_POINTER(aApplicationCache);
3238 if (!mApplicationCache) {
3239 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(GetDocShell()));
3240 if (!webNav) {
3241 return NS_ERROR_FAILURE;
3244 nsCOMPtr<nsIURI> uri;
3245 nsresult rv = webNav->GetCurrentURI(getter_AddRefs(uri));
3246 NS_ENSURE_SUCCESS(rv, rv);
3248 nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
3249 nsCOMPtr<nsIURI> manifestURI;
3250 nsContentUtils::GetOfflineAppManifest(doc, getter_AddRefs(manifestURI));
3252 nsIScriptContext* scriptContext = GetContext();
3253 NS_ENSURE_STATE(scriptContext);
3255 nsRefPtr<nsDOMOfflineResourceList> applicationCache =
3256 new nsDOMOfflineResourceList(manifestURI, uri, this, scriptContext);
3257 NS_ENSURE_TRUE(applicationCache, NS_ERROR_OUT_OF_MEMORY);
3259 applicationCache->Init();
3261 mApplicationCache = applicationCache;
3264 NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
3266 return NS_OK;
3269 NS_IMETHODIMP
3270 nsGlobalWindow::CreateBlobURL(nsIDOMBlob* aBlob, nsAString& aURL)
3272 return NS_ERROR_NOT_IMPLEMENTED;
3275 NS_IMETHODIMP
3276 nsGlobalWindow::RevokeBlobURL(const nsAString& aURL)
3278 return NS_ERROR_NOT_IMPLEMENTED;
3281 NS_IMETHODIMP
3282 nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
3284 #ifdef MOZ_DISABLE_DOMCRYPTO
3285 return NS_ERROR_NOT_IMPLEMENTED;
3286 #else
3287 FORWARD_TO_OUTER(GetCrypto, (aCrypto), NS_ERROR_NOT_INITIALIZED);
3289 if (!mCrypto) {
3290 mCrypto = do_CreateInstance(kCryptoContractID);
3293 NS_IF_ADDREF(*aCrypto = mCrypto);
3295 return NS_OK;
3296 #endif
3299 NS_IMETHODIMP
3300 nsGlobalWindow::GetPkcs11(nsIDOMPkcs11** aPkcs11)
3302 *aPkcs11 = nsnull;
3303 return NS_OK;
3306 NS_IMETHODIMP
3307 nsGlobalWindow::GetControllers(nsIControllers** aResult)
3309 FORWARD_TO_OUTER(GetControllers, (aResult), NS_ERROR_NOT_INITIALIZED);
3311 if (!mControllers) {
3312 nsresult rv;
3313 mControllers = do_CreateInstance(kXULControllersCID, &rv);
3314 NS_ENSURE_SUCCESS(rv, rv);
3316 // Add in the default controller
3317 nsCOMPtr<nsIController> controller = do_CreateInstance(
3318 NS_WINDOWCONTROLLER_CONTRACTID, &rv);
3319 NS_ENSURE_SUCCESS(rv, rv);
3321 mControllers->InsertControllerAt(0, controller);
3322 nsCOMPtr<nsIControllerContext> controllerContext = do_QueryInterface(controller);
3323 if (!controllerContext) return NS_ERROR_FAILURE;
3325 controllerContext->SetCommandContext(static_cast<nsIDOMWindow*>(this));
3328 *aResult = mControllers;
3329 NS_ADDREF(*aResult);
3330 return NS_OK;
3333 NS_IMETHODIMP
3334 nsGlobalWindow::GetOpener(nsIDOMWindowInternal** aOpener)
3336 FORWARD_TO_OUTER(GetOpener, (aOpener), NS_ERROR_NOT_INITIALIZED);
3338 *aOpener = nsnull;
3340 nsCOMPtr<nsPIDOMWindow> opener = do_QueryReferent(mOpener);
3341 if (!opener) {
3342 return NS_OK;
3345 // First, check if we were called from a privileged chrome script
3346 if (nsContentUtils::IsCallerTrustedForRead()) {
3347 NS_ADDREF(*aOpener = opener);
3348 return NS_OK;
3351 nsCOMPtr<nsPIDOMWindow> openerPwin(do_QueryInterface(opener));
3352 if (!openerPwin) {
3353 return NS_OK;
3356 // First, ensure that we're not handing back a chrome window.
3357 nsGlobalWindow *win = static_cast<nsGlobalWindow *>(openerPwin.get());
3358 if (win->IsChromeWindow()) {
3359 return NS_OK;
3362 // We don't want to reveal the opener if the opener is a mail window,
3363 // because opener can be used to spoof the contents of a message (bug 105050).
3364 // So, we look in the opener's root docshell to see if it's a mail window.
3365 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
3366 do_QueryInterface(openerPwin->GetDocShell());
3368 if (docShellAsItem) {
3369 nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
3370 docShellAsItem->GetRootTreeItem(getter_AddRefs(openerRootItem));
3371 nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
3372 if (openerRootDocShell) {
3373 PRUint32 appType;
3374 nsresult rv = openerRootDocShell->GetAppType(&appType);
3375 if (NS_SUCCEEDED(rv) && appType != nsIDocShell::APP_TYPE_MAIL) {
3376 *aOpener = opener;
3381 NS_IF_ADDREF(*aOpener);
3382 return NS_OK;
3385 NS_IMETHODIMP
3386 nsGlobalWindow::SetOpener(nsIDOMWindowInternal* aOpener)
3388 // check if we were called from a privileged chrome script.
3389 // If not, opener is settable only to null.
3390 if (aOpener && !nsContentUtils::IsCallerTrustedForWrite()) {
3391 return NS_OK;
3394 SetOpenerWindow(aOpener, PR_FALSE);
3396 return NS_OK;
3399 NS_IMETHODIMP
3400 nsGlobalWindow::GetStatus(nsAString& aStatus)
3402 FORWARD_TO_OUTER(GetStatus, (aStatus), NS_ERROR_NOT_INITIALIZED);
3404 aStatus = mStatus;
3405 return NS_OK;
3408 NS_IMETHODIMP
3409 nsGlobalWindow::SetStatus(const nsAString& aStatus)
3411 FORWARD_TO_OUTER(SetStatus, (aStatus), NS_ERROR_NOT_INITIALIZED);
3414 * If caller is not chrome and dom.disable_window_status_change is true,
3415 * prevent setting window.status by exiting early
3418 if (!CanSetProperty("dom.disable_window_status_change")) {
3419 return NS_OK;
3422 mStatus = aStatus;
3424 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3425 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3426 if(browserChrome) {
3427 browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
3428 PromiseFlatString(aStatus).get());
3431 return NS_OK;
3434 NS_IMETHODIMP
3435 nsGlobalWindow::GetDefaultStatus(nsAString& aDefaultStatus)
3437 FORWARD_TO_OUTER(GetDefaultStatus, (aDefaultStatus),
3438 NS_ERROR_NOT_INITIALIZED);
3440 aDefaultStatus = mDefaultStatus;
3441 return NS_OK;
3444 NS_IMETHODIMP
3445 nsGlobalWindow::SetDefaultStatus(const nsAString& aDefaultStatus)
3447 FORWARD_TO_OUTER(SetDefaultStatus, (aDefaultStatus),
3448 NS_ERROR_NOT_INITIALIZED);
3451 * If caller is not chrome and dom.disable_window_status_change is true,
3452 * prevent setting window.defaultStatus by exiting early
3455 if (!CanSetProperty("dom.disable_window_status_change")) {
3456 return NS_OK;
3459 mDefaultStatus = aDefaultStatus;
3461 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3462 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3463 if (browserChrome) {
3464 browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT_DEFAULT,
3465 PromiseFlatString(aDefaultStatus).get());
3468 return NS_OK;
3471 NS_IMETHODIMP
3472 nsGlobalWindow::GetName(nsAString& aName)
3474 FORWARD_TO_OUTER(GetName, (aName), NS_ERROR_NOT_INITIALIZED);
3476 nsXPIDLString name;
3477 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3478 if (docShellAsItem)
3479 docShellAsItem->GetName(getter_Copies(name));
3481 aName.Assign(name);
3482 return NS_OK;
3485 NS_IMETHODIMP
3486 nsGlobalWindow::SetName(const nsAString& aName)
3488 FORWARD_TO_OUTER(SetName, (aName), NS_ERROR_NOT_INITIALIZED);
3490 nsresult result = NS_OK;
3491 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3492 if (docShellAsItem)
3493 result = docShellAsItem->SetName(PromiseFlatString(aName).get());
3494 return result;
3497 // Helper functions used by many methods below.
3498 PRInt32
3499 nsGlobalWindow::DevToCSSIntPixels(PRInt32 px)
3501 if (!mDocShell)
3502 return px; // assume 1:1
3504 nsRefPtr<nsPresContext> presContext;
3505 mDocShell->GetPresContext(getter_AddRefs(presContext));
3506 if (!presContext)
3507 return px;
3509 return presContext->DevPixelsToIntCSSPixels(px);
3512 PRInt32
3513 nsGlobalWindow::CSSToDevIntPixels(PRInt32 px)
3515 if (!mDocShell)
3516 return px; // assume 1:1
3518 nsRefPtr<nsPresContext> presContext;
3519 mDocShell->GetPresContext(getter_AddRefs(presContext));
3520 if (!presContext)
3521 return px;
3523 return presContext->CSSPixelsToDevPixels(px);
3526 nsIntSize
3527 nsGlobalWindow::DevToCSSIntPixels(nsIntSize px)
3529 if (!mDocShell)
3530 return px; // assume 1:1
3532 nsRefPtr<nsPresContext> presContext;
3533 mDocShell->GetPresContext(getter_AddRefs(presContext));
3534 if (!presContext)
3535 return px;
3537 return nsIntSize(
3538 presContext->DevPixelsToIntCSSPixels(px.width),
3539 presContext->DevPixelsToIntCSSPixels(px.height));
3542 nsIntSize
3543 nsGlobalWindow::CSSToDevIntPixels(nsIntSize px)
3545 if (!mDocShell)
3546 return px; // assume 1:1
3548 nsRefPtr<nsPresContext> presContext;
3549 mDocShell->GetPresContext(getter_AddRefs(presContext));
3550 if (!presContext)
3551 return px;
3553 return nsIntSize(
3554 presContext->CSSPixelsToDevPixels(px.width),
3555 presContext->CSSPixelsToDevPixels(px.height));
3559 NS_IMETHODIMP
3560 nsGlobalWindow::GetInnerWidth(PRInt32* aInnerWidth)
3562 FORWARD_TO_OUTER(GetInnerWidth, (aInnerWidth), NS_ERROR_NOT_INITIALIZED);
3564 NS_ENSURE_STATE(mDocShell);
3566 EnsureSizeUpToDate();
3568 nsRefPtr<nsPresContext> presContext;
3569 mDocShell->GetPresContext(getter_AddRefs(presContext));
3571 if (presContext) {
3572 nsRect shellArea = presContext->GetVisibleArea();
3573 *aInnerWidth = nsPresContext::AppUnitsToIntCSSPixels(shellArea.width);
3574 } else {
3575 *aInnerWidth = 0;
3578 return NS_OK;
3581 NS_IMETHODIMP
3582 nsGlobalWindow::SetInnerWidth(PRInt32 aInnerWidth)
3584 FORWARD_TO_OUTER(SetInnerWidth, (aInnerWidth), NS_ERROR_NOT_INITIALIZED);
3586 NS_ENSURE_STATE(mDocShell);
3589 * If caller is not chrome and the user has not explicitly exempted the site,
3590 * prevent setting window.innerWidth by exiting early
3592 if (!CanMoveResizeWindows() || IsFrame()) {
3593 return NS_OK;
3596 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&aInnerWidth, nsnull),
3597 NS_ERROR_FAILURE);
3600 nsRefPtr<nsIPresShell> presShell;
3601 mDocShell->GetPresShell(getter_AddRefs(presShell));
3602 nsCOMPtr<nsIPresShell_MOZILLA_2_0_BRANCH> presShell20 =
3603 do_QueryInterface(presShell);
3605 if (presShell20 && presShell20->GetIsViewportOverridden())
3607 nscoord height = 0;
3608 nscoord width = 0;
3610 nsRefPtr<nsPresContext> presContext;
3611 presContext = presShell->GetPresContext();
3613 nsRect shellArea = presContext->GetVisibleArea();
3614 height = shellArea.height;
3615 width = nsPresContext::CSSPixelsToAppUnits(aInnerWidth);
3616 return SetCSSViewportWidthAndHeight(width, height);
3618 else
3620 PRInt32 height = 0;
3621 PRInt32 width = 0;
3623 nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
3624 docShellAsWin->GetSize(&width, &height);
3625 width = CSSToDevIntPixels(aInnerWidth);
3626 return SetDocShellWidthAndHeight(width, height);
3630 NS_IMETHODIMP
3631 nsGlobalWindow::GetInnerHeight(PRInt32* aInnerHeight)
3633 FORWARD_TO_OUTER(GetInnerHeight, (aInnerHeight), NS_ERROR_NOT_INITIALIZED);
3635 NS_ENSURE_STATE(mDocShell);
3637 EnsureSizeUpToDate();
3639 nsRefPtr<nsPresContext> presContext;
3640 mDocShell->GetPresContext(getter_AddRefs(presContext));
3642 if (presContext) {
3643 nsRect shellArea = presContext->GetVisibleArea();
3644 *aInnerHeight = nsPresContext::AppUnitsToIntCSSPixels(shellArea.height);
3645 } else {
3646 *aInnerHeight = 0;
3648 return NS_OK;
3651 NS_IMETHODIMP
3652 nsGlobalWindow::SetInnerHeight(PRInt32 aInnerHeight)
3654 FORWARD_TO_OUTER(SetInnerHeight, (aInnerHeight), NS_ERROR_NOT_INITIALIZED);
3656 NS_ENSURE_STATE(mDocShell);
3659 * If caller is not chrome and the user has not explicitly exempted the site,
3660 * prevent setting window.innerHeight by exiting early
3662 if (!CanMoveResizeWindows() || IsFrame()) {
3663 return NS_OK;
3666 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(nsnull, &aInnerHeight),
3667 NS_ERROR_FAILURE);
3669 nsRefPtr<nsIPresShell> presShell;
3670 mDocShell->GetPresShell(getter_AddRefs(presShell));
3671 nsCOMPtr<nsIPresShell_MOZILLA_2_0_BRANCH> presShell20 =
3672 do_QueryInterface(presShell);
3674 if (presShell20 && presShell20->GetIsViewportOverridden())
3676 nscoord height = 0;
3677 nscoord width = 0;
3679 nsRefPtr<nsPresContext> presContext;
3680 presContext = presShell->GetPresContext();
3682 nsRect shellArea = presContext->GetVisibleArea();
3683 width = shellArea.width;
3684 height = nsPresContext::CSSPixelsToAppUnits(aInnerHeight);
3685 return SetCSSViewportWidthAndHeight(width, height);
3687 else
3689 PRInt32 height = 0;
3690 PRInt32 width = 0;
3692 nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
3693 docShellAsWin->GetSize(&width, &height);
3694 height = CSSToDevIntPixels(aInnerHeight);
3695 return SetDocShellWidthAndHeight(width, height);
3699 nsresult
3700 nsGlobalWindow::GetOuterSize(nsIntSize* aSizeCSSPixels)
3702 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3703 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3704 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3706 nsGlobalWindow* rootWindow =
3707 static_cast<nsGlobalWindow *>(GetPrivateRoot());
3708 if (rootWindow) {
3709 rootWindow->FlushPendingNotifications(Flush_Layout);
3712 nsIntSize sizeDevPixels;
3713 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&sizeDevPixels.width,
3714 &sizeDevPixels.height),
3715 NS_ERROR_FAILURE);
3717 *aSizeCSSPixels = DevToCSSIntPixels(sizeDevPixels);
3718 return NS_OK;
3721 NS_IMETHODIMP
3722 nsGlobalWindow::GetOuterWidth(PRInt32* aOuterWidth)
3724 FORWARD_TO_OUTER(GetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
3726 nsIntSize sizeCSSPixels;
3727 nsresult rv = GetOuterSize(&sizeCSSPixels);
3728 NS_ENSURE_SUCCESS(rv, rv);
3730 *aOuterWidth = sizeCSSPixels.width;
3731 return NS_OK;
3734 NS_IMETHODIMP
3735 nsGlobalWindow::GetOuterHeight(PRInt32* aOuterHeight)
3737 FORWARD_TO_OUTER(GetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
3739 nsIntSize sizeCSSPixels;
3740 nsresult rv = GetOuterSize(&sizeCSSPixels);
3741 NS_ENSURE_SUCCESS(rv, rv);
3743 *aOuterHeight = sizeCSSPixels.height;
3744 return NS_OK;
3747 nsresult
3748 nsGlobalWindow::SetOuterSize(PRInt32 aLengthCSSPixels, PRBool aIsWidth)
3751 * If caller is not chrome and the user has not explicitly exempted the site,
3752 * prevent setting window.outerWidth by exiting early
3755 if (!CanMoveResizeWindows() || IsFrame()) {
3756 return NS_OK;
3759 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3760 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3761 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3763 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(
3764 aIsWidth ? &aLengthCSSPixels : nsnull,
3765 aIsWidth ? nsnull : &aLengthCSSPixels),
3766 NS_ERROR_FAILURE);
3768 PRInt32 width, height;
3769 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&width, &height), NS_ERROR_FAILURE);
3771 PRInt32 lengthDevPixels = CSSToDevIntPixels(aLengthCSSPixels);
3772 if (aIsWidth) {
3773 width = lengthDevPixels;
3774 } else {
3775 height = lengthDevPixels;
3777 return treeOwnerAsWin->SetSize(width, height, PR_TRUE);
3780 NS_IMETHODIMP
3781 nsGlobalWindow::SetOuterWidth(PRInt32 aOuterWidth)
3783 FORWARD_TO_OUTER(SetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
3785 return SetOuterSize(aOuterWidth, PR_TRUE);
3788 NS_IMETHODIMP
3789 nsGlobalWindow::SetOuterHeight(PRInt32 aOuterHeight)
3791 FORWARD_TO_OUTER(SetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
3793 return SetOuterSize(aOuterHeight, PR_FALSE);
3796 NS_IMETHODIMP
3797 nsGlobalWindow::GetScreenX(PRInt32* aScreenX)
3799 FORWARD_TO_OUTER(GetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3801 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3802 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3803 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3805 PRInt32 x, y;
3807 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3808 NS_ERROR_FAILURE);
3810 *aScreenX = DevToCSSIntPixels(x);
3811 return NS_OK;
3814 nsRect
3815 nsGlobalWindow::GetInnerScreenRect()
3817 if (!mDocShell)
3818 return nsRect();
3820 nsGlobalWindow* rootWindow =
3821 static_cast<nsGlobalWindow*>(GetPrivateRoot());
3822 if (rootWindow) {
3823 rootWindow->FlushPendingNotifications(Flush_Layout);
3826 nsCOMPtr<nsIPresShell> presShell;
3827 mDocShell->GetPresShell(getter_AddRefs(presShell));
3828 if (!presShell)
3829 return nsRect();
3830 nsIFrame* rootFrame = presShell->GetRootFrame();
3831 if (!rootFrame)
3832 return nsRect();
3834 return rootFrame->GetScreenRectInAppUnits();
3837 NS_IMETHODIMP
3838 nsGlobalWindow::GetMozInnerScreenX(float* aScreenX)
3840 FORWARD_TO_OUTER(GetMozInnerScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3842 nsRect r = GetInnerScreenRect();
3843 *aScreenX = nsPresContext::AppUnitsToFloatCSSPixels(r.x);
3844 return NS_OK;
3847 NS_IMETHODIMP
3848 nsGlobalWindow::GetMozInnerScreenY(float* aScreenY)
3850 FORWARD_TO_OUTER(GetMozInnerScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
3852 nsRect r = GetInnerScreenRect();
3853 *aScreenY = nsPresContext::AppUnitsToFloatCSSPixels(r.y);
3854 return NS_OK;
3857 NS_IMETHODIMP
3858 nsGlobalWindow::GetMozPaintCount(PRUint64* aResult)
3860 FORWARD_TO_OUTER(GetMozPaintCount, (aResult), NS_ERROR_NOT_INITIALIZED);
3862 *aResult = 0;
3864 if (!mDocShell)
3865 return NS_OK;
3867 nsCOMPtr<nsIPresShell> presShell;
3868 mDocShell->GetPresShell(getter_AddRefs(presShell));
3869 if (!presShell)
3870 return NS_OK;
3872 *aResult = presShell->GetPaintCount();
3873 return NS_OK;
3876 NS_IMETHODIMP
3877 nsGlobalWindow::MozRequestAnimationFrame(nsIAnimationFrameListener* aListener)
3879 FORWARD_TO_INNER(MozRequestAnimationFrame, (aListener),
3880 NS_ERROR_NOT_INITIALIZED);
3882 if (!mDoc) {
3883 return NS_OK;
3886 mDoc->ScheduleBeforePaintEvent(aListener);
3887 return NS_OK;
3890 NS_IMETHODIMP
3891 nsGlobalWindow::GetMozAnimationStartTime(PRInt64 *aTime)
3893 FORWARD_TO_INNER(GetMozAnimationStartTime, (aTime), NS_ERROR_NOT_INITIALIZED);
3895 if (mDoc) {
3896 nsIPresShell* presShell = mDoc->GetShell();
3897 if (presShell) {
3898 *aTime = presShell->GetPresContext()->RefreshDriver()->
3899 MostRecentRefreshEpochTime() / PR_USEC_PER_MSEC;
3900 return NS_OK;
3904 // If all else fails, just be compatible with Date.now()
3905 *aTime = JS_Now() / PR_USEC_PER_MSEC;
3906 return NS_OK;
3909 NS_IMETHODIMP
3910 nsGlobalWindow::SetScreenX(PRInt32 aScreenX)
3912 FORWARD_TO_OUTER(SetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3915 * If caller is not chrome and the user has not explicitly exempted the site,
3916 * prevent setting window.screenX by exiting early
3919 if (!CanMoveResizeWindows() || IsFrame()) {
3920 return NS_OK;
3923 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3924 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3925 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3927 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&aScreenX, nsnull),
3928 NS_ERROR_FAILURE);
3930 PRInt32 x, y;
3931 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3932 NS_ERROR_FAILURE);
3934 x = CSSToDevIntPixels(aScreenX);
3936 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(x, y),
3937 NS_ERROR_FAILURE);
3939 return NS_OK;
3942 NS_IMETHODIMP
3943 nsGlobalWindow::GetScreenY(PRInt32* aScreenY)
3945 FORWARD_TO_OUTER(GetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
3947 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3948 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3949 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3951 PRInt32 x, y;
3953 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3954 NS_ERROR_FAILURE);
3956 *aScreenY = DevToCSSIntPixels(y);
3957 return NS_OK;
3960 NS_IMETHODIMP
3961 nsGlobalWindow::SetScreenY(PRInt32 aScreenY)
3963 FORWARD_TO_OUTER(SetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
3966 * If caller is not chrome and the user has not explicitly exempted the site,
3967 * prevent setting window.screenY by exiting early
3970 if (!CanMoveResizeWindows() || IsFrame()) {
3971 return NS_OK;
3974 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3975 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3976 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3978 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(nsnull, &aScreenY),
3979 NS_ERROR_FAILURE);
3981 PRInt32 x, y;
3982 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3983 NS_ERROR_FAILURE);
3985 y = CSSToDevIntPixels(aScreenY);
3987 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(x, y),
3988 NS_ERROR_FAILURE);
3990 return NS_OK;
3993 // NOTE: Arguments to this function should have values scaled to
3994 // CSS pixels, not device pixels.
3995 nsresult
3996 nsGlobalWindow::CheckSecurityWidthAndHeight(PRInt32* aWidth, PRInt32* aHeight)
3998 #ifdef MOZ_XUL
3999 if (!nsContentUtils::IsCallerTrustedForWrite()) {
4000 // if attempting to resize the window, hide any open popups
4001 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
4002 nsContentUtils::HidePopupsInDocument(doc);
4004 #endif
4006 // This one is easy. Just ensure the variable is greater than 100;
4007 if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
4008 // Check security state for use in determing window dimensions
4010 if (!nsContentUtils::IsCallerTrustedForWrite()) {
4011 //sec check failed
4012 if (aWidth && *aWidth < 100) {
4013 *aWidth = 100;
4015 if (aHeight && *aHeight < 100) {
4016 *aHeight = 100;
4021 return NS_OK;
4024 // NOTE: Arguments to this function should have values in device pixels
4025 nsresult
4026 nsGlobalWindow::SetDocShellWidthAndHeight(PRInt32 aInnerWidth, PRInt32 aInnerHeight)
4028 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
4029 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
4031 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
4032 docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
4033 NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
4035 NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(docShellAsItem, aInnerWidth, aInnerHeight),
4036 NS_ERROR_FAILURE);
4038 return NS_OK;
4041 // NOTE: Arguments to this function should have values in app units
4042 nsresult
4043 nsGlobalWindow::SetCSSViewportWidthAndHeight(nscoord aInnerWidth, nscoord aInnerHeight)
4045 nsRefPtr<nsPresContext> presContext;
4046 mDocShell->GetPresContext(getter_AddRefs(presContext));
4048 nsRect shellArea = presContext->GetVisibleArea();
4049 shellArea.height = aInnerHeight;
4050 shellArea.width = aInnerWidth;
4052 presContext->SetVisibleArea(shellArea);
4053 return NS_OK;
4056 // NOTE: Arguments to this function should have values scaled to
4057 // CSS pixels, not device pixels.
4058 nsresult
4059 nsGlobalWindow::CheckSecurityLeftAndTop(PRInt32* aLeft, PRInt32* aTop)
4061 // This one is harder. We have to get the screen size and window dimensions.
4063 // Check security state for use in determing window dimensions
4065 if (!nsContentUtils::IsCallerTrustedForWrite()) {
4066 #ifdef MOZ_XUL
4067 // if attempting to move the window, hide any open popups
4068 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
4069 nsContentUtils::HidePopupsInDocument(doc);
4070 #endif
4072 nsGlobalWindow* rootWindow =
4073 static_cast<nsGlobalWindow*>(GetPrivateRoot());
4074 if (rootWindow) {
4075 rootWindow->FlushPendingNotifications(Flush_Layout);
4078 nsCOMPtr<nsIBaseWindow> treeOwner;
4079 GetTreeOwner(getter_AddRefs(treeOwner));
4081 nsCOMPtr<nsIDOMScreen> screen;
4082 GetScreen(getter_AddRefs(screen));
4084 if (treeOwner && screen) {
4085 PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
4086 PRInt32 winLeft, winTop, winWidth, winHeight;
4088 // Get the window size
4089 treeOwner->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
4091 // convert those values to CSS pixels
4092 // XXX four separate retrievals of the prescontext
4093 winLeft = DevToCSSIntPixels(winLeft);
4094 winTop = DevToCSSIntPixels(winTop);
4095 winWidth = DevToCSSIntPixels(winWidth);
4096 winHeight = DevToCSSIntPixels(winHeight);
4098 // Get the screen dimensions
4099 // XXX This should use nsIScreenManager once it's fully fleshed out.
4100 screen->GetAvailLeft(&screenLeft);
4101 screen->GetAvailWidth(&screenWidth);
4102 screen->GetAvailHeight(&screenHeight);
4103 #if defined(XP_MAC) || defined(XP_MACOSX)
4104 /* The mac's coordinate system is different from the assumed Windows'
4105 system. It offsets by the height of the menubar so that a window
4106 placed at (0,0) will be entirely visible. Unfortunately that
4107 correction is made elsewhere (in Widget) and the meaning of
4108 the Avail... coordinates is overloaded. Here we allow a window
4109 to be placed at (0,0) because it does make sense to do so.
4111 screen->GetTop(&screenTop);
4112 #else
4113 screen->GetAvailTop(&screenTop);
4114 #endif
4116 if (aLeft) {
4117 if (screenLeft+screenWidth < *aLeft+winWidth)
4118 *aLeft = screenLeft+screenWidth - winWidth;
4119 if (screenLeft > *aLeft)
4120 *aLeft = screenLeft;
4122 if (aTop) {
4123 if (screenTop+screenHeight < *aTop+winHeight)
4124 *aTop = screenTop+screenHeight - winHeight;
4125 if (screenTop > *aTop)
4126 *aTop = screenTop;
4128 } else {
4129 if (aLeft)
4130 *aLeft = 0;
4131 if (aTop)
4132 *aTop = 0;
4136 return NS_OK;
4139 NS_IMETHODIMP
4140 nsGlobalWindow::GetPageXOffset(PRInt32* aPageXOffset)
4142 return GetScrollX(aPageXOffset);
4145 NS_IMETHODIMP
4146 nsGlobalWindow::GetPageYOffset(PRInt32* aPageYOffset)
4148 return GetScrollY(aPageYOffset);
4151 nsresult
4152 nsGlobalWindow::GetScrollMaxXY(PRInt32* aScrollMaxX, PRInt32* aScrollMaxY)
4154 FORWARD_TO_OUTER(GetScrollMaxXY, (aScrollMaxX, aScrollMaxY),
4155 NS_ERROR_NOT_INITIALIZED);
4157 FlushPendingNotifications(Flush_Layout);
4158 nsIScrollableFrame *sf = GetScrollFrame();
4159 if (!sf)
4160 return NS_OK;
4162 nsRect scrollRange = sf->GetScrollRange();
4164 if (aScrollMaxX)
4165 *aScrollMaxX = NS_MAX(0,
4166 (PRInt32)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.XMost())));
4167 if (aScrollMaxY)
4168 *aScrollMaxY = NS_MAX(0,
4169 (PRInt32)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.YMost())));
4171 return NS_OK;
4174 NS_IMETHODIMP
4175 nsGlobalWindow::GetScrollMaxX(PRInt32* aScrollMaxX)
4177 NS_ENSURE_ARG_POINTER(aScrollMaxX);
4178 *aScrollMaxX = 0;
4179 return GetScrollMaxXY(aScrollMaxX, nsnull);
4182 NS_IMETHODIMP
4183 nsGlobalWindow::GetScrollMaxY(PRInt32* aScrollMaxY)
4185 NS_ENSURE_ARG_POINTER(aScrollMaxY);
4186 *aScrollMaxY = 0;
4187 return GetScrollMaxXY(nsnull, aScrollMaxY);
4190 nsresult
4191 nsGlobalWindow::GetScrollXY(PRInt32* aScrollX, PRInt32* aScrollY,
4192 PRBool aDoFlush)
4194 FORWARD_TO_OUTER(GetScrollXY, (aScrollX, aScrollY, aDoFlush),
4195 NS_ERROR_NOT_INITIALIZED);
4197 if (aDoFlush) {
4198 FlushPendingNotifications(Flush_Layout);
4199 } else {
4200 EnsureSizeUpToDate();
4203 nsIScrollableFrame *sf = GetScrollFrame();
4204 if (!sf)
4205 return NS_OK;
4207 nsPoint scrollPos = sf->GetScrollPosition();
4208 if (scrollPos != nsPoint(0,0) && !aDoFlush) {
4209 // Oh, well. This is the expensive case -- the window is scrolled and we
4210 // didn't actually flush yet. Repeat, but with a flush, since the content
4211 // may get shorter and hence our scroll position may decrease.
4212 return GetScrollXY(aScrollX, aScrollY, PR_TRUE);
4215 if (aScrollX)
4216 *aScrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x);
4217 if (aScrollY)
4218 *aScrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
4220 return NS_OK;
4223 NS_IMETHODIMP
4224 nsGlobalWindow::GetScrollX(PRInt32* aScrollX)
4226 NS_ENSURE_ARG_POINTER(aScrollX);
4227 *aScrollX = 0;
4228 return GetScrollXY(aScrollX, nsnull, PR_FALSE);
4231 NS_IMETHODIMP
4232 nsGlobalWindow::GetScrollY(PRInt32* aScrollY)
4234 NS_ENSURE_ARG_POINTER(aScrollY);
4235 *aScrollY = 0;
4236 return GetScrollXY(nsnull, aScrollY, PR_FALSE);
4239 NS_IMETHODIMP
4240 nsGlobalWindow::GetLength(PRUint32* aLength)
4242 nsCOMPtr<nsIDOMWindowCollection> frames;
4243 if (NS_SUCCEEDED(GetFrames(getter_AddRefs(frames))) && frames) {
4244 return frames->GetLength(aLength);
4246 return NS_ERROR_FAILURE;
4249 PRBool
4250 nsGlobalWindow::DispatchCustomEvent(const char *aEventName)
4252 PRBool defaultActionEnabled = PR_TRUE;
4253 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
4254 nsContentUtils::DispatchTrustedEvent(doc,
4255 static_cast<nsIScriptGlobalObject*>(this),
4256 NS_ConvertASCIItoUTF16(aEventName),
4257 PR_TRUE, PR_TRUE, &defaultActionEnabled);
4259 return defaultActionEnabled;
4262 static already_AddRefed<nsIDocShellTreeItem>
4263 GetCallerDocShellTreeItem()
4265 JSContext *cx = nsContentUtils::GetCurrentJSContext();
4266 nsIDocShellTreeItem *callerItem = nsnull;
4268 if (cx) {
4269 nsCOMPtr<nsIWebNavigation> callerWebNav =
4270 do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
4272 if (callerWebNav) {
4273 CallQueryInterface(callerWebNav, &callerItem);
4277 return callerItem;
4280 PRBool
4281 nsGlobalWindow::WindowExists(const nsAString& aName,
4282 PRBool aLookForCallerOnJSStack)
4284 NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
4285 NS_PRECONDITION(mDocShell, "Must have docshell");
4287 nsCOMPtr<nsIDocShellTreeItem> caller;
4288 if (aLookForCallerOnJSStack) {
4289 caller = GetCallerDocShellTreeItem();
4292 nsCOMPtr<nsIDocShellTreeItem> docShell = do_QueryInterface(mDocShell);
4293 NS_ASSERTION(docShell,
4294 "Docshell doesn't implement nsIDocShellTreeItem?");
4296 if (!caller) {
4297 caller = docShell;
4300 nsCOMPtr<nsIDocShellTreeItem> namedItem;
4301 docShell->FindItemWithName(PromiseFlatString(aName).get(), nsnull, caller,
4302 getter_AddRefs(namedItem));
4303 return namedItem != nsnull;
4306 already_AddRefed<nsIWidget>
4307 nsGlobalWindow::GetMainWidget()
4309 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4310 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4312 nsIWidget *widget = nsnull;
4314 if (treeOwnerAsWin) {
4315 treeOwnerAsWin->GetMainWidget(&widget);
4318 return widget;
4321 nsIWidget*
4322 nsGlobalWindow::GetNearestWidget()
4324 nsIDocShell* docShell = GetDocShell();
4325 NS_ENSURE_TRUE(docShell, nsnull);
4326 nsCOMPtr<nsIPresShell> presShell;
4327 docShell->GetPresShell(getter_AddRefs(presShell));
4328 NS_ENSURE_TRUE(presShell, nsnull);
4329 nsIFrame* rootFrame = presShell->GetRootFrame();
4330 NS_ENSURE_TRUE(rootFrame, nsnull);
4331 return rootFrame->GetView()->GetNearestWidget(nsnull);
4334 NS_IMETHODIMP
4335 nsGlobalWindow::SetFullScreen(PRBool aFullScreen)
4337 FORWARD_TO_OUTER(SetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
4339 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
4341 PRBool rootWinFullScreen;
4342 GetFullScreen(&rootWinFullScreen);
4343 // Only chrome can change our fullScreen mode.
4344 if (aFullScreen == rootWinFullScreen ||
4345 !nsContentUtils::IsCallerTrustedForWrite()) {
4346 return NS_OK;
4349 // SetFullScreen needs to be called on the root window, so get that
4350 // via the DocShell tree, and if we are not already the root,
4351 // call SetFullScreen on that window instead.
4352 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
4353 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4354 treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
4355 nsCOMPtr<nsIDOMWindowInternal> window = do_GetInterface(rootItem);
4356 if (!window)
4357 return NS_ERROR_FAILURE;
4358 if (rootItem != treeItem)
4359 return window->SetFullScreen(aFullScreen);
4361 // make sure we don't try to set full screen on a non-chrome window,
4362 // which might happen in embedding world
4363 PRInt32 itemType;
4364 treeItem->GetItemType(&itemType);
4365 if (itemType != nsIDocShellTreeItem::typeChrome)
4366 return NS_ERROR_FAILURE;
4368 // If we are already in full screen mode, just return.
4369 if (mFullScreen == aFullScreen)
4370 return NS_OK;
4372 // dispatch a "fullscreen" DOM event so that XUL apps can
4373 // respond visually if we are kicked into full screen mode
4374 if (!DispatchCustomEvent("fullscreen")) {
4375 return NS_OK;
4378 // Prevent chrome documents which are still loading from resizing
4379 // the window after we set fullscreen mode.
4380 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4381 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4382 nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwnerAsWin));
4383 if (aFullScreen && xulWin) {
4384 xulWin->SetIntrinsicallySized(PR_FALSE);
4387 // Set this before so if widget sends an event indicating its
4388 // gone full screen, the state trap above works.
4389 mFullScreen = aFullScreen;
4391 nsCOMPtr<nsIWidget> widget = GetMainWidget();
4392 if (widget)
4393 widget->MakeFullScreen(aFullScreen);
4395 return NS_OK;
4398 NS_IMETHODIMP
4399 nsGlobalWindow::GetFullScreen(PRBool* aFullScreen)
4401 FORWARD_TO_OUTER(GetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
4403 // Get the fullscreen value of the root window, to always have the value
4404 // accurate, even when called from content.
4405 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
4406 if (treeItem) {
4407 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4408 treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
4409 if (rootItem != treeItem) {
4410 nsCOMPtr<nsIDOMWindowInternal> window = do_GetInterface(rootItem);
4411 if (window)
4412 return window->GetFullScreen(aFullScreen);
4416 // We are the root window, or something went wrong. Return our internal value.
4417 *aFullScreen = mFullScreen;
4418 return NS_OK;
4421 PRBool
4422 nsGlobalWindow::DOMWindowDumpEnabled()
4424 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
4425 // In optimized builds we check a pref that controls if we should
4426 // enable output from dump() or not, in debug builds it's always
4427 // enabled.
4428 return gDOMWindowDumpEnabled;
4429 #else
4430 return PR_TRUE;
4431 #endif
4434 NS_IMETHODIMP
4435 nsGlobalWindow::Dump(const nsAString& aStr)
4437 if (!DOMWindowDumpEnabled()) {
4438 return NS_OK;
4441 char *cstr = ToNewUTF8String(aStr);
4443 #if defined(XP_MAC) || defined(XP_MACOSX)
4444 // have to convert \r to \n so that printing to the console works
4445 char *c = cstr, *cEnd = cstr + strlen(cstr);
4446 while (c < cEnd) {
4447 if (*c == '\r')
4448 *c = '\n';
4449 c++;
4451 #endif
4453 if (cstr) {
4454 FILE *fp = gDumpFile ? gDumpFile : stdout;
4455 fputs(cstr, fp);
4456 fflush(fp);
4457 nsMemory::Free(cstr);
4460 return NS_OK;
4463 void
4464 nsGlobalWindow::EnsureReflowFlushAndPaint()
4466 NS_ASSERTION(IsOuterWindow(), "EnsureReflowFlushAndPaint() must be called on"
4467 "the outer window");
4468 NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no "
4469 "docshell!");
4471 if (!mDocShell)
4472 return;
4474 nsCOMPtr<nsIPresShell> presShell;
4475 mDocShell->GetPresShell(getter_AddRefs(presShell));
4477 if (!presShell)
4478 return;
4480 // Flush pending reflows.
4481 if (mDoc) {
4482 mDoc->FlushPendingNotifications(Flush_Layout);
4485 // Unsuppress painting.
4486 presShell->UnsuppressPainting();
4489 NS_IMETHODIMP
4490 nsGlobalWindow::GetTextZoom(float *aZoom)
4492 FORWARD_TO_OUTER(GetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
4494 if (mDocShell) {
4495 nsCOMPtr<nsIContentViewer> contentViewer;
4496 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
4497 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
4499 if (markupViewer) {
4500 return markupViewer->GetTextZoom(aZoom);
4503 return NS_ERROR_FAILURE;
4506 NS_IMETHODIMP
4507 nsGlobalWindow::SetTextZoom(float aZoom)
4509 FORWARD_TO_OUTER(SetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
4511 if (mDocShell) {
4512 nsCOMPtr<nsIContentViewer> contentViewer;
4513 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
4514 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
4516 if (markupViewer)
4517 return markupViewer->SetTextZoom(aZoom);
4519 return NS_ERROR_FAILURE;
4522 // static
4523 void
4524 nsGlobalWindow::MakeScriptDialogTitle(nsAString &aOutTitle)
4526 aOutTitle.Truncate();
4528 // Try to get a host from the running principal -- this will do the
4529 // right thing for javascript: and data: documents.
4531 nsresult rv = NS_OK;
4532 NS_ASSERTION(nsContentUtils::GetSecurityManager(),
4533 "Global Window has no security manager!");
4534 if (nsContentUtils::GetSecurityManager()) {
4535 nsCOMPtr<nsIPrincipal> principal;
4536 rv = nsContentUtils::GetSecurityManager()->
4537 GetSubjectPrincipal(getter_AddRefs(principal));
4539 if (NS_SUCCEEDED(rv) && principal) {
4540 nsCOMPtr<nsIURI> uri;
4541 rv = principal->GetURI(getter_AddRefs(uri));
4543 if (NS_SUCCEEDED(rv) && uri) {
4544 // remove user:pass for privacy and spoof prevention
4546 nsCOMPtr<nsIURIFixup> fixup(do_GetService(NS_URIFIXUP_CONTRACTID));
4547 if (fixup) {
4548 nsCOMPtr<nsIURI> fixedURI;
4549 rv = fixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
4550 if (NS_SUCCEEDED(rv) && fixedURI) {
4551 nsCAutoString host;
4552 fixedURI->GetHost(host);
4554 if (!host.IsEmpty()) {
4555 // if this URI has a host we'll show it. For other
4556 // schemes (e.g. file:) we fall back to the localized
4557 // generic string
4559 nsCAutoString prepath;
4560 fixedURI->GetPrePath(prepath);
4562 NS_ConvertUTF8toUTF16 ucsPrePath(prepath);
4563 const PRUnichar *formatStrings[] = { ucsPrePath.get() };
4564 nsXPIDLString tempString;
4565 nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4566 "ScriptDlgHeading",
4567 formatStrings, NS_ARRAY_LENGTH(formatStrings),
4568 tempString);
4569 aOutTitle = tempString;
4575 else { // failed to get subject principal
4576 NS_WARNING("No script principal? Who is calling alert/confirm/prompt?!");
4580 if (aOutTitle.IsEmpty()) {
4581 // We didn't find a host so use the generic heading
4582 nsXPIDLString tempString;
4583 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4584 "ScriptDlgGenericHeading",
4585 tempString);
4586 aOutTitle = tempString;
4589 // Just in case
4590 if (aOutTitle.IsEmpty()) {
4591 NS_WARNING("could not get ScriptDlgGenericHeading string from string bundle");
4592 aOutTitle.AssignLiteral("[Script]");
4596 // static
4597 PRBool
4598 nsGlobalWindow::CanMoveResizeWindows()
4600 if (!CanSetProperty("dom.disable_window_move_resize"))
4601 return PR_FALSE;
4603 if (gMouseDown && !gDragServiceDisabled) {
4604 nsCOMPtr<nsIDragService> ds =
4605 do_GetService("@mozilla.org/widget/dragservice;1");
4606 if (ds) {
4607 gDragServiceDisabled = PR_TRUE;
4608 ds->Suppress();
4611 return PR_TRUE;
4614 NS_IMETHODIMP
4615 nsGlobalWindow::Alert(const nsAString& aString)
4617 FORWARD_TO_OUTER(Alert, (aString), NS_ERROR_NOT_INITIALIZED);
4619 if (AreDialogsBlocked())
4620 return NS_ERROR_NOT_AVAILABLE;
4622 // We have to capture this now so as not to get confused with the
4623 // popup state we push next
4624 PRBool shouldEnableDisableDialog = DialogOpenAttempted();
4626 // Reset popup state while opening a modal dialog, and firing events
4627 // about the dialog, to prevent the current state from being active
4628 // the whole time a modal dialog is open.
4629 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
4631 // Special handling for alert(null) in JS for backwards
4632 // compatibility.
4634 NS_NAMED_LITERAL_STRING(null_str, "null");
4636 const nsAString *str = DOMStringIsNull(aString) ? &null_str : &aString;
4638 // Before bringing up the window, unsuppress painting and flush
4639 // pending reflows.
4640 EnsureReflowFlushAndPaint();
4642 nsAutoString title;
4643 MakeScriptDialogTitle(title);
4645 // Remove non-terminating null characters from the
4646 // string. See bug #310037.
4647 nsAutoString final;
4648 nsContentUtils::StripNullChars(*str, final);
4650 // Check if we're being called at a point where we can't use tab-modal
4651 // prompts, because something doesn't want reentrancy.
4652 PRBool allowTabModal = GetIsTabModalPromptAllowed();
4654 nsresult rv;
4655 nsCOMPtr<nsIPromptFactory> promptFac =
4656 do_GetService("@mozilla.org/prompter;1", &rv);
4657 NS_ENSURE_SUCCESS(rv, rv);
4659 nsCOMPtr<nsIPrompt> prompt;
4660 rv = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
4661 reinterpret_cast<void**>(&prompt));
4662 NS_ENSURE_SUCCESS(rv, rv);
4664 nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
4665 if (promptBag)
4666 promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), allowTabModal);
4668 if (shouldEnableDisableDialog) {
4669 PRBool disallowDialog = PR_FALSE;
4670 nsXPIDLString label;
4671 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4672 "ScriptDialogLabel", label);
4674 rv = prompt->AlertCheck(title.get(), final.get(), label.get(),
4675 &disallowDialog);
4676 if (disallowDialog)
4677 PreventFurtherDialogs();
4678 } else {
4679 rv = prompt->Alert(title.get(), final.get());
4682 return rv;
4685 NS_IMETHODIMP
4686 nsGlobalWindow::Confirm(const nsAString& aString, PRBool* aReturn)
4688 FORWARD_TO_OUTER(Confirm, (aString, aReturn), NS_ERROR_NOT_INITIALIZED);
4690 if (AreDialogsBlocked())
4691 return NS_ERROR_NOT_AVAILABLE;
4693 // We have to capture this now so as not to get confused with the popup state
4694 // we push next
4695 PRBool shouldEnableDisableDialog = DialogOpenAttempted();
4697 // Reset popup state while opening a modal dialog, and firing events
4698 // about the dialog, to prevent the current state from being active
4699 // the whole time a modal dialog is open.
4700 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
4702 *aReturn = PR_FALSE;
4704 // Before bringing up the window, unsuppress painting and flush
4705 // pending reflows.
4706 EnsureReflowFlushAndPaint();
4708 nsAutoString title;
4709 MakeScriptDialogTitle(title);
4711 // Remove non-terminating null characters from the
4712 // string. See bug #310037.
4713 nsAutoString final;
4714 nsContentUtils::StripNullChars(aString, final);
4716 // Check if we're being called at a point where we can't use tab-modal
4717 // prompts, because something doesn't want reentrancy.
4718 PRBool allowTabModal = GetIsTabModalPromptAllowed();
4720 nsresult rv;
4721 nsCOMPtr<nsIPromptFactory> promptFac =
4722 do_GetService("@mozilla.org/prompter;1", &rv);
4723 NS_ENSURE_SUCCESS(rv, rv);
4725 nsCOMPtr<nsIPrompt> prompt;
4726 rv = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
4727 reinterpret_cast<void**>(&prompt));
4728 NS_ENSURE_SUCCESS(rv, rv);
4730 nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
4731 if (promptBag)
4732 promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), allowTabModal);
4734 if (shouldEnableDisableDialog) {
4735 PRBool disallowDialog = PR_FALSE;
4736 nsXPIDLString label;
4737 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4738 "ScriptDialogLabel", label);
4740 rv = prompt->ConfirmCheck(title.get(), final.get(), label.get(),
4741 &disallowDialog, aReturn);
4742 if (disallowDialog)
4743 PreventFurtherDialogs();
4744 } else {
4745 rv = prompt->Confirm(title.get(), final.get(), aReturn);
4748 return rv;
4751 NS_IMETHODIMP
4752 nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
4753 nsAString& aReturn)
4755 FORWARD_TO_OUTER(Prompt, (aMessage, aInitial, aReturn),
4756 NS_ERROR_NOT_INITIALIZED);
4758 SetDOMStringToNull(aReturn);
4760 if (AreDialogsBlocked())
4761 return NS_ERROR_NOT_AVAILABLE;
4763 // We have to capture this now so as not to get confused with the popup state
4764 // we push next
4765 PRBool shouldEnableDisableDialog = DialogOpenAttempted();
4767 // Reset popup state while opening a modal dialog, and firing events
4768 // about the dialog, to prevent the current state from being active
4769 // the whole time a modal dialog is open.
4770 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
4772 // Before bringing up the window, unsuppress painting and flush
4773 // pending reflows.
4774 EnsureReflowFlushAndPaint();
4776 nsAutoString title;
4777 MakeScriptDialogTitle(title);
4779 // Remove non-terminating null characters from the
4780 // string. See bug #310037.
4781 nsAutoString fixedMessage, fixedInitial;
4782 nsContentUtils::StripNullChars(aMessage, fixedMessage);
4783 nsContentUtils::StripNullChars(aInitial, fixedInitial);
4785 // Check if we're being called at a point where we can't use tab-modal
4786 // prompts, because something doesn't want reentrancy.
4787 PRBool allowTabModal = GetIsTabModalPromptAllowed();
4789 nsresult rv;
4790 nsCOMPtr<nsIPromptFactory> promptFac =
4791 do_GetService("@mozilla.org/prompter;1", &rv);
4792 NS_ENSURE_SUCCESS(rv, rv);
4794 nsCOMPtr<nsIPrompt> prompt;
4795 rv = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
4796 reinterpret_cast<void**>(&prompt));
4797 NS_ENSURE_SUCCESS(rv, rv);
4799 nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
4800 if (promptBag)
4801 promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), allowTabModal);
4803 // Pass in the default value, if any.
4804 PRUnichar *inoutValue = ToNewUnicode(fixedInitial);
4805 PRBool disallowDialog = PR_FALSE;
4807 nsXPIDLString label;
4808 if (shouldEnableDisableDialog) {
4809 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4810 "ScriptDialogLabel", label);
4813 PRBool ok;
4814 rv = prompt->Prompt(title.get(), fixedMessage.get(),
4815 &inoutValue, label.get(), &disallowDialog, &ok);
4817 if (disallowDialog) {
4818 PreventFurtherDialogs();
4821 NS_ENSURE_SUCCESS(rv, rv);
4823 nsAdoptingString outValue(inoutValue);
4825 if (ok && outValue) {
4826 aReturn.Assign(outValue);
4829 return rv;
4832 NS_IMETHODIMP
4833 nsGlobalWindow::Focus()
4835 FORWARD_TO_OUTER(Focus, (), NS_ERROR_NOT_INITIALIZED);
4837 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
4838 if (!fm)
4839 return NS_OK;
4841 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
4843 PRBool isVisible = PR_FALSE;
4844 if (baseWin) {
4845 baseWin->GetVisibility(&isVisible);
4848 if (!isVisible) {
4849 // A hidden tab is being focused, ignore this call.
4850 return NS_OK;
4853 nsIDOMWindowInternal *caller =
4854 static_cast<nsIDOMWindowInternal*>(nsContentUtils::GetWindowFromCaller());
4855 nsCOMPtr<nsIDOMWindowInternal> opener;
4856 GetOpener(getter_AddRefs(opener));
4858 // Enforce dom.disable_window_flip (for non-chrome), but still allow the
4859 // window which opened us to raise us at times when popups are allowed
4860 // (bugs 355482 and 369306).
4861 PRBool canFocus = CanSetProperty("dom.disable_window_flip") ||
4862 (opener == caller &&
4863 RevisePopupAbuseLevel(gPopupControlState) < openAbused);
4865 nsCOMPtr<nsIDOMWindow> activeWindow;
4866 fm->GetActiveWindow(getter_AddRefs(activeWindow));
4868 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
4869 NS_ASSERTION(treeItem, "What happened?");
4870 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4871 treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
4872 nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
4873 PRBool isActive = (rootWin == activeWindow);
4875 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4876 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4877 if (treeOwnerAsWin && (canFocus || isActive)) {
4878 PRBool isEnabled = PR_TRUE;
4879 if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled)) && !isEnabled) {
4880 NS_WARNING( "Should not try to set the focus on a disabled window" );
4881 return NS_OK;
4884 // XXXndeakin not sure what this is for or if it should go somewhere else
4885 nsCOMPtr<nsIEmbeddingSiteWindow> embeddingWin(do_GetInterface(treeOwnerAsWin));
4886 if (embeddingWin)
4887 embeddingWin->SetFocus();
4890 if (!mDocShell)
4891 return NS_OK;
4893 nsCOMPtr<nsIPresShell> presShell;
4894 // Don't look for a presshell if we're a root chrome window that's got
4895 // about:blank loaded. We don't want to focus our widget in that case.
4896 // XXXbz should we really be checking for IsInitialDocument() instead?
4897 PRBool lookForPresShell = PR_TRUE;
4898 PRInt32 itemType = nsIDocShellTreeItem::typeContent;
4899 treeItem->GetItemType(&itemType);
4900 if (itemType == nsIDocShellTreeItem::typeChrome &&
4901 GetPrivateRoot() == static_cast<nsIDOMWindowInternal*>(this) &&
4902 mDocument) {
4903 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
4904 NS_ASSERTION(doc, "Bogus doc?");
4905 nsIURI* ourURI = doc->GetDocumentURI();
4906 if (ourURI) {
4907 lookForPresShell = !IsAboutBlank(ourURI);
4911 if (lookForPresShell) {
4912 mDocShell->GetEldestPresShell(getter_AddRefs(presShell));
4915 nsCOMPtr<nsIDocShellTreeItem> parentDsti;
4916 treeItem->GetParent(getter_AddRefs(parentDsti));
4918 // set the parent's current focus to the frame containing this window.
4919 nsCOMPtr<nsIDOMWindow> parent(do_GetInterface(parentDsti));
4920 if (parent) {
4921 nsCOMPtr<nsIDOMDocument> parentdomdoc;
4922 parent->GetDocument(getter_AddRefs(parentdomdoc));
4924 nsCOMPtr<nsIDocument> parentdoc = do_QueryInterface(parentdomdoc);
4925 if (!parentdoc)
4926 return NS_OK;
4928 nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
4929 nsIContent* frame = parentdoc->FindContentForSubDocument(doc);
4930 nsCOMPtr<nsIDOMElement> frameElement = do_QueryInterface(frame);
4931 if (frameElement) {
4932 PRUint32 flags = nsIFocusManager::FLAG_NOSCROLL;
4933 if (canFocus)
4934 flags |= nsIFocusManager::FLAG_RAISE;
4935 return fm->SetFocus(frameElement, flags);
4938 else if (canFocus) {
4939 // if there is no parent, this must be a toplevel window, so raise the
4940 // window if canFocus is true
4941 return fm->SetActiveWindow(this);
4944 return NS_OK;
4947 NS_IMETHODIMP
4948 nsGlobalWindow::Blur()
4950 FORWARD_TO_OUTER(Blur, (), NS_ERROR_NOT_INITIALIZED);
4952 // If dom.disable_window_flip == true, then content should not be allowed
4953 // to call this function (this would allow popunders, bug 369306)
4954 if (!CanSetProperty("dom.disable_window_flip")) {
4955 return NS_OK;
4958 // If embedding apps don't implement nsIEmbeddingSiteWindow2, we
4959 // shouldn't throw exceptions to web content.
4960 nsresult rv = NS_OK;
4962 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
4963 GetTreeOwner(getter_AddRefs(treeOwner));
4964 nsCOMPtr<nsIEmbeddingSiteWindow2> siteWindow(do_GetInterface(treeOwner));
4965 if (siteWindow) {
4966 // This method call may cause mDocShell to become nsnull.
4967 rv = siteWindow->Blur();
4969 // if the root is focused, clear the focus
4970 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
4971 nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
4972 if (fm && mDocument) {
4973 nsCOMPtr<nsIDOMElement> element;
4974 fm->GetFocusedElementForWindow(this, PR_FALSE, nsnull, getter_AddRefs(element));
4975 nsCOMPtr<nsIContent> content = do_QueryInterface(element);
4976 if (content == doc->GetRootElement())
4977 fm->ClearFocus(this);
4981 return rv;
4984 NS_IMETHODIMP
4985 nsGlobalWindow::Back()
4987 FORWARD_TO_OUTER(Back, (), NS_ERROR_NOT_INITIALIZED);
4989 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4990 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
4992 return webNav->GoBack();
4995 NS_IMETHODIMP
4996 nsGlobalWindow::Forward()
4998 FORWARD_TO_OUTER(Forward, (), NS_ERROR_NOT_INITIALIZED);
5000 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
5001 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
5003 return webNav->GoForward();
5006 NS_IMETHODIMP
5007 nsGlobalWindow::Home()
5009 FORWARD_TO_OUTER(Home, (), NS_ERROR_NOT_INITIALIZED);
5011 if (!mDocShell)
5012 return NS_OK;
5014 nsAdoptingString homeURL =
5015 nsContentUtils::GetLocalizedStringPref(PREF_BROWSER_STARTUP_HOMEPAGE);
5017 if (homeURL.IsEmpty()) {
5018 // if all else fails, use this
5019 #ifdef DEBUG_seth
5020 printf("all else failed. using %s as the home page\n", DEFAULT_HOME_PAGE);
5021 #endif
5022 CopyASCIItoUTF16(DEFAULT_HOME_PAGE, homeURL);
5025 #ifdef MOZ_PHOENIX
5027 // Firefox lets the user specify multiple home pages to open in
5028 // individual tabs by separating them with '|'. Since we don't
5029 // have the machinery in place to easily open new tabs from here,
5030 // simply truncate the homeURL at the first '|' character to
5031 // prevent any possibilities of leaking the users list of home
5032 // pages to the first home page.
5034 // Once bug https://bugzilla.mozilla.org/show_bug.cgi?id=221445 is
5035 // fixed we can revisit this.
5036 PRInt32 firstPipe = homeURL.FindChar('|');
5038 if (firstPipe > 0) {
5039 homeURL.Truncate(firstPipe);
5042 #endif
5044 nsresult rv;
5045 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
5046 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
5047 rv = webNav->LoadURI(homeURL.get(),
5048 nsIWebNavigation::LOAD_FLAGS_NONE,
5049 nsnull,
5050 nsnull,
5051 nsnull);
5052 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5053 return NS_OK;
5056 NS_IMETHODIMP
5057 nsGlobalWindow::Stop()
5059 FORWARD_TO_OUTER(Stop, (), NS_ERROR_NOT_INITIALIZED);
5061 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
5062 if (!webNav)
5063 return NS_OK;
5065 return webNav->Stop(nsIWebNavigation::STOP_ALL);
5068 NS_IMETHODIMP
5069 nsGlobalWindow::Print()
5071 #ifdef NS_PRINTING
5072 FORWARD_TO_OUTER(Print, (), NS_ERROR_NOT_INITIALIZED);
5074 if (AreDialogsBlocked() || !ConfirmDialogAllowed())
5075 return NS_ERROR_NOT_AVAILABLE;
5077 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
5078 if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
5079 getter_AddRefs(webBrowserPrint)))) {
5081 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
5082 do_GetService("@mozilla.org/gfx/printsettings-service;1");
5084 nsCOMPtr<nsIPrintSettings> printSettings;
5085 if (printSettingsService) {
5086 PRBool printSettingsAreGlobal =
5087 nsContentUtils::GetBoolPref("print.use_global_printsettings", PR_FALSE);
5089 if (printSettingsAreGlobal) {
5090 printSettingsService->GetGlobalPrintSettings(getter_AddRefs(printSettings));
5092 nsXPIDLString printerName;
5093 printSettings->GetPrinterName(getter_Copies(printerName));
5094 if (printerName.IsEmpty()) {
5095 printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
5096 printSettings->SetPrinterName(printerName);
5098 printSettingsService->InitPrintSettingsFromPrinter(printerName, printSettings);
5099 printSettingsService->InitPrintSettingsFromPrefs(printSettings,
5100 PR_TRUE,
5101 nsIPrintSettings::kInitSaveAll);
5102 } else {
5103 printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));
5106 EnterModalState();
5107 webBrowserPrint->Print(printSettings, nsnull);
5108 LeaveModalState(nsnull);
5110 PRBool savePrintSettings =
5111 nsContentUtils::GetBoolPref("print.save_print_settings", PR_FALSE);
5112 if (printSettingsAreGlobal && savePrintSettings) {
5113 printSettingsService->
5114 SavePrintSettingsToPrefs(printSettings,
5115 PR_TRUE,
5116 nsIPrintSettings::kInitSaveAll);
5117 printSettingsService->
5118 SavePrintSettingsToPrefs(printSettings,
5119 PR_FALSE,
5120 nsIPrintSettings::kInitSavePrinterName);
5122 } else {
5123 webBrowserPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));
5124 webBrowserPrint->Print(printSettings, nsnull);
5127 #endif //NS_PRINTING
5129 return NS_OK;
5132 NS_IMETHODIMP
5133 nsGlobalWindow::MoveTo(PRInt32 aXPos, PRInt32 aYPos)
5135 FORWARD_TO_OUTER(MoveTo, (aXPos, aYPos), NS_ERROR_NOT_INITIALIZED);
5138 * If caller is not chrome and the user has not explicitly exempted the site,
5139 * prevent window.moveTo() by exiting early
5142 if (!CanMoveResizeWindows() || IsFrame()) {
5143 return NS_OK;
5146 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5147 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5148 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
5150 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&aXPos, &aYPos),
5151 NS_ERROR_FAILURE);
5153 // mild abuse of a "size" object so we don't need more helper functions
5154 nsIntSize devPos(CSSToDevIntPixels(nsIntSize(aXPos, aYPos)));
5156 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(devPos.width, devPos.height),
5157 NS_ERROR_FAILURE);
5159 return NS_OK;
5162 NS_IMETHODIMP
5163 nsGlobalWindow::MoveBy(PRInt32 aXDif, PRInt32 aYDif)
5165 FORWARD_TO_OUTER(MoveBy, (aXDif, aYDif), NS_ERROR_NOT_INITIALIZED);
5168 * If caller is not chrome and the user has not explicitly exempted the site,
5169 * prevent window.moveBy() by exiting early
5172 if (!CanMoveResizeWindows() || IsFrame()) {
5173 return NS_OK;
5176 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5177 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5178 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
5180 // To do this correctly we have to convert what we get from GetPosition
5181 // into CSS pixels, add the arguments, do the security check, and
5182 // then convert back to device pixels for the call to SetPosition.
5184 PRInt32 x, y;
5185 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y), NS_ERROR_FAILURE);
5187 // mild abuse of a "size" object so we don't need more helper functions
5188 nsIntSize cssPos(DevToCSSIntPixels(nsIntSize(x, y)));
5190 cssPos.width += aXDif;
5191 cssPos.height += aYDif;
5193 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&cssPos.width,
5194 &cssPos.height),
5195 NS_ERROR_FAILURE);
5197 nsIntSize newDevPos(CSSToDevIntPixels(cssPos));
5199 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(newDevPos.width,
5200 newDevPos.height),
5201 NS_ERROR_FAILURE);
5203 return NS_OK;
5206 NS_IMETHODIMP
5207 nsGlobalWindow::ResizeTo(PRInt32 aWidth, PRInt32 aHeight)
5209 FORWARD_TO_OUTER(ResizeTo, (aWidth, aHeight), NS_ERROR_NOT_INITIALIZED);
5212 * If caller is not chrome and the user has not explicitly exempted the site,
5213 * prevent window.resizeTo() by exiting early
5216 if (!CanMoveResizeWindows() || IsFrame()) {
5217 return NS_OK;
5220 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5221 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5222 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
5224 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&aWidth, &aHeight),
5225 NS_ERROR_FAILURE);
5227 nsIntSize devSz(CSSToDevIntPixels(nsIntSize(aWidth, aHeight)));
5229 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(devSz.width, devSz.height, PR_TRUE),
5230 NS_ERROR_FAILURE);
5232 return NS_OK;
5235 NS_IMETHODIMP
5236 nsGlobalWindow::ResizeBy(PRInt32 aWidthDif, PRInt32 aHeightDif)
5238 FORWARD_TO_OUTER(ResizeBy, (aWidthDif, aHeightDif), NS_ERROR_NOT_INITIALIZED);
5241 * If caller is not chrome and the user has not explicitly exempted the site,
5242 * prevent window.resizeBy() by exiting early
5245 if (!CanMoveResizeWindows() || IsFrame()) {
5246 return NS_OK;
5249 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5250 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5251 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
5253 PRInt32 width, height;
5254 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&width, &height), NS_ERROR_FAILURE);
5256 // To do this correctly we have to convert what we got from GetSize
5257 // into CSS pixels, add the arguments, do the security check, and
5258 // then convert back to device pixels for the call to SetSize.
5260 nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
5262 cssSize.width += aWidthDif;
5263 cssSize.height += aHeightDif;
5265 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&cssSize.width,
5266 &cssSize.height),
5267 NS_ERROR_FAILURE);
5269 nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
5271 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(newDevSize.width,
5272 newDevSize.height,
5273 PR_TRUE),
5274 NS_ERROR_FAILURE);
5276 return NS_OK;
5279 NS_IMETHODIMP
5280 nsGlobalWindow::SizeToContent()
5282 FORWARD_TO_OUTER(SizeToContent, (), NS_ERROR_NOT_INITIALIZED);
5284 if (!mDocShell) {
5285 return NS_OK;
5289 * If caller is not chrome and the user has not explicitly exempted the site,
5290 * prevent window.sizeToContent() by exiting early
5293 if (!CanMoveResizeWindows() || IsFrame()) {
5294 return NS_OK;
5297 // The content viewer does a check to make sure that it's a content
5298 // viewer for a toplevel docshell.
5300 nsCOMPtr<nsIContentViewer> cv;
5301 mDocShell->GetContentViewer(getter_AddRefs(cv));
5302 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(cv));
5303 NS_ENSURE_TRUE(markupViewer, NS_ERROR_FAILURE);
5304 NS_ENSURE_SUCCESS(markupViewer->SizeToContent(), NS_ERROR_FAILURE);
5306 return NS_OK;
5309 NS_IMETHODIMP
5310 nsGlobalWindow::GetWindowRoot(nsIDOMEventTarget **aWindowRoot)
5312 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
5313 return CallQueryInterface(root, aWindowRoot);
5316 already_AddRefed<nsPIWindowRoot>
5317 nsGlobalWindow::GetTopWindowRoot()
5319 nsIDOMWindowInternal *rootWindow = GetPrivateRoot();
5320 nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(rootWindow));
5321 if (!piWin)
5322 return nsnull;
5324 nsCOMPtr<nsPIWindowRoot> window = do_QueryInterface(piWin->GetChromeEventHandler());
5325 return window.forget();
5328 NS_IMETHODIMP
5329 nsGlobalWindow::Scroll(PRInt32 aXScroll, PRInt32 aYScroll)
5331 return ScrollTo(aXScroll, aYScroll);
5334 NS_IMETHODIMP
5335 nsGlobalWindow::ScrollTo(PRInt32 aXScroll, PRInt32 aYScroll)
5337 FlushPendingNotifications(Flush_Layout);
5338 nsIScrollableFrame *sf = GetScrollFrame();
5340 if (sf) {
5341 // Here we calculate what the max pixel value is that we can
5342 // scroll to, we do this by dividing maxint with the pixel to
5343 // twips conversion factor, and substracting 4, the 4 comes from
5344 // experimenting with this value, anything less makes the view
5345 // code not scroll correctly, I have no idea why. -- jst
5346 const PRInt32 maxpx = nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff) - 4;
5348 if (aXScroll > maxpx) {
5349 aXScroll = maxpx;
5352 if (aYScroll > maxpx) {
5353 aYScroll = maxpx;
5355 sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aXScroll),
5356 nsPresContext::CSSPixelsToAppUnits(aYScroll)),
5357 nsIScrollableFrame::INSTANT);
5360 return NS_OK;
5363 NS_IMETHODIMP
5364 nsGlobalWindow::ScrollBy(PRInt32 aXScrollDif, PRInt32 aYScrollDif)
5366 FlushPendingNotifications(Flush_Layout);
5367 nsIScrollableFrame *sf = GetScrollFrame();
5369 if (sf) {
5370 nsPoint scrollPos = sf->GetScrollPosition();
5371 // It seems like it would make more sense for ScrollBy to use
5372 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
5373 // Perhaps Web content does too.
5374 return ScrollTo(nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x) + aXScrollDif,
5375 nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y) + aYScrollDif);
5378 return NS_OK;
5381 NS_IMETHODIMP
5382 nsGlobalWindow::ScrollByLines(PRInt32 numLines)
5384 FlushPendingNotifications(Flush_Layout);
5385 nsIScrollableFrame *sf = GetScrollFrame();
5386 if (sf) {
5387 // It seems like it would make more sense for ScrollByLines to use
5388 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
5389 // Perhaps Web content does too.
5390 sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
5391 nsIScrollableFrame::INSTANT);
5394 return NS_OK;
5397 NS_IMETHODIMP
5398 nsGlobalWindow::ScrollByPages(PRInt32 numPages)
5400 FlushPendingNotifications(Flush_Layout);
5401 nsIScrollableFrame *sf = GetScrollFrame();
5402 if (sf) {
5403 // It seems like it would make more sense for ScrollByPages to use
5404 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
5405 // Perhaps Web content does too.
5406 sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
5407 nsIScrollableFrame::INSTANT);
5410 return NS_OK;
5413 NS_IMETHODIMP
5414 nsGlobalWindow::ClearTimeout()
5416 return ClearTimeoutOrInterval();
5419 NS_IMETHODIMP
5420 nsGlobalWindow::ClearInterval()
5422 return ClearTimeoutOrInterval();
5425 NS_IMETHODIMP
5426 nsGlobalWindow::SetTimeout(PRInt32 *_retval)
5428 return SetTimeoutOrInterval(PR_FALSE, _retval);
5431 NS_IMETHODIMP
5432 nsGlobalWindow::SetInterval(PRInt32 *_retval)
5434 return SetTimeoutOrInterval(PR_TRUE, _retval);
5437 NS_IMETHODIMP
5438 nsGlobalWindow::SetResizable(PRBool aResizable)
5440 // nop
5442 return NS_OK;
5445 static void
5446 ReportUseOfDeprecatedMethod(nsGlobalWindow* aWindow, const char* aWarning)
5448 nsCOMPtr<nsIDocument> doc = do_QueryInterface(aWindow->GetExtantDocument());
5449 nsContentUtils::ReportToConsole(nsContentUtils::eDOM_PROPERTIES,
5450 aWarning,
5451 nsnull, 0,
5452 nsnull,
5453 EmptyString(), 0, 0,
5454 nsIScriptError::warningFlag,
5455 "DOM Events", doc);
5458 NS_IMETHODIMP
5459 nsGlobalWindow::CaptureEvents(PRInt32 aEventFlags)
5461 ReportUseOfDeprecatedMethod(this, "UseOfCaptureEventsWarning");
5462 return NS_OK;
5465 NS_IMETHODIMP
5466 nsGlobalWindow::ReleaseEvents(PRInt32 aEventFlags)
5468 ReportUseOfDeprecatedMethod(this, "UseOfReleaseEventsWarning");
5469 return NS_OK;
5472 NS_IMETHODIMP
5473 nsGlobalWindow::RouteEvent(nsIDOMEvent* aEvt)
5475 ReportUseOfDeprecatedMethod(this, "UseOfRouteEventWarning");
5476 return NS_OK;
5479 NS_IMETHODIMP
5480 nsGlobalWindow::EnableExternalCapture()
5482 return NS_ERROR_FAILURE;
5485 NS_IMETHODIMP
5486 nsGlobalWindow::DisableExternalCapture()
5488 return NS_ERROR_FAILURE;
5491 static
5492 PRBool IsPopupBlocked(nsIDOMDocument* aDoc)
5494 nsCOMPtr<nsIPopupWindowManager> pm =
5495 do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
5497 if (!pm) {
5498 return PR_FALSE;
5501 PRBool blocked = PR_TRUE;
5502 nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
5504 if (doc) {
5505 PRUint32 permission = nsIPopupWindowManager::ALLOW_POPUP;
5506 pm->TestPermission(doc->GetDocumentURI(), &permission);
5507 blocked = (permission == nsIPopupWindowManager::DENY_POPUP);
5509 return blocked;
5512 /* static */
5513 void
5514 nsGlobalWindow::FirePopupBlockedEvent(nsIDOMDocument* aDoc,
5515 nsIDOMWindow *aRequestingWindow, nsIURI *aPopupURI,
5516 const nsAString &aPopupWindowName,
5517 const nsAString &aPopupWindowFeatures)
5519 if (aDoc) {
5520 // Fire a "DOMPopupBlocked" event so that the UI can hear about
5521 // blocked popups.
5522 nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(aDoc));
5523 nsCOMPtr<nsIDOMEvent> event;
5524 docEvent->CreateEvent(NS_LITERAL_STRING("PopupBlockedEvents"),
5525 getter_AddRefs(event));
5526 if (event) {
5527 nsCOMPtr<nsIDOMPopupBlockedEvent> pbev(do_QueryInterface(event));
5528 pbev->InitPopupBlockedEvent(NS_LITERAL_STRING("DOMPopupBlocked"),
5529 PR_TRUE, PR_TRUE, aRequestingWindow,
5530 aPopupURI, aPopupWindowName,
5531 aPopupWindowFeatures);
5532 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
5533 privateEvent->SetTrusted(PR_TRUE);
5535 nsCOMPtr<nsIDOMEventTarget> targ(do_QueryInterface(aDoc));
5536 PRBool defaultActionEnabled;
5537 targ->DispatchEvent(event, &defaultActionEnabled);
5542 void FirePopupWindowEvent(nsIDOMDocument* aDoc)
5544 // Fire a "PopupWindow" event
5545 nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
5546 nsContentUtils::DispatchTrustedEvent(doc, aDoc,
5547 NS_LITERAL_STRING("PopupWindow"),
5548 PR_TRUE, PR_TRUE);
5551 // static
5552 PRBool
5553 nsGlobalWindow::CanSetProperty(const char *aPrefName)
5555 // Chrome can set any property.
5556 if (nsContentUtils::IsCallerTrustedForWrite()) {
5557 return PR_TRUE;
5560 // If the pref is set to true, we can not set the property
5561 // and vice versa.
5562 return !nsContentUtils::GetBoolPref(aPrefName, PR_TRUE);
5565 PRBool
5566 nsGlobalWindow::PopupWhitelisted()
5568 if (!IsPopupBlocked(mDocument))
5569 return PR_TRUE;
5571 nsCOMPtr<nsIDOMWindow> parent;
5573 if (NS_FAILED(GetParent(getter_AddRefs(parent))) ||
5574 parent == static_cast<nsIDOMWindow*>(this))
5576 return PR_FALSE;
5579 return static_cast<nsGlobalWindow*>
5580 (static_cast<nsIDOMWindow*>
5581 (parent.get()))->PopupWhitelisted();
5585 * Examine the current document state to see if we're in a way that is
5586 * typically abused by web designers. The window.open code uses this
5587 * routine to determine whether to allow the new window.
5588 * Returns a value from the PopupControlState enum.
5590 PopupControlState
5591 nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
5593 FORWARD_TO_OUTER(RevisePopupAbuseLevel, (aControl), aControl);
5595 NS_ASSERTION(mDocShell, "Must have docshell");
5597 nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(mDocShell));
5599 NS_ASSERTION(item, "Docshell doesn't implement nsIDocShellTreeItem?");
5601 PRInt32 type = nsIDocShellTreeItem::typeChrome;
5602 item->GetItemType(&type);
5603 if (type != nsIDocShellTreeItem::typeContent)
5604 return openAllowed;
5606 PopupControlState abuse = aControl;
5607 switch (abuse) {
5608 case openControlled:
5609 case openAbused:
5610 case openOverridden:
5611 if (PopupWhitelisted())
5612 abuse = PopupControlState(abuse - 1);
5613 case openAllowed: break;
5614 default:
5615 NS_WARNING("Strange PopupControlState!");
5618 // limit the number of simultaneously open popups
5619 if (abuse == openAbused || abuse == openControlled) {
5620 PRInt32 popupMax = nsContentUtils::GetIntPref("dom.popup_maximum", -1);
5621 if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
5622 abuse = openOverridden;
5625 return abuse;
5628 /* If a window open is blocked, fire the appropriate DOM events.
5629 aBlocked signifies we just blocked a popup.
5630 aWindow signifies we just opened what is probably a popup.
5632 void
5633 nsGlobalWindow::FireAbuseEvents(PRBool aBlocked, PRBool aWindow,
5634 const nsAString &aPopupURL,
5635 const nsAString &aPopupWindowName,
5636 const nsAString &aPopupWindowFeatures)
5638 // fetch the URI of the window requesting the opened window
5640 nsCOMPtr<nsIDOMWindow> topWindow;
5641 GetTop(getter_AddRefs(topWindow));
5642 if (!topWindow)
5643 return;
5645 nsCOMPtr<nsIDOMDocument> topDoc;
5646 topWindow->GetDocument(getter_AddRefs(topDoc));
5648 nsCOMPtr<nsIURI> popupURI;
5650 // build the URI of the would-have-been popup window
5651 // (see nsWindowWatcher::URIfromURL)
5653 // first, fetch the opener's base URI
5655 nsIURI *baseURL = 0;
5657 JSContext *cx = nsContentUtils::GetCurrentJSContext();
5658 nsCOMPtr<nsIDOMWindow> contextWindow;
5660 if (cx) {
5661 nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
5662 if (currentCX) {
5663 contextWindow = do_QueryInterface(currentCX->GetGlobalObject());
5666 if (!contextWindow)
5667 contextWindow = static_cast<nsIDOMWindow*>(this);
5669 nsCOMPtr<nsIDOMDocument> domdoc;
5670 contextWindow->GetDocument(getter_AddRefs(domdoc));
5671 nsCOMPtr<nsIDocument> doc(do_QueryInterface(domdoc));
5672 if (doc)
5673 baseURL = doc->GetDocBaseURI();
5675 // use the base URI to build what would have been the popup's URI
5676 nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
5677 if (ios)
5678 ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), 0, baseURL,
5679 getter_AddRefs(popupURI));
5681 // fire an event chock full of informative URIs
5682 if (aBlocked)
5683 FirePopupBlockedEvent(topDoc, this, popupURI, aPopupWindowName,
5684 aPopupWindowFeatures);
5685 if (aWindow)
5686 FirePopupWindowEvent(topDoc);
5689 NS_IMETHODIMP
5690 nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
5691 const nsAString& aOptions, nsIDOMWindow **_retval)
5693 return OpenInternal(aUrl, aName, aOptions,
5694 PR_FALSE, // aDialog
5695 PR_FALSE, // aContentModal
5696 PR_TRUE, // aCalledNoScript
5697 PR_FALSE, // aDoJSFixups
5698 nsnull, nsnull, // No args
5699 GetPrincipal(), // aCalleePrincipal
5700 nsnull, // aJSCallerContext
5701 _retval);
5704 NS_IMETHODIMP
5705 nsGlobalWindow::OpenJS(const nsAString& aUrl, const nsAString& aName,
5706 const nsAString& aOptions, nsIDOMWindow **_retval)
5708 return OpenInternal(aUrl, aName, aOptions,
5709 PR_FALSE, // aDialog
5710 PR_FALSE, // aContentModal
5711 PR_FALSE, // aCalledNoScript
5712 PR_TRUE, // aDoJSFixups
5713 nsnull, nsnull, // No args
5714 GetPrincipal(), // aCalleePrincipal
5715 nsContentUtils::GetCurrentJSContext(), // aJSCallerContext
5716 _retval);
5719 // like Open, but attaches to the new window any extra parameters past
5720 // [features] as a JS property named "arguments"
5721 NS_IMETHODIMP
5722 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
5723 const nsAString& aOptions,
5724 nsISupports* aExtraArgument, nsIDOMWindow** _retval)
5726 return OpenInternal(aUrl, aName, aOptions,
5727 PR_TRUE, // aDialog
5728 PR_FALSE, // aContentModal
5729 PR_TRUE, // aCalledNoScript
5730 PR_FALSE, // aDoJSFixups
5731 nsnull, aExtraArgument, // Arguments
5732 GetPrincipal(), // aCalleePrincipal
5733 nsnull, // aJSCallerContext
5734 _retval);
5737 NS_IMETHODIMP
5738 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
5739 const nsAString& aOptions, nsIDOMWindow** _retval)
5741 if (!nsContentUtils::IsCallerTrustedForWrite()) {
5742 return NS_ERROR_DOM_SECURITY_ERR;
5745 nsAXPCNativeCallContext *ncc = nsnull;
5746 nsresult rv = nsContentUtils::XPConnect()->
5747 GetCurrentNativeCallContext(&ncc);
5748 NS_ENSURE_SUCCESS(rv, rv);
5750 if (!ncc)
5751 return NS_ERROR_NOT_AVAILABLE;
5753 JSContext *cx = nsnull;
5755 rv = ncc->GetJSContext(&cx);
5756 NS_ENSURE_SUCCESS(rv, rv);
5758 PRUint32 argc;
5759 jsval *argv = nsnull;
5761 // XXX - need to get this as nsISupports?
5762 ncc->GetArgc(&argc);
5763 ncc->GetArgvPtr(&argv);
5765 // Strip the url, name and options from the args seen by scripts.
5766 PRUint32 argOffset = argc < 3 ? argc : 3;
5767 nsCOMPtr<nsIArray> argvArray;
5768 rv = NS_CreateJSArgv(cx, argc - argOffset, argv + argOffset,
5769 getter_AddRefs(argvArray));
5770 NS_ENSURE_SUCCESS(rv, rv);
5772 return OpenInternal(aUrl, aName, aOptions,
5773 PR_TRUE, // aDialog
5774 PR_FALSE, // aContentModal
5775 PR_FALSE, // aCalledNoScript
5776 PR_FALSE, // aDoJSFixups
5777 argvArray, nsnull, // Arguments
5778 GetPrincipal(), // aCalleePrincipal
5779 cx, // aJSCallerContext
5780 _retval);
5783 NS_IMETHODIMP
5784 nsGlobalWindow::GetFrames(nsIDOMWindow** aFrames)
5786 FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
5788 *aFrames = this;
5789 NS_ADDREF(*aFrames);
5791 FlushPendingNotifications(Flush_ContentAndNotify);
5793 return NS_OK;
5796 nsGlobalWindow*
5797 nsGlobalWindow::CallerInnerWindow()
5799 JSContext *cx = nsContentUtils::GetCurrentJSContext();
5800 if (!cx) {
5801 NS_ERROR("Please don't call this method from C++!");
5803 return nsnull;
5806 JSObject *scope = nsnull;
5807 JSStackFrame *fp = nsnull;
5808 JS_FrameIterator(cx, &fp);
5809 if (fp) {
5810 while (fp->isDummyFrame()) {
5811 if (!JS_FrameIterator(cx, &fp))
5812 break;
5815 if (fp)
5816 scope = &fp->scopeChain();
5819 if (!scope)
5820 scope = JS_GetScopeChain(cx);
5822 JSAutoEnterCompartment ac;
5823 if (!ac.enter(cx, scope))
5824 return nsnull;
5826 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
5827 nsContentUtils::XPConnect()->
5828 GetWrappedNativeOfJSObject(cx, ::JS_GetGlobalForObject(cx, scope),
5829 getter_AddRefs(wrapper));
5830 if (!wrapper)
5831 return nsnull;
5833 // The calling window must be holding a reference, so we can just return a
5834 // raw pointer here and let the QI's addref be balanced by the nsCOMPtr
5835 // destructor's release.
5836 nsCOMPtr<nsPIDOMWindow> win = do_QueryWrappedNative(wrapper);
5837 if (!win)
5838 return GetCurrentInnerWindowInternal();
5839 return static_cast<nsGlobalWindow*>(win.get());
5844 * Class used to represent events generated by calls to Window.postMessage,
5845 * which asynchronously creates and dispatches events.
5847 class PostMessageEvent : public nsRunnable
5849 public:
5850 NS_DECL_NSIRUNNABLE
5852 PostMessageEvent(nsGlobalWindow* aSource,
5853 const nsAString& aCallerOrigin,
5854 const nsAString& aMessage,
5855 nsGlobalWindow* aTargetWindow,
5856 nsIURI* aProvidedOrigin,
5857 PRBool aTrustedCaller)
5858 : mSource(aSource),
5859 mCallerOrigin(aCallerOrigin),
5860 mMessage(aMessage),
5861 mTargetWindow(aTargetWindow),
5862 mProvidedOrigin(aProvidedOrigin),
5863 mTrustedCaller(aTrustedCaller)
5865 MOZ_COUNT_CTOR(PostMessageEvent);
5868 ~PostMessageEvent()
5870 MOZ_COUNT_DTOR(PostMessageEvent);
5873 private:
5874 nsRefPtr<nsGlobalWindow> mSource;
5875 nsString mCallerOrigin;
5876 nsString mMessage;
5877 nsRefPtr<nsGlobalWindow> mTargetWindow;
5878 nsCOMPtr<nsIURI> mProvidedOrigin;
5879 PRBool mTrustedCaller;
5882 NS_IMETHODIMP
5883 PostMessageEvent::Run()
5885 NS_ABORT_IF_FALSE(mTargetWindow->IsOuterWindow(),
5886 "should have been passed an outer window!");
5887 NS_ABORT_IF_FALSE(!mSource || mSource->IsOuterWindow(),
5888 "should have been passed an outer window!");
5890 nsRefPtr<nsGlobalWindow> targetWindow;
5891 if (mTargetWindow->IsClosedOrClosing() ||
5892 !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
5893 targetWindow->IsClosedOrClosing())
5894 return NS_OK;
5896 NS_ABORT_IF_FALSE(targetWindow->IsInnerWindow(),
5897 "we ordered an inner window!");
5899 // Ensure that any origin which might have been provided is the origin of this
5900 // window's document. Note that we do this *now* instead of when postMessage
5901 // is called because the target window might have been navigated to a
5902 // different location between then and now. If this check happened when
5903 // postMessage was called, it would be fairly easy for a malicious webpage to
5904 // intercept messages intended for another site by carefully timing navigation
5905 // of the target window so it changed location after postMessage but before
5906 // now.
5907 if (mProvidedOrigin) {
5908 // Get the target's origin either from its principal or, in the case the
5909 // principal doesn't carry a URI (e.g. the system principal), the target's
5910 // document.
5911 nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
5912 if (!targetPrin)
5913 return NS_OK;
5914 nsCOMPtr<nsIURI> targetURI;
5915 if (NS_FAILED(targetPrin->GetURI(getter_AddRefs(targetURI))))
5916 return NS_OK;
5917 if (!targetURI) {
5918 targetURI = targetWindow->mDoc->GetDocumentURI();
5919 if (!targetURI)
5920 return NS_OK;
5923 // Note: This is contrary to the spec with respect to file: URLs, which
5924 // the spec groups into a single origin, but given we intentionally
5925 // don't do that in other places it seems better to hold the line for
5926 // now. Long-term, we want HTML5 to address this so that we can
5927 // be compliant while being safer.
5928 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
5929 nsresult rv =
5930 ssm->CheckSameOriginURI(mProvidedOrigin, targetURI, PR_TRUE);
5931 if (NS_FAILED(rv))
5932 return NS_OK;
5936 // Create the event
5937 nsCOMPtr<nsIDOMDocumentEvent> docEvent =
5938 do_QueryInterface(targetWindow->mDocument);
5939 if (!docEvent)
5940 return NS_OK;
5941 nsCOMPtr<nsIDOMEvent> event;
5942 docEvent->CreateEvent(NS_LITERAL_STRING("MessageEvent"),
5943 getter_AddRefs(event));
5944 if (!event)
5945 return NS_OK;
5947 nsCOMPtr<nsIDOMMessageEvent> message = do_QueryInterface(event);
5948 nsresult rv = message->InitMessageEvent(NS_LITERAL_STRING("message"),
5949 PR_FALSE /* non-bubbling */,
5950 PR_TRUE /* cancelable */,
5951 mMessage,
5952 mCallerOrigin,
5953 EmptyString(),
5954 mSource);
5955 if (NS_FAILED(rv))
5956 return NS_OK;
5959 // We can't simply call dispatchEvent on the window because doing so ends
5960 // up flipping the trusted bit on the event, and we don't want that to
5961 // happen because then untrusted content can call postMessage on a chrome
5962 // window if it can get a reference to it.
5964 nsIPresShell *shell = targetWindow->mDoc->GetShell();
5965 nsRefPtr<nsPresContext> presContext;
5966 if (shell)
5967 presContext = shell->GetPresContext();
5969 nsCOMPtr<nsIPrivateDOMEvent> privEvent = do_QueryInterface(message);
5970 privEvent->SetTrusted(mTrustedCaller);
5971 nsEvent *internalEvent = privEvent->GetInternalNSEvent();
5973 nsEventStatus status = nsEventStatus_eIgnore;
5974 nsEventDispatcher::Dispatch(static_cast<nsPIDOMWindow*>(mTargetWindow),
5975 presContext,
5976 internalEvent,
5977 message,
5978 &status);
5979 return NS_OK;
5982 NS_IMETHODIMP
5983 nsGlobalWindow::PostMessageMoz(const nsAString& aMessage, const nsAString& aOrigin)
5985 FORWARD_TO_OUTER(PostMessageMoz, (aMessage, aOrigin), NS_ERROR_NOT_INITIALIZED);
5988 // Window.postMessage is an intentional subversion of the same-origin policy.
5989 // As such, this code must be particularly careful in the information it
5990 // exposes to calling code.
5992 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5995 // First, get the caller's window
5996 nsRefPtr<nsGlobalWindow> callerInnerWin = CallerInnerWindow();
5997 if (!callerInnerWin)
5998 return NS_OK;
5999 NS_ABORT_IF_FALSE(callerInnerWin->IsInnerWindow(),
6000 "should have gotten an inner window here");
6002 // Compute the caller's origin either from its principal or, in the case the
6003 // principal doesn't carry a URI (e.g. the system principal), the caller's
6004 // document. We must get this now instead of when the event is created and
6005 // dispatched, because ultimately it is the identity of the calling window
6006 // *now* that determines who sent the message (and not an identity which might
6007 // have changed due to intervening navigations).
6008 nsIPrincipal* callerPrin = callerInnerWin->GetPrincipal();
6009 if (!callerPrin)
6010 return NS_OK;
6012 nsCOMPtr<nsIURI> callerOuterURI;
6013 if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerOuterURI))))
6014 return NS_OK;
6016 nsAutoString origin;
6017 if (callerOuterURI) {
6018 // if the principal has a URI, use that to generate the origin
6019 nsContentUtils::GetUTFOrigin(callerPrin, origin);
6021 else {
6022 // otherwise use the URI of the document to generate origin
6023 nsCOMPtr<nsIDocument> doc = do_QueryInterface(callerInnerWin->mDocument);
6024 if (!doc)
6025 return NS_OK;
6026 callerOuterURI = doc->GetDocumentURI();
6027 // if the principal has a URI, use that to generate the origin
6028 nsContentUtils::GetUTFOrigin(callerOuterURI, origin);
6031 // Convert the provided origin string into a URI for comparison purposes.
6032 // "*" indicates no specific origin is required.
6033 nsCOMPtr<nsIURI> providedOrigin;
6034 if (!aOrigin.EqualsASCII("*")) {
6035 if (NS_FAILED(NS_NewURI(getter_AddRefs(providedOrigin), aOrigin)))
6036 return NS_ERROR_DOM_SYNTAX_ERR;
6037 if (NS_FAILED(providedOrigin->SetUserPass(EmptyCString())) ||
6038 NS_FAILED(providedOrigin->SetPath(EmptyCString())))
6039 return NS_OK;
6042 // Create and asynchronously dispatch a runnable which will handle actual DOM
6043 // event creation and dispatch.
6044 nsRefPtr<PostMessageEvent> event =
6045 new PostMessageEvent(nsContentUtils::IsCallerChrome()
6046 ? nsnull
6047 : callerInnerWin->GetOuterWindowInternal(),
6048 origin,
6049 aMessage,
6050 this,
6051 providedOrigin,
6052 nsContentUtils::IsCallerTrustedForWrite());
6053 return NS_DispatchToCurrentThread(event);
6056 class nsCloseEvent : public nsRunnable {
6058 nsRefPtr<nsGlobalWindow> mWindow;
6060 nsCloseEvent(nsGlobalWindow *aWindow)
6061 : mWindow(aWindow)
6064 public:
6066 static nsresult
6067 PostCloseEvent(nsGlobalWindow* aWindow) {
6068 nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow);
6069 nsresult rv = NS_DispatchToCurrentThread(ev);
6070 if (NS_SUCCEEDED(rv))
6071 aWindow->MaybeForgiveSpamCount();
6072 return rv;
6075 NS_IMETHOD Run() {
6076 if (mWindow)
6077 mWindow->ReallyCloseWindow();
6078 return NS_OK;
6083 PRBool
6084 nsGlobalWindow::CanClose()
6086 if (!mDocShell)
6087 return PR_TRUE;
6089 // Ask the content viewer whether the toplevel window can close.
6090 // If the content viewer returns false, it is responsible for calling
6091 // Close() as soon as it is possible for the window to close.
6092 // This allows us to not close the window while printing is happening.
6094 nsCOMPtr<nsIContentViewer> cv;
6095 mDocShell->GetContentViewer(getter_AddRefs(cv));
6096 if (cv) {
6097 PRBool canClose;
6098 nsresult rv = cv->PermitUnload(PR_FALSE, &canClose);
6099 if (NS_SUCCEEDED(rv) && !canClose)
6100 return PR_FALSE;
6102 rv = cv->RequestWindowClose(&canClose);
6103 if (NS_SUCCEEDED(rv) && !canClose)
6104 return PR_FALSE;
6107 return PR_TRUE;
6110 NS_IMETHODIMP
6111 nsGlobalWindow::Close()
6113 FORWARD_TO_OUTER(Close, (), NS_ERROR_NOT_INITIALIZED);
6115 if (IsFrame() || !mDocShell || IsInModalState()) {
6116 // window.close() is called on a frame in a frameset, on a window
6117 // that's already closed, or on a window for which there's
6118 // currently a modal dialog open. Ignore such calls.
6120 return NS_OK;
6123 if (mHavePendingClose) {
6124 // We're going to be closed anyway; do nothing since we don't want
6125 // to double-close
6126 return NS_OK;
6129 if (mBlockScriptedClosingFlag)
6131 // A script's popup has been blocked and we don't want
6132 // the window to be closed directly after this event,
6133 // so the user can see that there was a blocked popup.
6134 return NS_OK;
6137 // Don't allow scripts from content to close windows
6138 // that were not opened by script
6139 if (!mHadOriginalOpener && !nsContentUtils::IsCallerTrustedForWrite()) {
6140 PRBool allowClose =
6141 nsContentUtils::GetBoolPref("dom.allow_scripts_to_close_windows",
6142 PR_TRUE);
6143 if (!allowClose) {
6144 // We're blocking the close operation
6145 // report localized error msg in JS console
6146 nsContentUtils::ReportToConsole(
6147 nsContentUtils::eDOM_PROPERTIES,
6148 "WindowCloseBlockedWarning",
6149 nsnull, 0, // No params
6150 nsnull,
6151 EmptyString(), 0, 0, // No source, or column/line number
6152 nsIScriptError::warningFlag,
6153 "DOM Window", mDoc); // Better name for the category?
6155 return NS_OK;
6159 if (!mInClose && !mIsClosed && !CanClose())
6160 return NS_OK;
6162 // Fire a DOM event notifying listeners that this window is about to
6163 // be closed. The tab UI code may choose to cancel the default
6164 // action for this event, if so, we won't actually close the window
6165 // (since the tab UI code will close the tab in stead). Sure, this
6166 // could be abused by content code, but do we care? I don't think
6167 // so...
6169 PRBool wasInClose = mInClose;
6170 mInClose = PR_TRUE;
6172 if (!DispatchCustomEvent("DOMWindowClose")) {
6173 // Someone chose to prevent the default action for this event, if
6174 // so, let's not close this window after all...
6176 mInClose = wasInClose;
6177 return NS_OK;
6180 return FinalClose();
6183 nsresult
6184 nsGlobalWindow::ForceClose()
6186 if (IsFrame() || !mDocShell) {
6187 // This may be a frame in a frameset, or a window that's already closed.
6188 // Ignore such calls.
6190 return NS_OK;
6193 if (mHavePendingClose) {
6194 // We're going to be closed anyway; do nothing since we don't want
6195 // to double-close
6196 return NS_OK;
6199 mInClose = PR_TRUE;
6201 DispatchCustomEvent("DOMWindowClose");
6203 return FinalClose();
6206 nsresult
6207 nsGlobalWindow::FinalClose()
6209 nsresult rv;
6210 // Flag that we were closed.
6211 mIsClosed = PR_TRUE;
6213 nsCOMPtr<nsIJSContextStack> stack =
6214 do_GetService(sJSStackContractID);
6216 JSContext *cx = nsnull;
6218 if (stack) {
6219 stack->Peek(&cx);
6222 if (cx) {
6223 nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
6225 if (currentCX && currentCX == GetContextInternal()) {
6226 // We ignore the return value here. If setting the termination function
6227 // fails, it's better to fail to close the window than it is to crash
6228 // (which is what would tend to happen if we did this synchronously
6229 // here).
6230 rv = currentCX->SetTerminationFunction(CloseWindow,
6231 static_cast<nsIDOMWindow *>
6232 (this));
6233 if (NS_SUCCEEDED(rv)) {
6234 mHavePendingClose = PR_TRUE;
6236 return NS_OK;
6241 // We may have plugins on the page that have issued this close from their
6242 // event loop and because we currently destroy the plugin window with
6243 // frames, we crash. So, if we are called from Javascript, post an event
6244 // to really close the window.
6245 rv = NS_ERROR_FAILURE;
6246 if (!nsContentUtils::IsCallerChrome()) {
6247 rv = nsCloseEvent::PostCloseEvent(this);
6250 if (NS_FAILED(rv)) {
6251 ReallyCloseWindow();
6252 rv = NS_OK;
6253 } else {
6254 mHavePendingClose = PR_TRUE;
6257 return rv;
6261 void
6262 nsGlobalWindow::ReallyCloseWindow()
6264 FORWARD_TO_OUTER_VOID(ReallyCloseWindow, ());
6266 // Make sure we never reenter this method.
6267 mHavePendingClose = PR_TRUE;
6269 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
6270 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
6272 // If there's no treeOwnerAsWin, this window must already be closed.
6274 if (treeOwnerAsWin) {
6276 // but if we're a browser window we could be in some nasty
6277 // self-destroying cascade that we should mostly ignore
6279 nsCOMPtr<nsIDocShellTreeItem> docItem(do_QueryInterface(mDocShell));
6280 if (docItem) {
6281 nsCOMPtr<nsIBrowserDOMWindow> bwin;
6282 nsCOMPtr<nsIDocShellTreeItem> rootItem;
6283 docItem->GetRootTreeItem(getter_AddRefs(rootItem));
6284 nsCOMPtr<nsIDOMWindow> rootWin(do_GetInterface(rootItem));
6285 nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
6286 if (chromeWin)
6287 chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
6289 if (rootWin) {
6290 /* Normally we destroy the entire window, but not if
6291 this DOM window belongs to a tabbed browser and doesn't
6292 correspond to a tab. This allows a well-behaved tab
6293 to destroy the container as it should but is a final measure
6294 to prevent an errant tab from doing so when it shouldn't.
6295 This works because we reach this code when we shouldn't only
6296 in the particular circumstance that we belong to a tab
6297 that has just been closed (and is therefore already missing
6298 from the list of browsers) (and has an unload handler
6299 that closes the window). */
6300 // XXXbz now that we have mHavePendingClose, is this needed?
6301 PRBool isTab = PR_FALSE;
6302 if (rootWin == this ||
6303 !bwin || (bwin->IsTabContentWindow(GetOuterWindowInternal(),
6304 &isTab), isTab))
6305 treeOwnerAsWin->Destroy();
6309 CleanUp(PR_FALSE);
6313 nsIDOMWindow *
6314 nsGlobalWindow::EnterModalState()
6316 nsGlobalWindow* topWin = GetTop();
6318 if (!topWin) {
6319 NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
6321 return nsnull;
6324 // If there is an active ESM in this window, clear it. Otherwise, this can
6325 // cause a problem if a modal state is entered during a mouseup event.
6326 nsEventStateManager* activeESM =
6327 static_cast<nsEventStateManager*>(nsEventStateManager::GetActiveEventStateManager());
6328 if (activeESM && activeESM->GetPresContext()) {
6329 nsIPresShell* activeShell = activeESM->GetPresContext()->GetPresShell();
6330 if (activeShell && (
6331 nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(), mDoc) ||
6332 nsContentUtils::ContentIsCrossDocDescendantOf(mDoc, activeShell->GetDocument()))) {
6333 nsEventStateManager::ClearGlobalActiveContent(activeESM);
6335 activeShell->SetCapturingContent(nsnull, 0);
6337 if (activeShell) {
6338 nsCOMPtr<nsFrameSelection> frameSelection = activeShell->FrameSelection();
6339 frameSelection->SetMouseDownState(PR_FALSE);
6344 if (topWin->mModalStateDepth == 0) {
6345 NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
6347 mSuspendedDoc = do_QueryInterface(topWin->GetExtantDocument());
6348 if (mSuspendedDoc && mSuspendedDoc->EventHandlingSuppressed()) {
6349 mSuspendedDoc->SuppressEventHandling();
6350 } else {
6351 mSuspendedDoc = nsnull;
6354 topWin->mModalStateDepth++;
6356 JSContext *cx = nsContentUtils::GetCurrentJSContext();
6358 nsCOMPtr<nsIDOMWindow> callerWin;
6359 nsIScriptContext *scx;
6360 if (cx && (scx = GetScriptContextFromJSContext(cx))) {
6361 scx->EnterModalState();
6362 callerWin = do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
6365 if (mContext) {
6366 mContext->EnterModalState();
6369 return callerWin;
6372 // static
6373 void
6374 nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
6375 nsGlobalWindow *aWindow)
6377 nsGlobalWindow *inner;
6379 // Return early if we're frozen or have no inner window.
6380 if (!(inner = aWindow->GetCurrentInnerWindowInternal()) ||
6381 inner->IsFrozen()) {
6382 return;
6385 inner->RunTimeout(nsnull);
6387 // Check again if we're frozen since running pending timeouts
6388 // could've frozen us.
6389 if (inner->IsFrozen()) {
6390 return;
6393 nsCOMPtr<nsIDOMWindowCollection> frames;
6394 aWindow->GetFrames(getter_AddRefs(frames));
6396 if (!frames) {
6397 return;
6400 PRUint32 i, length;
6401 if (NS_FAILED(frames->GetLength(&length)) || !length) {
6402 return;
6405 for (i = 0; i < length && aTopWindow->mModalStateDepth == 0; i++) {
6406 nsCOMPtr<nsIDOMWindow> child;
6407 frames->Item(i, getter_AddRefs(child));
6409 if (!child) {
6410 return;
6413 nsGlobalWindow *childWin =
6414 static_cast<nsGlobalWindow *>
6415 (static_cast<nsIDOMWindow *>
6416 (child.get()));
6418 RunPendingTimeoutsRecursive(aTopWindow, childWin);
6422 class nsPendingTimeoutRunner : public nsRunnable
6424 public:
6425 nsPendingTimeoutRunner(nsGlobalWindow *aWindow)
6426 : mWindow(aWindow)
6428 NS_ASSERTION(mWindow, "mWindow is null.");
6431 NS_IMETHOD Run()
6433 nsGlobalWindow::RunPendingTimeoutsRecursive(mWindow, mWindow);
6435 return NS_OK;
6438 private:
6439 nsRefPtr<nsGlobalWindow> mWindow;
6442 void
6443 nsGlobalWindow::LeaveModalState(nsIDOMWindow *aCallerWin)
6445 nsGlobalWindow *topWin = GetTop();
6447 if (!topWin) {
6448 NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
6449 return;
6452 topWin->mModalStateDepth--;
6454 if (topWin->mModalStateDepth == 0) {
6455 nsCOMPtr<nsIRunnable> runner = new nsPendingTimeoutRunner(topWin);
6456 if (NS_FAILED(NS_DispatchToCurrentThread(runner)))
6457 NS_WARNING("failed to dispatch pending timeout runnable");
6459 if (mSuspendedDoc) {
6460 nsCOMPtr<nsIDocument> currentDoc =
6461 do_QueryInterface(topWin->GetExtantDocument());
6462 mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(currentDoc == mSuspendedDoc);
6463 mSuspendedDoc = nsnull;
6467 JSContext *cx = nsContentUtils::GetCurrentJSContext();
6469 if (aCallerWin) {
6470 nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aCallerWin));
6471 nsIScriptContext *scx = sgo->GetContext();
6472 scx->LeaveModalState();
6475 if (mContext) {
6476 mContext->LeaveModalState();
6479 // Remember the time of the last dialog quit.
6480 nsGlobalWindow *inner = topWin->GetCurrentInnerWindowInternal();
6481 if (inner)
6482 inner->mLastDialogQuitTime = TimeStamp::Now();
6485 PRBool
6486 nsGlobalWindow::IsInModalState()
6488 nsGlobalWindow *topWin = GetTop();
6490 if (!topWin) {
6491 NS_ERROR("Uh, IsInModalState() called w/o a reachable top window?");
6493 return PR_FALSE;
6496 return topWin->mModalStateDepth != 0;
6499 // static
6500 void
6501 nsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow) {
6502 nsCOMPtr<nsIObserverService> observerService =
6503 do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
6504 if (observerService) {
6505 observerService->
6506 NotifyObservers(static_cast<nsIScriptGlobalObject*>(aWindow),
6507 DOM_WINDOW_DESTROYED_TOPIC, nsnull);
6511 class WindowDestroyedEvent : public nsRunnable
6513 public:
6514 WindowDestroyedEvent(PRUint64 aID, const char* aTopic) :
6515 mID(aID), mTopic(aTopic) {}
6517 NS_IMETHOD Run()
6519 nsCOMPtr<nsIObserverService> observerService =
6520 do_GetService("@mozilla.org/observer-service;1");
6521 if (observerService) {
6522 nsCOMPtr<nsISupportsPRUint64> wrapper =
6523 do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
6524 if (wrapper) {
6525 wrapper->SetData(mID);
6526 observerService->NotifyObservers(wrapper, mTopic.get(), nsnull);
6529 return NS_OK;
6532 private:
6533 PRUint64 mID;
6534 nsCString mTopic;
6537 void
6538 nsGlobalWindow::NotifyWindowIDDestroyed(const char* aTopic)
6540 nsRefPtr<nsIRunnable> runnable = new WindowDestroyedEvent(mWindowID, aTopic);
6541 nsresult rv = NS_DispatchToCurrentThread(runnable);
6542 if (NS_SUCCEEDED(rv)) {
6543 mNotifiedIDDestroyed = PR_TRUE;
6547 void
6548 nsGlobalWindow::InitJavaProperties()
6550 nsIScriptContext *scx = GetContextInternal();
6552 if (mDidInitJavaProperties || IsOuterWindow() || !scx || !mJSObject) {
6553 return;
6556 // Set mDidInitJavaProperties to true here even if initialization
6557 // can fail. If it fails, we won't try again...
6558 mDidInitJavaProperties = PR_TRUE;
6560 // Check whether the plugin supports NPRuntime, if so, init through
6561 // it.
6563 nsCOMPtr<nsIPluginHost> host(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
6564 if (!host) {
6565 return;
6568 mDummyJavaPluginOwner = new nsDummyJavaPluginOwner(mDoc);
6569 if (!mDummyJavaPluginOwner) {
6570 return;
6573 host->InstantiateDummyJavaPlugin(mDummyJavaPluginOwner);
6575 // It's possible for us (or the Java plugin, rather) to process
6576 // events during the above call, which can lead to this window being
6577 // torn down or what not, so re-check that the dummy plugin is still
6578 // around.
6579 if (!mDummyJavaPluginOwner) {
6580 return;
6583 nsCOMPtr<nsIPluginInstance> dummyPlugin;
6584 mDummyJavaPluginOwner->GetInstance(*getter_AddRefs(dummyPlugin));
6586 if (dummyPlugin) {
6587 // A dummy plugin was instantiated. This means we have a Java
6588 // plugin that supports NPRuntime. For such a plugin, the plugin
6589 // instantiation code defines the Java properties for us, so we're
6590 // done here.
6592 return;
6595 // No NPRuntime enabled Java plugin found, null out the owner we
6596 // would have used in that case as it's no longer needed.
6597 mDummyJavaPluginOwner = nsnull;
6600 void*
6601 nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey)
6603 void* handler = nsnull;
6604 if (mCachedXBLPrototypeHandlers.IsInitialized()) {
6605 mCachedXBLPrototypeHandlers.Get(aKey, &handler);
6607 return handler;
6610 void
6611 nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
6612 nsScriptObjectHolder& aHandler)
6614 if (!mCachedXBLPrototypeHandlers.IsInitialized() &&
6615 !mCachedXBLPrototypeHandlers.Init()) {
6616 NS_ERROR("Failed to initiailize hashtable!");
6617 return;
6620 if (!mCachedXBLPrototypeHandlers.Count()) {
6621 // Can't use macros to get the participant because nsGlobalChromeWindow also
6622 // runs through this code. Use QueryInterface to get the correct objects.
6623 nsXPCOMCycleCollectionParticipant* participant;
6624 CallQueryInterface(this, &participant);
6625 NS_ASSERTION(participant,
6626 "Failed to QI to nsXPCOMCycleCollectionParticipant!");
6628 nsISupports* thisSupports;
6629 QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
6630 reinterpret_cast<void**>(&thisSupports));
6631 NS_ASSERTION(thisSupports, "Failed to QI to nsCycleCollectionISupports!");
6633 nsresult rv = nsContentUtils::HoldJSObjects(thisSupports, participant);
6634 if (NS_FAILED(rv)) {
6635 NS_ERROR("nsContentUtils::HoldJSObjects failed!");
6636 return;
6640 mCachedXBLPrototypeHandlers.Put(aKey, aHandler);
6643 NS_IMETHODIMP
6644 nsGlobalWindow::GetFrameElement(nsIDOMElement** aFrameElement)
6646 FORWARD_TO_OUTER(GetFrameElement, (aFrameElement), NS_ERROR_NOT_INITIALIZED);
6648 *aFrameElement = nsnull;
6650 nsCOMPtr<nsIDocShellTreeItem> docShellTI(do_QueryInterface(mDocShell));
6652 if (!docShellTI) {
6653 return NS_OK;
6656 nsCOMPtr<nsIDocShellTreeItem> parent;
6657 docShellTI->GetSameTypeParent(getter_AddRefs(parent));
6659 if (!parent || parent == docShellTI) {
6660 // We're at a chrome boundary, don't expose the chrome iframe
6661 // element to content code.
6663 return NS_OK;
6666 *aFrameElement = mFrameElement;
6667 NS_IF_ADDREF(*aFrameElement);
6669 return NS_OK;
6672 // Helper for converting window.showModalDialog() options (list of ';'
6673 // separated name (:|=) value pairs) to a format that's parsable by
6674 // our normal window opening code.
6676 void
6677 ConvertDialogOptions(const nsAString& aOptions, nsAString& aResult)
6679 nsAString::const_iterator end;
6680 aOptions.EndReading(end);
6682 nsAString::const_iterator iter;
6683 aOptions.BeginReading(iter);
6685 while (iter != end) {
6686 // Skip whitespace.
6687 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6688 ++iter;
6691 nsAString::const_iterator name_start = iter;
6693 // Skip characters until we find whitespace, ';', ':', or '='
6694 while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
6695 *iter != ';' &&
6696 *iter != ':' &&
6697 *iter != '=') {
6698 ++iter;
6701 nsAString::const_iterator name_end = iter;
6703 // Skip whitespace.
6704 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6705 ++iter;
6708 if (*iter == ';') {
6709 // No value found, skip the ';' and keep going.
6710 ++iter;
6712 continue;
6715 nsAString::const_iterator value_start = iter;
6716 nsAString::const_iterator value_end = iter;
6718 if (*iter == ':' || *iter == '=') {
6719 // We found name followed by ':' or '='. Look for a value.
6721 iter++; // Skip the ':' or '='
6723 // Skip whitespace.
6724 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6725 ++iter;
6728 value_start = iter;
6730 // Skip until we find whitespace, or ';'.
6731 while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
6732 *iter != ';') {
6733 ++iter;
6736 value_end = iter;
6738 // Skip whitespace.
6739 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6740 ++iter;
6744 const nsDependentSubstring& name = Substring(name_start, name_end);
6745 const nsDependentSubstring& value = Substring(value_start, value_end);
6747 if (name.LowerCaseEqualsLiteral("center")) {
6748 if (value.LowerCaseEqualsLiteral("on") ||
6749 value.LowerCaseEqualsLiteral("yes") ||
6750 value.LowerCaseEqualsLiteral("1")) {
6751 aResult.AppendLiteral(",centerscreen=1");
6753 } else if (name.LowerCaseEqualsLiteral("dialogwidth")) {
6754 if (!value.IsEmpty()) {
6755 aResult.AppendLiteral(",width=");
6756 aResult.Append(value);
6758 } else if (name.LowerCaseEqualsLiteral("dialogheight")) {
6759 if (!value.IsEmpty()) {
6760 aResult.AppendLiteral(",height=");
6761 aResult.Append(value);
6763 } else if (name.LowerCaseEqualsLiteral("dialogtop")) {
6764 if (!value.IsEmpty()) {
6765 aResult.AppendLiteral(",top=");
6766 aResult.Append(value);
6768 } else if (name.LowerCaseEqualsLiteral("dialogleft")) {
6769 if (!value.IsEmpty()) {
6770 aResult.AppendLiteral(",left=");
6771 aResult.Append(value);
6773 } else if (name.LowerCaseEqualsLiteral("resizable")) {
6774 if (value.LowerCaseEqualsLiteral("on") ||
6775 value.LowerCaseEqualsLiteral("yes") ||
6776 value.LowerCaseEqualsLiteral("1")) {
6777 aResult.AppendLiteral(",resizable=1");
6779 } else if (name.LowerCaseEqualsLiteral("scroll")) {
6780 if (value.LowerCaseEqualsLiteral("off") ||
6781 value.LowerCaseEqualsLiteral("no") ||
6782 value.LowerCaseEqualsLiteral("0")) {
6783 aResult.AppendLiteral(",scrollbars=0");
6787 if (iter == end) {
6788 break;
6791 iter++;
6795 NS_IMETHODIMP
6796 nsGlobalWindow::ShowModalDialog(const nsAString& aURI, nsIVariant *aArgs,
6797 const nsAString& aOptions,
6798 nsIVariant **aRetVal)
6800 FORWARD_TO_OUTER(ShowModalDialog, (aURI, aArgs, aOptions, aRetVal),
6801 NS_ERROR_NOT_INITIALIZED);
6803 *aRetVal = nsnull;
6805 // Before bringing up the window/dialog, unsuppress painting and flush
6806 // pending reflows.
6807 EnsureReflowFlushAndPaint();
6809 if (AreDialogsBlocked() || !ConfirmDialogAllowed())
6810 return NS_ERROR_NOT_AVAILABLE;
6812 nsCOMPtr<nsIDOMWindow> dlgWin;
6813 nsAutoString options(NS_LITERAL_STRING("-moz-internal-modal=1,status=1"));
6815 ConvertDialogOptions(aOptions, options);
6817 options.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0");
6819 EnterModalState();
6820 nsresult rv = OpenInternal(aURI, EmptyString(), options,
6821 PR_FALSE, // aDialog
6822 PR_TRUE, // aContentModal
6823 PR_TRUE, // aCalledNoScript
6824 PR_TRUE, // aDoJSFixups
6825 nsnull, aArgs, // args
6826 GetPrincipal(), // aCalleePrincipal
6827 nsnull, // aJSCallerContext
6828 getter_AddRefs(dlgWin));
6829 LeaveModalState(nsnull);
6831 NS_ENSURE_SUCCESS(rv, rv);
6833 if (dlgWin) {
6834 nsCOMPtr<nsIPrincipal> subjectPrincipal;
6835 rv = nsContentUtils::GetSecurityManager()->
6836 GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
6837 if (NS_FAILED(rv)) {
6838 return rv;
6841 PRBool canAccess = PR_TRUE;
6843 if (subjectPrincipal) {
6844 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
6845 do_QueryInterface(dlgWin);
6846 nsCOMPtr<nsIPrincipal> dialogPrincipal;
6848 if (objPrincipal) {
6849 dialogPrincipal = objPrincipal->GetPrincipal();
6851 rv = subjectPrincipal->Subsumes(dialogPrincipal, &canAccess);
6852 NS_ENSURE_SUCCESS(rv, rv);
6853 } else {
6854 // Uh, not sure what kind of dialog this is. Prevent access to
6855 // be on the safe side...
6857 canAccess = PR_FALSE;
6861 nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(dlgWin));
6863 if (canAccess) {
6864 nsPIDOMWindow *inner = win->GetCurrentInnerWindow();
6866 nsCOMPtr<nsIDOMModalContentWindow> dlgInner(do_QueryInterface(inner));
6868 if (dlgInner) {
6869 dlgInner->GetReturnValue(aRetVal);
6873 nsRefPtr<nsGlobalWindow> winInternal =
6874 static_cast<nsGlobalWindow*>(win.get());
6875 if (winInternal->mCallCleanUpAfterModalDialogCloses) {
6876 winInternal->mCallCleanUpAfterModalDialogCloses = PR_FALSE;
6877 winInternal->CleanUp(PR_TRUE);
6881 return NS_OK;
6884 class CommandDispatcher : public nsRunnable
6886 public:
6887 CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
6888 const nsAString& aAction)
6889 : mDispatcher(aDispatcher), mAction(aAction) {}
6891 NS_IMETHOD Run()
6893 return mDispatcher->UpdateCommands(mAction);
6896 nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
6897 nsString mAction;
6900 NS_IMETHODIMP
6901 nsGlobalWindow::UpdateCommands(const nsAString& anAction)
6903 nsPIDOMWindow *rootWindow = nsGlobalWindow::GetPrivateRoot();
6904 if (!rootWindow)
6905 return NS_OK;
6907 nsCOMPtr<nsIDOMXULDocument> xulDoc =
6908 do_QueryInterface(rootWindow->GetExtantDocument());
6909 // See if we contain a XUL document.
6910 if (xulDoc) {
6911 // Retrieve the command dispatcher and call updateCommands on it.
6912 nsCOMPtr<nsIDOMXULCommandDispatcher> xulCommandDispatcher;
6913 xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher));
6914 if (xulCommandDispatcher) {
6915 nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
6916 anAction));
6920 return NS_OK;
6923 PRBool
6924 nsGlobalWindow::GetBlurSuppression()
6926 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
6927 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
6928 PRBool suppress = PR_FALSE;
6929 if (treeOwnerAsWin)
6930 treeOwnerAsWin->GetBlurSuppression(&suppress);
6931 return suppress;
6934 NS_IMETHODIMP
6935 nsGlobalWindow::GetSelection(nsISelection** aSelection)
6937 FORWARD_TO_OUTER(GetSelection, (aSelection), NS_ERROR_NOT_INITIALIZED);
6939 NS_ENSURE_ARG_POINTER(aSelection);
6940 *aSelection = nsnull;
6942 if (!mDocShell)
6943 return NS_OK;
6945 nsCOMPtr<nsIPresShell> presShell;
6946 mDocShell->GetPresShell(getter_AddRefs(presShell));
6948 if (!presShell)
6949 return NS_OK;
6951 *aSelection = presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
6953 NS_IF_ADDREF(*aSelection);
6955 return NS_OK;
6958 NS_IMETHODIMP
6959 nsGlobalWindow::Find(const nsAString& aStr, PRBool aCaseSensitive,
6960 PRBool aBackwards, PRBool aWrapAround, PRBool aWholeWord,
6961 PRBool aSearchInFrames, PRBool aShowDialog,
6962 PRBool *aDidFind)
6964 FORWARD_TO_OUTER(Find, (aStr, aCaseSensitive, aBackwards, aWrapAround,
6965 aWholeWord, aSearchInFrames, aShowDialog, aDidFind),
6966 NS_ERROR_NOT_INITIALIZED);
6968 nsresult rv = NS_OK;
6969 *aDidFind = PR_FALSE;
6971 nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
6972 NS_ENSURE_TRUE(finder, NS_ERROR_FAILURE);
6974 // Set the options of the search
6975 rv = finder->SetSearchString(PromiseFlatString(aStr).get());
6976 NS_ENSURE_SUCCESS(rv, rv);
6977 finder->SetMatchCase(aCaseSensitive);
6978 finder->SetFindBackwards(aBackwards);
6979 finder->SetWrapFind(aWrapAround);
6980 finder->SetEntireWord(aWholeWord);
6981 finder->SetSearchFrames(aSearchInFrames);
6983 // the nsIWebBrowserFind is initialized to use this window
6984 // as the search root, but uses focus to set the current search
6985 // frame. If we're being called from JS (as here), this window
6986 // should be the current search frame.
6987 nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
6988 if (framesFinder) {
6989 framesFinder->SetRootSearchFrame(this); // paranoia
6990 framesFinder->SetCurrentSearchFrame(this);
6993 // The Find API does not accept empty strings. Launch the Find Dialog.
6994 if (aStr.IsEmpty() || aShowDialog) {
6995 // See if the find dialog is already up using nsIWindowMediator
6996 nsCOMPtr<nsIWindowMediator> windowMediator =
6997 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
6999 nsCOMPtr<nsIDOMWindowInternal> findDialog;
7001 if (windowMediator) {
7002 windowMediator->GetMostRecentWindow(NS_LITERAL_STRING("findInPage").get(),
7003 getter_AddRefs(findDialog));
7006 if (findDialog) {
7007 // The Find dialog is already open, bring it to the top.
7008 rv = findDialog->Focus();
7009 } else { // Open a Find dialog
7010 if (finder) {
7011 nsCOMPtr<nsIDOMWindow> dialog;
7012 rv = OpenDialog(NS_LITERAL_STRING("chrome://global/content/finddialog.xul"),
7013 NS_LITERAL_STRING("_blank"),
7014 NS_LITERAL_STRING("chrome, resizable=no, dependent=yes"),
7015 finder, getter_AddRefs(dialog));
7018 } else {
7019 // Launch the search with the passed in search string
7020 rv = finder->FindNext(aDidFind);
7021 NS_ENSURE_SUCCESS(rv, rv);
7024 return rv;
7027 static PRBool
7028 Is8bit(const nsAString& aString)
7030 static const PRUnichar EIGHT_BIT = PRUnichar(~0x00FF);
7032 nsAString::const_iterator done_reading;
7033 aString.EndReading(done_reading);
7035 // for each chunk of |aString|...
7036 PRUint32 fragmentLength = 0;
7037 nsAString::const_iterator iter;
7038 for (aString.BeginReading(iter); iter != done_reading;
7039 iter.advance(PRInt32(fragmentLength))) {
7040 fragmentLength = PRUint32(iter.size_forward());
7041 const PRUnichar* c = iter.get();
7042 const PRUnichar* fragmentEnd = c + fragmentLength;
7044 // for each character in this chunk...
7045 while (c < fragmentEnd)
7046 if (*c++ & EIGHT_BIT)
7047 return PR_FALSE;
7050 return PR_TRUE;
7053 NS_IMETHODIMP
7054 nsGlobalWindow::Atob(const nsAString& aAsciiBase64String,
7055 nsAString& aBinaryData)
7057 if (!Is8bit(aAsciiBase64String)) {
7058 aBinaryData.Truncate();
7059 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
7062 nsresult rv = nsXPConnect::Base64Decode(aAsciiBase64String, aBinaryData);
7063 if (NS_FAILED(rv) && rv == NS_ERROR_INVALID_ARG) {
7064 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
7066 return rv;
7069 NS_IMETHODIMP
7070 nsGlobalWindow::Btoa(const nsAString& aBinaryData,
7071 nsAString& aAsciiBase64String)
7073 if (!Is8bit(aBinaryData)) {
7074 aAsciiBase64String.Truncate();
7075 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
7078 return nsXPConnect::Base64Encode(aBinaryData, aAsciiBase64String);
7081 //*****************************************************************************
7082 // nsGlobalWindow::nsIDOMEventTarget
7083 //*****************************************************************************
7085 NS_IMETHODIMP
7086 nsGlobalWindow::AddEventListener(const nsAString& aType,
7087 nsIDOMEventListener* aListener,
7088 PRBool aUseCapture)
7090 FORWARD_TO_INNER_CREATE(AddEventListener, (aType, aListener, aUseCapture),
7091 NS_ERROR_NOT_AVAILABLE);
7093 return AddEventListener(aType, aListener, aUseCapture, PR_FALSE, 0);
7096 NS_IMETHODIMP
7097 nsGlobalWindow::RemoveEventListener(const nsAString& aType,
7098 nsIDOMEventListener* aListener,
7099 PRBool aUseCapture)
7101 return RemoveGroupedEventListener(aType, aListener, aUseCapture, nsnull);
7104 NS_IMETHODIMP
7105 nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, PRBool* _retval)
7107 FORWARD_TO_INNER(DispatchEvent, (aEvent, _retval), NS_OK);
7109 if (!mDoc) {
7110 return NS_ERROR_FAILURE;
7113 // Obtain a presentation shell
7114 nsIPresShell *shell = mDoc->GetShell();
7115 nsRefPtr<nsPresContext> presContext;
7116 if (shell) {
7117 // Retrieve the context
7118 presContext = shell->GetPresContext();
7121 nsEventStatus status = nsEventStatus_eIgnore;
7122 nsresult rv =
7123 nsEventDispatcher::DispatchDOMEvent(GetOuterWindow(), nsnull, aEvent,
7124 presContext, &status);
7126 *_retval = (status != nsEventStatus_eConsumeNoDefault);
7127 return rv;
7130 //*****************************************************************************
7131 // nsGlobalWindow::nsIDOM3EventTarget
7132 //*****************************************************************************
7134 NS_IMETHODIMP
7135 nsGlobalWindow::AddGroupedEventListener(const nsAString & aType,
7136 nsIDOMEventListener *aListener,
7137 PRBool aUseCapture,
7138 nsIDOMEventGroup *aEvtGrp)
7140 FORWARD_TO_INNER_CREATE(AddGroupedEventListener,
7141 (aType, aListener, aUseCapture, aEvtGrp),
7142 NS_ERROR_NOT_AVAILABLE);
7144 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
7145 NS_ENSURE_STATE(manager);
7146 PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
7147 return manager->AddEventListenerByType(aListener, aType, flags, aEvtGrp);
7150 NS_IMETHODIMP
7151 nsGlobalWindow::RemoveGroupedEventListener(const nsAString & aType,
7152 nsIDOMEventListener *aListener,
7153 PRBool aUseCapture,
7154 nsIDOMEventGroup *aEvtGrp)
7156 FORWARD_TO_INNER(RemoveGroupedEventListener,
7157 (aType, aListener, aUseCapture, aEvtGrp),
7158 NS_ERROR_NOT_INITIALIZED);
7160 if (mListenerManager) {
7161 PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
7163 mListenerManager->RemoveEventListenerByType(aListener, aType, flags,
7164 aEvtGrp);
7166 return NS_OK;
7169 NS_IMETHODIMP
7170 nsGlobalWindow::CanTrigger(const nsAString & type, PRBool *_retval)
7172 return NS_ERROR_NOT_IMPLEMENTED;
7175 NS_IMETHODIMP
7176 nsGlobalWindow::IsRegisteredHere(const nsAString & type, PRBool *_retval)
7178 return NS_ERROR_NOT_IMPLEMENTED;
7181 NS_IMETHODIMP
7182 nsGlobalWindow::AddEventListener(const nsAString& aType,
7183 nsIDOMEventListener *aListener,
7184 PRBool aUseCapture, PRBool aWantsUntrusted,
7185 PRUint8 optional_argc)
7187 NS_ASSERTION(!aWantsUntrusted || optional_argc > 0,
7188 "Won't check if this is chrome, you want to set "
7189 "aWantsUntrusted to PR_FALSE or make the aWantsUntrusted "
7190 "explicit by making optional_argc non-zero.");
7192 if (IsOuterWindow() && mInnerWindow &&
7193 !nsContentUtils::CanCallerAccess(mInnerWindow)) {
7194 return NS_ERROR_DOM_SECURITY_ERR;
7197 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
7198 NS_ENSURE_STATE(manager);
7200 PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
7202 if (aWantsUntrusted ||
7203 (optional_argc == 0 && !nsContentUtils::IsChromeDoc(mDoc))) {
7204 flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
7207 return manager->AddEventListenerByType(aListener, aType, flags, nsnull);
7210 nsresult
7211 nsGlobalWindow::AddEventListenerByIID(nsIDOMEventListener* aListener,
7212 const nsIID& aIID)
7214 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
7215 NS_ENSURE_STATE(manager);
7216 return manager->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
7219 nsresult
7220 nsGlobalWindow::RemoveEventListenerByIID(nsIDOMEventListener* aListener,
7221 const nsIID& aIID)
7223 FORWARD_TO_INNER(RemoveEventListenerByIID, (aListener, aIID),
7224 NS_ERROR_NOT_INITIALIZED);
7226 if (mListenerManager) {
7227 mListenerManager->RemoveEventListenerByIID(aListener, aIID,
7228 NS_EVENT_FLAG_BUBBLE);
7229 return NS_OK;
7231 return NS_ERROR_FAILURE;
7234 nsIEventListenerManager*
7235 nsGlobalWindow::GetListenerManager(PRBool aCreateIfNotFound)
7237 FORWARD_TO_INNER_CREATE(GetListenerManager, (aCreateIfNotFound), nsnull);
7239 if (!mListenerManager) {
7240 if (!aCreateIfNotFound) {
7241 return nsnull;
7244 static NS_DEFINE_CID(kEventListenerManagerCID,
7245 NS_EVENTLISTENERMANAGER_CID);
7247 mListenerManager = do_CreateInstance(kEventListenerManagerCID);
7248 if (mListenerManager) {
7249 mListenerManager->SetListenerTarget(
7250 static_cast<nsPIDOMEventTarget*>(this));
7254 return mListenerManager;
7257 nsresult
7258 nsGlobalWindow::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
7260 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
7261 NS_ENSURE_STATE(manager);
7262 return manager->GetSystemEventGroupLM(aGroup);
7265 nsIScriptContext*
7266 nsGlobalWindow::GetContextForEventHandlers(nsresult* aRv)
7268 nsIScriptContext* scx = GetContext();
7269 *aRv = scx ? NS_OK : NS_ERROR_UNEXPECTED;
7270 return scx;
7273 //*****************************************************************************
7274 // nsGlobalWindow::nsPIDOMWindow
7275 //*****************************************************************************
7277 nsPIDOMWindow*
7278 nsGlobalWindow::GetPrivateParent()
7280 FORWARD_TO_OUTER(GetPrivateParent, (), nsnull);
7282 nsCOMPtr<nsIDOMWindow> parent;
7283 GetParent(getter_AddRefs(parent));
7285 if (static_cast<nsIDOMWindow *>(this) == parent.get()) {
7286 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
7287 if (!chromeElement)
7288 return nsnull; // This is ok, just means a null parent.
7290 nsIDocument* doc = chromeElement->GetDocument();
7291 if (!doc)
7292 return nsnull; // This is ok, just means a null parent.
7294 nsIScriptGlobalObject *globalObject = doc->GetScriptGlobalObject();
7295 if (!globalObject)
7296 return nsnull; // This is ok, just means a null parent.
7298 parent = do_QueryInterface(globalObject);
7301 if (parent) {
7302 return static_cast<nsGlobalWindow *>
7303 (static_cast<nsIDOMWindow*>(parent.get()));
7306 return nsnull;
7309 nsPIDOMWindow*
7310 nsGlobalWindow::GetPrivateRoot()
7312 FORWARD_TO_OUTER(GetPrivateRoot, (), nsnull);
7314 nsCOMPtr<nsIDOMWindow> top;
7315 GetTop(getter_AddRefs(top));
7317 nsCOMPtr<nsPIDOMWindow> ptop = do_QueryInterface(top);
7318 NS_ASSERTION(ptop, "cannot get ptop");
7319 if (!ptop)
7320 return nsnull;
7322 nsIDocShell *docShell = ptop->GetDocShell();
7324 // Get the chrome event handler from the doc shell, since we only
7325 // want to deal with XUL chrome handlers and not the new kind of
7326 // window root handler.
7327 nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
7328 docShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
7330 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
7331 if (chromeElement) {
7332 nsIDocument* doc = chromeElement->GetDocument();
7333 if (doc) {
7334 nsIDOMWindow *parent = doc->GetWindow();
7335 if (parent) {
7336 parent->GetTop(getter_AddRefs(top));
7341 return static_cast<nsGlobalWindow *>
7342 (static_cast<nsIDOMWindow *>(top));
7346 NS_IMETHODIMP
7347 nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation)
7349 FORWARD_TO_INNER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED);
7351 *aLocation = nsnull;
7353 nsIDocShell *docShell = GetDocShell();
7354 if (!mLocation && docShell) {
7355 mLocation = new nsLocation(docShell);
7356 if (!mLocation) {
7357 return NS_ERROR_OUT_OF_MEMORY;
7361 NS_IF_ADDREF(*aLocation = mLocation);
7363 return NS_OK;
7366 void
7367 nsGlobalWindow::ActivateOrDeactivate(PRBool aActivate)
7369 // Set / unset mIsActive on the top level window, which is used for the
7370 // :-moz-window-inactive pseudoclass.
7371 nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
7372 if (!mainWidget)
7373 return;
7375 // Get the top level widget (if the main widget is a sheet, this will
7376 // be the sheet's top (non-sheet) parent).
7377 nsCOMPtr<nsIWidget> topLevelWidget = mainWidget->GetSheetWindowParent();
7378 if (!topLevelWidget) {
7379 topLevelWidget = mainWidget;
7382 // Get the top level widget's nsGlobalWindow
7383 nsCOMPtr<nsIDOMWindowInternal> topLevelWindow;
7384 if (topLevelWidget == mainWidget) {
7385 topLevelWindow = static_cast<nsIDOMWindowInternal*>(this);
7386 } else {
7387 // This is a workaround for the following problem:
7388 // When a window with an open sheet loses focus, only the sheet window
7389 // receives the NS_DEACTIVATE event. However, it's not the sheet that
7390 // should lose the active styling, but the containing top level window.
7391 void* clientData;
7392 topLevelWidget->GetClientData(clientData); // clientData is nsXULWindow
7393 nsISupports* data = static_cast<nsISupports*>(clientData);
7394 nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(data));
7395 topLevelWindow = do_GetInterface(req);
7397 if (topLevelWindow) {
7398 nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(topLevelWindow));
7399 piWin->SetActive(aActivate);
7403 static PRBool
7404 NotifyDocumentTree(nsIDocument* aDocument, void* aData)
7406 aDocument->EnumerateSubDocuments(NotifyDocumentTree, nsnull);
7407 aDocument->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
7408 return PR_TRUE;
7411 void
7412 nsGlobalWindow::SetActive(PRBool aActive)
7414 nsPIDOMWindow::SetActive(aActive);
7415 NotifyDocumentTree(mDoc, nsnull);
7418 void nsGlobalWindow::MaybeUpdateTouchState()
7420 FORWARD_TO_INNER_VOID(MaybeUpdateTouchState, ());
7422 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7424 nsCOMPtr<nsIDOMWindow> focusedWindow;
7425 fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
7427 if(this == focusedWindow) {
7428 UpdateTouchState();
7432 void nsGlobalWindow::UpdateTouchState()
7434 FORWARD_TO_INNER_VOID(UpdateTouchState, ());
7436 nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
7437 if (!mainWidget)
7438 return;
7440 if (mMayHaveTouchEventListener) {
7441 mainWidget->RegisterTouchWindow();
7442 } else {
7443 mainWidget->UnregisterTouchWindow();
7448 void
7449 nsGlobalWindow::EnableAccelerationUpdates()
7451 if (mHasAcceleration) {
7452 nsCOMPtr<nsIAccelerometer> ac =
7453 do_GetService(NS_ACCELEROMETER_CONTRACTID);
7454 if (ac) {
7455 ac->AddWindowListener(this);
7460 void
7461 nsGlobalWindow::DisableAccelerationUpdates()
7463 if (mHasAcceleration) {
7464 nsCOMPtr<nsIAccelerometer> ac =
7465 do_GetService(NS_ACCELEROMETER_CONTRACTID);
7466 if (ac) {
7467 ac->RemoveWindowListener(this);
7472 void
7473 nsGlobalWindow::SetChromeEventHandler(nsPIDOMEventTarget* aChromeEventHandler)
7475 SetChromeEventHandlerInternal(aChromeEventHandler);
7476 if (IsOuterWindow()) {
7477 // update the chrome event handler on all our inner windows
7478 for (nsGlobalWindow *inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
7479 inner != this;
7480 inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
7481 NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
7482 "bad outer window pointer");
7483 inner->SetChromeEventHandlerInternal(aChromeEventHandler);
7485 } else if (mOuterWindow) {
7486 // Need the cast to be able to call the protected method on a
7487 // superclass. We could make the method public instead, but it's really
7488 // better this way.
7489 static_cast<nsGlobalWindow*>(mOuterWindow.get())->
7490 SetChromeEventHandlerInternal(aChromeEventHandler);
7494 static PRBool IsLink(nsIContent* aContent)
7496 nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = do_QueryInterface(aContent);
7497 return (anchor || (aContent &&
7498 aContent->AttrValueIs(kNameSpaceID_XLink, nsGkAtoms::type,
7499 nsGkAtoms::simple, eCaseMatters)));
7502 void
7503 nsGlobalWindow::SetFocusedNode(nsIContent* aNode,
7504 PRUint32 aFocusMethod,
7505 PRBool aNeedsFocus)
7507 FORWARD_TO_INNER_VOID(SetFocusedNode, (aNode, aFocusMethod, aNeedsFocus));
7509 NS_ASSERTION(!aNode || aNode->GetCurrentDoc() == mDoc,
7510 "setting focus to a node from the wrong document");
7512 if (mFocusedNode != aNode) {
7513 UpdateCanvasFocus(PR_FALSE, aNode);
7514 mFocusedNode = aNode;
7515 mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
7516 mShowFocusRingForContent = PR_FALSE;
7519 if (mFocusedNode) {
7520 // if a node was focused by a keypress, turn on focus rings for the
7521 // window.
7522 if (mFocusMethod & nsIFocusManager::FLAG_BYKEY) {
7523 mFocusByKeyOccurred = PR_TRUE;
7524 } else if (
7525 // otherwise, we set mShowFocusRingForContent, as we don't want this to
7526 // be permanent for the window. On Windows, focus rings are only shown
7527 // when the FLAG_SHOWRING flag is used. On other platforms, focus rings
7528 // are only hidden for clicks on links.
7529 #ifndef XP_WIN
7530 !(mFocusMethod & nsIFocusManager::FLAG_BYMOUSE) || !IsLink(aNode) ||
7531 #endif
7532 aFocusMethod & nsIFocusManager::FLAG_SHOWRING) {
7533 mShowFocusRingForContent = PR_TRUE;
7537 if (aNeedsFocus)
7538 mNeedsFocus = aNeedsFocus;
7541 PRUint32
7542 nsGlobalWindow::GetFocusMethod()
7544 FORWARD_TO_INNER(GetFocusMethod, (), 0);
7546 return mFocusMethod;
7549 PRBool
7550 nsGlobalWindow::ShouldShowFocusRing()
7552 FORWARD_TO_INNER(ShouldShowFocusRing, (), PR_FALSE);
7554 return mShowFocusRings || mShowFocusRingForContent || mFocusByKeyOccurred;
7557 void
7558 nsGlobalWindow::SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
7559 UIStateChangeType aShowFocusRings)
7561 FORWARD_TO_INNER_VOID(SetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
7563 // only change the flags that have been modified
7564 if (aShowAccelerators != UIStateChangeType_NoChange)
7565 mShowAccelerators = aShowAccelerators == UIStateChangeType_Set;
7566 if (aShowFocusRings != UIStateChangeType_NoChange)
7567 mShowFocusRings = aShowFocusRings == UIStateChangeType_Set;
7569 // propagate the indicators to child windows
7570 nsCOMPtr<nsIDocShellTreeNode> node = do_QueryInterface(GetDocShell());
7571 if (node) {
7572 PRInt32 childCount = 0;
7573 node->GetChildCount(&childCount);
7575 for (PRInt32 i = 0; i < childCount; ++i) {
7576 nsCOMPtr<nsIDocShellTreeItem> childShell;
7577 node->GetChildAt(i, getter_AddRefs(childShell));
7578 nsCOMPtr<nsPIDOMWindow> childWindow = do_GetInterface(childShell);
7579 if (childWindow) {
7580 childWindow->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
7585 if (mHasFocus) {
7586 // send content state notifications
7587 nsCOMPtr<nsPresContext> presContext;
7588 if (mDocShell) {
7589 mDocShell->GetPresContext(getter_AddRefs(presContext));
7590 if (presContext) {
7591 presContext->EventStateManager()->
7592 SetContentState(mFocusedNode, NS_EVENT_STATE_FOCUS);
7598 void
7599 nsGlobalWindow::GetKeyboardIndicators(PRBool* aShowAccelerators,
7600 PRBool* aShowFocusRings)
7602 FORWARD_TO_INNER_VOID(GetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
7604 *aShowAccelerators = mShowAccelerators;
7605 *aShowFocusRings = mShowFocusRings;
7608 PRBool
7609 nsGlobalWindow::TakeFocus(PRBool aFocus, PRUint32 aFocusMethod)
7611 FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), PR_FALSE);
7613 if (aFocus)
7614 mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
7616 if (mHasFocus != aFocus) {
7617 mHasFocus = aFocus;
7618 UpdateCanvasFocus(PR_TRUE, mFocusedNode);
7621 // if mNeedsFocus is true, then the document has not yet received a
7622 // document-level focus event. If there is a root content node, then return
7623 // true to tell the calling focus manager that a focus event is expected. If
7624 // there is no root content node, the document hasn't loaded enough yet, or
7625 // there isn't one and there is no point in firing a focus event.
7626 if (aFocus && mNeedsFocus && mDoc && mDoc->GetRootElement() != nsnull) {
7627 mNeedsFocus = PR_FALSE;
7628 return PR_TRUE;
7631 mNeedsFocus = PR_FALSE;
7632 return PR_FALSE;
7635 void
7636 nsGlobalWindow::SetReadyForFocus()
7638 FORWARD_TO_INNER_VOID(SetReadyForFocus, ());
7640 PRBool oldNeedsFocus = mNeedsFocus;
7641 mNeedsFocus = PR_FALSE;
7643 // update whether focus rings need to be shown using the state from the
7644 // root window
7645 nsPIDOMWindow* root = GetPrivateRoot();
7646 if (root) {
7647 PRBool showAccelerators, showFocusRings;
7648 root->GetKeyboardIndicators(&showAccelerators, &showFocusRings);
7649 mShowFocusRings = showFocusRings;
7652 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7653 if (fm)
7654 fm->WindowShown(this, oldNeedsFocus);
7657 void
7658 nsGlobalWindow::PageHidden()
7660 FORWARD_TO_INNER_VOID(PageHidden, ());
7662 // the window is being hidden, so tell the focus manager that the frame is
7663 // no longer valid. Use the persisted field to determine if the document
7664 // is being destroyed.
7666 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7667 if (fm)
7668 fm->WindowHidden(this);
7670 mNeedsFocus = PR_TRUE;
7673 nsresult
7674 nsGlobalWindow::DispatchAsyncHashchange()
7676 FORWARD_TO_INNER(DispatchAsyncHashchange, (), NS_OK);
7678 nsCOMPtr<nsIRunnable> event =
7679 NS_NewRunnableMethod(this, &nsGlobalWindow::FireHashchange);
7681 return NS_DispatchToCurrentThread(event);
7684 nsresult
7685 nsGlobalWindow::FireHashchange()
7687 NS_ENSURE_TRUE(IsInnerWindow(), NS_ERROR_FAILURE);
7689 // Don't do anything if the window is frozen.
7690 if (IsFrozen())
7691 return NS_OK;
7693 // Dispatch the hashchange event, which doesn't bubble and isn't cancelable,
7694 // to the outer window.
7695 return nsContentUtils::DispatchTrustedEvent(mDoc, GetOuterWindow(),
7696 NS_LITERAL_STRING("hashchange"),
7697 PR_FALSE, PR_FALSE);
7700 nsresult
7701 nsGlobalWindow::DispatchSyncPopState(PRBool aIsInitial)
7703 FORWARD_TO_INNER(DispatchSyncPopState, (aIsInitial), NS_OK);
7705 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
7706 "Must be safe to run script here.");
7708 // Check that PopState hasn't been pref'ed off.
7709 if (!nsContentUtils::GetBoolPref(sPopStatePrefStr, PR_FALSE))
7710 return NS_OK;
7712 nsresult rv = NS_OK;
7714 // Bail if the window is frozen.
7715 if (IsFrozen()) {
7716 return NS_OK;
7719 // Get the document's pending state object -- it contains the data we're
7720 // going to send along with the popstate event. The object is serialized as
7721 // JSON.
7722 nsCOMPtr<nsIVariant> stateObj;
7723 nsCOMPtr<nsIDOMNSDocument_MOZILLA_2_0_BRANCH> doc2 = do_QueryInterface(mDoc);
7724 if (!doc2) {
7725 return NS_OK;
7728 rv = doc2->GetMozCurrentStateObject(getter_AddRefs(stateObj));
7729 NS_ENSURE_SUCCESS(rv, rv);
7731 // Obtain a presentation shell for use in creating a popstate event.
7732 nsIPresShell *shell = mDoc->GetShell();
7733 nsRefPtr<nsPresContext> presContext;
7734 if (shell) {
7735 presContext = shell->GetPresContext();
7738 // Create a new popstate event
7739 nsCOMPtr<nsIDOMEvent> domEvent;
7740 rv = nsEventDispatcher::CreateEvent(presContext, nsnull,
7741 NS_LITERAL_STRING("popstateevent"),
7742 getter_AddRefs(domEvent));
7743 NS_ENSURE_SUCCESS(rv, rv);
7745 nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(domEvent);
7746 NS_ENSURE_TRUE(privateEvent, NS_ERROR_FAILURE);
7748 // Initialize the popstate event, which does bubble but isn't cancellable.
7749 nsCOMPtr<nsIDOMPopStateEvent_MOZILLA_2_BRANCH> popstateEvent =
7750 do_QueryInterface(domEvent);
7751 rv = popstateEvent->InitPopStateEvent(NS_LITERAL_STRING("popstate"),
7752 PR_TRUE, PR_FALSE,
7753 stateObj,
7754 aIsInitial);
7755 NS_ENSURE_SUCCESS(rv, rv);
7757 rv = privateEvent->SetTrusted(PR_TRUE);
7758 NS_ENSURE_SUCCESS(rv, rv);
7760 nsCOMPtr<nsIDOMEventTarget> outerWindow =
7761 do_QueryInterface(GetOuterWindow());
7762 NS_ENSURE_TRUE(outerWindow, NS_ERROR_UNEXPECTED);
7764 rv = privateEvent->SetTarget(outerWindow);
7765 NS_ENSURE_SUCCESS(rv, rv);
7767 PRBool dummy; // default action
7768 return DispatchEvent(domEvent, &dummy);
7771 // Find an nsICanvasFrame under aFrame. Only search the principal
7772 // child lists. aFrame must be non-null.
7773 static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame)
7775 nsCanvasFrame* canvasFrame = do_QueryFrame(aFrame);
7776 if (canvasFrame) {
7777 return canvasFrame;
7780 nsIFrame* kid = aFrame->GetFirstChild(nsnull);
7781 while (kid) {
7782 canvasFrame = FindCanvasFrame(kid);
7783 if (canvasFrame) {
7784 return canvasFrame;
7786 kid = kid->GetNextSibling();
7789 return nsnull;
7792 //-------------------------------------------------------
7793 // Tells the HTMLFrame/CanvasFrame that is now has focus
7794 void
7795 nsGlobalWindow::UpdateCanvasFocus(PRBool aFocusChanged, nsIContent* aNewContent)
7797 // this is called from the inner window so use GetDocShell
7798 nsIDocShell* docShell = GetDocShell();
7799 if (!docShell)
7800 return;
7802 nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell);
7803 if (editorDocShell) {
7804 PRBool editable;
7805 editorDocShell->GetEditable(&editable);
7806 if (editable)
7807 return;
7810 nsCOMPtr<nsIPresShell> presShell;
7811 docShell->GetPresShell(getter_AddRefs(presShell));
7812 if (!presShell || !mDocument)
7813 return;
7815 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
7816 Element *rootElement = doc->GetRootElement();
7817 if (rootElement) {
7818 if ((mHasFocus || aFocusChanged) &&
7819 (mFocusedNode == rootElement || aNewContent == rootElement)) {
7820 nsIFrame* frame = rootElement->GetPrimaryFrame();
7821 if (frame) {
7822 frame = frame->GetParent();
7823 nsCanvasFrame* canvasFrame = do_QueryFrame(frame);
7824 if (canvasFrame) {
7825 canvasFrame->SetHasFocus(mHasFocus && rootElement == aNewContent);
7829 } else {
7830 // Look for the frame the hard way
7831 nsIFrame* frame = presShell->GetRootFrame();
7832 if (frame) {
7833 nsCanvasFrame* canvasFrame = FindCanvasFrame(frame);
7834 if (canvasFrame) {
7835 canvasFrame->SetHasFocus(PR_FALSE);
7841 //*****************************************************************************
7842 // nsGlobalWindow::nsIDOMViewCSS
7843 //*****************************************************************************
7845 NS_IMETHODIMP
7846 nsGlobalWindow::GetComputedStyle(nsIDOMElement* aElt,
7847 const nsAString& aPseudoElt,
7848 nsIDOMCSSStyleDeclaration** aReturn)
7850 FORWARD_TO_OUTER(GetComputedStyle, (aElt, aPseudoElt, aReturn),
7851 NS_ERROR_NOT_INITIALIZED);
7853 NS_ENSURE_ARG_POINTER(aReturn);
7854 *aReturn = nsnull;
7856 if (!aElt) {
7857 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
7860 if (!mDocShell) {
7861 return NS_OK;
7864 nsCOMPtr<nsIPresShell> presShell;
7865 mDocShell->GetPresShell(getter_AddRefs(presShell));
7867 if (!presShell) {
7868 return NS_OK;
7871 nsRefPtr<nsComputedDOMStyle> compStyle;
7872 nsresult rv = NS_NewComputedDOMStyle(aElt, aPseudoElt, presShell,
7873 getter_AddRefs(compStyle));
7874 NS_ENSURE_SUCCESS(rv, rv);
7876 *aReturn = compStyle.forget().get();
7878 return NS_OK;
7881 //*****************************************************************************
7882 // nsGlobalWindow::nsIDOMAbstractView
7883 //*****************************************************************************
7885 NS_IMETHODIMP
7886 nsGlobalWindow::GetDocument(nsIDOMDocumentView ** aDocumentView)
7888 NS_ENSURE_ARG_POINTER(aDocumentView);
7890 nsresult rv = NS_OK;
7892 if (mDocument) {
7893 rv = CallQueryInterface(mDocument, aDocumentView);
7895 else {
7896 *aDocumentView = nsnull;
7899 return rv;
7902 //*****************************************************************************
7903 // nsGlobalWindow::nsIDOMStorageWindow
7904 //*****************************************************************************
7906 NS_IMETHODIMP
7907 nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
7909 FORWARD_TO_INNER(GetSessionStorage, (aSessionStorage), NS_ERROR_UNEXPECTED);
7911 nsIPrincipal *principal = GetPrincipal();
7912 nsIDocShell* docShell = GetDocShell();
7914 if (!principal || !docShell) {
7915 *aSessionStorage = nsnull;
7916 return NS_OK;
7919 if (!nsContentUtils::GetBoolPref(kStorageEnabled)) {
7920 *aSessionStorage = nsnull;
7921 return NS_OK;
7924 if (mSessionStorage) {
7925 #ifdef PR_LOGGING
7926 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7927 PR_LogPrint("nsGlobalWindow %p has %p sessionStorage", this, mSessionStorage.get());
7929 #endif
7930 nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(mSessionStorage);
7931 if (piStorage) {
7932 PRBool canAccess = piStorage->CanAccess(principal);
7933 NS_ASSERTION(canAccess,
7934 "window %x owned sessionStorage "
7935 "that could not be accessed!");
7936 if (!canAccess) {
7937 mSessionStorage = nsnull;
7942 if (!mSessionStorage) {
7943 *aSessionStorage = nsnull;
7945 nsString documentURI;
7946 nsCOMPtr<nsIDOM3Document> document3 = do_QueryInterface(mDoc);
7947 if (document3)
7948 document3->GetDocumentURI(documentURI);
7950 nsresult rv = docShell->GetSessionStorageForPrincipal(principal,
7951 documentURI,
7952 PR_TRUE,
7953 getter_AddRefs(mSessionStorage));
7954 NS_ENSURE_SUCCESS(rv, rv);
7956 #ifdef PR_LOGGING
7957 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7958 PR_LogPrint("nsGlobalWindow %p tried to get a new sessionStorage %p", this, mSessionStorage.get());
7960 #endif
7962 if (!mSessionStorage) {
7963 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
7967 #ifdef PR_LOGGING
7968 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7969 PR_LogPrint("nsGlobalWindow %p returns %p sessionStorage", this, mSessionStorage.get());
7971 #endif
7973 NS_ADDREF(*aSessionStorage = mSessionStorage);
7974 return NS_OK;
7977 NS_IMETHODIMP
7978 nsGlobalWindow::GetGlobalStorage(nsIDOMStorageList ** aGlobalStorage)
7980 NS_ENSURE_ARG_POINTER(aGlobalStorage);
7982 #ifdef MOZ_STORAGE
7983 if (!nsContentUtils::GetBoolPref(kStorageEnabled)) {
7984 *aGlobalStorage = nsnull;
7985 return NS_OK;
7988 if (!sGlobalStorageList) {
7989 nsresult rv = NS_NewDOMStorageList(&sGlobalStorageList);
7990 NS_ENSURE_SUCCESS(rv, rv);
7993 *aGlobalStorage = sGlobalStorageList;
7994 NS_IF_ADDREF(*aGlobalStorage);
7996 return NS_OK;
7997 #else
7998 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
7999 #endif
8002 NS_IMETHODIMP
8003 nsGlobalWindow::GetLocalStorage(nsIDOMStorage ** aLocalStorage)
8005 FORWARD_TO_INNER(GetLocalStorage, (aLocalStorage), NS_ERROR_UNEXPECTED);
8007 NS_ENSURE_ARG(aLocalStorage);
8009 if (!nsContentUtils::GetBoolPref(kStorageEnabled)) {
8010 *aLocalStorage = nsnull;
8011 return NS_OK;
8014 if (!mLocalStorage) {
8015 *aLocalStorage = nsnull;
8017 nsresult rv;
8019 PRPackedBool unused;
8020 if (!nsDOMStorage::CanUseStorage(&unused))
8021 return NS_ERROR_DOM_SECURITY_ERR;
8023 nsIPrincipal *principal = GetPrincipal();
8024 if (!principal)
8025 return NS_OK;
8027 nsCOMPtr<nsIDOMStorageManager> storageManager =
8028 do_GetService("@mozilla.org/dom/storagemanager;1", &rv);
8029 NS_ENSURE_SUCCESS(rv, rv);
8031 nsString documentURI;
8032 nsCOMPtr<nsIDOM3Document> document3 = do_QueryInterface(mDoc);
8033 if (document3)
8034 document3->GetDocumentURI(documentURI);
8036 rv = storageManager->GetLocalStorageForPrincipal(principal,
8037 documentURI,
8038 getter_AddRefs(mLocalStorage));
8039 NS_ENSURE_SUCCESS(rv, rv);
8042 NS_ADDREF(*aLocalStorage = mLocalStorage);
8043 return NS_OK;
8046 //*****************************************************************************
8047 // nsGlobalWindow::nsIDOMStorageIndexedDB
8048 //*****************************************************************************
8050 NS_IMETHODIMP
8051 nsGlobalWindow::GetMozIndexedDB(nsIIDBFactory** _retval)
8053 if (!mIndexedDB) {
8054 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
8055 do_GetService(THIRDPARTYUTIL_CONTRACTID);
8056 NS_ENSURE_TRUE(thirdPartyUtil, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
8058 PRBool isThirdParty;
8059 nsresult rv = thirdPartyUtil->IsThirdPartyWindow(this, nsnull,
8060 &isThirdParty);
8061 NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
8063 if (isThirdParty) {
8064 NS_WARNING("IndexedDB is not permitted in a third-party window.");
8065 *_retval = nsnull;
8066 return NS_OK;
8069 mIndexedDB = indexedDB::IDBFactory::Create(this);
8070 NS_ENSURE_TRUE(mIndexedDB, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
8073 nsCOMPtr<nsIIDBFactory> request(mIndexedDB);
8074 request.forget(_retval);
8075 return NS_OK;
8078 //*****************************************************************************
8079 // nsGlobalWindow::nsIInterfaceRequestor
8080 //*****************************************************************************
8082 NS_IMETHODIMP
8083 nsGlobalWindow::GetInterface(const nsIID & aIID, void **aSink)
8085 NS_ENSURE_ARG_POINTER(aSink);
8086 *aSink = nsnull;
8088 if (aIID.Equals(NS_GET_IID(nsIDocCharset))) {
8089 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
8091 if (mDocShell) {
8092 nsCOMPtr<nsIDocCharset> docCharset(do_QueryInterface(mDocShell));
8093 if (docCharset) {
8094 *aSink = docCharset;
8095 NS_ADDREF(((nsISupports *) *aSink));
8099 else if (aIID.Equals(NS_GET_IID(nsIWebNavigation))) {
8100 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
8102 if (mDocShell) {
8103 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
8104 if (webNav) {
8105 *aSink = webNav;
8106 NS_ADDREF(((nsISupports *) *aSink));
8110 #ifdef NS_PRINTING
8111 else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
8112 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
8114 if (mDocShell) {
8115 nsCOMPtr<nsIContentViewer> viewer;
8116 mDocShell->GetContentViewer(getter_AddRefs(viewer));
8117 if (viewer) {
8118 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
8119 if (webBrowserPrint) {
8120 *aSink = webBrowserPrint;
8121 NS_ADDREF(((nsISupports *) *aSink));
8126 #endif
8127 else if (aIID.Equals(NS_GET_IID(nsIScriptEventManager))) {
8128 if (mDoc) {
8129 nsIScriptEventManager* mgr = mDoc->GetScriptEventManager();
8130 if (mgr) {
8131 *aSink = mgr;
8132 NS_ADDREF(((nsISupports *) *aSink));
8136 else if (aIID.Equals(NS_GET_IID(nsIDOMWindowUtils)) ||
8137 aIID.Equals(NS_GET_IID(nsIDOMWindowUtils_MOZILLA_2_0_BRANCH))) {
8138 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
8140 nsCOMPtr<nsISupports> utils(do_QueryReferent(mWindowUtils));
8141 if (utils) {
8142 *aSink = utils;
8143 NS_ADDREF(((nsISupports *) *aSink));
8144 } else {
8145 nsDOMWindowUtils *utilObj = new nsDOMWindowUtils(this);
8146 nsCOMPtr<nsISupports> utilsIfc =
8147 NS_ISUPPORTS_CAST(nsIDOMWindowUtils *, utilObj);
8148 if (utilsIfc) {
8149 mWindowUtils = do_GetWeakReference(utilsIfc);
8150 *aSink = utilsIfc;
8151 NS_ADDREF(((nsISupports *) *aSink));
8155 else {
8156 return QueryInterface(aIID, aSink);
8159 return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
8162 void
8163 nsGlobalWindow::FireOfflineStatusEvent()
8165 if (!mDoc)
8166 return;
8167 nsAutoString name;
8168 if (NS_IsOffline()) {
8169 name.AssignLiteral("offline");
8170 } else {
8171 name.AssignLiteral("online");
8173 // The event is fired at the body element, or if there is no body element,
8174 // at the document.
8175 nsCOMPtr<nsISupports> eventTarget = mDoc.get();
8176 nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDoc);
8177 if (htmlDoc) {
8178 nsCOMPtr<nsIDOMHTMLElement> body;
8179 htmlDoc->GetBody(getter_AddRefs(body));
8180 if (body) {
8181 eventTarget = body;
8184 else {
8185 nsCOMPtr<nsIDOMElement> documentElement;
8186 mDocument->GetDocumentElement(getter_AddRefs(documentElement));
8187 if(documentElement) {
8188 eventTarget = documentElement;
8191 nsContentUtils::DispatchTrustedEvent(mDoc, eventTarget, name, PR_TRUE, PR_FALSE);
8194 nsresult
8195 nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
8196 const PRUnichar* aData)
8198 if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
8199 if (IsFrozen()) {
8200 // if an even number of notifications arrive while we're frozen,
8201 // we don't need to fire.
8202 mFireOfflineStatusChangeEventOnThaw = !mFireOfflineStatusChangeEventOnThaw;
8203 } else {
8204 FireOfflineStatusEvent();
8206 return NS_OK;
8209 if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage-changed")) {
8210 nsIPrincipal *principal;
8211 nsresult rv;
8213 principal = GetPrincipal();
8214 if (principal) {
8215 // A global storage object changed, check to see if it's one
8216 // this window can access.
8218 nsCOMPtr<nsIURI> codebase;
8219 principal->GetURI(getter_AddRefs(codebase));
8221 if (!codebase) {
8222 return NS_OK;
8225 nsCAutoString currentDomain;
8226 rv = codebase->GetAsciiHost(currentDomain);
8227 if (NS_FAILED(rv)) {
8228 return NS_OK;
8231 if (!nsDOMStorageList::CanAccessDomain(NS_ConvertUTF16toUTF8(aData),
8232 currentDomain)) {
8233 // This window can't reach the global storage object for the
8234 // domain for which the change happened, so don't fire any
8235 // events in this window.
8237 return NS_OK;
8241 nsAutoString domain(aData);
8243 if (IsFrozen()) {
8244 // This window is frozen, rather than firing the events here,
8245 // store the domain in which the change happened and fire the
8246 // events if we're ever thawed.
8248 if (!mPendingStorageEventsObsolete) {
8249 mPendingStorageEventsObsolete = new nsDataHashtable<nsStringHashKey, PRBool>;
8250 NS_ENSURE_TRUE(mPendingStorageEventsObsolete, NS_ERROR_OUT_OF_MEMORY);
8252 rv = mPendingStorageEventsObsolete->Init();
8253 NS_ENSURE_SUCCESS(rv, rv);
8256 mPendingStorageEventsObsolete->Put(domain, PR_TRUE);
8258 return NS_OK;
8261 nsRefPtr<nsDOMStorageEventObsolete> event = new nsDOMStorageEventObsolete();
8262 NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
8264 rv = event->InitStorageEvent(NS_LITERAL_STRING("storage"), PR_FALSE, PR_FALSE, domain);
8265 NS_ENSURE_SUCCESS(rv, rv);
8267 nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
8269 nsCOMPtr<nsIDOMEventTarget> target;
8271 if (htmlDoc) {
8272 nsCOMPtr<nsIDOMHTMLElement> body;
8273 htmlDoc->GetBody(getter_AddRefs(body));
8275 target = do_QueryInterface(body);
8278 if (!target) {
8279 target = this;
8282 PRBool defaultActionEnabled;
8283 target->DispatchEvent((nsIDOMStorageEventObsolete *)event, &defaultActionEnabled);
8285 return NS_OK;
8288 if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage2-changed")) {
8289 nsIPrincipal *principal;
8290 nsresult rv;
8292 nsCOMPtr<nsIDOMStorageEvent> event = do_QueryInterface(aSubject, &rv);
8293 NS_ENSURE_SUCCESS(rv, rv);
8295 nsCOMPtr<nsIDOMStorage> changingStorage;
8296 rv = event->GetStorageArea(getter_AddRefs(changingStorage));
8297 NS_ENSURE_SUCCESS(rv, rv);
8299 nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(changingStorage);
8300 nsPIDOMStorage::nsDOMStorageType storageType = pistorage->StorageType();
8302 principal = GetPrincipal();
8303 switch (storageType)
8305 case nsPIDOMStorage::SessionStorage:
8307 if (SameCOMIdentity(mSessionStorage, changingStorage)) {
8308 // Do not fire any events for the same storage object, it's not shared
8309 // among windows, see nsGlobalWindow::GetSessionStoarge()
8310 return NS_OK;
8313 nsCOMPtr<nsIDOMStorage> storage = mSessionStorage;
8314 if (!storage) {
8315 nsIDocShell* docShell = GetDocShell();
8316 if (principal && docShell) {
8317 // No need to pass documentURI here, it's only needed when we want
8318 // to create a new storage, the third paramater would be PR_TRUE
8319 docShell->GetSessionStorageForPrincipal(principal,
8320 EmptyString(),
8321 PR_FALSE,
8322 getter_AddRefs(storage));
8326 if (!pistorage->IsForkOf(storage)) {
8327 // This storage event is coming from a different doc shell,
8328 // i.e. it is a clone, ignore this event.
8329 return NS_OK;
8332 #ifdef PR_LOGGING
8333 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
8334 PR_LogPrint("nsGlobalWindow %p with sessionStorage %p passing event from %p", this, mSessionStorage.get(), pistorage.get());
8336 #endif
8338 break;
8340 case nsPIDOMStorage::LocalStorage:
8342 if (SameCOMIdentity(mLocalStorage, changingStorage)) {
8343 // Do not fire any events for the same storage object, it's not shared
8344 // among windows, see nsGlobalWindow::GetLocalStoarge()
8345 return NS_OK;
8348 // Allow event fire only for the same principal storages
8349 // XXX We have to use EqualsIgnoreDomain after bug 495337 lands
8350 nsIPrincipal *storagePrincipal = pistorage->Principal();
8351 PRBool equals;
8353 rv = storagePrincipal->Equals(principal, &equals);
8354 NS_ENSURE_SUCCESS(rv, rv);
8356 if (!equals)
8357 return NS_OK;
8359 break;
8361 default:
8362 return NS_OK;
8365 if (IsFrozen()) {
8366 // This window is frozen, rather than firing the events here,
8367 // store the domain in which the change happened and fire the
8368 // events if we're ever thawed.
8370 mPendingStorageEvents.AppendObject(event);
8371 return NS_OK;
8374 PRBool defaultActionEnabled;
8375 DispatchEvent((nsIDOMStorageEvent *)event, &defaultActionEnabled);
8377 return NS_OK;
8380 if (!nsCRT::strcmp(aTopic, "offline-cache-update-added")) {
8381 if (mApplicationCache)
8382 return NS_OK;
8384 // Instantiate the application object now. It observes update belonging to
8385 // this window's document and correctly updates the applicationCache object
8386 // state.
8387 nsCOMPtr<nsIDOMOfflineResourceList> applicationCache;
8388 GetApplicationCache(getter_AddRefs(applicationCache));
8389 nsCOMPtr<nsIObserver> observer = do_QueryInterface(applicationCache);
8390 if (observer)
8391 observer->Observe(aSubject, aTopic, aData);
8393 return NS_OK;
8396 NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");
8397 return NS_ERROR_FAILURE;
8400 static PLDHashOperator
8401 FirePendingStorageEvents(const nsAString& aKey, PRBool aData, void *userArg)
8403 nsGlobalWindow *win = static_cast<nsGlobalWindow *>(userArg);
8405 nsCOMPtr<nsIDOMStorage> storage;
8406 win->GetSessionStorage(getter_AddRefs(storage));
8408 if (storage) {
8409 win->Observe(storage, "dom-storage-changed",
8410 aKey.IsEmpty() ? nsnull : PromiseFlatString(aKey).get());
8413 return PL_DHASH_NEXT;
8416 nsresult
8417 nsGlobalWindow::FireDelayedDOMEvents()
8419 FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED);
8421 for (PRInt32 i = 0; i < mPendingStorageEvents.Count(); ++i) {
8422 Observe(mPendingStorageEvents[i], "dom-storage2-changed", nsnull);
8425 if (mPendingStorageEventsObsolete) {
8426 // Fire pending storage events.
8427 mPendingStorageEventsObsolete->EnumerateRead(FirePendingStorageEvents, this);
8429 delete mPendingStorageEventsObsolete;
8430 mPendingStorageEventsObsolete = nsnull;
8433 if (mApplicationCache) {
8434 static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents();
8437 if (mFireOfflineStatusChangeEventOnThaw) {
8438 mFireOfflineStatusChangeEventOnThaw = PR_FALSE;
8439 FireOfflineStatusEvent();
8442 nsCOMPtr<nsIDocShellTreeNode> node =
8443 do_QueryInterface(GetDocShell());
8444 if (node) {
8445 PRInt32 childCount = 0;
8446 node->GetChildCount(&childCount);
8448 for (PRInt32 i = 0; i < childCount; ++i) {
8449 nsCOMPtr<nsIDocShellTreeItem> childShell;
8450 node->GetChildAt(i, getter_AddRefs(childShell));
8451 NS_ASSERTION(childShell, "null child shell");
8453 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
8454 if (pWin) {
8455 nsGlobalWindow *win =
8456 static_cast<nsGlobalWindow*>
8457 (static_cast<nsPIDOMWindow*>(pWin));
8458 win->FireDelayedDOMEvents();
8463 return NS_OK;
8466 //*****************************************************************************
8467 // nsGlobalWindow: Window Control Functions
8468 //*****************************************************************************
8470 nsIDOMWindowInternal *
8471 nsGlobalWindow::GetParentInternal()
8473 FORWARD_TO_OUTER(GetParentInternal, (), nsnull);
8475 nsIDOMWindowInternal *parentInternal = nsnull;
8477 nsCOMPtr<nsIDOMWindow> parent;
8478 GetParent(getter_AddRefs(parent));
8480 if (parent && parent != static_cast<nsIDOMWindow *>(this)) {
8481 nsCOMPtr<nsIDOMWindowInternal> tmp(do_QueryInterface(parent));
8482 NS_ASSERTION(parent, "Huh, parent not an nsIDOMWindowInternal?");
8484 parentInternal = tmp;
8487 return parentInternal;
8490 // static
8491 void
8492 nsGlobalWindow::CloseBlockScriptTerminationFunc(nsISupports *aRef)
8494 nsGlobalWindow* pwin = static_cast<nsGlobalWindow*>
8495 (static_cast<nsPIDOMWindow*>(aRef));
8496 pwin->mBlockScriptedClosingFlag = PR_FALSE;
8499 nsresult
8500 nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
8501 const nsAString& aOptions, PRBool aDialog,
8502 PRBool aContentModal, PRBool aCalledNoScript,
8503 PRBool aDoJSFixups, nsIArray *argv,
8504 nsISupports *aExtraArgument,
8505 nsIPrincipal *aCalleePrincipal,
8506 JSContext *aJSCallerContext,
8507 nsIDOMWindow **aReturn)
8509 FORWARD_TO_OUTER(OpenInternal, (aUrl, aName, aOptions, aDialog,
8510 aContentModal, aCalledNoScript, aDoJSFixups,
8511 argv, aExtraArgument, aCalleePrincipal,
8512 aJSCallerContext, aReturn),
8513 NS_ERROR_NOT_INITIALIZED);
8515 #ifdef NS_DEBUG
8516 PRUint32 argc = 0;
8517 if (argv)
8518 argv->GetLength(&argc);
8519 #endif
8520 NS_PRECONDITION(!aExtraArgument || (!argv && argc == 0),
8521 "Can't pass in arguments both ways");
8522 NS_PRECONDITION(!aCalledNoScript || (!argv && argc == 0),
8523 "Can't pass JS args when called via the noscript methods");
8524 NS_PRECONDITION(!aJSCallerContext || !aCalledNoScript,
8525 "Shouldn't have caller context when called noscript");
8527 *aReturn = nsnull;
8529 nsCOMPtr<nsIWebBrowserChrome> chrome;
8530 GetWebBrowserChrome(getter_AddRefs(chrome));
8531 if (!chrome) {
8532 // No chrome means we don't want to go through with this open call
8533 // -- see nsIWindowWatcher.idl
8534 return NS_ERROR_NOT_AVAILABLE;
8537 NS_ASSERTION(mDocShell, "Must have docshell here");
8539 const PRBool checkForPopup =
8540 !aDialog && !WindowExists(aName, !aCalledNoScript);
8542 // Note: it's very important that this be an nsXPIDLCString, since we want
8543 // .get() on it to return nsnull until we write stuff to it. The window
8544 // watcher expects a null URL string if there is no URL to load.
8545 nsXPIDLCString url;
8546 nsresult rv = NS_OK;
8548 // It's important to do this security check before determining whether this
8549 // window opening should be blocked, to ensure that we don't FireAbuseEvents
8550 // for a window opening that wouldn't have succeeded in the first place.
8551 if (!aUrl.IsEmpty()) {
8552 AppendUTF16toUTF8(aUrl, url);
8554 /* Check whether the URI is allowed, but not for dialogs --
8555 see bug 56851. The security of this function depends on
8556 window.openDialog being inaccessible from web scripts */
8557 if (url.get() && !aDialog)
8558 rv = SecurityCheckURL(url.get());
8561 if (NS_FAILED(rv))
8562 return rv;
8564 PopupControlState abuseLevel = gPopupControlState;
8565 if (checkForPopup) {
8566 abuseLevel = RevisePopupAbuseLevel(abuseLevel);
8567 if (abuseLevel >= openAbused) {
8568 if (aJSCallerContext) {
8569 // If script in some other window is doing a window.open on us and
8570 // it's being blocked, then it's OK to close us afterwards, probably.
8571 // But if we're doing a window.open on ourselves and block the popup,
8572 // prevent this window from closing until after this script terminates
8573 // so that whatever popup blocker UI the app has will be visible.
8574 if (mContext == GetScriptContextFromJSContext(aJSCallerContext)) {
8575 mBlockScriptedClosingFlag = PR_TRUE;
8576 mContext->SetTerminationFunction(CloseBlockScriptTerminationFunc,
8577 static_cast<nsPIDOMWindow*>
8578 (this));
8582 FireAbuseEvents(PR_TRUE, PR_FALSE, aUrl, aName, aOptions);
8583 return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
8587 nsCOMPtr<nsIDOMWindow> domReturn;
8589 nsCOMPtr<nsIWindowWatcher> wwatch =
8590 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
8591 NS_ENSURE_TRUE(wwatch, rv);
8593 NS_ConvertUTF16toUTF8 options(aOptions);
8594 NS_ConvertUTF16toUTF8 name(aName);
8596 const char *options_ptr = aOptions.IsEmpty() ? nsnull : options.get();
8597 const char *name_ptr = aName.IsEmpty() ? nsnull : name.get();
8600 // Reset popup state while opening a window to prevent the
8601 // current state from being active the whole time a modal
8602 // dialog is open.
8603 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
8605 if (!aCalledNoScript) {
8606 nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
8607 NS_ASSERTION(pwwatch,
8608 "Unable to open windows from JS because window watcher "
8609 "is broken");
8610 NS_ENSURE_TRUE(pwwatch, NS_ERROR_UNEXPECTED);
8612 rv = pwwatch->OpenWindowJS(this, url.get(), name_ptr, options_ptr,
8613 aDialog, argv,
8614 getter_AddRefs(domReturn));
8615 } else {
8616 // Push a null JSContext here so that the window watcher won't screw us
8617 // up. We do NOT want this case looking at the JS context on the stack
8618 // when searching. Compare comments on
8619 // nsIDOMWindowInternal::OpenWindow and nsIWindowWatcher::OpenWindow.
8620 nsCOMPtr<nsIJSContextStack> stack;
8622 if (!aContentModal) {
8623 stack = do_GetService(sJSStackContractID);
8626 if (stack) {
8627 rv = stack->Push(nsnull);
8628 NS_ENSURE_SUCCESS(rv, rv);
8631 rv = wwatch->OpenWindow(this, url.get(), name_ptr, options_ptr,
8632 aExtraArgument, getter_AddRefs(domReturn));
8634 if (stack) {
8635 JSContext* cx;
8636 stack->Pop(&cx);
8637 NS_ASSERTION(!cx, "Unexpected JSContext popped!");
8642 NS_ENSURE_SUCCESS(rv, rv);
8644 // success!
8646 domReturn.swap(*aReturn);
8648 if (aDoJSFixups) {
8649 nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
8650 if (!chrome_win) {
8651 // A new non-chrome window was created from a call to
8652 // window.open() from JavaScript, make sure there's a document in
8653 // the new window. We do this by simply asking the new window for
8654 // its document, this will synchronously create an empty document
8655 // if there is no document in the window.
8656 // XXXbz should this just use EnsureInnerWindow()?
8657 #ifdef DEBUG_jst
8659 nsCOMPtr<nsPIDOMWindow> pidomwin(do_QueryInterface(*aReturn));
8661 nsIDOMDocument *temp = pidomwin->GetExtantDocument();
8663 NS_ASSERTION(temp, "No document in new window!!!");
8665 #endif
8667 nsCOMPtr<nsIDOMDocument> doc;
8668 (*aReturn)->GetDocument(getter_AddRefs(doc));
8672 if (checkForPopup) {
8673 if (abuseLevel >= openControlled) {
8674 nsGlobalWindow *opened = static_cast<nsGlobalWindow *>(*aReturn);
8675 if (!opened->IsPopupSpamWindow()) {
8676 opened->SetPopupSpamWindow(PR_TRUE);
8677 ++gOpenPopupSpamCount;
8680 if (abuseLevel >= openAbused)
8681 FireAbuseEvents(PR_FALSE, PR_TRUE, aUrl, aName, aOptions);
8684 return rv;
8687 // static
8688 void
8689 nsGlobalWindow::CloseWindow(nsISupports *aWindow)
8691 nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aWindow));
8693 nsGlobalWindow* globalWin =
8694 static_cast<nsGlobalWindow *>
8695 (static_cast<nsPIDOMWindow*>(win));
8697 // Need to post an event for closing, otherwise window and
8698 // presshell etc. may get destroyed while creating frames, bug 338897.
8699 nsCloseEvent::PostCloseEvent(globalWin);
8700 // else if OOM, better not to close. That might cause a crash.
8703 // static
8704 void
8705 nsGlobalWindow::ClearWindowScope(nsISupports *aWindow)
8707 nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aWindow));
8708 nsIScriptContext *scx = sgo->GetContext();
8709 if (scx) {
8710 scx->ClearScope(sgo->GetGlobalJSObject(), PR_TRUE);
8714 //*****************************************************************************
8715 // nsGlobalWindow: Timeout Functions
8716 //*****************************************************************************
8718 PRUint32 sNestingLevel;
8720 nsresult
8721 nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
8722 PRInt32 interval,
8723 PRBool aIsInterval, PRInt32 *aReturn)
8725 FORWARD_TO_INNER(SetTimeoutOrInterval, (aHandler, interval, aIsInterval, aReturn),
8726 NS_ERROR_NOT_INITIALIZED);
8728 // If we don't have a document (we could have been unloaded since
8729 // the call to setTimeout was made), do nothing.
8730 if (!mDocument) {
8731 return NS_OK;
8734 PRUint32 nestingLevel = sNestingLevel + 1;
8735 if (interval < DOMMinTimeoutValue()) {
8736 if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL) {
8737 // Don't allow timeouts less than DOMMinTimeoutValue() from
8738 // now...
8740 interval = DOMMinTimeoutValue();;
8742 else if (interval < 0) {
8743 // Clamp negative intervals to 0.
8745 interval = 0;
8749 NS_ASSERTION(interval >= 0, "DOMMinTimeoutValue() lies");
8750 PRUint32 realInterval = interval;
8752 // Make sure we don't proceed with a interval larger than our timer
8753 // code can handle.
8754 if (realInterval > PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE)) {
8755 realInterval = PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE);
8758 nsTimeout *timeout = new nsTimeout();
8759 if (!timeout)
8760 return NS_ERROR_OUT_OF_MEMORY;
8762 // Increment the timeout's reference count to represent this function's hold
8763 // on the timeout.
8764 timeout->AddRef();
8766 if (aIsInterval) {
8767 timeout->mInterval = realInterval;
8769 timeout->mScriptHandler = aHandler;
8771 // Get principal of currently executing code, save for execution of timeout.
8772 // If our principals subsume the subject principal then use the subject
8773 // principal. Otherwise, use our principal to avoid running script in
8774 // elevated principals.
8776 nsCOMPtr<nsIPrincipal> subjectPrincipal;
8777 nsresult rv;
8778 rv = nsContentUtils::GetSecurityManager()->
8779 GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
8780 if (NS_FAILED(rv)) {
8781 timeout->Release();
8783 return NS_ERROR_FAILURE;
8786 PRBool subsumes = PR_FALSE;
8787 nsCOMPtr<nsIPrincipal> ourPrincipal = GetPrincipal();
8789 // Note the direction of this test: We don't allow setTimeouts running with
8790 // chrome privileges on content windows, but we do allow setTimeouts running
8791 // with content privileges on chrome windows (where they can't do very much,
8792 // of course).
8793 rv = ourPrincipal->Subsumes(subjectPrincipal, &subsumes);
8794 if (NS_FAILED(rv)) {
8795 timeout->Release();
8797 return NS_ERROR_FAILURE;
8800 if (subsumes) {
8801 timeout->mPrincipal = subjectPrincipal;
8802 } else {
8803 timeout->mPrincipal = ourPrincipal;
8806 TimeDuration delta = TimeDuration::FromMilliseconds(realInterval);
8808 if (!IsFrozen() && !mTimeoutsSuspendDepth) {
8809 // If we're not currently frozen, then we set timeout->mWhen to be the
8810 // actual firing time of the timer (i.e., now + delta). We also actually
8811 // create a timer and fire it off.
8813 timeout->mWhen = TimeStamp::Now() + delta;
8815 timeout->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
8816 if (NS_FAILED(rv)) {
8817 timeout->Release();
8819 return rv;
8822 rv = timeout->mTimer->InitWithFuncCallback(TimerCallback, timeout,
8823 realInterval,
8824 nsITimer::TYPE_ONE_SHOT);
8825 if (NS_FAILED(rv)) {
8826 timeout->Release();
8828 return rv;
8831 // The timeout is now also held in the timer's closure.
8832 timeout->AddRef();
8833 } else {
8834 // If we are frozen, however, then we instead simply set
8835 // timeout->mTimeRemaining to be the "time remaining" in the timeout (i.e.,
8836 // the interval itself). We don't create a timer for it, since that will
8837 // happen when we are thawed and the timeout will then get a timer and run
8838 // to completion.
8840 timeout->mTimeRemaining = delta;
8843 timeout->mWindow = this;
8845 if (!aIsInterval) {
8846 timeout->mNestingLevel = nestingLevel;
8849 // No popups from timeouts by default
8850 timeout->mPopupState = openAbused;
8852 if (gRunningTimeoutDepth == 0 && gPopupControlState < openAbused) {
8853 // This timeout is *not* set from another timeout and it's set
8854 // while popups are enabled. Propagate the state to the timeout if
8855 // its delay (interval) is equal to or less than what
8856 // "dom.disable_open_click_delay" is set to (in ms).
8858 PRInt32 delay =
8859 nsContentUtils::GetIntPref("dom.disable_open_click_delay");
8861 if (interval <= delay) {
8862 timeout->mPopupState = gPopupControlState;
8866 InsertTimeoutIntoList(timeout);
8868 timeout->mPublicId = ++mTimeoutPublicIdCounter;
8869 *aReturn = timeout->mPublicId;
8871 // Our hold on the timeout is expiring. Note that this should not actually
8872 // free the timeout (since the list should have taken ownership as well).
8873 timeout->Release();
8875 return NS_OK;
8879 nsresult
8880 nsGlobalWindow::SetTimeoutOrInterval(PRBool aIsInterval, PRInt32 *aReturn)
8882 // This needs to forward to the inner window, but since the current
8883 // inner may not be the inner in the calling scope, we need to treat
8884 // this specially here as we don't want timeouts registered in a
8885 // dying inner window to get registered and run on the current inner
8886 // window. To get this right, we need to forward this call to the
8887 // inner window that's calling window.setTimeout().
8889 if (IsOuterWindow()) {
8890 nsGlobalWindow* callerInner = CallerInnerWindow();
8891 NS_ENSURE_TRUE(callerInner, NS_ERROR_NOT_AVAILABLE);
8893 // If the caller and the callee share the same outer window,
8894 // forward to the callee inner. Else, we forward to the current
8895 // inner (e.g. someone is calling setTimeout() on a reference to
8896 // some other window).
8898 if (callerInner->GetOuterWindow() == this &&
8899 callerInner->IsInnerWindow()) {
8900 return callerInner->SetTimeoutOrInterval(aIsInterval, aReturn);
8903 FORWARD_TO_INNER(SetTimeoutOrInterval, (aIsInterval, aReturn),
8904 NS_ERROR_NOT_INITIALIZED);
8907 PRInt32 interval = 0;
8908 PRBool isInterval = aIsInterval;
8909 nsCOMPtr<nsIScriptTimeoutHandler> handler;
8910 nsresult rv = NS_CreateJSTimeoutHandler(this,
8911 &isInterval,
8912 &interval,
8913 getter_AddRefs(handler));
8914 if (NS_FAILED(rv))
8915 return (rv == NS_ERROR_DOM_TYPE_ERR) ? NS_OK : rv;
8917 return SetTimeoutOrInterval(handler, interval, isInterval, aReturn);
8920 // static
8921 void
8922 nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
8924 // If a modal dialog is open for this window, return early. Pending
8925 // timeouts will run when the modal dialog is dismissed.
8926 if (IsInModalState() || mTimeoutsSuspendDepth) {
8927 return;
8930 NS_TIME_FUNCTION;
8932 NS_ASSERTION(IsInnerWindow(), "Timeout running on outer window!");
8933 NS_ASSERTION(!IsFrozen(), "Timeout running on a window in the bfcache!");
8935 nsTimeout *nextTimeout, *timeout;
8936 nsTimeout *last_expired_timeout, *last_insertion_point;
8937 nsTimeout dummy_timeout;
8938 PRUint32 firingDepth = mTimeoutFiringDepth + 1;
8940 // Make sure that the window and the script context don't go away as
8941 // a result of running timeouts
8942 nsCOMPtr<nsIScriptGlobalObject> windowKungFuDeathGrip(this);
8944 // A native timer has gone off. See which of our timeouts need
8945 // servicing
8946 TimeStamp now = TimeStamp::Now();
8947 TimeStamp deadline;
8949 if (aTimeout && aTimeout->mWhen > now) {
8950 // The OS timer fired early (yikes!), and possibly out of order
8951 // too. Set |deadline| to be the time when the OS timer *should*
8952 // have fired so that any timers that *should* have fired before
8953 // aTimeout *will* be fired now. This happens most of the time on
8954 // Win2k.
8956 deadline = aTimeout->mWhen;
8957 } else {
8958 deadline = now;
8961 // The timeout list is kept in deadline order. Discover the latest
8962 // timeout whose deadline has expired. On some platforms, native
8963 // timeout events fire "early", so we need to test the timer as well
8964 // as the deadline.
8965 last_expired_timeout = nsnull;
8966 for (timeout = FirstTimeout(); IsTimeout(timeout); timeout = timeout->Next()) {
8967 if (((timeout == aTimeout) || (timeout->mWhen <= deadline)) &&
8968 (timeout->mFiringDepth == 0)) {
8969 // Mark any timeouts that are on the list to be fired with the
8970 // firing depth so that we can reentrantly run timeouts
8971 timeout->mFiringDepth = firingDepth;
8972 last_expired_timeout = timeout;
8976 // Maybe the timeout that the event was fired for has been deleted
8977 // and there are no others timeouts with deadlines that make them
8978 // eligible for execution yet. Go away.
8979 if (!last_expired_timeout) {
8980 return;
8983 // Insert a dummy timeout into the list of timeouts between the
8984 // portion of the list that we are about to process now and those
8985 // timeouts that will be processed in a future call to
8986 // win_run_timeout(). This dummy timeout serves as the head of the
8987 // list for any timeouts inserted as a result of running a timeout.
8988 dummy_timeout.mFiringDepth = firingDepth;
8989 dummy_timeout.mWhen = now;
8990 PR_INSERT_AFTER(&dummy_timeout, last_expired_timeout);
8992 // Don't let ClearWindowTimeouts throw away our stack-allocated
8993 // dummy timeout.
8994 dummy_timeout.AddRef();
8995 dummy_timeout.AddRef();
8997 last_insertion_point = mTimeoutInsertionPoint;
8998 mTimeoutInsertionPoint = &dummy_timeout;
9000 for (timeout = FirstTimeout();
9001 timeout != &dummy_timeout && !IsFrozen();
9002 timeout = nextTimeout) {
9003 nextTimeout = timeout->Next();
9005 if (timeout->mFiringDepth != firingDepth) {
9006 // We skip the timeout since it's on the list to run at another
9007 // depth.
9009 continue;
9012 if (mTimeoutsSuspendDepth) {
9013 // Some timer did suspend us. Make sure the
9014 // rest of the timers get executed later.
9015 timeout->mFiringDepth = 0;
9016 continue;
9019 // The timeout is on the list to run at this depth, go ahead and
9020 // process it.
9022 // Get the script context (a strong ref to prevent it going away)
9023 // for this timeout and ensure the script language is enabled.
9024 nsCOMPtr<nsIScriptContext> scx = GetScriptContextInternal(
9025 timeout->mScriptHandler->GetScriptTypeID());
9027 if (!scx) {
9028 // No context means this window was closed or never properly
9029 // initialized for this language.
9030 continue;
9033 // The "scripts disabled" concept is still a little vague wrt
9034 // multiple languages. Prepare for the day when languages can be
9035 // disabled independently of the other languages...
9036 if (!scx->GetScriptsEnabled()) {
9037 // Scripts were enabled once in this window (unless aTimeout ==
9038 // nsnull) but now scripts are disabled (we might be in
9039 // print-preview, for instance), this means we shouldn't run any
9040 // timeouts at this point.
9042 // If scripts are enabled for this language in this window again
9043 // we'll fire the timeouts that are due at that point.
9044 continue;
9047 // This timeout is good to run
9048 nsTimeout *last_running_timeout = mRunningTimeout;
9049 mRunningTimeout = timeout;
9050 timeout->mRunning = PR_TRUE;
9052 // Push this timeout's popup control state, which should only be
9053 // eabled the first time a timeout fires that was created while
9054 // popups were enabled and with a delay less than
9055 // "dom.disable_open_click_delay".
9056 nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
9058 // Clear the timeout's popup state, if any, to prevent interval
9059 // timeouts from repeatedly opening poups.
9060 timeout->mPopupState = openAbused;
9062 // Hold on to the timeout in case mExpr or mFunObj releases its
9063 // doc.
9064 timeout->AddRef();
9066 ++gRunningTimeoutDepth;
9067 ++mTimeoutFiringDepth;
9069 PRBool trackNestingLevel = !timeout->mInterval;
9070 PRUint32 nestingLevel;
9071 if (trackNestingLevel) {
9072 nestingLevel = sNestingLevel;
9073 sNestingLevel = timeout->mNestingLevel;
9076 nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
9077 void *scriptObject = handler->GetScriptObject();
9078 if (!scriptObject) {
9079 // Evaluate the timeout expression.
9080 const PRUnichar *script = handler->GetHandlerText();
9081 NS_ASSERTION(script, "timeout has no script nor handler text!");
9083 const char *filename = nsnull;
9084 PRUint32 lineNo = 0;
9085 handler->GetLocation(&filename, &lineNo);
9087 NS_TIME_FUNCTION_MARK("(file: %s, line: %d)", filename, lineNo);
9089 PRBool is_undefined;
9090 scx->EvaluateString(nsDependentString(script),
9091 GetScriptGlobal(handler->GetScriptTypeID()),
9092 timeout->mPrincipal, filename, lineNo,
9093 handler->GetScriptVersion(), nsnull,
9094 &is_undefined);
9095 } else {
9096 // Let the script handler know about the "secret" final argument that
9097 // indicates timeout lateness in milliseconds
9098 TimeDuration lateness = now - timeout->mWhen;
9100 handler->SetLateness(lateness.ToMilliseconds());
9102 nsCOMPtr<nsIVariant> dummy;
9103 nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
9104 scx->CallEventHandler(me,
9105 GetScriptGlobal(handler->GetScriptTypeID()),
9106 scriptObject, handler->GetArgv(),
9107 // XXXmarkh - consider allowing CallEventHandler to
9108 // accept nsnull?
9109 getter_AddRefs(dummy));
9112 handler = nsnull; // drop reference before dropping timeout refs.
9114 if (trackNestingLevel) {
9115 sNestingLevel = nestingLevel;
9118 --mTimeoutFiringDepth;
9119 --gRunningTimeoutDepth;
9121 mRunningTimeout = last_running_timeout;
9122 timeout->mRunning = PR_FALSE;
9124 // We ignore any failures from calling EvaluateString() or
9125 // CallEventHandler() on the context here since we're in a loop
9126 // where we're likely to be running timeouts whose OS timers
9127 // didn't fire in time and we don't want to not fire those timers
9128 // now just because execution of one timer failed. We can't
9129 // propagate the error to anyone who cares about it from this
9130 // point anyway, and the script context should have already reported
9131 // the script error in the usual way - so we just drop it.
9133 // If all timeouts were cleared and |timeout != aTimeout| then
9134 // |timeout| may be the last reference to the timeout so check if
9135 // it was cleared before releasing it.
9136 PRBool timeout_was_cleared = timeout->mCleared;
9138 timeout->Release();
9140 if (timeout_was_cleared) {
9141 // The running timeout's window was cleared, this means that
9142 // ClearAllTimeouts() was called from a *nested* call, possibly
9143 // through a timeout that fired while a modal (to this window)
9144 // dialog was open or through other non-obvious paths.
9146 mTimeoutInsertionPoint = last_insertion_point;
9148 return;
9151 PRBool isInterval = PR_FALSE;
9153 // If we have a regular interval timer, we re-schedule the
9154 // timeout, accounting for clock drift.
9155 if (timeout->mInterval) {
9156 // Compute time to next timeout for interval timer.
9157 // Make sure nextInterval is at least DOMMinTimeoutValue().
9158 TimeDuration nextInterval =
9159 TimeDuration::FromMilliseconds(NS_MAX(timeout->mInterval,
9160 PRUint32(DOMMinTimeoutValue())));
9162 // If we're running pending timeouts because they've been temporarily
9163 // disabled (!aTimeout), set the next interval to be relative to "now",
9164 // and not to when the timeout that was pending should have fired. Also
9165 // check if the next interval timeout is overdue. If so, then restart
9166 // the interval from now.
9167 TimeStamp firingTime;
9168 if (!aTimeout || timeout->mWhen + nextInterval <= now)
9169 firingTime = now + nextInterval;
9170 else
9171 firingTime = timeout->mWhen + nextInterval;
9173 TimeDuration delay = firingTime - TimeStamp::Now();
9175 // And make sure delay is nonnegative; that might happen if the timer
9176 // thread is firing our timers somewhat early.
9177 if (delay < TimeDuration(0)) {
9178 delay = TimeDuration(0);
9181 if (timeout->mTimer) {
9182 timeout->mWhen = firingTime;
9184 // Reschedule the OS timer. Don't bother returning any error
9185 // codes if this fails since the callers of this method
9186 // doesn't care about them nobody who cares about them
9187 // anyways.
9189 // Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
9190 // PRTime to make the division do the right thing on 64-bit
9191 // platforms whether delay is positive or negative (which we
9192 // know is always positive here, but cast anyways for
9193 // consistency).
9194 nsresult rv = timeout->mTimer->
9195 InitWithFuncCallback(TimerCallback, timeout,
9196 delay.ToMilliseconds(),
9197 nsITimer::TYPE_ONE_SHOT);
9199 if (NS_FAILED(rv)) {
9200 NS_ERROR("Error initializing timer for DOM timeout!");
9202 // We failed to initialize the new OS timer, this timer does
9203 // us no good here so we just cancel it (just in case) and
9204 // null out the pointer to the OS timer, this will release the
9205 // OS timer. As we continue executing the code below we'll end
9206 // up deleting the timeout since it's not an interval timeout
9207 // any more (since timeout->mTimer == nsnull).
9208 timeout->mTimer->Cancel();
9209 timeout->mTimer = nsnull;
9211 // Now that the OS timer no longer has a reference to the
9212 // timeout we need to drop that reference.
9213 timeout->Release();
9215 } else {
9216 NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth,
9217 "How'd our timer end up null if we're not frozen or "
9218 "suspended?");
9220 timeout->mTimeRemaining = delay;
9221 isInterval = PR_TRUE;
9225 if (timeout->mTimer) {
9226 if (timeout->mInterval) {
9227 isInterval = PR_TRUE;
9228 } else {
9229 // The timeout still has an OS timer, and it's not an
9230 // interval, that means that the OS timer could still fire (if
9231 // it didn't already, i.e. aTimeout == timeout), cancel the OS
9232 // timer and release its reference to the timeout.
9233 timeout->mTimer->Cancel();
9234 timeout->mTimer = nsnull;
9236 timeout->Release();
9240 // Running a timeout can cause another timeout to be deleted, so
9241 // we need to reset the pointer to the following timeout.
9242 nextTimeout = timeout->Next();
9244 PR_REMOVE_LINK(timeout);
9246 if (isInterval) {
9247 // Reschedule an interval timeout. Insert interval timeout
9248 // onto list sorted in deadline order.
9249 // AddRefs timeout.
9250 InsertTimeoutIntoList(timeout);
9253 // Release the timeout struct since it's possibly out of the list
9254 timeout->Release();
9257 // Take the dummy timeout off the head of the list
9258 PR_REMOVE_LINK(&dummy_timeout);
9260 mTimeoutInsertionPoint = last_insertion_point;
9263 nsrefcnt
9264 nsTimeout::Release()
9266 if (--mRefCnt > 0)
9267 return mRefCnt;
9269 // language specific cleanup done as mScriptHandler destructs...
9271 // Kill the timer if it is still alive.
9272 if (mTimer) {
9273 mTimer->Cancel();
9274 mTimer = nsnull;
9277 delete this;
9278 return 0;
9281 nsrefcnt
9282 nsTimeout::AddRef()
9284 return ++mRefCnt;
9288 nsresult
9289 nsGlobalWindow::ClearTimeoutOrInterval(PRInt32 aTimerID)
9291 FORWARD_TO_INNER(ClearTimeoutOrInterval, (aTimerID), NS_ERROR_NOT_INITIALIZED);
9293 PRUint32 public_id = (PRUint32)aTimerID;
9294 nsTimeout *timeout;
9296 for (timeout = FirstTimeout();
9297 IsTimeout(timeout);
9298 timeout = timeout->Next()) {
9299 if (timeout->mPublicId == public_id) {
9300 if (timeout->mRunning) {
9301 /* We're running from inside the timeout. Mark this
9302 timeout for deferred deletion by the code in
9303 RunTimeout() */
9304 timeout->mInterval = 0;
9306 else {
9307 /* Delete the timeout from the pending timeout list */
9308 PR_REMOVE_LINK(timeout);
9310 if (timeout->mTimer) {
9311 timeout->mTimer->Cancel();
9312 timeout->mTimer = nsnull;
9313 timeout->Release();
9315 timeout->Release();
9317 break;
9321 return NS_OK;
9324 // A JavaScript specific version.
9325 nsresult
9326 nsGlobalWindow::ClearTimeoutOrInterval()
9328 FORWARD_TO_INNER(ClearTimeoutOrInterval, (), NS_ERROR_NOT_INITIALIZED);
9330 nsresult rv = NS_OK;
9331 nsAXPCNativeCallContext *ncc = nsnull;
9333 rv = nsContentUtils::XPConnect()->
9334 GetCurrentNativeCallContext(&ncc);
9335 NS_ENSURE_SUCCESS(rv, rv);
9337 if (!ncc)
9338 return NS_ERROR_NOT_AVAILABLE;
9340 JSContext *cx = nsnull;
9342 rv = ncc->GetJSContext(&cx);
9343 NS_ENSURE_SUCCESS(rv, rv);
9345 PRUint32 argc;
9347 ncc->GetArgc(&argc);
9349 if (argc < 1) {
9350 // No arguments, return early.
9352 return NS_OK;
9355 jsval *argv = nsnull;
9357 ncc->GetArgvPtr(&argv);
9359 int32 timer_id;
9361 JSAutoRequest ar(cx);
9363 // XXXjst: Can we deal with this w/o using GetCurrentNativeCallContext()
9364 if (argv[0] == JSVAL_VOID || !::JS_ValueToInt32(cx, argv[0], &timer_id) ||
9365 timer_id <= 0) {
9366 // Undefined or non-positive number passed as argument, return
9367 // early. Make sure that JS_ValueToInt32 didn't set an exception.
9369 ::JS_ClearPendingException(cx);
9370 return NS_OK;
9373 return ClearTimeoutOrInterval(timer_id);
9376 void
9377 nsGlobalWindow::ClearAllTimeouts()
9379 nsTimeout *timeout, *nextTimeout;
9381 for (timeout = FirstTimeout(); IsTimeout(timeout); timeout = nextTimeout) {
9382 /* If RunTimeout() is higher up on the stack for this
9383 window, e.g. as a result of document.write from a timeout,
9384 then we need to reset the list insertion point for
9385 newly-created timeouts in case the user adds a timeout,
9386 before we pop the stack back to RunTimeout. */
9387 if (mRunningTimeout == timeout)
9388 mTimeoutInsertionPoint = nsnull;
9390 nextTimeout = timeout->Next();
9392 if (timeout->mTimer) {
9393 timeout->mTimer->Cancel();
9394 timeout->mTimer = nsnull;
9396 // Drop the count since the timer isn't going to hold on
9397 // anymore.
9398 timeout->Release();
9401 // Set timeout->mCleared to true to indicate that the timeout was
9402 // cleared and taken out of the list of timeouts
9403 timeout->mCleared = PR_TRUE;
9405 // Drop the count since we're removing it from the list.
9406 timeout->Release();
9409 // Clear out our list
9410 PR_INIT_CLIST(&mTimeouts);
9413 void
9414 nsGlobalWindow::InsertTimeoutIntoList(nsTimeout *aTimeout)
9416 NS_ASSERTION(IsInnerWindow(),
9417 "InsertTimeoutIntoList() called on outer window!");
9419 // Start at mLastTimeout and go backwards. Don't go further than
9420 // mTimeoutInsertionPoint, though. This optimizes for the common case of
9421 // insertion at the end.
9422 nsTimeout* prevSibling;
9423 for (prevSibling = LastTimeout();
9424 IsTimeout(prevSibling) && prevSibling != mTimeoutInsertionPoint &&
9425 // This condition needs to match the one in SetTimeoutOrInterval that
9426 // determines whether to set mWhen or mTimeRemaining.
9427 ((IsFrozen() || mTimeoutsSuspendDepth) ?
9428 prevSibling->mTimeRemaining > aTimeout->mTimeRemaining :
9429 prevSibling->mWhen > aTimeout->mWhen);
9430 prevSibling = prevSibling->Prev()) {
9431 /* Do nothing; just searching */
9434 // Now link in aTimeout after prevSibling.
9435 PR_INSERT_AFTER(aTimeout, prevSibling);
9437 aTimeout->mFiringDepth = 0;
9439 // Increment the timeout's reference count since it's now held on to
9440 // by the list
9441 aTimeout->AddRef();
9444 // static
9445 void
9446 nsGlobalWindow::TimerCallback(nsITimer *aTimer, void *aClosure)
9448 nsTimeout *timeout = (nsTimeout *)aClosure;
9450 // Hold on to the timeout to ensure it doesn't go away while it's
9451 // being handled (aka kungFuDeathGrip).
9452 timeout->AddRef();
9454 timeout->mWindow->RunTimeout(timeout);
9456 // Drop our reference to the timeout now that we're done with it.
9457 timeout->Release();
9460 //*****************************************************************************
9461 // nsGlobalWindow: Helper Functions
9462 //*****************************************************************************
9464 nsresult
9465 nsGlobalWindow::GetTreeOwner(nsIDocShellTreeOwner **aTreeOwner)
9467 FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
9469 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
9471 // If there's no docShellAsItem, this window must have been closed,
9472 // in that case there is no tree owner.
9474 if (!docShellAsItem) {
9475 *aTreeOwner = nsnull;
9477 return NS_OK;
9480 return docShellAsItem->GetTreeOwner(aTreeOwner);
9483 nsresult
9484 nsGlobalWindow::GetTreeOwner(nsIBaseWindow **aTreeOwner)
9486 FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
9488 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
9489 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
9491 // If there's no docShellAsItem, this window must have been closed,
9492 // in that case there is no tree owner.
9494 if (docShellAsItem) {
9495 docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
9498 if (!treeOwner) {
9499 *aTreeOwner = nsnull;
9500 return NS_OK;
9503 return CallQueryInterface(treeOwner, aTreeOwner);
9506 nsresult
9507 nsGlobalWindow::GetWebBrowserChrome(nsIWebBrowserChrome **aBrowserChrome)
9509 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
9510 GetTreeOwner(getter_AddRefs(treeOwner));
9512 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner));
9513 NS_IF_ADDREF(*aBrowserChrome = browserChrome);
9515 return NS_OK;
9518 nsIScrollableFrame *
9519 nsGlobalWindow::GetScrollFrame()
9521 FORWARD_TO_OUTER(GetScrollFrame, (), nsnull);
9523 if (!mDocShell) {
9524 return nsnull;
9527 nsCOMPtr<nsIPresShell> presShell;
9528 mDocShell->GetPresShell(getter_AddRefs(presShell));
9529 if (presShell) {
9530 return presShell->GetRootScrollFrameAsScrollable();
9532 return nsnull;
9535 nsresult
9536 nsGlobalWindow::BuildURIfromBase(const char *aURL, nsIURI **aBuiltURI,
9537 PRBool *aFreeSecurityPass,
9538 JSContext **aCXused)
9540 nsIScriptContext *scx = GetContextInternal();
9541 JSContext *cx = nsnull;
9543 *aBuiltURI = nsnull;
9544 *aFreeSecurityPass = PR_FALSE;
9545 if (aCXused)
9546 *aCXused = nsnull;
9548 // get JSContext
9549 NS_ASSERTION(scx, "opening window missing its context");
9550 NS_ASSERTION(mDocument, "opening window missing its document");
9551 if (!scx || !mDocument)
9552 return NS_ERROR_FAILURE;
9554 nsCOMPtr<nsIDOMChromeWindow> chrome_win =
9555 do_QueryInterface(static_cast<nsIDOMWindow *>(this));
9557 if (nsContentUtils::IsCallerChrome() && !chrome_win) {
9558 // If open() is called from chrome on a non-chrome window, we'll
9559 // use the context from the window on which open() is being called
9560 // to prevent giving chrome priveleges to new windows opened in
9561 // such a way. This also makes us get the appropriate base URI for
9562 // the below URI resolution code.
9564 cx = (JSContext *)scx->GetNativeContext();
9565 } else {
9566 // get the JSContext from the call stack
9567 nsCOMPtr<nsIThreadJSContextStack> stack(do_GetService(sJSStackContractID));
9568 if (stack)
9569 stack->Peek(&cx);
9572 /* resolve the URI, which could be relative to the calling window
9573 (note the algorithm to get the base URI should match the one
9574 used to actually kick off the load in nsWindowWatcher.cpp). */
9575 nsCAutoString charset(NS_LITERAL_CSTRING("UTF-8")); // default to utf-8
9576 nsIURI* baseURI = nsnull;
9577 nsCOMPtr<nsIURI> uriToLoad;
9578 nsCOMPtr<nsIDOMWindow> sourceWindow;
9580 if (cx) {
9581 nsIScriptContext *scriptcx = nsJSUtils::GetDynamicScriptContext(cx);
9582 if (scriptcx)
9583 sourceWindow = do_QueryInterface(scriptcx->GetGlobalObject());
9586 if (!sourceWindow) {
9587 sourceWindow = do_QueryInterface(NS_ISUPPORTS_CAST(nsIDOMWindow *, this));
9588 *aFreeSecurityPass = PR_TRUE;
9591 if (sourceWindow) {
9592 nsCOMPtr<nsIDOMDocument> domDoc;
9593 sourceWindow->GetDocument(getter_AddRefs(domDoc));
9594 nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
9595 if (doc) {
9596 baseURI = doc->GetDocBaseURI();
9597 charset = doc->GetDocumentCharacterSet();
9601 if (aCXused)
9602 *aCXused = cx;
9603 return NS_NewURI(aBuiltURI, nsDependentCString(aURL), charset.get(), baseURI);
9606 nsresult
9607 nsGlobalWindow::SecurityCheckURL(const char *aURL)
9609 JSContext *cx;
9610 PRBool freePass;
9611 nsCOMPtr<nsIURI> uri;
9613 if (NS_FAILED(BuildURIfromBase(aURL, getter_AddRefs(uri), &freePass, &cx)))
9614 return NS_ERROR_FAILURE;
9616 if (!freePass && NS_FAILED(nsContentUtils::GetSecurityManager()->
9617 CheckLoadURIFromScript(cx, uri)))
9618 return NS_ERROR_FAILURE;
9620 return NS_OK;
9623 void
9624 nsGlobalWindow::FlushPendingNotifications(mozFlushType aType)
9626 if (mDoc) {
9627 mDoc->FlushPendingNotifications(aType);
9631 void
9632 nsGlobalWindow::EnsureSizeUpToDate()
9634 // If we're a subframe, make sure our size is up to date. It's OK that this
9635 // crosses the content/chrome boundary, since chrome can have pending reflows
9636 // too.
9637 nsGlobalWindow *parent =
9638 static_cast<nsGlobalWindow *>(GetPrivateParent());
9639 if (parent) {
9640 parent->FlushPendingNotifications(Flush_Layout);
9644 nsresult
9645 nsGlobalWindow::SaveWindowState(nsISupports **aState)
9647 NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
9649 *aState = nsnull;
9651 if (!mContext || !mJSObject) {
9652 // The window may be getting torn down; don't bother saving state.
9653 return NS_OK;
9656 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
9657 NS_ASSERTION(inner, "No inner window to save");
9659 // Don't do anything else to this inner window! After this point, all
9660 // calls to SetTimeoutOrInterval will create entries in the timeout
9661 // list that will only run after this window has come out of the bfcache.
9662 // Also, while we're frozen, we won't dispatch online/offline events
9663 // to the page.
9664 inner->Freeze();
9666 // Remember the outer window's prototype.
9667 JSContext *cx = (JSContext *)mContext->GetNativeContext();
9668 JSAutoRequest req(cx);
9670 nsIXPConnect *xpc = nsContentUtils::XPConnect();
9672 nsCOMPtr<nsIClassInfo> ci =
9673 do_QueryInterface((nsIScriptGlobalObject *)this);
9674 nsCOMPtr<nsIXPConnectJSObjectHolder> proto;
9675 nsresult rv = xpc->GetWrappedNativePrototype(cx, mJSObject, ci,
9676 getter_AddRefs(proto));
9677 NS_ENSURE_SUCCESS(rv, rv);
9679 JSObject *realProto = JS_GetPrototype(cx, mJSObject);
9680 nsCOMPtr<nsIXPConnectJSObjectHolder> realProtoHolder;
9681 if (realProto) {
9682 rv = xpc->HoldObject(cx, realProto, getter_AddRefs(realProtoHolder));
9683 NS_ENSURE_SUCCESS(rv, rv);
9686 nsCOMPtr<nsISupports> state = new WindowStateHolder(inner,
9687 mInnerWindowHolder,
9688 mNavigator,
9689 proto,
9690 realProtoHolder);
9691 NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY);
9693 JSObject *wnProto;
9694 proto->GetJSObject(&wnProto);
9695 if (!JS_SetPrototype(cx, mJSObject, wnProto)) {
9696 return NS_ERROR_FAILURE;
9699 #ifdef DEBUG_PAGE_CACHE
9700 printf("saving window state, state = %p\n", (void*)state);
9701 #endif
9703 state.swap(*aState);
9704 return NS_OK;
9707 nsresult
9708 nsGlobalWindow::RestoreWindowState(nsISupports *aState)
9710 NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window");
9712 if (!mContext || !mJSObject) {
9713 // The window may be getting torn down; don't bother restoring state.
9714 return NS_OK;
9717 nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
9718 NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE);
9720 #ifdef DEBUG_PAGE_CACHE
9721 printf("restoring window state, state = %p\n", (void*)holder);
9722 #endif
9724 // And we're ready to go!
9725 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
9727 // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
9728 // it easy to tell which link was last clicked when going back a page.
9729 nsIContent* focusedNode = inner->GetFocusedNode();
9730 if (IsLink(focusedNode)) {
9731 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
9732 if (fm) {
9733 nsCOMPtr<nsIDOMElement> focusedElement(do_QueryInterface(focusedNode));
9734 fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
9735 nsIFocusManager::FLAG_SHOWRING);
9739 inner->Thaw();
9741 holder->DidRestoreWindow();
9743 return NS_OK;
9746 void
9747 nsGlobalWindow::SuspendTimeouts(PRUint32 aIncrease,
9748 PRBool aFreezeChildren)
9750 FORWARD_TO_INNER_VOID(SuspendTimeouts, (aIncrease, aFreezeChildren));
9752 PRBool suspended = (mTimeoutsSuspendDepth != 0);
9753 mTimeoutsSuspendDepth += aIncrease;
9755 if (!suspended) {
9756 DisableAccelerationUpdates();
9758 nsDOMThreadService* dts = nsDOMThreadService::get();
9759 if (dts) {
9760 dts->SuspendWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
9763 TimeStamp now = TimeStamp::Now();
9764 for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
9765 // Set mTimeRemaining to be the time remaining for this timer.
9766 if (t->mWhen > now)
9767 t->mTimeRemaining = t->mWhen - now;
9768 else
9769 t->mTimeRemaining = TimeDuration(0);
9771 // Drop the XPCOM timer; we'll reschedule when restoring the state.
9772 if (t->mTimer) {
9773 t->mTimer->Cancel();
9774 t->mTimer = nsnull;
9776 // Drop the reference that the timer's closure had on this timeout, we'll
9777 // add it back in ResumeTimeouts. Note that it shouldn't matter that we're
9778 // passing null for the context, since this shouldn't actually release this
9779 // timeout.
9780 t->Release();
9785 // Suspend our children as well.
9786 nsCOMPtr<nsIDocShellTreeNode> node(do_QueryInterface(GetDocShell()));
9787 if (node) {
9788 PRInt32 childCount = 0;
9789 node->GetChildCount(&childCount);
9791 for (PRInt32 i = 0; i < childCount; ++i) {
9792 nsCOMPtr<nsIDocShellTreeItem> childShell;
9793 node->GetChildAt(i, getter_AddRefs(childShell));
9794 NS_ASSERTION(childShell, "null child shell");
9796 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
9797 if (pWin) {
9798 nsGlobalWindow *win =
9799 static_cast<nsGlobalWindow*>
9800 (static_cast<nsPIDOMWindow*>(pWin));
9801 NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
9802 nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
9804 // This is a bit hackish. Only freeze/suspend windows which are truly our
9805 // subwindows.
9806 nsCOMPtr<nsIContent> frame = do_QueryInterface(pWin->GetFrameElementInternal());
9807 if (!mDoc || !frame || mDoc != frame->GetOwnerDoc() || !inner) {
9808 continue;
9811 win->SuspendTimeouts(aIncrease, aFreezeChildren);
9813 if (inner && aFreezeChildren) {
9814 inner->Freeze();
9821 nsresult
9822 nsGlobalWindow::ResumeTimeouts(PRBool aThawChildren)
9824 FORWARD_TO_INNER(ResumeTimeouts, (), NS_ERROR_NOT_INITIALIZED);
9826 NS_ASSERTION(mTimeoutsSuspendDepth, "Mismatched calls to ResumeTimeouts!");
9827 --mTimeoutsSuspendDepth;
9828 PRBool shouldResume = (mTimeoutsSuspendDepth == 0);
9829 nsresult rv;
9831 if (shouldResume) {
9832 EnableAccelerationUpdates();
9834 nsDOMThreadService* dts = nsDOMThreadService::get();
9835 if (dts) {
9836 dts->ResumeWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
9839 // Restore all of the timeouts, using the stored time remaining
9840 // (stored in timeout->mTimeRemaining).
9842 TimeStamp now = TimeStamp::Now();
9844 #ifdef DEBUG
9845 PRBool _seenDummyTimeout = PR_FALSE;
9846 #endif
9848 for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
9849 // There's a chance we're being called with RunTimeout on the stack in which
9850 // case we have a dummy timeout in the list that *must not* be resumed. It
9851 // can be identified by a null mWindow.
9852 if (!t->mWindow) {
9853 #ifdef DEBUG
9854 NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
9855 _seenDummyTimeout = PR_TRUE;
9856 #endif
9857 continue;
9860 // XXXbz the combination of the way |delay| and |t->mWhen| are set here
9861 // makes no sense. Are we trying to impose that min timeout value or
9862 // not???
9863 PRUint32 delay =
9864 NS_MAX(PRInt32(t->mTimeRemaining.ToMilliseconds()),
9865 DOMMinTimeoutValue());
9867 // Set mWhen back to the time when the timer is supposed to
9868 // fire.
9869 t->mWhen = now + t->mTimeRemaining;
9871 t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
9872 NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY);
9874 rv = t->mTimer->InitWithFuncCallback(TimerCallback, t, delay,
9875 nsITimer::TYPE_ONE_SHOT);
9876 if (NS_FAILED(rv)) {
9877 t->mTimer = nsnull;
9878 return rv;
9881 // Add a reference for the new timer's closure.
9882 t->AddRef();
9886 // Resume our children as well.
9887 nsCOMPtr<nsIDocShellTreeNode> node =
9888 do_QueryInterface(GetDocShell());
9889 if (node) {
9890 PRInt32 childCount = 0;
9891 node->GetChildCount(&childCount);
9893 for (PRInt32 i = 0; i < childCount; ++i) {
9894 nsCOMPtr<nsIDocShellTreeItem> childShell;
9895 node->GetChildAt(i, getter_AddRefs(childShell));
9896 NS_ASSERTION(childShell, "null child shell");
9898 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
9899 if (pWin) {
9900 nsGlobalWindow *win =
9901 static_cast<nsGlobalWindow*>
9902 (static_cast<nsPIDOMWindow*>(pWin));
9904 NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
9905 nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
9907 // This is a bit hackish. Only thaw/resume windows which are truly our
9908 // subwindows.
9909 nsCOMPtr<nsIContent> frame = do_QueryInterface(pWin->GetFrameElementInternal());
9910 if (!mDoc || !frame || mDoc != frame->GetOwnerDoc() || !inner) {
9911 continue;
9914 if (inner && aThawChildren) {
9915 inner->Thaw();
9918 rv = win->ResumeTimeouts(aThawChildren);
9919 NS_ENSURE_SUCCESS(rv, rv);
9924 return NS_OK;
9927 PRUint32
9928 nsGlobalWindow::TimeoutSuspendCount()
9930 FORWARD_TO_INNER(TimeoutSuspendCount, (), 0);
9931 return mTimeoutsSuspendDepth;
9934 NS_IMETHODIMP
9935 nsGlobalWindow::GetScriptTypeID(PRUint32 *aScriptType)
9937 NS_ERROR("No default script type here - ask some element");
9938 return nsIProgrammingLanguage::UNKNOWN;
9941 NS_IMETHODIMP
9942 nsGlobalWindow::SetScriptTypeID(PRUint32 aScriptType)
9944 NS_ERROR("Can't change default script type for a document");
9945 return NS_ERROR_NOT_IMPLEMENTED;
9948 void
9949 nsGlobalWindow::SetHasOrientationEventListener()
9951 mHasAcceleration = PR_TRUE;
9952 EnableAccelerationUpdates();
9955 NS_IMETHODIMP
9956 nsGlobalWindow::GetURL(nsIDOMMozURLProperty** aURL)
9958 FORWARD_TO_INNER(GetURL, (aURL), NS_ERROR_UNEXPECTED);
9960 if (!mURLProperty) {
9961 mURLProperty = new nsDOMMozURLProperty(this);
9964 NS_ADDREF(*aURL = mURLProperty);
9966 return NS_OK;
9969 // nsGlobalChromeWindow implementation
9971 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
9972 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
9973 nsGlobalWindow)
9974 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBrowserDOMWindow)
9975 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMessageManager)
9976 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
9978 DOMCI_DATA(ChromeWindow, nsGlobalChromeWindow)
9980 // QueryInterface implementation for nsGlobalChromeWindow
9981 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow)
9982 NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)
9983 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ChromeWindow)
9984 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
9986 NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
9987 NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
9989 NS_IMETHODIMP
9990 nsGlobalChromeWindow::GetWindowState(PRUint16* aWindowState)
9992 *aWindowState = nsIDOMChromeWindow::STATE_NORMAL;
9994 nsCOMPtr<nsIWidget> widget = GetMainWidget();
9996 PRInt32 aMode = 0;
9998 if (widget) {
9999 nsresult rv = widget->GetSizeMode(&aMode);
10000 NS_ENSURE_SUCCESS(rv, rv);
10003 switch (aMode) {
10004 case nsSizeMode_Minimized:
10005 *aWindowState = nsIDOMChromeWindow::STATE_MINIMIZED;
10006 break;
10007 case nsSizeMode_Maximized:
10008 *aWindowState = nsIDOMChromeWindow::STATE_MAXIMIZED;
10009 break;
10010 case nsSizeMode_Fullscreen:
10011 *aWindowState = nsIDOMChromeWindow::STATE_FULLSCREEN;
10012 break;
10013 case nsSizeMode_Normal:
10014 *aWindowState = nsIDOMChromeWindow::STATE_NORMAL;
10015 break;
10016 default:
10017 NS_WARNING("Illegal window state for this chrome window");
10018 break;
10021 return NS_OK;
10024 NS_IMETHODIMP
10025 nsGlobalChromeWindow::Maximize()
10027 nsCOMPtr<nsIWidget> widget = GetMainWidget();
10028 nsresult rv = NS_OK;
10030 if (widget) {
10031 rv = widget->SetSizeMode(nsSizeMode_Maximized);
10034 return rv;
10037 NS_IMETHODIMP
10038 nsGlobalChromeWindow::Minimize()
10040 nsCOMPtr<nsIWidget> widget = GetMainWidget();
10041 nsresult rv = NS_OK;
10043 if (widget)
10044 rv = widget->SetSizeMode(nsSizeMode_Minimized);
10046 return rv;
10049 NS_IMETHODIMP
10050 nsGlobalChromeWindow::Restore()
10052 nsCOMPtr<nsIWidget> widget = GetMainWidget();
10053 nsresult rv = NS_OK;
10055 if (widget) {
10056 rv = widget->SetSizeMode(nsSizeMode_Normal);
10059 return rv;
10062 NS_IMETHODIMP
10063 nsGlobalChromeWindow::GetAttention()
10065 return GetAttentionWithCycleCount(-1);
10068 NS_IMETHODIMP
10069 nsGlobalChromeWindow::GetAttentionWithCycleCount(PRInt32 aCycleCount)
10071 nsCOMPtr<nsIWidget> widget = GetMainWidget();
10072 nsresult rv = NS_OK;
10074 if (widget) {
10075 rv = widget->GetAttention(aCycleCount);
10078 return rv;
10081 NS_IMETHODIMP
10082 nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent)
10084 nsCOMPtr<nsIWidget> widget = GetMainWidget();
10085 if (!widget) {
10086 return NS_OK;
10089 nsCOMPtr<nsIPrivateDOMEvent> privEvent = do_QueryInterface(aMouseDownEvent);
10090 NS_ENSURE_TRUE(privEvent, NS_ERROR_FAILURE);
10091 nsEvent *internalEvent = privEvent->GetInternalNSEvent();
10092 NS_ENSURE_TRUE(internalEvent &&
10093 internalEvent->eventStructType == NS_MOUSE_EVENT,
10094 NS_ERROR_FAILURE);
10095 nsMouseEvent *mouseEvent = static_cast<nsMouseEvent*>(internalEvent);
10097 return widget->BeginMoveDrag(mouseEvent);
10100 //Note: This call will lock the cursor, it will not change as it moves.
10101 //To unlock, the cursor must be set back to CURSOR_AUTO.
10102 NS_IMETHODIMP
10103 nsGlobalChromeWindow::SetCursor(const nsAString& aCursor)
10105 FORWARD_TO_OUTER_CHROME(SetCursor, (aCursor), NS_ERROR_NOT_INITIALIZED);
10107 nsresult rv = NS_OK;
10108 PRInt32 cursor;
10110 // use C strings to keep the code/data size down
10111 NS_ConvertUTF16toUTF8 cursorString(aCursor);
10113 if (cursorString.Equals("auto"))
10114 cursor = NS_STYLE_CURSOR_AUTO;
10115 else {
10116 nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
10117 if (eCSSKeyword_UNKNOWN == keyword ||
10118 !nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, cursor)) {
10119 // XXX remove the following three values (leave return NS_OK) after 1.8
10120 // XXX since they should have been -moz- prefixed (covered by FindKeyword).
10121 // XXX (also remove |cursorString| at that point?).
10122 if (cursorString.Equals("grab"))
10123 cursor = NS_STYLE_CURSOR_GRAB;
10124 else if (cursorString.Equals("grabbing"))
10125 cursor = NS_STYLE_CURSOR_GRABBING;
10126 else if (cursorString.Equals("spinning"))
10127 cursor = NS_STYLE_CURSOR_SPINNING;
10128 else
10129 return NS_OK;
10133 nsRefPtr<nsPresContext> presContext;
10134 if (mDocShell) {
10135 mDocShell->GetPresContext(getter_AddRefs(presContext));
10138 if (presContext) {
10139 // Need root widget.
10140 nsCOMPtr<nsIPresShell> presShell;
10141 mDocShell->GetPresShell(getter_AddRefs(presShell));
10142 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
10144 nsIViewManager* vm = presShell->GetViewManager();
10145 NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
10147 nsIView *rootView;
10148 vm->GetRootView(rootView);
10149 NS_ENSURE_TRUE(rootView, NS_ERROR_FAILURE);
10151 nsIWidget* widget = rootView->GetNearestWidget(nsnull);
10152 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
10154 // Call esm and set cursor.
10155 rv = presContext->EventStateManager()->SetCursor(cursor, nsnull,
10156 PR_FALSE, 0.0f, 0.0f,
10157 widget, PR_TRUE);
10160 return rv;
10163 NS_IMETHODIMP
10164 nsGlobalChromeWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow)
10166 FORWARD_TO_OUTER_CHROME(GetBrowserDOMWindow, (aBrowserWindow),
10167 NS_ERROR_NOT_INITIALIZED);
10169 NS_ENSURE_ARG_POINTER(aBrowserWindow);
10171 *aBrowserWindow = mBrowserDOMWindow;
10172 NS_IF_ADDREF(*aBrowserWindow);
10173 return NS_OK;
10176 NS_IMETHODIMP
10177 nsGlobalChromeWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow *aBrowserWindow)
10179 FORWARD_TO_OUTER_CHROME(SetBrowserDOMWindow, (aBrowserWindow),
10180 NS_ERROR_NOT_INITIALIZED);
10182 mBrowserDOMWindow = aBrowserWindow;
10183 return NS_OK;
10186 NS_IMETHODIMP
10187 nsGlobalChromeWindow::NotifyDefaultButtonLoaded(nsIDOMElement* aDefaultButton)
10189 #ifdef MOZ_XUL
10190 NS_ENSURE_ARG(aDefaultButton);
10192 // Don't snap to a disabled button.
10193 nsCOMPtr<nsIDOMXULControlElement> xulControl =
10194 do_QueryInterface(aDefaultButton);
10195 NS_ENSURE_TRUE(xulControl, NS_ERROR_FAILURE);
10196 PRBool disabled;
10197 nsresult rv = xulControl->GetDisabled(&disabled);
10198 NS_ENSURE_SUCCESS(rv, rv);
10199 if (disabled)
10200 return NS_OK;
10202 // Get the button rect in screen coordinates.
10203 nsCOMPtr<nsIContent> content(do_QueryInterface(aDefaultButton));
10204 NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
10205 nsIFrame *frame = content->GetPrimaryFrame();
10206 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
10207 nsIntRect buttonRect = frame->GetScreenRect();
10209 // Get the widget rect in screen coordinates.
10210 nsIWidget *widget = GetNearestWidget();
10211 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
10212 nsIntRect widgetRect;
10213 rv = widget->GetScreenBounds(widgetRect);
10214 NS_ENSURE_SUCCESS(rv, rv);
10216 // Convert the buttonRect coordinates from screen to the widget.
10217 buttonRect -= widgetRect.TopLeft();
10218 rv = widget->OnDefaultButtonLoaded(buttonRect);
10219 if (rv == NS_ERROR_NOT_IMPLEMENTED)
10220 return NS_OK;
10221 return rv;
10222 #else
10223 return NS_ERROR_NOT_IMPLEMENTED;
10224 #endif
10227 NS_IMETHODIMP
10228 nsGlobalChromeWindow::GetMessageManager(nsIChromeFrameMessageManager** aManager)
10230 FORWARD_TO_INNER_CHROME(GetMessageManager, (aManager), NS_ERROR_FAILURE);
10231 if (!mMessageManager) {
10232 nsIScriptContext* scx = GetContextInternal();
10233 NS_ENSURE_STATE(scx);
10234 JSContext* cx = (JSContext *)scx->GetNativeContext();
10235 NS_ENSURE_STATE(cx);
10236 nsCOMPtr<nsIChromeFrameMessageManager> globalMM =
10237 do_GetService("@mozilla.org/globalmessagemanager;1");
10238 mMessageManager =
10239 new nsFrameMessageManager(PR_TRUE,
10240 nsnull,
10241 nsnull,
10242 nsnull,
10243 nsnull,
10244 static_cast<nsFrameMessageManager*>(globalMM.get()),
10245 cx);
10246 NS_ENSURE_TRUE(mMessageManager, NS_ERROR_OUT_OF_MEMORY);
10248 CallQueryInterface(mMessageManager, aManager);
10249 return NS_OK;
10252 // nsGlobalModalWindow implementation
10254 // QueryInterface implementation for nsGlobalModalWindow
10255 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalModalWindow)
10256 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalModalWindow,
10257 nsGlobalWindow)
10258 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mReturnValue)
10259 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
10261 DOMCI_DATA(ModalContentWindow, nsGlobalModalWindow)
10263 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalModalWindow)
10264 NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow)
10265 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ModalContentWindow)
10266 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
10268 NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
10269 NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
10272 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalModalWindow,
10273 nsGlobalWindow)
10274 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReturnValue)
10275 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
10278 NS_IMETHODIMP
10279 nsGlobalModalWindow::GetDialogArguments(nsIArray **aArguments)
10281 FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(GetDialogArguments, (aArguments),
10282 NS_ERROR_NOT_INITIALIZED);
10284 PRBool subsumes = PR_FALSE;
10285 nsIPrincipal *self = GetPrincipal();
10286 if (self && NS_SUCCEEDED(self->Subsumes(mArgumentsOrigin, &subsumes)) &&
10287 subsumes) {
10288 NS_IF_ADDREF(*aArguments = mArguments);
10289 } else {
10290 *aArguments = nsnull;
10293 return NS_OK;
10296 NS_IMETHODIMP
10297 nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
10299 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
10301 NS_IF_ADDREF(*aRetVal = mReturnValue);
10303 return NS_OK;
10306 NS_IMETHODIMP
10307 nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
10309 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aRetVal), NS_OK);
10311 mReturnValue = aRetVal;
10313 return NS_OK;
10316 nsresult
10317 nsGlobalModalWindow::SetNewDocument(nsIDocument *aDocument,
10318 nsISupports *aState,
10319 PRBool aForceReuseInnerWindow)
10321 // If we're loading a new document into a modal dialog, clear the
10322 // return value that was set, if any, by the current document.
10323 if (aDocument) {
10324 mReturnValue = nsnull;
10327 return nsGlobalWindow::SetNewDocument(aDocument, aState,
10328 aForceReuseInnerWindow);
10331 //*****************************************************************************
10332 // nsGlobalWindow: Creator Function (This should go away)
10333 //*****************************************************************************
10335 nsresult
10336 NS_NewScriptGlobalObject(PRBool aIsChrome, PRBool aIsModalContentWindow,
10337 nsIScriptGlobalObject **aResult)
10339 *aResult = nsnull;
10341 nsGlobalWindow *global;
10343 if (aIsChrome) {
10344 global = new nsGlobalChromeWindow(nsnull);
10345 } else if (aIsModalContentWindow) {
10346 global = new nsGlobalModalWindow(nsnull);
10347 } else {
10348 global = new nsGlobalWindow(nsnull);
10351 NS_ENSURE_TRUE(global, NS_ERROR_OUT_OF_MEMORY);
10353 NS_ADDREF(*aResult = global);
10355 return NS_OK;
10358 //*****************************************************************************
10359 //*** nsNavigator: Object Management
10360 //*****************************************************************************
10362 nsNavigator::nsNavigator(nsIDocShell *aDocShell)
10363 : mDocShell(aDocShell)
10367 nsNavigator::~nsNavigator()
10369 if (mMimeTypes)
10370 mMimeTypes->Invalidate();
10371 if (mPlugins)
10372 mPlugins->Invalidate();
10375 //*****************************************************************************
10376 // nsNavigator::nsISupports
10377 //*****************************************************************************
10380 DOMCI_DATA(Navigator, nsNavigator)
10382 // QueryInterface implementation for nsNavigator
10383 NS_INTERFACE_MAP_BEGIN(nsNavigator)
10384 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNavigator)
10385 NS_INTERFACE_MAP_ENTRY(nsIDOMNavigator)
10386 NS_INTERFACE_MAP_ENTRY(nsIDOMClientInformation)
10387 NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorGeolocation)
10388 NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorDesktopNotification)
10389 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
10390 NS_INTERFACE_MAP_END
10393 NS_IMPL_ADDREF(nsNavigator)
10394 NS_IMPL_RELEASE(nsNavigator)
10397 void
10398 nsNavigator::SetDocShell(nsIDocShell *aDocShell)
10400 mDocShell = aDocShell;
10401 if (mPlugins)
10402 mPlugins->SetDocShell(aDocShell);
10404 // if there is a page transition, make sure delete the geolocation object
10405 if (mGeolocation)
10407 mGeolocation->Shutdown();
10408 mGeolocation = nsnull;
10411 if (mNotification)
10413 mNotification->Shutdown();
10414 mNotification = nsnull;
10418 //*****************************************************************************
10419 // nsNavigator::nsIDOMNavigator
10420 //*****************************************************************************
10422 nsresult
10423 NS_GetNavigatorUserAgent(nsAString& aUserAgent)
10425 nsresult rv;
10426 nsCOMPtr<nsIHttpProtocolHandler>
10427 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10428 if (NS_SUCCEEDED(rv)) {
10429 nsCAutoString ua;
10430 rv = service->GetUserAgent(ua);
10431 CopyASCIItoUTF16(ua, aUserAgent);
10434 return rv;
10437 nsresult
10438 NS_GetNavigatorPlatform(nsAString& aPlatform)
10440 if (!nsContentUtils::IsCallerTrustedForRead()) {
10441 const nsAdoptingCString& override =
10442 nsContentUtils::GetCharPref("general.platform.override");
10444 if (override) {
10445 CopyUTF8toUTF16(override, aPlatform);
10446 return NS_OK;
10450 nsresult rv;
10451 nsCOMPtr<nsIHttpProtocolHandler>
10452 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10453 if (NS_SUCCEEDED(rv)) {
10454 // sorry for the #if platform ugliness, but Communicator is
10455 // likewise hardcoded and we're seeking backward compatibility
10456 // here (bug 47080)
10457 #if defined(_WIN64)
10458 aPlatform.AssignLiteral("Win64");
10459 #elif defined(WIN32)
10460 aPlatform.AssignLiteral("Win32");
10461 #elif defined(XP_MACOSX) && defined(__ppc__)
10462 aPlatform.AssignLiteral("MacPPC");
10463 #elif defined(XP_MACOSX) && defined(__i386__)
10464 aPlatform.AssignLiteral("MacIntel");
10465 #elif defined(XP_MACOSX) && defined(__x86_64__)
10466 aPlatform.AssignLiteral("MacIntel");
10467 #elif defined(XP_OS2)
10468 aPlatform.AssignLiteral("OS/2");
10469 #else
10470 // XXX Communicator uses compiled-in build-time string defines
10471 // to indicate the platform it was compiled *for*, not what it is
10472 // currently running *on* which is what this does.
10473 nsCAutoString plat;
10474 rv = service->GetOscpu(plat);
10475 CopyASCIItoUTF16(plat, aPlatform);
10476 #endif
10479 return rv;
10481 nsresult
10482 NS_GetNavigatorAppVersion(nsAString& aAppVersion)
10484 if (!nsContentUtils::IsCallerTrustedForRead()) {
10485 const nsAdoptingCString& override =
10486 nsContentUtils::GetCharPref("general.appversion.override");
10488 if (override) {
10489 CopyUTF8toUTF16(override, aAppVersion);
10490 return NS_OK;
10494 nsresult rv;
10495 nsCOMPtr<nsIHttpProtocolHandler>
10496 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10497 if (NS_SUCCEEDED(rv)) {
10498 nsCAutoString str;
10499 rv = service->GetAppVersion(str);
10500 CopyASCIItoUTF16(str, aAppVersion);
10501 if (NS_FAILED(rv))
10502 return rv;
10504 aAppVersion.AppendLiteral(" (");
10506 rv = service->GetPlatform(str);
10507 if (NS_FAILED(rv))
10508 return rv;
10510 AppendASCIItoUTF16(str, aAppVersion);
10512 aAppVersion.Append(PRUnichar(')'));
10515 return rv;
10518 nsresult
10519 NS_GetNavigatorAppName(nsAString& aAppName)
10521 if (!nsContentUtils::IsCallerTrustedForRead()) {
10522 const nsAdoptingCString& override =
10523 nsContentUtils::GetCharPref("general.appname.override");
10525 if (override) {
10526 CopyUTF8toUTF16(override, aAppName);
10527 return NS_OK;
10531 aAppName.AssignLiteral("Netscape");
10532 return NS_OK;
10535 NS_IMETHODIMP
10536 nsNavigator::GetUserAgent(nsAString& aUserAgent)
10538 return NS_GetNavigatorUserAgent(aUserAgent);
10541 NS_IMETHODIMP
10542 nsNavigator::GetAppCodeName(nsAString& aAppCodeName)
10544 nsresult rv;
10545 nsCOMPtr<nsIHttpProtocolHandler>
10546 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10547 if (NS_SUCCEEDED(rv)) {
10548 nsCAutoString appName;
10549 rv = service->GetAppName(appName);
10550 CopyASCIItoUTF16(appName, aAppCodeName);
10553 return rv;
10556 NS_IMETHODIMP
10557 nsNavigator::GetAppVersion(nsAString& aAppVersion)
10559 return NS_GetNavigatorAppVersion(aAppVersion);
10562 NS_IMETHODIMP
10563 nsNavigator::GetAppName(nsAString& aAppName)
10565 return NS_GetNavigatorAppName(aAppName);
10568 NS_IMETHODIMP
10569 nsNavigator::GetLanguage(nsAString& aLanguage)
10571 nsresult rv;
10572 nsCOMPtr<nsIHttpProtocolHandler>
10573 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10574 if (NS_SUCCEEDED(rv)) {
10575 nsCAutoString lang;
10576 rv = service->GetLanguage(lang);
10577 CopyASCIItoUTF16(lang, aLanguage);
10580 return rv;
10583 NS_IMETHODIMP
10584 nsNavigator::GetPlatform(nsAString& aPlatform)
10586 return NS_GetNavigatorPlatform(aPlatform);
10589 NS_IMETHODIMP
10590 nsNavigator::GetOscpu(nsAString& aOSCPU)
10592 if (!nsContentUtils::IsCallerTrustedForRead()) {
10593 const nsAdoptingCString& override =
10594 nsContentUtils::GetCharPref("general.oscpu.override");
10596 if (override) {
10597 CopyUTF8toUTF16(override, aOSCPU);
10598 return NS_OK;
10602 nsresult rv;
10603 nsCOMPtr<nsIHttpProtocolHandler>
10604 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10605 if (NS_SUCCEEDED(rv)) {
10606 nsCAutoString oscpu;
10607 rv = service->GetOscpu(oscpu);
10608 CopyASCIItoUTF16(oscpu, aOSCPU);
10611 return rv;
10614 NS_IMETHODIMP
10615 nsNavigator::GetVendor(nsAString& aVendor)
10617 aVendor.Truncate();
10618 return NS_OK;
10622 NS_IMETHODIMP
10623 nsNavigator::GetVendorSub(nsAString& aVendorSub)
10625 aVendorSub.Truncate();
10626 return NS_OK;
10629 NS_IMETHODIMP
10630 nsNavigator::GetProduct(nsAString& aProduct)
10632 nsresult rv;
10633 nsCOMPtr<nsIHttpProtocolHandler>
10634 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10635 if (NS_SUCCEEDED(rv)) {
10636 nsCAutoString product;
10637 rv = service->GetProduct(product);
10638 CopyASCIItoUTF16(product, aProduct);
10641 return rv;
10644 NS_IMETHODIMP
10645 nsNavigator::GetProductSub(nsAString& aProductSub)
10647 if (!nsContentUtils::IsCallerTrustedForRead()) {
10648 const nsAdoptingCString& override =
10649 nsContentUtils::GetCharPref("general.productSub.override");
10651 if (override) {
10652 CopyUTF8toUTF16(override, aProductSub);
10653 return NS_OK;
10654 } else {
10655 // 'general.useragent.productSub' backwards compatible with 1.8 branch.
10656 const nsAdoptingCString& override2 =
10657 nsContentUtils::GetCharPref("general.useragent.productSub");
10659 if (override2) {
10660 CopyUTF8toUTF16(override2, aProductSub);
10661 return NS_OK;
10666 nsresult rv;
10667 nsCOMPtr<nsIHttpProtocolHandler>
10668 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10669 if (NS_SUCCEEDED(rv)) {
10670 nsCAutoString productSub;
10671 rv = service->GetProductSub(productSub);
10672 CopyASCIItoUTF16(productSub, aProductSub);
10675 return rv;
10678 NS_IMETHODIMP
10679 nsNavigator::GetSecurityPolicy(nsAString& aSecurityPolicy)
10681 return NS_OK;
10684 NS_IMETHODIMP
10685 nsNavigator::GetMimeTypes(nsIDOMMimeTypeArray **aMimeTypes)
10687 if (!mMimeTypes) {
10688 mMimeTypes = new nsMimeTypeArray(this);
10689 if (!mMimeTypes) {
10690 return NS_ERROR_OUT_OF_MEMORY;
10694 NS_ADDREF(*aMimeTypes = mMimeTypes);
10696 return NS_OK;
10699 NS_IMETHODIMP
10700 nsNavigator::GetPlugins(nsIDOMPluginArray **aPlugins)
10702 if (!mPlugins) {
10703 mPlugins = new nsPluginArray(this, mDocShell);
10704 if (!mPlugins) {
10705 return NS_ERROR_OUT_OF_MEMORY;
10709 NS_ADDREF(*aPlugins = mPlugins);
10711 return NS_OK;
10714 // values for the network.cookie.cookieBehavior pref are documented in
10715 // nsCookieService.cpp.
10716 #define COOKIE_BEHAVIOR_REJECT 2
10718 NS_IMETHODIMP
10719 nsNavigator::GetCookieEnabled(PRBool *aCookieEnabled)
10721 *aCookieEnabled =
10722 (nsContentUtils::GetIntPref("network.cookie.cookieBehavior",
10723 COOKIE_BEHAVIOR_REJECT) !=
10724 COOKIE_BEHAVIOR_REJECT);
10726 return NS_OK;
10729 NS_IMETHODIMP
10730 nsNavigator::GetOnLine(PRBool* aOnline)
10732 NS_PRECONDITION(aOnline, "Null out param");
10734 *aOnline = !NS_IsOffline();
10735 return NS_OK;
10738 NS_IMETHODIMP
10739 nsNavigator::GetBuildID(nsAString& aBuildID)
10741 if (!nsContentUtils::IsCallerTrustedForRead()) {
10742 const nsAdoptingCString& override =
10743 nsContentUtils::GetCharPref("general.buildID.override");
10745 if (override) {
10746 CopyUTF8toUTF16(override, aBuildID);
10747 return NS_OK;
10751 nsCOMPtr<nsIXULAppInfo> appInfo =
10752 do_GetService("@mozilla.org/xre/app-info;1");
10753 if (!appInfo)
10754 return NS_ERROR_NOT_IMPLEMENTED;
10756 nsCAutoString buildID;
10757 nsresult rv = appInfo->GetAppBuildID(buildID);
10758 if (NS_FAILED(rv))
10759 return rv;
10761 aBuildID.Truncate();
10762 AppendASCIItoUTF16(buildID, aBuildID);
10763 return NS_OK;
10766 NS_IMETHODIMP
10767 nsNavigator::JavaEnabled(PRBool *aReturn)
10769 // Return true if we have a handler for "application/x-java-vm",
10770 // otherwise return false.
10771 *aReturn = PR_FALSE;
10773 if (!mMimeTypes) {
10774 mMimeTypes = new nsMimeTypeArray(this);
10775 if (!mMimeTypes)
10776 return NS_ERROR_OUT_OF_MEMORY;
10779 RefreshMIMEArray();
10781 PRUint32 count;
10782 mMimeTypes->GetLength(&count);
10783 for (PRUint32 i = 0; i < count; i++) {
10784 nsresult rv;
10785 nsIDOMMimeType* type = mMimeTypes->GetItemAt(i, &rv);
10786 nsAutoString mimeString;
10787 if (type && NS_SUCCEEDED(type->GetType(mimeString))) {
10788 if (mimeString.EqualsLiteral("application/x-java-vm")) {
10789 *aReturn = PR_TRUE;
10790 break;
10795 return NS_OK;
10798 NS_IMETHODIMP
10799 nsNavigator::TaintEnabled(PRBool *aReturn)
10801 *aReturn = PR_FALSE;
10802 return NS_OK;
10805 void
10806 nsNavigator::LoadingNewDocument()
10808 // Release these so that they will be recreated for the
10809 // new document (if requested). The plugins or mime types
10810 // arrays may have changed. See bug 150087.
10811 if (mMimeTypes) {
10812 mMimeTypes->Invalidate();
10813 mMimeTypes = nsnull;
10816 if (mPlugins) {
10817 mPlugins->Invalidate();
10818 mPlugins = nsnull;
10821 if (mGeolocation)
10823 mGeolocation->Shutdown();
10824 mGeolocation = nsnull;
10827 if (mNotification)
10829 mNotification->Shutdown();
10830 mNotification = nsnull;
10835 nsresult
10836 nsNavigator::RefreshMIMEArray()
10838 nsresult rv = NS_OK;
10839 if (mMimeTypes)
10840 rv = mMimeTypes->Refresh();
10841 return rv;
10844 bool
10845 nsNavigator::HasDesktopNotificationSupport()
10847 return nsContentUtils::GetBoolPref("notification.feature.enabled", PR_FALSE);
10850 //*****************************************************************************
10851 // nsNavigator::nsIDOMClientInformation
10852 //*****************************************************************************
10854 NS_IMETHODIMP
10855 nsNavigator::RegisterContentHandler(const nsAString& aMIMEType,
10856 const nsAString& aURI,
10857 const nsAString& aTitle)
10859 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
10860 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
10861 if (registrar && mDocShell) {
10862 nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
10863 if (contentDOMWindow)
10864 return registrar->RegisterContentHandler(aMIMEType, aURI, aTitle,
10865 contentDOMWindow);
10868 return NS_OK;
10871 NS_IMETHODIMP
10872 nsNavigator::RegisterProtocolHandler(const nsAString& aProtocol,
10873 const nsAString& aURI,
10874 const nsAString& aTitle)
10876 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
10877 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
10878 if (registrar && mDocShell) {
10879 nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
10880 if (contentDOMWindow)
10881 return registrar->RegisterProtocolHandler(aProtocol, aURI, aTitle,
10882 contentDOMWindow);
10885 return NS_OK;
10889 NS_IMETHODIMP
10890 nsNavigator::MozIsLocallyAvailable(const nsAString &aURI,
10891 PRBool aWhenOffline,
10892 PRBool *aIsAvailable)
10894 nsCOMPtr<nsIURI> uri;
10895 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI);
10896 NS_ENSURE_SUCCESS(rv, rv);
10898 // This method of checking the cache will only work for http/https urls
10899 PRBool match;
10900 rv = uri->SchemeIs("http", &match);
10901 NS_ENSURE_SUCCESS(rv, rv);
10902 if (!match) {
10903 rv = uri->SchemeIs("https", &match);
10904 NS_ENSURE_SUCCESS(rv, rv);
10905 if (!match) return NS_ERROR_DOM_BAD_URI;
10908 // Same origin check
10909 nsCOMPtr<nsIJSContextStack> stack = do_GetService(sJSStackContractID);
10910 NS_ENSURE_TRUE(stack, NS_ERROR_FAILURE);
10912 JSContext *cx = nsnull;
10913 rv = stack->Peek(&cx);
10914 NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
10916 rv = nsContentUtils::GetSecurityManager()->CheckSameOrigin(cx, uri);
10917 NS_ENSURE_SUCCESS(rv, rv);
10919 // these load flags cause an error to be thrown if there is no
10920 // valid cache entry, and skip the load if there is.
10921 // if the cache is busy, assume that it is not yet available rather
10922 // than waiting for it to become available.
10923 PRUint32 loadFlags = nsIChannel::INHIBIT_CACHING |
10924 nsICachingChannel::LOAD_NO_NETWORK_IO |
10925 nsICachingChannel::LOAD_ONLY_IF_MODIFIED |
10926 nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY;
10928 if (aWhenOffline) {
10929 loadFlags |= nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE |
10930 nsICachingChannel::LOAD_ONLY_FROM_CACHE |
10931 nsIRequest::LOAD_FROM_CACHE;
10934 nsCOMPtr<nsIChannel> channel;
10935 rv = NS_NewChannel(getter_AddRefs(channel), uri,
10936 nsnull, nsnull, nsnull, loadFlags);
10937 NS_ENSURE_SUCCESS(rv, rv);
10939 nsCOMPtr<nsIInputStream> stream;
10940 rv = channel->Open(getter_AddRefs(stream));
10941 NS_ENSURE_SUCCESS(rv, rv);
10943 stream->Close();
10945 nsresult status;
10946 rv = channel->GetStatus(&status);
10947 NS_ENSURE_SUCCESS(rv, rv);
10949 if (NS_SUCCEEDED(status)) {
10950 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
10951 rv = httpChannel->GetRequestSucceeded(aIsAvailable);
10952 NS_ENSURE_SUCCESS(rv, rv);
10953 } else {
10954 *aIsAvailable = PR_FALSE;
10957 return NS_OK;
10960 //*****************************************************************************
10961 // nsNavigator::nsIDOMNavigatorGeolocation
10962 //*****************************************************************************
10964 NS_IMETHODIMP nsNavigator::GetGeolocation(nsIDOMGeoGeolocation **_retval)
10966 NS_ENSURE_ARG_POINTER(_retval);
10967 *_retval = nsnull;
10969 if (mGeolocation) {
10970 NS_ADDREF(*_retval = mGeolocation);
10971 return NS_OK;
10974 if (!mDocShell)
10975 return NS_ERROR_FAILURE;
10977 nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
10978 if (!contentDOMWindow)
10979 return NS_ERROR_FAILURE;
10981 mGeolocation = new nsGeolocation();
10982 if (!mGeolocation)
10983 return NS_ERROR_FAILURE;
10985 if (NS_FAILED(mGeolocation->Init(contentDOMWindow)))
10986 return NS_ERROR_FAILURE;
10988 NS_ADDREF(*_retval = mGeolocation);
10989 return NS_OK;
10993 //*****************************************************************************
10994 // nsNavigator::nsIDOMNavigatorDesktopNotification
10995 //*****************************************************************************
10997 NS_IMETHODIMP nsNavigator::GetMozNotification(nsIDOMDesktopNotificationCenter **aRetVal)
10999 NS_ENSURE_ARG_POINTER(aRetVal);
11000 *aRetVal = nsnull;
11002 if (mNotification) {
11003 NS_ADDREF(*aRetVal = mNotification);
11004 return NS_OK;
11007 nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(mDocShell));
11008 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
11010 nsCOMPtr<nsIDocument> document = do_GetInterface(mDocShell);
11011 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
11013 nsIScriptGlobalObject *sgo = document->GetScopeObject();
11014 NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
11016 nsIScriptContext *scx = sgo->GetContext();
11017 NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
11019 mNotification = new nsDesktopNotificationCenter(window->GetCurrentInnerWindow(),
11020 scx);
11021 if (!mNotification) {
11022 return NS_ERROR_FAILURE;
11025 NS_ADDREF(*aRetVal = mNotification);
11026 return NS_OK;