Bug 618017: Encountering XML should not override the version. (r=lw)
[mozilla-central.git] / dom / base / nsGlobalWindow.cpp
blob2ee2fb1f5c55c9d339c98441263f1dfd23f7ae00
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"
70 // Other Classes
71 #include "nsIEventListenerManager.h"
72 #include "nsEscape.h"
73 #include "nsStyleCoord.h"
74 #include "nsMimeTypeArray.h"
75 #include "nsNetUtil.h"
76 #include "nsICachingChannel.h"
77 #include "nsPluginArray.h"
78 #include "nsIPluginHost.h"
79 #include "nsGeolocation.h"
80 #include "nsDesktopNotification.h"
81 #include "nsContentCID.h"
82 #include "nsLayoutStatics.h"
83 #include "nsCycleCollector.h"
84 #include "nsCCUncollectableMarker.h"
85 #include "nsDOMThreadService.h"
86 #include "nsAutoJSValHolder.h"
88 // Interfaces Needed
89 #include "nsIFrame.h"
90 #include "nsCanvasFrame.h"
91 #include "nsIWidget.h"
92 #include "nsIBaseWindow.h"
93 #include "nsAccelerometer.h"
94 #include "nsIContent.h"
95 #include "nsIContentViewerEdit.h"
96 #include "nsIDocShell.h"
97 #include "nsIDocShellLoadInfo.h"
98 #include "nsIDocShellTreeItem.h"
99 #include "nsIDocShellTreeNode.h"
100 #include "nsIEditorDocShell.h"
101 #include "nsIDocCharset.h"
102 #include "nsIDocument.h"
103 #include "nsIHTMLDocument.h"
104 #include "nsIDOMHTMLDocument.h"
105 #include "nsIDOMHTMLElement.h"
106 #ifndef MOZ_DISABLE_DOMCRYPTO
107 #include "nsIDOMCrypto.h"
108 #endif
109 #include "nsIDOMDocument.h"
110 #include "nsIDOM3Document.h"
111 #include "nsIDOMNSDocument.h"
112 #include "nsIDOMDocumentView.h"
113 #include "nsIDOMElement.h"
114 #include "nsIDOMDocumentEvent.h"
115 #include "nsIDOMEvent.h"
116 #include "nsIDOMHTMLAnchorElement.h"
117 #include "nsIDOMKeyEvent.h"
118 #include "nsIDOMMessageEvent.h"
119 #include "nsIDOMPopupBlockedEvent.h"
120 #include "nsIDOMPopStateEvent.h"
121 #include "nsIDOMOfflineResourceList.h"
122 #include "nsIDOMGeoGeolocation.h"
123 #include "nsIDOMDesktopNotification.h"
124 #include "nsPIDOMStorage.h"
125 #include "nsDOMString.h"
126 #include "nsIEmbeddingSiteWindow2.h"
127 #include "nsThreadUtils.h"
128 #include "nsIEventStateManager.h"
129 #include "nsIHttpProtocolHandler.h"
130 #include "nsIJSContextStack.h"
131 #include "nsIJSRuntimeService.h"
132 #include "nsIMarkupDocumentViewer.h"
133 #include "nsIPrefBranch.h"
134 #include "nsIPresShell.h"
135 #include "nsIPrivateDOMEvent.h"
136 #include "nsIProgrammingLanguage.h"
137 #include "nsIServiceManager.h"
138 #include "nsIScriptGlobalObjectOwner.h"
139 #include "nsIScriptSecurityManager.h"
140 #include "nsIScrollableFrame.h"
141 #include "nsIView.h"
142 #include "nsIViewManager.h"
143 #include "nsISelectionController.h"
144 #include "nsISelection.h"
145 #include "nsIPrompt.h"
146 #include "nsIPromptService.h"
147 #include "nsIPromptFactory.h"
148 #include "nsIWritablePropertyBag2.h"
149 #include "nsIWebNavigation.h"
150 #include "nsIWebBrowser.h"
151 #include "nsIWebBrowserChrome.h"
152 #include "nsIWebBrowserFind.h" // For window.find()
153 #include "nsIWebContentHandlerRegistrar.h"
154 #include "nsIWindowMediator.h" // For window.find()
155 #include "nsComputedDOMStyle.h"
156 #include "nsIEntropyCollector.h"
157 #include "nsDOMCID.h"
158 #include "nsDOMError.h"
159 #include "nsDOMWindowUtils.h"
160 #include "nsIWindowWatcher.h"
161 #include "nsPIWindowWatcher.h"
162 #include "nsIContentViewer.h"
163 #include "nsDOMClassInfo.h"
164 #include "nsIJSNativeInitializer.h"
165 #include "nsIScriptError.h"
166 #include "nsIScriptEventManager.h" // For GetInterface()
167 #include "nsIConsoleService.h"
168 #include "nsIControllers.h"
169 #include "nsIControllerContext.h"
170 #include "nsGlobalWindowCommands.h"
171 #include "nsAutoPtr.h"
172 #include "nsContentUtils.h"
173 #include "nsCSSProps.h"
174 #include "nsFileDataProtocolHandler.h"
175 #include "nsIDOMFile.h"
176 #include "nsIURIFixup.h"
177 #include "mozilla/FunctionTimer.h"
178 #include "nsCDefaultURIFixup.h"
179 #include "nsEventDispatcher.h"
180 #include "nsIObserverService.h"
181 #include "nsIXULAppInfo.h"
182 #include "nsNetUtil.h"
183 #include "nsFocusManager.h"
184 #include "nsIJSON.h"
185 #include "nsIXULWindow.h"
186 #include "nsEventStateManager.h"
187 #ifdef MOZ_XUL
188 #include "nsXULPopupManager.h"
189 #include "nsIDOMXULControlElement.h"
190 #include "nsIFrame.h"
191 #endif
193 #include "xpcprivate.h"
195 #ifdef NS_PRINTING
196 #include "nsIPrintSettings.h"
197 #include "nsIPrintSettingsService.h"
198 #include "nsIWebBrowserPrint.h"
199 #endif
201 #include "nsWindowRoot.h"
202 #include "nsNetCID.h"
203 #include "nsIArray.h"
204 #include "nsIScriptRuntime.h"
206 // XXX An unfortunate dependency exists here (two XUL files).
207 #include "nsIDOMXULDocument.h"
208 #include "nsIDOMXULCommandDispatcher.h"
210 #include "nsBindingManager.h"
211 #include "nsIXBLService.h"
213 // used for popup blocking, needs to be converted to something
214 // belonging to the back-end like nsIContentPolicy
215 #include "nsIPopupWindowManager.h"
217 #include "nsIDragService.h"
218 #include "mozilla/dom/Element.h"
219 #include "nsFrameLoader.h"
220 #include "nsISupportsPrimitives.h"
221 #include "nsXPCOMCID.h"
223 #include "mozilla/FunctionTimer.h"
224 #include "mozIThirdPartyUtil.h"
226 #ifdef MOZ_LOGGING
227 // so we can get logging even in release builds
228 #define FORCE_PR_LOG 1
229 #endif
230 #include "prlog.h"
232 #include "mozilla/dom/indexedDB/IDBFactory.h"
233 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
235 #include "nsRefreshDriver.h"
237 #ifdef PR_LOGGING
238 static PRLogModuleInfo* gDOMLeakPRLog;
239 #endif
241 static const char kStorageEnabled[] = "dom.storage.enabled";
243 using namespace mozilla::dom;
244 using mozilla::TimeStamp;
245 using mozilla::TimeDuration;
247 nsIDOMStorageList *nsGlobalWindow::sGlobalStorageList = nsnull;
248 nsGlobalWindow::WindowByIdTable *nsGlobalWindow::sOuterWindowsById = nsnull;
250 static nsIEntropyCollector *gEntropyCollector = nsnull;
251 static PRInt32 gRefCnt = 0;
252 static PRInt32 gOpenPopupSpamCount = 0;
253 static PopupControlState gPopupControlState = openAbused;
254 static PRInt32 gRunningTimeoutDepth = 0;
255 static PRPackedBool gMouseDown = PR_FALSE;
256 static PRPackedBool gDragServiceDisabled = PR_FALSE;
257 static FILE *gDumpFile = nsnull;
258 static PRUint64 gNextWindowID = 0;
259 static PRUint32 gSerialCounter = 0;
261 #ifdef DEBUG_jst
262 PRInt32 gTimeoutCnt = 0;
263 #endif
265 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
266 static PRBool gDOMWindowDumpEnabled = PR_FALSE;
267 #endif
269 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
270 #define DEBUG_PAGE_CACHE
271 #endif
273 // The default shortest interval/timeout we permit
274 #define DEFAULT_MIN_TIMEOUT_VALUE 10 // 10ms
275 static PRInt32 gMinTimeoutValue;
276 static inline PRInt32 DOMMinTimeoutValue() {
277 return NS_MAX(gMinTimeoutValue, 0);
280 // The number of nested timeouts before we start clamping. HTML5 says 1, WebKit
281 // uses 5.
282 #define DOM_CLAMP_TIMEOUT_NESTING_LEVEL 5
284 // The longest interval (as PRIntervalTime) we permit, or that our
285 // timer code can handle, really. See DELAY_INTERVAL_LIMIT in
286 // nsTimerImpl.h for details.
287 #define DOM_MAX_TIMEOUT_VALUE PR_BIT(8 * sizeof(PRIntervalTime) - 1)
289 #define FORWARD_TO_OUTER(method, args, err_rval) \
290 PR_BEGIN_MACRO \
291 if (IsInnerWindow()) { \
292 nsGlobalWindow *outer = GetOuterWindowInternal(); \
293 if (!outer) { \
294 NS_WARNING("No outer window available!"); \
295 return err_rval; \
297 return outer->method args; \
299 PR_END_MACRO
301 #define FORWARD_TO_OUTER_VOID(method, args) \
302 PR_BEGIN_MACRO \
303 if (IsInnerWindow()) { \
304 nsGlobalWindow *outer = GetOuterWindowInternal(); \
305 if (!outer) { \
306 NS_WARNING("No outer window available!"); \
307 return; \
309 outer->method args; \
310 return; \
312 PR_END_MACRO
314 #define FORWARD_TO_OUTER_CHROME(method, args, err_rval) \
315 PR_BEGIN_MACRO \
316 if (IsInnerWindow()) { \
317 nsGlobalWindow *outer = GetOuterWindowInternal(); \
318 if (!outer) { \
319 NS_WARNING("No outer window available!"); \
320 return err_rval; \
322 return ((nsGlobalChromeWindow *)outer)->method args; \
324 PR_END_MACRO
326 #define FORWARD_TO_INNER_CHROME(method, args, err_rval) \
327 PR_BEGIN_MACRO \
328 if (IsOuterWindow()) { \
329 if (!mInnerWindow) { \
330 NS_WARNING("No inner window available!"); \
331 return err_rval; \
333 return ((nsGlobalChromeWindow *)mInnerWindow)->method args; \
335 PR_END_MACRO
337 #define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
338 PR_BEGIN_MACRO \
339 if (IsInnerWindow()) { \
340 nsGlobalWindow *outer = GetOuterWindowInternal(); \
341 if (!outer) { \
342 NS_WARNING("No outer window available!"); \
343 return err_rval; \
345 return ((nsGlobalModalWindow *)outer)->method args; \
347 PR_END_MACRO
349 #define FORWARD_TO_INNER(method, args, err_rval) \
350 PR_BEGIN_MACRO \
351 if (IsOuterWindow()) { \
352 if (!mInnerWindow) { \
353 NS_WARNING("No inner window available!"); \
354 return err_rval; \
356 return GetCurrentInnerWindowInternal()->method args; \
358 PR_END_MACRO
360 #define FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
361 PR_BEGIN_MACRO \
362 if (IsOuterWindow()) { \
363 if (!mInnerWindow) { \
364 NS_WARNING("No inner window available!"); \
365 return err_rval; \
367 return ((nsGlobalModalWindow*)GetCurrentInnerWindowInternal())->method args; \
369 PR_END_MACRO
371 #define FORWARD_TO_INNER_VOID(method, args) \
372 PR_BEGIN_MACRO \
373 if (IsOuterWindow()) { \
374 if (!mInnerWindow) { \
375 NS_WARNING("No inner window available!"); \
376 return; \
378 GetCurrentInnerWindowInternal()->method args; \
379 return; \
381 PR_END_MACRO
383 // Same as FORWARD_TO_INNER, but this will create a fresh inner if an
384 // inner doesn't already exists.
385 #define FORWARD_TO_INNER_CREATE(method, args, err_rval) \
386 PR_BEGIN_MACRO \
387 if (IsOuterWindow()) { \
388 if (!mInnerWindow) { \
389 if (mIsClosed) { \
390 return err_rval; \
392 nsCOMPtr<nsIDOMDocument> doc; \
393 nsresult fwdic_nr = GetDocument(getter_AddRefs(doc)); \
394 NS_ENSURE_SUCCESS(fwdic_nr, err_rval); \
395 if (!mInnerWindow) { \
396 return err_rval; \
399 return GetCurrentInnerWindowInternal()->method args; \
401 PR_END_MACRO
403 // CIDs
404 static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
406 static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
407 #ifndef MOZ_DISABLE_DOMCRYPTO
408 static const char kCryptoContractID[] = NS_CRYPTO_CONTRACTID;
409 static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID;
410 #endif
411 static const char sPopStatePrefStr[] = "browser.history.allowPopState";
413 static PRBool
414 IsAboutBlank(nsIURI* aURI)
416 NS_PRECONDITION(aURI, "Must have URI");
418 // GetSpec can be expensive for some URIs, so check the scheme first.
419 PRBool isAbout = PR_FALSE;
420 if (NS_FAILED(aURI->SchemeIs("about", &isAbout)) || !isAbout) {
421 return PR_FALSE;
424 nsCAutoString str;
425 aURI->GetSpec(str);
426 return str.EqualsLiteral("about:blank");
429 class nsDummyJavaPluginOwner : public nsIPluginInstanceOwner
431 public:
432 nsDummyJavaPluginOwner(nsIDocument *aDocument)
433 : mDocument(aDocument)
437 void Destroy();
439 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
440 NS_DECL_NSIPLUGININSTANCEOWNER
442 NS_IMETHOD GetURL(const char *aURL, const char *aTarget,
443 nsIInputStream *aPostStream,
444 void *aHeadersData, PRUint32 aHeadersDataLen);
445 NS_IMETHOD ShowStatus(const PRUnichar *aStatusMsg);
446 NPError ShowNativeContextMenu(NPMenu* menu, void* event);
447 NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
448 double *destX, double *destY, NPCoordinateSpace destSpace);
449 void SendIdleEvent();
451 NS_DECL_CYCLE_COLLECTION_CLASS(nsDummyJavaPluginOwner)
453 private:
454 nsCOMPtr<nsIPluginInstance> mInstance;
455 nsCOMPtr<nsIDocument> mDocument;
458 NS_IMPL_CYCLE_COLLECTION_2(nsDummyJavaPluginOwner, mDocument, mInstance)
460 // QueryInterface implementation for nsDummyJavaPluginOwner
461 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDummyJavaPluginOwner)
462 NS_INTERFACE_MAP_ENTRY(nsISupports)
463 NS_INTERFACE_MAP_ENTRY(nsIPluginInstanceOwner)
464 NS_INTERFACE_MAP_END
466 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDummyJavaPluginOwner)
467 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDummyJavaPluginOwner)
470 void
471 nsDummyJavaPluginOwner::Destroy()
473 // If we have a plugin instance, stop it and destroy it now.
474 if (mInstance) {
475 mInstance->Stop();
476 mInstance->InvalidateOwner();
477 mInstance = nsnull;
480 mDocument = nsnull;
483 NS_IMETHODIMP
484 nsDummyJavaPluginOwner::SetInstance(nsIPluginInstance *aInstance)
486 // If we're going to null out mInstance after use, be sure to call
487 // mInstance->InvalidateOwner() here, since it now won't be called
488 // from nsDummyJavaPluginOwner::Destroy().
489 if (mInstance && !aInstance)
490 mInstance->InvalidateOwner();
492 mInstance = aInstance;
494 return NS_OK;
497 NS_IMETHODIMP
498 nsDummyJavaPluginOwner::GetInstance(nsIPluginInstance *&aInstance)
500 NS_IF_ADDREF(aInstance = mInstance);
502 return NS_OK;
505 NS_IMETHODIMP
506 nsDummyJavaPluginOwner::GetWindow(NPWindow *&aWindow)
508 aWindow = nsnull;
510 return NS_OK;
513 NS_IMETHODIMP
514 nsDummyJavaPluginOwner::GetMode(PRInt32 *aMode)
516 // This is wrong, but there's no better alternative.
517 *aMode = NP_EMBED;
519 return NS_ERROR_NOT_IMPLEMENTED;
522 NS_IMETHODIMP
523 nsDummyJavaPluginOwner::CreateWidget(void)
525 return NS_ERROR_NOT_IMPLEMENTED;
528 NS_IMETHODIMP
529 nsDummyJavaPluginOwner::GetURL(const char *aURL, const char *aTarget,
530 nsIInputStream *aPostStream,
531 void *aHeadersData, PRUint32 aHeadersDataLen)
533 return NS_ERROR_NOT_IMPLEMENTED;
536 NS_IMETHODIMP
537 nsDummyJavaPluginOwner::ShowStatus(const char *aStatusMsg)
539 return NS_ERROR_NOT_IMPLEMENTED;
542 NS_IMETHODIMP
543 nsDummyJavaPluginOwner::ShowStatus(const PRUnichar *aStatusMsg)
545 return NS_ERROR_NOT_IMPLEMENTED;
548 NPError
549 nsDummyJavaPluginOwner::ShowNativeContextMenu(NPMenu* menu, void* event)
551 return NPERR_GENERIC_ERROR;
554 NPBool
555 nsDummyJavaPluginOwner::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
556 double *destX, double *destY, NPCoordinateSpace destSpace)
558 return PR_FALSE;
561 NS_IMETHODIMP
562 nsDummyJavaPluginOwner::GetDocument(nsIDocument **aDocument)
564 NS_IF_ADDREF(*aDocument = mDocument);
566 return NS_OK;
569 NS_IMETHODIMP
570 nsDummyJavaPluginOwner::InvalidateRect(NPRect *invalidRect)
572 return NS_ERROR_NOT_IMPLEMENTED;
575 NS_IMETHODIMP
576 nsDummyJavaPluginOwner::InvalidateRegion(NPRegion invalidRegion)
578 return NS_ERROR_NOT_IMPLEMENTED;
581 NS_IMETHODIMP
582 nsDummyJavaPluginOwner::ForceRedraw()
584 return NS_ERROR_NOT_IMPLEMENTED;
587 NS_IMETHODIMP
588 nsDummyJavaPluginOwner::GetNetscapeWindow(void *value)
590 return NS_ERROR_NOT_IMPLEMENTED;
593 NS_IMETHODIMP
594 nsDummyJavaPluginOwner::SetEventModel(PRInt32 eventModel)
596 return NS_ERROR_NOT_IMPLEMENTED;
599 void
600 nsDummyJavaPluginOwner::SendIdleEvent()
605 * An object implementing the window.URL property.
607 class nsDOMMozURLProperty : public nsIDOMMozURLProperty
609 public:
610 nsDOMMozURLProperty(nsGlobalWindow* aWindow)
611 : mWindow(aWindow)
615 NS_DECL_ISUPPORTS
616 NS_DECL_NSIDOMMOZURLPROPERTY
618 void ClearWindowReference() {
619 mWindow = nsnull;
621 private:
622 nsGlobalWindow* mWindow;
625 DOMCI_DATA(MozURLProperty, nsDOMMozURLProperty)
626 NS_IMPL_ADDREF(nsDOMMozURLProperty)
627 NS_IMPL_RELEASE(nsDOMMozURLProperty)
628 NS_INTERFACE_MAP_BEGIN(nsDOMMozURLProperty)
629 NS_INTERFACE_MAP_ENTRY(nsIDOMMozURLProperty)
630 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozURLProperty)
631 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozURLProperty)
632 NS_INTERFACE_MAP_END
634 NS_IMETHODIMP
635 nsDOMMozURLProperty::CreateObjectURL(nsIDOMBlob* aBlob, nsAString& aURL)
637 NS_PRECONDITION(!mWindow || mWindow->IsInnerWindow(),
638 "Should be inner window");
640 NS_ENSURE_STATE(mWindow && mWindow->mDoc);
641 NS_ENSURE_ARG_POINTER(aBlob);
643 nsIDocument* doc = mWindow->mDoc;
645 nsresult rv = aBlob->GetInternalUrl(doc->NodePrincipal(), aURL);
646 NS_ENSURE_SUCCESS(rv, rv);
648 doc->RegisterFileDataUri(NS_LossyConvertUTF16toASCII(aURL));
650 return NS_OK;
653 NS_IMETHODIMP
654 nsDOMMozURLProperty::RevokeObjectURL(const nsAString& aURL)
656 NS_PRECONDITION(!mWindow || mWindow->IsInnerWindow(),
657 "Should be inner window");
659 NS_ENSURE_STATE(mWindow);
661 NS_LossyConvertUTF16toASCII asciiurl(aURL);
663 nsIPrincipal* winPrincipal = mWindow->GetPrincipal();
664 if (!winPrincipal) {
665 return NS_OK;
668 nsIPrincipal* principal =
669 nsFileDataProtocolHandler::GetFileDataEntryPrincipal(asciiurl);
670 PRBool subsumes;
671 if (principal && winPrincipal &&
672 NS_SUCCEEDED(winPrincipal->Subsumes(principal, &subsumes)) &&
673 subsumes) {
674 if (mWindow->mDoc) {
675 mWindow->mDoc->UnregisterFileDataUri(asciiurl);
677 nsFileDataProtocolHandler::RemoveFileDataEntry(asciiurl);
680 return NS_OK;
684 * An indirect observer object that means we don't have to implement nsIObserver
685 * on nsGlobalWindow, where any script could see it.
687 class nsGlobalWindowObserver : public nsIObserver {
688 public:
689 nsGlobalWindowObserver(nsGlobalWindow* aWindow) : mWindow(aWindow) {}
690 NS_DECL_ISUPPORTS
691 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aData)
693 if (!mWindow)
694 return NS_OK;
695 return mWindow->Observe(aSubject, aTopic, aData);
697 void Forget() { mWindow = nsnull; }
698 private:
699 nsGlobalWindow* mWindow;
702 NS_IMPL_ISUPPORTS1(nsGlobalWindowObserver, nsIObserver)
704 nsTimeout::nsTimeout()
706 #ifdef DEBUG_jst
708 extern int gTimeoutCnt;
710 ++gTimeoutCnt;
712 #endif
714 memset(this, 0, sizeof(*this));
716 MOZ_COUNT_CTOR(nsTimeout);
719 nsTimeout::~nsTimeout()
721 #ifdef DEBUG_jst
723 extern int gTimeoutCnt;
725 --gTimeoutCnt;
727 #endif
729 MOZ_COUNT_DTOR(nsTimeout);
732 NS_IMPL_CYCLE_COLLECTION_CLASS(nsTimeout)
733 NS_IMPL_CYCLE_COLLECTION_UNLINK_NATIVE_0(nsTimeout)
734 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsTimeout)
735 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mWindow,
736 nsIScriptGlobalObject)
737 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrincipal)
738 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptHandler)
739 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
740 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout, AddRef)
741 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTimeout, Release)
743 nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
744 : mFrameElement(nsnull), mDocShell(nsnull), mModalStateDepth(0),
745 mRunningTimeout(nsnull), mMutationBits(0), mIsDocumentLoaded(PR_FALSE),
746 mIsHandlingResizeEvent(PR_FALSE), mIsInnerWindow(aOuterWindow != nsnull),
747 mMayHavePaintEventListener(PR_FALSE), mMayHaveTouchEventListener(PR_FALSE),
748 mMayHaveAudioAvailableEventListener(PR_FALSE), mIsModalContentWindow(PR_FALSE),
749 mIsActive(PR_FALSE), mInnerWindow(nsnull), mOuterWindow(aOuterWindow),
750 // Make sure no actual window ends up with mWindowID == 0
751 mWindowID(++gNextWindowID), mHasNotifiedGlobalCreated(PR_FALSE)
754 nsPIDOMWindow::~nsPIDOMWindow() {}
756 //*****************************************************************************
757 // nsOuterWindowProxy: Outer Window Proxy
758 //*****************************************************************************
760 JSString *
761 nsOuterWindowProxy::obj_toString(JSContext *cx, JSObject *proxy)
763 JS_ASSERT(proxy->isProxy());
765 return JS_NewStringCopyZ(cx, "[object Window]");
768 nsOuterWindowProxy
769 nsOuterWindowProxy::singleton;
771 JSObject *
772 NS_NewOuterWindowProxy(JSContext *cx, JSObject *parent)
774 JSAutoEnterCompartment ac;
775 if (!ac.enter(cx, parent)) {
776 return nsnull;
779 JSObject *obj = JSWrapper::New(cx, parent, parent->getProto(), parent,
780 &nsOuterWindowProxy::singleton);
781 NS_ASSERTION(obj->getClass()->ext.innerObject, "bad class");
782 return obj;
785 //*****************************************************************************
786 //*** nsGlobalWindow: Object Management
787 //*****************************************************************************
789 nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
790 : nsPIDOMWindow(aOuterWindow),
791 mIsFrozen(PR_FALSE),
792 mDidInitJavaProperties(PR_FALSE),
793 mFullScreen(PR_FALSE),
794 mIsClosed(PR_FALSE),
795 mInClose(PR_FALSE),
796 mHavePendingClose(PR_FALSE),
797 mHadOriginalOpener(PR_FALSE),
798 mIsPopupSpam(PR_FALSE),
799 mBlockScriptedClosingFlag(PR_FALSE),
800 mFireOfflineStatusChangeEventOnThaw(PR_FALSE),
801 mCreatingInnerWindow(PR_FALSE),
802 mIsChrome(PR_FALSE),
803 mCleanMessageManager(PR_FALSE),
804 mNeedsFocus(PR_TRUE),
805 mHasFocus(PR_FALSE),
806 #if defined(XP_MAC) || defined(XP_MACOSX)
807 mShowAccelerators(PR_FALSE),
808 mShowFocusRings(PR_FALSE),
809 #else
810 mShowAccelerators(PR_TRUE),
811 mShowFocusRings(PR_TRUE),
812 #endif
813 mShowFocusRingForContent(PR_FALSE),
814 mFocusByKeyOccurred(PR_FALSE),
815 mHasAcceleration(PR_FALSE),
816 mNotifiedIDDestroyed(PR_FALSE),
817 mTimeoutInsertionPoint(nsnull),
818 mTimeoutPublicIdCounter(1),
819 mTimeoutFiringDepth(0),
820 mJSObject(nsnull),
821 mPendingStorageEventsObsolete(nsnull),
822 mTimeoutsSuspendDepth(0),
823 mFocusMethod(0),
824 mSerial(0),
825 #ifdef DEBUG
826 mSetOpenerWindowCalled(PR_FALSE),
827 #endif
828 mCleanedUp(PR_FALSE),
829 mCallCleanUpAfterModalDialogCloses(PR_FALSE),
830 mDialogAbuseCount(0),
831 mDialogDisabled(PR_FALSE)
833 nsLayoutStatics::AddRef();
835 // Initialize the PRCList (this).
836 PR_INIT_CLIST(this);
838 // Initialize timeout storage
839 PR_INIT_CLIST(&mTimeouts);
841 if (aOuterWindow) {
842 // |this| is an inner window, add this inner window to the outer
843 // window list of inners.
844 PR_INSERT_AFTER(this, aOuterWindow);
846 mObserver = new nsGlobalWindowObserver(this);
847 if (mObserver) {
848 NS_ADDREF(mObserver);
849 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
850 if (os) {
851 // Watch for online/offline status changes so we can fire events. Use
852 // a strong reference.
853 os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
854 PR_FALSE);
856 // Watch for dom-storage-changed so we can fire storage
857 // events. Use a strong reference.
858 os->AddObserver(mObserver, "dom-storage2-changed", PR_FALSE);
859 os->AddObserver(mObserver, "dom-storage-changed", PR_FALSE);
862 } else {
863 // |this| is an outer window. Outer windows start out frozen and
864 // remain frozen until they get an inner window, so freeze this
865 // outer window here.
866 Freeze();
868 mObserver = nsnull;
869 SetIsProxy();
871 if (!sOuterWindowsById) {
872 sOuterWindowsById = new WindowByIdTable();
873 if (!sOuterWindowsById->Init()) {
874 delete sOuterWindowsById;
875 sOuterWindowsById = nsnull;
879 if (sOuterWindowsById) {
880 sOuterWindowsById->Put(mWindowID, this);
884 // We could have failed the first time through trying
885 // to create the entropy collector, so we should
886 // try to get one until we succeed.
888 gRefCnt++;
890 if (gRefCnt == 1) {
891 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
892 nsContentUtils::AddBoolPrefVarCache("browser.dom.window.dump.enabled",
893 &gDOMWindowDumpEnabled);
894 #endif
895 nsContentUtils::AddIntPrefVarCache("dom.min_timeout_value",
896 &gMinTimeoutValue,
897 DEFAULT_MIN_TIMEOUT_VALUE);
900 if (gDumpFile == nsnull) {
901 const nsAdoptingCString& fname =
902 nsContentUtils::GetCharPref("browser.dom.window.dump.file");
903 if (!fname.IsEmpty()) {
904 // if this fails to open, Dump() knows to just go to stdout
905 // on null.
906 gDumpFile = fopen(fname, "wb+");
907 } else {
908 gDumpFile = stdout;
912 if (!gEntropyCollector) {
913 CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
916 mSerial = ++gSerialCounter;
918 #ifdef DEBUG
919 printf("++DOMWINDOW == %d (%p) [serial = %d] [outer = %p]\n", gRefCnt,
920 static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
921 gSerialCounter, static_cast<void*>(aOuterWindow));
922 #endif
924 #ifdef PR_LOGGING
925 if (!gDOMLeakPRLog)
926 gDOMLeakPRLog = PR_NewLogModule("DOMLeak");
928 if (gDOMLeakPRLog)
929 PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
930 ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
931 #endif
934 nsGlobalWindow::~nsGlobalWindow()
936 if (sOuterWindowsById) {
937 sOuterWindowsById->Remove(mWindowID);
939 if (!--gRefCnt) {
940 NS_IF_RELEASE(gEntropyCollector);
941 delete sOuterWindowsById;
942 sOuterWindowsById = nsnull;
944 #ifdef DEBUG
945 nsCAutoString url;
946 if (mLastOpenedURI) {
947 mLastOpenedURI->GetSpec(url);
950 printf("--DOMWINDOW == %d (%p) [serial = %d] [outer = %p] [url = %s]\n",
951 gRefCnt, static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
952 mSerial, static_cast<void*>(mOuterWindow.get()), url.get());
953 #endif
955 #ifdef PR_LOGGING
956 if (gDOMLeakPRLog)
957 PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
958 ("DOMWINDOW %p destroyed", this));
959 #endif
961 if (IsOuterWindow()) {
962 // An outer window is destroyed with inner windows still possibly
963 // alive, iterate through the inner windows and null out their
964 // back pointer to this outer, and pull them out of the list of
965 // inner windows.
967 nsGlobalWindow *w;
968 while ((w = (nsGlobalWindow *)PR_LIST_HEAD(this)) != this) {
969 PR_REMOVE_AND_INIT_LINK(w);
971 } else {
972 if (mListenerManager) {
973 mListenerManager->Disconnect();
974 mListenerManager = nsnull;
977 // An inner window is destroyed, pull it out of the outer window's
978 // list if inner windows.
980 PR_REMOVE_LINK(this);
982 // If our outer window's inner window is this window, null out the
983 // outer window's reference to this window that's being deleted.
984 nsGlobalWindow *outer = GetOuterWindowInternal();
985 if (outer && outer->mInnerWindow == this) {
986 outer->mInnerWindow = nsnull;
990 mDocument = nsnull; // Forces Release
991 mDoc = nsnull;
993 NS_ASSERTION(!mArguments, "mArguments wasn't cleaned up properly!");
995 CleanUp(PR_TRUE);
997 #ifdef DEBUG
998 nsCycleCollector_DEBUG_wasFreed(static_cast<nsIScriptGlobalObject*>(this));
999 #endif
1001 if (mURLProperty) {
1002 mURLProperty->ClearWindowReference();
1005 nsLayoutStatics::Release();
1008 // static
1009 void
1010 nsGlobalWindow::ShutDown()
1012 NS_IF_RELEASE(sGlobalStorageList);
1014 if (gDumpFile && gDumpFile != stdout) {
1015 fclose(gDumpFile);
1017 gDumpFile = nsnull;
1020 // static
1021 void
1022 nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow)
1024 if (aWindow->mCachedXBLPrototypeHandlers.IsInitialized() &&
1025 aWindow->mCachedXBLPrototypeHandlers.Count() > 0) {
1026 aWindow->mCachedXBLPrototypeHandlers.Clear();
1028 nsISupports* supports;
1029 aWindow->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
1030 reinterpret_cast<void**>(&supports));
1031 NS_ASSERTION(supports, "Failed to QI to nsCycleCollectionISupports?!");
1033 nsContentUtils::DropJSObjects(supports);
1037 void
1038 nsGlobalWindow::MaybeForgiveSpamCount()
1040 if (IsOuterWindow() &&
1041 IsPopupSpamWindow())
1043 SetPopupSpamWindow(PR_FALSE);
1044 --gOpenPopupSpamCount;
1045 NS_ASSERTION(gOpenPopupSpamCount >= 0,
1046 "Unbalanced decrement of gOpenPopupSpamCount");
1050 void
1051 nsGlobalWindow::CleanUp(PRBool aIgnoreModalDialog)
1053 if (IsOuterWindow() && !aIgnoreModalDialog) {
1054 nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
1055 nsCOMPtr<nsIDOMModalContentWindow>
1056 dlg(do_QueryInterface(static_cast<nsPIDOMWindow*>(inner)));
1057 if (dlg) {
1058 // The window we're trying to clean up is the outer window of a
1059 // modal dialog. Defer cleanup until the window closes, and let
1060 // ShowModalDialog take care of calling CleanUp.
1061 mCallCleanUpAfterModalDialogCloses = PR_TRUE;
1062 return;
1066 // Guarantee idempotence.
1067 if (mCleanedUp)
1068 return;
1069 mCleanedUp = PR_TRUE;
1071 if (mObserver) {
1072 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1073 if (os) {
1074 os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
1075 os->RemoveObserver(mObserver, "dom-storage2-changed");
1076 os->RemoveObserver(mObserver, "dom-storage-changed");
1079 // Drop its reference to this dying window, in case for some bogus reason
1080 // the object stays around.
1081 mObserver->Forget();
1082 NS_RELEASE(mObserver);
1085 mNavigator = nsnull;
1086 mScreen = nsnull;
1087 mMenubar = nsnull;
1088 mToolbar = nsnull;
1089 mLocationbar = nsnull;
1090 mPersonalbar = nsnull;
1091 mStatusbar = nsnull;
1092 mScrollbars = nsnull;
1093 mLocation = nsnull;
1094 mHistory = nsnull;
1095 mFrames = nsnull;
1096 mApplicationCache = nsnull;
1097 mIndexedDB = nsnull;
1098 mPendingStorageEventsObsolete = nsnull;
1101 ClearControllers();
1103 mOpener = nsnull; // Forces Release
1104 if (mContext) {
1105 #ifdef DEBUG
1106 nsCycleCollector_DEBUG_shouldBeFreed(mContext);
1107 #endif
1108 mContext = nsnull; // Forces Release
1110 mChromeEventHandler = nsnull; // Forces Release
1111 mParentTarget = nsnull;
1113 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
1115 if (inner) {
1116 inner->CleanUp(aIgnoreModalDialog);
1119 DisableAccelerationUpdates();
1120 mHasAcceleration = PR_FALSE;
1122 if (mCleanMessageManager) {
1123 NS_ABORT_IF_FALSE(mIsChrome, "only chrome should have msg manager cleaned");
1124 nsGlobalChromeWindow *asChrome = static_cast<nsGlobalChromeWindow*>(this);
1125 if (asChrome->mMessageManager) {
1126 static_cast<nsFrameMessageManager*>(
1127 asChrome->mMessageManager.get())->Disconnect();
1131 mInnerWindowHolder = nsnull;
1132 mArguments = nsnull;
1133 mArgumentsLast = nsnull;
1134 mArgumentsOrigin = nsnull;
1136 CleanupCachedXBLHandlers(this);
1138 #ifdef DEBUG
1139 nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
1140 #endif
1143 void
1144 nsGlobalWindow::ClearControllers()
1146 if (mControllers) {
1147 PRUint32 count;
1148 mControllers->GetControllerCount(&count);
1150 while (count--) {
1151 nsCOMPtr<nsIController> controller;
1152 mControllers->GetControllerAt(count, getter_AddRefs(controller));
1154 nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
1155 if (context)
1156 context->SetCommandContext(nsnull);
1159 mControllers = nsnull;
1163 // static
1164 void
1165 nsGlobalWindow::TryClearWindowScope(nsISupports *aWindow)
1167 nsGlobalWindow *window =
1168 static_cast<nsGlobalWindow *>(static_cast<nsIDOMWindow*>(aWindow));
1170 // This termination function might be called when any script evaluation in our
1171 // context terminated, even if there are other scripts in the stack. Thus, we
1172 // have to check again if a script is executing and post a new termination
1173 // function if necessary.
1174 window->ClearScopeWhenAllScriptsStop();
1177 void
1178 nsGlobalWindow::ClearScopeWhenAllScriptsStop()
1180 NS_ASSERTION(IsInnerWindow(), "Must be an inner window");
1182 // We cannot clear scope safely until all the scripts in our script context
1183 // stopped. This might be a long wait, for example if one script is busy
1184 // because it started a nested event loop for a modal dialog.
1185 nsIScriptContext *jsscx = GetContextInternal();
1186 if (jsscx && jsscx->GetExecutingScript()) {
1187 // We ignore the return value because the only reason that we clear scope
1188 // here is to try to prevent leaks. Failing to clear scope might mean that
1189 // we'll leak more but if we don't have enough memory to allocate a
1190 // termination function we probably don't have to worry about this anyway.
1191 jsscx->SetTerminationFunction(TryClearWindowScope,
1192 static_cast<nsIDOMWindow *>(this));
1193 return;
1196 NotifyWindowIDDestroyed("inner-window-destroyed");
1197 nsIScriptContext *scx = GetContextInternal();
1198 if (scx) {
1199 scx->ClearScope(mJSObject, PR_TRUE);
1203 void
1204 nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
1206 NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
1208 // Kill all of the workers for this window.
1209 nsDOMThreadService* dts = nsDOMThreadService::get();
1210 if (dts) {
1211 nsIScriptContext *scx = GetContextInternal();
1213 JSContext *cx = scx ? (JSContext *)scx->GetNativeContext() : nsnull;
1215 // Have to suspend this request here because CancelWorkersForGlobal will
1216 // lock until the worker has died and that could cause a deadlock.
1217 JSAutoSuspendRequest asr(cx);
1219 dts->CancelWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
1222 // Close all IndexedDB databases for this window.
1223 indexedDB::IndexedDatabaseManager* idbManager =
1224 indexedDB::IndexedDatabaseManager::Get();
1225 if (idbManager) {
1226 idbManager->AbortCloseDatabasesForWindow(this);
1229 ClearAllTimeouts();
1231 mChromeEventHandler = nsnull;
1233 if (mListenerManager) {
1234 mListenerManager->Disconnect();
1235 mListenerManager = nsnull;
1238 mLocation = nsnull;
1239 mHistory = nsnull;
1241 if (mDocument) {
1242 NS_ASSERTION(mDoc, "Why is mDoc null?");
1244 // Remember the document's principal.
1245 mDocumentPrincipal = mDoc->NodePrincipal();
1248 #ifdef DEBUG
1249 if (mDocument)
1250 nsCycleCollector_DEBUG_shouldBeFreed(nsCOMPtr<nsISupports>(do_QueryInterface(mDocument)));
1251 #endif
1253 // Make sure that this is called before we null out the document.
1254 NotifyDOMWindowDestroyed(this);
1256 // Remove our reference to the document and the document principal.
1257 mDocument = nsnull;
1258 mDoc = nsnull;
1260 if (mApplicationCache) {
1261 static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
1262 mApplicationCache = nsnull;
1265 mIndexedDB = nsnull;
1267 if (aClearScope) {
1268 ClearScopeWhenAllScriptsStop();
1271 if (mDummyJavaPluginOwner) {
1272 // Tear down the dummy java plugin.
1274 // XXXjst: On a general note, should windows with java stuff in
1275 // them ever even make it into the fast-back cache?
1277 mDummyJavaPluginOwner->Destroy();
1279 mDummyJavaPluginOwner = nsnull;
1282 CleanupCachedXBLHandlers(this);
1284 #ifdef DEBUG
1285 nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
1286 #endif
1289 //*****************************************************************************
1290 // nsGlobalWindow::nsISupports
1291 //*****************************************************************************
1293 #define OUTER_WINDOW_ONLY \
1294 if (IsOuterWindow()) {
1296 #define END_OUTER_WINDOW_ONLY \
1297 foundInterface = 0; \
1298 } else
1300 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
1302 DOMCI_DATA(Window, nsGlobalWindow)
1304 // QueryInterface implementation for nsGlobalWindow
1305 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
1306 // Make sure this matches the cast in nsGlobalWindow::FromWrapper()
1307 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptGlobalObject)
1308 NS_INTERFACE_MAP_ENTRY(nsIDOMWindowInternal)
1309 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
1310 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow2)
1311 NS_INTERFACE_MAP_ENTRY(nsIDOMJSWindow)
1312 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
1313 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
1314 NS_INTERFACE_MAP_ENTRY(nsPIDOMEventTarget)
1315 NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
1316 NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
1317 NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
1318 NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow)
1319 NS_INTERFACE_MAP_ENTRY(nsIDOMViewCSS)
1320 NS_INTERFACE_MAP_ENTRY(nsIDOMAbstractView)
1321 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageWindow)
1322 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageIndexedDB)
1323 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
1324 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
1325 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow_2_0_BRANCH)
1326 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
1327 OUTER_WINDOW_ONLY
1328 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1329 END_OUTER_WINDOW_ONLY
1330 NS_INTERFACE_MAP_END
1333 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsGlobalWindow, nsIScriptGlobalObject)
1334 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsGlobalWindow,
1335 nsIScriptGlobalObject)
1338 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGlobalWindow)
1339 if (tmp->mDoc && nsCCUncollectableMarker::InGeneration(
1340 cb, tmp->mDoc->GetMarkedCCGeneration())) {
1341 return NS_SUCCESS_INTERRUPTED_TRAVERSE;
1344 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
1346 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mControllers)
1347 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArguments)
1348 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArgumentsLast)
1350 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInnerWindowHolder)
1351 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOuterWindow)
1353 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOpenerScriptPrincipal)
1354 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mListenerManager)
1356 for (nsTimeout* timeout = tmp->FirstTimeout();
1357 tmp->IsTimeout(timeout);
1358 timeout = timeout->Next()) {
1359 cb.NoteNativeChild(timeout, &NS_CYCLE_COLLECTION_NAME(nsTimeout));
1362 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSessionStorage)
1363 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mApplicationCache)
1364 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocumentPrincipal)
1365 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDoc)
1367 // Traverse stuff from nsPIDOMWindow
1368 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChromeEventHandler)
1369 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParentTarget)
1370 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
1371 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFrameElement)
1373 // Traverse mDummyJavaPluginOwner
1374 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDummyJavaPluginOwner)
1376 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFocusedNode)
1378 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPendingStorageEvents)
1380 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1382 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
1383 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
1385 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mControllers)
1386 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArguments)
1387 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArgumentsLast)
1389 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInnerWindowHolder)
1390 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOuterWindow)
1392 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOpenerScriptPrincipal)
1393 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListenerManager)
1394 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSessionStorage)
1395 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mApplicationCache)
1396 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocumentPrincipal)
1398 // Unlink stuff from nsPIDOMWindow
1399 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChromeEventHandler)
1400 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParentTarget)
1401 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
1402 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFrameElement)
1404 // Unlink mDummyJavaPluginOwner
1405 if (tmp->mDummyJavaPluginOwner) {
1406 tmp->mDummyJavaPluginOwner->Destroy();
1407 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDummyJavaPluginOwner)
1410 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFocusedNode)
1412 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPendingStorageEvents)
1414 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1416 struct TraceData
1418 TraceData(TraceCallback& aCallback, void* aClosure) :
1419 callback(aCallback), closure(aClosure) {}
1421 TraceCallback& callback;
1422 void* closure;
1425 static PLDHashOperator
1426 TraceXBLHandlers(const void* aKey, void* aData, void* aClosure)
1428 TraceData* data = static_cast<TraceData*>(aClosure);
1429 data->callback(nsIProgrammingLanguage::JAVASCRIPT, aData, data->closure);
1430 return PL_DHASH_NEXT;
1433 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
1434 if (tmp->mCachedXBLPrototypeHandlers.IsInitialized()) {
1435 TraceData data(aCallback, aClosure);
1436 tmp->mCachedXBLPrototypeHandlers.EnumerateRead(TraceXBLHandlers, &data);
1438 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1440 NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsGlobalWindow)
1441 nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
1442 NS_IMPL_CYCLE_COLLECTION_ROOT_END
1444 //*****************************************************************************
1445 // nsGlobalWindow::nsIScriptGlobalObject
1446 //*****************************************************************************
1448 nsresult
1449 nsGlobalWindow::SetScriptContext(PRUint32 lang_id, nsIScriptContext *aScriptContext)
1451 NS_ASSERTION(lang_id == nsIProgrammingLanguage::JAVASCRIPT,
1452 "We don't support this language ID");
1453 NS_ASSERTION(IsOuterWindow(), "Uh, SetScriptContext() called on inner window!");
1455 NS_ASSERTION(!aScriptContext || !mContext, "Bad call to SetContext()!");
1457 if (aScriptContext) {
1458 // should probably assert the context is clean???
1459 aScriptContext->WillInitializeContext();
1461 nsresult rv = aScriptContext->InitContext();
1462 NS_ENSURE_SUCCESS(rv, rv);
1464 if (IsFrame()) {
1465 // This window is a [i]frame, don't bother GC'ing when the
1466 // frame's context is destroyed since a GC will happen when the
1467 // frameset or host document is destroyed anyway.
1469 aScriptContext->SetGCOnDestruction(PR_FALSE);
1473 mContext = aScriptContext;
1474 return NS_OK;
1477 nsresult
1478 nsGlobalWindow::EnsureScriptEnvironment(PRUint32 aLangID)
1480 NS_ASSERTION(aLangID == nsIProgrammingLanguage::JAVASCRIPT,
1481 "We don't support this language ID");
1482 FORWARD_TO_OUTER(EnsureScriptEnvironment, (aLangID), NS_ERROR_NOT_INITIALIZED);
1484 if (mJSObject)
1485 return NS_OK;
1487 NS_ASSERTION(!GetCurrentInnerWindowInternal(),
1488 "mJSObject is null, but we have an inner window?");
1490 nsCOMPtr<nsIScriptRuntime> scriptRuntime;
1491 nsresult rv = NS_GetScriptRuntimeByID(aLangID, getter_AddRefs(scriptRuntime));
1492 NS_ENSURE_SUCCESS(rv, rv);
1494 nsCOMPtr<nsIScriptContext> context;
1495 rv = scriptRuntime->CreateContext(getter_AddRefs(context));
1496 NS_ENSURE_SUCCESS(rv, rv);
1498 return SetScriptContext(aLangID, context);
1501 nsIScriptContext *
1502 nsGlobalWindow::GetScriptContext(PRUint32 lang)
1504 NS_ASSERTION(lang == nsIProgrammingLanguage::JAVASCRIPT,
1505 "We don't support this language ID");
1507 FORWARD_TO_OUTER(GetScriptContext, (lang), nsnull);
1508 return mContext;
1511 void *
1512 nsGlobalWindow::GetScriptGlobal(PRUint32 lang)
1514 NS_ASSERTION(lang == nsIProgrammingLanguage::JAVASCRIPT,
1515 "We don't support this language ID");
1516 return mJSObject;
1519 nsIScriptContext *
1520 nsGlobalWindow::GetContext()
1522 FORWARD_TO_OUTER(GetContext, (), nsnull);
1524 // check GetContext is indeed identical to GetScriptContext()
1525 NS_ASSERTION(mContext == GetScriptContext(nsIProgrammingLanguage::JAVASCRIPT),
1526 "GetContext confused?");
1527 return mContext;
1530 JSObject *
1531 nsGlobalWindow::GetGlobalJSObject()
1533 NS_ASSERTION(mJSObject == GetScriptGlobal(nsIProgrammingLanguage::JAVASCRIPT),
1534 "GetGlobalJSObject confused?");
1535 return FastGetGlobalJSObject();
1538 PRBool
1539 nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument)
1541 // We reuse the inner window when:
1542 // a. We are currently at our original document.
1543 // b. At least one of the following conditions are true:
1544 // -- We are not currently a content window (i.e., we're currently a chrome
1545 // window).
1546 // -- The new document is the same as the old document. This means that we're
1547 // getting called from document.open().
1548 // -- The new document has the same origin as what we have loaded right now.
1550 if (!mDoc || !aNewDocument) {
1551 return PR_FALSE;
1554 if (!mDoc->IsInitialDocument()) {
1555 return PR_FALSE;
1558 NS_ASSERTION(IsAboutBlank(mDoc->GetDocumentURI()),
1559 "How'd this happen?");
1561 // Great, we're the original document, check for one of the other
1562 // conditions.
1563 if (mDoc == aNewDocument) {
1564 // aClearScopeHint is false.
1565 return PR_TRUE;
1568 PRBool equal;
1569 if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),
1570 &equal)) &&
1571 equal) {
1572 // The origin is the same.
1573 return PR_TRUE;
1576 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
1578 if (treeItem) {
1579 PRInt32 itemType = nsIDocShellTreeItem::typeContent;
1580 treeItem->GetItemType(&itemType);
1582 // If we're a chrome window, then we want to reuse the inner window.
1583 return itemType == nsIDocShellTreeItem::typeChrome;
1586 // No treeItem: don't reuse the current inner window.
1587 return PR_FALSE;
1590 void
1591 nsGlobalWindow::SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal)
1593 FORWARD_TO_OUTER_VOID(SetOpenerScriptPrincipal, (aPrincipal));
1595 if (mDoc) {
1596 if (!mDoc->IsInitialDocument()) {
1597 // We have a document already, and it's not the original one. Bail out.
1598 // Do NOT set mOpenerScriptPrincipal in this case, just to be safe.
1599 return;
1602 #ifdef DEBUG
1603 // We better have an about:blank document loaded at this point. Otherwise,
1604 // something is really weird.
1605 nsCOMPtr<nsIURI> uri;
1606 mDoc->NodePrincipal()->GetURI(getter_AddRefs(uri));
1607 NS_ASSERTION(uri && IsAboutBlank(uri) &&
1608 IsAboutBlank(mDoc->GetDocumentURI()),
1609 "Unexpected original document");
1610 #endif
1612 nsCOMPtr<nsIDocShell_MOZILLA_2_0_BRANCH> ds(do_QueryInterface(GetDocShell()));
1613 ds->CreateAboutBlankContentViewer(aPrincipal);
1614 mDoc->SetIsInitialDocument(PR_TRUE);
1618 nsIPrincipal*
1619 nsGlobalWindow::GetOpenerScriptPrincipal()
1621 FORWARD_TO_OUTER(GetOpenerScriptPrincipal, (), nsnull);
1623 return mOpenerScriptPrincipal;
1626 PopupControlState
1627 PushPopupControlState(PopupControlState aState, PRBool aForce)
1629 PopupControlState oldState = gPopupControlState;
1631 if (aState < gPopupControlState || aForce) {
1632 gPopupControlState = aState;
1635 return oldState;
1638 void
1639 PopPopupControlState(PopupControlState aState)
1641 gPopupControlState = aState;
1644 PopupControlState
1645 nsGlobalWindow::PushPopupControlState(PopupControlState aState,
1646 PRBool aForce) const
1648 return ::PushPopupControlState(aState, aForce);
1651 void
1652 nsGlobalWindow::PopPopupControlState(PopupControlState aState) const
1654 ::PopPopupControlState(aState);
1657 PopupControlState
1658 nsGlobalWindow::GetPopupControlState() const
1660 return gPopupControlState;
1663 #define WINDOWSTATEHOLDER_IID \
1664 {0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}
1666 class WindowStateHolder : public nsISupports
1668 public:
1669 NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
1670 NS_DECL_ISUPPORTS
1672 WindowStateHolder(nsGlobalWindow *aWindow,
1673 nsIXPConnectJSObjectHolder *aHolder,
1674 nsNavigator *aNavigator,
1675 nsIXPConnectJSObjectHolder *aOuterProto,
1676 nsIXPConnectJSObjectHolder *aOuterRealProto);
1678 nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
1679 nsIXPConnectJSObjectHolder *GetInnerWindowHolder()
1680 { return mInnerWindowHolder; }
1682 nsNavigator* GetNavigator() { return mNavigator; }
1683 nsIXPConnectJSObjectHolder* GetOuterProto() { return mOuterProto; }
1684 nsIXPConnectJSObjectHolder* GetOuterRealProto() { return mOuterRealProto; }
1686 void DidRestoreWindow()
1688 mInnerWindow = nsnull;
1690 mInnerWindowHolder = nsnull;
1691 mNavigator = nsnull;
1692 mOuterProto = nsnull;
1693 mOuterRealProto = nsnull;
1696 protected:
1697 ~WindowStateHolder();
1699 nsGlobalWindow *mInnerWindow;
1700 // We hold onto this to make sure the inner window doesn't go away. The outer
1701 // window ends up recalculating it anyway.
1702 nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
1703 nsRefPtr<nsNavigator> mNavigator;
1704 nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterProto;
1705 nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterRealProto;
1708 NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
1710 WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
1711 nsIXPConnectJSObjectHolder *aHolder,
1712 nsNavigator *aNavigator,
1713 nsIXPConnectJSObjectHolder *aOuterProto,
1714 nsIXPConnectJSObjectHolder *aOuterRealProto)
1715 : mInnerWindow(aWindow),
1716 mNavigator(aNavigator),
1717 mOuterProto(aOuterProto),
1718 mOuterRealProto(aOuterRealProto)
1720 NS_PRECONDITION(aWindow, "null window");
1721 NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
1723 mInnerWindowHolder = aHolder;
1725 aWindow->SuspendTimeouts();
1728 WindowStateHolder::~WindowStateHolder()
1730 if (mInnerWindow) {
1731 // This window was left in the bfcache and is now going away. We need to
1732 // free it up.
1733 // Note that FreeInnerObjects may already have been called on the
1734 // inner window if its outer has already had SetDocShell(null)
1735 // called. In this case the contexts will all be null and the
1736 // PR_TRUE for aClearScope won't do anything; this is OK since
1737 // SetDocShell(null) already did it.
1738 mInnerWindow->FreeInnerObjects(PR_TRUE);
1742 NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder)
1744 nsresult
1745 nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
1746 nsISupports* aState,
1747 PRBool aForceReuseInnerWindow)
1749 NS_TIME_FUNCTION;
1751 NS_PRECONDITION(mDocumentPrincipal == nsnull,
1752 "mDocumentPrincipal prematurely set!");
1754 if (!aDocument) {
1755 NS_ERROR("SetNewDocument(null) called!");
1757 return NS_ERROR_INVALID_ARG;
1760 if (IsInnerWindow()) {
1761 if (!mOuterWindow) {
1762 return NS_ERROR_NOT_INITIALIZED;
1765 // Refuse to set a new document if the call came from an inner
1766 // window that's not the current inner window.
1767 if (mOuterWindow->GetCurrentInnerWindow() != this) {
1768 return NS_ERROR_NOT_AVAILABLE;
1771 return GetOuterWindowInternal()->SetNewDocument(aDocument, aState,
1772 aForceReuseInnerWindow);
1775 NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
1777 if (IsFrozen()) {
1778 // This outer is now getting its first inner, thaw the outer now
1779 // that it's ready and is getting an inner window.
1781 Thaw();
1784 NS_ASSERTION(!GetCurrentInnerWindow() ||
1785 GetCurrentInnerWindow()->GetExtantDocument() == mDocument,
1786 "Uh, mDocument doesn't match the current inner window "
1787 "document!");
1789 PRBool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
1790 if (aForceReuseInnerWindow &&
1791 !wouldReuseInnerWindow &&
1792 mDoc &&
1793 mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
1794 NS_ERROR("Attempted forced inner window reuse while changing principal");
1795 return NS_ERROR_UNEXPECTED;
1798 nsresult rv = NS_OK;
1800 nsCOMPtr<nsIDocument> oldDoc(do_QueryInterface(mDocument));
1802 nsIScriptContext *scx = GetContextInternal();
1803 NS_ENSURE_TRUE(scx, NS_ERROR_NOT_INITIALIZED);
1805 JSContext *cx = (JSContext *)scx->GetNativeContext();
1806 #ifndef MOZ_DISABLE_DOMCRYPTO
1807 // clear smartcard events, our document has gone away.
1808 if (mCrypto) {
1809 mCrypto->SetEnableSmartCardEvents(PR_FALSE);
1811 #endif
1812 if (!mDocument) {
1813 // First document load.
1815 // Get our private root. If it is equal to us, then we need to
1816 // attach our global key bindings that handles browser scrolling
1817 // and other browser commands.
1818 nsIDOMWindowInternal *internal = nsGlobalWindow::GetPrivateRoot();
1820 if (internal == static_cast<nsIDOMWindowInternal *>(this)) {
1821 nsCOMPtr<nsIXBLService> xblService = do_GetService("@mozilla.org/xbl;1");
1822 if (xblService) {
1823 nsCOMPtr<nsPIDOMEventTarget> piTarget =
1824 do_QueryInterface(mChromeEventHandler);
1825 xblService->AttachGlobalKeyHandler(piTarget);
1830 /* No mDocShell means we're already been partially closed down. When that
1831 happens, setting status isn't a big requirement, so don't. (Doesn't happen
1832 under normal circumstances, but bug 49615 describes a case.) */
1834 nsContentUtils::AddScriptRunner(
1835 NS_NewRunnableMethod(this, &nsGlobalWindow::ClearStatus));
1837 PRBool reUseInnerWindow = aForceReuseInnerWindow || wouldReuseInnerWindow;
1839 // Remember the old document's principal.
1840 nsIPrincipal *oldPrincipal = nsnull;
1841 if (oldDoc) {
1842 oldPrincipal = oldDoc->NodePrincipal();
1845 // Drop our reference to the navigator object unless we're reusing
1846 // the existing inner window or the new document is from the same
1847 // origin as the old document.
1848 if (!reUseInnerWindow && mNavigator && oldPrincipal) {
1849 PRBool equal;
1850 rv = oldPrincipal->Equals(aDocument->NodePrincipal(), &equal);
1852 if (NS_FAILED(rv) || !equal) {
1853 // Different origins. Release the navigator object so it gets
1854 // recreated for the new document. The plugins or mime types
1855 // arrays may have changed. See bug 150087.
1856 mNavigator->SetDocShell(nsnull);
1858 mNavigator = nsnull;
1862 if (mNavigator && aDocument != oldDoc) {
1863 // We didn't drop our reference to our old navigator object and
1864 // we're loading a new document. Notify the navigator object about
1865 // the new document load so that it can make sure it is ready for
1866 // the new document.
1868 mNavigator->LoadingNewDocument();
1871 // Set mDocument even if this is an outer window to avoid
1872 // having to *always* reach into the inner window to find the
1873 // document.
1874 mDocument = do_QueryInterface(aDocument);
1875 mDoc = aDocument;
1877 #ifdef DEBUG
1878 mLastOpenedURI = aDocument->GetDocumentURI();
1879 #endif
1881 mContext->WillInitializeContext();
1883 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
1885 nsRefPtr<nsGlobalWindow> newInnerWindow;
1887 PRBool thisChrome = IsChromeWindow();
1888 nsCOMPtr<nsIXPConnectJSObjectHolder> navigatorHolder;
1889 jsval nav;
1891 PRBool isChrome = PR_FALSE;
1893 nsCxPusher cxPusher;
1894 if (!cxPusher.Push(cx)) {
1895 return NS_ERROR_FAILURE;
1898 JSAutoRequest ar(cx);
1900 nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
1901 NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
1903 // Make sure to clear scope on the outer window *before* we
1904 // initialize the new inner window. If we don't, things
1905 // (Object.prototype etc) could leak from the old outer to the new
1906 // inner scope.
1907 mContext->ClearScope(mJSObject, PR_FALSE);
1909 // This code should not be called during shutdown any more (now that
1910 // we don't ever call SetNewDocument(nsnull), so no need to null
1911 // check xpc here.
1912 nsIXPConnect *xpc = nsContentUtils::XPConnect();
1913 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
1914 if (reUseInnerWindow) {
1915 // We're reusing the current inner window.
1916 NS_ASSERTION(!currentInner->IsFrozen(),
1917 "We should never be reusing a shared inner window");
1918 newInnerWindow = currentInner;
1920 if (aDocument != oldDoc) {
1921 nsWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject);
1923 } else {
1924 if (aState) {
1925 newInnerWindow = wsh->GetInnerWindow();
1926 mInnerWindowHolder = wsh->GetInnerWindowHolder();
1928 NS_ASSERTION(newInnerWindow, "Got a state without inner window");
1930 // These assignments addref.
1931 mNavigator = wsh->GetNavigator();
1933 if (mNavigator) {
1934 // Update mNavigator's docshell pointer now.
1935 mNavigator->SetDocShell(mDocShell);
1936 mNavigator->LoadingNewDocument();
1938 } else if (thisChrome) {
1939 newInnerWindow = new nsGlobalChromeWindow(this);
1940 isChrome = PR_TRUE;
1941 } else if (mIsModalContentWindow) {
1942 newInnerWindow = new nsGlobalModalWindow(this);
1943 } else {
1944 newInnerWindow = new nsGlobalWindow(this);
1947 if (currentInner && currentInner->mJSObject) {
1948 if (mNavigator && !aState) {
1949 // Hold on to the navigator wrapper so that we can set
1950 // window.navigator in the new window to point to the same
1951 // object (assuming we didn't change origins etc). See bug
1952 // 163645 for more on why we need this.
1954 nsIDOMNavigator* navigator =
1955 static_cast<nsIDOMNavigator*>(mNavigator.get());
1956 nsContentUtils::WrapNative(cx, currentInner->mJSObject, navigator,
1957 &NS_GET_IID(nsIDOMNavigator), &nav,
1958 getter_AddRefs(navigatorHolder));
1962 if (!aState) {
1963 // This is redundant if we're restoring from a previous inner window.
1964 nsIScriptGlobalObject *sgo =
1965 (nsIScriptGlobalObject *)newInnerWindow.get();
1967 // Freeze the outer window and null out the inner window so
1968 // that initializing classes on the new inner doesn't end up
1969 // reaching into the old inner window for classes etc.
1971 // [This happens with Object.prototype when XPConnect creates
1972 // a temporary global while initializing classes; the reason
1973 // being that xpconnect creates the temp global w/o a parent
1974 // and proto, which makes the JS engine look up classes in
1975 // cx->globalObject, i.e. this outer window].
1977 mInnerWindow = nsnull;
1979 Freeze();
1980 mCreatingInnerWindow = PR_TRUE;
1981 // Every script context we are initialized with must create a
1982 // new global.
1983 void *&newGlobal = (void *&)newInnerWindow->mJSObject;
1984 nsCOMPtr<nsIXPConnectJSObjectHolder> &holder = mInnerWindowHolder;
1985 rv = mContext->CreateNativeGlobalForInner(sgo, isChrome,
1986 aDocument->NodePrincipal(),
1987 &newGlobal,
1988 getter_AddRefs(holder));
1989 NS_ASSERTION(NS_SUCCEEDED(rv) && newGlobal && holder,
1990 "Failed to get script global and holder");
1992 mCreatingInnerWindow = PR_FALSE;
1993 Thaw();
1995 NS_ENSURE_SUCCESS(rv, rv);
1998 if (currentInner && currentInner->mJSObject) {
1999 PRBool termFuncSet = PR_FALSE;
2001 if (oldDoc == aDocument) {
2002 // Suspend the current context's request before Pop() resumes the old
2003 // context's request.
2004 JSAutoSuspendRequest asr(cx);
2006 // Pop our context here so that we get the correct one for the
2007 // termination function.
2008 cxPusher.Pop();
2010 JSContext *oldCx = nsContentUtils::GetCurrentJSContext();
2012 nsIScriptContext *callerScx;
2013 if (oldCx && (callerScx = GetScriptContextFromJSContext(oldCx))) {
2014 // We're called from document.open() (and document.open() is
2015 // called from JS), clear the scope etc in a termination
2016 // function on the calling context to prevent clearing the
2017 // calling scope.
2018 NS_ASSERTION(!currentInner->IsFrozen(),
2019 "How does this opened window get into session history");
2021 JSAutoRequest ar(oldCx);
2023 callerScx->SetTerminationFunction(ClearWindowScope,
2024 static_cast<nsIDOMWindow *>
2025 (currentInner));
2027 termFuncSet = PR_TRUE;
2030 // Re-push our context.
2031 cxPusher.Push(cx);
2034 // Don't clear scope on our current inner window if it's going to be
2035 // held in the bfcache.
2036 if (!currentInner->IsFrozen()) {
2037 // Skip the ClearScope if we set a termination function to do
2038 // it ourselves, later.
2039 currentInner->FreeInnerObjects(!termFuncSet);
2043 mInnerWindow = newInnerWindow;
2045 if (!mJSObject) {
2046 mContext->CreateOuterObject(this, newInnerWindow);
2047 mContext->DidInitializeContext();
2049 mJSObject = (JSObject *)mContext->GetNativeGlobal();
2050 SetWrapper(mJSObject);
2051 } else {
2052 JSObject *outerObject =
2053 NS_NewOuterWindowProxy(cx, newInnerWindow->mJSObject);
2054 if (!outerObject) {
2055 NS_ERROR("out of memory");
2056 return NS_ERROR_FAILURE;
2059 outerObject = JS_TransplantObject(cx, mJSObject, outerObject);
2060 if (!outerObject) {
2061 NS_ERROR("unable to transplant wrappers, probably OOM");
2062 return NS_ERROR_FAILURE;
2065 mJSObject = outerObject;
2066 SetWrapper(mJSObject);
2069 JSAutoEnterCompartment ac;
2070 if (!ac.enter(cx, mJSObject)) {
2071 NS_ERROR("unable to enter a compartment");
2072 return NS_ERROR_FAILURE;
2075 JS_SetParent(cx, mJSObject, newInnerWindow->mJSObject);
2077 mContext->SetOuterObject(mJSObject);
2081 JSAutoEnterCompartment ac;
2082 if (!ac.enter(cx, mJSObject)) {
2083 NS_ERROR("unable to enter a compartment");
2084 return NS_ERROR_FAILURE;
2087 // XXX Not sure if this is needed.
2088 if (aState) {
2089 JSObject *proto;
2090 if (nsIXPConnectJSObjectHolder *holder = wsh->GetOuterRealProto()) {
2091 holder->GetJSObject(&proto);
2092 } else {
2093 proto = nsnull;
2096 if (!JS_SetPrototype(cx, mJSObject, proto)) {
2097 NS_ERROR("can't set prototype");
2098 return NS_ERROR_FAILURE;
2100 } else {
2101 if (!JS_DefineProperty(cx, newInnerWindow->mJSObject, "window",
2102 OBJECT_TO_JSVAL(mJSObject),
2103 JS_PropertyStub, JS_StrictPropertyStub,
2104 JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
2105 NS_ERROR("can't create the 'window' property");
2106 return NS_ERROR_FAILURE;
2111 JSAutoEnterCompartment ac;
2112 if (!ac.enter(cx, mJSObject)) {
2113 NS_ERROR("unable to enter a compartment");
2114 return NS_ERROR_FAILURE;
2117 if (!aState && !reUseInnerWindow) {
2118 // Loading a new page and creating a new inner window, *not*
2119 // restoring from session history.
2121 // Now that both the the inner and outer windows are initialized
2122 // let the script context do its magic to hook them together.
2123 mContext->ConnectToInner(newInnerWindow, mJSObject);
2125 nsCOMPtr<nsIContent> frame = do_QueryInterface(GetFrameElementInternal());
2126 if (frame && frame->GetOwnerDoc()) {
2127 nsPIDOMWindow* parentWindow = frame->GetOwnerDoc()->GetWindow();
2128 if (parentWindow && parentWindow->TimeoutSuspendCount()) {
2129 SuspendTimeouts(parentWindow->TimeoutSuspendCount());
2134 // Tell the contexts we have completed setting up the doc.
2135 // Add an extra ref in case we release mContext during GC.
2136 nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
2137 nsCOMPtr<nsIDOMDocument> dd(do_QueryInterface(aDocument));
2138 mContext->DidSetDocument(dd, newInnerWindow->mJSObject);
2140 // Now that the prototype is all set up, install the global scope
2141 // polluter. This must happen after the above prototype fixup. If
2142 // the GSP was to be installed on the inner window's real
2143 // prototype (as it would be if this was done before the prototype
2144 // fixup above) we would end up holding the GSP alive (through
2145 // XPConnect's internal marking of wrapper prototypes) as long as
2146 // the inner window was around, and if the GSP had properties on
2147 // it that held an element alive we'd hold the document alive,
2148 // which could hold event handlers alive, which hold the context
2149 // alive etc.
2151 if ((!reUseInnerWindow || aDocument != oldDoc) && !aState) {
2152 nsCOMPtr<nsIHTMLDocument> html_doc(do_QueryInterface(mDocument));
2153 nsWindowSH::InstallGlobalScopePolluter(cx, newInnerWindow->mJSObject,
2154 html_doc);
2157 if (aDocument) {
2158 aDocument->SetScriptGlobalObject(newInnerWindow);
2161 if (!aState) {
2162 if (reUseInnerWindow) {
2163 if (newInnerWindow->mDoc != aDocument) {
2164 newInnerWindow->mDocument = do_QueryInterface(aDocument);
2165 newInnerWindow->mDoc = aDocument;
2167 // We're reusing the inner window for a new document. In this
2168 // case we don't clear the inner window's scope, but we must
2169 // make sure the cached document property gets updated.
2171 // XXXmarkh - tell other languages about this?
2172 ::JS_DeleteProperty(cx, currentInner->mJSObject, "document");
2174 } else {
2175 rv = newInnerWindow->InnerSetNewDocument(aDocument);
2176 NS_ENSURE_SUCCESS(rv, rv);
2178 // Initialize DOM classes etc on the inner window.
2179 rv = mContext->InitClasses(newInnerWindow->mJSObject);
2180 NS_ENSURE_SUCCESS(rv, rv);
2182 if (navigatorHolder) {
2183 JS_ASSERT(JSVAL_IS_OBJECT(nav));
2185 if (JSVAL_TO_OBJECT(nav)->compartment() == newInnerWindow->mJSObject->compartment()) {
2186 // Restore window.navigator onto the new inner window.
2188 ::JS_DefineProperty(cx, newInnerWindow->mJSObject, "navigator",
2189 nav, nsnull, nsnull,
2190 JSPROP_ENUMERATE | JSPROP_PERMANENT |
2191 JSPROP_READONLY);
2193 // The Navigator's prototype object keeps a reference to the
2194 // window in which it was first created and can thus cause that
2195 // window to stay alive for too long. Reparenting it here allows
2196 // the window to be collected sooner.
2197 nsIDOMNavigator* navigator =
2198 static_cast<nsIDOMNavigator*>(mNavigator);
2200 xpc->
2201 ReparentWrappedNativeIfFound(cx, JSVAL_TO_OBJECT(nav),
2202 newInnerWindow->mJSObject,
2203 navigator,
2204 getter_AddRefs(navigatorHolder));
2209 if (mArguments) {
2210 newInnerWindow->DefineArgumentsProperty(mArguments);
2211 newInnerWindow->mArguments = mArguments;
2212 newInnerWindow->mArgumentsOrigin = mArgumentsOrigin;
2214 mArguments = nsnull;
2215 mArgumentsOrigin = nsnull;
2218 // Give the new inner window our chrome event handler (since it
2219 // doesn't have one).
2220 newInnerWindow->mChromeEventHandler = mChromeEventHandler;
2223 mContext->GC();
2224 mContext->DidInitializeContext();
2226 if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
2227 // We should probably notify. However if this is the, arguably bad,
2228 // situation when we're creating a temporary non-chrome-about-blank
2229 // document in a chrome docshell, don't notify just yet. Instead wait
2230 // until we have a real chrome doc.
2231 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
2232 PRInt32 itemType = nsIDocShellTreeItem::typeContent;
2233 if (treeItem) {
2234 treeItem->GetItemType(&itemType);
2237 if (itemType != nsIDocShellTreeItem::typeChrome ||
2238 nsContentUtils::IsSystemPrincipal(mDoc->NodePrincipal())) {
2239 newInnerWindow->mHasNotifiedGlobalCreated = PR_TRUE;
2240 nsContentUtils::AddScriptRunner(
2241 NS_NewRunnableMethod(this, &nsGlobalWindow::DispatchDOMWindowCreated));
2245 return NS_OK;
2248 void
2249 nsGlobalWindow::DispatchDOMWindowCreated()
2251 if (!mDoc || !mDocument) {
2252 return;
2255 // Fire DOMWindowCreated at chrome event listeners
2256 nsContentUtils::DispatchChromeEvent(mDoc, mDocument, NS_LITERAL_STRING("DOMWindowCreated"),
2257 PR_TRUE /* bubbles */,
2258 PR_FALSE /* not cancellable */);
2260 nsCOMPtr<nsIObserverService> observerService =
2261 mozilla::services::GetObserverService();
2262 if (observerService) {
2263 nsAutoString origin;
2264 nsIPrincipal* principal = mDoc->NodePrincipal();
2265 nsContentUtils::GetUTFOrigin(principal, origin);
2266 observerService->
2267 NotifyObservers(static_cast<nsIDOMWindow*>(this),
2268 nsContentUtils::IsSystemPrincipal(principal) ?
2269 "chrome-document-global-created" :
2270 "content-document-global-created",
2271 origin.get());
2275 void
2276 nsGlobalWindow::ClearStatus()
2278 SetStatus(EmptyString());
2279 SetDefaultStatus(EmptyString());
2282 nsresult
2283 nsGlobalWindow::InnerSetNewDocument(nsIDocument* aDocument)
2285 NS_PRECONDITION(IsInnerWindow(), "Must only be called on inner windows");
2287 #ifdef PR_LOGGING
2288 if (aDocument && gDOMLeakPRLog &&
2289 PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
2290 nsIURI *uri = aDocument->GetDocumentURI();
2291 nsCAutoString spec;
2292 if (uri)
2293 uri->GetSpec(spec);
2294 PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get());
2296 #endif
2298 mDocument = do_QueryInterface(aDocument);
2299 mDoc = aDocument;
2300 mLocalStorage = nsnull;
2301 mSessionStorage = nsnull;
2303 #ifdef DEBUG
2304 mLastOpenedURI = aDocument->GetDocumentURI();
2305 #endif
2307 // Clear our mutation bitfield.
2308 mMutationBits = 0;
2310 return NS_OK;
2313 void
2314 nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
2316 NS_ASSERTION(IsOuterWindow(), "Uh, SetDocShell() called on inner window!");
2318 if (aDocShell == mDocShell)
2319 return;
2321 // SetDocShell(nsnull) means the window is being torn down. Drop our
2322 // reference to the script context, allowing it to be deleted
2323 // later. Meanwhile, keep our weak reference to the script object
2324 // (mJSObject) so that it can be retrieved later (until it is
2325 // finalized by the JS GC).
2327 if (!aDocShell) {
2328 NS_ASSERTION(PR_CLIST_IS_EMPTY(&mTimeouts),
2329 "Uh, outer window holds timeouts!");
2331 // Call FreeInnerObjects on all inner windows, not just the current
2332 // one, since some could be held by WindowStateHolder objects that
2333 // are GC-owned.
2334 for (nsRefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
2335 inner != this;
2336 inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
2337 NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
2338 "bad outer window pointer");
2339 inner->FreeInnerObjects(PR_TRUE);
2342 // Make sure that this is called before we null out the document.
2343 NotifyDOMWindowDestroyed(this);
2345 NotifyWindowIDDestroyed("outer-window-destroyed");
2347 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
2349 if (currentInner) {
2350 NS_ASSERTION(mDoc, "Must have doc!");
2352 // Remember the document's principal.
2353 mDocumentPrincipal = mDoc->NodePrincipal();
2355 // Release our document reference
2356 mDocument = nsnull;
2357 mDoc = nsnull;
2360 if (mContext) {
2361 mContext->ClearScope(mJSObject, PR_TRUE);
2364 ClearControllers();
2366 mChromeEventHandler = nsnull; // force release now
2368 if (mArguments) {
2369 // We got no new document after someone called
2370 // SetArguments(), drop our reference to the arguments.
2371 mArguments = nsnull;
2372 mArgumentsLast = nsnull;
2373 mArgumentsOrigin = nsnull;
2376 if (mContext) {
2377 mContext->GC();
2378 mContext->FinalizeContext();
2379 mContext = nsnull;
2382 #ifdef DEBUG
2383 nsCycleCollector_DEBUG_shouldBeFreed(mContext);
2384 nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
2385 #endif
2388 mDocShell = aDocShell; // Weak Reference
2390 if (mNavigator)
2391 mNavigator->SetDocShell(aDocShell);
2392 if (mFrames)
2393 mFrames->SetDocShell(aDocShell);
2394 if (mScreen)
2395 mScreen->SetDocShell(aDocShell);
2397 // tell our member elements about the new browserwindow
2398 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2399 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2400 if (mMenubar) {
2401 mMenubar->SetWebBrowserChrome(browserChrome);
2403 if (mToolbar) {
2404 mToolbar->SetWebBrowserChrome(browserChrome);
2406 if (mLocationbar) {
2407 mLocationbar->SetWebBrowserChrome(browserChrome);
2409 if (mPersonalbar) {
2410 mPersonalbar->SetWebBrowserChrome(browserChrome);
2412 if (mStatusbar) {
2413 mStatusbar->SetWebBrowserChrome(browserChrome);
2415 if (mScrollbars) {
2416 mScrollbars->SetWebBrowserChrome(browserChrome);
2419 if (!mDocShell) {
2420 MaybeForgiveSpamCount();
2421 CleanUp(PR_FALSE);
2422 } else {
2423 // Get our enclosing chrome shell and retrieve its global window impl, so
2424 // that we can do some forwarding to the chrome document.
2425 nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
2426 mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
2427 mChromeEventHandler = do_QueryInterface(chromeEventHandler);
2428 if (!mChromeEventHandler) {
2429 // We have no chrome event handler. If we have a parent,
2430 // get our chrome event handler from the parent. If
2431 // we don't have a parent, then we need to make a new
2432 // window root object that will function as a chrome event
2433 // handler and receive all events that occur anywhere inside
2434 // our window.
2435 nsCOMPtr<nsIDOMWindow> parentWindow;
2436 GetParent(getter_AddRefs(parentWindow));
2437 if (parentWindow.get() != static_cast<nsIDOMWindow*>(this)) {
2438 nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(parentWindow));
2439 mChromeEventHandler = piWindow->GetChromeEventHandler();
2441 else NS_NewWindowRoot(this, getter_AddRefs(mChromeEventHandler));
2446 void
2447 nsGlobalWindow::SetOpenerWindow(nsIDOMWindowInternal* aOpener,
2448 PRBool aOriginalOpener)
2450 FORWARD_TO_OUTER_VOID(SetOpenerWindow, (aOpener, aOriginalOpener));
2452 NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
2453 "aOriginalOpener is true, but not first call to "
2454 "SetOpenerWindow!");
2455 NS_ASSERTION(aOpener || !aOriginalOpener,
2456 "Shouldn't set mHadOriginalOpener if aOpener is null");
2458 mOpener = do_GetWeakReference(aOpener);
2459 NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!");
2461 if (aOriginalOpener) {
2462 mHadOriginalOpener = PR_TRUE;
2465 #ifdef DEBUG
2466 mSetOpenerWindowCalled = PR_TRUE;
2467 #endif
2470 void
2471 nsGlobalWindow::UpdateParentTarget()
2473 nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(mChromeEventHandler);
2474 if (flo) {
2475 nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
2476 if (fl) {
2477 mParentTarget = fl->GetTabChildGlobalAsEventTarget();
2480 if (!mParentTarget) {
2481 mParentTarget = mChromeEventHandler;
2485 nsresult
2486 nsGlobalWindow::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
2488 NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
2489 static PRUint32 count = 0;
2490 PRUint32 msg = aVisitor.mEvent->message;
2492 aVisitor.mCanHandle = PR_TRUE;
2493 aVisitor.mForceContentDispatch = PR_TRUE; //FIXME! Bug 329119
2494 if ((msg == NS_MOUSE_MOVE) && gEntropyCollector) {
2495 //Chances are this counter will overflow during the life of the
2496 //process, but that's OK for our case. Means we get a little
2497 //more entropy.
2498 if (count++ % 100 == 0) {
2499 //Since the high bits seem to be zero's most of the time,
2500 //let's only take the lowest half of the point structure.
2501 PRInt16 myCoord[2];
2503 myCoord[0] = aVisitor.mEvent->refPoint.x;
2504 myCoord[1] = aVisitor.mEvent->refPoint.y;
2505 gEntropyCollector->RandomUpdate((void*)myCoord, sizeof(myCoord));
2506 gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
2507 sizeof(PRUint32));
2509 } else if (msg == NS_RESIZE_EVENT) {
2510 mIsHandlingResizeEvent = PR_TRUE;
2511 } else if (msg == NS_MOUSE_BUTTON_DOWN &&
2512 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2513 gMouseDown = PR_TRUE;
2514 } else if (msg == NS_MOUSE_BUTTON_UP &&
2515 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2516 gMouseDown = PR_FALSE;
2517 if (gDragServiceDisabled) {
2518 nsCOMPtr<nsIDragService> ds =
2519 do_GetService("@mozilla.org/widget/dragservice;1");
2520 if (ds) {
2521 gDragServiceDisabled = PR_FALSE;
2522 ds->Unsuppress();
2527 aVisitor.mParentTarget = GetParentTarget();
2528 return NS_OK;
2531 bool
2532 nsGlobalWindow::DialogOpenAttempted()
2534 nsGlobalWindow *topWindow = GetTop();
2535 if (!topWindow) {
2536 NS_ERROR("DialogOpenAttempted() called without a top window?");
2538 return false;
2541 topWindow = topWindow->GetCurrentInnerWindowInternal();
2542 if (!topWindow ||
2543 topWindow->mLastDialogQuitTime.IsNull() ||
2544 nsContentUtils::IsCallerTrustedForCapability("UniversalXPConnect")) {
2545 return false;
2548 TimeDuration dialogDuration(TimeStamp::Now() -
2549 topWindow->mLastDialogQuitTime);
2551 if (dialogDuration.ToSeconds() <
2552 nsContentUtils::GetIntPref("dom.successive_dialog_time_limit",
2553 SUCCESSIVE_DIALOG_TIME_LIMIT)) {
2554 topWindow->mDialogAbuseCount++;
2556 return (topWindow->GetPopupControlState() > openAllowed ||
2557 topWindow->mDialogAbuseCount > MAX_DIALOG_COUNT);
2560 topWindow->mDialogAbuseCount = 0;
2562 return false;
2565 bool
2566 nsGlobalWindow::AreDialogsBlocked()
2568 nsGlobalWindow *topWindow = GetTop();
2569 if (!topWindow) {
2570 NS_ASSERTION(!mDocShell, "AreDialogsBlocked() called without a top window?");
2572 return true;
2575 topWindow = topWindow->GetCurrentInnerWindowInternal();
2577 return !topWindow ||
2578 (topWindow->mDialogDisabled &&
2579 (topWindow->GetPopupControlState() > openAllowed ||
2580 topWindow->mDialogAbuseCount >= MAX_DIALOG_COUNT));
2583 bool
2584 nsGlobalWindow::ConfirmDialogAllowed()
2586 FORWARD_TO_OUTER(ConfirmDialogAllowed, (), NS_ERROR_NOT_INITIALIZED);
2588 NS_ENSURE_TRUE(mDocShell, false);
2589 nsCOMPtr<nsIPromptService> promptSvc =
2590 do_GetService("@mozilla.org/embedcomp/prompt-service;1");
2592 if (!DialogOpenAttempted() || !promptSvc) {
2593 return true;
2596 // Reset popup state while opening a modal dialog, and firing events
2597 // about the dialog, to prevent the current state from being active
2598 // the whole time a modal dialog is open.
2599 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
2601 PRBool disableDialog = PR_FALSE;
2602 nsXPIDLString label, title;
2603 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2604 "ScriptDialogLabel", label);
2605 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2606 "ScriptDialogPreventTitle", title);
2607 promptSvc->Confirm(this, title.get(), label.get(), &disableDialog);
2608 if (disableDialog) {
2609 PreventFurtherDialogs();
2610 return false;
2613 return true;
2616 void
2617 nsGlobalWindow::PreventFurtherDialogs()
2619 nsGlobalWindow *topWindow = GetTop();
2620 if (!topWindow) {
2621 NS_ERROR("PreventFurtherDialogs() called without a top window?");
2623 return;
2626 topWindow = topWindow->GetCurrentInnerWindowInternal();
2628 if (topWindow)
2629 topWindow->mDialogDisabled = PR_TRUE;
2632 nsresult
2633 nsGlobalWindow::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
2635 NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
2637 // Return early if there is nothing to do.
2638 switch (aVisitor.mEvent->message) {
2639 case NS_RESIZE_EVENT:
2640 case NS_PAGE_UNLOAD:
2641 case NS_LOAD:
2642 break;
2643 default:
2644 return NS_OK;
2647 /* mChromeEventHandler and mContext go dangling in the middle of this
2648 function under some circumstances (events that destroy the window)
2649 without this addref. */
2650 nsCOMPtr<nsPIDOMEventTarget> kungFuDeathGrip1(mChromeEventHandler);
2651 nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
2653 if (aVisitor.mEvent->message == NS_RESIZE_EVENT) {
2654 mIsHandlingResizeEvent = PR_FALSE;
2655 } else if (aVisitor.mEvent->message == NS_PAGE_UNLOAD &&
2656 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2657 // Execute bindingdetached handlers before we tear ourselves
2658 // down.
2659 if (mDocument) {
2660 NS_ASSERTION(mDoc, "Must have doc");
2661 mDoc->BindingManager()->ExecuteDetachedHandlers();
2663 mIsDocumentLoaded = PR_FALSE;
2664 } else if (aVisitor.mEvent->message == NS_LOAD &&
2665 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2666 // This is page load event since load events don't propagate to |window|.
2667 // @see nsDocument::PreHandleEvent.
2668 mIsDocumentLoaded = PR_TRUE;
2670 nsCOMPtr<nsIContent> content(do_QueryInterface(GetFrameElementInternal()));
2671 nsCOMPtr<nsIDocShellTreeItem> treeItem =
2672 do_QueryInterface(GetDocShell());
2674 PRInt32 itemType = nsIDocShellTreeItem::typeChrome;
2676 if (treeItem) {
2677 treeItem->GetItemType(&itemType);
2680 if (content && GetParentInternal() &&
2681 itemType != nsIDocShellTreeItem::typeChrome) {
2682 // If we're not in chrome, or at a chrome boundary, fire the
2683 // onload event for the frame element.
2685 nsEventStatus status = nsEventStatus_eIgnore;
2686 nsEvent event(NS_IS_TRUSTED_EVENT(aVisitor.mEvent), NS_LOAD);
2687 event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
2689 // Most of the time we could get a pres context to pass in here,
2690 // but not always (i.e. if this window is not shown there won't
2691 // be a pres context available). Since we're not firing a GUI
2692 // event we don't need a pres context anyway so we just pass
2693 // null as the pres context all the time here.
2695 nsEventDispatcher::Dispatch(content, nsnull, &event, nsnull, &status);
2699 return NS_OK;
2702 nsresult
2703 nsGlobalWindow::DispatchDOMEvent(nsEvent* aEvent,
2704 nsIDOMEvent* aDOMEvent,
2705 nsPresContext* aPresContext,
2706 nsEventStatus* aEventStatus)
2708 return
2709 nsEventDispatcher::DispatchDOMEvent(static_cast<nsPIDOMWindow*>(this),
2710 aEvent, aDOMEvent, aPresContext,
2711 aEventStatus);
2714 void
2715 nsGlobalWindow::OnFinalize(PRUint32 aLangID, void *aObject)
2717 NS_ASSERTION(aLangID == nsIProgrammingLanguage::JAVASCRIPT,
2718 "We don't support this language ID");
2720 if (aObject == mJSObject) {
2721 mJSObject = nsnull;
2725 void
2726 nsGlobalWindow::SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts)
2728 FORWARD_TO_INNER_VOID(SetScriptsEnabled, (aEnabled, aFireTimeouts));
2730 if (aEnabled && aFireTimeouts) {
2731 // Scripts are enabled (again?) on this context, run timeouts that
2732 // fired on this context while scripts were disabled.
2733 void (nsGlobalWindow::*run)() = &nsGlobalWindow::RunTimeout;
2734 NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, run));
2738 nsresult
2739 nsGlobalWindow::SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin)
2741 FORWARD_TO_OUTER(SetArguments, (aArguments, aOrigin),
2742 NS_ERROR_NOT_INITIALIZED);
2744 // Hold on to the arguments so that we can re-set them once the next
2745 // document is loaded.
2746 mArguments = aArguments;
2747 mArgumentsOrigin = aOrigin;
2749 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
2751 if (!mIsModalContentWindow) {
2752 mArgumentsLast = aArguments;
2753 } else if (currentInner) {
2754 // SetArguments() is being called on a modal content window that
2755 // already has an inner window. This can happen when loading
2756 // javascript: URIs as modal content dialogs. In this case, we'll
2757 // set up the dialog window, both inner and outer, before we call
2758 // SetArguments() on the window, so to deal with that, make sure
2759 // here that the arguments are propagated to the inner window.
2761 currentInner->mArguments = aArguments;
2762 currentInner->mArgumentsOrigin = aOrigin;
2765 return currentInner ?
2766 currentInner->DefineArgumentsProperty(aArguments) : NS_OK;
2769 nsresult
2770 nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments)
2772 JSContext *cx;
2773 nsIScriptContext *ctx = GetOuterWindowInternal()->mContext;
2774 NS_ENSURE_TRUE(aArguments && ctx &&
2775 (cx = (JSContext *)ctx->GetNativeContext()),
2776 NS_ERROR_NOT_INITIALIZED);
2778 if (mIsModalContentWindow) {
2779 // Modal content windows don't have an "arguments" property, they
2780 // have a "dialogArguments" property which is handled
2781 // separately. See nsWindowSH::NewResolve().
2783 return NS_OK;
2786 return GetContextInternal()->SetProperty(mJSObject, "arguments", aArguments);
2789 //*****************************************************************************
2790 // nsGlobalWindow::nsIScriptObjectPrincipal
2791 //*****************************************************************************
2793 nsIPrincipal*
2794 nsGlobalWindow::GetPrincipal()
2796 if (mDoc) {
2797 // If we have a document, get the principal from the document
2798 return mDoc->NodePrincipal();
2801 if (mDocumentPrincipal) {
2802 return mDocumentPrincipal;
2805 // If we don't have a principal and we don't have a document we
2806 // ask the parent window for the principal. This can happen when
2807 // loading a frameset that has a <frame src="javascript:xxx">, in
2808 // that case the global window is used in JS before we've loaded
2809 // a document into the window.
2811 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2812 do_QueryInterface(GetParentInternal());
2814 if (objPrincipal) {
2815 return objPrincipal->GetPrincipal();
2818 return nsnull;
2821 //*****************************************************************************
2822 // nsGlobalWindow::nsIDOMWindow
2823 //*****************************************************************************
2825 NS_IMETHODIMP
2826 nsGlobalWindow::GetDocument(nsIDOMDocument** aDocument)
2828 // This method *should* forward calls to the outer window, but since
2829 // there's nothing here that *depends* on anything in the outer
2830 // (GetDocShell() eliminates that dependency), we won't do that to
2831 // avoid the extra virtual function call.
2833 // lazily instantiate an about:blank document if necessary, and if
2834 // we have what it takes to do so. Note that domdoc here is the same
2835 // thing as our mDocument, but we don't have to explicitly set the
2836 // member variable because the docshell has already called
2837 // SetNewDocument().
2838 nsIDocShell *docShell;
2839 if (!mDocument && (docShell = GetDocShell()))
2840 nsCOMPtr<nsIDOMDocument> domdoc(do_GetInterface(docShell));
2842 NS_IF_ADDREF(*aDocument = mDocument);
2844 return NS_OK;
2847 //*****************************************************************************
2848 // nsGlobalWindow::nsIDOMWindowInternal
2849 //*****************************************************************************
2851 NS_IMETHODIMP
2852 nsGlobalWindow::GetWindow(nsIDOMWindowInternal** aWindow)
2854 FORWARD_TO_OUTER(GetWindow, (aWindow), NS_ERROR_NOT_INITIALIZED);
2856 *aWindow = static_cast<nsIDOMWindowInternal *>(this);
2857 NS_ADDREF(*aWindow);
2858 return NS_OK;
2861 NS_IMETHODIMP
2862 nsGlobalWindow::GetSelf(nsIDOMWindowInternal** aWindow)
2864 FORWARD_TO_OUTER(GetSelf, (aWindow), NS_ERROR_NOT_INITIALIZED);
2866 *aWindow = static_cast<nsIDOMWindowInternal *>(this);
2867 NS_ADDREF(*aWindow);
2868 return NS_OK;
2871 NS_IMETHODIMP
2872 nsGlobalWindow::GetNavigator(nsIDOMNavigator** aNavigator)
2874 FORWARD_TO_OUTER(GetNavigator, (aNavigator), NS_ERROR_NOT_INITIALIZED);
2876 *aNavigator = nsnull;
2878 if (!mNavigator) {
2879 mNavigator = new nsNavigator(mDocShell);
2880 if (!mNavigator) {
2881 return NS_ERROR_OUT_OF_MEMORY;
2885 NS_ADDREF(*aNavigator = mNavigator);
2887 return NS_OK;
2890 NS_IMETHODIMP
2891 nsGlobalWindow::GetScreen(nsIDOMScreen** aScreen)
2893 FORWARD_TO_OUTER(GetScreen, (aScreen), NS_ERROR_NOT_INITIALIZED);
2895 *aScreen = nsnull;
2897 if (!mScreen && mDocShell) {
2898 mScreen = new nsScreen(mDocShell);
2899 if (!mScreen) {
2900 return NS_ERROR_OUT_OF_MEMORY;
2904 NS_IF_ADDREF(*aScreen = mScreen);
2906 return NS_OK;
2909 NS_IMETHODIMP
2910 nsGlobalWindow::GetHistory(nsIDOMHistory** aHistory)
2912 FORWARD_TO_INNER(GetHistory, (aHistory), NS_ERROR_NOT_INITIALIZED);
2914 *aHistory = nsnull;
2916 if (!mHistory) {
2917 mHistory = new nsHistory(this);
2918 if (!mHistory) {
2919 return NS_ERROR_OUT_OF_MEMORY;
2923 NS_IF_ADDREF(*aHistory = mHistory);
2924 return NS_OK;
2927 NS_IMETHODIMP
2928 nsGlobalWindow::GetParent(nsIDOMWindow** aParent)
2930 FORWARD_TO_OUTER(GetParent, (aParent), NS_ERROR_NOT_INITIALIZED);
2932 *aParent = nsnull;
2933 if (!mDocShell)
2934 return NS_OK;
2936 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
2937 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
2939 nsCOMPtr<nsIDocShellTreeItem> parent;
2940 docShellAsItem->GetSameTypeParent(getter_AddRefs(parent));
2942 if (parent) {
2943 nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(parent));
2944 NS_ENSURE_SUCCESS(CallQueryInterface(globalObject.get(), aParent),
2945 NS_ERROR_FAILURE);
2947 else {
2948 *aParent = static_cast<nsIDOMWindowInternal *>(this);
2949 NS_ADDREF(*aParent);
2951 return NS_OK;
2954 NS_IMETHODIMP
2955 nsGlobalWindow::GetTop(nsIDOMWindow** aTop)
2957 FORWARD_TO_OUTER(GetTop, (aTop), NS_ERROR_NOT_INITIALIZED);
2959 *aTop = nsnull;
2960 if (mDocShell) {
2961 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
2962 nsCOMPtr<nsIDocShellTreeItem> root;
2963 docShellAsItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
2965 if (root) {
2966 nsCOMPtr<nsIDOMWindow> top(do_GetInterface(root));
2967 top.swap(*aTop);
2971 return NS_OK;
2974 NS_IMETHODIMP
2975 nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
2977 FORWARD_TO_OUTER(GetContent, (aContent), NS_ERROR_NOT_INITIALIZED);
2979 *aContent = nsnull;
2981 nsCOMPtr<nsIDocShellTreeItem> primaryContent;
2983 if (!nsContentUtils::IsCallerChrome()) {
2984 // If we're called by non-chrome code, make sure we don't return
2985 // the primary content window if the calling tab is hidden. In
2986 // such a case we return the same-type root in the hidden tab,
2987 // which is "good enough", for now.
2988 nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mDocShell));
2990 if (baseWin) {
2991 PRBool visible = PR_FALSE;
2992 baseWin->GetVisibility(&visible);
2994 if (!visible) {
2995 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
2997 treeItem->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));
3002 if (!primaryContent) {
3003 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
3004 GetTreeOwner(getter_AddRefs(treeOwner));
3005 NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
3007 treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
3010 nsCOMPtr<nsIDOMWindowInternal> domWindow(do_GetInterface(primaryContent));
3011 NS_IF_ADDREF(*aContent = domWindow);
3013 return NS_OK;
3016 NS_IMETHODIMP
3017 nsGlobalWindow::GetPrompter(nsIPrompt** aPrompt)
3019 FORWARD_TO_OUTER(GetPrompter, (aPrompt), NS_ERROR_NOT_INITIALIZED);
3021 if (!mDocShell)
3022 return NS_ERROR_FAILURE;
3024 nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
3025 NS_ENSURE_TRUE(prompter, NS_ERROR_NO_INTERFACE);
3027 NS_ADDREF(*aPrompt = prompter);
3028 return NS_OK;
3031 NS_IMETHODIMP
3032 nsGlobalWindow::GetMenubar(nsIDOMBarProp** aMenubar)
3034 FORWARD_TO_OUTER(GetMenubar, (aMenubar), NS_ERROR_NOT_INITIALIZED);
3036 *aMenubar = nsnull;
3038 if (!mMenubar) {
3039 mMenubar = new nsMenubarProp();
3040 if (!mMenubar) {
3041 return NS_ERROR_OUT_OF_MEMORY;
3044 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3045 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3047 mMenubar->SetWebBrowserChrome(browserChrome);
3050 NS_ADDREF(*aMenubar = mMenubar);
3052 return NS_OK;
3055 NS_IMETHODIMP
3056 nsGlobalWindow::GetToolbar(nsIDOMBarProp** aToolbar)
3058 FORWARD_TO_OUTER(GetToolbar, (aToolbar), NS_ERROR_NOT_INITIALIZED);
3060 *aToolbar = nsnull;
3062 if (!mToolbar) {
3063 mToolbar = new nsToolbarProp();
3064 if (!mToolbar) {
3065 return NS_ERROR_OUT_OF_MEMORY;
3068 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3069 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3071 mToolbar->SetWebBrowserChrome(browserChrome);
3074 NS_ADDREF(*aToolbar = mToolbar);
3076 return NS_OK;
3079 NS_IMETHODIMP
3080 nsGlobalWindow::GetLocationbar(nsIDOMBarProp** aLocationbar)
3082 FORWARD_TO_OUTER(GetLocationbar, (aLocationbar), NS_ERROR_NOT_INITIALIZED);
3084 *aLocationbar = nsnull;
3086 if (!mLocationbar) {
3087 mLocationbar = new nsLocationbarProp();
3088 if (!mLocationbar) {
3089 return NS_ERROR_OUT_OF_MEMORY;
3092 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3093 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3095 mLocationbar->SetWebBrowserChrome(browserChrome);
3098 NS_ADDREF(*aLocationbar = mLocationbar);
3100 return NS_OK;
3103 NS_IMETHODIMP
3104 nsGlobalWindow::GetPersonalbar(nsIDOMBarProp** aPersonalbar)
3106 FORWARD_TO_OUTER(GetPersonalbar, (aPersonalbar), NS_ERROR_NOT_INITIALIZED);
3108 *aPersonalbar = nsnull;
3110 if (!mPersonalbar) {
3111 mPersonalbar = new nsPersonalbarProp();
3112 if (!mPersonalbar) {
3113 return NS_ERROR_OUT_OF_MEMORY;
3116 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3117 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3119 mPersonalbar->SetWebBrowserChrome(browserChrome);
3122 NS_ADDREF(*aPersonalbar = mPersonalbar);
3124 return NS_OK;
3127 NS_IMETHODIMP
3128 nsGlobalWindow::GetStatusbar(nsIDOMBarProp** aStatusbar)
3130 FORWARD_TO_OUTER(GetStatusbar, (aStatusbar), NS_ERROR_NOT_INITIALIZED);
3132 *aStatusbar = nsnull;
3134 if (!mStatusbar) {
3135 mStatusbar = new nsStatusbarProp();
3136 if (!mStatusbar) {
3137 return NS_ERROR_OUT_OF_MEMORY;
3140 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3141 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3143 mStatusbar->SetWebBrowserChrome(browserChrome);
3146 NS_ADDREF(*aStatusbar = mStatusbar);
3148 return NS_OK;
3151 NS_IMETHODIMP
3152 nsGlobalWindow::GetScrollbars(nsIDOMBarProp** aScrollbars)
3154 FORWARD_TO_OUTER(GetScrollbars, (aScrollbars), NS_ERROR_NOT_INITIALIZED);
3156 *aScrollbars = nsnull;
3158 if (!mScrollbars) {
3159 mScrollbars = new nsScrollbarsProp(this);
3160 if (!mScrollbars) {
3161 return NS_ERROR_OUT_OF_MEMORY;
3164 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3165 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3167 mScrollbars->SetWebBrowserChrome(browserChrome);
3170 NS_ADDREF(*aScrollbars = mScrollbars);
3172 return NS_OK;
3175 NS_IMETHODIMP
3176 nsGlobalWindow::GetClosed(PRBool* aClosed)
3178 FORWARD_TO_OUTER(GetClosed, (aClosed), NS_ERROR_NOT_INITIALIZED);
3180 // If someone called close(), or if we don't have a docshell, we're
3181 // closed.
3182 *aClosed = mIsClosed || !mDocShell;
3184 return NS_OK;
3187 NS_IMETHODIMP
3188 nsGlobalWindow::GetFrames(nsIDOMWindowCollection** aFrames)
3190 FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
3192 *aFrames = nsnull;
3194 if (!mFrames && mDocShell) {
3195 mFrames = new nsDOMWindowList(mDocShell);
3196 if (!mFrames) {
3197 return NS_ERROR_OUT_OF_MEMORY;
3201 *aFrames = static_cast<nsIDOMWindowCollection *>(mFrames);
3202 NS_IF_ADDREF(*aFrames);
3203 return NS_OK;
3206 NS_IMETHODIMP
3207 nsGlobalWindow::GetApplicationCache(nsIDOMOfflineResourceList **aApplicationCache)
3209 FORWARD_TO_INNER(GetApplicationCache, (aApplicationCache), NS_ERROR_UNEXPECTED);
3211 NS_ENSURE_ARG_POINTER(aApplicationCache);
3213 if (!mApplicationCache) {
3214 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(GetDocShell()));
3215 if (!webNav) {
3216 return NS_ERROR_FAILURE;
3219 nsCOMPtr<nsIURI> uri;
3220 nsresult rv = webNav->GetCurrentURI(getter_AddRefs(uri));
3221 NS_ENSURE_SUCCESS(rv, rv);
3223 nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
3224 nsCOMPtr<nsIURI> manifestURI;
3225 nsContentUtils::GetOfflineAppManifest(doc, getter_AddRefs(manifestURI));
3227 nsIScriptContext* scriptContext = GetContext();
3228 NS_ENSURE_STATE(scriptContext);
3230 nsRefPtr<nsDOMOfflineResourceList> applicationCache =
3231 new nsDOMOfflineResourceList(manifestURI, uri, this, scriptContext);
3232 NS_ENSURE_TRUE(applicationCache, NS_ERROR_OUT_OF_MEMORY);
3234 applicationCache->Init();
3236 mApplicationCache = applicationCache;
3239 NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
3241 return NS_OK;
3244 NS_IMETHODIMP
3245 nsGlobalWindow::CreateBlobURL(nsIDOMBlob* aBlob, nsAString& aURL)
3247 return NS_ERROR_NOT_IMPLEMENTED;
3250 NS_IMETHODIMP
3251 nsGlobalWindow::RevokeBlobURL(const nsAString& aURL)
3253 return NS_ERROR_NOT_IMPLEMENTED;
3256 NS_IMETHODIMP
3257 nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
3259 #ifdef MOZ_DISABLE_DOMCRYPTO
3260 return NS_ERROR_NOT_IMPLEMENTED;
3261 #else
3262 FORWARD_TO_OUTER(GetCrypto, (aCrypto), NS_ERROR_NOT_INITIALIZED);
3264 if (!mCrypto) {
3265 mCrypto = do_CreateInstance(kCryptoContractID);
3268 NS_IF_ADDREF(*aCrypto = mCrypto);
3270 return NS_OK;
3271 #endif
3274 NS_IMETHODIMP
3275 nsGlobalWindow::GetPkcs11(nsIDOMPkcs11** aPkcs11)
3277 *aPkcs11 = nsnull;
3278 return NS_OK;
3281 NS_IMETHODIMP
3282 nsGlobalWindow::GetControllers(nsIControllers** aResult)
3284 FORWARD_TO_OUTER(GetControllers, (aResult), NS_ERROR_NOT_INITIALIZED);
3286 if (!mControllers) {
3287 nsresult rv;
3288 mControllers = do_CreateInstance(kXULControllersCID, &rv);
3289 NS_ENSURE_SUCCESS(rv, rv);
3291 // Add in the default controller
3292 nsCOMPtr<nsIController> controller = do_CreateInstance(
3293 NS_WINDOWCONTROLLER_CONTRACTID, &rv);
3294 NS_ENSURE_SUCCESS(rv, rv);
3296 mControllers->InsertControllerAt(0, controller);
3297 nsCOMPtr<nsIControllerContext> controllerContext = do_QueryInterface(controller);
3298 if (!controllerContext) return NS_ERROR_FAILURE;
3300 controllerContext->SetCommandContext(static_cast<nsIDOMWindow*>(this));
3303 *aResult = mControllers;
3304 NS_ADDREF(*aResult);
3305 return NS_OK;
3308 NS_IMETHODIMP
3309 nsGlobalWindow::GetOpener(nsIDOMWindowInternal** aOpener)
3311 FORWARD_TO_OUTER(GetOpener, (aOpener), NS_ERROR_NOT_INITIALIZED);
3313 *aOpener = nsnull;
3315 nsCOMPtr<nsPIDOMWindow> opener = do_QueryReferent(mOpener);
3316 if (!opener) {
3317 return NS_OK;
3320 // First, check if we were called from a privileged chrome script
3321 if (nsContentUtils::IsCallerTrustedForRead()) {
3322 NS_ADDREF(*aOpener = opener);
3323 return NS_OK;
3326 nsCOMPtr<nsPIDOMWindow> openerPwin(do_QueryInterface(opener));
3327 if (!openerPwin) {
3328 return NS_OK;
3331 // First, ensure that we're not handing back a chrome window.
3332 nsGlobalWindow *win = static_cast<nsGlobalWindow *>(openerPwin.get());
3333 if (win->IsChromeWindow()) {
3334 return NS_OK;
3337 // We don't want to reveal the opener if the opener is a mail window,
3338 // because opener can be used to spoof the contents of a message (bug 105050).
3339 // So, we look in the opener's root docshell to see if it's a mail window.
3340 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
3341 do_QueryInterface(openerPwin->GetDocShell());
3343 if (docShellAsItem) {
3344 nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
3345 docShellAsItem->GetRootTreeItem(getter_AddRefs(openerRootItem));
3346 nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
3347 if (openerRootDocShell) {
3348 PRUint32 appType;
3349 nsresult rv = openerRootDocShell->GetAppType(&appType);
3350 if (NS_SUCCEEDED(rv) && appType != nsIDocShell::APP_TYPE_MAIL) {
3351 *aOpener = opener;
3356 NS_IF_ADDREF(*aOpener);
3357 return NS_OK;
3360 NS_IMETHODIMP
3361 nsGlobalWindow::SetOpener(nsIDOMWindowInternal* aOpener)
3363 // check if we were called from a privileged chrome script.
3364 // If not, opener is settable only to null.
3365 if (aOpener && !nsContentUtils::IsCallerTrustedForWrite()) {
3366 return NS_OK;
3369 SetOpenerWindow(aOpener, PR_FALSE);
3371 return NS_OK;
3374 NS_IMETHODIMP
3375 nsGlobalWindow::GetStatus(nsAString& aStatus)
3377 FORWARD_TO_OUTER(GetStatus, (aStatus), NS_ERROR_NOT_INITIALIZED);
3379 aStatus = mStatus;
3380 return NS_OK;
3383 NS_IMETHODIMP
3384 nsGlobalWindow::SetStatus(const nsAString& aStatus)
3386 FORWARD_TO_OUTER(SetStatus, (aStatus), NS_ERROR_NOT_INITIALIZED);
3389 * If caller is not chrome and dom.disable_window_status_change is true,
3390 * prevent setting window.status by exiting early
3393 if (!CanSetProperty("dom.disable_window_status_change")) {
3394 return NS_OK;
3397 mStatus = aStatus;
3399 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3400 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3401 if(browserChrome) {
3402 browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
3403 PromiseFlatString(aStatus).get());
3406 return NS_OK;
3409 NS_IMETHODIMP
3410 nsGlobalWindow::GetDefaultStatus(nsAString& aDefaultStatus)
3412 FORWARD_TO_OUTER(GetDefaultStatus, (aDefaultStatus),
3413 NS_ERROR_NOT_INITIALIZED);
3415 aDefaultStatus = mDefaultStatus;
3416 return NS_OK;
3419 NS_IMETHODIMP
3420 nsGlobalWindow::SetDefaultStatus(const nsAString& aDefaultStatus)
3422 FORWARD_TO_OUTER(SetDefaultStatus, (aDefaultStatus),
3423 NS_ERROR_NOT_INITIALIZED);
3426 * If caller is not chrome and dom.disable_window_status_change is true,
3427 * prevent setting window.defaultStatus by exiting early
3430 if (!CanSetProperty("dom.disable_window_status_change")) {
3431 return NS_OK;
3434 mDefaultStatus = aDefaultStatus;
3436 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3437 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3438 if (browserChrome) {
3439 browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT_DEFAULT,
3440 PromiseFlatString(aDefaultStatus).get());
3443 return NS_OK;
3446 NS_IMETHODIMP
3447 nsGlobalWindow::GetName(nsAString& aName)
3449 FORWARD_TO_OUTER(GetName, (aName), NS_ERROR_NOT_INITIALIZED);
3451 nsXPIDLString name;
3452 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3453 if (docShellAsItem)
3454 docShellAsItem->GetName(getter_Copies(name));
3456 aName.Assign(name);
3457 return NS_OK;
3460 NS_IMETHODIMP
3461 nsGlobalWindow::SetName(const nsAString& aName)
3463 FORWARD_TO_OUTER(SetName, (aName), NS_ERROR_NOT_INITIALIZED);
3465 nsresult result = NS_OK;
3466 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3467 if (docShellAsItem)
3468 result = docShellAsItem->SetName(PromiseFlatString(aName).get());
3469 return result;
3472 // Helper functions used by many methods below.
3473 PRInt32
3474 nsGlobalWindow::DevToCSSIntPixels(PRInt32 px)
3476 if (!mDocShell)
3477 return px; // assume 1:1
3479 nsRefPtr<nsPresContext> presContext;
3480 mDocShell->GetPresContext(getter_AddRefs(presContext));
3481 if (!presContext)
3482 return px;
3484 return presContext->DevPixelsToIntCSSPixels(px);
3487 PRInt32
3488 nsGlobalWindow::CSSToDevIntPixels(PRInt32 px)
3490 if (!mDocShell)
3491 return px; // assume 1:1
3493 nsRefPtr<nsPresContext> presContext;
3494 mDocShell->GetPresContext(getter_AddRefs(presContext));
3495 if (!presContext)
3496 return px;
3498 return presContext->CSSPixelsToDevPixels(px);
3501 nsIntSize
3502 nsGlobalWindow::DevToCSSIntPixels(nsIntSize px)
3504 if (!mDocShell)
3505 return px; // assume 1:1
3507 nsRefPtr<nsPresContext> presContext;
3508 mDocShell->GetPresContext(getter_AddRefs(presContext));
3509 if (!presContext)
3510 return px;
3512 return nsIntSize(
3513 presContext->DevPixelsToIntCSSPixels(px.width),
3514 presContext->DevPixelsToIntCSSPixels(px.height));
3517 nsIntSize
3518 nsGlobalWindow::CSSToDevIntPixels(nsIntSize px)
3520 if (!mDocShell)
3521 return px; // assume 1:1
3523 nsRefPtr<nsPresContext> presContext;
3524 mDocShell->GetPresContext(getter_AddRefs(presContext));
3525 if (!presContext)
3526 return px;
3528 return nsIntSize(
3529 presContext->CSSPixelsToDevPixels(px.width),
3530 presContext->CSSPixelsToDevPixels(px.height));
3534 NS_IMETHODIMP
3535 nsGlobalWindow::GetInnerWidth(PRInt32* aInnerWidth)
3537 FORWARD_TO_OUTER(GetInnerWidth, (aInnerWidth), NS_ERROR_NOT_INITIALIZED);
3539 NS_ENSURE_STATE(mDocShell);
3541 EnsureSizeUpToDate();
3543 nsRefPtr<nsPresContext> presContext;
3544 mDocShell->GetPresContext(getter_AddRefs(presContext));
3546 if (presContext) {
3547 nsRect shellArea = presContext->GetVisibleArea();
3548 *aInnerWidth = nsPresContext::AppUnitsToIntCSSPixels(shellArea.width);
3549 } else {
3550 *aInnerWidth = 0;
3553 return NS_OK;
3556 NS_IMETHODIMP
3557 nsGlobalWindow::SetInnerWidth(PRInt32 aInnerWidth)
3559 FORWARD_TO_OUTER(SetInnerWidth, (aInnerWidth), NS_ERROR_NOT_INITIALIZED);
3561 NS_ENSURE_STATE(mDocShell);
3564 * If caller is not chrome and the user has not explicitly exempted the site,
3565 * prevent setting window.innerWidth by exiting early
3567 if (!CanMoveResizeWindows() || IsFrame()) {
3568 return NS_OK;
3571 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&aInnerWidth, nsnull),
3572 NS_ERROR_FAILURE);
3575 nsRefPtr<nsIPresShell> presShell;
3576 mDocShell->GetPresShell(getter_AddRefs(presShell));
3577 nsCOMPtr<nsIPresShell_MOZILLA_2_0_BRANCH> presShell20 =
3578 do_QueryInterface(presShell);
3580 if (presShell20 && presShell20->GetIsViewportOverridden())
3582 nscoord height = 0;
3583 nscoord width = 0;
3585 nsRefPtr<nsPresContext> presContext;
3586 presContext = presShell->GetPresContext();
3588 nsRect shellArea = presContext->GetVisibleArea();
3589 height = shellArea.height;
3590 width = nsPresContext::CSSPixelsToAppUnits(aInnerWidth);
3591 return SetCSSViewportWidthAndHeight(width, height);
3593 else
3595 PRInt32 height = 0;
3596 PRInt32 width = 0;
3598 nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
3599 docShellAsWin->GetSize(&width, &height);
3600 width = CSSToDevIntPixels(aInnerWidth);
3601 return SetDocShellWidthAndHeight(width, height);
3605 NS_IMETHODIMP
3606 nsGlobalWindow::GetInnerHeight(PRInt32* aInnerHeight)
3608 FORWARD_TO_OUTER(GetInnerHeight, (aInnerHeight), NS_ERROR_NOT_INITIALIZED);
3610 NS_ENSURE_STATE(mDocShell);
3612 EnsureSizeUpToDate();
3614 nsRefPtr<nsPresContext> presContext;
3615 mDocShell->GetPresContext(getter_AddRefs(presContext));
3617 if (presContext) {
3618 nsRect shellArea = presContext->GetVisibleArea();
3619 *aInnerHeight = nsPresContext::AppUnitsToIntCSSPixels(shellArea.height);
3620 } else {
3621 *aInnerHeight = 0;
3623 return NS_OK;
3626 NS_IMETHODIMP
3627 nsGlobalWindow::SetInnerHeight(PRInt32 aInnerHeight)
3629 FORWARD_TO_OUTER(SetInnerHeight, (aInnerHeight), NS_ERROR_NOT_INITIALIZED);
3631 NS_ENSURE_STATE(mDocShell);
3634 * If caller is not chrome and the user has not explicitly exempted the site,
3635 * prevent setting window.innerHeight by exiting early
3637 if (!CanMoveResizeWindows() || IsFrame()) {
3638 return NS_OK;
3641 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(nsnull, &aInnerHeight),
3642 NS_ERROR_FAILURE);
3644 nsRefPtr<nsIPresShell> presShell;
3645 mDocShell->GetPresShell(getter_AddRefs(presShell));
3646 nsCOMPtr<nsIPresShell_MOZILLA_2_0_BRANCH> presShell20 =
3647 do_QueryInterface(presShell);
3649 if (presShell20 && presShell20->GetIsViewportOverridden())
3651 nscoord height = 0;
3652 nscoord width = 0;
3654 nsRefPtr<nsPresContext> presContext;
3655 presContext = presShell->GetPresContext();
3657 nsRect shellArea = presContext->GetVisibleArea();
3658 width = shellArea.width;
3659 height = nsPresContext::CSSPixelsToAppUnits(aInnerHeight);
3660 return SetCSSViewportWidthAndHeight(width, height);
3662 else
3664 PRInt32 height = 0;
3665 PRInt32 width = 0;
3667 nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
3668 docShellAsWin->GetSize(&width, &height);
3669 height = CSSToDevIntPixels(aInnerHeight);
3670 return SetDocShellWidthAndHeight(width, height);
3674 nsresult
3675 nsGlobalWindow::GetOuterSize(nsIntSize* aSizeCSSPixels)
3677 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3678 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3679 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3681 nsGlobalWindow* rootWindow =
3682 static_cast<nsGlobalWindow *>(GetPrivateRoot());
3683 if (rootWindow) {
3684 rootWindow->FlushPendingNotifications(Flush_Layout);
3687 nsIntSize sizeDevPixels;
3688 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&sizeDevPixels.width,
3689 &sizeDevPixels.height),
3690 NS_ERROR_FAILURE);
3692 *aSizeCSSPixels = DevToCSSIntPixels(sizeDevPixels);
3693 return NS_OK;
3696 NS_IMETHODIMP
3697 nsGlobalWindow::GetOuterWidth(PRInt32* aOuterWidth)
3699 FORWARD_TO_OUTER(GetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
3701 nsIntSize sizeCSSPixels;
3702 nsresult rv = GetOuterSize(&sizeCSSPixels);
3703 NS_ENSURE_SUCCESS(rv, rv);
3705 *aOuterWidth = sizeCSSPixels.width;
3706 return NS_OK;
3709 NS_IMETHODIMP
3710 nsGlobalWindow::GetOuterHeight(PRInt32* aOuterHeight)
3712 FORWARD_TO_OUTER(GetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
3714 nsIntSize sizeCSSPixels;
3715 nsresult rv = GetOuterSize(&sizeCSSPixels);
3716 NS_ENSURE_SUCCESS(rv, rv);
3718 *aOuterHeight = sizeCSSPixels.height;
3719 return NS_OK;
3722 nsresult
3723 nsGlobalWindow::SetOuterSize(PRInt32 aLengthCSSPixels, PRBool aIsWidth)
3726 * If caller is not chrome and the user has not explicitly exempted the site,
3727 * prevent setting window.outerWidth by exiting early
3730 if (!CanMoveResizeWindows() || IsFrame()) {
3731 return NS_OK;
3734 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3735 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3736 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3738 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(
3739 aIsWidth ? &aLengthCSSPixels : nsnull,
3740 aIsWidth ? nsnull : &aLengthCSSPixels),
3741 NS_ERROR_FAILURE);
3743 PRInt32 width, height;
3744 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&width, &height), NS_ERROR_FAILURE);
3746 PRInt32 lengthDevPixels = CSSToDevIntPixels(aLengthCSSPixels);
3747 if (aIsWidth) {
3748 width = lengthDevPixels;
3749 } else {
3750 height = lengthDevPixels;
3752 return treeOwnerAsWin->SetSize(width, height, PR_TRUE);
3755 NS_IMETHODIMP
3756 nsGlobalWindow::SetOuterWidth(PRInt32 aOuterWidth)
3758 FORWARD_TO_OUTER(SetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
3760 return SetOuterSize(aOuterWidth, PR_TRUE);
3763 NS_IMETHODIMP
3764 nsGlobalWindow::SetOuterHeight(PRInt32 aOuterHeight)
3766 FORWARD_TO_OUTER(SetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
3768 return SetOuterSize(aOuterHeight, PR_FALSE);
3771 NS_IMETHODIMP
3772 nsGlobalWindow::GetScreenX(PRInt32* aScreenX)
3774 FORWARD_TO_OUTER(GetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3776 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3777 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3778 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3780 PRInt32 x, y;
3782 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3783 NS_ERROR_FAILURE);
3785 *aScreenX = DevToCSSIntPixels(x);
3786 return NS_OK;
3789 nsRect
3790 nsGlobalWindow::GetInnerScreenRect()
3792 if (!mDocShell)
3793 return nsRect();
3795 nsGlobalWindow* rootWindow =
3796 static_cast<nsGlobalWindow*>(GetPrivateRoot());
3797 if (rootWindow) {
3798 rootWindow->FlushPendingNotifications(Flush_Layout);
3801 nsCOMPtr<nsIPresShell> presShell;
3802 mDocShell->GetPresShell(getter_AddRefs(presShell));
3803 if (!presShell)
3804 return nsRect();
3805 nsIFrame* rootFrame = presShell->GetRootFrame();
3806 if (!rootFrame)
3807 return nsRect();
3809 return rootFrame->GetScreenRectInAppUnits();
3812 NS_IMETHODIMP
3813 nsGlobalWindow::GetMozInnerScreenX(float* aScreenX)
3815 FORWARD_TO_OUTER(GetMozInnerScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3817 nsRect r = GetInnerScreenRect();
3818 *aScreenX = nsPresContext::AppUnitsToFloatCSSPixels(r.x);
3819 return NS_OK;
3822 NS_IMETHODIMP
3823 nsGlobalWindow::GetMozInnerScreenY(float* aScreenY)
3825 FORWARD_TO_OUTER(GetMozInnerScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
3827 nsRect r = GetInnerScreenRect();
3828 *aScreenY = nsPresContext::AppUnitsToFloatCSSPixels(r.y);
3829 return NS_OK;
3832 NS_IMETHODIMP
3833 nsGlobalWindow::GetMozPaintCount(PRUint64* aResult)
3835 FORWARD_TO_OUTER(GetMozPaintCount, (aResult), NS_ERROR_NOT_INITIALIZED);
3837 *aResult = 0;
3839 if (!mDocShell)
3840 return NS_OK;
3842 nsCOMPtr<nsIPresShell> presShell;
3843 mDocShell->GetPresShell(getter_AddRefs(presShell));
3844 if (!presShell)
3845 return NS_OK;
3847 *aResult = presShell->GetPaintCount();
3848 return NS_OK;
3851 NS_IMETHODIMP
3852 nsGlobalWindow::MozRequestAnimationFrame(nsIAnimationFrameListener* aListener)
3854 FORWARD_TO_INNER(MozRequestAnimationFrame, (aListener),
3855 NS_ERROR_NOT_INITIALIZED);
3857 if (!mDoc) {
3858 return NS_OK;
3861 mDoc->ScheduleBeforePaintEvent(aListener);
3862 return NS_OK;
3865 NS_IMETHODIMP
3866 nsGlobalWindow::GetMozAnimationStartTime(PRInt64 *aTime)
3868 FORWARD_TO_INNER(GetMozAnimationStartTime, (aTime), NS_ERROR_NOT_INITIALIZED);
3870 if (mDoc) {
3871 nsIPresShell* presShell = mDoc->GetShell();
3872 if (presShell) {
3873 *aTime = presShell->GetPresContext()->RefreshDriver()->
3874 MostRecentRefreshEpochTime() / PR_USEC_PER_MSEC;
3875 return NS_OK;
3879 // If all else fails, just be compatible with Date.now()
3880 *aTime = JS_Now() / PR_USEC_PER_MSEC;
3881 return NS_OK;
3884 NS_IMETHODIMP
3885 nsGlobalWindow::SetScreenX(PRInt32 aScreenX)
3887 FORWARD_TO_OUTER(SetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3890 * If caller is not chrome and the user has not explicitly exempted the site,
3891 * prevent setting window.screenX by exiting early
3894 if (!CanMoveResizeWindows() || IsFrame()) {
3895 return NS_OK;
3898 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3899 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3900 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3902 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&aScreenX, nsnull),
3903 NS_ERROR_FAILURE);
3905 PRInt32 x, y;
3906 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3907 NS_ERROR_FAILURE);
3909 x = CSSToDevIntPixels(aScreenX);
3911 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(x, y),
3912 NS_ERROR_FAILURE);
3914 return NS_OK;
3917 NS_IMETHODIMP
3918 nsGlobalWindow::GetScreenY(PRInt32* aScreenY)
3920 FORWARD_TO_OUTER(GetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
3922 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3923 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3924 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3926 PRInt32 x, y;
3928 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3929 NS_ERROR_FAILURE);
3931 *aScreenY = DevToCSSIntPixels(y);
3932 return NS_OK;
3935 NS_IMETHODIMP
3936 nsGlobalWindow::SetScreenY(PRInt32 aScreenY)
3938 FORWARD_TO_OUTER(SetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
3941 * If caller is not chrome and the user has not explicitly exempted the site,
3942 * prevent setting window.screenY by exiting early
3945 if (!CanMoveResizeWindows() || IsFrame()) {
3946 return NS_OK;
3949 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3950 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3951 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3953 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(nsnull, &aScreenY),
3954 NS_ERROR_FAILURE);
3956 PRInt32 x, y;
3957 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3958 NS_ERROR_FAILURE);
3960 y = CSSToDevIntPixels(aScreenY);
3962 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(x, y),
3963 NS_ERROR_FAILURE);
3965 return NS_OK;
3968 // NOTE: Arguments to this function should have values scaled to
3969 // CSS pixels, not device pixels.
3970 nsresult
3971 nsGlobalWindow::CheckSecurityWidthAndHeight(PRInt32* aWidth, PRInt32* aHeight)
3973 #ifdef MOZ_XUL
3974 if (!nsContentUtils::IsCallerTrustedForWrite()) {
3975 // if attempting to resize the window, hide any open popups
3976 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
3977 nsContentUtils::HidePopupsInDocument(doc);
3979 #endif
3981 // This one is easy. Just ensure the variable is greater than 100;
3982 if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
3983 // Check security state for use in determing window dimensions
3985 if (!nsContentUtils::IsCallerTrustedForWrite()) {
3986 //sec check failed
3987 if (aWidth && *aWidth < 100) {
3988 *aWidth = 100;
3990 if (aHeight && *aHeight < 100) {
3991 *aHeight = 100;
3996 return NS_OK;
3999 // NOTE: Arguments to this function should have values in device pixels
4000 nsresult
4001 nsGlobalWindow::SetDocShellWidthAndHeight(PRInt32 aInnerWidth, PRInt32 aInnerHeight)
4003 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
4004 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
4006 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
4007 docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
4008 NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
4010 NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(docShellAsItem, aInnerWidth, aInnerHeight),
4011 NS_ERROR_FAILURE);
4013 return NS_OK;
4016 // NOTE: Arguments to this function should have values in app units
4017 nsresult
4018 nsGlobalWindow::SetCSSViewportWidthAndHeight(nscoord aInnerWidth, nscoord aInnerHeight)
4020 nsRefPtr<nsPresContext> presContext;
4021 mDocShell->GetPresContext(getter_AddRefs(presContext));
4023 nsRect shellArea = presContext->GetVisibleArea();
4024 shellArea.height = aInnerHeight;
4025 shellArea.width = aInnerWidth;
4027 presContext->SetVisibleArea(shellArea);
4028 return NS_OK;
4031 // NOTE: Arguments to this function should have values scaled to
4032 // CSS pixels, not device pixels.
4033 nsresult
4034 nsGlobalWindow::CheckSecurityLeftAndTop(PRInt32* aLeft, PRInt32* aTop)
4036 // This one is harder. We have to get the screen size and window dimensions.
4038 // Check security state for use in determing window dimensions
4040 if (!nsContentUtils::IsCallerTrustedForWrite()) {
4041 #ifdef MOZ_XUL
4042 // if attempting to move the window, hide any open popups
4043 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
4044 nsContentUtils::HidePopupsInDocument(doc);
4045 #endif
4047 nsGlobalWindow* rootWindow =
4048 static_cast<nsGlobalWindow*>(GetPrivateRoot());
4049 if (rootWindow) {
4050 rootWindow->FlushPendingNotifications(Flush_Layout);
4053 nsCOMPtr<nsIBaseWindow> treeOwner;
4054 GetTreeOwner(getter_AddRefs(treeOwner));
4056 nsCOMPtr<nsIDOMScreen> screen;
4057 GetScreen(getter_AddRefs(screen));
4059 if (treeOwner && screen) {
4060 PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
4061 PRInt32 winLeft, winTop, winWidth, winHeight;
4063 // Get the window size
4064 treeOwner->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
4066 // convert those values to CSS pixels
4067 // XXX four separate retrievals of the prescontext
4068 winLeft = DevToCSSIntPixels(winLeft);
4069 winTop = DevToCSSIntPixels(winTop);
4070 winWidth = DevToCSSIntPixels(winWidth);
4071 winHeight = DevToCSSIntPixels(winHeight);
4073 // Get the screen dimensions
4074 // XXX This should use nsIScreenManager once it's fully fleshed out.
4075 screen->GetAvailLeft(&screenLeft);
4076 screen->GetAvailWidth(&screenWidth);
4077 screen->GetAvailHeight(&screenHeight);
4078 #if defined(XP_MAC) || defined(XP_MACOSX)
4079 /* The mac's coordinate system is different from the assumed Windows'
4080 system. It offsets by the height of the menubar so that a window
4081 placed at (0,0) will be entirely visible. Unfortunately that
4082 correction is made elsewhere (in Widget) and the meaning of
4083 the Avail... coordinates is overloaded. Here we allow a window
4084 to be placed at (0,0) because it does make sense to do so.
4086 screen->GetTop(&screenTop);
4087 #else
4088 screen->GetAvailTop(&screenTop);
4089 #endif
4091 if (aLeft) {
4092 if (screenLeft+screenWidth < *aLeft+winWidth)
4093 *aLeft = screenLeft+screenWidth - winWidth;
4094 if (screenLeft > *aLeft)
4095 *aLeft = screenLeft;
4097 if (aTop) {
4098 if (screenTop+screenHeight < *aTop+winHeight)
4099 *aTop = screenTop+screenHeight - winHeight;
4100 if (screenTop > *aTop)
4101 *aTop = screenTop;
4103 } else {
4104 if (aLeft)
4105 *aLeft = 0;
4106 if (aTop)
4107 *aTop = 0;
4111 return NS_OK;
4114 NS_IMETHODIMP
4115 nsGlobalWindow::GetPageXOffset(PRInt32* aPageXOffset)
4117 return GetScrollX(aPageXOffset);
4120 NS_IMETHODIMP
4121 nsGlobalWindow::GetPageYOffset(PRInt32* aPageYOffset)
4123 return GetScrollY(aPageYOffset);
4126 nsresult
4127 nsGlobalWindow::GetScrollMaxXY(PRInt32* aScrollMaxX, PRInt32* aScrollMaxY)
4129 FORWARD_TO_OUTER(GetScrollMaxXY, (aScrollMaxX, aScrollMaxY),
4130 NS_ERROR_NOT_INITIALIZED);
4132 FlushPendingNotifications(Flush_Layout);
4133 nsIScrollableFrame *sf = GetScrollFrame();
4134 if (!sf)
4135 return NS_OK;
4137 nsRect scrollRange = sf->GetScrollRange();
4139 if (aScrollMaxX)
4140 *aScrollMaxX = NS_MAX(0,
4141 (PRInt32)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.XMost())));
4142 if (aScrollMaxY)
4143 *aScrollMaxY = NS_MAX(0,
4144 (PRInt32)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.YMost())));
4146 return NS_OK;
4149 NS_IMETHODIMP
4150 nsGlobalWindow::GetScrollMaxX(PRInt32* aScrollMaxX)
4152 NS_ENSURE_ARG_POINTER(aScrollMaxX);
4153 *aScrollMaxX = 0;
4154 return GetScrollMaxXY(aScrollMaxX, nsnull);
4157 NS_IMETHODIMP
4158 nsGlobalWindow::GetScrollMaxY(PRInt32* aScrollMaxY)
4160 NS_ENSURE_ARG_POINTER(aScrollMaxY);
4161 *aScrollMaxY = 0;
4162 return GetScrollMaxXY(nsnull, aScrollMaxY);
4165 nsresult
4166 nsGlobalWindow::GetScrollXY(PRInt32* aScrollX, PRInt32* aScrollY,
4167 PRBool aDoFlush)
4169 FORWARD_TO_OUTER(GetScrollXY, (aScrollX, aScrollY, aDoFlush),
4170 NS_ERROR_NOT_INITIALIZED);
4172 if (aDoFlush) {
4173 FlushPendingNotifications(Flush_Layout);
4174 } else {
4175 EnsureSizeUpToDate();
4178 nsIScrollableFrame *sf = GetScrollFrame();
4179 if (!sf)
4180 return NS_OK;
4182 nsPoint scrollPos = sf->GetScrollPosition();
4183 if (scrollPos != nsPoint(0,0) && !aDoFlush) {
4184 // Oh, well. This is the expensive case -- the window is scrolled and we
4185 // didn't actually flush yet. Repeat, but with a flush, since the content
4186 // may get shorter and hence our scroll position may decrease.
4187 return GetScrollXY(aScrollX, aScrollY, PR_TRUE);
4190 if (aScrollX)
4191 *aScrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x);
4192 if (aScrollY)
4193 *aScrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
4195 return NS_OK;
4198 NS_IMETHODIMP
4199 nsGlobalWindow::GetScrollX(PRInt32* aScrollX)
4201 NS_ENSURE_ARG_POINTER(aScrollX);
4202 *aScrollX = 0;
4203 return GetScrollXY(aScrollX, nsnull, PR_FALSE);
4206 NS_IMETHODIMP
4207 nsGlobalWindow::GetScrollY(PRInt32* aScrollY)
4209 NS_ENSURE_ARG_POINTER(aScrollY);
4210 *aScrollY = 0;
4211 return GetScrollXY(nsnull, aScrollY, PR_FALSE);
4214 NS_IMETHODIMP
4215 nsGlobalWindow::GetLength(PRUint32* aLength)
4217 nsCOMPtr<nsIDOMWindowCollection> frames;
4218 if (NS_SUCCEEDED(GetFrames(getter_AddRefs(frames))) && frames) {
4219 return frames->GetLength(aLength);
4221 return NS_ERROR_FAILURE;
4224 PRBool
4225 nsGlobalWindow::DispatchCustomEvent(const char *aEventName)
4227 PRBool defaultActionEnabled = PR_TRUE;
4228 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
4229 nsContentUtils::DispatchTrustedEvent(doc,
4230 static_cast<nsIScriptGlobalObject*>(this),
4231 NS_ConvertASCIItoUTF16(aEventName),
4232 PR_TRUE, PR_TRUE, &defaultActionEnabled);
4234 return defaultActionEnabled;
4237 static already_AddRefed<nsIDocShellTreeItem>
4238 GetCallerDocShellTreeItem()
4240 JSContext *cx = nsContentUtils::GetCurrentJSContext();
4241 nsIDocShellTreeItem *callerItem = nsnull;
4243 if (cx) {
4244 nsCOMPtr<nsIWebNavigation> callerWebNav =
4245 do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
4247 if (callerWebNav) {
4248 CallQueryInterface(callerWebNav, &callerItem);
4252 return callerItem;
4255 PRBool
4256 nsGlobalWindow::WindowExists(const nsAString& aName,
4257 PRBool aLookForCallerOnJSStack)
4259 NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
4260 NS_PRECONDITION(mDocShell, "Must have docshell");
4262 nsCOMPtr<nsIDocShellTreeItem> caller;
4263 if (aLookForCallerOnJSStack) {
4264 caller = GetCallerDocShellTreeItem();
4267 nsCOMPtr<nsIDocShellTreeItem> docShell = do_QueryInterface(mDocShell);
4268 NS_ASSERTION(docShell,
4269 "Docshell doesn't implement nsIDocShellTreeItem?");
4271 if (!caller) {
4272 caller = docShell;
4275 nsCOMPtr<nsIDocShellTreeItem> namedItem;
4276 docShell->FindItemWithName(PromiseFlatString(aName).get(), nsnull, caller,
4277 getter_AddRefs(namedItem));
4278 return namedItem != nsnull;
4281 already_AddRefed<nsIWidget>
4282 nsGlobalWindow::GetMainWidget()
4284 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4285 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4287 nsIWidget *widget = nsnull;
4289 if (treeOwnerAsWin) {
4290 treeOwnerAsWin->GetMainWidget(&widget);
4293 return widget;
4296 nsIWidget*
4297 nsGlobalWindow::GetNearestWidget()
4299 nsIDocShell* docShell = GetDocShell();
4300 NS_ENSURE_TRUE(docShell, nsnull);
4301 nsCOMPtr<nsIPresShell> presShell;
4302 docShell->GetPresShell(getter_AddRefs(presShell));
4303 NS_ENSURE_TRUE(presShell, nsnull);
4304 nsIFrame* rootFrame = presShell->GetRootFrame();
4305 NS_ENSURE_TRUE(rootFrame, nsnull);
4306 return rootFrame->GetView()->GetNearestWidget(nsnull);
4309 NS_IMETHODIMP
4310 nsGlobalWindow::SetFullScreen(PRBool aFullScreen)
4312 FORWARD_TO_OUTER(SetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
4314 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
4316 PRBool rootWinFullScreen;
4317 GetFullScreen(&rootWinFullScreen);
4318 // Only chrome can change our fullScreen mode.
4319 if (aFullScreen == rootWinFullScreen ||
4320 !nsContentUtils::IsCallerTrustedForWrite()) {
4321 return NS_OK;
4324 // SetFullScreen needs to be called on the root window, so get that
4325 // via the DocShell tree, and if we are not already the root,
4326 // call SetFullScreen on that window instead.
4327 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
4328 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4329 treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
4330 nsCOMPtr<nsIDOMWindowInternal> window = do_GetInterface(rootItem);
4331 if (!window)
4332 return NS_ERROR_FAILURE;
4333 if (rootItem != treeItem)
4334 return window->SetFullScreen(aFullScreen);
4336 // make sure we don't try to set full screen on a non-chrome window,
4337 // which might happen in embedding world
4338 PRInt32 itemType;
4339 treeItem->GetItemType(&itemType);
4340 if (itemType != nsIDocShellTreeItem::typeChrome)
4341 return NS_ERROR_FAILURE;
4343 // If we are already in full screen mode, just return.
4344 if (mFullScreen == aFullScreen)
4345 return NS_OK;
4347 // dispatch a "fullscreen" DOM event so that XUL apps can
4348 // respond visually if we are kicked into full screen mode
4349 if (!DispatchCustomEvent("fullscreen")) {
4350 return NS_OK;
4353 // Prevent chrome documents which are still loading from resizing
4354 // the window after we set fullscreen mode.
4355 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4356 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4357 nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwnerAsWin));
4358 if (aFullScreen && xulWin) {
4359 xulWin->SetIntrinsicallySized(PR_FALSE);
4362 // Set this before so if widget sends an event indicating its
4363 // gone full screen, the state trap above works.
4364 mFullScreen = aFullScreen;
4366 nsCOMPtr<nsIWidget> widget = GetMainWidget();
4367 if (widget)
4368 widget->MakeFullScreen(aFullScreen);
4370 return NS_OK;
4373 NS_IMETHODIMP
4374 nsGlobalWindow::GetFullScreen(PRBool* aFullScreen)
4376 FORWARD_TO_OUTER(GetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
4378 // Get the fullscreen value of the root window, to always have the value
4379 // accurate, even when called from content.
4380 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
4381 if (treeItem) {
4382 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4383 treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
4384 if (rootItem != treeItem) {
4385 nsCOMPtr<nsIDOMWindowInternal> window = do_GetInterface(rootItem);
4386 if (window)
4387 return window->GetFullScreen(aFullScreen);
4391 // We are the root window, or something went wrong. Return our internal value.
4392 *aFullScreen = mFullScreen;
4393 return NS_OK;
4396 PRBool
4397 nsGlobalWindow::DOMWindowDumpEnabled()
4399 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
4400 // In optimized builds we check a pref that controls if we should
4401 // enable output from dump() or not, in debug builds it's always
4402 // enabled.
4403 return gDOMWindowDumpEnabled;
4404 #else
4405 return PR_TRUE;
4406 #endif
4409 NS_IMETHODIMP
4410 nsGlobalWindow::Dump(const nsAString& aStr)
4412 if (!DOMWindowDumpEnabled()) {
4413 return NS_OK;
4416 char *cstr = ToNewUTF8String(aStr);
4418 #if defined(XP_MAC) || defined(XP_MACOSX)
4419 // have to convert \r to \n so that printing to the console works
4420 char *c = cstr, *cEnd = cstr + strlen(cstr);
4421 while (c < cEnd) {
4422 if (*c == '\r')
4423 *c = '\n';
4424 c++;
4426 #endif
4428 if (cstr) {
4429 FILE *fp = gDumpFile ? gDumpFile : stdout;
4430 fputs(cstr, fp);
4431 fflush(fp);
4432 nsMemory::Free(cstr);
4435 return NS_OK;
4438 void
4439 nsGlobalWindow::EnsureReflowFlushAndPaint()
4441 NS_ASSERTION(IsOuterWindow(), "EnsureReflowFlushAndPaint() must be called on"
4442 "the outer window");
4443 NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no "
4444 "docshell!");
4446 if (!mDocShell)
4447 return;
4449 nsCOMPtr<nsIPresShell> presShell;
4450 mDocShell->GetPresShell(getter_AddRefs(presShell));
4452 if (!presShell)
4453 return;
4455 // Flush pending reflows.
4456 if (mDoc) {
4457 mDoc->FlushPendingNotifications(Flush_Layout);
4460 // Unsuppress painting.
4461 presShell->UnsuppressPainting();
4464 NS_IMETHODIMP
4465 nsGlobalWindow::GetTextZoom(float *aZoom)
4467 FORWARD_TO_OUTER(GetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
4469 if (mDocShell) {
4470 nsCOMPtr<nsIContentViewer> contentViewer;
4471 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
4472 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
4474 if (markupViewer) {
4475 return markupViewer->GetTextZoom(aZoom);
4478 return NS_ERROR_FAILURE;
4481 NS_IMETHODIMP
4482 nsGlobalWindow::SetTextZoom(float aZoom)
4484 FORWARD_TO_OUTER(SetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
4486 if (mDocShell) {
4487 nsCOMPtr<nsIContentViewer> contentViewer;
4488 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
4489 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
4491 if (markupViewer)
4492 return markupViewer->SetTextZoom(aZoom);
4494 return NS_ERROR_FAILURE;
4497 // static
4498 void
4499 nsGlobalWindow::MakeScriptDialogTitle(nsAString &aOutTitle)
4501 aOutTitle.Truncate();
4503 // Try to get a host from the running principal -- this will do the
4504 // right thing for javascript: and data: documents.
4506 nsresult rv = NS_OK;
4507 NS_ASSERTION(nsContentUtils::GetSecurityManager(),
4508 "Global Window has no security manager!");
4509 if (nsContentUtils::GetSecurityManager()) {
4510 nsCOMPtr<nsIPrincipal> principal;
4511 rv = nsContentUtils::GetSecurityManager()->
4512 GetSubjectPrincipal(getter_AddRefs(principal));
4514 if (NS_SUCCEEDED(rv) && principal) {
4515 nsCOMPtr<nsIURI> uri;
4516 rv = principal->GetURI(getter_AddRefs(uri));
4518 if (NS_SUCCEEDED(rv) && uri) {
4519 // remove user:pass for privacy and spoof prevention
4521 nsCOMPtr<nsIURIFixup> fixup(do_GetService(NS_URIFIXUP_CONTRACTID));
4522 if (fixup) {
4523 nsCOMPtr<nsIURI> fixedURI;
4524 rv = fixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
4525 if (NS_SUCCEEDED(rv) && fixedURI) {
4526 nsCAutoString host;
4527 fixedURI->GetHost(host);
4529 if (!host.IsEmpty()) {
4530 // if this URI has a host we'll show it. For other
4531 // schemes (e.g. file:) we fall back to the localized
4532 // generic string
4534 nsCAutoString prepath;
4535 fixedURI->GetPrePath(prepath);
4537 NS_ConvertUTF8toUTF16 ucsPrePath(prepath);
4538 const PRUnichar *formatStrings[] = { ucsPrePath.get() };
4539 nsXPIDLString tempString;
4540 nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4541 "ScriptDlgHeading",
4542 formatStrings, NS_ARRAY_LENGTH(formatStrings),
4543 tempString);
4544 aOutTitle = tempString;
4550 else { // failed to get subject principal
4551 NS_WARNING("No script principal? Who is calling alert/confirm/prompt?!");
4555 if (aOutTitle.IsEmpty()) {
4556 // We didn't find a host so use the generic heading
4557 nsXPIDLString tempString;
4558 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4559 "ScriptDlgGenericHeading",
4560 tempString);
4561 aOutTitle = tempString;
4564 // Just in case
4565 if (aOutTitle.IsEmpty()) {
4566 NS_WARNING("could not get ScriptDlgGenericHeading string from string bundle");
4567 aOutTitle.AssignLiteral("[Script]");
4571 // static
4572 PRBool
4573 nsGlobalWindow::CanMoveResizeWindows()
4575 if (!CanSetProperty("dom.disable_window_move_resize"))
4576 return PR_FALSE;
4578 if (gMouseDown && !gDragServiceDisabled) {
4579 nsCOMPtr<nsIDragService> ds =
4580 do_GetService("@mozilla.org/widget/dragservice;1");
4581 if (ds) {
4582 gDragServiceDisabled = PR_TRUE;
4583 ds->Suppress();
4586 return PR_TRUE;
4589 NS_IMETHODIMP
4590 nsGlobalWindow::Alert(const nsAString& aString)
4592 FORWARD_TO_OUTER(Alert, (aString), NS_ERROR_NOT_INITIALIZED);
4594 if (AreDialogsBlocked())
4595 return NS_ERROR_NOT_AVAILABLE;
4597 // We have to capture this now so as not to get confused with the
4598 // popup state we push next
4599 PRBool shouldEnableDisableDialog = DialogOpenAttempted();
4601 // Reset popup state while opening a modal dialog, and firing events
4602 // about the dialog, to prevent the current state from being active
4603 // the whole time a modal dialog is open.
4604 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
4606 // Special handling for alert(null) in JS for backwards
4607 // compatibility.
4609 NS_NAMED_LITERAL_STRING(null_str, "null");
4611 const nsAString *str = DOMStringIsNull(aString) ? &null_str : &aString;
4613 // Before bringing up the window, unsuppress painting and flush
4614 // pending reflows.
4615 EnsureReflowFlushAndPaint();
4617 nsAutoString title;
4618 MakeScriptDialogTitle(title);
4620 // Remove non-terminating null characters from the
4621 // string. See bug #310037.
4622 nsAutoString final;
4623 nsContentUtils::StripNullChars(*str, final);
4625 nsresult rv;
4626 nsCOMPtr<nsIPromptFactory> promptFac =
4627 do_GetService("@mozilla.org/prompter;1", &rv);
4628 NS_ENSURE_SUCCESS(rv, rv);
4630 nsCOMPtr<nsIPrompt> prompt;
4631 rv = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
4632 reinterpret_cast<void**>(&prompt));
4633 NS_ENSURE_SUCCESS(rv, rv);
4635 nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
4636 if (promptBag)
4637 promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), PR_TRUE);
4639 if (shouldEnableDisableDialog) {
4640 PRBool disallowDialog = PR_FALSE;
4641 nsXPIDLString label;
4642 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4643 "ScriptDialogLabel", label);
4645 rv = prompt->AlertCheck(title.get(), final.get(), label.get(),
4646 &disallowDialog);
4647 if (disallowDialog)
4648 PreventFurtherDialogs();
4649 } else {
4650 rv = prompt->Alert(title.get(), final.get());
4653 return rv;
4656 NS_IMETHODIMP
4657 nsGlobalWindow::Confirm(const nsAString& aString, PRBool* aReturn)
4659 FORWARD_TO_OUTER(Confirm, (aString, aReturn), NS_ERROR_NOT_INITIALIZED);
4661 if (AreDialogsBlocked())
4662 return NS_ERROR_NOT_AVAILABLE;
4664 // We have to capture this now so as not to get confused with the popup state
4665 // we push next
4666 PRBool shouldEnableDisableDialog = DialogOpenAttempted();
4668 // Reset popup state while opening a modal dialog, and firing events
4669 // about the dialog, to prevent the current state from being active
4670 // the whole time a modal dialog is open.
4671 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
4673 *aReturn = PR_FALSE;
4675 // Before bringing up the window, unsuppress painting and flush
4676 // pending reflows.
4677 EnsureReflowFlushAndPaint();
4679 nsAutoString title;
4680 MakeScriptDialogTitle(title);
4682 // Remove non-terminating null characters from the
4683 // string. See bug #310037.
4684 nsAutoString final;
4685 nsContentUtils::StripNullChars(aString, final);
4687 nsresult rv;
4688 nsCOMPtr<nsIPromptFactory> promptFac =
4689 do_GetService("@mozilla.org/prompter;1", &rv);
4690 NS_ENSURE_SUCCESS(rv, rv);
4692 nsCOMPtr<nsIPrompt> prompt;
4693 rv = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
4694 reinterpret_cast<void**>(&prompt));
4695 NS_ENSURE_SUCCESS(rv, rv);
4697 nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
4698 if (promptBag)
4699 promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), PR_TRUE);
4701 if (shouldEnableDisableDialog) {
4702 PRBool disallowDialog = PR_FALSE;
4703 nsXPIDLString label;
4704 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4705 "ScriptDialogLabel", label);
4707 rv = prompt->ConfirmCheck(title.get(), final.get(), label.get(),
4708 &disallowDialog, aReturn);
4709 if (disallowDialog)
4710 PreventFurtherDialogs();
4711 } else {
4712 rv = prompt->Confirm(title.get(), final.get(), aReturn);
4715 return rv;
4718 NS_IMETHODIMP
4719 nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
4720 nsAString& aReturn)
4722 FORWARD_TO_OUTER(Prompt, (aMessage, aInitial, aReturn),
4723 NS_ERROR_NOT_INITIALIZED);
4725 SetDOMStringToNull(aReturn);
4727 if (AreDialogsBlocked())
4728 return NS_ERROR_NOT_AVAILABLE;
4730 // We have to capture this now so as not to get confused with the popup state
4731 // we push next
4732 PRBool shouldEnableDisableDialog = DialogOpenAttempted();
4734 // Reset popup state while opening a modal dialog, and firing events
4735 // about the dialog, to prevent the current state from being active
4736 // the whole time a modal dialog is open.
4737 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
4739 // Before bringing up the window, unsuppress painting and flush
4740 // pending reflows.
4741 EnsureReflowFlushAndPaint();
4743 nsAutoString title;
4744 MakeScriptDialogTitle(title);
4746 // Remove non-terminating null characters from the
4747 // string. See bug #310037.
4748 nsAutoString fixedMessage, fixedInitial;
4749 nsContentUtils::StripNullChars(aMessage, fixedMessage);
4750 nsContentUtils::StripNullChars(aInitial, fixedInitial);
4752 nsresult rv;
4753 nsCOMPtr<nsIPromptFactory> promptFac =
4754 do_GetService("@mozilla.org/prompter;1", &rv);
4755 NS_ENSURE_SUCCESS(rv, rv);
4757 nsCOMPtr<nsIPrompt> prompt;
4758 rv = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
4759 reinterpret_cast<void**>(&prompt));
4760 NS_ENSURE_SUCCESS(rv, rv);
4762 nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
4763 if (promptBag)
4764 promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), PR_TRUE);
4766 // Pass in the default value, if any.
4767 PRUnichar *inoutValue = ToNewUnicode(fixedInitial);
4768 PRBool disallowDialog = PR_FALSE;
4770 nsXPIDLString label;
4771 if (shouldEnableDisableDialog) {
4772 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4773 "ScriptDialogLabel", label);
4776 PRBool ok;
4777 rv = prompt->Prompt(title.get(), fixedMessage.get(),
4778 &inoutValue, label.get(), &disallowDialog, &ok);
4780 if (disallowDialog) {
4781 PreventFurtherDialogs();
4784 NS_ENSURE_SUCCESS(rv, rv);
4786 nsAdoptingString outValue(inoutValue);
4788 if (ok && outValue) {
4789 aReturn.Assign(outValue);
4792 return rv;
4795 NS_IMETHODIMP
4796 nsGlobalWindow::Focus()
4798 FORWARD_TO_OUTER(Focus, (), NS_ERROR_NOT_INITIALIZED);
4800 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
4801 if (!fm)
4802 return NS_OK;
4804 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
4806 PRBool isVisible = PR_FALSE;
4807 if (baseWin) {
4808 baseWin->GetVisibility(&isVisible);
4811 if (!isVisible) {
4812 // A hidden tab is being focused, ignore this call.
4813 return NS_OK;
4816 nsIDOMWindowInternal *caller =
4817 static_cast<nsIDOMWindowInternal*>(nsContentUtils::GetWindowFromCaller());
4818 nsCOMPtr<nsIDOMWindowInternal> opener;
4819 GetOpener(getter_AddRefs(opener));
4821 // Enforce dom.disable_window_flip (for non-chrome), but still allow the
4822 // window which opened us to raise us at times when popups are allowed
4823 // (bugs 355482 and 369306).
4824 PRBool canFocus = CanSetProperty("dom.disable_window_flip") ||
4825 (opener == caller &&
4826 RevisePopupAbuseLevel(gPopupControlState) < openAbused);
4828 nsCOMPtr<nsIDOMWindow> activeWindow;
4829 fm->GetActiveWindow(getter_AddRefs(activeWindow));
4831 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
4832 NS_ASSERTION(treeItem, "What happened?");
4833 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4834 treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
4835 nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
4836 PRBool isActive = (rootWin == activeWindow);
4838 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4839 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4840 if (treeOwnerAsWin && (canFocus || isActive)) {
4841 PRBool isEnabled = PR_TRUE;
4842 if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled)) && !isEnabled) {
4843 NS_WARNING( "Should not try to set the focus on a disabled window" );
4844 return NS_OK;
4847 // XXXndeakin not sure what this is for or if it should go somewhere else
4848 nsCOMPtr<nsIEmbeddingSiteWindow> embeddingWin(do_GetInterface(treeOwnerAsWin));
4849 if (embeddingWin)
4850 embeddingWin->SetFocus();
4853 if (!mDocShell)
4854 return NS_OK;
4856 nsCOMPtr<nsIPresShell> presShell;
4857 // Don't look for a presshell if we're a root chrome window that's got
4858 // about:blank loaded. We don't want to focus our widget in that case.
4859 // XXXbz should we really be checking for IsInitialDocument() instead?
4860 PRBool lookForPresShell = PR_TRUE;
4861 PRInt32 itemType = nsIDocShellTreeItem::typeContent;
4862 treeItem->GetItemType(&itemType);
4863 if (itemType == nsIDocShellTreeItem::typeChrome &&
4864 GetPrivateRoot() == static_cast<nsIDOMWindowInternal*>(this) &&
4865 mDocument) {
4866 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
4867 NS_ASSERTION(doc, "Bogus doc?");
4868 nsIURI* ourURI = doc->GetDocumentURI();
4869 if (ourURI) {
4870 lookForPresShell = !IsAboutBlank(ourURI);
4874 if (lookForPresShell) {
4875 mDocShell->GetEldestPresShell(getter_AddRefs(presShell));
4878 nsCOMPtr<nsIDocShellTreeItem> parentDsti;
4879 treeItem->GetParent(getter_AddRefs(parentDsti));
4881 // set the parent's current focus to the frame containing this window.
4882 nsCOMPtr<nsIDOMWindow> parent(do_GetInterface(parentDsti));
4883 if (parent) {
4884 nsCOMPtr<nsIDOMDocument> parentdomdoc;
4885 parent->GetDocument(getter_AddRefs(parentdomdoc));
4887 nsCOMPtr<nsIDocument> parentdoc = do_QueryInterface(parentdomdoc);
4888 if (!parentdoc)
4889 return NS_OK;
4891 nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
4892 nsIContent* frame = parentdoc->FindContentForSubDocument(doc);
4893 nsCOMPtr<nsIDOMElement> frameElement = do_QueryInterface(frame);
4894 if (frameElement) {
4895 PRUint32 flags = nsIFocusManager::FLAG_NOSCROLL;
4896 if (canFocus)
4897 flags |= nsIFocusManager::FLAG_RAISE;
4898 return fm->SetFocus(frameElement, flags);
4901 else if (canFocus) {
4902 // if there is no parent, this must be a toplevel window, so raise the
4903 // window if canFocus is true
4904 return fm->SetActiveWindow(this);
4907 return NS_OK;
4910 NS_IMETHODIMP
4911 nsGlobalWindow::Blur()
4913 FORWARD_TO_OUTER(Blur, (), NS_ERROR_NOT_INITIALIZED);
4915 // If dom.disable_window_flip == true, then content should not be allowed
4916 // to call this function (this would allow popunders, bug 369306)
4917 if (!CanSetProperty("dom.disable_window_flip")) {
4918 return NS_OK;
4921 // If embedding apps don't implement nsIEmbeddingSiteWindow2, we
4922 // shouldn't throw exceptions to web content.
4923 nsresult rv = NS_OK;
4925 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
4926 GetTreeOwner(getter_AddRefs(treeOwner));
4927 nsCOMPtr<nsIEmbeddingSiteWindow2> siteWindow(do_GetInterface(treeOwner));
4928 if (siteWindow) {
4929 // This method call may cause mDocShell to become nsnull.
4930 rv = siteWindow->Blur();
4932 // if the root is focused, clear the focus
4933 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
4934 nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
4935 if (fm && mDocument) {
4936 nsCOMPtr<nsIDOMElement> element;
4937 fm->GetFocusedElementForWindow(this, PR_FALSE, nsnull, getter_AddRefs(element));
4938 nsCOMPtr<nsIContent> content = do_QueryInterface(element);
4939 if (content == doc->GetRootElement())
4940 fm->ClearFocus(this);
4944 return rv;
4947 NS_IMETHODIMP
4948 nsGlobalWindow::Back()
4950 FORWARD_TO_OUTER(Back, (), NS_ERROR_NOT_INITIALIZED);
4952 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4953 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
4955 return webNav->GoBack();
4958 NS_IMETHODIMP
4959 nsGlobalWindow::Forward()
4961 FORWARD_TO_OUTER(Forward, (), NS_ERROR_NOT_INITIALIZED);
4963 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4964 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
4966 return webNav->GoForward();
4969 NS_IMETHODIMP
4970 nsGlobalWindow::Home()
4972 FORWARD_TO_OUTER(Home, (), NS_ERROR_NOT_INITIALIZED);
4974 if (!mDocShell)
4975 return NS_OK;
4977 nsAdoptingString homeURL =
4978 nsContentUtils::GetLocalizedStringPref(PREF_BROWSER_STARTUP_HOMEPAGE);
4980 if (homeURL.IsEmpty()) {
4981 // if all else fails, use this
4982 #ifdef DEBUG_seth
4983 printf("all else failed. using %s as the home page\n", DEFAULT_HOME_PAGE);
4984 #endif
4985 CopyASCIItoUTF16(DEFAULT_HOME_PAGE, homeURL);
4988 #ifdef MOZ_PHOENIX
4990 // Firefox lets the user specify multiple home pages to open in
4991 // individual tabs by separating them with '|'. Since we don't
4992 // have the machinery in place to easily open new tabs from here,
4993 // simply truncate the homeURL at the first '|' character to
4994 // prevent any possibilities of leaking the users list of home
4995 // pages to the first home page.
4997 // Once bug https://bugzilla.mozilla.org/show_bug.cgi?id=221445 is
4998 // fixed we can revisit this.
4999 PRInt32 firstPipe = homeURL.FindChar('|');
5001 if (firstPipe > 0) {
5002 homeURL.Truncate(firstPipe);
5005 #endif
5007 nsresult rv;
5008 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
5009 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
5010 rv = webNav->LoadURI(homeURL.get(),
5011 nsIWebNavigation::LOAD_FLAGS_NONE,
5012 nsnull,
5013 nsnull,
5014 nsnull);
5015 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5016 return NS_OK;
5019 NS_IMETHODIMP
5020 nsGlobalWindow::Stop()
5022 FORWARD_TO_OUTER(Stop, (), NS_ERROR_NOT_INITIALIZED);
5024 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
5025 if (!webNav)
5026 return NS_OK;
5028 return webNav->Stop(nsIWebNavigation::STOP_ALL);
5031 NS_IMETHODIMP
5032 nsGlobalWindow::Print()
5034 #ifdef NS_PRINTING
5035 FORWARD_TO_OUTER(Print, (), NS_ERROR_NOT_INITIALIZED);
5037 if (AreDialogsBlocked() || !ConfirmDialogAllowed())
5038 return NS_ERROR_NOT_AVAILABLE;
5040 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
5041 if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
5042 getter_AddRefs(webBrowserPrint)))) {
5044 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
5045 do_GetService("@mozilla.org/gfx/printsettings-service;1");
5047 nsCOMPtr<nsIPrintSettings> printSettings;
5048 if (printSettingsService) {
5049 PRBool printSettingsAreGlobal =
5050 nsContentUtils::GetBoolPref("print.use_global_printsettings", PR_FALSE);
5052 if (printSettingsAreGlobal) {
5053 printSettingsService->GetGlobalPrintSettings(getter_AddRefs(printSettings));
5055 nsXPIDLString printerName;
5056 printSettings->GetPrinterName(getter_Copies(printerName));
5057 if (printerName.IsEmpty()) {
5058 printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
5059 printSettings->SetPrinterName(printerName);
5061 printSettingsService->InitPrintSettingsFromPrinter(printerName, printSettings);
5062 printSettingsService->InitPrintSettingsFromPrefs(printSettings,
5063 PR_TRUE,
5064 nsIPrintSettings::kInitSaveAll);
5065 } else {
5066 printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));
5069 EnterModalState();
5070 webBrowserPrint->Print(printSettings, nsnull);
5071 LeaveModalState(nsnull);
5073 PRBool savePrintSettings =
5074 nsContentUtils::GetBoolPref("print.save_print_settings", PR_FALSE);
5075 if (printSettingsAreGlobal && savePrintSettings) {
5076 printSettingsService->
5077 SavePrintSettingsToPrefs(printSettings,
5078 PR_TRUE,
5079 nsIPrintSettings::kInitSaveAll);
5080 printSettingsService->
5081 SavePrintSettingsToPrefs(printSettings,
5082 PR_FALSE,
5083 nsIPrintSettings::kInitSavePrinterName);
5085 } else {
5086 webBrowserPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));
5087 webBrowserPrint->Print(printSettings, nsnull);
5090 #endif //NS_PRINTING
5092 return NS_OK;
5095 NS_IMETHODIMP
5096 nsGlobalWindow::MoveTo(PRInt32 aXPos, PRInt32 aYPos)
5098 FORWARD_TO_OUTER(MoveTo, (aXPos, aYPos), NS_ERROR_NOT_INITIALIZED);
5101 * If caller is not chrome and the user has not explicitly exempted the site,
5102 * prevent window.moveTo() by exiting early
5105 if (!CanMoveResizeWindows() || IsFrame()) {
5106 return NS_OK;
5109 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5110 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5111 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
5113 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&aXPos, &aYPos),
5114 NS_ERROR_FAILURE);
5116 // mild abuse of a "size" object so we don't need more helper functions
5117 nsIntSize devPos(CSSToDevIntPixels(nsIntSize(aXPos, aYPos)));
5119 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(devPos.width, devPos.height),
5120 NS_ERROR_FAILURE);
5122 return NS_OK;
5125 NS_IMETHODIMP
5126 nsGlobalWindow::MoveBy(PRInt32 aXDif, PRInt32 aYDif)
5128 FORWARD_TO_OUTER(MoveBy, (aXDif, aYDif), NS_ERROR_NOT_INITIALIZED);
5131 * If caller is not chrome and the user has not explicitly exempted the site,
5132 * prevent window.moveBy() by exiting early
5135 if (!CanMoveResizeWindows() || IsFrame()) {
5136 return NS_OK;
5139 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5140 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5141 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
5143 // To do this correctly we have to convert what we get from GetPosition
5144 // into CSS pixels, add the arguments, do the security check, and
5145 // then convert back to device pixels for the call to SetPosition.
5147 PRInt32 x, y;
5148 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y), NS_ERROR_FAILURE);
5150 // mild abuse of a "size" object so we don't need more helper functions
5151 nsIntSize cssPos(DevToCSSIntPixels(nsIntSize(x, y)));
5153 cssPos.width += aXDif;
5154 cssPos.height += aYDif;
5156 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&cssPos.width,
5157 &cssPos.height),
5158 NS_ERROR_FAILURE);
5160 nsIntSize newDevPos(CSSToDevIntPixels(cssPos));
5162 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(newDevPos.width,
5163 newDevPos.height),
5164 NS_ERROR_FAILURE);
5166 return NS_OK;
5169 NS_IMETHODIMP
5170 nsGlobalWindow::ResizeTo(PRInt32 aWidth, PRInt32 aHeight)
5172 FORWARD_TO_OUTER(ResizeTo, (aWidth, aHeight), NS_ERROR_NOT_INITIALIZED);
5175 * If caller is not chrome and the user has not explicitly exempted the site,
5176 * prevent window.resizeTo() by exiting early
5179 if (!CanMoveResizeWindows() || IsFrame()) {
5180 return NS_OK;
5183 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5184 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5185 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
5187 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&aWidth, &aHeight),
5188 NS_ERROR_FAILURE);
5190 nsIntSize devSz(CSSToDevIntPixels(nsIntSize(aWidth, aHeight)));
5192 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(devSz.width, devSz.height, PR_TRUE),
5193 NS_ERROR_FAILURE);
5195 return NS_OK;
5198 NS_IMETHODIMP
5199 nsGlobalWindow::ResizeBy(PRInt32 aWidthDif, PRInt32 aHeightDif)
5201 FORWARD_TO_OUTER(ResizeBy, (aWidthDif, aHeightDif), NS_ERROR_NOT_INITIALIZED);
5204 * If caller is not chrome and the user has not explicitly exempted the site,
5205 * prevent window.resizeBy() by exiting early
5208 if (!CanMoveResizeWindows() || IsFrame()) {
5209 return NS_OK;
5212 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5213 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5214 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
5216 PRInt32 width, height;
5217 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&width, &height), NS_ERROR_FAILURE);
5219 // To do this correctly we have to convert what we got from GetSize
5220 // into CSS pixels, add the arguments, do the security check, and
5221 // then convert back to device pixels for the call to SetSize.
5223 nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
5225 cssSize.width += aWidthDif;
5226 cssSize.height += aHeightDif;
5228 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&cssSize.width,
5229 &cssSize.height),
5230 NS_ERROR_FAILURE);
5232 nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
5234 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(newDevSize.width,
5235 newDevSize.height,
5236 PR_TRUE),
5237 NS_ERROR_FAILURE);
5239 return NS_OK;
5242 NS_IMETHODIMP
5243 nsGlobalWindow::SizeToContent()
5245 FORWARD_TO_OUTER(SizeToContent, (), NS_ERROR_NOT_INITIALIZED);
5247 if (!mDocShell) {
5248 return NS_OK;
5252 * If caller is not chrome and the user has not explicitly exempted the site,
5253 * prevent window.sizeToContent() by exiting early
5256 if (!CanMoveResizeWindows() || IsFrame()) {
5257 return NS_OK;
5260 // The content viewer does a check to make sure that it's a content
5261 // viewer for a toplevel docshell.
5263 nsCOMPtr<nsIContentViewer> cv;
5264 mDocShell->GetContentViewer(getter_AddRefs(cv));
5265 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(cv));
5266 NS_ENSURE_TRUE(markupViewer, NS_ERROR_FAILURE);
5267 NS_ENSURE_SUCCESS(markupViewer->SizeToContent(), NS_ERROR_FAILURE);
5269 return NS_OK;
5272 NS_IMETHODIMP
5273 nsGlobalWindow::GetWindowRoot(nsIDOMEventTarget **aWindowRoot)
5275 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
5276 return CallQueryInterface(root, aWindowRoot);
5279 already_AddRefed<nsPIWindowRoot>
5280 nsGlobalWindow::GetTopWindowRoot()
5282 nsIDOMWindowInternal *rootWindow = GetPrivateRoot();
5283 nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(rootWindow));
5284 if (!piWin)
5285 return nsnull;
5287 nsCOMPtr<nsPIWindowRoot> window = do_QueryInterface(piWin->GetChromeEventHandler());
5288 return window.forget();
5291 NS_IMETHODIMP
5292 nsGlobalWindow::Scroll(PRInt32 aXScroll, PRInt32 aYScroll)
5294 return ScrollTo(aXScroll, aYScroll);
5297 NS_IMETHODIMP
5298 nsGlobalWindow::ScrollTo(PRInt32 aXScroll, PRInt32 aYScroll)
5300 FlushPendingNotifications(Flush_Layout);
5301 nsIScrollableFrame *sf = GetScrollFrame();
5303 if (sf) {
5304 // Here we calculate what the max pixel value is that we can
5305 // scroll to, we do this by dividing maxint with the pixel to
5306 // twips conversion factor, and substracting 4, the 4 comes from
5307 // experimenting with this value, anything less makes the view
5308 // code not scroll correctly, I have no idea why. -- jst
5309 const PRInt32 maxpx = nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff) - 4;
5311 if (aXScroll > maxpx) {
5312 aXScroll = maxpx;
5315 if (aYScroll > maxpx) {
5316 aYScroll = maxpx;
5318 sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aXScroll),
5319 nsPresContext::CSSPixelsToAppUnits(aYScroll)),
5320 nsIScrollableFrame::INSTANT);
5323 return NS_OK;
5326 NS_IMETHODIMP
5327 nsGlobalWindow::ScrollBy(PRInt32 aXScrollDif, PRInt32 aYScrollDif)
5329 FlushPendingNotifications(Flush_Layout);
5330 nsIScrollableFrame *sf = GetScrollFrame();
5332 if (sf) {
5333 nsPoint scrollPos = sf->GetScrollPosition();
5334 // It seems like it would make more sense for ScrollBy to use
5335 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
5336 // Perhaps Web content does too.
5337 return ScrollTo(nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x) + aXScrollDif,
5338 nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y) + aYScrollDif);
5341 return NS_OK;
5344 NS_IMETHODIMP
5345 nsGlobalWindow::ScrollByLines(PRInt32 numLines)
5347 FlushPendingNotifications(Flush_Layout);
5348 nsIScrollableFrame *sf = GetScrollFrame();
5349 if (sf) {
5350 // It seems like it would make more sense for ScrollByLines to use
5351 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
5352 // Perhaps Web content does too.
5353 sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
5354 nsIScrollableFrame::INSTANT);
5357 return NS_OK;
5360 NS_IMETHODIMP
5361 nsGlobalWindow::ScrollByPages(PRInt32 numPages)
5363 FlushPendingNotifications(Flush_Layout);
5364 nsIScrollableFrame *sf = GetScrollFrame();
5365 if (sf) {
5366 // It seems like it would make more sense for ScrollByPages to use
5367 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
5368 // Perhaps Web content does too.
5369 sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
5370 nsIScrollableFrame::INSTANT);
5373 return NS_OK;
5376 NS_IMETHODIMP
5377 nsGlobalWindow::ClearTimeout()
5379 return ClearTimeoutOrInterval();
5382 NS_IMETHODIMP
5383 nsGlobalWindow::ClearInterval()
5385 return ClearTimeoutOrInterval();
5388 NS_IMETHODIMP
5389 nsGlobalWindow::SetTimeout(PRInt32 *_retval)
5391 return SetTimeoutOrInterval(PR_FALSE, _retval);
5394 NS_IMETHODIMP
5395 nsGlobalWindow::SetInterval(PRInt32 *_retval)
5397 return SetTimeoutOrInterval(PR_TRUE, _retval);
5400 NS_IMETHODIMP
5401 nsGlobalWindow::SetResizable(PRBool aResizable)
5403 // nop
5405 return NS_OK;
5408 static void
5409 ReportUseOfDeprecatedMethod(nsGlobalWindow* aWindow, const char* aWarning)
5411 nsCOMPtr<nsIDocument> doc = do_QueryInterface(aWindow->GetExtantDocument());
5412 nsContentUtils::ReportToConsole(nsContentUtils::eDOM_PROPERTIES,
5413 aWarning,
5414 nsnull, 0,
5415 nsnull,
5416 EmptyString(), 0, 0,
5417 nsIScriptError::warningFlag,
5418 "DOM Events", doc);
5421 NS_IMETHODIMP
5422 nsGlobalWindow::CaptureEvents(PRInt32 aEventFlags)
5424 ReportUseOfDeprecatedMethod(this, "UseOfCaptureEventsWarning");
5425 return NS_OK;
5428 NS_IMETHODIMP
5429 nsGlobalWindow::ReleaseEvents(PRInt32 aEventFlags)
5431 ReportUseOfDeprecatedMethod(this, "UseOfReleaseEventsWarning");
5432 return NS_OK;
5435 NS_IMETHODIMP
5436 nsGlobalWindow::RouteEvent(nsIDOMEvent* aEvt)
5438 ReportUseOfDeprecatedMethod(this, "UseOfRouteEventWarning");
5439 return NS_OK;
5442 NS_IMETHODIMP
5443 nsGlobalWindow::EnableExternalCapture()
5445 return NS_ERROR_FAILURE;
5448 NS_IMETHODIMP
5449 nsGlobalWindow::DisableExternalCapture()
5451 return NS_ERROR_FAILURE;
5454 static
5455 PRBool IsPopupBlocked(nsIDOMDocument* aDoc)
5457 nsCOMPtr<nsIPopupWindowManager> pm =
5458 do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
5460 if (!pm) {
5461 return PR_FALSE;
5464 PRBool blocked = PR_TRUE;
5465 nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
5467 if (doc) {
5468 PRUint32 permission = nsIPopupWindowManager::ALLOW_POPUP;
5469 pm->TestPermission(doc->GetDocumentURI(), &permission);
5470 blocked = (permission == nsIPopupWindowManager::DENY_POPUP);
5472 return blocked;
5475 /* static */
5476 void
5477 nsGlobalWindow::FirePopupBlockedEvent(nsIDOMDocument* aDoc,
5478 nsIDOMWindow *aRequestingWindow, nsIURI *aPopupURI,
5479 const nsAString &aPopupWindowName,
5480 const nsAString &aPopupWindowFeatures)
5482 if (aDoc) {
5483 // Fire a "DOMPopupBlocked" event so that the UI can hear about
5484 // blocked popups.
5485 nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(aDoc));
5486 nsCOMPtr<nsIDOMEvent> event;
5487 docEvent->CreateEvent(NS_LITERAL_STRING("PopupBlockedEvents"),
5488 getter_AddRefs(event));
5489 if (event) {
5490 nsCOMPtr<nsIDOMPopupBlockedEvent> pbev(do_QueryInterface(event));
5491 pbev->InitPopupBlockedEvent(NS_LITERAL_STRING("DOMPopupBlocked"),
5492 PR_TRUE, PR_TRUE, aRequestingWindow,
5493 aPopupURI, aPopupWindowName,
5494 aPopupWindowFeatures);
5495 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
5496 privateEvent->SetTrusted(PR_TRUE);
5498 nsCOMPtr<nsIDOMEventTarget> targ(do_QueryInterface(aDoc));
5499 PRBool defaultActionEnabled;
5500 targ->DispatchEvent(event, &defaultActionEnabled);
5505 void FirePopupWindowEvent(nsIDOMDocument* aDoc)
5507 // Fire a "PopupWindow" event
5508 nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
5509 nsContentUtils::DispatchTrustedEvent(doc, aDoc,
5510 NS_LITERAL_STRING("PopupWindow"),
5511 PR_TRUE, PR_TRUE);
5514 // static
5515 PRBool
5516 nsGlobalWindow::CanSetProperty(const char *aPrefName)
5518 // Chrome can set any property.
5519 if (nsContentUtils::IsCallerTrustedForWrite()) {
5520 return PR_TRUE;
5523 // If the pref is set to true, we can not set the property
5524 // and vice versa.
5525 return !nsContentUtils::GetBoolPref(aPrefName, PR_TRUE);
5528 PRBool
5529 nsGlobalWindow::PopupWhitelisted()
5531 if (!IsPopupBlocked(mDocument))
5532 return PR_TRUE;
5534 nsCOMPtr<nsIDOMWindow> parent;
5536 if (NS_FAILED(GetParent(getter_AddRefs(parent))) ||
5537 parent == static_cast<nsIDOMWindow*>(this))
5539 return PR_FALSE;
5542 return static_cast<nsGlobalWindow*>
5543 (static_cast<nsIDOMWindow*>
5544 (parent.get()))->PopupWhitelisted();
5548 * Examine the current document state to see if we're in a way that is
5549 * typically abused by web designers. The window.open code uses this
5550 * routine to determine whether to allow the new window.
5551 * Returns a value from the PopupControlState enum.
5553 PopupControlState
5554 nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
5556 FORWARD_TO_OUTER(RevisePopupAbuseLevel, (aControl), aControl);
5558 NS_ASSERTION(mDocShell, "Must have docshell");
5560 nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(mDocShell));
5562 NS_ASSERTION(item, "Docshell doesn't implement nsIDocShellTreeItem?");
5564 PRInt32 type = nsIDocShellTreeItem::typeChrome;
5565 item->GetItemType(&type);
5566 if (type != nsIDocShellTreeItem::typeContent)
5567 return openAllowed;
5569 PopupControlState abuse = aControl;
5570 switch (abuse) {
5571 case openControlled:
5572 case openAbused:
5573 case openOverridden:
5574 if (PopupWhitelisted())
5575 abuse = PopupControlState(abuse - 1);
5576 case openAllowed: break;
5577 default:
5578 NS_WARNING("Strange PopupControlState!");
5581 // limit the number of simultaneously open popups
5582 if (abuse == openAbused || abuse == openControlled) {
5583 PRInt32 popupMax = nsContentUtils::GetIntPref("dom.popup_maximum", -1);
5584 if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
5585 abuse = openOverridden;
5588 return abuse;
5591 /* If a window open is blocked, fire the appropriate DOM events.
5592 aBlocked signifies we just blocked a popup.
5593 aWindow signifies we just opened what is probably a popup.
5595 void
5596 nsGlobalWindow::FireAbuseEvents(PRBool aBlocked, PRBool aWindow,
5597 const nsAString &aPopupURL,
5598 const nsAString &aPopupWindowName,
5599 const nsAString &aPopupWindowFeatures)
5601 // fetch the URI of the window requesting the opened window
5603 nsCOMPtr<nsIDOMWindow> topWindow;
5604 GetTop(getter_AddRefs(topWindow));
5605 if (!topWindow)
5606 return;
5608 nsCOMPtr<nsIDOMDocument> topDoc;
5609 topWindow->GetDocument(getter_AddRefs(topDoc));
5611 nsCOMPtr<nsIURI> popupURI;
5613 // build the URI of the would-have-been popup window
5614 // (see nsWindowWatcher::URIfromURL)
5616 // first, fetch the opener's base URI
5618 nsIURI *baseURL = 0;
5620 JSContext *cx = nsContentUtils::GetCurrentJSContext();
5621 nsCOMPtr<nsIDOMWindow> contextWindow;
5623 if (cx) {
5624 nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
5625 if (currentCX) {
5626 contextWindow = do_QueryInterface(currentCX->GetGlobalObject());
5629 if (!contextWindow)
5630 contextWindow = static_cast<nsIDOMWindow*>(this);
5632 nsCOMPtr<nsIDOMDocument> domdoc;
5633 contextWindow->GetDocument(getter_AddRefs(domdoc));
5634 nsCOMPtr<nsIDocument> doc(do_QueryInterface(domdoc));
5635 if (doc)
5636 baseURL = doc->GetDocBaseURI();
5638 // use the base URI to build what would have been the popup's URI
5639 nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
5640 if (ios)
5641 ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), 0, baseURL,
5642 getter_AddRefs(popupURI));
5644 // fire an event chock full of informative URIs
5645 if (aBlocked)
5646 FirePopupBlockedEvent(topDoc, this, popupURI, aPopupWindowName,
5647 aPopupWindowFeatures);
5648 if (aWindow)
5649 FirePopupWindowEvent(topDoc);
5652 NS_IMETHODIMP
5653 nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
5654 const nsAString& aOptions, nsIDOMWindow **_retval)
5656 return OpenInternal(aUrl, aName, aOptions,
5657 PR_FALSE, // aDialog
5658 PR_FALSE, // aContentModal
5659 PR_TRUE, // aCalledNoScript
5660 PR_FALSE, // aDoJSFixups
5661 nsnull, nsnull, // No args
5662 GetPrincipal(), // aCalleePrincipal
5663 nsnull, // aJSCallerContext
5664 _retval);
5667 NS_IMETHODIMP
5668 nsGlobalWindow::OpenJS(const nsAString& aUrl, const nsAString& aName,
5669 const nsAString& aOptions, nsIDOMWindow **_retval)
5671 return OpenInternal(aUrl, aName, aOptions,
5672 PR_FALSE, // aDialog
5673 PR_FALSE, // aContentModal
5674 PR_FALSE, // aCalledNoScript
5675 PR_TRUE, // aDoJSFixups
5676 nsnull, nsnull, // No args
5677 GetPrincipal(), // aCalleePrincipal
5678 nsContentUtils::GetCurrentJSContext(), // aJSCallerContext
5679 _retval);
5682 // like Open, but attaches to the new window any extra parameters past
5683 // [features] as a JS property named "arguments"
5684 NS_IMETHODIMP
5685 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
5686 const nsAString& aOptions,
5687 nsISupports* aExtraArgument, nsIDOMWindow** _retval)
5689 return OpenInternal(aUrl, aName, aOptions,
5690 PR_TRUE, // aDialog
5691 PR_FALSE, // aContentModal
5692 PR_TRUE, // aCalledNoScript
5693 PR_FALSE, // aDoJSFixups
5694 nsnull, aExtraArgument, // Arguments
5695 GetPrincipal(), // aCalleePrincipal
5696 nsnull, // aJSCallerContext
5697 _retval);
5700 NS_IMETHODIMP
5701 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
5702 const nsAString& aOptions, nsIDOMWindow** _retval)
5704 if (!nsContentUtils::IsCallerTrustedForWrite()) {
5705 return NS_ERROR_DOM_SECURITY_ERR;
5708 nsAXPCNativeCallContext *ncc = nsnull;
5709 nsresult rv = nsContentUtils::XPConnect()->
5710 GetCurrentNativeCallContext(&ncc);
5711 NS_ENSURE_SUCCESS(rv, rv);
5713 if (!ncc)
5714 return NS_ERROR_NOT_AVAILABLE;
5716 JSContext *cx = nsnull;
5718 rv = ncc->GetJSContext(&cx);
5719 NS_ENSURE_SUCCESS(rv, rv);
5721 PRUint32 argc;
5722 jsval *argv = nsnull;
5724 // XXX - need to get this as nsISupports?
5725 ncc->GetArgc(&argc);
5726 ncc->GetArgvPtr(&argv);
5728 // Strip the url, name and options from the args seen by scripts.
5729 PRUint32 argOffset = argc < 3 ? argc : 3;
5730 nsCOMPtr<nsIArray> argvArray;
5731 rv = NS_CreateJSArgv(cx, argc - argOffset, argv + argOffset,
5732 getter_AddRefs(argvArray));
5733 NS_ENSURE_SUCCESS(rv, rv);
5735 return OpenInternal(aUrl, aName, aOptions,
5736 PR_TRUE, // aDialog
5737 PR_FALSE, // aContentModal
5738 PR_FALSE, // aCalledNoScript
5739 PR_FALSE, // aDoJSFixups
5740 argvArray, nsnull, // Arguments
5741 GetPrincipal(), // aCalleePrincipal
5742 cx, // aJSCallerContext
5743 _retval);
5746 NS_IMETHODIMP
5747 nsGlobalWindow::GetFrames(nsIDOMWindow** aFrames)
5749 FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
5751 *aFrames = this;
5752 NS_ADDREF(*aFrames);
5754 FlushPendingNotifications(Flush_ContentAndNotify);
5756 return NS_OK;
5759 nsGlobalWindow*
5760 nsGlobalWindow::CallerInnerWindow()
5762 JSContext *cx = nsContentUtils::GetCurrentJSContext();
5763 if (!cx) {
5764 NS_ERROR("Please don't call this method from C++!");
5766 return nsnull;
5769 JSObject *scope = nsnull;
5770 JSStackFrame *fp = nsnull;
5771 JS_FrameIterator(cx, &fp);
5772 if (fp) {
5773 while (fp->isDummyFrame()) {
5774 if (!JS_FrameIterator(cx, &fp))
5775 break;
5778 if (fp)
5779 scope = &fp->scopeChain();
5782 if (!scope)
5783 scope = JS_GetScopeChain(cx);
5785 JSAutoEnterCompartment ac;
5786 if (!ac.enter(cx, scope))
5787 return nsnull;
5789 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
5790 nsContentUtils::XPConnect()->
5791 GetWrappedNativeOfJSObject(cx, ::JS_GetGlobalForObject(cx, scope),
5792 getter_AddRefs(wrapper));
5793 if (!wrapper)
5794 return nsnull;
5796 // The calling window must be holding a reference, so we can just return a
5797 // raw pointer here and let the QI's addref be balanced by the nsCOMPtr
5798 // destructor's release.
5799 nsCOMPtr<nsPIDOMWindow> win = do_QueryWrappedNative(wrapper);
5800 if (!win)
5801 return GetCurrentInnerWindowInternal();
5802 return static_cast<nsGlobalWindow*>(win.get());
5807 * Class used to represent events generated by calls to Window.postMessage,
5808 * which asynchronously creates and dispatches events.
5810 class PostMessageEvent : public nsRunnable
5812 public:
5813 NS_DECL_NSIRUNNABLE
5815 PostMessageEvent(nsGlobalWindow* aSource,
5816 const nsAString& aCallerOrigin,
5817 const nsAString& aMessage,
5818 nsGlobalWindow* aTargetWindow,
5819 nsIURI* aProvidedOrigin,
5820 PRBool aTrustedCaller)
5821 : mSource(aSource),
5822 mCallerOrigin(aCallerOrigin),
5823 mMessage(aMessage),
5824 mTargetWindow(aTargetWindow),
5825 mProvidedOrigin(aProvidedOrigin),
5826 mTrustedCaller(aTrustedCaller)
5828 MOZ_COUNT_CTOR(PostMessageEvent);
5831 ~PostMessageEvent()
5833 MOZ_COUNT_DTOR(PostMessageEvent);
5836 private:
5837 nsRefPtr<nsGlobalWindow> mSource;
5838 nsString mCallerOrigin;
5839 nsString mMessage;
5840 nsRefPtr<nsGlobalWindow> mTargetWindow;
5841 nsCOMPtr<nsIURI> mProvidedOrigin;
5842 PRBool mTrustedCaller;
5845 NS_IMETHODIMP
5846 PostMessageEvent::Run()
5848 NS_ABORT_IF_FALSE(mTargetWindow->IsOuterWindow(),
5849 "should have been passed an outer window!");
5850 NS_ABORT_IF_FALSE(!mSource || mSource->IsOuterWindow(),
5851 "should have been passed an outer window!");
5853 nsRefPtr<nsGlobalWindow> targetWindow;
5854 if (mTargetWindow->IsClosedOrClosing() ||
5855 !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
5856 targetWindow->IsClosedOrClosing())
5857 return NS_OK;
5859 NS_ABORT_IF_FALSE(targetWindow->IsInnerWindow(),
5860 "we ordered an inner window!");
5862 // Ensure that any origin which might have been provided is the origin of this
5863 // window's document. Note that we do this *now* instead of when postMessage
5864 // is called because the target window might have been navigated to a
5865 // different location between then and now. If this check happened when
5866 // postMessage was called, it would be fairly easy for a malicious webpage to
5867 // intercept messages intended for another site by carefully timing navigation
5868 // of the target window so it changed location after postMessage but before
5869 // now.
5870 if (mProvidedOrigin) {
5871 // Get the target's origin either from its principal or, in the case the
5872 // principal doesn't carry a URI (e.g. the system principal), the target's
5873 // document.
5874 nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
5875 if (!targetPrin)
5876 return NS_OK;
5877 nsCOMPtr<nsIURI> targetURI;
5878 if (NS_FAILED(targetPrin->GetURI(getter_AddRefs(targetURI))))
5879 return NS_OK;
5880 if (!targetURI) {
5881 targetURI = targetWindow->mDoc->GetDocumentURI();
5882 if (!targetURI)
5883 return NS_OK;
5886 // Note: This is contrary to the spec with respect to file: URLs, which
5887 // the spec groups into a single origin, but given we intentionally
5888 // don't do that in other places it seems better to hold the line for
5889 // now. Long-term, we want HTML5 to address this so that we can
5890 // be compliant while being safer.
5891 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
5892 nsresult rv =
5893 ssm->CheckSameOriginURI(mProvidedOrigin, targetURI, PR_TRUE);
5894 if (NS_FAILED(rv))
5895 return NS_OK;
5899 // Create the event
5900 nsCOMPtr<nsIDOMDocumentEvent> docEvent =
5901 do_QueryInterface(targetWindow->mDocument);
5902 if (!docEvent)
5903 return NS_OK;
5904 nsCOMPtr<nsIDOMEvent> event;
5905 docEvent->CreateEvent(NS_LITERAL_STRING("MessageEvent"),
5906 getter_AddRefs(event));
5907 if (!event)
5908 return NS_OK;
5910 nsCOMPtr<nsIDOMMessageEvent> message = do_QueryInterface(event);
5911 nsresult rv = message->InitMessageEvent(NS_LITERAL_STRING("message"),
5912 PR_FALSE /* non-bubbling */,
5913 PR_TRUE /* cancelable */,
5914 mMessage,
5915 mCallerOrigin,
5916 EmptyString(),
5917 mSource);
5918 if (NS_FAILED(rv))
5919 return NS_OK;
5922 // We can't simply call dispatchEvent on the window because doing so ends
5923 // up flipping the trusted bit on the event, and we don't want that to
5924 // happen because then untrusted content can call postMessage on a chrome
5925 // window if it can get a reference to it.
5927 nsIPresShell *shell = targetWindow->mDoc->GetShell();
5928 nsRefPtr<nsPresContext> presContext;
5929 if (shell)
5930 presContext = shell->GetPresContext();
5932 nsCOMPtr<nsIPrivateDOMEvent> privEvent = do_QueryInterface(message);
5933 privEvent->SetTrusted(mTrustedCaller);
5934 nsEvent *internalEvent = privEvent->GetInternalNSEvent();
5936 nsEventStatus status = nsEventStatus_eIgnore;
5937 nsEventDispatcher::Dispatch(static_cast<nsPIDOMWindow*>(mTargetWindow),
5938 presContext,
5939 internalEvent,
5940 message,
5941 &status);
5942 return NS_OK;
5945 NS_IMETHODIMP
5946 nsGlobalWindow::PostMessageMoz(const nsAString& aMessage, const nsAString& aOrigin)
5948 FORWARD_TO_OUTER(PostMessageMoz, (aMessage, aOrigin), NS_ERROR_NOT_INITIALIZED);
5951 // Window.postMessage is an intentional subversion of the same-origin policy.
5952 // As such, this code must be particularly careful in the information it
5953 // exposes to calling code.
5955 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5958 // First, get the caller's window
5959 nsRefPtr<nsGlobalWindow> callerInnerWin = CallerInnerWindow();
5960 if (!callerInnerWin)
5961 return NS_OK;
5962 NS_ABORT_IF_FALSE(callerInnerWin->IsInnerWindow(),
5963 "should have gotten an inner window here");
5965 // Compute the caller's origin either from its principal or, in the case the
5966 // principal doesn't carry a URI (e.g. the system principal), the caller's
5967 // document. We must get this now instead of when the event is created and
5968 // dispatched, because ultimately it is the identity of the calling window
5969 // *now* that determines who sent the message (and not an identity which might
5970 // have changed due to intervening navigations).
5971 nsIPrincipal* callerPrin = callerInnerWin->GetPrincipal();
5972 if (!callerPrin)
5973 return NS_OK;
5975 nsCOMPtr<nsIURI> callerOuterURI;
5976 if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerOuterURI))))
5977 return NS_OK;
5979 nsAutoString origin;
5980 if (callerOuterURI) {
5981 // if the principal has a URI, use that to generate the origin
5982 nsContentUtils::GetUTFOrigin(callerPrin, origin);
5984 else {
5985 // otherwise use the URI of the document to generate origin
5986 nsCOMPtr<nsIDocument> doc = do_QueryInterface(callerInnerWin->mDocument);
5987 if (!doc)
5988 return NS_OK;
5989 callerOuterURI = doc->GetDocumentURI();
5990 // if the principal has a URI, use that to generate the origin
5991 nsContentUtils::GetUTFOrigin(callerOuterURI, origin);
5994 // Convert the provided origin string into a URI for comparison purposes.
5995 // "*" indicates no specific origin is required.
5996 nsCOMPtr<nsIURI> providedOrigin;
5997 if (!aOrigin.EqualsASCII("*")) {
5998 if (NS_FAILED(NS_NewURI(getter_AddRefs(providedOrigin), aOrigin)))
5999 return NS_ERROR_DOM_SYNTAX_ERR;
6000 if (NS_FAILED(providedOrigin->SetUserPass(EmptyCString())) ||
6001 NS_FAILED(providedOrigin->SetPath(EmptyCString())))
6002 return NS_OK;
6005 // Create and asynchronously dispatch a runnable which will handle actual DOM
6006 // event creation and dispatch.
6007 nsRefPtr<PostMessageEvent> event =
6008 new PostMessageEvent(nsContentUtils::IsCallerChrome()
6009 ? nsnull
6010 : callerInnerWin->GetOuterWindowInternal(),
6011 origin,
6012 aMessage,
6013 this,
6014 providedOrigin,
6015 nsContentUtils::IsCallerTrustedForWrite());
6016 return NS_DispatchToCurrentThread(event);
6019 class nsCloseEvent : public nsRunnable {
6021 nsRefPtr<nsGlobalWindow> mWindow;
6023 nsCloseEvent(nsGlobalWindow *aWindow)
6024 : mWindow(aWindow)
6027 public:
6029 static nsresult
6030 PostCloseEvent(nsGlobalWindow* aWindow) {
6031 nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow);
6032 nsresult rv = NS_DispatchToCurrentThread(ev);
6033 if (NS_SUCCEEDED(rv))
6034 aWindow->MaybeForgiveSpamCount();
6035 return rv;
6038 NS_IMETHOD Run() {
6039 if (mWindow)
6040 mWindow->ReallyCloseWindow();
6041 return NS_OK;
6046 PRBool
6047 nsGlobalWindow::CanClose()
6049 if (!mDocShell)
6050 return PR_TRUE;
6052 // Ask the content viewer whether the toplevel window can close.
6053 // If the content viewer returns false, it is responsible for calling
6054 // Close() as soon as it is possible for the window to close.
6055 // This allows us to not close the window while printing is happening.
6057 nsCOMPtr<nsIContentViewer> cv;
6058 mDocShell->GetContentViewer(getter_AddRefs(cv));
6059 if (cv) {
6060 PRBool canClose;
6061 nsresult rv = cv->PermitUnload(PR_FALSE, &canClose);
6062 if (NS_SUCCEEDED(rv) && !canClose)
6063 return PR_FALSE;
6065 rv = cv->RequestWindowClose(&canClose);
6066 if (NS_SUCCEEDED(rv) && !canClose)
6067 return PR_FALSE;
6070 return PR_TRUE;
6073 NS_IMETHODIMP
6074 nsGlobalWindow::Close()
6076 FORWARD_TO_OUTER(Close, (), NS_ERROR_NOT_INITIALIZED);
6078 if (IsFrame() || !mDocShell || IsInModalState()) {
6079 // window.close() is called on a frame in a frameset, on a window
6080 // that's already closed, or on a window for which there's
6081 // currently a modal dialog open. Ignore such calls.
6083 return NS_OK;
6086 if (mHavePendingClose) {
6087 // We're going to be closed anyway; do nothing since we don't want
6088 // to double-close
6089 return NS_OK;
6092 if (mBlockScriptedClosingFlag)
6094 // A script's popup has been blocked and we don't want
6095 // the window to be closed directly after this event,
6096 // so the user can see that there was a blocked popup.
6097 return NS_OK;
6100 // Don't allow scripts from content to close windows
6101 // that were not opened by script
6102 if (!mHadOriginalOpener && !nsContentUtils::IsCallerTrustedForWrite()) {
6103 PRBool allowClose =
6104 nsContentUtils::GetBoolPref("dom.allow_scripts_to_close_windows",
6105 PR_TRUE);
6106 if (!allowClose) {
6107 // We're blocking the close operation
6108 // report localized error msg in JS console
6109 nsContentUtils::ReportToConsole(
6110 nsContentUtils::eDOM_PROPERTIES,
6111 "WindowCloseBlockedWarning",
6112 nsnull, 0, // No params
6113 nsnull,
6114 EmptyString(), 0, 0, // No source, or column/line number
6115 nsIScriptError::warningFlag,
6116 "DOM Window", mDoc); // Better name for the category?
6118 return NS_OK;
6122 if (!mInClose && !mIsClosed && !CanClose())
6123 return NS_OK;
6125 // Fire a DOM event notifying listeners that this window is about to
6126 // be closed. The tab UI code may choose to cancel the default
6127 // action for this event, if so, we won't actually close the window
6128 // (since the tab UI code will close the tab in stead). Sure, this
6129 // could be abused by content code, but do we care? I don't think
6130 // so...
6132 PRBool wasInClose = mInClose;
6133 mInClose = PR_TRUE;
6135 if (!DispatchCustomEvent("DOMWindowClose")) {
6136 // Someone chose to prevent the default action for this event, if
6137 // so, let's not close this window after all...
6139 mInClose = wasInClose;
6140 return NS_OK;
6143 return FinalClose();
6146 nsresult
6147 nsGlobalWindow::ForceClose()
6149 if (IsFrame() || !mDocShell) {
6150 // This may be a frame in a frameset, or a window that's already closed.
6151 // Ignore such calls.
6153 return NS_OK;
6156 if (mHavePendingClose) {
6157 // We're going to be closed anyway; do nothing since we don't want
6158 // to double-close
6159 return NS_OK;
6162 mInClose = PR_TRUE;
6164 DispatchCustomEvent("DOMWindowClose");
6166 return FinalClose();
6169 nsresult
6170 nsGlobalWindow::FinalClose()
6172 nsresult rv;
6173 // Flag that we were closed.
6174 mIsClosed = PR_TRUE;
6176 nsCOMPtr<nsIJSContextStack> stack =
6177 do_GetService(sJSStackContractID);
6179 JSContext *cx = nsnull;
6181 if (stack) {
6182 stack->Peek(&cx);
6185 if (cx) {
6186 nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
6188 if (currentCX && currentCX == GetContextInternal()) {
6189 // We ignore the return value here. If setting the termination function
6190 // fails, it's better to fail to close the window than it is to crash
6191 // (which is what would tend to happen if we did this synchronously
6192 // here).
6193 rv = currentCX->SetTerminationFunction(CloseWindow,
6194 static_cast<nsIDOMWindow *>
6195 (this));
6196 if (NS_SUCCEEDED(rv)) {
6197 mHavePendingClose = PR_TRUE;
6199 return NS_OK;
6204 // We may have plugins on the page that have issued this close from their
6205 // event loop and because we currently destroy the plugin window with
6206 // frames, we crash. So, if we are called from Javascript, post an event
6207 // to really close the window.
6208 rv = NS_ERROR_FAILURE;
6209 if (!nsContentUtils::IsCallerChrome()) {
6210 rv = nsCloseEvent::PostCloseEvent(this);
6213 if (NS_FAILED(rv)) {
6214 ReallyCloseWindow();
6215 rv = NS_OK;
6216 } else {
6217 mHavePendingClose = PR_TRUE;
6220 return rv;
6224 void
6225 nsGlobalWindow::ReallyCloseWindow()
6227 FORWARD_TO_OUTER_VOID(ReallyCloseWindow, ());
6229 // Make sure we never reenter this method.
6230 mHavePendingClose = PR_TRUE;
6232 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
6233 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
6235 // If there's no treeOwnerAsWin, this window must already be closed.
6237 if (treeOwnerAsWin) {
6239 // but if we're a browser window we could be in some nasty
6240 // self-destroying cascade that we should mostly ignore
6242 nsCOMPtr<nsIDocShellTreeItem> docItem(do_QueryInterface(mDocShell));
6243 if (docItem) {
6244 nsCOMPtr<nsIBrowserDOMWindow> bwin;
6245 nsCOMPtr<nsIDocShellTreeItem> rootItem;
6246 docItem->GetRootTreeItem(getter_AddRefs(rootItem));
6247 nsCOMPtr<nsIDOMWindow> rootWin(do_GetInterface(rootItem));
6248 nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
6249 if (chromeWin)
6250 chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
6252 if (rootWin) {
6253 /* Normally we destroy the entire window, but not if
6254 this DOM window belongs to a tabbed browser and doesn't
6255 correspond to a tab. This allows a well-behaved tab
6256 to destroy the container as it should but is a final measure
6257 to prevent an errant tab from doing so when it shouldn't.
6258 This works because we reach this code when we shouldn't only
6259 in the particular circumstance that we belong to a tab
6260 that has just been closed (and is therefore already missing
6261 from the list of browsers) (and has an unload handler
6262 that closes the window). */
6263 // XXXbz now that we have mHavePendingClose, is this needed?
6264 PRBool isTab = PR_FALSE;
6265 if (rootWin == this ||
6266 !bwin || (bwin->IsTabContentWindow(GetOuterWindowInternal(),
6267 &isTab), isTab))
6268 treeOwnerAsWin->Destroy();
6272 CleanUp(PR_FALSE);
6276 nsIDOMWindow *
6277 nsGlobalWindow::EnterModalState()
6279 nsGlobalWindow* topWin = GetTop();
6281 if (!topWin) {
6282 NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
6284 return nsnull;
6287 // If there is an active ESM in this window, clear it. Otherwise, this can
6288 // cause a problem if a modal state is entered during a mouseup event.
6289 nsEventStateManager* activeESM =
6290 static_cast<nsEventStateManager*>(nsEventStateManager::GetActiveEventStateManager());
6291 if (activeESM && activeESM->GetPresContext()) {
6292 nsIPresShell* activeShell = activeESM->GetPresContext()->GetPresShell();
6293 if (activeShell && (
6294 nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(), mDoc) ||
6295 nsContentUtils::ContentIsCrossDocDescendantOf(mDoc, activeShell->GetDocument()))) {
6296 nsEventStateManager::ClearGlobalActiveContent(activeESM);
6298 activeShell->SetCapturingContent(nsnull, 0);
6300 if (activeShell) {
6301 nsCOMPtr<nsFrameSelection> frameSelection = activeShell->FrameSelection();
6302 frameSelection->SetMouseDownState(PR_FALSE);
6307 if (topWin->mModalStateDepth == 0) {
6308 NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
6310 mSuspendedDoc = do_QueryInterface(topWin->GetExtantDocument());
6311 if (mSuspendedDoc && mSuspendedDoc->EventHandlingSuppressed()) {
6312 mSuspendedDoc->SuppressEventHandling();
6313 } else {
6314 mSuspendedDoc = nsnull;
6317 topWin->mModalStateDepth++;
6319 JSContext *cx = nsContentUtils::GetCurrentJSContext();
6321 nsCOMPtr<nsIDOMWindow> callerWin;
6322 nsIScriptContext *scx;
6323 if (cx && (scx = GetScriptContextFromJSContext(cx))) {
6324 scx->EnterModalState();
6325 callerWin = do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
6328 if (mContext) {
6329 mContext->EnterModalState();
6332 return callerWin;
6335 // static
6336 void
6337 nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
6338 nsGlobalWindow *aWindow)
6340 nsGlobalWindow *inner;
6342 // Return early if we're frozen or have no inner window.
6343 if (!(inner = aWindow->GetCurrentInnerWindowInternal()) ||
6344 inner->IsFrozen()) {
6345 return;
6348 inner->RunTimeout(nsnull);
6350 // Check again if we're frozen since running pending timeouts
6351 // could've frozen us.
6352 if (inner->IsFrozen()) {
6353 return;
6356 nsCOMPtr<nsIDOMWindowCollection> frames;
6357 aWindow->GetFrames(getter_AddRefs(frames));
6359 if (!frames) {
6360 return;
6363 PRUint32 i, length;
6364 if (NS_FAILED(frames->GetLength(&length)) || !length) {
6365 return;
6368 for (i = 0; i < length && aTopWindow->mModalStateDepth == 0; i++) {
6369 nsCOMPtr<nsIDOMWindow> child;
6370 frames->Item(i, getter_AddRefs(child));
6372 if (!child) {
6373 return;
6376 nsGlobalWindow *childWin =
6377 static_cast<nsGlobalWindow *>
6378 (static_cast<nsIDOMWindow *>
6379 (child.get()));
6381 RunPendingTimeoutsRecursive(aTopWindow, childWin);
6385 class nsPendingTimeoutRunner : public nsRunnable
6387 public:
6388 nsPendingTimeoutRunner(nsGlobalWindow *aWindow)
6389 : mWindow(aWindow)
6391 NS_ASSERTION(mWindow, "mWindow is null.");
6394 NS_IMETHOD Run()
6396 nsGlobalWindow::RunPendingTimeoutsRecursive(mWindow, mWindow);
6398 return NS_OK;
6401 private:
6402 nsRefPtr<nsGlobalWindow> mWindow;
6405 void
6406 nsGlobalWindow::LeaveModalState(nsIDOMWindow *aCallerWin)
6408 nsGlobalWindow *topWin = GetTop();
6410 if (!topWin) {
6411 NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
6412 return;
6415 topWin->mModalStateDepth--;
6417 if (topWin->mModalStateDepth == 0) {
6418 nsCOMPtr<nsIRunnable> runner = new nsPendingTimeoutRunner(topWin);
6419 if (NS_FAILED(NS_DispatchToCurrentThread(runner)))
6420 NS_WARNING("failed to dispatch pending timeout runnable");
6422 if (mSuspendedDoc) {
6423 nsCOMPtr<nsIDocument> currentDoc =
6424 do_QueryInterface(topWin->GetExtantDocument());
6425 mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(currentDoc == mSuspendedDoc);
6426 mSuspendedDoc = nsnull;
6430 JSContext *cx = nsContentUtils::GetCurrentJSContext();
6432 if (aCallerWin) {
6433 nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aCallerWin));
6434 nsIScriptContext *scx = sgo->GetContext();
6435 scx->LeaveModalState();
6438 if (mContext) {
6439 mContext->LeaveModalState();
6442 // Remember the time of the last dialog quit.
6443 nsGlobalWindow *inner = topWin->GetCurrentInnerWindowInternal();
6444 if (inner)
6445 inner->mLastDialogQuitTime = TimeStamp::Now();
6448 PRBool
6449 nsGlobalWindow::IsInModalState()
6451 nsGlobalWindow *topWin = GetTop();
6453 if (!topWin) {
6454 NS_ERROR("Uh, IsInModalState() called w/o a reachable top window?");
6456 return PR_FALSE;
6459 return topWin->mModalStateDepth != 0;
6462 // static
6463 void
6464 nsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow) {
6465 nsCOMPtr<nsIObserverService> observerService =
6466 do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
6467 if (observerService) {
6468 observerService->
6469 NotifyObservers(static_cast<nsIScriptGlobalObject*>(aWindow),
6470 DOM_WINDOW_DESTROYED_TOPIC, nsnull);
6474 class WindowDestroyedEvent : public nsRunnable
6476 public:
6477 WindowDestroyedEvent(PRUint64 aID, const char* aTopic) :
6478 mID(aID), mTopic(aTopic) {}
6480 NS_IMETHOD Run()
6482 nsCOMPtr<nsIObserverService> observerService =
6483 do_GetService("@mozilla.org/observer-service;1");
6484 if (observerService) {
6485 nsCOMPtr<nsISupportsPRUint64> wrapper =
6486 do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
6487 if (wrapper) {
6488 wrapper->SetData(mID);
6489 observerService->NotifyObservers(wrapper, mTopic.get(), nsnull);
6492 return NS_OK;
6495 private:
6496 PRUint64 mID;
6497 nsCString mTopic;
6500 void
6501 nsGlobalWindow::NotifyWindowIDDestroyed(const char* aTopic)
6503 nsRefPtr<nsIRunnable> runnable = new WindowDestroyedEvent(mWindowID, aTopic);
6504 nsresult rv = NS_DispatchToCurrentThread(runnable);
6505 if (NS_SUCCEEDED(rv)) {
6506 mNotifiedIDDestroyed = PR_TRUE;
6510 void
6511 nsGlobalWindow::InitJavaProperties()
6513 nsIScriptContext *scx = GetContextInternal();
6515 if (mDidInitJavaProperties || IsOuterWindow() || !scx || !mJSObject) {
6516 return;
6519 // Set mDidInitJavaProperties to true here even if initialization
6520 // can fail. If it fails, we won't try again...
6521 mDidInitJavaProperties = PR_TRUE;
6523 // Check whether the plugin supports NPRuntime, if so, init through
6524 // it.
6526 nsCOMPtr<nsIPluginHost> host(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
6527 if (!host) {
6528 return;
6531 mDummyJavaPluginOwner = new nsDummyJavaPluginOwner(mDoc);
6532 if (!mDummyJavaPluginOwner) {
6533 return;
6536 host->InstantiateDummyJavaPlugin(mDummyJavaPluginOwner);
6538 // It's possible for us (or the Java plugin, rather) to process
6539 // events during the above call, which can lead to this window being
6540 // torn down or what not, so re-check that the dummy plugin is still
6541 // around.
6542 if (!mDummyJavaPluginOwner) {
6543 return;
6546 nsCOMPtr<nsIPluginInstance> dummyPlugin;
6547 mDummyJavaPluginOwner->GetInstance(*getter_AddRefs(dummyPlugin));
6549 if (dummyPlugin) {
6550 // A dummy plugin was instantiated. This means we have a Java
6551 // plugin that supports NPRuntime. For such a plugin, the plugin
6552 // instantiation code defines the Java properties for us, so we're
6553 // done here.
6555 return;
6558 // No NPRuntime enabled Java plugin found, null out the owner we
6559 // would have used in that case as it's no longer needed.
6560 mDummyJavaPluginOwner = nsnull;
6563 void*
6564 nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey)
6566 void* handler = nsnull;
6567 if (mCachedXBLPrototypeHandlers.IsInitialized()) {
6568 mCachedXBLPrototypeHandlers.Get(aKey, &handler);
6570 return handler;
6573 void
6574 nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
6575 nsScriptObjectHolder& aHandler)
6577 if (!mCachedXBLPrototypeHandlers.IsInitialized() &&
6578 !mCachedXBLPrototypeHandlers.Init()) {
6579 NS_ERROR("Failed to initiailize hashtable!");
6580 return;
6583 if (!mCachedXBLPrototypeHandlers.Count()) {
6584 // Can't use macros to get the participant because nsGlobalChromeWindow also
6585 // runs through this code. Use QueryInterface to get the correct objects.
6586 nsXPCOMCycleCollectionParticipant* participant;
6587 CallQueryInterface(this, &participant);
6588 NS_ASSERTION(participant,
6589 "Failed to QI to nsXPCOMCycleCollectionParticipant!");
6591 nsISupports* thisSupports;
6592 QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
6593 reinterpret_cast<void**>(&thisSupports));
6594 NS_ASSERTION(thisSupports, "Failed to QI to nsCycleCollectionISupports!");
6596 nsresult rv = nsContentUtils::HoldJSObjects(thisSupports, participant);
6597 if (NS_FAILED(rv)) {
6598 NS_ERROR("nsContentUtils::HoldJSObjects failed!");
6599 return;
6603 mCachedXBLPrototypeHandlers.Put(aKey, aHandler);
6606 NS_IMETHODIMP
6607 nsGlobalWindow::GetFrameElement(nsIDOMElement** aFrameElement)
6609 FORWARD_TO_OUTER(GetFrameElement, (aFrameElement), NS_ERROR_NOT_INITIALIZED);
6611 *aFrameElement = nsnull;
6613 nsCOMPtr<nsIDocShellTreeItem> docShellTI(do_QueryInterface(mDocShell));
6615 if (!docShellTI) {
6616 return NS_OK;
6619 nsCOMPtr<nsIDocShellTreeItem> parent;
6620 docShellTI->GetSameTypeParent(getter_AddRefs(parent));
6622 if (!parent || parent == docShellTI) {
6623 // We're at a chrome boundary, don't expose the chrome iframe
6624 // element to content code.
6626 return NS_OK;
6629 *aFrameElement = mFrameElement;
6630 NS_IF_ADDREF(*aFrameElement);
6632 return NS_OK;
6635 // Helper for converting window.showModalDialog() options (list of ';'
6636 // separated name (:|=) value pairs) to a format that's parsable by
6637 // our normal window opening code.
6639 void
6640 ConvertDialogOptions(const nsAString& aOptions, nsAString& aResult)
6642 nsAString::const_iterator end;
6643 aOptions.EndReading(end);
6645 nsAString::const_iterator iter;
6646 aOptions.BeginReading(iter);
6648 while (iter != end) {
6649 // Skip whitespace.
6650 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6651 ++iter;
6654 nsAString::const_iterator name_start = iter;
6656 // Skip characters until we find whitespace, ';', ':', or '='
6657 while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
6658 *iter != ';' &&
6659 *iter != ':' &&
6660 *iter != '=') {
6661 ++iter;
6664 nsAString::const_iterator name_end = iter;
6666 // Skip whitespace.
6667 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6668 ++iter;
6671 if (*iter == ';') {
6672 // No value found, skip the ';' and keep going.
6673 ++iter;
6675 continue;
6678 nsAString::const_iterator value_start = iter;
6679 nsAString::const_iterator value_end = iter;
6681 if (*iter == ':' || *iter == '=') {
6682 // We found name followed by ':' or '='. Look for a value.
6684 iter++; // Skip the ':' or '='
6686 // Skip whitespace.
6687 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6688 ++iter;
6691 value_start = iter;
6693 // Skip until we find whitespace, or ';'.
6694 while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
6695 *iter != ';') {
6696 ++iter;
6699 value_end = iter;
6701 // Skip whitespace.
6702 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6703 ++iter;
6707 const nsDependentSubstring& name = Substring(name_start, name_end);
6708 const nsDependentSubstring& value = Substring(value_start, value_end);
6710 if (name.LowerCaseEqualsLiteral("center")) {
6711 if (value.LowerCaseEqualsLiteral("on") ||
6712 value.LowerCaseEqualsLiteral("yes") ||
6713 value.LowerCaseEqualsLiteral("1")) {
6714 aResult.AppendLiteral(",centerscreen=1");
6716 } else if (name.LowerCaseEqualsLiteral("dialogwidth")) {
6717 if (!value.IsEmpty()) {
6718 aResult.AppendLiteral(",width=");
6719 aResult.Append(value);
6721 } else if (name.LowerCaseEqualsLiteral("dialogheight")) {
6722 if (!value.IsEmpty()) {
6723 aResult.AppendLiteral(",height=");
6724 aResult.Append(value);
6726 } else if (name.LowerCaseEqualsLiteral("dialogtop")) {
6727 if (!value.IsEmpty()) {
6728 aResult.AppendLiteral(",top=");
6729 aResult.Append(value);
6731 } else if (name.LowerCaseEqualsLiteral("dialogleft")) {
6732 if (!value.IsEmpty()) {
6733 aResult.AppendLiteral(",left=");
6734 aResult.Append(value);
6736 } else if (name.LowerCaseEqualsLiteral("resizable")) {
6737 if (value.LowerCaseEqualsLiteral("on") ||
6738 value.LowerCaseEqualsLiteral("yes") ||
6739 value.LowerCaseEqualsLiteral("1")) {
6740 aResult.AppendLiteral(",resizable=1");
6742 } else if (name.LowerCaseEqualsLiteral("scroll")) {
6743 if (value.LowerCaseEqualsLiteral("off") ||
6744 value.LowerCaseEqualsLiteral("no") ||
6745 value.LowerCaseEqualsLiteral("0")) {
6746 aResult.AppendLiteral(",scrollbars=0");
6750 if (iter == end) {
6751 break;
6754 iter++;
6758 NS_IMETHODIMP
6759 nsGlobalWindow::ShowModalDialog(const nsAString& aURI, nsIVariant *aArgs,
6760 const nsAString& aOptions,
6761 nsIVariant **aRetVal)
6763 FORWARD_TO_OUTER(ShowModalDialog, (aURI, aArgs, aOptions, aRetVal),
6764 NS_ERROR_NOT_INITIALIZED);
6766 *aRetVal = nsnull;
6768 // Before bringing up the window/dialog, unsuppress painting and flush
6769 // pending reflows.
6770 EnsureReflowFlushAndPaint();
6772 if (AreDialogsBlocked() || !ConfirmDialogAllowed())
6773 return NS_ERROR_NOT_AVAILABLE;
6775 nsCOMPtr<nsIDOMWindow> dlgWin;
6776 nsAutoString options(NS_LITERAL_STRING("-moz-internal-modal=1,status=1"));
6778 ConvertDialogOptions(aOptions, options);
6780 options.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0");
6782 EnterModalState();
6783 nsresult rv = OpenInternal(aURI, EmptyString(), options,
6784 PR_FALSE, // aDialog
6785 PR_TRUE, // aContentModal
6786 PR_TRUE, // aCalledNoScript
6787 PR_TRUE, // aDoJSFixups
6788 nsnull, aArgs, // args
6789 GetPrincipal(), // aCalleePrincipal
6790 nsnull, // aJSCallerContext
6791 getter_AddRefs(dlgWin));
6792 LeaveModalState(nsnull);
6794 NS_ENSURE_SUCCESS(rv, rv);
6796 if (dlgWin) {
6797 nsCOMPtr<nsIPrincipal> subjectPrincipal;
6798 rv = nsContentUtils::GetSecurityManager()->
6799 GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
6800 if (NS_FAILED(rv)) {
6801 return rv;
6804 PRBool canAccess = PR_TRUE;
6806 if (subjectPrincipal) {
6807 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
6808 do_QueryInterface(dlgWin);
6809 nsCOMPtr<nsIPrincipal> dialogPrincipal;
6811 if (objPrincipal) {
6812 dialogPrincipal = objPrincipal->GetPrincipal();
6814 rv = subjectPrincipal->Subsumes(dialogPrincipal, &canAccess);
6815 NS_ENSURE_SUCCESS(rv, rv);
6816 } else {
6817 // Uh, not sure what kind of dialog this is. Prevent access to
6818 // be on the safe side...
6820 canAccess = PR_FALSE;
6824 nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(dlgWin));
6826 if (canAccess) {
6827 nsPIDOMWindow *inner = win->GetCurrentInnerWindow();
6829 nsCOMPtr<nsIDOMModalContentWindow> dlgInner(do_QueryInterface(inner));
6831 if (dlgInner) {
6832 dlgInner->GetReturnValue(aRetVal);
6836 nsRefPtr<nsGlobalWindow> winInternal =
6837 static_cast<nsGlobalWindow*>(win.get());
6838 if (winInternal->mCallCleanUpAfterModalDialogCloses) {
6839 winInternal->mCallCleanUpAfterModalDialogCloses = PR_FALSE;
6840 winInternal->CleanUp(PR_TRUE);
6844 return NS_OK;
6847 class CommandDispatcher : public nsRunnable
6849 public:
6850 CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
6851 const nsAString& aAction)
6852 : mDispatcher(aDispatcher), mAction(aAction) {}
6854 NS_IMETHOD Run()
6856 return mDispatcher->UpdateCommands(mAction);
6859 nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
6860 nsString mAction;
6863 NS_IMETHODIMP
6864 nsGlobalWindow::UpdateCommands(const nsAString& anAction)
6866 nsPIDOMWindow *rootWindow = nsGlobalWindow::GetPrivateRoot();
6867 if (!rootWindow)
6868 return NS_OK;
6870 nsCOMPtr<nsIDOMXULDocument> xulDoc =
6871 do_QueryInterface(rootWindow->GetExtantDocument());
6872 // See if we contain a XUL document.
6873 if (xulDoc) {
6874 // Retrieve the command dispatcher and call updateCommands on it.
6875 nsCOMPtr<nsIDOMXULCommandDispatcher> xulCommandDispatcher;
6876 xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher));
6877 if (xulCommandDispatcher) {
6878 nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
6879 anAction));
6883 return NS_OK;
6886 PRBool
6887 nsGlobalWindow::GetBlurSuppression()
6889 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
6890 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
6891 PRBool suppress = PR_FALSE;
6892 if (treeOwnerAsWin)
6893 treeOwnerAsWin->GetBlurSuppression(&suppress);
6894 return suppress;
6897 NS_IMETHODIMP
6898 nsGlobalWindow::GetSelection(nsISelection** aSelection)
6900 FORWARD_TO_OUTER(GetSelection, (aSelection), NS_ERROR_NOT_INITIALIZED);
6902 NS_ENSURE_ARG_POINTER(aSelection);
6903 *aSelection = nsnull;
6905 if (!mDocShell)
6906 return NS_OK;
6908 nsCOMPtr<nsIPresShell> presShell;
6909 mDocShell->GetPresShell(getter_AddRefs(presShell));
6911 if (!presShell)
6912 return NS_OK;
6914 *aSelection = presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
6916 NS_IF_ADDREF(*aSelection);
6918 return NS_OK;
6921 NS_IMETHODIMP
6922 nsGlobalWindow::Find(const nsAString& aStr, PRBool aCaseSensitive,
6923 PRBool aBackwards, PRBool aWrapAround, PRBool aWholeWord,
6924 PRBool aSearchInFrames, PRBool aShowDialog,
6925 PRBool *aDidFind)
6927 FORWARD_TO_OUTER(Find, (aStr, aCaseSensitive, aBackwards, aWrapAround,
6928 aWholeWord, aSearchInFrames, aShowDialog, aDidFind),
6929 NS_ERROR_NOT_INITIALIZED);
6931 nsresult rv = NS_OK;
6932 *aDidFind = PR_FALSE;
6934 nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
6935 NS_ENSURE_TRUE(finder, NS_ERROR_FAILURE);
6937 // Set the options of the search
6938 rv = finder->SetSearchString(PromiseFlatString(aStr).get());
6939 NS_ENSURE_SUCCESS(rv, rv);
6940 finder->SetMatchCase(aCaseSensitive);
6941 finder->SetFindBackwards(aBackwards);
6942 finder->SetWrapFind(aWrapAround);
6943 finder->SetEntireWord(aWholeWord);
6944 finder->SetSearchFrames(aSearchInFrames);
6946 // the nsIWebBrowserFind is initialized to use this window
6947 // as the search root, but uses focus to set the current search
6948 // frame. If we're being called from JS (as here), this window
6949 // should be the current search frame.
6950 nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
6951 if (framesFinder) {
6952 framesFinder->SetRootSearchFrame(this); // paranoia
6953 framesFinder->SetCurrentSearchFrame(this);
6956 // The Find API does not accept empty strings. Launch the Find Dialog.
6957 if (aStr.IsEmpty() || aShowDialog) {
6958 // See if the find dialog is already up using nsIWindowMediator
6959 nsCOMPtr<nsIWindowMediator> windowMediator =
6960 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
6962 nsCOMPtr<nsIDOMWindowInternal> findDialog;
6964 if (windowMediator) {
6965 windowMediator->GetMostRecentWindow(NS_LITERAL_STRING("findInPage").get(),
6966 getter_AddRefs(findDialog));
6969 if (findDialog) {
6970 // The Find dialog is already open, bring it to the top.
6971 rv = findDialog->Focus();
6972 } else { // Open a Find dialog
6973 if (finder) {
6974 nsCOMPtr<nsIDOMWindow> dialog;
6975 rv = OpenDialog(NS_LITERAL_STRING("chrome://global/content/finddialog.xul"),
6976 NS_LITERAL_STRING("_blank"),
6977 NS_LITERAL_STRING("chrome, resizable=no, dependent=yes"),
6978 finder, getter_AddRefs(dialog));
6981 } else {
6982 // Launch the search with the passed in search string
6983 rv = finder->FindNext(aDidFind);
6984 NS_ENSURE_SUCCESS(rv, rv);
6987 return rv;
6990 static PRBool
6991 Is8bit(const nsAString& aString)
6993 static const PRUnichar EIGHT_BIT = PRUnichar(~0x00FF);
6995 nsAString::const_iterator done_reading;
6996 aString.EndReading(done_reading);
6998 // for each chunk of |aString|...
6999 PRUint32 fragmentLength = 0;
7000 nsAString::const_iterator iter;
7001 for (aString.BeginReading(iter); iter != done_reading;
7002 iter.advance(PRInt32(fragmentLength))) {
7003 fragmentLength = PRUint32(iter.size_forward());
7004 const PRUnichar* c = iter.get();
7005 const PRUnichar* fragmentEnd = c + fragmentLength;
7007 // for each character in this chunk...
7008 while (c < fragmentEnd)
7009 if (*c++ & EIGHT_BIT)
7010 return PR_FALSE;
7013 return PR_TRUE;
7016 NS_IMETHODIMP
7017 nsGlobalWindow::Atob(const nsAString& aAsciiBase64String,
7018 nsAString& aBinaryData)
7020 if (!Is8bit(aAsciiBase64String)) {
7021 aBinaryData.Truncate();
7022 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
7025 nsresult rv = nsXPConnect::Base64Decode(aAsciiBase64String, aBinaryData);
7026 if (NS_FAILED(rv) && rv == NS_ERROR_INVALID_ARG) {
7027 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
7029 return rv;
7032 NS_IMETHODIMP
7033 nsGlobalWindow::Btoa(const nsAString& aBinaryData,
7034 nsAString& aAsciiBase64String)
7036 if (!Is8bit(aBinaryData)) {
7037 aAsciiBase64String.Truncate();
7038 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
7041 return nsXPConnect::Base64Encode(aBinaryData, aAsciiBase64String);
7044 //*****************************************************************************
7045 // nsGlobalWindow::nsIDOMEventTarget
7046 //*****************************************************************************
7048 NS_IMETHODIMP
7049 nsGlobalWindow::AddEventListener(const nsAString& aType,
7050 nsIDOMEventListener* aListener,
7051 PRBool aUseCapture)
7053 FORWARD_TO_INNER_CREATE(AddEventListener, (aType, aListener, aUseCapture),
7054 NS_ERROR_NOT_AVAILABLE);
7056 return AddEventListener(aType, aListener, aUseCapture, PR_FALSE, 0);
7059 NS_IMETHODIMP
7060 nsGlobalWindow::RemoveEventListener(const nsAString& aType,
7061 nsIDOMEventListener* aListener,
7062 PRBool aUseCapture)
7064 return RemoveGroupedEventListener(aType, aListener, aUseCapture, nsnull);
7067 NS_IMETHODIMP
7068 nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, PRBool* _retval)
7070 FORWARD_TO_INNER(DispatchEvent, (aEvent, _retval), NS_OK);
7072 if (!mDoc) {
7073 return NS_ERROR_FAILURE;
7076 // Obtain a presentation shell
7077 nsIPresShell *shell = mDoc->GetShell();
7078 nsRefPtr<nsPresContext> presContext;
7079 if (shell) {
7080 // Retrieve the context
7081 presContext = shell->GetPresContext();
7084 nsEventStatus status = nsEventStatus_eIgnore;
7085 nsresult rv =
7086 nsEventDispatcher::DispatchDOMEvent(GetOuterWindow(), nsnull, aEvent,
7087 presContext, &status);
7089 *_retval = (status != nsEventStatus_eConsumeNoDefault);
7090 return rv;
7093 //*****************************************************************************
7094 // nsGlobalWindow::nsIDOM3EventTarget
7095 //*****************************************************************************
7097 NS_IMETHODIMP
7098 nsGlobalWindow::AddGroupedEventListener(const nsAString & aType,
7099 nsIDOMEventListener *aListener,
7100 PRBool aUseCapture,
7101 nsIDOMEventGroup *aEvtGrp)
7103 FORWARD_TO_INNER_CREATE(AddGroupedEventListener,
7104 (aType, aListener, aUseCapture, aEvtGrp),
7105 NS_ERROR_NOT_AVAILABLE);
7107 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
7108 NS_ENSURE_STATE(manager);
7109 PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
7110 return manager->AddEventListenerByType(aListener, aType, flags, aEvtGrp);
7113 NS_IMETHODIMP
7114 nsGlobalWindow::RemoveGroupedEventListener(const nsAString & aType,
7115 nsIDOMEventListener *aListener,
7116 PRBool aUseCapture,
7117 nsIDOMEventGroup *aEvtGrp)
7119 FORWARD_TO_INNER(RemoveGroupedEventListener,
7120 (aType, aListener, aUseCapture, aEvtGrp),
7121 NS_ERROR_NOT_INITIALIZED);
7123 if (mListenerManager) {
7124 PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
7126 mListenerManager->RemoveEventListenerByType(aListener, aType, flags,
7127 aEvtGrp);
7129 return NS_OK;
7132 NS_IMETHODIMP
7133 nsGlobalWindow::CanTrigger(const nsAString & type, PRBool *_retval)
7135 return NS_ERROR_NOT_IMPLEMENTED;
7138 NS_IMETHODIMP
7139 nsGlobalWindow::IsRegisteredHere(const nsAString & type, PRBool *_retval)
7141 return NS_ERROR_NOT_IMPLEMENTED;
7144 NS_IMETHODIMP
7145 nsGlobalWindow::AddEventListener(const nsAString& aType,
7146 nsIDOMEventListener *aListener,
7147 PRBool aUseCapture, PRBool aWantsUntrusted,
7148 PRUint8 optional_argc)
7150 NS_ASSERTION(!aWantsUntrusted || optional_argc > 0,
7151 "Won't check if this is chrome, you want to set "
7152 "aWantsUntrusted to PR_FALSE or make the aWantsUntrusted "
7153 "explicit by making optional_argc non-zero.");
7155 if (IsOuterWindow() && mInnerWindow &&
7156 !nsContentUtils::CanCallerAccess(mInnerWindow)) {
7157 return NS_ERROR_DOM_SECURITY_ERR;
7160 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
7161 NS_ENSURE_STATE(manager);
7163 PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
7165 if (aWantsUntrusted ||
7166 (optional_argc == 0 && !nsContentUtils::IsChromeDoc(mDoc))) {
7167 flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
7170 return manager->AddEventListenerByType(aListener, aType, flags, nsnull);
7173 nsresult
7174 nsGlobalWindow::AddEventListenerByIID(nsIDOMEventListener* aListener,
7175 const nsIID& aIID)
7177 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
7178 NS_ENSURE_STATE(manager);
7179 return manager->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
7182 nsresult
7183 nsGlobalWindow::RemoveEventListenerByIID(nsIDOMEventListener* aListener,
7184 const nsIID& aIID)
7186 FORWARD_TO_INNER(RemoveEventListenerByIID, (aListener, aIID),
7187 NS_ERROR_NOT_INITIALIZED);
7189 if (mListenerManager) {
7190 mListenerManager->RemoveEventListenerByIID(aListener, aIID,
7191 NS_EVENT_FLAG_BUBBLE);
7192 return NS_OK;
7194 return NS_ERROR_FAILURE;
7197 nsIEventListenerManager*
7198 nsGlobalWindow::GetListenerManager(PRBool aCreateIfNotFound)
7200 FORWARD_TO_INNER_CREATE(GetListenerManager, (aCreateIfNotFound), nsnull);
7202 if (!mListenerManager) {
7203 if (!aCreateIfNotFound) {
7204 return nsnull;
7207 static NS_DEFINE_CID(kEventListenerManagerCID,
7208 NS_EVENTLISTENERMANAGER_CID);
7210 mListenerManager = do_CreateInstance(kEventListenerManagerCID);
7211 if (mListenerManager) {
7212 mListenerManager->SetListenerTarget(
7213 static_cast<nsPIDOMEventTarget*>(this));
7217 return mListenerManager;
7220 nsresult
7221 nsGlobalWindow::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
7223 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
7224 NS_ENSURE_STATE(manager);
7225 return manager->GetSystemEventGroupLM(aGroup);
7228 nsIScriptContext*
7229 nsGlobalWindow::GetContextForEventHandlers(nsresult* aRv)
7231 nsIScriptContext* scx = GetContext();
7232 *aRv = scx ? NS_OK : NS_ERROR_UNEXPECTED;
7233 return scx;
7236 //*****************************************************************************
7237 // nsGlobalWindow::nsPIDOMWindow
7238 //*****************************************************************************
7240 nsPIDOMWindow*
7241 nsGlobalWindow::GetPrivateParent()
7243 FORWARD_TO_OUTER(GetPrivateParent, (), nsnull);
7245 nsCOMPtr<nsIDOMWindow> parent;
7246 GetParent(getter_AddRefs(parent));
7248 if (static_cast<nsIDOMWindow *>(this) == parent.get()) {
7249 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
7250 if (!chromeElement)
7251 return nsnull; // This is ok, just means a null parent.
7253 nsIDocument* doc = chromeElement->GetDocument();
7254 if (!doc)
7255 return nsnull; // This is ok, just means a null parent.
7257 nsIScriptGlobalObject *globalObject = doc->GetScriptGlobalObject();
7258 if (!globalObject)
7259 return nsnull; // This is ok, just means a null parent.
7261 parent = do_QueryInterface(globalObject);
7264 if (parent) {
7265 return static_cast<nsGlobalWindow *>
7266 (static_cast<nsIDOMWindow*>(parent.get()));
7269 return nsnull;
7272 nsPIDOMWindow*
7273 nsGlobalWindow::GetPrivateRoot()
7275 FORWARD_TO_OUTER(GetPrivateRoot, (), nsnull);
7277 nsCOMPtr<nsIDOMWindow> top;
7278 GetTop(getter_AddRefs(top));
7280 nsCOMPtr<nsPIDOMWindow> ptop = do_QueryInterface(top);
7281 NS_ASSERTION(ptop, "cannot get ptop");
7282 if (!ptop)
7283 return nsnull;
7285 nsIDocShell *docShell = ptop->GetDocShell();
7287 // Get the chrome event handler from the doc shell, since we only
7288 // want to deal with XUL chrome handlers and not the new kind of
7289 // window root handler.
7290 nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
7291 docShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
7293 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
7294 if (chromeElement) {
7295 nsIDocument* doc = chromeElement->GetDocument();
7296 if (doc) {
7297 nsIDOMWindow *parent = doc->GetWindow();
7298 if (parent) {
7299 parent->GetTop(getter_AddRefs(top));
7304 return static_cast<nsGlobalWindow *>
7305 (static_cast<nsIDOMWindow *>(top));
7309 NS_IMETHODIMP
7310 nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation)
7312 FORWARD_TO_INNER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED);
7314 *aLocation = nsnull;
7316 nsIDocShell *docShell = GetDocShell();
7317 if (!mLocation && docShell) {
7318 mLocation = new nsLocation(docShell);
7319 if (!mLocation) {
7320 return NS_ERROR_OUT_OF_MEMORY;
7324 NS_IF_ADDREF(*aLocation = mLocation);
7326 return NS_OK;
7329 void
7330 nsGlobalWindow::ActivateOrDeactivate(PRBool aActivate)
7332 // Set / unset mIsActive on the top level window, which is used for the
7333 // :-moz-window-inactive pseudoclass.
7334 nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
7335 if (!mainWidget)
7336 return;
7338 // Get the top level widget (if the main widget is a sheet, this will
7339 // be the sheet's top (non-sheet) parent).
7340 nsCOMPtr<nsIWidget> topLevelWidget = mainWidget->GetSheetWindowParent();
7341 if (!topLevelWidget) {
7342 topLevelWidget = mainWidget;
7345 // Get the top level widget's nsGlobalWindow
7346 nsCOMPtr<nsIDOMWindowInternal> topLevelWindow;
7347 if (topLevelWidget == mainWidget) {
7348 topLevelWindow = static_cast<nsIDOMWindowInternal*>(this);
7349 } else {
7350 // This is a workaround for the following problem:
7351 // When a window with an open sheet loses focus, only the sheet window
7352 // receives the NS_DEACTIVATE event. However, it's not the sheet that
7353 // should lose the active styling, but the containing top level window.
7354 void* clientData;
7355 topLevelWidget->GetClientData(clientData); // clientData is nsXULWindow
7356 nsISupports* data = static_cast<nsISupports*>(clientData);
7357 nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(data));
7358 topLevelWindow = do_GetInterface(req);
7360 if (topLevelWindow) {
7361 nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(topLevelWindow));
7362 piWin->SetActive(aActivate);
7366 static PRBool
7367 NotifyDocumentTree(nsIDocument* aDocument, void* aData)
7369 aDocument->EnumerateSubDocuments(NotifyDocumentTree, nsnull);
7370 aDocument->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
7371 return PR_TRUE;
7374 void
7375 nsGlobalWindow::SetActive(PRBool aActive)
7377 nsPIDOMWindow::SetActive(aActive);
7378 NotifyDocumentTree(mDoc, nsnull);
7381 void nsGlobalWindow::MaybeUpdateTouchState()
7383 FORWARD_TO_INNER_VOID(MaybeUpdateTouchState, ());
7385 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7387 nsCOMPtr<nsIDOMWindow> focusedWindow;
7388 fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
7390 if(this == focusedWindow) {
7391 UpdateTouchState();
7395 void nsGlobalWindow::UpdateTouchState()
7397 FORWARD_TO_INNER_VOID(UpdateTouchState, ());
7399 nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
7400 if (!mainWidget)
7401 return;
7403 if (mMayHaveTouchEventListener) {
7404 mainWidget->RegisterTouchWindow();
7405 } else {
7406 mainWidget->UnregisterTouchWindow();
7411 void
7412 nsGlobalWindow::EnableAccelerationUpdates()
7414 if (mHasAcceleration) {
7415 nsCOMPtr<nsIAccelerometer> ac =
7416 do_GetService(NS_ACCELEROMETER_CONTRACTID);
7417 if (ac) {
7418 ac->AddWindowListener(this);
7423 void
7424 nsGlobalWindow::DisableAccelerationUpdates()
7426 if (mHasAcceleration) {
7427 nsCOMPtr<nsIAccelerometer> ac =
7428 do_GetService(NS_ACCELEROMETER_CONTRACTID);
7429 if (ac) {
7430 ac->RemoveWindowListener(this);
7435 void
7436 nsGlobalWindow::SetChromeEventHandler(nsPIDOMEventTarget* aChromeEventHandler)
7438 SetChromeEventHandlerInternal(aChromeEventHandler);
7439 if (IsOuterWindow()) {
7440 // update the chrome event handler on all our inner windows
7441 for (nsGlobalWindow *inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
7442 inner != this;
7443 inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
7444 NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
7445 "bad outer window pointer");
7446 inner->SetChromeEventHandlerInternal(aChromeEventHandler);
7448 } else if (mOuterWindow) {
7449 // Need the cast to be able to call the protected method on a
7450 // superclass. We could make the method public instead, but it's really
7451 // better this way.
7452 static_cast<nsGlobalWindow*>(mOuterWindow.get())->
7453 SetChromeEventHandlerInternal(aChromeEventHandler);
7457 static PRBool IsLink(nsIContent* aContent)
7459 nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = do_QueryInterface(aContent);
7460 return (anchor || (aContent &&
7461 aContent->AttrValueIs(kNameSpaceID_XLink, nsGkAtoms::type,
7462 nsGkAtoms::simple, eCaseMatters)));
7465 void
7466 nsGlobalWindow::SetFocusedNode(nsIContent* aNode,
7467 PRUint32 aFocusMethod,
7468 PRBool aNeedsFocus)
7470 FORWARD_TO_INNER_VOID(SetFocusedNode, (aNode, aFocusMethod, aNeedsFocus));
7472 NS_ASSERTION(!aNode || aNode->GetCurrentDoc() == mDoc,
7473 "setting focus to a node from the wrong document");
7475 if (mFocusedNode != aNode) {
7476 UpdateCanvasFocus(PR_FALSE, aNode);
7477 mFocusedNode = aNode;
7478 mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
7479 mShowFocusRingForContent = PR_FALSE;
7482 if (mFocusedNode) {
7483 // if a node was focused by a keypress, turn on focus rings for the
7484 // window.
7485 if (mFocusMethod & nsIFocusManager::FLAG_BYKEY) {
7486 mFocusByKeyOccurred = PR_TRUE;
7487 } else if (
7488 // otherwise, we set mShowFocusRingForContent, as we don't want this to
7489 // be permanent for the window. On Windows, focus rings are only shown
7490 // when the FLAG_SHOWRING flag is used. On other platforms, focus rings
7491 // are only hidden for clicks on links.
7492 #ifndef XP_WIN
7493 !(mFocusMethod & nsIFocusManager::FLAG_BYMOUSE) || !IsLink(aNode) ||
7494 #endif
7495 aFocusMethod & nsIFocusManager::FLAG_SHOWRING) {
7496 mShowFocusRingForContent = PR_TRUE;
7500 if (aNeedsFocus)
7501 mNeedsFocus = aNeedsFocus;
7504 PRUint32
7505 nsGlobalWindow::GetFocusMethod()
7507 FORWARD_TO_INNER(GetFocusMethod, (), 0);
7509 return mFocusMethod;
7512 PRBool
7513 nsGlobalWindow::ShouldShowFocusRing()
7515 FORWARD_TO_INNER(ShouldShowFocusRing, (), PR_FALSE);
7517 return mShowFocusRings || mShowFocusRingForContent || mFocusByKeyOccurred;
7520 void
7521 nsGlobalWindow::SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
7522 UIStateChangeType aShowFocusRings)
7524 FORWARD_TO_INNER_VOID(SetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
7526 // only change the flags that have been modified
7527 if (aShowAccelerators != UIStateChangeType_NoChange)
7528 mShowAccelerators = aShowAccelerators == UIStateChangeType_Set;
7529 if (aShowFocusRings != UIStateChangeType_NoChange)
7530 mShowFocusRings = aShowFocusRings == UIStateChangeType_Set;
7532 // propagate the indicators to child windows
7533 nsCOMPtr<nsIDocShellTreeNode> node = do_QueryInterface(GetDocShell());
7534 if (node) {
7535 PRInt32 childCount = 0;
7536 node->GetChildCount(&childCount);
7538 for (PRInt32 i = 0; i < childCount; ++i) {
7539 nsCOMPtr<nsIDocShellTreeItem> childShell;
7540 node->GetChildAt(i, getter_AddRefs(childShell));
7541 nsCOMPtr<nsPIDOMWindow> childWindow = do_GetInterface(childShell);
7542 if (childWindow) {
7543 childWindow->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
7548 if (mHasFocus) {
7549 // send content state notifications
7550 nsCOMPtr<nsPresContext> presContext;
7551 if (mDocShell) {
7552 mDocShell->GetPresContext(getter_AddRefs(presContext));
7553 if (presContext) {
7554 presContext->EventStateManager()->
7555 SetContentState(mFocusedNode, NS_EVENT_STATE_FOCUS);
7561 void
7562 nsGlobalWindow::GetKeyboardIndicators(PRBool* aShowAccelerators,
7563 PRBool* aShowFocusRings)
7565 FORWARD_TO_INNER_VOID(GetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
7567 *aShowAccelerators = mShowAccelerators;
7568 *aShowFocusRings = mShowFocusRings;
7571 PRBool
7572 nsGlobalWindow::TakeFocus(PRBool aFocus, PRUint32 aFocusMethod)
7574 FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), PR_FALSE);
7576 if (aFocus)
7577 mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
7579 if (mHasFocus != aFocus) {
7580 mHasFocus = aFocus;
7581 UpdateCanvasFocus(PR_TRUE, mFocusedNode);
7584 // if mNeedsFocus is true, then the document has not yet received a
7585 // document-level focus event. If there is a root content node, then return
7586 // true to tell the calling focus manager that a focus event is expected. If
7587 // there is no root content node, the document hasn't loaded enough yet, or
7588 // there isn't one and there is no point in firing a focus event.
7589 if (aFocus && mNeedsFocus && mDoc && mDoc->GetRootElement() != nsnull) {
7590 mNeedsFocus = PR_FALSE;
7591 return PR_TRUE;
7594 mNeedsFocus = PR_FALSE;
7595 return PR_FALSE;
7598 void
7599 nsGlobalWindow::SetReadyForFocus()
7601 FORWARD_TO_INNER_VOID(SetReadyForFocus, ());
7603 PRBool oldNeedsFocus = mNeedsFocus;
7604 mNeedsFocus = PR_FALSE;
7606 // update whether focus rings need to be shown using the state from the
7607 // root window
7608 nsPIDOMWindow* root = GetPrivateRoot();
7609 if (root) {
7610 PRBool showAccelerators, showFocusRings;
7611 root->GetKeyboardIndicators(&showAccelerators, &showFocusRings);
7612 mShowFocusRings = showFocusRings;
7615 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7616 if (fm)
7617 fm->WindowShown(this, oldNeedsFocus);
7620 void
7621 nsGlobalWindow::PageHidden()
7623 FORWARD_TO_INNER_VOID(PageHidden, ());
7625 // the window is being hidden, so tell the focus manager that the frame is
7626 // no longer valid. Use the persisted field to determine if the document
7627 // is being destroyed.
7629 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7630 if (fm)
7631 fm->WindowHidden(this);
7633 mNeedsFocus = PR_TRUE;
7636 nsresult
7637 nsGlobalWindow::DispatchAsyncHashchange()
7639 FORWARD_TO_INNER(DispatchAsyncHashchange, (), NS_OK);
7641 nsCOMPtr<nsIRunnable> event =
7642 NS_NewRunnableMethod(this, &nsGlobalWindow::FireHashchange);
7644 return NS_DispatchToCurrentThread(event);
7647 nsresult
7648 nsGlobalWindow::FireHashchange()
7650 NS_ENSURE_TRUE(IsInnerWindow(), NS_ERROR_FAILURE);
7652 // Don't do anything if the window is frozen.
7653 if (IsFrozen())
7654 return NS_OK;
7656 // Dispatch the hashchange event, which doesn't bubble and isn't cancelable,
7657 // to the outer window.
7658 return nsContentUtils::DispatchTrustedEvent(mDoc, GetOuterWindow(),
7659 NS_LITERAL_STRING("hashchange"),
7660 PR_FALSE, PR_FALSE);
7663 nsresult
7664 nsGlobalWindow::DispatchSyncPopState()
7666 FORWARD_TO_INNER(DispatchSyncPopState, (), NS_OK);
7668 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
7669 "Must be safe to run script here.");
7671 // Check that PopState hasn't been pref'ed off.
7672 if (!nsContentUtils::GetBoolPref(sPopStatePrefStr, PR_FALSE))
7673 return NS_OK;
7675 nsresult rv = NS_OK;
7677 // Bail if the window is frozen.
7678 if (IsFrozen()) {
7679 return NS_OK;
7682 // Bail if there's no document or the document's readystate isn't "complete".
7683 if (!mDoc) {
7684 return NS_OK;
7687 nsIDocument::ReadyState readyState = mDoc->GetReadyStateEnum();
7688 if (readyState != nsIDocument::READYSTATE_COMPLETE) {
7689 return NS_OK;
7692 // Get the document's pending state object -- it contains the data we're
7693 // going to send along with the popstate event. The object is serialized as
7694 // JSON.
7695 nsAString& stateObjJSON = mDoc->GetPendingStateObject();
7697 nsCOMPtr<nsIVariant> stateObj;
7698 // Parse the JSON, if there's any to parse.
7699 if (!stateObjJSON.IsEmpty()) {
7700 // Get the JSContext associated with our document. We need this for
7701 // deserialization.
7702 nsCOMPtr<nsIDocument> document = do_QueryInterface(mDocument);
7703 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
7705 // Get the JSContext from the document, like we do in
7706 // nsContentUtils::GetContextFromDocument().
7707 nsIScriptGlobalObject *sgo = document->GetScopeObject();
7708 NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
7710 nsIScriptContext *scx = sgo->GetContext();
7711 NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
7713 JSContext *cx = (JSContext*) scx->GetNativeContext();
7715 // Make sure we in the request while we have jsval on the native stack.
7716 JSAutoRequest ar(cx);
7718 // If our json call triggers a JS-to-C++ call, we want that call to use cx
7719 // as the context. So we push cx onto the context stack.
7720 nsCxPusher cxPusher;
7722 jsval jsStateObj = JSVAL_NULL;
7724 // Deserialize the state object into an nsIVariant.
7725 nsCOMPtr<nsIJSON> json = do_GetService("@mozilla.org/dom/json;1");
7726 NS_ENSURE_TRUE(cxPusher.Push(cx), NS_ERROR_FAILURE);
7727 rv = json->DecodeToJSVal(stateObjJSON, cx, &jsStateObj);
7728 NS_ENSURE_SUCCESS(rv, rv);
7729 cxPusher.Pop();
7731 nsCOMPtr<nsIXPConnect> xpconnect = do_GetService(nsIXPConnect::GetCID());
7732 NS_ENSURE_TRUE(xpconnect, NS_ERROR_FAILURE);
7733 rv = xpconnect->JSValToVariant(cx, &jsStateObj, getter_AddRefs(stateObj));
7734 NS_ENSURE_SUCCESS(rv, rv);
7737 // Obtain a presentation shell for use in creating a popstate event.
7738 nsIPresShell *shell = mDoc->GetShell();
7739 nsRefPtr<nsPresContext> presContext;
7740 if (shell) {
7741 presContext = shell->GetPresContext();
7744 // Create a new popstate event
7745 nsCOMPtr<nsIDOMEvent> domEvent;
7746 rv = nsEventDispatcher::CreateEvent(presContext, nsnull,
7747 NS_LITERAL_STRING("popstateevent"),
7748 getter_AddRefs(domEvent));
7749 NS_ENSURE_SUCCESS(rv, rv);
7751 nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(domEvent);
7752 NS_ENSURE_TRUE(privateEvent, NS_ERROR_FAILURE);
7754 // Initialize the popstate event, which does bubble but isn't cancellable.
7755 nsCOMPtr<nsIDOMPopStateEvent> popstateEvent = do_QueryInterface(domEvent);
7756 rv = popstateEvent->InitPopStateEvent(NS_LITERAL_STRING("popstate"),
7757 PR_TRUE, PR_FALSE,
7758 stateObj);
7759 NS_ENSURE_SUCCESS(rv, rv);
7761 rv = privateEvent->SetTrusted(PR_TRUE);
7762 NS_ENSURE_SUCCESS(rv, rv);
7764 nsCOMPtr<nsIDOMEventTarget> outerWindow =
7765 do_QueryInterface(GetOuterWindow());
7766 NS_ENSURE_TRUE(outerWindow, NS_ERROR_UNEXPECTED);
7768 rv = privateEvent->SetTarget(outerWindow);
7769 NS_ENSURE_SUCCESS(rv, rv);
7771 PRBool dummy; // default action
7772 return DispatchEvent(popstateEvent, &dummy);
7775 // Find an nsICanvasFrame under aFrame. Only search the principal
7776 // child lists. aFrame must be non-null.
7777 static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame)
7779 nsCanvasFrame* canvasFrame = do_QueryFrame(aFrame);
7780 if (canvasFrame) {
7781 return canvasFrame;
7784 nsIFrame* kid = aFrame->GetFirstChild(nsnull);
7785 while (kid) {
7786 canvasFrame = FindCanvasFrame(kid);
7787 if (canvasFrame) {
7788 return canvasFrame;
7790 kid = kid->GetNextSibling();
7793 return nsnull;
7796 //-------------------------------------------------------
7797 // Tells the HTMLFrame/CanvasFrame that is now has focus
7798 void
7799 nsGlobalWindow::UpdateCanvasFocus(PRBool aFocusChanged, nsIContent* aNewContent)
7801 // this is called from the inner window so use GetDocShell
7802 nsIDocShell* docShell = GetDocShell();
7803 if (!docShell)
7804 return;
7806 nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell);
7807 if (editorDocShell) {
7808 PRBool editable;
7809 editorDocShell->GetEditable(&editable);
7810 if (editable)
7811 return;
7814 nsCOMPtr<nsIPresShell> presShell;
7815 docShell->GetPresShell(getter_AddRefs(presShell));
7816 if (!presShell || !mDocument)
7817 return;
7819 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
7820 Element *rootElement = doc->GetRootElement();
7821 if (rootElement) {
7822 if ((mHasFocus || aFocusChanged) &&
7823 (mFocusedNode == rootElement || aNewContent == rootElement)) {
7824 nsIFrame* frame = rootElement->GetPrimaryFrame();
7825 if (frame) {
7826 frame = frame->GetParent();
7827 nsCanvasFrame* canvasFrame = do_QueryFrame(frame);
7828 if (canvasFrame) {
7829 canvasFrame->SetHasFocus(mHasFocus && rootElement == aNewContent);
7833 } else {
7834 // Look for the frame the hard way
7835 nsIFrame* frame = presShell->GetRootFrame();
7836 if (frame) {
7837 nsCanvasFrame* canvasFrame = FindCanvasFrame(frame);
7838 if (canvasFrame) {
7839 canvasFrame->SetHasFocus(PR_FALSE);
7845 //*****************************************************************************
7846 // nsGlobalWindow::nsIDOMViewCSS
7847 //*****************************************************************************
7849 NS_IMETHODIMP
7850 nsGlobalWindow::GetComputedStyle(nsIDOMElement* aElt,
7851 const nsAString& aPseudoElt,
7852 nsIDOMCSSStyleDeclaration** aReturn)
7854 FORWARD_TO_OUTER(GetComputedStyle, (aElt, aPseudoElt, aReturn),
7855 NS_ERROR_NOT_INITIALIZED);
7857 NS_ENSURE_ARG_POINTER(aReturn);
7858 *aReturn = nsnull;
7860 if (!aElt) {
7861 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
7864 if (!mDocShell) {
7865 return NS_OK;
7868 nsCOMPtr<nsIPresShell> presShell;
7869 mDocShell->GetPresShell(getter_AddRefs(presShell));
7871 if (!presShell) {
7872 return NS_OK;
7875 nsRefPtr<nsComputedDOMStyle> compStyle;
7876 nsresult rv = NS_NewComputedDOMStyle(aElt, aPseudoElt, presShell,
7877 getter_AddRefs(compStyle));
7878 NS_ENSURE_SUCCESS(rv, rv);
7880 *aReturn = compStyle.forget().get();
7882 return NS_OK;
7885 //*****************************************************************************
7886 // nsGlobalWindow::nsIDOMAbstractView
7887 //*****************************************************************************
7889 NS_IMETHODIMP
7890 nsGlobalWindow::GetDocument(nsIDOMDocumentView ** aDocumentView)
7892 NS_ENSURE_ARG_POINTER(aDocumentView);
7894 nsresult rv = NS_OK;
7896 if (mDocument) {
7897 rv = CallQueryInterface(mDocument, aDocumentView);
7899 else {
7900 *aDocumentView = nsnull;
7903 return rv;
7906 //*****************************************************************************
7907 // nsGlobalWindow::nsIDOMStorageWindow
7908 //*****************************************************************************
7910 NS_IMETHODIMP
7911 nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
7913 FORWARD_TO_INNER(GetSessionStorage, (aSessionStorage), NS_ERROR_UNEXPECTED);
7915 nsIPrincipal *principal = GetPrincipal();
7916 nsIDocShell* docShell = GetDocShell();
7918 if (!principal || !docShell) {
7919 *aSessionStorage = nsnull;
7920 return NS_OK;
7923 if (!nsContentUtils::GetBoolPref(kStorageEnabled)) {
7924 *aSessionStorage = nsnull;
7925 return NS_OK;
7928 if (mSessionStorage) {
7929 #ifdef PR_LOGGING
7930 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7931 PR_LogPrint("nsGlobalWindow %p has %p sessionStorage", this, mSessionStorage.get());
7933 #endif
7934 nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(mSessionStorage);
7935 if (piStorage) {
7936 PRBool canAccess = piStorage->CanAccess(principal);
7937 NS_ASSERTION(canAccess,
7938 "window %x owned sessionStorage "
7939 "that could not be accessed!");
7940 if (!canAccess) {
7941 mSessionStorage = nsnull;
7946 if (!mSessionStorage) {
7947 *aSessionStorage = nsnull;
7949 nsString documentURI;
7950 nsCOMPtr<nsIDOM3Document> document3 = do_QueryInterface(mDoc);
7951 if (document3)
7952 document3->GetDocumentURI(documentURI);
7954 nsresult rv = docShell->GetSessionStorageForPrincipal(principal,
7955 documentURI,
7956 PR_TRUE,
7957 getter_AddRefs(mSessionStorage));
7958 NS_ENSURE_SUCCESS(rv, rv);
7960 #ifdef PR_LOGGING
7961 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7962 PR_LogPrint("nsGlobalWindow %p tried to get a new sessionStorage %p", this, mSessionStorage.get());
7964 #endif
7966 if (!mSessionStorage) {
7967 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
7971 #ifdef PR_LOGGING
7972 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7973 PR_LogPrint("nsGlobalWindow %p returns %p sessionStorage", this, mSessionStorage.get());
7975 #endif
7977 NS_ADDREF(*aSessionStorage = mSessionStorage);
7978 return NS_OK;
7981 NS_IMETHODIMP
7982 nsGlobalWindow::GetGlobalStorage(nsIDOMStorageList ** aGlobalStorage)
7984 NS_ENSURE_ARG_POINTER(aGlobalStorage);
7986 #ifdef MOZ_STORAGE
7987 if (!nsContentUtils::GetBoolPref(kStorageEnabled)) {
7988 *aGlobalStorage = nsnull;
7989 return NS_OK;
7992 if (!sGlobalStorageList) {
7993 nsresult rv = NS_NewDOMStorageList(&sGlobalStorageList);
7994 NS_ENSURE_SUCCESS(rv, rv);
7997 *aGlobalStorage = sGlobalStorageList;
7998 NS_IF_ADDREF(*aGlobalStorage);
8000 return NS_OK;
8001 #else
8002 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
8003 #endif
8006 NS_IMETHODIMP
8007 nsGlobalWindow::GetLocalStorage(nsIDOMStorage ** aLocalStorage)
8009 FORWARD_TO_INNER(GetLocalStorage, (aLocalStorage), NS_ERROR_UNEXPECTED);
8011 NS_ENSURE_ARG(aLocalStorage);
8013 if (!nsContentUtils::GetBoolPref(kStorageEnabled)) {
8014 *aLocalStorage = nsnull;
8015 return NS_OK;
8018 if (!mLocalStorage) {
8019 *aLocalStorage = nsnull;
8021 nsresult rv;
8023 PRPackedBool unused;
8024 if (!nsDOMStorage::CanUseStorage(&unused))
8025 return NS_ERROR_DOM_SECURITY_ERR;
8027 nsIPrincipal *principal = GetPrincipal();
8028 if (!principal)
8029 return NS_OK;
8031 nsCOMPtr<nsIDOMStorageManager> storageManager =
8032 do_GetService("@mozilla.org/dom/storagemanager;1", &rv);
8033 NS_ENSURE_SUCCESS(rv, rv);
8035 nsString documentURI;
8036 nsCOMPtr<nsIDOM3Document> document3 = do_QueryInterface(mDoc);
8037 if (document3)
8038 document3->GetDocumentURI(documentURI);
8040 rv = storageManager->GetLocalStorageForPrincipal(principal,
8041 documentURI,
8042 getter_AddRefs(mLocalStorage));
8043 NS_ENSURE_SUCCESS(rv, rv);
8046 NS_ADDREF(*aLocalStorage = mLocalStorage);
8047 return NS_OK;
8050 //*****************************************************************************
8051 // nsGlobalWindow::nsIDOMStorageIndexedDB
8052 //*****************************************************************************
8054 NS_IMETHODIMP
8055 nsGlobalWindow::GetMozIndexedDB(nsIIDBFactory** _retval)
8057 if (!mIndexedDB) {
8058 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
8059 do_GetService(THIRDPARTYUTIL_CONTRACTID);
8060 NS_ENSURE_TRUE(thirdPartyUtil, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
8062 PRBool isThirdParty;
8063 nsresult rv = thirdPartyUtil->IsThirdPartyWindow(this, nsnull,
8064 &isThirdParty);
8065 NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
8067 if (isThirdParty) {
8068 NS_WARNING("IndexedDB is not permitted in a third-party window.");
8069 *_retval = nsnull;
8070 return NS_OK;
8073 mIndexedDB = indexedDB::IDBFactory::Create(this);
8074 NS_ENSURE_TRUE(mIndexedDB, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
8077 nsCOMPtr<nsIIDBFactory> request(mIndexedDB);
8078 request.forget(_retval);
8079 return NS_OK;
8082 //*****************************************************************************
8083 // nsGlobalWindow::nsIInterfaceRequestor
8084 //*****************************************************************************
8086 NS_IMETHODIMP
8087 nsGlobalWindow::GetInterface(const nsIID & aIID, void **aSink)
8089 NS_ENSURE_ARG_POINTER(aSink);
8090 *aSink = nsnull;
8092 if (aIID.Equals(NS_GET_IID(nsIDocCharset))) {
8093 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
8095 if (mDocShell) {
8096 nsCOMPtr<nsIDocCharset> docCharset(do_QueryInterface(mDocShell));
8097 if (docCharset) {
8098 *aSink = docCharset;
8099 NS_ADDREF(((nsISupports *) *aSink));
8103 else if (aIID.Equals(NS_GET_IID(nsIWebNavigation))) {
8104 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
8106 if (mDocShell) {
8107 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
8108 if (webNav) {
8109 *aSink = webNav;
8110 NS_ADDREF(((nsISupports *) *aSink));
8114 #ifdef NS_PRINTING
8115 else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
8116 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
8118 if (mDocShell) {
8119 nsCOMPtr<nsIContentViewer> viewer;
8120 mDocShell->GetContentViewer(getter_AddRefs(viewer));
8121 if (viewer) {
8122 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
8123 if (webBrowserPrint) {
8124 *aSink = webBrowserPrint;
8125 NS_ADDREF(((nsISupports *) *aSink));
8130 #endif
8131 else if (aIID.Equals(NS_GET_IID(nsIScriptEventManager))) {
8132 if (mDoc) {
8133 nsIScriptEventManager* mgr = mDoc->GetScriptEventManager();
8134 if (mgr) {
8135 *aSink = mgr;
8136 NS_ADDREF(((nsISupports *) *aSink));
8140 else if (aIID.Equals(NS_GET_IID(nsIDOMWindowUtils)) ||
8141 aIID.Equals(NS_GET_IID(nsIDOMWindowUtils_MOZILLA_2_0_BRANCH))) {
8142 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
8144 nsCOMPtr<nsISupports> utils(do_QueryReferent(mWindowUtils));
8145 if (utils) {
8146 *aSink = utils;
8147 NS_ADDREF(((nsISupports *) *aSink));
8148 } else {
8149 nsDOMWindowUtils *utilObj = new nsDOMWindowUtils(this);
8150 nsCOMPtr<nsISupports> utilsIfc =
8151 NS_ISUPPORTS_CAST(nsIDOMWindowUtils *, utilObj);
8152 if (utilsIfc) {
8153 mWindowUtils = do_GetWeakReference(utilsIfc);
8154 *aSink = utilsIfc;
8155 NS_ADDREF(((nsISupports *) *aSink));
8159 else {
8160 return QueryInterface(aIID, aSink);
8163 return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
8166 void
8167 nsGlobalWindow::FireOfflineStatusEvent()
8169 if (!mDoc)
8170 return;
8171 nsAutoString name;
8172 if (NS_IsOffline()) {
8173 name.AssignLiteral("offline");
8174 } else {
8175 name.AssignLiteral("online");
8177 // The event is fired at the body element, or if there is no body element,
8178 // at the document.
8179 nsCOMPtr<nsISupports> eventTarget = mDoc.get();
8180 nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDoc);
8181 if (htmlDoc) {
8182 nsCOMPtr<nsIDOMHTMLElement> body;
8183 htmlDoc->GetBody(getter_AddRefs(body));
8184 if (body) {
8185 eventTarget = body;
8188 else {
8189 nsCOMPtr<nsIDOMElement> documentElement;
8190 mDocument->GetDocumentElement(getter_AddRefs(documentElement));
8191 if(documentElement) {
8192 eventTarget = documentElement;
8195 nsContentUtils::DispatchTrustedEvent(mDoc, eventTarget, name, PR_TRUE, PR_FALSE);
8198 nsresult
8199 nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
8200 const PRUnichar* aData)
8202 if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
8203 if (IsFrozen()) {
8204 // if an even number of notifications arrive while we're frozen,
8205 // we don't need to fire.
8206 mFireOfflineStatusChangeEventOnThaw = !mFireOfflineStatusChangeEventOnThaw;
8207 } else {
8208 FireOfflineStatusEvent();
8210 return NS_OK;
8213 if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage-changed")) {
8214 nsIPrincipal *principal;
8215 nsresult rv;
8217 principal = GetPrincipal();
8218 if (principal) {
8219 // A global storage object changed, check to see if it's one
8220 // this window can access.
8222 nsCOMPtr<nsIURI> codebase;
8223 principal->GetURI(getter_AddRefs(codebase));
8225 if (!codebase) {
8226 return NS_OK;
8229 nsCAutoString currentDomain;
8230 rv = codebase->GetAsciiHost(currentDomain);
8231 if (NS_FAILED(rv)) {
8232 return NS_OK;
8235 if (!nsDOMStorageList::CanAccessDomain(NS_ConvertUTF16toUTF8(aData),
8236 currentDomain)) {
8237 // This window can't reach the global storage object for the
8238 // domain for which the change happened, so don't fire any
8239 // events in this window.
8241 return NS_OK;
8245 nsAutoString domain(aData);
8247 if (IsFrozen()) {
8248 // This window is frozen, rather than firing the events here,
8249 // store the domain in which the change happened and fire the
8250 // events if we're ever thawed.
8252 if (!mPendingStorageEventsObsolete) {
8253 mPendingStorageEventsObsolete = new nsDataHashtable<nsStringHashKey, PRBool>;
8254 NS_ENSURE_TRUE(mPendingStorageEventsObsolete, NS_ERROR_OUT_OF_MEMORY);
8256 rv = mPendingStorageEventsObsolete->Init();
8257 NS_ENSURE_SUCCESS(rv, rv);
8260 mPendingStorageEventsObsolete->Put(domain, PR_TRUE);
8262 return NS_OK;
8265 nsRefPtr<nsDOMStorageEventObsolete> event = new nsDOMStorageEventObsolete();
8266 NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
8268 rv = event->InitStorageEvent(NS_LITERAL_STRING("storage"), PR_FALSE, PR_FALSE, domain);
8269 NS_ENSURE_SUCCESS(rv, rv);
8271 nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
8273 nsCOMPtr<nsIDOMEventTarget> target;
8275 if (htmlDoc) {
8276 nsCOMPtr<nsIDOMHTMLElement> body;
8277 htmlDoc->GetBody(getter_AddRefs(body));
8279 target = do_QueryInterface(body);
8282 if (!target) {
8283 target = this;
8286 PRBool defaultActionEnabled;
8287 target->DispatchEvent((nsIDOMStorageEventObsolete *)event, &defaultActionEnabled);
8289 return NS_OK;
8292 if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage2-changed")) {
8293 nsIPrincipal *principal;
8294 nsresult rv;
8296 nsCOMPtr<nsIDOMStorageEvent> event = do_QueryInterface(aSubject, &rv);
8297 NS_ENSURE_SUCCESS(rv, rv);
8299 nsCOMPtr<nsIDOMStorage> changingStorage;
8300 rv = event->GetStorageArea(getter_AddRefs(changingStorage));
8301 NS_ENSURE_SUCCESS(rv, rv);
8303 nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(changingStorage);
8304 nsPIDOMStorage::nsDOMStorageType storageType = pistorage->StorageType();
8306 principal = GetPrincipal();
8307 switch (storageType)
8309 case nsPIDOMStorage::SessionStorage:
8311 if (SameCOMIdentity(mSessionStorage, changingStorage)) {
8312 // Do not fire any events for the same storage object, it's not shared
8313 // among windows, see nsGlobalWindow::GetSessionStoarge()
8314 return NS_OK;
8317 nsCOMPtr<nsIDOMStorage> storage = mSessionStorage;
8318 if (!storage) {
8319 nsIDocShell* docShell = GetDocShell();
8320 if (principal && docShell) {
8321 // No need to pass documentURI here, it's only needed when we want
8322 // to create a new storage, the third paramater would be PR_TRUE
8323 docShell->GetSessionStorageForPrincipal(principal,
8324 EmptyString(),
8325 PR_FALSE,
8326 getter_AddRefs(storage));
8330 if (!pistorage->IsForkOf(storage)) {
8331 // This storage event is coming from a different doc shell,
8332 // i.e. it is a clone, ignore this event.
8333 return NS_OK;
8336 #ifdef PR_LOGGING
8337 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
8338 PR_LogPrint("nsGlobalWindow %p with sessionStorage %p passing event from %p", this, mSessionStorage.get(), pistorage.get());
8340 #endif
8342 break;
8344 case nsPIDOMStorage::LocalStorage:
8346 if (SameCOMIdentity(mLocalStorage, changingStorage)) {
8347 // Do not fire any events for the same storage object, it's not shared
8348 // among windows, see nsGlobalWindow::GetLocalStoarge()
8349 return NS_OK;
8352 // Allow event fire only for the same principal storages
8353 // XXX We have to use EqualsIgnoreDomain after bug 495337 lands
8354 nsIPrincipal *storagePrincipal = pistorage->Principal();
8355 PRBool equals;
8357 rv = storagePrincipal->Equals(principal, &equals);
8358 NS_ENSURE_SUCCESS(rv, rv);
8360 if (!equals)
8361 return NS_OK;
8363 break;
8365 default:
8366 return NS_OK;
8369 if (IsFrozen()) {
8370 // This window is frozen, rather than firing the events here,
8371 // store the domain in which the change happened and fire the
8372 // events if we're ever thawed.
8374 mPendingStorageEvents.AppendObject(event);
8375 return NS_OK;
8378 PRBool defaultActionEnabled;
8379 DispatchEvent((nsIDOMStorageEvent *)event, &defaultActionEnabled);
8381 return NS_OK;
8384 if (!nsCRT::strcmp(aTopic, "offline-cache-update-added")) {
8385 if (mApplicationCache)
8386 return NS_OK;
8388 // Instantiate the application object now. It observes update belonging to
8389 // this window's document and correctly updates the applicationCache object
8390 // state.
8391 nsCOMPtr<nsIDOMOfflineResourceList> applicationCache;
8392 GetApplicationCache(getter_AddRefs(applicationCache));
8393 nsCOMPtr<nsIObserver> observer = do_QueryInterface(applicationCache);
8394 if (observer)
8395 observer->Observe(aSubject, aTopic, aData);
8397 return NS_OK;
8400 NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");
8401 return NS_ERROR_FAILURE;
8404 static PLDHashOperator
8405 FirePendingStorageEvents(const nsAString& aKey, PRBool aData, void *userArg)
8407 nsGlobalWindow *win = static_cast<nsGlobalWindow *>(userArg);
8409 nsCOMPtr<nsIDOMStorage> storage;
8410 win->GetSessionStorage(getter_AddRefs(storage));
8412 if (storage) {
8413 win->Observe(storage, "dom-storage-changed",
8414 aKey.IsEmpty() ? nsnull : PromiseFlatString(aKey).get());
8417 return PL_DHASH_NEXT;
8420 nsresult
8421 nsGlobalWindow::FireDelayedDOMEvents()
8423 FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED);
8425 for (PRInt32 i = 0; i < mPendingStorageEvents.Count(); ++i) {
8426 Observe(mPendingStorageEvents[i], "dom-storage2-changed", nsnull);
8429 if (mPendingStorageEventsObsolete) {
8430 // Fire pending storage events.
8431 mPendingStorageEventsObsolete->EnumerateRead(FirePendingStorageEvents, this);
8433 delete mPendingStorageEventsObsolete;
8434 mPendingStorageEventsObsolete = nsnull;
8437 if (mApplicationCache) {
8438 static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents();
8441 if (mFireOfflineStatusChangeEventOnThaw) {
8442 mFireOfflineStatusChangeEventOnThaw = PR_FALSE;
8443 FireOfflineStatusEvent();
8446 nsCOMPtr<nsIDocShellTreeNode> node =
8447 do_QueryInterface(GetDocShell());
8448 if (node) {
8449 PRInt32 childCount = 0;
8450 node->GetChildCount(&childCount);
8452 for (PRInt32 i = 0; i < childCount; ++i) {
8453 nsCOMPtr<nsIDocShellTreeItem> childShell;
8454 node->GetChildAt(i, getter_AddRefs(childShell));
8455 NS_ASSERTION(childShell, "null child shell");
8457 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
8458 if (pWin) {
8459 nsGlobalWindow *win =
8460 static_cast<nsGlobalWindow*>
8461 (static_cast<nsPIDOMWindow*>(pWin));
8462 win->FireDelayedDOMEvents();
8467 return NS_OK;
8470 //*****************************************************************************
8471 // nsGlobalWindow: Window Control Functions
8472 //*****************************************************************************
8474 nsIDOMWindowInternal *
8475 nsGlobalWindow::GetParentInternal()
8477 FORWARD_TO_OUTER(GetParentInternal, (), nsnull);
8479 nsIDOMWindowInternal *parentInternal = nsnull;
8481 nsCOMPtr<nsIDOMWindow> parent;
8482 GetParent(getter_AddRefs(parent));
8484 if (parent && parent != static_cast<nsIDOMWindow *>(this)) {
8485 nsCOMPtr<nsIDOMWindowInternal> tmp(do_QueryInterface(parent));
8486 NS_ASSERTION(parent, "Huh, parent not an nsIDOMWindowInternal?");
8488 parentInternal = tmp;
8491 return parentInternal;
8494 // static
8495 void
8496 nsGlobalWindow::CloseBlockScriptTerminationFunc(nsISupports *aRef)
8498 nsGlobalWindow* pwin = static_cast<nsGlobalWindow*>
8499 (static_cast<nsPIDOMWindow*>(aRef));
8500 pwin->mBlockScriptedClosingFlag = PR_FALSE;
8503 nsresult
8504 nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
8505 const nsAString& aOptions, PRBool aDialog,
8506 PRBool aContentModal, PRBool aCalledNoScript,
8507 PRBool aDoJSFixups, nsIArray *argv,
8508 nsISupports *aExtraArgument,
8509 nsIPrincipal *aCalleePrincipal,
8510 JSContext *aJSCallerContext,
8511 nsIDOMWindow **aReturn)
8513 FORWARD_TO_OUTER(OpenInternal, (aUrl, aName, aOptions, aDialog,
8514 aContentModal, aCalledNoScript, aDoJSFixups,
8515 argv, aExtraArgument, aCalleePrincipal,
8516 aJSCallerContext, aReturn),
8517 NS_ERROR_NOT_INITIALIZED);
8519 #ifdef NS_DEBUG
8520 PRUint32 argc = 0;
8521 if (argv)
8522 argv->GetLength(&argc);
8523 #endif
8524 NS_PRECONDITION(!aExtraArgument || (!argv && argc == 0),
8525 "Can't pass in arguments both ways");
8526 NS_PRECONDITION(!aCalledNoScript || (!argv && argc == 0),
8527 "Can't pass JS args when called via the noscript methods");
8528 NS_PRECONDITION(!aJSCallerContext || !aCalledNoScript,
8529 "Shouldn't have caller context when called noscript");
8531 *aReturn = nsnull;
8533 nsCOMPtr<nsIWebBrowserChrome> chrome;
8534 GetWebBrowserChrome(getter_AddRefs(chrome));
8535 if (!chrome) {
8536 // No chrome means we don't want to go through with this open call
8537 // -- see nsIWindowWatcher.idl
8538 return NS_ERROR_NOT_AVAILABLE;
8541 NS_ASSERTION(mDocShell, "Must have docshell here");
8543 const PRBool checkForPopup =
8544 !aDialog && !WindowExists(aName, !aCalledNoScript);
8546 // Note: it's very important that this be an nsXPIDLCString, since we want
8547 // .get() on it to return nsnull until we write stuff to it. The window
8548 // watcher expects a null URL string if there is no URL to load.
8549 nsXPIDLCString url;
8550 nsresult rv = NS_OK;
8552 // It's important to do this security check before determining whether this
8553 // window opening should be blocked, to ensure that we don't FireAbuseEvents
8554 // for a window opening that wouldn't have succeeded in the first place.
8555 if (!aUrl.IsEmpty()) {
8556 AppendUTF16toUTF8(aUrl, url);
8558 /* Check whether the URI is allowed, but not for dialogs --
8559 see bug 56851. The security of this function depends on
8560 window.openDialog being inaccessible from web scripts */
8561 if (url.get() && !aDialog)
8562 rv = SecurityCheckURL(url.get());
8565 if (NS_FAILED(rv))
8566 return rv;
8568 PopupControlState abuseLevel = gPopupControlState;
8569 if (checkForPopup) {
8570 abuseLevel = RevisePopupAbuseLevel(abuseLevel);
8571 if (abuseLevel >= openAbused) {
8572 if (aJSCallerContext) {
8573 // If script in some other window is doing a window.open on us and
8574 // it's being blocked, then it's OK to close us afterwards, probably.
8575 // But if we're doing a window.open on ourselves and block the popup,
8576 // prevent this window from closing until after this script terminates
8577 // so that whatever popup blocker UI the app has will be visible.
8578 if (mContext == GetScriptContextFromJSContext(aJSCallerContext)) {
8579 mBlockScriptedClosingFlag = PR_TRUE;
8580 mContext->SetTerminationFunction(CloseBlockScriptTerminationFunc,
8581 static_cast<nsPIDOMWindow*>
8582 (this));
8586 FireAbuseEvents(PR_TRUE, PR_FALSE, aUrl, aName, aOptions);
8587 return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
8591 nsCOMPtr<nsIDOMWindow> domReturn;
8593 nsCOMPtr<nsIWindowWatcher> wwatch =
8594 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
8595 NS_ENSURE_TRUE(wwatch, rv);
8597 NS_ConvertUTF16toUTF8 options(aOptions);
8598 NS_ConvertUTF16toUTF8 name(aName);
8600 const char *options_ptr = aOptions.IsEmpty() ? nsnull : options.get();
8601 const char *name_ptr = aName.IsEmpty() ? nsnull : name.get();
8604 // Reset popup state while opening a window to prevent the
8605 // current state from being active the whole time a modal
8606 // dialog is open.
8607 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
8609 if (!aCalledNoScript) {
8610 nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
8611 NS_ASSERTION(pwwatch,
8612 "Unable to open windows from JS because window watcher "
8613 "is broken");
8614 NS_ENSURE_TRUE(pwwatch, NS_ERROR_UNEXPECTED);
8616 rv = pwwatch->OpenWindowJS(this, url.get(), name_ptr, options_ptr,
8617 aDialog, argv,
8618 getter_AddRefs(domReturn));
8619 } else {
8620 // Push a null JSContext here so that the window watcher won't screw us
8621 // up. We do NOT want this case looking at the JS context on the stack
8622 // when searching. Compare comments on
8623 // nsIDOMWindowInternal::OpenWindow and nsIWindowWatcher::OpenWindow.
8624 nsCOMPtr<nsIJSContextStack> stack;
8626 if (!aContentModal) {
8627 stack = do_GetService(sJSStackContractID);
8630 if (stack) {
8631 rv = stack->Push(nsnull);
8632 NS_ENSURE_SUCCESS(rv, rv);
8635 rv = wwatch->OpenWindow(this, url.get(), name_ptr, options_ptr,
8636 aExtraArgument, getter_AddRefs(domReturn));
8638 if (stack) {
8639 JSContext* cx;
8640 stack->Pop(&cx);
8641 NS_ASSERTION(!cx, "Unexpected JSContext popped!");
8646 NS_ENSURE_SUCCESS(rv, rv);
8648 // success!
8650 domReturn.swap(*aReturn);
8652 if (aDoJSFixups) {
8653 nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
8654 if (!chrome_win) {
8655 // A new non-chrome window was created from a call to
8656 // window.open() from JavaScript, make sure there's a document in
8657 // the new window. We do this by simply asking the new window for
8658 // its document, this will synchronously create an empty document
8659 // if there is no document in the window.
8660 // XXXbz should this just use EnsureInnerWindow()?
8661 #ifdef DEBUG_jst
8663 nsCOMPtr<nsPIDOMWindow> pidomwin(do_QueryInterface(*aReturn));
8665 nsIDOMDocument *temp = pidomwin->GetExtantDocument();
8667 NS_ASSERTION(temp, "No document in new window!!!");
8669 #endif
8671 nsCOMPtr<nsIDOMDocument> doc;
8672 (*aReturn)->GetDocument(getter_AddRefs(doc));
8676 if (checkForPopup) {
8677 if (abuseLevel >= openControlled) {
8678 nsGlobalWindow *opened = static_cast<nsGlobalWindow *>(*aReturn);
8679 if (!opened->IsPopupSpamWindow()) {
8680 opened->SetPopupSpamWindow(PR_TRUE);
8681 ++gOpenPopupSpamCount;
8684 if (abuseLevel >= openAbused)
8685 FireAbuseEvents(PR_FALSE, PR_TRUE, aUrl, aName, aOptions);
8688 return rv;
8691 // static
8692 void
8693 nsGlobalWindow::CloseWindow(nsISupports *aWindow)
8695 nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aWindow));
8697 nsGlobalWindow* globalWin =
8698 static_cast<nsGlobalWindow *>
8699 (static_cast<nsPIDOMWindow*>(win));
8701 // Need to post an event for closing, otherwise window and
8702 // presshell etc. may get destroyed while creating frames, bug 338897.
8703 nsCloseEvent::PostCloseEvent(globalWin);
8704 // else if OOM, better not to close. That might cause a crash.
8707 // static
8708 void
8709 nsGlobalWindow::ClearWindowScope(nsISupports *aWindow)
8711 nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aWindow));
8712 nsIScriptContext *scx = sgo->GetContext();
8713 if (scx) {
8714 scx->ClearScope(sgo->GetGlobalJSObject(), PR_TRUE);
8718 //*****************************************************************************
8719 // nsGlobalWindow: Timeout Functions
8720 //*****************************************************************************
8722 PRUint32 sNestingLevel;
8724 nsresult
8725 nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
8726 PRInt32 interval,
8727 PRBool aIsInterval, PRInt32 *aReturn)
8729 FORWARD_TO_INNER(SetTimeoutOrInterval, (aHandler, interval, aIsInterval, aReturn),
8730 NS_ERROR_NOT_INITIALIZED);
8732 // If we don't have a document (we could have been unloaded since
8733 // the call to setTimeout was made), do nothing.
8734 if (!mDocument) {
8735 return NS_OK;
8738 PRUint32 nestingLevel = sNestingLevel + 1;
8739 if (interval < DOMMinTimeoutValue()) {
8740 if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL) {
8741 // Don't allow timeouts less than DOMMinTimeoutValue() from
8742 // now...
8744 interval = DOMMinTimeoutValue();;
8746 else if (interval < 0) {
8747 // Clamp negative intervals to 0.
8749 interval = 0;
8753 NS_ASSERTION(interval >= 0, "DOMMinTimeoutValue() lies");
8754 PRUint32 realInterval = interval;
8756 // Make sure we don't proceed with a interval larger than our timer
8757 // code can handle.
8758 if (realInterval > PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE)) {
8759 realInterval = PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE);
8762 nsTimeout *timeout = new nsTimeout();
8763 if (!timeout)
8764 return NS_ERROR_OUT_OF_MEMORY;
8766 // Increment the timeout's reference count to represent this function's hold
8767 // on the timeout.
8768 timeout->AddRef();
8770 if (aIsInterval) {
8771 timeout->mInterval = realInterval;
8773 timeout->mScriptHandler = aHandler;
8775 // Get principal of currently executing code, save for execution of timeout.
8776 // If our principals subsume the subject principal then use the subject
8777 // principal. Otherwise, use our principal to avoid running script in
8778 // elevated principals.
8780 nsCOMPtr<nsIPrincipal> subjectPrincipal;
8781 nsresult rv;
8782 rv = nsContentUtils::GetSecurityManager()->
8783 GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
8784 if (NS_FAILED(rv)) {
8785 timeout->Release();
8787 return NS_ERROR_FAILURE;
8790 PRBool subsumes = PR_FALSE;
8791 nsCOMPtr<nsIPrincipal> ourPrincipal = GetPrincipal();
8793 // Note the direction of this test: We don't allow setTimeouts running with
8794 // chrome privileges on content windows, but we do allow setTimeouts running
8795 // with content privileges on chrome windows (where they can't do very much,
8796 // of course).
8797 rv = ourPrincipal->Subsumes(subjectPrincipal, &subsumes);
8798 if (NS_FAILED(rv)) {
8799 timeout->Release();
8801 return NS_ERROR_FAILURE;
8804 if (subsumes) {
8805 timeout->mPrincipal = subjectPrincipal;
8806 } else {
8807 timeout->mPrincipal = ourPrincipal;
8810 TimeDuration delta = TimeDuration::FromMilliseconds(realInterval);
8812 if (!IsFrozen() && !mTimeoutsSuspendDepth) {
8813 // If we're not currently frozen, then we set timeout->mWhen to be the
8814 // actual firing time of the timer (i.e., now + delta). We also actually
8815 // create a timer and fire it off.
8817 timeout->mWhen = TimeStamp::Now() + delta;
8819 timeout->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
8820 if (NS_FAILED(rv)) {
8821 timeout->Release();
8823 return rv;
8826 rv = timeout->mTimer->InitWithFuncCallback(TimerCallback, timeout,
8827 realInterval,
8828 nsITimer::TYPE_ONE_SHOT);
8829 if (NS_FAILED(rv)) {
8830 timeout->Release();
8832 return rv;
8835 // The timeout is now also held in the timer's closure.
8836 timeout->AddRef();
8837 } else {
8838 // If we are frozen, however, then we instead simply set
8839 // timeout->mTimeRemaining to be the "time remaining" in the timeout (i.e.,
8840 // the interval itself). We don't create a timer for it, since that will
8841 // happen when we are thawed and the timeout will then get a timer and run
8842 // to completion.
8844 timeout->mTimeRemaining = delta;
8847 timeout->mWindow = this;
8849 if (!aIsInterval) {
8850 timeout->mNestingLevel = nestingLevel;
8853 // No popups from timeouts by default
8854 timeout->mPopupState = openAbused;
8856 if (gRunningTimeoutDepth == 0 && gPopupControlState < openAbused) {
8857 // This timeout is *not* set from another timeout and it's set
8858 // while popups are enabled. Propagate the state to the timeout if
8859 // its delay (interval) is equal to or less than what
8860 // "dom.disable_open_click_delay" is set to (in ms).
8862 PRInt32 delay =
8863 nsContentUtils::GetIntPref("dom.disable_open_click_delay");
8865 if (interval <= delay) {
8866 timeout->mPopupState = gPopupControlState;
8870 InsertTimeoutIntoList(timeout);
8872 timeout->mPublicId = ++mTimeoutPublicIdCounter;
8873 *aReturn = timeout->mPublicId;
8875 // Our hold on the timeout is expiring. Note that this should not actually
8876 // free the timeout (since the list should have taken ownership as well).
8877 timeout->Release();
8879 return NS_OK;
8883 nsresult
8884 nsGlobalWindow::SetTimeoutOrInterval(PRBool aIsInterval, PRInt32 *aReturn)
8886 // This needs to forward to the inner window, but since the current
8887 // inner may not be the inner in the calling scope, we need to treat
8888 // this specially here as we don't want timeouts registered in a
8889 // dying inner window to get registered and run on the current inner
8890 // window. To get this right, we need to forward this call to the
8891 // inner window that's calling window.setTimeout().
8893 if (IsOuterWindow()) {
8894 nsGlobalWindow* callerInner = CallerInnerWindow();
8895 NS_ENSURE_TRUE(callerInner, NS_ERROR_NOT_AVAILABLE);
8897 // If the caller and the callee share the same outer window,
8898 // forward to the callee inner. Else, we forward to the current
8899 // inner (e.g. someone is calling setTimeout() on a reference to
8900 // some other window).
8902 if (callerInner->GetOuterWindow() == this &&
8903 callerInner->IsInnerWindow()) {
8904 return callerInner->SetTimeoutOrInterval(aIsInterval, aReturn);
8907 FORWARD_TO_INNER(SetTimeoutOrInterval, (aIsInterval, aReturn),
8908 NS_ERROR_NOT_INITIALIZED);
8911 PRInt32 interval = 0;
8912 PRBool isInterval = aIsInterval;
8913 nsCOMPtr<nsIScriptTimeoutHandler> handler;
8914 nsresult rv = NS_CreateJSTimeoutHandler(this,
8915 &isInterval,
8916 &interval,
8917 getter_AddRefs(handler));
8918 if (NS_FAILED(rv))
8919 return (rv == NS_ERROR_DOM_TYPE_ERR) ? NS_OK : rv;
8921 return SetTimeoutOrInterval(handler, interval, isInterval, aReturn);
8924 // static
8925 void
8926 nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
8928 // If a modal dialog is open for this window, return early. Pending
8929 // timeouts will run when the modal dialog is dismissed.
8930 if (IsInModalState() || mTimeoutsSuspendDepth) {
8931 return;
8934 NS_TIME_FUNCTION;
8936 NS_ASSERTION(IsInnerWindow(), "Timeout running on outer window!");
8937 NS_ASSERTION(!IsFrozen(), "Timeout running on a window in the bfcache!");
8939 nsTimeout *nextTimeout, *timeout;
8940 nsTimeout *last_expired_timeout, *last_insertion_point;
8941 nsTimeout dummy_timeout;
8942 PRUint32 firingDepth = mTimeoutFiringDepth + 1;
8944 // Make sure that the window and the script context don't go away as
8945 // a result of running timeouts
8946 nsCOMPtr<nsIScriptGlobalObject> windowKungFuDeathGrip(this);
8948 // A native timer has gone off. See which of our timeouts need
8949 // servicing
8950 TimeStamp now = TimeStamp::Now();
8951 TimeStamp deadline;
8953 if (aTimeout && aTimeout->mWhen > now) {
8954 // The OS timer fired early (yikes!), and possibly out of order
8955 // too. Set |deadline| to be the time when the OS timer *should*
8956 // have fired so that any timers that *should* have fired before
8957 // aTimeout *will* be fired now. This happens most of the time on
8958 // Win2k.
8960 deadline = aTimeout->mWhen;
8961 } else {
8962 deadline = now;
8965 // The timeout list is kept in deadline order. Discover the latest
8966 // timeout whose deadline has expired. On some platforms, native
8967 // timeout events fire "early", so we need to test the timer as well
8968 // as the deadline.
8969 last_expired_timeout = nsnull;
8970 for (timeout = FirstTimeout(); IsTimeout(timeout); timeout = timeout->Next()) {
8971 if (((timeout == aTimeout) || (timeout->mWhen <= deadline)) &&
8972 (timeout->mFiringDepth == 0)) {
8973 // Mark any timeouts that are on the list to be fired with the
8974 // firing depth so that we can reentrantly run timeouts
8975 timeout->mFiringDepth = firingDepth;
8976 last_expired_timeout = timeout;
8980 // Maybe the timeout that the event was fired for has been deleted
8981 // and there are no others timeouts with deadlines that make them
8982 // eligible for execution yet. Go away.
8983 if (!last_expired_timeout) {
8984 return;
8987 // Insert a dummy timeout into the list of timeouts between the
8988 // portion of the list that we are about to process now and those
8989 // timeouts that will be processed in a future call to
8990 // win_run_timeout(). This dummy timeout serves as the head of the
8991 // list for any timeouts inserted as a result of running a timeout.
8992 dummy_timeout.mFiringDepth = firingDepth;
8993 dummy_timeout.mWhen = now;
8994 PR_INSERT_AFTER(&dummy_timeout, last_expired_timeout);
8996 // Don't let ClearWindowTimeouts throw away our stack-allocated
8997 // dummy timeout.
8998 dummy_timeout.AddRef();
8999 dummy_timeout.AddRef();
9001 last_insertion_point = mTimeoutInsertionPoint;
9002 mTimeoutInsertionPoint = &dummy_timeout;
9004 for (timeout = FirstTimeout();
9005 timeout != &dummy_timeout && !IsFrozen();
9006 timeout = nextTimeout) {
9007 nextTimeout = timeout->Next();
9009 if (timeout->mFiringDepth != firingDepth) {
9010 // We skip the timeout since it's on the list to run at another
9011 // depth.
9013 continue;
9016 if (mTimeoutsSuspendDepth) {
9017 // Some timer did suspend us. Make sure the
9018 // rest of the timers get executed later.
9019 timeout->mFiringDepth = 0;
9020 continue;
9023 // The timeout is on the list to run at this depth, go ahead and
9024 // process it.
9026 // Get the script context (a strong ref to prevent it going away)
9027 // for this timeout and ensure the script language is enabled.
9028 nsCOMPtr<nsIScriptContext> scx = GetScriptContextInternal(
9029 timeout->mScriptHandler->GetScriptTypeID());
9031 if (!scx) {
9032 // No context means this window was closed or never properly
9033 // initialized for this language.
9034 continue;
9037 // The "scripts disabled" concept is still a little vague wrt
9038 // multiple languages. Prepare for the day when languages can be
9039 // disabled independently of the other languages...
9040 if (!scx->GetScriptsEnabled()) {
9041 // Scripts were enabled once in this window (unless aTimeout ==
9042 // nsnull) but now scripts are disabled (we might be in
9043 // print-preview, for instance), this means we shouldn't run any
9044 // timeouts at this point.
9046 // If scripts are enabled for this language in this window again
9047 // we'll fire the timeouts that are due at that point.
9048 continue;
9051 // This timeout is good to run
9052 nsTimeout *last_running_timeout = mRunningTimeout;
9053 mRunningTimeout = timeout;
9054 timeout->mRunning = PR_TRUE;
9056 // Push this timeout's popup control state, which should only be
9057 // eabled the first time a timeout fires that was created while
9058 // popups were enabled and with a delay less than
9059 // "dom.disable_open_click_delay".
9060 nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
9062 // Clear the timeout's popup state, if any, to prevent interval
9063 // timeouts from repeatedly opening poups.
9064 timeout->mPopupState = openAbused;
9066 // Hold on to the timeout in case mExpr or mFunObj releases its
9067 // doc.
9068 timeout->AddRef();
9070 ++gRunningTimeoutDepth;
9071 ++mTimeoutFiringDepth;
9073 PRBool trackNestingLevel = !timeout->mInterval;
9074 PRUint32 nestingLevel;
9075 if (trackNestingLevel) {
9076 nestingLevel = sNestingLevel;
9077 sNestingLevel = timeout->mNestingLevel;
9080 nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
9081 void *scriptObject = handler->GetScriptObject();
9082 if (!scriptObject) {
9083 // Evaluate the timeout expression.
9084 const PRUnichar *script = handler->GetHandlerText();
9085 NS_ASSERTION(script, "timeout has no script nor handler text!");
9087 const char *filename = nsnull;
9088 PRUint32 lineNo = 0;
9089 handler->GetLocation(&filename, &lineNo);
9091 NS_TIME_FUNCTION_MARK("(file: %s, line: %d)", filename, lineNo);
9093 PRBool is_undefined;
9094 scx->EvaluateString(nsDependentString(script),
9095 GetScriptGlobal(handler->GetScriptTypeID()),
9096 timeout->mPrincipal, filename, lineNo,
9097 handler->GetScriptVersion(), nsnull,
9098 &is_undefined);
9099 } else {
9100 // Let the script handler know about the "secret" final argument that
9101 // indicates timeout lateness in milliseconds
9102 TimeDuration lateness = now - timeout->mWhen;
9104 handler->SetLateness(lateness.ToMilliseconds());
9106 nsCOMPtr<nsIVariant> dummy;
9107 nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
9108 scx->CallEventHandler(me,
9109 GetScriptGlobal(handler->GetScriptTypeID()),
9110 scriptObject, handler->GetArgv(),
9111 // XXXmarkh - consider allowing CallEventHandler to
9112 // accept nsnull?
9113 getter_AddRefs(dummy));
9116 handler = nsnull; // drop reference before dropping timeout refs.
9118 if (trackNestingLevel) {
9119 sNestingLevel = nestingLevel;
9122 --mTimeoutFiringDepth;
9123 --gRunningTimeoutDepth;
9125 mRunningTimeout = last_running_timeout;
9126 timeout->mRunning = PR_FALSE;
9128 // We ignore any failures from calling EvaluateString() or
9129 // CallEventHandler() on the context here since we're in a loop
9130 // where we're likely to be running timeouts whose OS timers
9131 // didn't fire in time and we don't want to not fire those timers
9132 // now just because execution of one timer failed. We can't
9133 // propagate the error to anyone who cares about it from this
9134 // point anyway, and the script context should have already reported
9135 // the script error in the usual way - so we just drop it.
9137 // If all timeouts were cleared and |timeout != aTimeout| then
9138 // |timeout| may be the last reference to the timeout so check if
9139 // it was cleared before releasing it.
9140 PRBool timeout_was_cleared = timeout->mCleared;
9142 timeout->Release();
9144 if (timeout_was_cleared) {
9145 // The running timeout's window was cleared, this means that
9146 // ClearAllTimeouts() was called from a *nested* call, possibly
9147 // through a timeout that fired while a modal (to this window)
9148 // dialog was open or through other non-obvious paths.
9150 mTimeoutInsertionPoint = last_insertion_point;
9152 return;
9155 PRBool isInterval = PR_FALSE;
9157 // If we have a regular interval timer, we re-schedule the
9158 // timeout, accounting for clock drift.
9159 if (timeout->mInterval) {
9160 // Compute time to next timeout for interval timer.
9161 // Make sure nextInterval is at least DOMMinTimeoutValue().
9162 TimeDuration nextInterval =
9163 TimeDuration::FromMilliseconds(NS_MAX(timeout->mInterval,
9164 PRUint32(DOMMinTimeoutValue())));
9166 // If we're running pending timeouts because they've been temporarily
9167 // disabled (!aTimeout), set the next interval to be relative to "now",
9168 // and not to when the timeout that was pending should have fired. Also
9169 // check if the next interval timeout is overdue. If so, then restart
9170 // the interval from now.
9171 TimeStamp firingTime;
9172 if (!aTimeout || timeout->mWhen + nextInterval <= now)
9173 firingTime = now + nextInterval;
9174 else
9175 firingTime = timeout->mWhen + nextInterval;
9177 TimeDuration delay = firingTime - TimeStamp::Now();
9179 // And make sure delay is nonnegative; that might happen if the timer
9180 // thread is firing our timers somewhat early.
9181 if (delay < TimeDuration(0)) {
9182 delay = TimeDuration(0);
9185 if (timeout->mTimer) {
9186 timeout->mWhen = firingTime;
9188 // Reschedule the OS timer. Don't bother returning any error
9189 // codes if this fails since the callers of this method
9190 // doesn't care about them nobody who cares about them
9191 // anyways.
9193 // Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
9194 // PRTime to make the division do the right thing on 64-bit
9195 // platforms whether delay is positive or negative (which we
9196 // know is always positive here, but cast anyways for
9197 // consistency).
9198 nsresult rv = timeout->mTimer->
9199 InitWithFuncCallback(TimerCallback, timeout,
9200 delay.ToMilliseconds(),
9201 nsITimer::TYPE_ONE_SHOT);
9203 if (NS_FAILED(rv)) {
9204 NS_ERROR("Error initializing timer for DOM timeout!");
9206 // We failed to initialize the new OS timer, this timer does
9207 // us no good here so we just cancel it (just in case) and
9208 // null out the pointer to the OS timer, this will release the
9209 // OS timer. As we continue executing the code below we'll end
9210 // up deleting the timeout since it's not an interval timeout
9211 // any more (since timeout->mTimer == nsnull).
9212 timeout->mTimer->Cancel();
9213 timeout->mTimer = nsnull;
9215 // Now that the OS timer no longer has a reference to the
9216 // timeout we need to drop that reference.
9217 timeout->Release();
9219 } else {
9220 NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth,
9221 "How'd our timer end up null if we're not frozen or "
9222 "suspended?");
9224 timeout->mTimeRemaining = delay;
9225 isInterval = PR_TRUE;
9229 if (timeout->mTimer) {
9230 if (timeout->mInterval) {
9231 isInterval = PR_TRUE;
9232 } else {
9233 // The timeout still has an OS timer, and it's not an
9234 // interval, that means that the OS timer could still fire (if
9235 // it didn't already, i.e. aTimeout == timeout), cancel the OS
9236 // timer and release its reference to the timeout.
9237 timeout->mTimer->Cancel();
9238 timeout->mTimer = nsnull;
9240 timeout->Release();
9244 // Running a timeout can cause another timeout to be deleted, so
9245 // we need to reset the pointer to the following timeout.
9246 nextTimeout = timeout->Next();
9248 PR_REMOVE_LINK(timeout);
9250 if (isInterval) {
9251 // Reschedule an interval timeout. Insert interval timeout
9252 // onto list sorted in deadline order.
9253 // AddRefs timeout.
9254 InsertTimeoutIntoList(timeout);
9257 // Release the timeout struct since it's possibly out of the list
9258 timeout->Release();
9261 // Take the dummy timeout off the head of the list
9262 PR_REMOVE_LINK(&dummy_timeout);
9264 mTimeoutInsertionPoint = last_insertion_point;
9267 nsrefcnt
9268 nsTimeout::Release()
9270 if (--mRefCnt > 0)
9271 return mRefCnt;
9273 // language specific cleanup done as mScriptHandler destructs...
9275 // Kill the timer if it is still alive.
9276 if (mTimer) {
9277 mTimer->Cancel();
9278 mTimer = nsnull;
9281 delete this;
9282 return 0;
9285 nsrefcnt
9286 nsTimeout::AddRef()
9288 return ++mRefCnt;
9292 nsresult
9293 nsGlobalWindow::ClearTimeoutOrInterval(PRInt32 aTimerID)
9295 FORWARD_TO_INNER(ClearTimeoutOrInterval, (aTimerID), NS_ERROR_NOT_INITIALIZED);
9297 PRUint32 public_id = (PRUint32)aTimerID;
9298 nsTimeout *timeout;
9300 for (timeout = FirstTimeout();
9301 IsTimeout(timeout);
9302 timeout = timeout->Next()) {
9303 if (timeout->mPublicId == public_id) {
9304 if (timeout->mRunning) {
9305 /* We're running from inside the timeout. Mark this
9306 timeout for deferred deletion by the code in
9307 RunTimeout() */
9308 timeout->mInterval = 0;
9310 else {
9311 /* Delete the timeout from the pending timeout list */
9312 PR_REMOVE_LINK(timeout);
9314 if (timeout->mTimer) {
9315 timeout->mTimer->Cancel();
9316 timeout->mTimer = nsnull;
9317 timeout->Release();
9319 timeout->Release();
9321 break;
9325 return NS_OK;
9328 // A JavaScript specific version.
9329 nsresult
9330 nsGlobalWindow::ClearTimeoutOrInterval()
9332 FORWARD_TO_INNER(ClearTimeoutOrInterval, (), NS_ERROR_NOT_INITIALIZED);
9334 nsresult rv = NS_OK;
9335 nsAXPCNativeCallContext *ncc = nsnull;
9337 rv = nsContentUtils::XPConnect()->
9338 GetCurrentNativeCallContext(&ncc);
9339 NS_ENSURE_SUCCESS(rv, rv);
9341 if (!ncc)
9342 return NS_ERROR_NOT_AVAILABLE;
9344 JSContext *cx = nsnull;
9346 rv = ncc->GetJSContext(&cx);
9347 NS_ENSURE_SUCCESS(rv, rv);
9349 PRUint32 argc;
9351 ncc->GetArgc(&argc);
9353 if (argc < 1) {
9354 // No arguments, return early.
9356 return NS_OK;
9359 jsval *argv = nsnull;
9361 ncc->GetArgvPtr(&argv);
9363 int32 timer_id;
9365 JSAutoRequest ar(cx);
9367 // XXXjst: Can we deal with this w/o using GetCurrentNativeCallContext()
9368 if (argv[0] == JSVAL_VOID || !::JS_ValueToInt32(cx, argv[0], &timer_id) ||
9369 timer_id <= 0) {
9370 // Undefined or non-positive number passed as argument, return
9371 // early. Make sure that JS_ValueToInt32 didn't set an exception.
9373 ::JS_ClearPendingException(cx);
9374 return NS_OK;
9377 return ClearTimeoutOrInterval(timer_id);
9380 void
9381 nsGlobalWindow::ClearAllTimeouts()
9383 nsTimeout *timeout, *nextTimeout;
9385 for (timeout = FirstTimeout(); IsTimeout(timeout); timeout = nextTimeout) {
9386 /* If RunTimeout() is higher up on the stack for this
9387 window, e.g. as a result of document.write from a timeout,
9388 then we need to reset the list insertion point for
9389 newly-created timeouts in case the user adds a timeout,
9390 before we pop the stack back to RunTimeout. */
9391 if (mRunningTimeout == timeout)
9392 mTimeoutInsertionPoint = nsnull;
9394 nextTimeout = timeout->Next();
9396 if (timeout->mTimer) {
9397 timeout->mTimer->Cancel();
9398 timeout->mTimer = nsnull;
9400 // Drop the count since the timer isn't going to hold on
9401 // anymore.
9402 timeout->Release();
9405 // Set timeout->mCleared to true to indicate that the timeout was
9406 // cleared and taken out of the list of timeouts
9407 timeout->mCleared = PR_TRUE;
9409 // Drop the count since we're removing it from the list.
9410 timeout->Release();
9413 // Clear out our list
9414 PR_INIT_CLIST(&mTimeouts);
9417 void
9418 nsGlobalWindow::InsertTimeoutIntoList(nsTimeout *aTimeout)
9420 NS_ASSERTION(IsInnerWindow(),
9421 "InsertTimeoutIntoList() called on outer window!");
9423 // Start at mLastTimeout and go backwards. Don't go further than
9424 // mTimeoutInsertionPoint, though. This optimizes for the common case of
9425 // insertion at the end.
9426 nsTimeout* prevSibling;
9427 for (prevSibling = LastTimeout();
9428 IsTimeout(prevSibling) && prevSibling != mTimeoutInsertionPoint &&
9429 // This condition needs to match the one in SetTimeoutOrInterval that
9430 // determines whether to set mWhen or mTimeRemaining.
9431 ((IsFrozen() || mTimeoutsSuspendDepth) ?
9432 prevSibling->mTimeRemaining > aTimeout->mTimeRemaining :
9433 prevSibling->mWhen > aTimeout->mWhen);
9434 prevSibling = prevSibling->Prev()) {
9435 /* Do nothing; just searching */
9438 // Now link in aTimeout after prevSibling.
9439 PR_INSERT_AFTER(aTimeout, prevSibling);
9441 aTimeout->mFiringDepth = 0;
9443 // Increment the timeout's reference count since it's now held on to
9444 // by the list
9445 aTimeout->AddRef();
9448 // static
9449 void
9450 nsGlobalWindow::TimerCallback(nsITimer *aTimer, void *aClosure)
9452 nsTimeout *timeout = (nsTimeout *)aClosure;
9454 // Hold on to the timeout to ensure it doesn't go away while it's
9455 // being handled (aka kungFuDeathGrip).
9456 timeout->AddRef();
9458 timeout->mWindow->RunTimeout(timeout);
9460 // Drop our reference to the timeout now that we're done with it.
9461 timeout->Release();
9464 //*****************************************************************************
9465 // nsGlobalWindow: Helper Functions
9466 //*****************************************************************************
9468 nsresult
9469 nsGlobalWindow::GetTreeOwner(nsIDocShellTreeOwner **aTreeOwner)
9471 FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
9473 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
9475 // If there's no docShellAsItem, this window must have been closed,
9476 // in that case there is no tree owner.
9478 if (!docShellAsItem) {
9479 *aTreeOwner = nsnull;
9481 return NS_OK;
9484 return docShellAsItem->GetTreeOwner(aTreeOwner);
9487 nsresult
9488 nsGlobalWindow::GetTreeOwner(nsIBaseWindow **aTreeOwner)
9490 FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
9492 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
9493 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
9495 // If there's no docShellAsItem, this window must have been closed,
9496 // in that case there is no tree owner.
9498 if (docShellAsItem) {
9499 docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
9502 if (!treeOwner) {
9503 *aTreeOwner = nsnull;
9504 return NS_OK;
9507 return CallQueryInterface(treeOwner, aTreeOwner);
9510 nsresult
9511 nsGlobalWindow::GetWebBrowserChrome(nsIWebBrowserChrome **aBrowserChrome)
9513 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
9514 GetTreeOwner(getter_AddRefs(treeOwner));
9516 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner));
9517 NS_IF_ADDREF(*aBrowserChrome = browserChrome);
9519 return NS_OK;
9522 nsIScrollableFrame *
9523 nsGlobalWindow::GetScrollFrame()
9525 FORWARD_TO_OUTER(GetScrollFrame, (), nsnull);
9527 if (!mDocShell) {
9528 return nsnull;
9531 nsCOMPtr<nsIPresShell> presShell;
9532 mDocShell->GetPresShell(getter_AddRefs(presShell));
9533 if (presShell) {
9534 return presShell->GetRootScrollFrameAsScrollable();
9536 return nsnull;
9539 nsresult
9540 nsGlobalWindow::BuildURIfromBase(const char *aURL, nsIURI **aBuiltURI,
9541 PRBool *aFreeSecurityPass,
9542 JSContext **aCXused)
9544 nsIScriptContext *scx = GetContextInternal();
9545 JSContext *cx = nsnull;
9547 *aBuiltURI = nsnull;
9548 *aFreeSecurityPass = PR_FALSE;
9549 if (aCXused)
9550 *aCXused = nsnull;
9552 // get JSContext
9553 NS_ASSERTION(scx, "opening window missing its context");
9554 NS_ASSERTION(mDocument, "opening window missing its document");
9555 if (!scx || !mDocument)
9556 return NS_ERROR_FAILURE;
9558 nsCOMPtr<nsIDOMChromeWindow> chrome_win =
9559 do_QueryInterface(static_cast<nsIDOMWindow *>(this));
9561 if (nsContentUtils::IsCallerChrome() && !chrome_win) {
9562 // If open() is called from chrome on a non-chrome window, we'll
9563 // use the context from the window on which open() is being called
9564 // to prevent giving chrome priveleges to new windows opened in
9565 // such a way. This also makes us get the appropriate base URI for
9566 // the below URI resolution code.
9568 cx = (JSContext *)scx->GetNativeContext();
9569 } else {
9570 // get the JSContext from the call stack
9571 nsCOMPtr<nsIThreadJSContextStack> stack(do_GetService(sJSStackContractID));
9572 if (stack)
9573 stack->Peek(&cx);
9576 /* resolve the URI, which could be relative to the calling window
9577 (note the algorithm to get the base URI should match the one
9578 used to actually kick off the load in nsWindowWatcher.cpp). */
9579 nsCAutoString charset(NS_LITERAL_CSTRING("UTF-8")); // default to utf-8
9580 nsIURI* baseURI = nsnull;
9581 nsCOMPtr<nsIURI> uriToLoad;
9582 nsCOMPtr<nsIDOMWindow> sourceWindow;
9584 if (cx) {
9585 nsIScriptContext *scriptcx = nsJSUtils::GetDynamicScriptContext(cx);
9586 if (scriptcx)
9587 sourceWindow = do_QueryInterface(scriptcx->GetGlobalObject());
9590 if (!sourceWindow) {
9591 sourceWindow = do_QueryInterface(NS_ISUPPORTS_CAST(nsIDOMWindow *, this));
9592 *aFreeSecurityPass = PR_TRUE;
9595 if (sourceWindow) {
9596 nsCOMPtr<nsIDOMDocument> domDoc;
9597 sourceWindow->GetDocument(getter_AddRefs(domDoc));
9598 nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
9599 if (doc) {
9600 baseURI = doc->GetDocBaseURI();
9601 charset = doc->GetDocumentCharacterSet();
9605 if (aCXused)
9606 *aCXused = cx;
9607 return NS_NewURI(aBuiltURI, nsDependentCString(aURL), charset.get(), baseURI);
9610 nsresult
9611 nsGlobalWindow::SecurityCheckURL(const char *aURL)
9613 JSContext *cx;
9614 PRBool freePass;
9615 nsCOMPtr<nsIURI> uri;
9617 if (NS_FAILED(BuildURIfromBase(aURL, getter_AddRefs(uri), &freePass, &cx)))
9618 return NS_ERROR_FAILURE;
9620 if (!freePass && NS_FAILED(nsContentUtils::GetSecurityManager()->
9621 CheckLoadURIFromScript(cx, uri)))
9622 return NS_ERROR_FAILURE;
9624 return NS_OK;
9627 void
9628 nsGlobalWindow::FlushPendingNotifications(mozFlushType aType)
9630 if (mDoc) {
9631 mDoc->FlushPendingNotifications(aType);
9635 void
9636 nsGlobalWindow::EnsureSizeUpToDate()
9638 // If we're a subframe, make sure our size is up to date. It's OK that this
9639 // crosses the content/chrome boundary, since chrome can have pending reflows
9640 // too.
9641 nsGlobalWindow *parent =
9642 static_cast<nsGlobalWindow *>(GetPrivateParent());
9643 if (parent) {
9644 parent->FlushPendingNotifications(Flush_Layout);
9648 nsresult
9649 nsGlobalWindow::SaveWindowState(nsISupports **aState)
9651 NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
9653 *aState = nsnull;
9655 if (!mContext || !mJSObject) {
9656 // The window may be getting torn down; don't bother saving state.
9657 return NS_OK;
9660 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
9661 NS_ASSERTION(inner, "No inner window to save");
9663 // Don't do anything else to this inner window! After this point, all
9664 // calls to SetTimeoutOrInterval will create entries in the timeout
9665 // list that will only run after this window has come out of the bfcache.
9666 // Also, while we're frozen, we won't dispatch online/offline events
9667 // to the page.
9668 inner->Freeze();
9670 // Remember the outer window's prototype.
9671 JSContext *cx = (JSContext *)mContext->GetNativeContext();
9672 JSAutoRequest req(cx);
9674 nsIXPConnect *xpc = nsContentUtils::XPConnect();
9676 nsCOMPtr<nsIClassInfo> ci =
9677 do_QueryInterface((nsIScriptGlobalObject *)this);
9678 nsCOMPtr<nsIXPConnectJSObjectHolder> proto;
9679 nsresult rv = xpc->GetWrappedNativePrototype(cx, mJSObject, ci,
9680 getter_AddRefs(proto));
9681 NS_ENSURE_SUCCESS(rv, rv);
9683 JSObject *realProto = JS_GetPrototype(cx, mJSObject);
9684 nsCOMPtr<nsIXPConnectJSObjectHolder> realProtoHolder;
9685 if (realProto) {
9686 rv = xpc->HoldObject(cx, realProto, getter_AddRefs(realProtoHolder));
9687 NS_ENSURE_SUCCESS(rv, rv);
9690 nsCOMPtr<nsISupports> state = new WindowStateHolder(inner,
9691 mInnerWindowHolder,
9692 mNavigator,
9693 proto,
9694 realProtoHolder);
9695 NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY);
9697 JSObject *wnProto;
9698 proto->GetJSObject(&wnProto);
9699 if (!JS_SetPrototype(cx, mJSObject, wnProto)) {
9700 return NS_ERROR_FAILURE;
9703 #ifdef DEBUG_PAGE_CACHE
9704 printf("saving window state, state = %p\n", (void*)state);
9705 #endif
9707 state.swap(*aState);
9708 return NS_OK;
9711 nsresult
9712 nsGlobalWindow::RestoreWindowState(nsISupports *aState)
9714 NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window");
9716 if (!mContext || !mJSObject) {
9717 // The window may be getting torn down; don't bother restoring state.
9718 return NS_OK;
9721 nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
9722 NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE);
9724 #ifdef DEBUG_PAGE_CACHE
9725 printf("restoring window state, state = %p\n", (void*)holder);
9726 #endif
9728 // And we're ready to go!
9729 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
9731 // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
9732 // it easy to tell which link was last clicked when going back a page.
9733 nsIContent* focusedNode = inner->GetFocusedNode();
9734 if (IsLink(focusedNode)) {
9735 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
9736 if (fm) {
9737 nsCOMPtr<nsIDOMElement> focusedElement(do_QueryInterface(focusedNode));
9738 fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
9739 nsIFocusManager::FLAG_SHOWRING);
9743 inner->Thaw();
9745 holder->DidRestoreWindow();
9747 return NS_OK;
9750 void
9751 nsGlobalWindow::SuspendTimeouts(PRUint32 aIncrease,
9752 PRBool aFreezeChildren)
9754 FORWARD_TO_INNER_VOID(SuspendTimeouts, (aIncrease, aFreezeChildren));
9756 PRBool suspended = (mTimeoutsSuspendDepth != 0);
9757 mTimeoutsSuspendDepth += aIncrease;
9759 if (!suspended) {
9760 DisableAccelerationUpdates();
9762 nsDOMThreadService* dts = nsDOMThreadService::get();
9763 if (dts) {
9764 dts->SuspendWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
9767 TimeStamp now = TimeStamp::Now();
9768 for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
9769 // Set mTimeRemaining to be the time remaining for this timer.
9770 if (t->mWhen > now)
9771 t->mTimeRemaining = t->mWhen - now;
9772 else
9773 t->mTimeRemaining = TimeDuration(0);
9775 // Drop the XPCOM timer; we'll reschedule when restoring the state.
9776 if (t->mTimer) {
9777 t->mTimer->Cancel();
9778 t->mTimer = nsnull;
9780 // Drop the reference that the timer's closure had on this timeout, we'll
9781 // add it back in ResumeTimeouts. Note that it shouldn't matter that we're
9782 // passing null for the context, since this shouldn't actually release this
9783 // timeout.
9784 t->Release();
9789 // Suspend our children as well.
9790 nsCOMPtr<nsIDocShellTreeNode> node(do_QueryInterface(GetDocShell()));
9791 if (node) {
9792 PRInt32 childCount = 0;
9793 node->GetChildCount(&childCount);
9795 for (PRInt32 i = 0; i < childCount; ++i) {
9796 nsCOMPtr<nsIDocShellTreeItem> childShell;
9797 node->GetChildAt(i, getter_AddRefs(childShell));
9798 NS_ASSERTION(childShell, "null child shell");
9800 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
9801 if (pWin) {
9802 nsGlobalWindow *win =
9803 static_cast<nsGlobalWindow*>
9804 (static_cast<nsPIDOMWindow*>(pWin));
9805 NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
9806 nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
9808 // This is a bit hackish. Only freeze/suspend windows which are truly our
9809 // subwindows.
9810 nsCOMPtr<nsIContent> frame = do_QueryInterface(pWin->GetFrameElementInternal());
9811 if (!mDoc || !frame || mDoc != frame->GetOwnerDoc() || !inner) {
9812 continue;
9815 win->SuspendTimeouts(aIncrease, aFreezeChildren);
9817 if (inner && aFreezeChildren) {
9818 inner->Freeze();
9825 nsresult
9826 nsGlobalWindow::ResumeTimeouts(PRBool aThawChildren)
9828 FORWARD_TO_INNER(ResumeTimeouts, (), NS_ERROR_NOT_INITIALIZED);
9830 NS_ASSERTION(mTimeoutsSuspendDepth, "Mismatched calls to ResumeTimeouts!");
9831 --mTimeoutsSuspendDepth;
9832 PRBool shouldResume = (mTimeoutsSuspendDepth == 0);
9833 nsresult rv;
9835 if (shouldResume) {
9836 EnableAccelerationUpdates();
9838 nsDOMThreadService* dts = nsDOMThreadService::get();
9839 if (dts) {
9840 dts->ResumeWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
9843 // Restore all of the timeouts, using the stored time remaining
9844 // (stored in timeout->mTimeRemaining).
9846 TimeStamp now = TimeStamp::Now();
9848 #ifdef DEBUG
9849 PRBool _seenDummyTimeout = PR_FALSE;
9850 #endif
9852 for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
9853 // There's a chance we're being called with RunTimeout on the stack in which
9854 // case we have a dummy timeout in the list that *must not* be resumed. It
9855 // can be identified by a null mWindow.
9856 if (!t->mWindow) {
9857 #ifdef DEBUG
9858 NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
9859 _seenDummyTimeout = PR_TRUE;
9860 #endif
9861 continue;
9864 // XXXbz the combination of the way |delay| and |t->mWhen| are set here
9865 // makes no sense. Are we trying to impose that min timeout value or
9866 // not???
9867 PRUint32 delay =
9868 NS_MAX(PRInt32(t->mTimeRemaining.ToMilliseconds()),
9869 DOMMinTimeoutValue());
9871 // Set mWhen back to the time when the timer is supposed to
9872 // fire.
9873 t->mWhen = now + t->mTimeRemaining;
9875 t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
9876 NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY);
9878 rv = t->mTimer->InitWithFuncCallback(TimerCallback, t, delay,
9879 nsITimer::TYPE_ONE_SHOT);
9880 if (NS_FAILED(rv)) {
9881 t->mTimer = nsnull;
9882 return rv;
9885 // Add a reference for the new timer's closure.
9886 t->AddRef();
9890 // Resume our children as well.
9891 nsCOMPtr<nsIDocShellTreeNode> node =
9892 do_QueryInterface(GetDocShell());
9893 if (node) {
9894 PRInt32 childCount = 0;
9895 node->GetChildCount(&childCount);
9897 for (PRInt32 i = 0; i < childCount; ++i) {
9898 nsCOMPtr<nsIDocShellTreeItem> childShell;
9899 node->GetChildAt(i, getter_AddRefs(childShell));
9900 NS_ASSERTION(childShell, "null child shell");
9902 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
9903 if (pWin) {
9904 nsGlobalWindow *win =
9905 static_cast<nsGlobalWindow*>
9906 (static_cast<nsPIDOMWindow*>(pWin));
9908 NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
9909 nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
9911 // This is a bit hackish. Only thaw/resume windows which are truly our
9912 // subwindows.
9913 nsCOMPtr<nsIContent> frame = do_QueryInterface(pWin->GetFrameElementInternal());
9914 if (!mDoc || !frame || mDoc != frame->GetOwnerDoc() || !inner) {
9915 continue;
9918 if (inner && aThawChildren) {
9919 inner->Thaw();
9922 rv = win->ResumeTimeouts(aThawChildren);
9923 NS_ENSURE_SUCCESS(rv, rv);
9928 return NS_OK;
9931 PRUint32
9932 nsGlobalWindow::TimeoutSuspendCount()
9934 FORWARD_TO_INNER(TimeoutSuspendCount, (), 0);
9935 return mTimeoutsSuspendDepth;
9938 NS_IMETHODIMP
9939 nsGlobalWindow::GetScriptTypeID(PRUint32 *aScriptType)
9941 NS_ERROR("No default script type here - ask some element");
9942 return nsIProgrammingLanguage::UNKNOWN;
9945 NS_IMETHODIMP
9946 nsGlobalWindow::SetScriptTypeID(PRUint32 aScriptType)
9948 NS_ERROR("Can't change default script type for a document");
9949 return NS_ERROR_NOT_IMPLEMENTED;
9952 void
9953 nsGlobalWindow::SetHasOrientationEventListener()
9955 mHasAcceleration = PR_TRUE;
9956 EnableAccelerationUpdates();
9959 NS_IMETHODIMP
9960 nsGlobalWindow::GetURL(nsIDOMMozURLProperty** aURL)
9962 FORWARD_TO_INNER(GetURL, (aURL), NS_ERROR_UNEXPECTED);
9964 if (!mURLProperty) {
9965 mURLProperty = new nsDOMMozURLProperty(this);
9968 NS_ADDREF(*aURL = mURLProperty);
9970 return NS_OK;
9973 // nsGlobalChromeWindow implementation
9975 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
9976 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
9977 nsGlobalWindow)
9978 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBrowserDOMWindow)
9979 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMessageManager)
9980 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
9982 DOMCI_DATA(ChromeWindow, nsGlobalChromeWindow)
9984 // QueryInterface implementation for nsGlobalChromeWindow
9985 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow)
9986 NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)
9987 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ChromeWindow)
9988 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
9990 NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
9991 NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
9993 NS_IMETHODIMP
9994 nsGlobalChromeWindow::GetWindowState(PRUint16* aWindowState)
9996 *aWindowState = nsIDOMChromeWindow::STATE_NORMAL;
9998 nsCOMPtr<nsIWidget> widget = GetMainWidget();
10000 PRInt32 aMode = 0;
10002 if (widget) {
10003 nsresult rv = widget->GetSizeMode(&aMode);
10004 NS_ENSURE_SUCCESS(rv, rv);
10007 switch (aMode) {
10008 case nsSizeMode_Minimized:
10009 *aWindowState = nsIDOMChromeWindow::STATE_MINIMIZED;
10010 break;
10011 case nsSizeMode_Maximized:
10012 *aWindowState = nsIDOMChromeWindow::STATE_MAXIMIZED;
10013 break;
10014 case nsSizeMode_Fullscreen:
10015 *aWindowState = nsIDOMChromeWindow::STATE_FULLSCREEN;
10016 break;
10017 case nsSizeMode_Normal:
10018 *aWindowState = nsIDOMChromeWindow::STATE_NORMAL;
10019 break;
10020 default:
10021 NS_WARNING("Illegal window state for this chrome window");
10022 break;
10025 return NS_OK;
10028 NS_IMETHODIMP
10029 nsGlobalChromeWindow::Maximize()
10031 nsCOMPtr<nsIWidget> widget = GetMainWidget();
10032 nsresult rv = NS_OK;
10034 if (widget) {
10035 rv = widget->SetSizeMode(nsSizeMode_Maximized);
10038 return rv;
10041 NS_IMETHODIMP
10042 nsGlobalChromeWindow::Minimize()
10044 nsCOMPtr<nsIWidget> widget = GetMainWidget();
10045 nsresult rv = NS_OK;
10047 if (widget)
10048 rv = widget->SetSizeMode(nsSizeMode_Minimized);
10050 return rv;
10053 NS_IMETHODIMP
10054 nsGlobalChromeWindow::Restore()
10056 nsCOMPtr<nsIWidget> widget = GetMainWidget();
10057 nsresult rv = NS_OK;
10059 if (widget) {
10060 rv = widget->SetSizeMode(nsSizeMode_Normal);
10063 return rv;
10066 NS_IMETHODIMP
10067 nsGlobalChromeWindow::GetAttention()
10069 return GetAttentionWithCycleCount(-1);
10072 NS_IMETHODIMP
10073 nsGlobalChromeWindow::GetAttentionWithCycleCount(PRInt32 aCycleCount)
10075 nsCOMPtr<nsIWidget> widget = GetMainWidget();
10076 nsresult rv = NS_OK;
10078 if (widget) {
10079 rv = widget->GetAttention(aCycleCount);
10082 return rv;
10085 NS_IMETHODIMP
10086 nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent)
10088 nsCOMPtr<nsIWidget> widget = GetMainWidget();
10089 if (!widget) {
10090 return NS_OK;
10093 nsCOMPtr<nsIPrivateDOMEvent> privEvent = do_QueryInterface(aMouseDownEvent);
10094 NS_ENSURE_TRUE(privEvent, NS_ERROR_FAILURE);
10095 nsEvent *internalEvent = privEvent->GetInternalNSEvent();
10096 NS_ENSURE_TRUE(internalEvent &&
10097 internalEvent->eventStructType == NS_MOUSE_EVENT,
10098 NS_ERROR_FAILURE);
10099 nsMouseEvent *mouseEvent = static_cast<nsMouseEvent*>(internalEvent);
10101 return widget->BeginMoveDrag(mouseEvent);
10104 //Note: This call will lock the cursor, it will not change as it moves.
10105 //To unlock, the cursor must be set back to CURSOR_AUTO.
10106 NS_IMETHODIMP
10107 nsGlobalChromeWindow::SetCursor(const nsAString& aCursor)
10109 FORWARD_TO_OUTER_CHROME(SetCursor, (aCursor), NS_ERROR_NOT_INITIALIZED);
10111 nsresult rv = NS_OK;
10112 PRInt32 cursor;
10114 // use C strings to keep the code/data size down
10115 NS_ConvertUTF16toUTF8 cursorString(aCursor);
10117 if (cursorString.Equals("auto"))
10118 cursor = NS_STYLE_CURSOR_AUTO;
10119 else {
10120 nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
10121 if (eCSSKeyword_UNKNOWN == keyword ||
10122 !nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, cursor)) {
10123 // XXX remove the following three values (leave return NS_OK) after 1.8
10124 // XXX since they should have been -moz- prefixed (covered by FindKeyword).
10125 // XXX (also remove |cursorString| at that point?).
10126 if (cursorString.Equals("grab"))
10127 cursor = NS_STYLE_CURSOR_GRAB;
10128 else if (cursorString.Equals("grabbing"))
10129 cursor = NS_STYLE_CURSOR_GRABBING;
10130 else if (cursorString.Equals("spinning"))
10131 cursor = NS_STYLE_CURSOR_SPINNING;
10132 else
10133 return NS_OK;
10137 nsRefPtr<nsPresContext> presContext;
10138 if (mDocShell) {
10139 mDocShell->GetPresContext(getter_AddRefs(presContext));
10142 if (presContext) {
10143 // Need root widget.
10144 nsCOMPtr<nsIPresShell> presShell;
10145 mDocShell->GetPresShell(getter_AddRefs(presShell));
10146 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
10148 nsIViewManager* vm = presShell->GetViewManager();
10149 NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
10151 nsIView *rootView;
10152 vm->GetRootView(rootView);
10153 NS_ENSURE_TRUE(rootView, NS_ERROR_FAILURE);
10155 nsIWidget* widget = rootView->GetNearestWidget(nsnull);
10156 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
10158 // Call esm and set cursor.
10159 rv = presContext->EventStateManager()->SetCursor(cursor, nsnull,
10160 PR_FALSE, 0.0f, 0.0f,
10161 widget, PR_TRUE);
10164 return rv;
10167 NS_IMETHODIMP
10168 nsGlobalChromeWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow)
10170 FORWARD_TO_OUTER_CHROME(GetBrowserDOMWindow, (aBrowserWindow),
10171 NS_ERROR_NOT_INITIALIZED);
10173 NS_ENSURE_ARG_POINTER(aBrowserWindow);
10175 *aBrowserWindow = mBrowserDOMWindow;
10176 NS_IF_ADDREF(*aBrowserWindow);
10177 return NS_OK;
10180 NS_IMETHODIMP
10181 nsGlobalChromeWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow *aBrowserWindow)
10183 FORWARD_TO_OUTER_CHROME(SetBrowserDOMWindow, (aBrowserWindow),
10184 NS_ERROR_NOT_INITIALIZED);
10186 mBrowserDOMWindow = aBrowserWindow;
10187 return NS_OK;
10190 NS_IMETHODIMP
10191 nsGlobalChromeWindow::NotifyDefaultButtonLoaded(nsIDOMElement* aDefaultButton)
10193 #ifdef MOZ_XUL
10194 NS_ENSURE_ARG(aDefaultButton);
10196 // Don't snap to a disabled button.
10197 nsCOMPtr<nsIDOMXULControlElement> xulControl =
10198 do_QueryInterface(aDefaultButton);
10199 NS_ENSURE_TRUE(xulControl, NS_ERROR_FAILURE);
10200 PRBool disabled;
10201 nsresult rv = xulControl->GetDisabled(&disabled);
10202 NS_ENSURE_SUCCESS(rv, rv);
10203 if (disabled)
10204 return NS_OK;
10206 // Get the button rect in screen coordinates.
10207 nsCOMPtr<nsIContent> content(do_QueryInterface(aDefaultButton));
10208 NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
10209 nsIFrame *frame = content->GetPrimaryFrame();
10210 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
10211 nsIntRect buttonRect = frame->GetScreenRect();
10213 // Get the widget rect in screen coordinates.
10214 nsIWidget *widget = GetNearestWidget();
10215 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
10216 nsIntRect widgetRect;
10217 rv = widget->GetScreenBounds(widgetRect);
10218 NS_ENSURE_SUCCESS(rv, rv);
10220 // Convert the buttonRect coordinates from screen to the widget.
10221 buttonRect -= widgetRect.TopLeft();
10222 rv = widget->OnDefaultButtonLoaded(buttonRect);
10223 if (rv == NS_ERROR_NOT_IMPLEMENTED)
10224 return NS_OK;
10225 return rv;
10226 #else
10227 return NS_ERROR_NOT_IMPLEMENTED;
10228 #endif
10231 NS_IMETHODIMP
10232 nsGlobalChromeWindow::GetMessageManager(nsIChromeFrameMessageManager** aManager)
10234 FORWARD_TO_INNER_CHROME(GetMessageManager, (aManager), NS_ERROR_FAILURE);
10235 if (!mMessageManager) {
10236 nsIScriptContext* scx = GetContextInternal();
10237 NS_ENSURE_STATE(scx);
10238 JSContext* cx = (JSContext *)scx->GetNativeContext();
10239 NS_ENSURE_STATE(cx);
10240 nsCOMPtr<nsIChromeFrameMessageManager> globalMM =
10241 do_GetService("@mozilla.org/globalmessagemanager;1");
10242 mMessageManager =
10243 new nsFrameMessageManager(PR_TRUE,
10244 nsnull,
10245 nsnull,
10246 nsnull,
10247 nsnull,
10248 static_cast<nsFrameMessageManager*>(globalMM.get()),
10249 cx);
10250 NS_ENSURE_TRUE(mMessageManager, NS_ERROR_OUT_OF_MEMORY);
10252 CallQueryInterface(mMessageManager, aManager);
10253 return NS_OK;
10256 // nsGlobalModalWindow implementation
10258 // QueryInterface implementation for nsGlobalModalWindow
10259 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalModalWindow)
10260 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalModalWindow,
10261 nsGlobalWindow)
10262 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mReturnValue)
10263 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
10265 DOMCI_DATA(ModalContentWindow, nsGlobalModalWindow)
10267 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalModalWindow)
10268 NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow)
10269 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ModalContentWindow)
10270 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
10272 NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
10273 NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
10276 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalModalWindow,
10277 nsGlobalWindow)
10278 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReturnValue)
10279 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
10282 NS_IMETHODIMP
10283 nsGlobalModalWindow::GetDialogArguments(nsIArray **aArguments)
10285 FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(GetDialogArguments, (aArguments),
10286 NS_ERROR_NOT_INITIALIZED);
10288 PRBool subsumes = PR_FALSE;
10289 nsIPrincipal *self = GetPrincipal();
10290 if (self && NS_SUCCEEDED(self->Subsumes(mArgumentsOrigin, &subsumes)) &&
10291 subsumes) {
10292 NS_IF_ADDREF(*aArguments = mArguments);
10293 } else {
10294 *aArguments = nsnull;
10297 return NS_OK;
10300 NS_IMETHODIMP
10301 nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
10303 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
10305 NS_IF_ADDREF(*aRetVal = mReturnValue);
10307 return NS_OK;
10310 NS_IMETHODIMP
10311 nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
10313 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aRetVal), NS_OK);
10315 mReturnValue = aRetVal;
10317 return NS_OK;
10320 nsresult
10321 nsGlobalModalWindow::SetNewDocument(nsIDocument *aDocument,
10322 nsISupports *aState,
10323 PRBool aForceReuseInnerWindow)
10325 // If we're loading a new document into a modal dialog, clear the
10326 // return value that was set, if any, by the current document.
10327 if (aDocument) {
10328 mReturnValue = nsnull;
10331 return nsGlobalWindow::SetNewDocument(aDocument, aState,
10332 aForceReuseInnerWindow);
10335 //*****************************************************************************
10336 // nsGlobalWindow: Creator Function (This should go away)
10337 //*****************************************************************************
10339 nsresult
10340 NS_NewScriptGlobalObject(PRBool aIsChrome, PRBool aIsModalContentWindow,
10341 nsIScriptGlobalObject **aResult)
10343 *aResult = nsnull;
10345 nsGlobalWindow *global;
10347 if (aIsChrome) {
10348 global = new nsGlobalChromeWindow(nsnull);
10349 } else if (aIsModalContentWindow) {
10350 global = new nsGlobalModalWindow(nsnull);
10351 } else {
10352 global = new nsGlobalWindow(nsnull);
10355 NS_ENSURE_TRUE(global, NS_ERROR_OUT_OF_MEMORY);
10357 NS_ADDREF(*aResult = global);
10359 return NS_OK;
10362 //*****************************************************************************
10363 //*** nsNavigator: Object Management
10364 //*****************************************************************************
10366 nsNavigator::nsNavigator(nsIDocShell *aDocShell)
10367 : mDocShell(aDocShell)
10371 nsNavigator::~nsNavigator()
10373 if (mMimeTypes)
10374 mMimeTypes->Invalidate();
10375 if (mPlugins)
10376 mPlugins->Invalidate();
10379 //*****************************************************************************
10380 // nsNavigator::nsISupports
10381 //*****************************************************************************
10384 DOMCI_DATA(Navigator, nsNavigator)
10386 // QueryInterface implementation for nsNavigator
10387 NS_INTERFACE_MAP_BEGIN(nsNavigator)
10388 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNavigator)
10389 NS_INTERFACE_MAP_ENTRY(nsIDOMNavigator)
10390 NS_INTERFACE_MAP_ENTRY(nsIDOMClientInformation)
10391 NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorGeolocation)
10392 NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorDesktopNotification)
10393 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
10394 NS_INTERFACE_MAP_END
10397 NS_IMPL_ADDREF(nsNavigator)
10398 NS_IMPL_RELEASE(nsNavigator)
10401 void
10402 nsNavigator::SetDocShell(nsIDocShell *aDocShell)
10404 mDocShell = aDocShell;
10405 if (mPlugins)
10406 mPlugins->SetDocShell(aDocShell);
10408 // if there is a page transition, make sure delete the geolocation object
10409 if (mGeolocation)
10411 mGeolocation->Shutdown();
10412 mGeolocation = nsnull;
10415 if (mNotification)
10417 mNotification->Shutdown();
10418 mNotification = nsnull;
10422 //*****************************************************************************
10423 // nsNavigator::nsIDOMNavigator
10424 //*****************************************************************************
10426 nsresult
10427 NS_GetNavigatorUserAgent(nsAString& aUserAgent)
10429 nsresult rv;
10430 nsCOMPtr<nsIHttpProtocolHandler>
10431 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10432 if (NS_SUCCEEDED(rv)) {
10433 nsCAutoString ua;
10434 rv = service->GetUserAgent(ua);
10435 CopyASCIItoUTF16(ua, aUserAgent);
10438 return rv;
10441 nsresult
10442 NS_GetNavigatorPlatform(nsAString& aPlatform)
10444 if (!nsContentUtils::IsCallerTrustedForRead()) {
10445 const nsAdoptingCString& override =
10446 nsContentUtils::GetCharPref("general.platform.override");
10448 if (override) {
10449 CopyUTF8toUTF16(override, aPlatform);
10450 return NS_OK;
10454 nsresult rv;
10455 nsCOMPtr<nsIHttpProtocolHandler>
10456 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10457 if (NS_SUCCEEDED(rv)) {
10458 // sorry for the #if platform ugliness, but Communicator is
10459 // likewise hardcoded and we're seeking backward compatibility
10460 // here (bug 47080)
10461 #if defined(_WIN64)
10462 aPlatform.AssignLiteral("Win64");
10463 #elif defined(WIN32)
10464 aPlatform.AssignLiteral("Win32");
10465 #elif defined(XP_MACOSX) && defined(__ppc__)
10466 aPlatform.AssignLiteral("MacPPC");
10467 #elif defined(XP_MACOSX) && defined(__i386__)
10468 aPlatform.AssignLiteral("MacIntel");
10469 #elif defined(XP_MACOSX) && defined(__x86_64__)
10470 aPlatform.AssignLiteral("MacIntel");
10471 #elif defined(XP_OS2)
10472 aPlatform.AssignLiteral("OS/2");
10473 #else
10474 // XXX Communicator uses compiled-in build-time string defines
10475 // to indicate the platform it was compiled *for*, not what it is
10476 // currently running *on* which is what this does.
10477 nsCAutoString plat;
10478 rv = service->GetOscpu(plat);
10479 CopyASCIItoUTF16(plat, aPlatform);
10480 #endif
10483 return rv;
10485 nsresult
10486 NS_GetNavigatorAppVersion(nsAString& aAppVersion)
10488 if (!nsContentUtils::IsCallerTrustedForRead()) {
10489 const nsAdoptingCString& override =
10490 nsContentUtils::GetCharPref("general.appversion.override");
10492 if (override) {
10493 CopyUTF8toUTF16(override, aAppVersion);
10494 return NS_OK;
10498 nsresult rv;
10499 nsCOMPtr<nsIHttpProtocolHandler>
10500 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10501 if (NS_SUCCEEDED(rv)) {
10502 nsCAutoString str;
10503 rv = service->GetAppVersion(str);
10504 CopyASCIItoUTF16(str, aAppVersion);
10505 if (NS_FAILED(rv))
10506 return rv;
10508 aAppVersion.AppendLiteral(" (");
10510 rv = service->GetPlatform(str);
10511 if (NS_FAILED(rv))
10512 return rv;
10514 AppendASCIItoUTF16(str, aAppVersion);
10516 aAppVersion.Append(PRUnichar(')'));
10519 return rv;
10522 nsresult
10523 NS_GetNavigatorAppName(nsAString& aAppName)
10525 if (!nsContentUtils::IsCallerTrustedForRead()) {
10526 const nsAdoptingCString& override =
10527 nsContentUtils::GetCharPref("general.appname.override");
10529 if (override) {
10530 CopyUTF8toUTF16(override, aAppName);
10531 return NS_OK;
10535 aAppName.AssignLiteral("Netscape");
10536 return NS_OK;
10539 NS_IMETHODIMP
10540 nsNavigator::GetUserAgent(nsAString& aUserAgent)
10542 return NS_GetNavigatorUserAgent(aUserAgent);
10545 NS_IMETHODIMP
10546 nsNavigator::GetAppCodeName(nsAString& aAppCodeName)
10548 nsresult rv;
10549 nsCOMPtr<nsIHttpProtocolHandler>
10550 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10551 if (NS_SUCCEEDED(rv)) {
10552 nsCAutoString appName;
10553 rv = service->GetAppName(appName);
10554 CopyASCIItoUTF16(appName, aAppCodeName);
10557 return rv;
10560 NS_IMETHODIMP
10561 nsNavigator::GetAppVersion(nsAString& aAppVersion)
10563 return NS_GetNavigatorAppVersion(aAppVersion);
10566 NS_IMETHODIMP
10567 nsNavigator::GetAppName(nsAString& aAppName)
10569 return NS_GetNavigatorAppName(aAppName);
10572 NS_IMETHODIMP
10573 nsNavigator::GetLanguage(nsAString& aLanguage)
10575 nsresult rv;
10576 nsCOMPtr<nsIHttpProtocolHandler>
10577 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10578 if (NS_SUCCEEDED(rv)) {
10579 nsCAutoString lang;
10580 rv = service->GetLanguage(lang);
10581 CopyASCIItoUTF16(lang, aLanguage);
10584 return rv;
10587 NS_IMETHODIMP
10588 nsNavigator::GetPlatform(nsAString& aPlatform)
10590 return NS_GetNavigatorPlatform(aPlatform);
10593 NS_IMETHODIMP
10594 nsNavigator::GetOscpu(nsAString& aOSCPU)
10596 if (!nsContentUtils::IsCallerTrustedForRead()) {
10597 const nsAdoptingCString& override =
10598 nsContentUtils::GetCharPref("general.oscpu.override");
10600 if (override) {
10601 CopyUTF8toUTF16(override, aOSCPU);
10602 return NS_OK;
10606 nsresult rv;
10607 nsCOMPtr<nsIHttpProtocolHandler>
10608 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10609 if (NS_SUCCEEDED(rv)) {
10610 nsCAutoString oscpu;
10611 rv = service->GetOscpu(oscpu);
10612 CopyASCIItoUTF16(oscpu, aOSCPU);
10615 return rv;
10618 NS_IMETHODIMP
10619 nsNavigator::GetVendor(nsAString& aVendor)
10621 aVendor.Truncate();
10622 return NS_OK;
10626 NS_IMETHODIMP
10627 nsNavigator::GetVendorSub(nsAString& aVendorSub)
10629 aVendorSub.Truncate();
10630 return NS_OK;
10633 NS_IMETHODIMP
10634 nsNavigator::GetProduct(nsAString& aProduct)
10636 nsresult rv;
10637 nsCOMPtr<nsIHttpProtocolHandler>
10638 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10639 if (NS_SUCCEEDED(rv)) {
10640 nsCAutoString product;
10641 rv = service->GetProduct(product);
10642 CopyASCIItoUTF16(product, aProduct);
10645 return rv;
10648 NS_IMETHODIMP
10649 nsNavigator::GetProductSub(nsAString& aProductSub)
10651 if (!nsContentUtils::IsCallerTrustedForRead()) {
10652 const nsAdoptingCString& override =
10653 nsContentUtils::GetCharPref("general.productSub.override");
10655 if (override) {
10656 CopyUTF8toUTF16(override, aProductSub);
10657 return NS_OK;
10658 } else {
10659 // 'general.useragent.productSub' backwards compatible with 1.8 branch.
10660 const nsAdoptingCString& override2 =
10661 nsContentUtils::GetCharPref("general.useragent.productSub");
10663 if (override2) {
10664 CopyUTF8toUTF16(override2, aProductSub);
10665 return NS_OK;
10670 nsresult rv;
10671 nsCOMPtr<nsIHttpProtocolHandler>
10672 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10673 if (NS_SUCCEEDED(rv)) {
10674 nsCAutoString productSub;
10675 rv = service->GetProductSub(productSub);
10676 CopyASCIItoUTF16(productSub, aProductSub);
10679 return rv;
10682 NS_IMETHODIMP
10683 nsNavigator::GetSecurityPolicy(nsAString& aSecurityPolicy)
10685 return NS_OK;
10688 NS_IMETHODIMP
10689 nsNavigator::GetMimeTypes(nsIDOMMimeTypeArray **aMimeTypes)
10691 if (!mMimeTypes) {
10692 mMimeTypes = new nsMimeTypeArray(this);
10693 if (!mMimeTypes) {
10694 return NS_ERROR_OUT_OF_MEMORY;
10698 NS_ADDREF(*aMimeTypes = mMimeTypes);
10700 return NS_OK;
10703 NS_IMETHODIMP
10704 nsNavigator::GetPlugins(nsIDOMPluginArray **aPlugins)
10706 if (!mPlugins) {
10707 mPlugins = new nsPluginArray(this, mDocShell);
10708 if (!mPlugins) {
10709 return NS_ERROR_OUT_OF_MEMORY;
10713 NS_ADDREF(*aPlugins = mPlugins);
10715 return NS_OK;
10718 // values for the network.cookie.cookieBehavior pref are documented in
10719 // nsCookieService.cpp.
10720 #define COOKIE_BEHAVIOR_REJECT 2
10722 NS_IMETHODIMP
10723 nsNavigator::GetCookieEnabled(PRBool *aCookieEnabled)
10725 *aCookieEnabled =
10726 (nsContentUtils::GetIntPref("network.cookie.cookieBehavior",
10727 COOKIE_BEHAVIOR_REJECT) !=
10728 COOKIE_BEHAVIOR_REJECT);
10730 return NS_OK;
10733 NS_IMETHODIMP
10734 nsNavigator::GetOnLine(PRBool* aOnline)
10736 NS_PRECONDITION(aOnline, "Null out param");
10738 *aOnline = !NS_IsOffline();
10739 return NS_OK;
10742 NS_IMETHODIMP
10743 nsNavigator::GetBuildID(nsAString& aBuildID)
10745 if (!nsContentUtils::IsCallerTrustedForRead()) {
10746 const nsAdoptingCString& override =
10747 nsContentUtils::GetCharPref("general.buildID.override");
10749 if (override) {
10750 CopyUTF8toUTF16(override, aBuildID);
10751 return NS_OK;
10755 nsCOMPtr<nsIXULAppInfo> appInfo =
10756 do_GetService("@mozilla.org/xre/app-info;1");
10757 if (!appInfo)
10758 return NS_ERROR_NOT_IMPLEMENTED;
10760 nsCAutoString buildID;
10761 nsresult rv = appInfo->GetAppBuildID(buildID);
10762 if (NS_FAILED(rv))
10763 return rv;
10765 aBuildID.Truncate();
10766 AppendASCIItoUTF16(buildID, aBuildID);
10767 return NS_OK;
10770 NS_IMETHODIMP
10771 nsNavigator::JavaEnabled(PRBool *aReturn)
10773 // Return true if we have a handler for "application/x-java-vm",
10774 // otherwise return false.
10775 *aReturn = PR_FALSE;
10777 if (!mMimeTypes) {
10778 mMimeTypes = new nsMimeTypeArray(this);
10779 if (!mMimeTypes)
10780 return NS_ERROR_OUT_OF_MEMORY;
10783 RefreshMIMEArray();
10785 PRUint32 count;
10786 mMimeTypes->GetLength(&count);
10787 for (PRUint32 i = 0; i < count; i++) {
10788 nsresult rv;
10789 nsIDOMMimeType* type = mMimeTypes->GetItemAt(i, &rv);
10790 nsAutoString mimeString;
10791 if (type && NS_SUCCEEDED(type->GetType(mimeString))) {
10792 if (mimeString.EqualsLiteral("application/x-java-vm")) {
10793 *aReturn = PR_TRUE;
10794 break;
10799 return NS_OK;
10802 NS_IMETHODIMP
10803 nsNavigator::TaintEnabled(PRBool *aReturn)
10805 *aReturn = PR_FALSE;
10806 return NS_OK;
10809 void
10810 nsNavigator::LoadingNewDocument()
10812 // Release these so that they will be recreated for the
10813 // new document (if requested). The plugins or mime types
10814 // arrays may have changed. See bug 150087.
10815 if (mMimeTypes) {
10816 mMimeTypes->Invalidate();
10817 mMimeTypes = nsnull;
10820 if (mPlugins) {
10821 mPlugins->Invalidate();
10822 mPlugins = nsnull;
10825 if (mGeolocation)
10827 mGeolocation->Shutdown();
10828 mGeolocation = nsnull;
10831 if (mNotification)
10833 mNotification->Shutdown();
10834 mNotification = nsnull;
10839 nsresult
10840 nsNavigator::RefreshMIMEArray()
10842 nsresult rv = NS_OK;
10843 if (mMimeTypes)
10844 rv = mMimeTypes->Refresh();
10845 return rv;
10848 bool
10849 nsNavigator::HasDesktopNotificationSupport()
10851 return nsContentUtils::GetBoolPref("notification.feature.enabled", PR_FALSE);
10854 //*****************************************************************************
10855 // nsNavigator::nsIDOMClientInformation
10856 //*****************************************************************************
10858 NS_IMETHODIMP
10859 nsNavigator::RegisterContentHandler(const nsAString& aMIMEType,
10860 const nsAString& aURI,
10861 const nsAString& aTitle)
10863 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
10864 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
10865 if (registrar && mDocShell) {
10866 nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
10867 if (contentDOMWindow)
10868 return registrar->RegisterContentHandler(aMIMEType, aURI, aTitle,
10869 contentDOMWindow);
10872 return NS_OK;
10875 NS_IMETHODIMP
10876 nsNavigator::RegisterProtocolHandler(const nsAString& aProtocol,
10877 const nsAString& aURI,
10878 const nsAString& aTitle)
10880 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
10881 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
10882 if (registrar && mDocShell) {
10883 nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
10884 if (contentDOMWindow)
10885 return registrar->RegisterProtocolHandler(aProtocol, aURI, aTitle,
10886 contentDOMWindow);
10889 return NS_OK;
10893 NS_IMETHODIMP
10894 nsNavigator::MozIsLocallyAvailable(const nsAString &aURI,
10895 PRBool aWhenOffline,
10896 PRBool *aIsAvailable)
10898 nsCOMPtr<nsIURI> uri;
10899 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI);
10900 NS_ENSURE_SUCCESS(rv, rv);
10902 // This method of checking the cache will only work for http/https urls
10903 PRBool match;
10904 rv = uri->SchemeIs("http", &match);
10905 NS_ENSURE_SUCCESS(rv, rv);
10906 if (!match) {
10907 rv = uri->SchemeIs("https", &match);
10908 NS_ENSURE_SUCCESS(rv, rv);
10909 if (!match) return NS_ERROR_DOM_BAD_URI;
10912 // Same origin check
10913 nsCOMPtr<nsIJSContextStack> stack = do_GetService(sJSStackContractID);
10914 NS_ENSURE_TRUE(stack, NS_ERROR_FAILURE);
10916 JSContext *cx = nsnull;
10917 rv = stack->Peek(&cx);
10918 NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
10920 rv = nsContentUtils::GetSecurityManager()->CheckSameOrigin(cx, uri);
10921 NS_ENSURE_SUCCESS(rv, rv);
10923 // these load flags cause an error to be thrown if there is no
10924 // valid cache entry, and skip the load if there is.
10925 // if the cache is busy, assume that it is not yet available rather
10926 // than waiting for it to become available.
10927 PRUint32 loadFlags = nsIChannel::INHIBIT_CACHING |
10928 nsICachingChannel::LOAD_NO_NETWORK_IO |
10929 nsICachingChannel::LOAD_ONLY_IF_MODIFIED |
10930 nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY;
10932 if (aWhenOffline) {
10933 loadFlags |= nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE |
10934 nsICachingChannel::LOAD_ONLY_FROM_CACHE |
10935 nsIRequest::LOAD_FROM_CACHE;
10938 nsCOMPtr<nsIChannel> channel;
10939 rv = NS_NewChannel(getter_AddRefs(channel), uri,
10940 nsnull, nsnull, nsnull, loadFlags);
10941 NS_ENSURE_SUCCESS(rv, rv);
10943 nsCOMPtr<nsIInputStream> stream;
10944 rv = channel->Open(getter_AddRefs(stream));
10945 NS_ENSURE_SUCCESS(rv, rv);
10947 stream->Close();
10949 nsresult status;
10950 rv = channel->GetStatus(&status);
10951 NS_ENSURE_SUCCESS(rv, rv);
10953 if (NS_SUCCEEDED(status)) {
10954 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
10955 rv = httpChannel->GetRequestSucceeded(aIsAvailable);
10956 NS_ENSURE_SUCCESS(rv, rv);
10957 } else {
10958 *aIsAvailable = PR_FALSE;
10961 return NS_OK;
10964 //*****************************************************************************
10965 // nsNavigator::nsIDOMNavigatorGeolocation
10966 //*****************************************************************************
10968 NS_IMETHODIMP nsNavigator::GetGeolocation(nsIDOMGeoGeolocation **_retval)
10970 NS_ENSURE_ARG_POINTER(_retval);
10971 *_retval = nsnull;
10973 if (mGeolocation) {
10974 NS_ADDREF(*_retval = mGeolocation);
10975 return NS_OK;
10978 if (!mDocShell)
10979 return NS_ERROR_FAILURE;
10981 nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
10982 if (!contentDOMWindow)
10983 return NS_ERROR_FAILURE;
10985 mGeolocation = new nsGeolocation();
10986 if (!mGeolocation)
10987 return NS_ERROR_FAILURE;
10989 if (NS_FAILED(mGeolocation->Init(contentDOMWindow)))
10990 return NS_ERROR_FAILURE;
10992 NS_ADDREF(*_retval = mGeolocation);
10993 return NS_OK;
10997 //*****************************************************************************
10998 // nsNavigator::nsIDOMNavigatorDesktopNotification
10999 //*****************************************************************************
11001 NS_IMETHODIMP nsNavigator::GetMozNotification(nsIDOMDesktopNotificationCenter **aRetVal)
11003 NS_ENSURE_ARG_POINTER(aRetVal);
11004 *aRetVal = nsnull;
11006 if (mNotification) {
11007 NS_ADDREF(*aRetVal = mNotification);
11008 return NS_OK;
11011 nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(mDocShell));
11012 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
11014 nsCOMPtr<nsIDocument> document = do_GetInterface(mDocShell);
11015 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
11017 nsIScriptGlobalObject *sgo = document->GetScopeObject();
11018 NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
11020 nsIScriptContext *scx = sgo->GetContext();
11021 NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
11023 mNotification = new nsDesktopNotificationCenter(window->GetCurrentInnerWindow(),
11024 scx);
11025 if (!mNotification) {
11026 return NS_ERROR_FAILURE;
11029 NS_ADDREF(*aRetVal = mNotification);
11030 return NS_OK;