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
5 : *
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/
10 : *
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.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
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.
22 : *
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>
33 : * Ben Bucksch <ben.bucksch beonex.com>
34 : * Emanuele Costa <emanuele.costa@gmail.com>
35 : *
36 : * Alternatively, the contents of this file may be used under the terms of
37 : * either of the GNU General Public License Version 2 or later (the "GPL"),
38 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
39 : * in which case the provisions of the GPL or the LGPL are applicable instead
40 : * of those above. If you wish to allow use of your version of this file only
41 : * under the terms of either the GPL or the LGPL, and not to allow others to
42 : * use your version of this file under the terms of the MPL, indicate your
43 : * decision by deleting the provisions above and replace them with the notice
44 : * and other provisions required by the GPL or the LGPL. If you do not delete
45 : * the provisions above, a recipient may use your version of this file under
46 : * the terms of any one of the MPL, the GPL or the LGPL.
47 : *
48 : * ***** END LICENSE BLOCK ***** */
49 :
50 : #include "base/basictypes.h"
51 :
52 : /* This must occur *after* base/basictypes.h to avoid typedefs conflicts. */
53 : #include "mozilla/Util.h"
54 :
55 : // Local Includes
56 : #include "nsGlobalWindow.h"
57 : #include "Navigator.h"
58 : #include "nsScreen.h"
59 : #include "nsHistory.h"
60 : #include "nsPerformance.h"
61 : #include "nsDOMNavigationTiming.h"
62 : #include "nsBarProps.h"
63 : #include "nsDOMStorage.h"
64 : #include "nsDOMOfflineResourceList.h"
65 : #include "nsDOMError.h"
66 :
67 : // Helper Classes
68 : #include "nsXPIDLString.h"
69 : #include "nsJSUtils.h"
70 : #include "prmem.h"
71 : #include "jsapi.h" // for JSAutoRequest
72 : #include "jsdbgapi.h" // for JS_ClearWatchPointsForObject
73 : #include "jsfriendapi.h" // for JS_GetGlobalForFrame
74 : #include "nsReadableUtils.h"
75 : #include "nsDOMClassInfo.h"
76 : #include "nsJSEnvironment.h"
77 : #include "nsCharSeparatedTokenizer.h" // for Accept-Language parsing
78 : #include "nsUnicharUtils.h"
79 : #include "mozilla/Preferences.h"
80 :
81 : // Other Classes
82 : #include "nsEventListenerManager.h"
83 : #include "nsEscape.h"
84 : #include "nsStyleCoord.h"
85 : #include "nsMimeTypeArray.h"
86 : #include "nsNetUtil.h"
87 : #include "nsICachingChannel.h"
88 : #include "nsPluginArray.h"
89 : #include "nsIPluginHost.h"
90 : #include "nsPluginHost.h"
91 : #include "nsIPluginInstanceOwner.h"
92 : #include "nsGeolocation.h"
93 : #include "nsDesktopNotification.h"
94 : #include "nsContentCID.h"
95 : #include "nsLayoutStatics.h"
96 : #include "nsCycleCollector.h"
97 : #include "nsCCUncollectableMarker.h"
98 : #include "nsAutoJSValHolder.h"
99 : #include "nsDOMMediaQueryList.h"
100 : #include "mozilla/dom/workers/Workers.h"
101 :
102 : // Interfaces Needed
103 : #include "nsIFrame.h"
104 : #include "nsCanvasFrame.h"
105 : #include "nsIWidget.h"
106 : #include "nsIBaseWindow.h"
107 : #include "nsDeviceMotion.h"
108 : #include "nsIContent.h"
109 : #include "nsIContentViewerEdit.h"
110 : #include "nsIDocShell.h"
111 : #include "nsIDocShellLoadInfo.h"
112 : #include "nsIDocShellTreeItem.h"
113 : #include "nsIDocShellTreeNode.h"
114 : #include "nsIEditorDocShell.h"
115 : #include "nsIDocCharset.h"
116 : #include "nsIDocument.h"
117 : #include "nsIHTMLDocument.h"
118 : #include "nsIDOMHTMLDocument.h"
119 : #include "nsIDOMHTMLElement.h"
120 : #ifndef MOZ_DISABLE_DOMCRYPTO
121 : #include "nsIDOMCrypto.h"
122 : #endif
123 : #include "nsIDOMDocument.h"
124 : #include "nsIDOMElement.h"
125 : #include "nsIDOMEvent.h"
126 : #include "nsIDOMHTMLAnchorElement.h"
127 : #include "nsIDOMKeyEvent.h"
128 : #include "nsIDOMMessageEvent.h"
129 : #include "nsIDOMPopupBlockedEvent.h"
130 : #include "nsIDOMPopStateEvent.h"
131 : #include "nsIDOMHashChangeEvent.h"
132 : #include "nsIDOMOfflineResourceList.h"
133 : #include "nsIDOMGeoGeolocation.h"
134 : #include "nsIDOMDesktopNotification.h"
135 : #include "nsPIDOMStorage.h"
136 : #include "nsDOMString.h"
137 : #include "nsIEmbeddingSiteWindow2.h"
138 : #include "nsThreadUtils.h"
139 : #include "nsEventStateManager.h"
140 : #include "nsIHttpProtocolHandler.h"
141 : #include "nsIJSContextStack.h"
142 : #include "nsIJSRuntimeService.h"
143 : #include "nsIMarkupDocumentViewer.h"
144 : #include "nsIPrefBranch.h"
145 : #include "nsIPresShell.h"
146 : #include "nsIPrivateDOMEvent.h"
147 : #include "nsIProgrammingLanguage.h"
148 : #include "nsIServiceManager.h"
149 : #include "nsIScriptGlobalObjectOwner.h"
150 : #include "nsIScriptSecurityManager.h"
151 : #include "nsIScrollableFrame.h"
152 : #include "nsIView.h"
153 : #include "nsIViewManager.h"
154 : #include "nsISelectionController.h"
155 : #include "nsISelection.h"
156 : #include "nsIPrompt.h"
157 : #include "nsIPromptService.h"
158 : #include "nsIPromptFactory.h"
159 : #include "nsIWritablePropertyBag2.h"
160 : #include "nsIWebNavigation.h"
161 : #include "nsIWebBrowser.h"
162 : #include "nsIWebBrowserChrome.h"
163 : #include "nsIWebBrowserFind.h" // For window.find()
164 : #include "nsIWebContentHandlerRegistrar.h"
165 : #include "nsIWindowMediator.h" // For window.find()
166 : #include "nsComputedDOMStyle.h"
167 : #include "nsIEntropyCollector.h"
168 : #include "nsDOMCID.h"
169 : #include "nsDOMError.h"
170 : #include "nsDOMWindowUtils.h"
171 : #include "nsIWindowWatcher.h"
172 : #include "nsPIWindowWatcher.h"
173 : #include "nsIContentViewer.h"
174 : #include "nsIJSNativeInitializer.h"
175 : #include "nsIScriptError.h"
176 : #include "nsIConsoleService.h"
177 : #include "nsIControllers.h"
178 : #include "nsIControllerContext.h"
179 : #include "nsGlobalWindowCommands.h"
180 : #include "nsAutoPtr.h"
181 : #include "nsContentUtils.h"
182 : #include "nsCSSProps.h"
183 : #include "nsBlobProtocolHandler.h"
184 : #include "nsIDOMFile.h"
185 : #include "nsIDOMFileList.h"
186 : #include "nsIURIFixup.h"
187 : #include "mozilla/FunctionTimer.h"
188 : #include "nsCDefaultURIFixup.h"
189 : #include "nsEventDispatcher.h"
190 : #include "nsIObserverService.h"
191 : #include "nsIXULAppInfo.h"
192 : #include "nsNetUtil.h"
193 : #include "nsFocusManager.h"
194 : #include "nsIXULWindow.h"
195 : #include "nsEventStateManager.h"
196 : #include "nsITimedChannel.h"
197 : #include "nsICookiePermission.h"
198 : #include "nsServiceManagerUtils.h"
199 : #ifdef MOZ_XUL
200 : #include "nsXULPopupManager.h"
201 : #include "nsIDOMXULControlElement.h"
202 : #include "nsMenuPopupFrame.h"
203 : #endif
204 :
205 : #include "xpcprivate.h"
206 :
207 : #ifdef NS_PRINTING
208 : #include "nsIPrintSettings.h"
209 : #include "nsIPrintSettingsService.h"
210 : #include "nsIWebBrowserPrint.h"
211 : #endif
212 :
213 : #include "nsWindowRoot.h"
214 : #include "nsNetCID.h"
215 : #include "nsIArray.h"
216 : #include "nsIScriptRuntime.h"
217 :
218 : // XXX An unfortunate dependency exists here (two XUL files).
219 : #include "nsIDOMXULDocument.h"
220 : #include "nsIDOMXULCommandDispatcher.h"
221 :
222 : #include "nsBindingManager.h"
223 : #include "nsIXBLService.h"
224 :
225 : // used for popup blocking, needs to be converted to something
226 : // belonging to the back-end like nsIContentPolicy
227 : #include "nsIPopupWindowManager.h"
228 :
229 : #include "nsIDragService.h"
230 : #include "mozilla/dom/Element.h"
231 : #include "nsFrameLoader.h"
232 : #include "nsISupportsPrimitives.h"
233 : #include "nsXPCOMCID.h"
234 :
235 : #include "mozilla/FunctionTimer.h"
236 : #include "mozIThirdPartyUtil.h"
237 :
238 : #ifdef MOZ_LOGGING
239 : // so we can get logging even in release builds
240 : #define FORCE_PR_LOG 1
241 : #endif
242 : #include "prlog.h"
243 : #include "prenv.h"
244 :
245 : #include "mozilla/dom/indexedDB/IDBFactory.h"
246 : #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
247 :
248 : #include "mozilla/dom/StructuredCloneTags.h"
249 :
250 : #include "nsRefreshDriver.h"
251 : #include "mozAutoDocUpdate.h"
252 :
253 : #include "mozilla/Telemetry.h"
254 : #include "nsLocation.h"
255 : #include "nsWrapperCacheInlines.h"
256 : #include "nsDOMEventTargetHelper.h"
257 :
258 : #ifdef ANDROID
259 : #include <android/log.h>
260 : #endif
261 :
262 : #ifdef PR_LOGGING
263 : static PRLogModuleInfo* gDOMLeakPRLog;
264 : #endif
265 :
266 : static const char kStorageEnabled[] = "dom.storage.enabled";
267 :
268 : using namespace mozilla;
269 : using namespace mozilla::dom;
270 : using mozilla::TimeStamp;
271 : using mozilla::TimeDuration;
272 :
273 : nsIDOMStorageList *nsGlobalWindow::sGlobalStorageList = nsnull;
274 : nsGlobalWindow::WindowByIdTable *nsGlobalWindow::sWindowsById = nsnull;
275 : bool nsGlobalWindow::sWarnedAboutWindowInternal = false;
276 :
277 : static nsIEntropyCollector *gEntropyCollector = nsnull;
278 : static PRInt32 gRefCnt = 0;
279 : static PRInt32 gOpenPopupSpamCount = 0;
280 : static PopupControlState gPopupControlState = openAbused;
281 : static PRInt32 gRunningTimeoutDepth = 0;
282 : static bool gMouseDown = false;
283 : static bool gDragServiceDisabled = false;
284 : static FILE *gDumpFile = nsnull;
285 : static PRUint64 gNextWindowID = 0;
286 : static PRUint32 gSerialCounter = 0;
287 : static PRUint32 gTimeoutsRecentlySet = 0;
288 1464 : static TimeStamp gLastRecordedRecentTimeouts;
289 : #define STATISTICS_INTERVAL (30 * PR_MSEC_PER_SEC)
290 :
291 : #ifdef DEBUG_jst
292 : PRInt32 gTimeoutCnt = 0;
293 : #endif
294 :
295 : #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
296 : static bool gDOMWindowDumpEnabled = false;
297 : #endif
298 :
299 : #if defined(DEBUG_bryner) || defined(DEBUG_chb)
300 : #define DEBUG_PAGE_CACHE
301 : #endif
302 :
303 : #define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"
304 :
305 : // The default shortest interval/timeout we permit
306 : #define DEFAULT_MIN_TIMEOUT_VALUE 4 // 4ms
307 : #define DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms
308 : static PRInt32 gMinTimeoutValue;
309 : static PRInt32 gMinBackgroundTimeoutValue;
310 : inline PRInt32
311 0 : nsGlobalWindow::DOMMinTimeoutValue() const {
312 0 : bool isBackground = !mOuterWindow || mOuterWindow->IsBackground();
313 : return
314 0 : NS_MAX(isBackground ? gMinBackgroundTimeoutValue : gMinTimeoutValue, 0);
315 : }
316 :
317 : // The number of nested timeouts before we start clamping. HTML5 says 1, WebKit
318 : // uses 5.
319 : #define DOM_CLAMP_TIMEOUT_NESTING_LEVEL 5
320 :
321 : // The longest interval (as PRIntervalTime) we permit, or that our
322 : // timer code can handle, really. See DELAY_INTERVAL_LIMIT in
323 : // nsTimerImpl.h for details.
324 : #define DOM_MAX_TIMEOUT_VALUE DELAY_INTERVAL_LIMIT
325 :
326 : #define FORWARD_TO_OUTER(method, args, err_rval) \
327 : PR_BEGIN_MACRO \
328 : if (IsInnerWindow()) { \
329 : nsGlobalWindow *outer = GetOuterWindowInternal(); \
330 : if (!outer) { \
331 : NS_WARNING("No outer window available!"); \
332 : return err_rval; \
333 : } \
334 : return outer->method args; \
335 : } \
336 : PR_END_MACRO
337 :
338 : #define FORWARD_TO_OUTER_VOID(method, args) \
339 : PR_BEGIN_MACRO \
340 : if (IsInnerWindow()) { \
341 : nsGlobalWindow *outer = GetOuterWindowInternal(); \
342 : if (!outer) { \
343 : NS_WARNING("No outer window available!"); \
344 : return; \
345 : } \
346 : outer->method args; \
347 : return; \
348 : } \
349 : PR_END_MACRO
350 :
351 : #define FORWARD_TO_OUTER_CHROME(method, args, err_rval) \
352 : PR_BEGIN_MACRO \
353 : if (IsInnerWindow()) { \
354 : nsGlobalWindow *outer = GetOuterWindowInternal(); \
355 : if (!outer) { \
356 : NS_WARNING("No outer window available!"); \
357 : return err_rval; \
358 : } \
359 : return ((nsGlobalChromeWindow *)outer)->method args; \
360 : } \
361 : PR_END_MACRO
362 :
363 : #define FORWARD_TO_INNER_CHROME(method, args, err_rval) \
364 : PR_BEGIN_MACRO \
365 : if (IsOuterWindow()) { \
366 : if (!mInnerWindow) { \
367 : NS_WARNING("No inner window available!"); \
368 : return err_rval; \
369 : } \
370 : return ((nsGlobalChromeWindow *)mInnerWindow)->method args; \
371 : } \
372 : PR_END_MACRO
373 :
374 : #define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
375 : PR_BEGIN_MACRO \
376 : if (IsInnerWindow()) { \
377 : nsGlobalWindow *outer = GetOuterWindowInternal(); \
378 : if (!outer) { \
379 : NS_WARNING("No outer window available!"); \
380 : return err_rval; \
381 : } \
382 : return ((nsGlobalModalWindow *)outer)->method args; \
383 : } \
384 : PR_END_MACRO
385 :
386 : #define FORWARD_TO_INNER(method, args, err_rval) \
387 : PR_BEGIN_MACRO \
388 : if (IsOuterWindow()) { \
389 : if (!mInnerWindow) { \
390 : NS_WARNING("No inner window available!"); \
391 : return err_rval; \
392 : } \
393 : return GetCurrentInnerWindowInternal()->method args; \
394 : } \
395 : PR_END_MACRO
396 :
397 : #define FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
398 : PR_BEGIN_MACRO \
399 : if (IsOuterWindow()) { \
400 : if (!mInnerWindow) { \
401 : NS_WARNING("No inner window available!"); \
402 : return err_rval; \
403 : } \
404 : return ((nsGlobalModalWindow*)GetCurrentInnerWindowInternal())->method args; \
405 : } \
406 : PR_END_MACRO
407 :
408 : #define FORWARD_TO_INNER_VOID(method, args) \
409 : PR_BEGIN_MACRO \
410 : if (IsOuterWindow()) { \
411 : if (!mInnerWindow) { \
412 : NS_WARNING("No inner window available!"); \
413 : return; \
414 : } \
415 : GetCurrentInnerWindowInternal()->method args; \
416 : return; \
417 : } \
418 : PR_END_MACRO
419 :
420 : // Same as FORWARD_TO_INNER, but this will create a fresh inner if an
421 : // inner doesn't already exists.
422 : #define FORWARD_TO_INNER_CREATE(method, args, err_rval) \
423 : PR_BEGIN_MACRO \
424 : if (IsOuterWindow()) { \
425 : if (!mInnerWindow) { \
426 : if (mIsClosed) { \
427 : return err_rval; \
428 : } \
429 : nsCOMPtr<nsIDOMDocument> doc; \
430 : nsresult fwdic_nr = GetDocument(getter_AddRefs(doc)); \
431 : NS_ENSURE_SUCCESS(fwdic_nr, err_rval); \
432 : if (!mInnerWindow) { \
433 : return err_rval; \
434 : } \
435 : } \
436 : return GetCurrentInnerWindowInternal()->method args; \
437 : } \
438 : PR_END_MACRO
439 :
440 : // CIDs
441 : static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
442 :
443 : static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
444 : #ifndef MOZ_DISABLE_DOMCRYPTO
445 : static const char kCryptoContractID[] = NS_CRYPTO_CONTRACTID;
446 : static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID;
447 : #endif
448 : static const char sPopStatePrefStr[] = "browser.history.allowPopState";
449 :
450 : class nsDummyJavaPluginOwner : public nsIPluginInstanceOwner
451 0 : {
452 : public:
453 0 : nsDummyJavaPluginOwner(nsIDocument *aDocument)
454 0 : : mDocument(aDocument)
455 : {
456 0 : }
457 :
458 : void Destroy();
459 :
460 0 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
461 : NS_DECL_NSIPLUGININSTANCEOWNER
462 :
463 : NS_IMETHOD GetURL(const char *aURL, const char *aTarget,
464 : nsIInputStream *aPostStream,
465 : void *aHeadersData, PRUint32 aHeadersDataLen);
466 : NS_IMETHOD ShowStatus(const PRUnichar *aStatusMsg);
467 : NPError ShowNativeContextMenu(NPMenu* menu, void* event);
468 : NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
469 : double *destX, double *destY, NPCoordinateSpace destSpace);
470 : void SendIdleEvent();
471 :
472 0 : NPError InitAsyncSurface(NPSize *size, NPImageFormat format,
473 : void *initData, NPAsyncSurface *surface)
474 0 : { return NPERR_GENERIC_ERROR; }
475 :
476 0 : NPError FinalizeAsyncSurface(NPAsyncSurface *surface) { return NPERR_GENERIC_ERROR; }
477 0 : void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed) { return; }
478 :
479 1464 : NS_DECL_CYCLE_COLLECTION_CLASS(nsDummyJavaPluginOwner)
480 :
481 : private:
482 : nsRefPtr<nsNPAPIPluginInstance> mInstance;
483 : nsCOMPtr<nsIDocument> mDocument;
484 : };
485 :
486 1464 : NS_IMPL_CYCLE_COLLECTION_2(nsDummyJavaPluginOwner, mDocument, mInstance)
487 :
488 : // QueryInterface implementation for nsDummyJavaPluginOwner
489 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDummyJavaPluginOwner)
490 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
491 0 : NS_INTERFACE_MAP_ENTRY(nsIPluginInstanceOwner)
492 0 : NS_INTERFACE_MAP_END
493 :
494 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDummyJavaPluginOwner)
495 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDummyJavaPluginOwner)
496 :
497 :
498 : void
499 0 : nsDummyJavaPluginOwner::Destroy()
500 : {
501 : // If we have a plugin instance, stop it and destroy it now.
502 0 : if (mInstance) {
503 0 : mInstance->Stop();
504 0 : mInstance->InvalidateOwner();
505 0 : mInstance = nsnull;
506 : }
507 :
508 0 : mDocument = nsnull;
509 0 : }
510 :
511 : NS_IMETHODIMP
512 0 : nsDummyJavaPluginOwner::SetInstance(nsNPAPIPluginInstance *aInstance)
513 : {
514 : // If we're going to null out mInstance after use, be sure to call
515 : // mInstance->InvalidateOwner() here, since it now won't be called
516 : // from nsDummyJavaPluginOwner::Destroy().
517 0 : if (mInstance && !aInstance)
518 0 : mInstance->InvalidateOwner();
519 :
520 0 : mInstance = aInstance;
521 :
522 0 : return NS_OK;
523 : }
524 :
525 : NS_IMETHODIMP
526 0 : nsDummyJavaPluginOwner::GetInstance(nsNPAPIPluginInstance **aInstance)
527 : {
528 0 : *aInstance = mInstance;
529 0 : NS_IF_ADDREF(*aInstance);
530 :
531 0 : return NS_OK;
532 : }
533 :
534 : NS_IMETHODIMP
535 0 : nsDummyJavaPluginOwner::GetWindow(NPWindow *&aWindow)
536 : {
537 0 : aWindow = nsnull;
538 :
539 0 : return NS_OK;
540 : }
541 :
542 : NS_IMETHODIMP
543 0 : nsDummyJavaPluginOwner::CallSetWindow()
544 : {
545 0 : return NS_ERROR_NOT_IMPLEMENTED;
546 : }
547 :
548 : NS_IMETHODIMP
549 0 : nsDummyJavaPluginOwner::GetMode(PRInt32 *aMode)
550 : {
551 : // This is wrong, but there's no better alternative.
552 0 : *aMode = NP_EMBED;
553 :
554 0 : return NS_ERROR_NOT_IMPLEMENTED;
555 : }
556 :
557 : NS_IMETHODIMP
558 0 : nsDummyJavaPluginOwner::CreateWidget(void)
559 : {
560 0 : return NS_ERROR_NOT_IMPLEMENTED;
561 : }
562 :
563 : NS_IMETHODIMP
564 0 : nsDummyJavaPluginOwner::GetURL(const char *aURL, const char *aTarget,
565 : nsIInputStream *aPostStream,
566 : void *aHeadersData, PRUint32 aHeadersDataLen)
567 : {
568 0 : return NS_ERROR_NOT_IMPLEMENTED;
569 : }
570 :
571 : NS_IMETHODIMP
572 0 : nsDummyJavaPluginOwner::ShowStatus(const char *aStatusMsg)
573 : {
574 0 : return NS_ERROR_NOT_IMPLEMENTED;
575 : }
576 :
577 : NS_IMETHODIMP
578 0 : nsDummyJavaPluginOwner::ShowStatus(const PRUnichar *aStatusMsg)
579 : {
580 0 : return NS_ERROR_NOT_IMPLEMENTED;
581 : }
582 :
583 : NPError
584 0 : nsDummyJavaPluginOwner::ShowNativeContextMenu(NPMenu* menu, void* event)
585 : {
586 0 : return NPERR_GENERIC_ERROR;
587 : }
588 :
589 : NPBool
590 0 : nsDummyJavaPluginOwner::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
591 : double *destX, double *destY, NPCoordinateSpace destSpace)
592 : {
593 0 : return false;
594 : }
595 :
596 : NS_IMETHODIMP
597 0 : nsDummyJavaPluginOwner::GetDocument(nsIDocument **aDocument)
598 : {
599 0 : NS_IF_ADDREF(*aDocument = mDocument);
600 :
601 0 : return NS_OK;
602 : }
603 :
604 : NS_IMETHODIMP
605 0 : nsDummyJavaPluginOwner::InvalidateRect(NPRect *invalidRect)
606 : {
607 0 : return NS_ERROR_NOT_IMPLEMENTED;
608 : }
609 :
610 : NS_IMETHODIMP
611 0 : nsDummyJavaPluginOwner::InvalidateRegion(NPRegion invalidRegion)
612 : {
613 0 : return NS_ERROR_NOT_IMPLEMENTED;
614 : }
615 :
616 : NS_IMETHODIMP
617 0 : nsDummyJavaPluginOwner::RedrawPlugin()
618 : {
619 0 : return NS_ERROR_NOT_IMPLEMENTED;
620 : }
621 :
622 : NS_IMETHODIMP
623 0 : nsDummyJavaPluginOwner::GetNetscapeWindow(void *value)
624 : {
625 0 : return NS_ERROR_NOT_IMPLEMENTED;
626 : }
627 :
628 : NS_IMETHODIMP
629 0 : nsDummyJavaPluginOwner::SetEventModel(PRInt32 eventModel)
630 : {
631 0 : return NS_ERROR_NOT_IMPLEMENTED;
632 : }
633 :
634 : void
635 0 : nsDummyJavaPluginOwner::SendIdleEvent()
636 : {
637 0 : }
638 :
639 : /**
640 : * An object implementing the window.URL property.
641 : */
642 : class nsDOMMozURLProperty : public nsIDOMMozURLProperty
643 : {
644 : public:
645 0 : nsDOMMozURLProperty(nsGlobalWindow* aWindow)
646 0 : : mWindow(aWindow)
647 : {
648 0 : }
649 :
650 : NS_DECL_ISUPPORTS
651 : NS_DECL_NSIDOMMOZURLPROPERTY
652 :
653 0 : void ClearWindowReference() {
654 0 : mWindow = nsnull;
655 0 : }
656 : private:
657 : nsGlobalWindow* mWindow;
658 : };
659 :
660 : DOMCI_DATA(MozURLProperty, nsDOMMozURLProperty)
661 0 : NS_IMPL_ADDREF(nsDOMMozURLProperty)
662 0 : NS_IMPL_RELEASE(nsDOMMozURLProperty)
663 0 : NS_INTERFACE_MAP_BEGIN(nsDOMMozURLProperty)
664 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMMozURLProperty)
665 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozURLProperty)
666 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozURLProperty)
667 0 : NS_INTERFACE_MAP_END
668 :
669 : NS_IMETHODIMP
670 0 : nsDOMMozURLProperty::CreateObjectURL(nsIDOMBlob* aBlob, nsAString& aURL)
671 : {
672 0 : NS_PRECONDITION(!mWindow || mWindow->IsInnerWindow(),
673 : "Should be inner window");
674 :
675 0 : NS_ENSURE_STATE(mWindow && mWindow->mDoc);
676 0 : NS_ENSURE_ARG_POINTER(aBlob);
677 :
678 0 : nsIDocument* doc = mWindow->mDoc;
679 :
680 0 : nsresult rv = aBlob->GetInternalUrl(doc->NodePrincipal(), aURL);
681 0 : NS_ENSURE_SUCCESS(rv, rv);
682 :
683 0 : doc->RegisterFileDataUri(NS_LossyConvertUTF16toASCII(aURL));
684 :
685 0 : return NS_OK;
686 : }
687 :
688 : NS_IMETHODIMP
689 0 : nsDOMMozURLProperty::RevokeObjectURL(const nsAString& aURL)
690 : {
691 0 : NS_PRECONDITION(!mWindow || mWindow->IsInnerWindow(),
692 : "Should be inner window");
693 :
694 0 : NS_ENSURE_STATE(mWindow);
695 :
696 0 : NS_LossyConvertUTF16toASCII asciiurl(aURL);
697 :
698 0 : nsIPrincipal* winPrincipal = mWindow->GetPrincipal();
699 0 : if (!winPrincipal) {
700 0 : return NS_OK;
701 : }
702 :
703 : nsIPrincipal* principal =
704 0 : nsBlobProtocolHandler::GetFileDataEntryPrincipal(asciiurl);
705 : bool subsumes;
706 0 : if (principal && winPrincipal &&
707 0 : NS_SUCCEEDED(winPrincipal->Subsumes(principal, &subsumes)) &&
708 : subsumes) {
709 0 : if (mWindow->mDoc) {
710 0 : mWindow->mDoc->UnregisterFileDataUri(asciiurl);
711 : }
712 0 : nsBlobProtocolHandler::RemoveFileDataEntry(asciiurl);
713 : }
714 :
715 0 : return NS_OK;
716 : }
717 :
718 : /**
719 : * An indirect observer object that means we don't have to implement nsIObserver
720 : * on nsGlobalWindow, where any script could see it.
721 : */
722 : class nsGlobalWindowObserver : public nsIObserver {
723 : public:
724 0 : nsGlobalWindowObserver(nsGlobalWindow* aWindow) : mWindow(aWindow) {}
725 : NS_DECL_ISUPPORTS
726 0 : NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aData)
727 : {
728 0 : if (!mWindow)
729 0 : return NS_OK;
730 0 : return mWindow->Observe(aSubject, aTopic, aData);
731 : }
732 0 : void Forget() { mWindow = nsnull; }
733 : private:
734 : nsGlobalWindow* mWindow;
735 : };
736 :
737 0 : NS_IMPL_ISUPPORTS1(nsGlobalWindowObserver, nsIObserver)
738 :
739 0 : nsTimeout::nsTimeout()
740 : {
741 : #ifdef DEBUG_jst
742 : {
743 : extern int gTimeoutCnt;
744 :
745 : ++gTimeoutCnt;
746 : }
747 : #endif
748 :
749 0 : memset(this, 0, sizeof(*this));
750 :
751 0 : MOZ_COUNT_CTOR(nsTimeout);
752 0 : }
753 :
754 0 : nsTimeout::~nsTimeout()
755 : {
756 : #ifdef DEBUG_jst
757 : {
758 : extern int gTimeoutCnt;
759 :
760 : --gTimeoutCnt;
761 : }
762 : #endif
763 :
764 0 : MOZ_COUNT_DTOR(nsTimeout);
765 0 : }
766 :
767 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsTimeout)
768 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NATIVE_0(nsTimeout)
769 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsTimeout)
770 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mWindow,
771 : nsIScriptGlobalObject)
772 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrincipal)
773 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptHandler)
774 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
775 0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout, AddRef)
776 0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTimeout, Release)
777 :
778 0 : nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
779 : : mFrameElement(nsnull), mDocShell(nsnull), mModalStateDepth(0),
780 : mRunningTimeout(nsnull), mMutationBits(0), mIsDocumentLoaded(false),
781 : mIsHandlingResizeEvent(false), mIsInnerWindow(aOuterWindow != nsnull),
782 : mMayHavePaintEventListener(false), mMayHaveTouchEventListener(false),
783 : mMayHaveMouseEnterLeaveEventListener(false),
784 : mIsModalContentWindow(false),
785 : mIsActive(false), mIsBackground(false),
786 : mInnerWindow(nsnull), mOuterWindow(aOuterWindow),
787 : // Make sure no actual window ends up with mWindowID == 0
788 0 : mWindowID(++gNextWindowID), mHasNotifiedGlobalCreated(false)
789 0 : {}
790 :
791 0 : nsPIDOMWindow::~nsPIDOMWindow() {}
792 :
793 : //*****************************************************************************
794 : // nsOuterWindowProxy: Outer Window Proxy
795 : //*****************************************************************************
796 :
797 : JSString *
798 0 : nsOuterWindowProxy::obj_toString(JSContext *cx, JSObject *proxy)
799 : {
800 0 : JS_ASSERT(js::IsProxy(proxy));
801 :
802 0 : return JS_NewStringCopyZ(cx, "[object Window]");
803 : }
804 :
805 : void
806 0 : nsOuterWindowProxy::finalize(JSContext *cx, JSObject *proxy)
807 : {
808 : nsISupports *global =
809 0 : static_cast<nsISupports*>(js::GetProxyExtra(proxy, 0).toPrivate());
810 0 : if (global) {
811 : nsWrapperCache *cache;
812 0 : CallQueryInterface(global, &cache);
813 0 : cache->ClearWrapperIfProxy();
814 : }
815 0 : }
816 :
817 : nsOuterWindowProxy
818 1464 : nsOuterWindowProxy::singleton;
819 :
820 : JSObject *
821 0 : NS_NewOuterWindowProxy(JSContext *cx, JSObject *parent)
822 : {
823 0 : JSAutoEnterCompartment ac;
824 0 : if (!ac.enter(cx, parent)) {
825 0 : return nsnull;
826 : }
827 :
828 : JSObject *obj = js::Wrapper::New(cx, parent, js::GetObjectProto(parent), parent,
829 0 : &nsOuterWindowProxy::singleton);
830 0 : NS_ASSERTION(js::GetObjectClass(obj)->ext.innerObject, "bad class");
831 0 : return obj;
832 : }
833 :
834 : //*****************************************************************************
835 : //*** nsGlobalWindow: Object Management
836 : //*****************************************************************************
837 :
838 0 : nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
839 : : nsPIDOMWindow(aOuterWindow),
840 : mIsFrozen(false),
841 : mDidInitJavaProperties(false),
842 : mFullScreen(false),
843 : mIsClosed(false),
844 : mInClose(false),
845 : mHavePendingClose(false),
846 : mHadOriginalOpener(false),
847 : mIsPopupSpam(false),
848 : mBlockScriptedClosingFlag(false),
849 : mFireOfflineStatusChangeEventOnThaw(false),
850 : mCreatingInnerWindow(false),
851 : mIsChrome(false),
852 : mCleanMessageManager(false),
853 : mNeedsFocus(true),
854 : mHasFocus(false),
855 : #if defined(XP_MACOSX)
856 : mShowAccelerators(false),
857 : mShowFocusRings(false),
858 : #else
859 : mShowAccelerators(true),
860 : mShowFocusRings(true),
861 : #endif
862 : mShowFocusRingForContent(false),
863 : mFocusByKeyOccurred(false),
864 : mHasDeviceMotion(false),
865 : mNotifiedIDDestroyed(false),
866 : mTimeoutInsertionPoint(nsnull),
867 : mTimeoutPublicIdCounter(1),
868 : mTimeoutFiringDepth(0),
869 : mJSObject(nsnull),
870 : mPendingStorageEventsObsolete(nsnull),
871 : mTimeoutsSuspendDepth(0),
872 : mFocusMethod(0),
873 : mSerial(0),
874 : #ifdef DEBUG
875 : mSetOpenerWindowCalled(false),
876 : #endif
877 : mCleanedUp(false),
878 : mCallCleanUpAfterModalDialogCloses(false),
879 : mDialogAbuseCount(0),
880 0 : mDialogDisabled(false)
881 : {
882 0 : nsLayoutStatics::AddRef();
883 :
884 : // Initialize the PRCList (this).
885 0 : PR_INIT_CLIST(this);
886 :
887 : // Initialize timeout storage
888 0 : PR_INIT_CLIST(&mTimeouts);
889 :
890 0 : if (aOuterWindow) {
891 : // |this| is an inner window, add this inner window to the outer
892 : // window list of inners.
893 0 : PR_INSERT_AFTER(this, aOuterWindow);
894 :
895 0 : mObserver = new nsGlobalWindowObserver(this);
896 0 : if (mObserver) {
897 0 : NS_ADDREF(mObserver);
898 0 : nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
899 0 : if (os) {
900 : // Watch for online/offline status changes so we can fire events. Use
901 : // a strong reference.
902 0 : os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
903 0 : false);
904 :
905 : // Watch for dom-storage-changed so we can fire storage
906 : // events. Use a strong reference.
907 0 : os->AddObserver(mObserver, "dom-storage2-changed", false);
908 0 : os->AddObserver(mObserver, "dom-storage-changed", false);
909 : }
910 : }
911 : } else {
912 : // |this| is an outer window. Outer windows start out frozen and
913 : // remain frozen until they get an inner window, so freeze this
914 : // outer window here.
915 0 : Freeze();
916 :
917 0 : mObserver = nsnull;
918 0 : SetIsProxy();
919 : }
920 :
921 : // We could have failed the first time through trying
922 : // to create the entropy collector, so we should
923 : // try to get one until we succeed.
924 :
925 0 : gRefCnt++;
926 :
927 0 : if (gRefCnt == 1) {
928 : #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
929 : Preferences::AddBoolVarCache(&gDOMWindowDumpEnabled,
930 : "browser.dom.window.dump.enabled");
931 : #endif
932 : Preferences::AddIntVarCache(&gMinTimeoutValue,
933 : "dom.min_timeout_value",
934 0 : DEFAULT_MIN_TIMEOUT_VALUE);
935 : Preferences::AddIntVarCache(&gMinBackgroundTimeoutValue,
936 : "dom.min_background_timeout_value",
937 0 : DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE);
938 : }
939 :
940 0 : if (gDumpFile == nsnull) {
941 : const nsAdoptingCString& fname =
942 0 : Preferences::GetCString("browser.dom.window.dump.file");
943 0 : if (!fname.IsEmpty()) {
944 : // if this fails to open, Dump() knows to just go to stdout
945 : // on null.
946 0 : gDumpFile = fopen(fname, "wb+");
947 : } else {
948 0 : gDumpFile = stdout;
949 : }
950 : }
951 :
952 0 : mSerial = ++gSerialCounter;
953 :
954 : #ifdef DEBUG
955 0 : if (!PR_GetEnv("MOZ_QUIET")) {
956 : printf("++DOMWINDOW == %d (%p) [serial = %d] [outer = %p]\n", gRefCnt,
957 : static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
958 0 : gSerialCounter, static_cast<void*>(aOuterWindow));
959 : }
960 : #endif
961 :
962 : #ifdef PR_LOGGING
963 0 : if (gDOMLeakPRLog)
964 0 : PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
965 : ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
966 : #endif
967 :
968 0 : NS_ASSERTION(sWindowsById, "Windows hash table must be created!");
969 0 : NS_ASSERTION(!sWindowsById->Get(mWindowID),
970 : "This window shouldn't be in the hash table yet!");
971 0 : sWindowsById->Put(mWindowID, this);
972 :
973 0 : mEventTargetObjects.Init();
974 0 : }
975 :
976 : /* static */
977 : void
978 1404 : nsGlobalWindow::Init()
979 : {
980 1404 : CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
981 1404 : NS_ASSERTION(gEntropyCollector,
982 : "gEntropyCollector should have been initialized!");
983 :
984 : #ifdef PR_LOGGING
985 1404 : gDOMLeakPRLog = PR_NewLogModule("DOMLeak");
986 1404 : NS_ASSERTION(gDOMLeakPRLog, "gDOMLeakPRLog should have been initialized!");
987 : #endif
988 :
989 1404 : sWindowsById = new WindowByIdTable();
990 : // There are two reasons to have Init() failing: if we were not able to
991 : // alloc the memory or if the size we want to init is too high. None of them
992 : // should happen.
993 : #ifdef DEBUG
994 1404 : NS_ASSERTION(sWindowsById->Init(), "Init() should not fail!");
995 : #else
996 : sWindowsById->Init();
997 : #endif
998 1404 : }
999 :
1000 : static PLDHashOperator
1001 0 : DisconnectEventTargetObjects(nsPtrHashKey<nsDOMEventTargetHelper>* aKey,
1002 : void* aClosure)
1003 : {
1004 0 : nsRefPtr<nsDOMEventTargetHelper> target = aKey->GetKey();
1005 0 : target->DisconnectFromOwner();
1006 0 : return PL_DHASH_NEXT;
1007 : }
1008 :
1009 0 : nsGlobalWindow::~nsGlobalWindow()
1010 : {
1011 0 : mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nsnull);
1012 0 : mEventTargetObjects.Clear();
1013 :
1014 : // We have to check if sWindowsById isn't null because ::Shutdown might have
1015 : // been called.
1016 0 : if (sWindowsById) {
1017 0 : NS_ASSERTION(sWindowsById->Get(mWindowID),
1018 : "This window should be in the hash table");
1019 0 : sWindowsById->Remove(mWindowID);
1020 : }
1021 :
1022 0 : --gRefCnt;
1023 :
1024 : #ifdef DEBUG
1025 0 : if (!PR_GetEnv("MOZ_QUIET")) {
1026 0 : nsCAutoString url;
1027 0 : if (mLastOpenedURI) {
1028 0 : mLastOpenedURI->GetSpec(url);
1029 : }
1030 :
1031 : printf("--DOMWINDOW == %d (%p) [serial = %d] [outer = %p] [url = %s]\n",
1032 : gRefCnt, static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
1033 0 : mSerial, static_cast<void*>(mOuterWindow.get()), url.get());
1034 : }
1035 : #endif
1036 :
1037 : #ifdef PR_LOGGING
1038 0 : if (gDOMLeakPRLog)
1039 0 : PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
1040 : ("DOMWINDOW %p destroyed", this));
1041 : #endif
1042 :
1043 0 : if (IsOuterWindow()) {
1044 0 : JSObject *proxy = GetWrapperPreserveColor();
1045 0 : if (proxy) {
1046 0 : js::SetProxyExtra(proxy, 0, js::PrivateValue(NULL));
1047 : }
1048 :
1049 : // An outer window is destroyed with inner windows still possibly
1050 : // alive, iterate through the inner windows and null out their
1051 : // back pointer to this outer, and pull them out of the list of
1052 : // inner windows.
1053 :
1054 : nsGlobalWindow *w;
1055 0 : while ((w = (nsGlobalWindow *)PR_LIST_HEAD(this)) != this) {
1056 0 : PR_REMOVE_AND_INIT_LINK(w);
1057 : }
1058 : } else {
1059 : Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
1060 0 : mMutationBits ? 1 : 0);
1061 :
1062 0 : if (mListenerManager) {
1063 0 : mListenerManager->Disconnect();
1064 0 : mListenerManager = nsnull;
1065 : }
1066 :
1067 : // An inner window is destroyed, pull it out of the outer window's
1068 : // list if inner windows.
1069 :
1070 0 : PR_REMOVE_LINK(this);
1071 :
1072 : // If our outer window's inner window is this window, null out the
1073 : // outer window's reference to this window that's being deleted.
1074 0 : nsGlobalWindow *outer = GetOuterWindowInternal();
1075 0 : if (outer && outer->mInnerWindow == this) {
1076 0 : outer->mInnerWindow = nsnull;
1077 : }
1078 : }
1079 :
1080 0 : mDocument = nsnull; // Forces Release
1081 0 : mDoc = nsnull;
1082 :
1083 0 : NS_ASSERTION(!mArguments, "mArguments wasn't cleaned up properly!");
1084 :
1085 0 : CleanUp(true);
1086 :
1087 : #ifdef DEBUG
1088 0 : nsCycleCollector_DEBUG_wasFreed(static_cast<nsIScriptGlobalObject*>(this));
1089 : #endif
1090 :
1091 0 : if (mURLProperty) {
1092 0 : mURLProperty->ClearWindowReference();
1093 : }
1094 :
1095 0 : DisableDeviceMotionUpdates();
1096 0 : mHasDeviceMotion = false;
1097 :
1098 0 : nsLayoutStatics::Release();
1099 0 : }
1100 :
1101 : void
1102 0 : nsGlobalWindow::AddEventTargetObject(nsDOMEventTargetHelper* aObject)
1103 : {
1104 0 : mEventTargetObjects.PutEntry(aObject);
1105 0 : }
1106 :
1107 : void
1108 0 : nsGlobalWindow::RemoveEventTargetObject(nsDOMEventTargetHelper* aObject)
1109 : {
1110 0 : mEventTargetObjects.RemoveEntry(aObject);
1111 0 : }
1112 :
1113 : // static
1114 : void
1115 1453 : nsGlobalWindow::ShutDown()
1116 : {
1117 1453 : NS_IF_RELEASE(sGlobalStorageList);
1118 :
1119 1453 : if (gDumpFile && gDumpFile != stdout) {
1120 0 : fclose(gDumpFile);
1121 : }
1122 1453 : gDumpFile = nsnull;
1123 :
1124 1453 : NS_IF_RELEASE(gEntropyCollector);
1125 :
1126 1453 : delete sWindowsById;
1127 1453 : sWindowsById = nsnull;
1128 1453 : }
1129 :
1130 : // static
1131 : void
1132 0 : nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow)
1133 : {
1134 0 : if (aWindow->mCachedXBLPrototypeHandlers.IsInitialized() &&
1135 0 : aWindow->mCachedXBLPrototypeHandlers.Count() > 0) {
1136 0 : aWindow->mCachedXBLPrototypeHandlers.Clear();
1137 :
1138 : nsISupports* supports;
1139 : aWindow->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
1140 0 : reinterpret_cast<void**>(&supports));
1141 0 : NS_ASSERTION(supports, "Failed to QI to nsCycleCollectionISupports?!");
1142 :
1143 0 : nsContentUtils::DropJSObjects(supports);
1144 : }
1145 0 : }
1146 :
1147 : void
1148 0 : nsGlobalWindow::MaybeForgiveSpamCount()
1149 : {
1150 0 : if (IsOuterWindow() &&
1151 0 : IsPopupSpamWindow())
1152 : {
1153 0 : SetPopupSpamWindow(false);
1154 0 : --gOpenPopupSpamCount;
1155 0 : NS_ASSERTION(gOpenPopupSpamCount >= 0,
1156 : "Unbalanced decrement of gOpenPopupSpamCount");
1157 : }
1158 0 : }
1159 :
1160 : void
1161 0 : nsGlobalWindow::CleanUp(bool aIgnoreModalDialog)
1162 : {
1163 0 : if (IsOuterWindow() && !aIgnoreModalDialog) {
1164 0 : nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
1165 0 : nsCOMPtr<nsIDOMModalContentWindow> dlg(do_QueryObject(inner));
1166 0 : if (dlg) {
1167 : // The window we're trying to clean up is the outer window of a
1168 : // modal dialog. Defer cleanup until the window closes, and let
1169 : // ShowModalDialog take care of calling CleanUp.
1170 0 : mCallCleanUpAfterModalDialogCloses = true;
1171 : return;
1172 : }
1173 : }
1174 :
1175 : // Guarantee idempotence.
1176 0 : if (mCleanedUp)
1177 0 : return;
1178 0 : mCleanedUp = true;
1179 :
1180 0 : mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nsnull);
1181 0 : mEventTargetObjects.Clear();
1182 :
1183 0 : if (mObserver) {
1184 0 : nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1185 0 : if (os) {
1186 0 : os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
1187 0 : os->RemoveObserver(mObserver, "dom-storage2-changed");
1188 0 : os->RemoveObserver(mObserver, "dom-storage-changed");
1189 : }
1190 :
1191 : // Drop its reference to this dying window, in case for some bogus reason
1192 : // the object stays around.
1193 0 : mObserver->Forget();
1194 0 : NS_RELEASE(mObserver);
1195 : }
1196 :
1197 0 : mNavigator = nsnull;
1198 0 : mScreen = nsnull;
1199 0 : mMenubar = nsnull;
1200 0 : mToolbar = nsnull;
1201 0 : mLocationbar = nsnull;
1202 0 : mPersonalbar = nsnull;
1203 0 : mStatusbar = nsnull;
1204 0 : mScrollbars = nsnull;
1205 0 : mLocation = nsnull;
1206 0 : mHistory = nsnull;
1207 0 : mFrames = nsnull;
1208 0 : mApplicationCache = nsnull;
1209 0 : mIndexedDB = nsnull;
1210 0 : mPendingStorageEventsObsolete = nsnull;
1211 :
1212 0 : mPerformance = nsnull;
1213 :
1214 0 : ClearControllers();
1215 :
1216 0 : mOpener = nsnull; // Forces Release
1217 0 : if (mContext) {
1218 : #ifdef DEBUG
1219 0 : nsCycleCollector_DEBUG_shouldBeFreed(mContext);
1220 : #endif
1221 0 : mContext = nsnull; // Forces Release
1222 : }
1223 0 : mChromeEventHandler = nsnull; // Forces Release
1224 0 : mParentTarget = nsnull;
1225 :
1226 0 : nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
1227 :
1228 0 : if (inner) {
1229 0 : inner->CleanUp(aIgnoreModalDialog);
1230 : }
1231 :
1232 0 : if (mCleanMessageManager) {
1233 0 : NS_ABORT_IF_FALSE(mIsChrome, "only chrome should have msg manager cleaned");
1234 0 : nsGlobalChromeWindow *asChrome = static_cast<nsGlobalChromeWindow*>(this);
1235 0 : if (asChrome->mMessageManager) {
1236 : static_cast<nsFrameMessageManager*>(
1237 0 : asChrome->mMessageManager.get())->Disconnect();
1238 : }
1239 : }
1240 :
1241 0 : mInnerWindowHolder = nsnull;
1242 0 : mArguments = nsnull;
1243 0 : mArgumentsLast = nsnull;
1244 0 : mArgumentsOrigin = nsnull;
1245 :
1246 0 : CleanupCachedXBLHandlers(this);
1247 :
1248 : #ifdef DEBUG
1249 0 : nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
1250 : #endif
1251 : }
1252 :
1253 : void
1254 0 : nsGlobalWindow::ClearControllers()
1255 : {
1256 0 : if (mControllers) {
1257 : PRUint32 count;
1258 0 : mControllers->GetControllerCount(&count);
1259 :
1260 0 : while (count--) {
1261 0 : nsCOMPtr<nsIController> controller;
1262 0 : mControllers->GetControllerAt(count, getter_AddRefs(controller));
1263 :
1264 0 : nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
1265 0 : if (context)
1266 0 : context->SetCommandContext(nsnull);
1267 : }
1268 :
1269 0 : mControllers = nsnull;
1270 : }
1271 0 : }
1272 :
1273 : void
1274 0 : nsGlobalWindow::FreeInnerObjects()
1275 : {
1276 0 : NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
1277 :
1278 : // Make sure that this is called before we null out the document and
1279 : // other members that the window destroyed observers could
1280 : // re-create.
1281 0 : NotifyDOMWindowDestroyed(this);
1282 :
1283 : // Kill all of the workers for this window.
1284 0 : nsIScriptContext *scx = GetContextInternal();
1285 0 : JSContext *cx = scx ? scx->GetNativeContext() : nsnull;
1286 0 : mozilla::dom::workers::CancelWorkersForWindow(cx, this);
1287 :
1288 : // Close all IndexedDB databases for this window.
1289 : indexedDB::IndexedDatabaseManager* idbManager =
1290 0 : indexedDB::IndexedDatabaseManager::Get();
1291 0 : if (idbManager) {
1292 0 : idbManager->AbortCloseDatabasesForWindow(this);
1293 : }
1294 :
1295 0 : ClearAllTimeouts();
1296 :
1297 0 : mChromeEventHandler = nsnull;
1298 :
1299 0 : if (mListenerManager) {
1300 0 : mListenerManager->Disconnect();
1301 0 : mListenerManager = nsnull;
1302 : }
1303 :
1304 0 : mLocation = nsnull;
1305 0 : mHistory = nsnull;
1306 :
1307 0 : if (mNavigator) {
1308 0 : mNavigator->Invalidate();
1309 0 : mNavigator = nsnull;
1310 : }
1311 :
1312 0 : if (mDocument) {
1313 0 : NS_ASSERTION(mDoc, "Why is mDoc null?");
1314 :
1315 : // Remember the document's principal.
1316 0 : mDocumentPrincipal = mDoc->NodePrincipal();
1317 : }
1318 :
1319 : #ifdef DEBUG
1320 0 : if (mDocument)
1321 0 : nsCycleCollector_DEBUG_shouldBeFreed(nsCOMPtr<nsISupports>(do_QueryInterface(mDocument)));
1322 : #endif
1323 :
1324 : // Remove our reference to the document and the document principal.
1325 0 : mDocument = nsnull;
1326 0 : mDoc = nsnull;
1327 0 : mFocusedNode = nsnull;
1328 :
1329 0 : if (mApplicationCache) {
1330 0 : static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
1331 0 : mApplicationCache = nsnull;
1332 : }
1333 :
1334 0 : mIndexedDB = nsnull;
1335 :
1336 0 : NotifyWindowIDDestroyed("inner-window-destroyed");
1337 :
1338 0 : if (mDummyJavaPluginOwner) {
1339 : // Tear down the dummy java plugin.
1340 :
1341 : // XXXjst: On a general note, should windows with java stuff in
1342 : // them ever even make it into the fast-back cache?
1343 :
1344 0 : mDummyJavaPluginOwner->Destroy();
1345 0 : mDummyJavaPluginOwner = nsnull;
1346 0 : mDidInitJavaProperties = false;
1347 : }
1348 :
1349 0 : CleanupCachedXBLHandlers(this);
1350 :
1351 : #ifdef DEBUG
1352 0 : nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
1353 : #endif
1354 0 : }
1355 :
1356 : //*****************************************************************************
1357 : // nsGlobalWindow::nsISupports
1358 : //*****************************************************************************
1359 :
1360 : #define OUTER_WINDOW_ONLY \
1361 : if (IsOuterWindow()) {
1362 :
1363 : #define END_OUTER_WINDOW_ONLY \
1364 : foundInterface = 0; \
1365 : } else
1366 :
1367 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
1368 :
1369 : DOMCI_DATA(Window, nsGlobalWindow)
1370 :
1371 : // QueryInterface implementation for nsGlobalWindow
1372 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
1373 : // Make sure this matches the cast in nsGlobalWindow::FromWrapper()
1374 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptGlobalObject)
1375 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
1376 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMWindow_globalStorage)
1377 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMJSWindow)
1378 0 : if (aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) {
1379 0 : foundInterface = static_cast<nsIDOMWindowInternal*>(this);
1380 0 : if (!sWarnedAboutWindowInternal) {
1381 0 : sWarnedAboutWindowInternal = true;
1382 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
1383 : "Extensions", mDoc,
1384 : nsContentUtils::eDOM_PROPERTIES,
1385 0 : "nsIDOMWindowInternalWarning");
1386 : }
1387 : } else
1388 0 : NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
1389 0 : NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
1390 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
1391 0 : NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow)
1392 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMStorageIndexedDB)
1393 0 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
1394 0 : NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
1395 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMWindowPerformance)
1396 0 : NS_INTERFACE_MAP_ENTRY(nsITouchEventReceiver)
1397 0 : NS_INTERFACE_MAP_ENTRY(nsIInlineEventHandlers)
1398 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
1399 0 : OUTER_WINDOW_ONLY
1400 0 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1401 0 : END_OUTER_WINDOW_ONLY
1402 0 : NS_INTERFACE_MAP_END
1403 :
1404 :
1405 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow)
1406 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow)
1407 :
1408 : static PLDHashOperator
1409 0 : MarkXBLHandlers(const void* aKey, JSObject* aData, void* aClosure)
1410 : {
1411 0 : xpc_UnmarkGrayObject(aData);
1412 0 : return PL_DHASH_NEXT;
1413 : }
1414 :
1415 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
1416 0 : if (tmp->IsBlackForCC()) {
1417 0 : if (tmp->mCachedXBLPrototypeHandlers.IsInitialized()) {
1418 0 : tmp->mCachedXBLPrototypeHandlers.EnumerateRead(MarkXBLHandlers, nsnull);
1419 : }
1420 0 : return true;
1421 : }
1422 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
1423 :
1424 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindow)
1425 0 : return tmp->IsBlackForCC();
1426 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
1427 :
1428 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindow)
1429 0 : return tmp->IsBlackForCC();
1430 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
1431 :
1432 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGlobalWindow)
1433 0 : if (!cb.WantAllTraces() && tmp->IsBlackForCC()) {
1434 0 : return NS_SUCCESS_INTERRUPTED_TRAVERSE;
1435 : }
1436 :
1437 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
1438 :
1439 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mControllers)
1440 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArguments)
1441 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArgumentsLast)
1442 :
1443 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInnerWindowHolder)
1444 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOuterWindow)
1445 :
1446 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOpenerScriptPrincipal)
1447 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mListenerManager,
1448 : nsEventListenerManager)
1449 :
1450 0 : for (nsTimeout* timeout = tmp->FirstTimeout();
1451 0 : tmp->IsTimeout(timeout);
1452 : timeout = timeout->Next()) {
1453 0 : cb.NoteNativeChild(timeout, &NS_CYCLE_COLLECTION_NAME(nsTimeout));
1454 : }
1455 :
1456 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSessionStorage)
1457 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mApplicationCache)
1458 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocumentPrincipal)
1459 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDoc)
1460 :
1461 : // Traverse stuff from nsPIDOMWindow
1462 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChromeEventHandler)
1463 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParentTarget)
1464 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
1465 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFrameElement)
1466 :
1467 : // Traverse mDummyJavaPluginOwner
1468 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDummyJavaPluginOwner)
1469 :
1470 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFocusedNode)
1471 :
1472 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPendingStorageEvents)
1473 :
1474 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1475 :
1476 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
1477 0 : nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
1478 :
1479 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
1480 :
1481 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mControllers)
1482 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArguments)
1483 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArgumentsLast)
1484 :
1485 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInnerWindowHolder)
1486 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOuterWindow)
1487 :
1488 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOpenerScriptPrincipal)
1489 0 : if (tmp->mListenerManager) {
1490 0 : tmp->mListenerManager->Disconnect();
1491 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListenerManager)
1492 : }
1493 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSessionStorage)
1494 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mApplicationCache)
1495 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocumentPrincipal)
1496 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDoc)
1497 :
1498 : // Unlink stuff from nsPIDOMWindow
1499 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChromeEventHandler)
1500 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParentTarget)
1501 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
1502 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFrameElement)
1503 :
1504 : // Unlink mDummyJavaPluginOwner
1505 0 : if (tmp->mDummyJavaPluginOwner) {
1506 0 : tmp->mDummyJavaPluginOwner->Destroy();
1507 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDummyJavaPluginOwner)
1508 0 : tmp->mDidInitJavaProperties = false;
1509 : }
1510 :
1511 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFocusedNode)
1512 :
1513 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPendingStorageEvents)
1514 :
1515 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1516 :
1517 : struct TraceData
1518 : {
1519 0 : TraceData(TraceCallback& aCallback, void* aClosure) :
1520 0 : callback(aCallback), closure(aClosure) {}
1521 :
1522 : TraceCallback& callback;
1523 : void* closure;
1524 : };
1525 :
1526 : static PLDHashOperator
1527 0 : TraceXBLHandlers(const void* aKey, JSObject* aData, void* aClosure)
1528 : {
1529 0 : TraceData* data = static_cast<TraceData*>(aClosure);
1530 : data->callback(nsIProgrammingLanguage::JAVASCRIPT, aData,
1531 0 : "Cached XBL prototype handler", data->closure);
1532 0 : return PL_DHASH_NEXT;
1533 : }
1534 :
1535 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
1536 0 : if (tmp->mCachedXBLPrototypeHandlers.IsInitialized()) {
1537 0 : TraceData data(aCallback, aClosure);
1538 0 : tmp->mCachedXBLPrototypeHandlers.EnumerateRead(TraceXBLHandlers, &data);
1539 : }
1540 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
1541 :
1542 : bool
1543 0 : nsGlobalWindow::IsBlackForCC()
1544 : {
1545 : return
1546 : (mDoc &&
1547 0 : nsCCUncollectableMarker::InGeneration(mDoc->GetMarkedCCGeneration())) ||
1548 0 : (nsCCUncollectableMarker::sGeneration && IsBlack());
1549 : }
1550 :
1551 : void
1552 0 : nsGlobalWindow::UnmarkGrayTimers()
1553 : {
1554 0 : for (nsTimeout* timeout = FirstTimeout();
1555 0 : timeout && IsTimeout(timeout);
1556 : timeout = timeout->Next()) {
1557 0 : if (timeout->mScriptHandler) {
1558 0 : JSObject* o = timeout->mScriptHandler->GetScriptObject();
1559 0 : xpc_UnmarkGrayObject(o);
1560 : }
1561 : }
1562 0 : }
1563 :
1564 : //*****************************************************************************
1565 : // nsGlobalWindow::nsIScriptGlobalObject
1566 : //*****************************************************************************
1567 :
1568 : nsresult
1569 0 : nsGlobalWindow::SetScriptContext(PRUint32 lang_id, nsIScriptContext *aScriptContext)
1570 : {
1571 0 : NS_ASSERTION(lang_id == nsIProgrammingLanguage::JAVASCRIPT,
1572 : "We don't support this language ID");
1573 0 : NS_ASSERTION(IsOuterWindow(), "Uh, SetScriptContext() called on inner window!");
1574 :
1575 0 : NS_ASSERTION(!aScriptContext || !mContext, "Bad call to SetContext()!");
1576 :
1577 0 : if (aScriptContext) {
1578 : // should probably assert the context is clean???
1579 0 : aScriptContext->WillInitializeContext();
1580 :
1581 0 : nsresult rv = aScriptContext->InitContext();
1582 0 : NS_ENSURE_SUCCESS(rv, rv);
1583 :
1584 0 : if (IsFrame()) {
1585 : // This window is a [i]frame, don't bother GC'ing when the
1586 : // frame's context is destroyed since a GC will happen when the
1587 : // frameset or host document is destroyed anyway.
1588 :
1589 0 : aScriptContext->SetGCOnDestruction(false);
1590 : }
1591 : }
1592 :
1593 0 : mContext = aScriptContext;
1594 0 : return NS_OK;
1595 : }
1596 :
1597 : nsresult
1598 0 : nsGlobalWindow::EnsureScriptEnvironment(PRUint32 aLangID)
1599 : {
1600 0 : NS_ASSERTION(aLangID == nsIProgrammingLanguage::JAVASCRIPT,
1601 : "We don't support this language ID");
1602 0 : FORWARD_TO_OUTER(EnsureScriptEnvironment, (aLangID), NS_ERROR_NOT_INITIALIZED);
1603 :
1604 0 : if (mJSObject)
1605 0 : return NS_OK;
1606 :
1607 0 : NS_ASSERTION(!GetCurrentInnerWindowInternal(),
1608 : "mJSObject is null, but we have an inner window?");
1609 :
1610 0 : nsCOMPtr<nsIScriptRuntime> scriptRuntime;
1611 0 : nsresult rv = NS_GetScriptRuntimeByID(aLangID, getter_AddRefs(scriptRuntime));
1612 0 : NS_ENSURE_SUCCESS(rv, rv);
1613 :
1614 0 : nsCOMPtr<nsIScriptContext> context = scriptRuntime->CreateContext();
1615 0 : return SetScriptContext(aLangID, context);
1616 : }
1617 :
1618 : nsIScriptContext *
1619 0 : nsGlobalWindow::GetScriptContext(PRUint32 lang)
1620 : {
1621 0 : NS_ASSERTION(lang == nsIProgrammingLanguage::JAVASCRIPT,
1622 : "We don't support this language ID");
1623 :
1624 0 : FORWARD_TO_OUTER(GetScriptContext, (lang), nsnull);
1625 0 : return mContext;
1626 : }
1627 :
1628 : nsIScriptContext *
1629 0 : nsGlobalWindow::GetContext()
1630 : {
1631 0 : FORWARD_TO_OUTER(GetContext, (), nsnull);
1632 :
1633 : // check GetContext is indeed identical to GetScriptContext()
1634 0 : NS_ASSERTION(mContext == GetScriptContext(nsIProgrammingLanguage::JAVASCRIPT),
1635 : "GetContext confused?");
1636 0 : return mContext;
1637 : }
1638 :
1639 : JSObject *
1640 0 : nsGlobalWindow::GetGlobalJSObject()
1641 : {
1642 0 : return FastGetGlobalJSObject();
1643 : }
1644 :
1645 : bool
1646 0 : nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument)
1647 : {
1648 : // We reuse the inner window when:
1649 : // a. We are currently at our original document.
1650 : // b. At least one of the following conditions are true:
1651 : // -- We are not currently a content window (i.e., we're currently a chrome
1652 : // window).
1653 : // -- The new document is the same as the old document. This means that we're
1654 : // getting called from document.open().
1655 : // -- The new document has the same origin as what we have loaded right now.
1656 :
1657 0 : if (!mDoc || !aNewDocument) {
1658 0 : return false;
1659 : }
1660 :
1661 0 : if (!mDoc->IsInitialDocument()) {
1662 0 : return false;
1663 : }
1664 :
1665 0 : NS_ASSERTION(NS_IsAboutBlank(mDoc->GetDocumentURI()),
1666 : "How'd this happen?");
1667 :
1668 : // Great, we're the original document, check for one of the other
1669 : // conditions.
1670 0 : if (mDoc == aNewDocument) {
1671 0 : return true;
1672 : }
1673 :
1674 : bool equal;
1675 0 : if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),
1676 : &equal)) &&
1677 : equal) {
1678 : // The origin is the same.
1679 0 : return true;
1680 : }
1681 :
1682 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
1683 :
1684 0 : if (treeItem) {
1685 0 : PRInt32 itemType = nsIDocShellTreeItem::typeContent;
1686 0 : treeItem->GetItemType(&itemType);
1687 :
1688 : // If we're a chrome window, then we want to reuse the inner window.
1689 0 : return itemType == nsIDocShellTreeItem::typeChrome;
1690 : }
1691 :
1692 : // No treeItem: don't reuse the current inner window.
1693 0 : return false;
1694 : }
1695 :
1696 : void
1697 0 : nsGlobalWindow::SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal)
1698 : {
1699 0 : FORWARD_TO_OUTER_VOID(SetOpenerScriptPrincipal, (aPrincipal));
1700 :
1701 0 : if (mDoc) {
1702 0 : if (!mDoc->IsInitialDocument()) {
1703 : // We have a document already, and it's not the original one. Bail out.
1704 : // Do NOT set mOpenerScriptPrincipal in this case, just to be safe.
1705 0 : return;
1706 : }
1707 :
1708 : #ifdef DEBUG
1709 : // We better have an about:blank document loaded at this point. Otherwise,
1710 : // something is really weird.
1711 0 : nsCOMPtr<nsIURI> uri;
1712 0 : mDoc->NodePrincipal()->GetURI(getter_AddRefs(uri));
1713 0 : NS_ASSERTION(uri && NS_IsAboutBlank(uri) &&
1714 : NS_IsAboutBlank(mDoc->GetDocumentURI()),
1715 : "Unexpected original document");
1716 : #endif
1717 :
1718 0 : GetDocShell()->CreateAboutBlankContentViewer(aPrincipal);
1719 0 : mDoc->SetIsInitialDocument(true);
1720 :
1721 0 : nsCOMPtr<nsIPresShell> shell;
1722 0 : GetDocShell()->GetPresShell(getter_AddRefs(shell));
1723 :
1724 0 : if (shell && !shell->DidInitialReflow()) {
1725 : // Ensure that if someone plays with this document they will get
1726 : // layout happening.
1727 0 : nsRect r = shell->GetPresContext()->GetVisibleArea();
1728 0 : shell->InitialReflow(r.width, r.height);
1729 : }
1730 : }
1731 : }
1732 :
1733 : nsIPrincipal*
1734 0 : nsGlobalWindow::GetOpenerScriptPrincipal()
1735 : {
1736 0 : FORWARD_TO_OUTER(GetOpenerScriptPrincipal, (), nsnull);
1737 :
1738 0 : return mOpenerScriptPrincipal;
1739 : }
1740 :
1741 : PopupControlState
1742 8230 : PushPopupControlState(PopupControlState aState, bool aForce)
1743 : {
1744 8230 : PopupControlState oldState = gPopupControlState;
1745 :
1746 8230 : if (aState < gPopupControlState || aForce) {
1747 0 : gPopupControlState = aState;
1748 : }
1749 :
1750 8230 : return oldState;
1751 : }
1752 :
1753 : void
1754 8230 : PopPopupControlState(PopupControlState aState)
1755 : {
1756 8230 : gPopupControlState = aState;
1757 8230 : }
1758 :
1759 : PopupControlState
1760 0 : nsGlobalWindow::PushPopupControlState(PopupControlState aState,
1761 : bool aForce) const
1762 : {
1763 0 : return ::PushPopupControlState(aState, aForce);
1764 : }
1765 :
1766 : void
1767 0 : nsGlobalWindow::PopPopupControlState(PopupControlState aState) const
1768 : {
1769 0 : ::PopPopupControlState(aState);
1770 0 : }
1771 :
1772 : PopupControlState
1773 0 : nsGlobalWindow::GetPopupControlState() const
1774 : {
1775 0 : return gPopupControlState;
1776 : }
1777 :
1778 : #define WINDOWSTATEHOLDER_IID \
1779 : {0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}
1780 :
1781 : class WindowStateHolder : public nsISupports
1782 : {
1783 : public:
1784 : NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
1785 : NS_DECL_ISUPPORTS
1786 :
1787 : WindowStateHolder(nsGlobalWindow *aWindow,
1788 : nsIXPConnectJSObjectHolder *aHolder,
1789 : nsIXPConnectJSObjectHolder *aOuterProto,
1790 : nsIXPConnectJSObjectHolder *aOuterRealProto);
1791 :
1792 0 : nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
1793 0 : nsIXPConnectJSObjectHolder *GetInnerWindowHolder()
1794 0 : { return mInnerWindowHolder; }
1795 :
1796 : nsIXPConnectJSObjectHolder* GetOuterProto() { return mOuterProto; }
1797 0 : nsIXPConnectJSObjectHolder* GetOuterRealProto() { return mOuterRealProto; }
1798 :
1799 0 : void DidRestoreWindow()
1800 : {
1801 0 : mInnerWindow = nsnull;
1802 :
1803 0 : mInnerWindowHolder = nsnull;
1804 0 : mOuterProto = nsnull;
1805 0 : mOuterRealProto = nsnull;
1806 0 : }
1807 :
1808 : protected:
1809 : ~WindowStateHolder();
1810 :
1811 : nsGlobalWindow *mInnerWindow;
1812 : // We hold onto this to make sure the inner window doesn't go away. The outer
1813 : // window ends up recalculating it anyway.
1814 : nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
1815 : nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterProto;
1816 : nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterRealProto;
1817 : };
1818 :
1819 : NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
1820 :
1821 0 : WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
1822 : nsIXPConnectJSObjectHolder *aHolder,
1823 : nsIXPConnectJSObjectHolder *aOuterProto,
1824 : nsIXPConnectJSObjectHolder *aOuterRealProto)
1825 : : mInnerWindow(aWindow),
1826 : mOuterProto(aOuterProto),
1827 0 : mOuterRealProto(aOuterRealProto)
1828 : {
1829 0 : NS_PRECONDITION(aWindow, "null window");
1830 0 : NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
1831 :
1832 0 : mInnerWindowHolder = aHolder;
1833 :
1834 0 : aWindow->SuspendTimeouts();
1835 0 : }
1836 :
1837 0 : WindowStateHolder::~WindowStateHolder()
1838 : {
1839 0 : if (mInnerWindow) {
1840 : // This window was left in the bfcache and is now going away. We need to
1841 : // free it up.
1842 : // Note that FreeInnerObjects may already have been called on the
1843 : // inner window if its outer has already had SetDocShell(null)
1844 : // called.
1845 0 : mInnerWindow->FreeInnerObjects();
1846 : }
1847 0 : }
1848 :
1849 0 : NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder)
1850 :
1851 :
1852 : struct ReparentWaiverClosure
1853 : {
1854 : JSContext *mCx;
1855 : JSObject *mNewInner;
1856 : };
1857 :
1858 : static JSDHashOperator
1859 0 : ReparentWaiverWrappers(JSDHashTable *table, JSDHashEntryHdr *hdr,
1860 : uint32 number, void *arg)
1861 : {
1862 0 : ReparentWaiverClosure *closure = static_cast<ReparentWaiverClosure*>(arg);
1863 0 : JSObject *value = static_cast<JSObject2JSObjectMap::Entry *>(hdr)->value;
1864 :
1865 : // We reparent wrappers that have as their parent an inner window whose
1866 : // outer has the new inner window as its current inner.
1867 0 : JSObject *parent = JS_GetParent(value);
1868 0 : JSObject *outer = JS_ObjectToOuterObject(closure->mCx, parent);
1869 0 : if (outer) {
1870 0 : JSObject *inner = JS_ObjectToInnerObject(closure->mCx, outer);
1871 0 : if (inner == closure->mNewInner && inner != parent)
1872 0 : JS_SetParent(closure->mCx, value, closure->mNewInner);
1873 : } else {
1874 0 : JS_ClearPendingException(closure->mCx);
1875 : }
1876 0 : return JS_DHASH_NEXT;
1877 : }
1878 :
1879 : nsresult
1880 0 : nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
1881 : nsISupports* aState,
1882 : bool aForceReuseInnerWindow)
1883 : {
1884 : NS_TIME_FUNCTION;
1885 :
1886 0 : NS_PRECONDITION(mDocumentPrincipal == nsnull,
1887 : "mDocumentPrincipal prematurely set!");
1888 :
1889 0 : if (!aDocument) {
1890 0 : NS_ERROR("SetNewDocument(null) called!");
1891 :
1892 0 : return NS_ERROR_INVALID_ARG;
1893 : }
1894 :
1895 0 : if (IsInnerWindow()) {
1896 0 : if (!mOuterWindow) {
1897 0 : return NS_ERROR_NOT_INITIALIZED;
1898 : }
1899 :
1900 : // Refuse to set a new document if the call came from an inner
1901 : // window that's not the current inner window.
1902 0 : if (mOuterWindow->GetCurrentInnerWindow() != this) {
1903 0 : return NS_ERROR_NOT_AVAILABLE;
1904 : }
1905 :
1906 0 : return GetOuterWindowInternal()->SetNewDocument(aDocument, aState,
1907 0 : aForceReuseInnerWindow);
1908 : }
1909 :
1910 0 : NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
1911 :
1912 0 : if (IsFrozen()) {
1913 : // This outer is now getting its first inner, thaw the outer now
1914 : // that it's ready and is getting an inner window.
1915 :
1916 0 : Thaw();
1917 : }
1918 :
1919 0 : NS_ASSERTION(!GetCurrentInnerWindow() ||
1920 : GetCurrentInnerWindow()->GetExtantDocument() == mDocument,
1921 : "Uh, mDocument doesn't match the current inner window "
1922 : "document!");
1923 :
1924 0 : bool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
1925 0 : if (aForceReuseInnerWindow &&
1926 0 : !wouldReuseInnerWindow &&
1927 0 : mDoc &&
1928 0 : mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
1929 0 : NS_ERROR("Attempted forced inner window reuse while changing principal");
1930 0 : return NS_ERROR_UNEXPECTED;
1931 : }
1932 :
1933 0 : nsCOMPtr<nsIDocument> oldDoc(do_QueryInterface(mDocument));
1934 :
1935 0 : nsIScriptContext *scx = GetContextInternal();
1936 0 : NS_ENSURE_TRUE(scx, NS_ERROR_NOT_INITIALIZED);
1937 :
1938 0 : JSContext *cx = scx->GetNativeContext();
1939 : #ifndef MOZ_DISABLE_DOMCRYPTO
1940 : // clear smartcard events, our document has gone away.
1941 0 : if (mCrypto) {
1942 0 : mCrypto->SetEnableSmartCardEvents(false);
1943 : }
1944 : #endif
1945 0 : if (!mDocument) {
1946 : // First document load.
1947 :
1948 : // Get our private root. If it is equal to us, then we need to
1949 : // attach our global key bindings that handles browser scrolling
1950 : // and other browser commands.
1951 0 : nsIDOMWindow* privateRoot = nsGlobalWindow::GetPrivateRoot();
1952 :
1953 0 : if (privateRoot == static_cast<nsIDOMWindow*>(this)) {
1954 0 : nsCOMPtr<nsIXBLService> xblService = do_GetService("@mozilla.org/xbl;1");
1955 0 : if (xblService) {
1956 0 : xblService->AttachGlobalKeyHandler(mChromeEventHandler);
1957 : }
1958 : }
1959 : }
1960 :
1961 : /* No mDocShell means we're already been partially closed down. When that
1962 : happens, setting status isn't a big requirement, so don't. (Doesn't happen
1963 : under normal circumstances, but bug 49615 describes a case.) */
1964 :
1965 : nsContentUtils::AddScriptRunner(
1966 0 : NS_NewRunnableMethod(this, &nsGlobalWindow::ClearStatus));
1967 :
1968 0 : bool reUseInnerWindow = aForceReuseInnerWindow || wouldReuseInnerWindow;
1969 :
1970 0 : nsresult rv = NS_OK;
1971 :
1972 : // Set mDocument even if this is an outer window to avoid
1973 : // having to *always* reach into the inner window to find the
1974 : // document.
1975 0 : mDocument = do_QueryInterface(aDocument);
1976 0 : mDoc = aDocument;
1977 :
1978 : #ifdef DEBUG
1979 0 : mLastOpenedURI = aDocument->GetDocumentURI();
1980 : #endif
1981 :
1982 0 : mContext->WillInitializeContext();
1983 :
1984 0 : nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
1985 :
1986 0 : nsRefPtr<nsGlobalWindow> newInnerWindow;
1987 0 : bool createdInnerWindow = false;
1988 :
1989 0 : bool thisChrome = IsChromeWindow();
1990 :
1991 0 : bool isChrome = false;
1992 :
1993 0 : nsCxPusher cxPusher;
1994 0 : if (!cxPusher.Push(cx)) {
1995 0 : return NS_ERROR_FAILURE;
1996 : }
1997 :
1998 0 : JSAutoRequest ar(cx);
1999 :
2000 0 : nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
2001 0 : NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
2002 :
2003 0 : if (reUseInnerWindow) {
2004 : // We're reusing the current inner window.
2005 0 : NS_ASSERTION(!currentInner->IsFrozen(),
2006 : "We should never be reusing a shared inner window");
2007 0 : newInnerWindow = currentInner;
2008 :
2009 0 : if (aDocument != oldDoc) {
2010 0 : nsWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject);
2011 : }
2012 :
2013 : // The API we're really looking for here is to go clear all of the
2014 : // Xray wrappers associated with our outer window. However, we
2015 : // don't expose that API because the implementation would be
2016 : // identical to that of JS_TransplantObject, so we just call that
2017 : // instead.
2018 0 : if (!JS_TransplantObject(cx, mJSObject, mJSObject)) {
2019 0 : return NS_ERROR_FAILURE;
2020 : }
2021 : } else {
2022 0 : if (aState) {
2023 0 : newInnerWindow = wsh->GetInnerWindow();
2024 0 : mInnerWindowHolder = wsh->GetInnerWindowHolder();
2025 :
2026 0 : NS_ASSERTION(newInnerWindow, "Got a state without inner window");
2027 0 : } else if (thisChrome) {
2028 0 : newInnerWindow = new nsGlobalChromeWindow(this);
2029 0 : isChrome = true;
2030 0 : } else if (mIsModalContentWindow) {
2031 0 : newInnerWindow = new nsGlobalModalWindow(this);
2032 : } else {
2033 0 : newInnerWindow = new nsGlobalWindow(this);
2034 : }
2035 :
2036 0 : if (!aState) {
2037 : // This is redundant if we're restoring from a previous inner window.
2038 : nsIScriptGlobalObject *sgo =
2039 0 : (nsIScriptGlobalObject *)newInnerWindow.get();
2040 :
2041 : // Freeze the outer window and null out the inner window so
2042 : // that initializing classes on the new inner doesn't end up
2043 : // reaching into the old inner window for classes etc.
2044 : //
2045 : // [This happens with Object.prototype when XPConnect creates
2046 : // a temporary global while initializing classes; the reason
2047 : // being that xpconnect creates the temp global w/o a parent
2048 : // and proto, which makes the JS engine look up classes in
2049 : // cx->globalObject, i.e. this outer window].
2050 :
2051 0 : mInnerWindow = nsnull;
2052 :
2053 0 : Freeze();
2054 0 : mCreatingInnerWindow = true;
2055 : // Every script context we are initialized with must create a
2056 : // new global.
2057 0 : nsCOMPtr<nsIXPConnectJSObjectHolder> &holder = mInnerWindowHolder;
2058 0 : rv = mContext->CreateNativeGlobalForInner(sgo, isChrome,
2059 : aDocument->NodePrincipal(),
2060 0 : &newInnerWindow->mJSObject,
2061 0 : getter_AddRefs(holder));
2062 0 : NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerWindow->mJSObject && holder,
2063 : "Failed to get script global and holder");
2064 :
2065 0 : mCreatingInnerWindow = false;
2066 0 : createdInnerWindow = true;
2067 0 : Thaw();
2068 :
2069 0 : NS_ENSURE_SUCCESS(rv, rv);
2070 : }
2071 :
2072 0 : if (currentInner && currentInner->mJSObject) {
2073 0 : if (oldDoc == aDocument) {
2074 : // Move the navigator from the old inner window to the new one since
2075 : // this is a document.write. This is safe from a same-origin point of
2076 : // view because document.write can only be used by the same origin.
2077 0 : newInnerWindow->mNavigator = currentInner->mNavigator;
2078 0 : currentInner->mNavigator = nsnull;
2079 0 : if (newInnerWindow->mNavigator) {
2080 0 : newInnerWindow->mNavigator->SetWindow(newInnerWindow);
2081 : }
2082 : }
2083 :
2084 : // Don't free objects on our current inner window if it's going to be
2085 : // held in the bfcache.
2086 0 : if (!currentInner->IsFrozen()) {
2087 0 : currentInner->FreeInnerObjects();
2088 : }
2089 : }
2090 :
2091 0 : mInnerWindow = newInnerWindow;
2092 :
2093 0 : if (!mJSObject) {
2094 0 : mContext->CreateOuterObject(this, newInnerWindow);
2095 0 : mContext->DidInitializeContext();
2096 :
2097 0 : mJSObject = mContext->GetNativeGlobal();
2098 0 : SetWrapper(mJSObject);
2099 : } else {
2100 : JSObject *outerObject =
2101 0 : NS_NewOuterWindowProxy(cx, newInnerWindow->mJSObject);
2102 0 : if (!outerObject) {
2103 0 : NS_ERROR("out of memory");
2104 0 : return NS_ERROR_FAILURE;
2105 : }
2106 :
2107 0 : js::SetProxyExtra(mJSObject, 0, js::PrivateValue(NULL));
2108 :
2109 0 : outerObject = JS_TransplantObject(cx, mJSObject, outerObject);
2110 0 : if (!outerObject) {
2111 0 : NS_ERROR("unable to transplant wrappers, probably OOM");
2112 0 : return NS_ERROR_FAILURE;
2113 : }
2114 :
2115 0 : nsIScriptGlobalObject *global = static_cast<nsIScriptGlobalObject*>(this);
2116 0 : js::SetProxyExtra(outerObject, 0, js::PrivateValue(global));
2117 :
2118 0 : mJSObject = outerObject;
2119 0 : SetWrapper(mJSObject);
2120 :
2121 : {
2122 0 : JSAutoEnterCompartment ac;
2123 0 : if (!ac.enter(cx, mJSObject)) {
2124 0 : NS_ERROR("unable to enter a compartment");
2125 0 : return NS_ERROR_FAILURE;
2126 : }
2127 :
2128 0 : JS_SetParent(cx, mJSObject, newInnerWindow->mJSObject);
2129 :
2130 0 : mContext->SetOuterObject(mJSObject);
2131 :
2132 0 : JSCompartment *compartment = js::GetObjectCompartment(mJSObject);
2133 : xpc::CompartmentPrivate *priv =
2134 0 : static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(compartment));
2135 0 : if (priv && priv->waiverWrapperMap) {
2136 0 : NS_ASSERTION(!JS_IsExceptionPending(cx),
2137 : "We might overwrite a pending exception!");
2138 : ReparentWaiverClosure closure = {
2139 : cx,
2140 0 : newInnerWindow->mJSObject
2141 0 : };
2142 0 : priv->waiverWrapperMap->Enumerate(ReparentWaiverWrappers, &closure);
2143 : }
2144 : }
2145 : }
2146 :
2147 : // If we created a new inner window above, we need to do the last little bit
2148 : // of initialization now that the dust has settled.
2149 0 : if (createdInnerWindow) {
2150 0 : nsIXPConnect *xpc = nsContentUtils::XPConnect();
2151 0 : nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
2152 0 : nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerWindow->mJSObject,
2153 0 : getter_AddRefs(wrapper));
2154 0 : NS_ENSURE_SUCCESS(rv, rv);
2155 0 : NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
2156 0 : rv = wrapper->FinishInitForWrappedGlobal();
2157 0 : NS_ENSURE_SUCCESS(rv, rv);
2158 : }
2159 :
2160 0 : JSAutoEnterCompartment ac;
2161 0 : if (!ac.enter(cx, mJSObject)) {
2162 0 : NS_ERROR("unable to enter a compartment");
2163 0 : return NS_ERROR_FAILURE;
2164 : }
2165 :
2166 : // XXX Not sure if this is needed.
2167 0 : if (aState) {
2168 : JSObject *proto;
2169 0 : if (nsIXPConnectJSObjectHolder *holder = wsh->GetOuterRealProto()) {
2170 0 : holder->GetJSObject(&proto);
2171 : } else {
2172 0 : proto = nsnull;
2173 : }
2174 :
2175 0 : if (!JS_SetPrototype(cx, mJSObject, proto)) {
2176 0 : NS_ERROR("can't set prototype");
2177 0 : return NS_ERROR_FAILURE;
2178 : }
2179 : } else {
2180 0 : if (!JS_DefineProperty(cx, newInnerWindow->mJSObject, "window",
2181 0 : OBJECT_TO_JSVAL(mJSObject),
2182 : JS_PropertyStub, JS_StrictPropertyStub,
2183 0 : JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
2184 0 : NS_ERROR("can't create the 'window' property");
2185 0 : return NS_ERROR_FAILURE;
2186 : }
2187 : }
2188 : }
2189 :
2190 0 : JSAutoEnterCompartment ac;
2191 0 : if (!ac.enter(cx, mJSObject)) {
2192 0 : NS_ERROR("unable to enter a compartment");
2193 0 : return NS_ERROR_FAILURE;
2194 : }
2195 :
2196 0 : if (!aState && !reUseInnerWindow) {
2197 : // Loading a new page and creating a new inner window, *not*
2198 : // restoring from session history.
2199 :
2200 : // Now that both the the inner and outer windows are initialized
2201 : // let the script context do its magic to hook them together.
2202 0 : mContext->ConnectToInner(newInnerWindow, mJSObject);
2203 :
2204 0 : nsCOMPtr<nsIContent> frame = do_QueryInterface(GetFrameElementInternal());
2205 0 : if (frame && frame->OwnerDoc()) {
2206 0 : nsPIDOMWindow* parentWindow = frame->OwnerDoc()->GetWindow();
2207 0 : if (parentWindow && parentWindow->TimeoutSuspendCount()) {
2208 0 : SuspendTimeouts(parentWindow->TimeoutSuspendCount());
2209 : }
2210 : }
2211 : }
2212 :
2213 : // Add an extra ref in case we release mContext during GC.
2214 0 : nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
2215 :
2216 : // Now that the prototype is all set up, install the global scope
2217 : // polluter. This must happen after the above prototype fixup. If
2218 : // the GSP was to be installed on the inner window's real
2219 : // prototype (as it would be if this was done before the prototype
2220 : // fixup above) we would end up holding the GSP alive (through
2221 : // XPConnect's internal marking of wrapper prototypes) as long as
2222 : // the inner window was around, and if the GSP had properties on
2223 : // it that held an element alive we'd hold the document alive,
2224 : // which could hold event handlers alive, which hold the context
2225 : // alive etc.
2226 :
2227 0 : if ((!reUseInnerWindow || aDocument != oldDoc) && !aState) {
2228 0 : nsCOMPtr<nsIHTMLDocument> html_doc(do_QueryInterface(mDocument));
2229 0 : nsWindowSH::InstallGlobalScopePolluter(cx, newInnerWindow->mJSObject,
2230 0 : html_doc);
2231 : }
2232 :
2233 0 : if (aDocument) {
2234 0 : aDocument->SetScriptGlobalObject(newInnerWindow);
2235 : }
2236 :
2237 0 : if (!aState) {
2238 0 : if (reUseInnerWindow) {
2239 0 : if (newInnerWindow->mDoc != aDocument) {
2240 0 : newInnerWindow->mDocument = do_QueryInterface(aDocument);
2241 0 : newInnerWindow->mDoc = aDocument;
2242 :
2243 : // We're reusing the inner window for a new document. In this
2244 : // case we don't clear the inner window's scope, but we must
2245 : // make sure the cached document property gets updated.
2246 :
2247 : // XXXmarkh - tell other languages about this?
2248 0 : ::JS_DeleteProperty(cx, currentInner->mJSObject, "document");
2249 :
2250 0 : if (mDummyJavaPluginOwner) {
2251 : // Since we're reusing the inner window, tear down the
2252 : // dummy Java plugin we created for the old document in
2253 : // this window.
2254 0 : mDummyJavaPluginOwner->Destroy();
2255 0 : mDummyJavaPluginOwner = nsnull;
2256 :
2257 0 : mDidInitJavaProperties = false;
2258 : }
2259 : }
2260 : } else {
2261 0 : rv = newInnerWindow->InnerSetNewDocument(aDocument);
2262 0 : NS_ENSURE_SUCCESS(rv, rv);
2263 :
2264 : // Initialize DOM classes etc on the inner window.
2265 0 : rv = mContext->InitClasses(newInnerWindow->mJSObject);
2266 0 : NS_ENSURE_SUCCESS(rv, rv);
2267 : }
2268 :
2269 0 : if (mArguments) {
2270 0 : newInnerWindow->DefineArgumentsProperty(mArguments);
2271 0 : newInnerWindow->mArguments = mArguments;
2272 0 : newInnerWindow->mArgumentsOrigin = mArgumentsOrigin;
2273 :
2274 0 : mArguments = nsnull;
2275 0 : mArgumentsOrigin = nsnull;
2276 : }
2277 :
2278 : // Give the new inner window our chrome event handler (since it
2279 : // doesn't have one).
2280 0 : newInnerWindow->mChromeEventHandler = mChromeEventHandler;
2281 : }
2282 :
2283 0 : mContext->GC(js::gcreason::SET_NEW_DOCUMENT);
2284 0 : mContext->DidInitializeContext();
2285 :
2286 0 : if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
2287 : // We should probably notify. However if this is the, arguably bad,
2288 : // situation when we're creating a temporary non-chrome-about-blank
2289 : // document in a chrome docshell, don't notify just yet. Instead wait
2290 : // until we have a real chrome doc.
2291 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
2292 0 : PRInt32 itemType = nsIDocShellTreeItem::typeContent;
2293 0 : if (treeItem) {
2294 0 : treeItem->GetItemType(&itemType);
2295 : }
2296 :
2297 0 : if (itemType != nsIDocShellTreeItem::typeChrome ||
2298 0 : nsContentUtils::IsSystemPrincipal(mDoc->NodePrincipal())) {
2299 0 : newInnerWindow->mHasNotifiedGlobalCreated = true;
2300 : nsContentUtils::AddScriptRunner(
2301 0 : NS_NewRunnableMethod(this, &nsGlobalWindow::DispatchDOMWindowCreated));
2302 : }
2303 : }
2304 :
2305 0 : return NS_OK;
2306 : }
2307 :
2308 : void
2309 0 : nsGlobalWindow::DispatchDOMWindowCreated()
2310 : {
2311 0 : if (!mDoc || !mDocument) {
2312 0 : return;
2313 : }
2314 :
2315 : // Fire DOMWindowCreated at chrome event listeners
2316 0 : nsContentUtils::DispatchChromeEvent(mDoc, mDocument, NS_LITERAL_STRING("DOMWindowCreated"),
2317 : true /* bubbles */,
2318 0 : false /* not cancellable */);
2319 :
2320 : nsCOMPtr<nsIObserverService> observerService =
2321 0 : mozilla::services::GetObserverService();
2322 0 : if (observerService) {
2323 0 : nsAutoString origin;
2324 0 : nsIPrincipal* principal = mDoc->NodePrincipal();
2325 0 : nsContentUtils::GetUTFOrigin(principal, origin);
2326 0 : observerService->
2327 : NotifyObservers(static_cast<nsIDOMWindow*>(this),
2328 0 : nsContentUtils::IsSystemPrincipal(principal) ?
2329 : "chrome-document-global-created" :
2330 : "content-document-global-created",
2331 0 : origin.get());
2332 : }
2333 : }
2334 :
2335 : void
2336 0 : nsGlobalWindow::ClearStatus()
2337 : {
2338 0 : SetStatus(EmptyString());
2339 0 : SetDefaultStatus(EmptyString());
2340 0 : }
2341 :
2342 : nsresult
2343 0 : nsGlobalWindow::InnerSetNewDocument(nsIDocument* aDocument)
2344 : {
2345 0 : NS_PRECONDITION(IsInnerWindow(), "Must only be called on inner windows");
2346 :
2347 : #ifdef PR_LOGGING
2348 0 : if (aDocument && gDOMLeakPRLog &&
2349 : PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
2350 0 : nsIURI *uri = aDocument->GetDocumentURI();
2351 0 : nsCAutoString spec;
2352 0 : if (uri)
2353 0 : uri->GetSpec(spec);
2354 0 : PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get());
2355 : }
2356 : #endif
2357 :
2358 0 : mDocument = do_QueryInterface(aDocument);
2359 0 : mDoc = aDocument;
2360 0 : mFocusedNode = nsnull;
2361 0 : mLocalStorage = nsnull;
2362 0 : mSessionStorage = nsnull;
2363 :
2364 : #ifdef DEBUG
2365 0 : mLastOpenedURI = aDocument->GetDocumentURI();
2366 : #endif
2367 :
2368 : Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
2369 0 : mMutationBits ? 1 : 0);
2370 :
2371 : // Clear our mutation bitfield.
2372 0 : mMutationBits = 0;
2373 :
2374 0 : return NS_OK;
2375 : }
2376 :
2377 : void
2378 0 : nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
2379 : {
2380 0 : NS_ASSERTION(IsOuterWindow(), "Uh, SetDocShell() called on inner window!");
2381 :
2382 0 : if (aDocShell == mDocShell)
2383 0 : return;
2384 :
2385 : // SetDocShell(nsnull) means the window is being torn down. Drop our
2386 : // reference to the script context, allowing it to be deleted
2387 : // later. Meanwhile, keep our weak reference to the script object
2388 : // (mJSObject) so that it can be retrieved later (until it is
2389 : // finalized by the JS GC).
2390 :
2391 0 : if (!aDocShell) {
2392 0 : NS_ASSERTION(PR_CLIST_IS_EMPTY(&mTimeouts),
2393 : "Uh, outer window holds timeouts!");
2394 :
2395 : // Call FreeInnerObjects on all inner windows, not just the current
2396 : // one, since some could be held by WindowStateHolder objects that
2397 : // are GC-owned.
2398 0 : for (nsRefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
2399 : inner != this;
2400 0 : inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
2401 0 : NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
2402 : "bad outer window pointer");
2403 0 : inner->FreeInnerObjects();
2404 : }
2405 :
2406 : // Make sure that this is called before we null out the document.
2407 0 : NotifyDOMWindowDestroyed(this);
2408 :
2409 0 : NotifyWindowIDDestroyed("outer-window-destroyed");
2410 :
2411 0 : nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
2412 :
2413 0 : if (currentInner) {
2414 0 : NS_ASSERTION(mDoc, "Must have doc!");
2415 :
2416 : // Remember the document's principal.
2417 0 : mDocumentPrincipal = mDoc->NodePrincipal();
2418 :
2419 : // Release our document reference
2420 0 : mDocument = nsnull;
2421 0 : mDoc = nsnull;
2422 0 : mFocusedNode = nsnull;
2423 : }
2424 :
2425 0 : ClearControllers();
2426 :
2427 0 : mChromeEventHandler = nsnull; // force release now
2428 :
2429 0 : if (mArguments) {
2430 : // We got no new document after someone called
2431 : // SetArguments(), drop our reference to the arguments.
2432 0 : mArguments = nsnull;
2433 0 : mArgumentsLast = nsnull;
2434 0 : mArgumentsOrigin = nsnull;
2435 : }
2436 :
2437 0 : if (mContext) {
2438 0 : mContext->GC(js::gcreason::SET_DOC_SHELL);
2439 0 : mContext = nsnull;
2440 : }
2441 :
2442 : #ifdef DEBUG
2443 0 : nsCycleCollector_DEBUG_shouldBeFreed(mContext);
2444 0 : nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
2445 : #endif
2446 : }
2447 :
2448 0 : mDocShell = aDocShell; // Weak Reference
2449 :
2450 0 : NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
2451 :
2452 0 : if (mFrames)
2453 0 : mFrames->SetDocShell(aDocShell);
2454 0 : if (mScreen)
2455 0 : mScreen->SetDocShell(aDocShell);
2456 :
2457 0 : if (!mDocShell) {
2458 0 : MaybeForgiveSpamCount();
2459 0 : CleanUp(false);
2460 : } else {
2461 : // Get our enclosing chrome shell and retrieve its global window impl, so
2462 : // that we can do some forwarding to the chrome document.
2463 0 : nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
2464 0 : mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
2465 0 : mChromeEventHandler = do_QueryInterface(chromeEventHandler);
2466 0 : if (!mChromeEventHandler) {
2467 : // We have no chrome event handler. If we have a parent,
2468 : // get our chrome event handler from the parent. If
2469 : // we don't have a parent, then we need to make a new
2470 : // window root object that will function as a chrome event
2471 : // handler and receive all events that occur anywhere inside
2472 : // our window.
2473 0 : nsCOMPtr<nsIDOMWindow> parentWindow;
2474 0 : GetParent(getter_AddRefs(parentWindow));
2475 0 : if (parentWindow.get() != static_cast<nsIDOMWindow*>(this)) {
2476 0 : nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(parentWindow));
2477 0 : mChromeEventHandler = piWindow->GetChromeEventHandler();
2478 : }
2479 0 : else NS_NewWindowRoot(this, getter_AddRefs(mChromeEventHandler));
2480 : }
2481 :
2482 : bool docShellActive;
2483 0 : mDocShell->GetIsActive(&docShellActive);
2484 0 : mIsBackground = !docShellActive;
2485 : }
2486 : }
2487 :
2488 : void
2489 0 : nsGlobalWindow::SetOpenerWindow(nsIDOMWindow* aOpener,
2490 : bool aOriginalOpener)
2491 : {
2492 0 : FORWARD_TO_OUTER_VOID(SetOpenerWindow, (aOpener, aOriginalOpener));
2493 :
2494 0 : NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
2495 : "aOriginalOpener is true, but not first call to "
2496 : "SetOpenerWindow!");
2497 0 : NS_ASSERTION(aOpener || !aOriginalOpener,
2498 : "Shouldn't set mHadOriginalOpener if aOpener is null");
2499 :
2500 0 : mOpener = do_GetWeakReference(aOpener);
2501 0 : NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!");
2502 :
2503 0 : if (aOriginalOpener) {
2504 0 : mHadOriginalOpener = true;
2505 : }
2506 :
2507 : #ifdef DEBUG
2508 0 : mSetOpenerWindowCalled = true;
2509 : #endif
2510 : }
2511 :
2512 : void
2513 0 : nsGlobalWindow::UpdateParentTarget()
2514 : {
2515 0 : nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(mChromeEventHandler);
2516 0 : if (flo) {
2517 0 : nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
2518 0 : if (fl) {
2519 0 : mParentTarget = fl->GetTabChildGlobalAsEventTarget();
2520 : }
2521 : }
2522 0 : if (!mParentTarget) {
2523 0 : mParentTarget = mChromeEventHandler;
2524 : }
2525 0 : }
2526 :
2527 : bool
2528 0 : nsGlobalWindow::GetIsTabModalPromptAllowed()
2529 : {
2530 0 : bool allowTabModal = true;
2531 0 : if (mDocShell) {
2532 0 : nsCOMPtr<nsIContentViewer> cv;
2533 0 : mDocShell->GetContentViewer(getter_AddRefs(cv));
2534 0 : cv->GetIsTabModalPromptAllowed(&allowTabModal);
2535 : }
2536 :
2537 0 : return allowTabModal;
2538 : }
2539 :
2540 : nsIDOMEventTarget*
2541 0 : nsGlobalWindow::GetTargetForDOMEvent()
2542 : {
2543 0 : return static_cast<nsIDOMEventTarget*>(GetOuterWindowInternal());
2544 : }
2545 :
2546 : nsIDOMEventTarget*
2547 0 : nsGlobalWindow::GetTargetForEventTargetChain()
2548 : {
2549 0 : return IsInnerWindow() ?
2550 0 : this : static_cast<nsIDOMEventTarget*>(GetCurrentInnerWindowInternal());
2551 : }
2552 :
2553 : nsresult
2554 0 : nsGlobalWindow::WillHandleEvent(nsEventChainPostVisitor& aVisitor)
2555 : {
2556 0 : return NS_OK;
2557 : }
2558 :
2559 : JSContext*
2560 0 : nsGlobalWindow::GetJSContextForEventHandlers()
2561 : {
2562 0 : return nsnull;
2563 : }
2564 :
2565 : nsresult
2566 0 : nsGlobalWindow::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
2567 : {
2568 0 : NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
2569 : static PRUint32 count = 0;
2570 0 : PRUint32 msg = aVisitor.mEvent->message;
2571 :
2572 0 : aVisitor.mCanHandle = true;
2573 0 : aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
2574 0 : if ((msg == NS_MOUSE_MOVE) && gEntropyCollector) {
2575 : //Chances are this counter will overflow during the life of the
2576 : //process, but that's OK for our case. Means we get a little
2577 : //more entropy.
2578 0 : if (count++ % 100 == 0) {
2579 : //Since the high bits seem to be zero's most of the time,
2580 : //let's only take the lowest half of the point structure.
2581 : PRInt16 myCoord[2];
2582 :
2583 0 : myCoord[0] = aVisitor.mEvent->refPoint.x;
2584 0 : myCoord[1] = aVisitor.mEvent->refPoint.y;
2585 0 : gEntropyCollector->RandomUpdate((void*)myCoord, sizeof(myCoord));
2586 : gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
2587 0 : sizeof(PRUint32));
2588 0 : }
2589 0 : } else if (msg == NS_RESIZE_EVENT) {
2590 0 : mIsHandlingResizeEvent = true;
2591 0 : } else if (msg == NS_MOUSE_BUTTON_DOWN &&
2592 : NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2593 0 : gMouseDown = true;
2594 0 : } else if ((msg == NS_MOUSE_BUTTON_UP ||
2595 : msg == NS_DRAGDROP_END) &&
2596 : NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2597 0 : gMouseDown = false;
2598 0 : if (gDragServiceDisabled) {
2599 : nsCOMPtr<nsIDragService> ds =
2600 0 : do_GetService("@mozilla.org/widget/dragservice;1");
2601 0 : if (ds) {
2602 0 : gDragServiceDisabled = false;
2603 0 : ds->Unsuppress();
2604 : }
2605 : }
2606 : }
2607 :
2608 0 : aVisitor.mParentTarget = GetParentTarget();
2609 0 : return NS_OK;
2610 : }
2611 :
2612 : bool
2613 0 : nsGlobalWindow::DialogOpenAttempted()
2614 : {
2615 0 : nsGlobalWindow *topWindow = GetTop();
2616 0 : if (!topWindow) {
2617 0 : NS_ERROR("DialogOpenAttempted() called without a top window?");
2618 :
2619 0 : return false;
2620 : }
2621 :
2622 0 : topWindow = topWindow->GetCurrentInnerWindowInternal();
2623 0 : if (!topWindow ||
2624 0 : topWindow->mLastDialogQuitTime.IsNull() ||
2625 0 : nsContentUtils::CallerHasUniversalXPConnect()) {
2626 0 : return false;
2627 : }
2628 :
2629 : TimeDuration dialogDuration(TimeStamp::Now() -
2630 0 : topWindow->mLastDialogQuitTime);
2631 :
2632 0 : if (dialogDuration.ToSeconds() <
2633 : Preferences::GetInt("dom.successive_dialog_time_limit",
2634 0 : SUCCESSIVE_DIALOG_TIME_LIMIT)) {
2635 0 : topWindow->mDialogAbuseCount++;
2636 :
2637 0 : return (topWindow->GetPopupControlState() > openAllowed ||
2638 0 : topWindow->mDialogAbuseCount > MAX_DIALOG_COUNT);
2639 : }
2640 :
2641 0 : topWindow->mDialogAbuseCount = 0;
2642 :
2643 0 : return false;
2644 : }
2645 :
2646 : bool
2647 0 : nsGlobalWindow::AreDialogsBlocked()
2648 : {
2649 0 : nsGlobalWindow *topWindow = GetTop();
2650 0 : if (!topWindow) {
2651 0 : NS_ASSERTION(!mDocShell, "AreDialogsBlocked() called without a top window?");
2652 :
2653 0 : return true;
2654 : }
2655 :
2656 0 : topWindow = topWindow->GetCurrentInnerWindowInternal();
2657 :
2658 : return !topWindow ||
2659 : (topWindow->mDialogDisabled &&
2660 0 : (topWindow->GetPopupControlState() > openAllowed ||
2661 0 : topWindow->mDialogAbuseCount >= MAX_DIALOG_COUNT));
2662 : }
2663 :
2664 : bool
2665 0 : nsGlobalWindow::ConfirmDialogAllowed()
2666 : {
2667 0 : FORWARD_TO_OUTER(ConfirmDialogAllowed, (), false);
2668 :
2669 0 : NS_ENSURE_TRUE(mDocShell, false);
2670 : nsCOMPtr<nsIPromptService> promptSvc =
2671 0 : do_GetService("@mozilla.org/embedcomp/prompt-service;1");
2672 :
2673 0 : if (!DialogOpenAttempted() || !promptSvc) {
2674 0 : return true;
2675 : }
2676 :
2677 : // Reset popup state while opening a modal dialog, and firing events
2678 : // about the dialog, to prevent the current state from being active
2679 : // the whole time a modal dialog is open.
2680 0 : nsAutoPopupStatePusher popupStatePusher(openAbused, true);
2681 :
2682 0 : bool disableDialog = false;
2683 0 : nsXPIDLString label, title;
2684 : nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2685 0 : "ScriptDialogLabel", label);
2686 : nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
2687 0 : "ScriptDialogPreventTitle", title);
2688 0 : promptSvc->Confirm(this, title.get(), label.get(), &disableDialog);
2689 0 : if (disableDialog) {
2690 0 : PreventFurtherDialogs();
2691 0 : return false;
2692 : }
2693 :
2694 0 : return true;
2695 : }
2696 :
2697 : void
2698 0 : nsGlobalWindow::PreventFurtherDialogs()
2699 : {
2700 0 : nsGlobalWindow *topWindow = GetTop();
2701 0 : if (!topWindow) {
2702 0 : NS_ERROR("PreventFurtherDialogs() called without a top window?");
2703 :
2704 0 : return;
2705 : }
2706 :
2707 0 : topWindow = topWindow->GetCurrentInnerWindowInternal();
2708 :
2709 0 : if (topWindow)
2710 0 : topWindow->mDialogDisabled = true;
2711 : }
2712 :
2713 : nsresult
2714 0 : nsGlobalWindow::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
2715 : {
2716 0 : NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
2717 :
2718 : // Return early if there is nothing to do.
2719 0 : switch (aVisitor.mEvent->message) {
2720 : case NS_RESIZE_EVENT:
2721 : case NS_PAGE_UNLOAD:
2722 : case NS_LOAD:
2723 : break;
2724 : default:
2725 0 : return NS_OK;
2726 : }
2727 :
2728 : /* mChromeEventHandler and mContext go dangling in the middle of this
2729 : function under some circumstances (events that destroy the window)
2730 : without this addref. */
2731 0 : nsCOMPtr<nsIDOMEventTarget> kungFuDeathGrip1(mChromeEventHandler);
2732 0 : nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
2733 :
2734 0 : if (aVisitor.mEvent->message == NS_RESIZE_EVENT) {
2735 0 : mIsHandlingResizeEvent = false;
2736 0 : } else if (aVisitor.mEvent->message == NS_PAGE_UNLOAD &&
2737 : NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2738 : // Execute bindingdetached handlers before we tear ourselves
2739 : // down.
2740 0 : if (mDocument) {
2741 0 : NS_ASSERTION(mDoc, "Must have doc");
2742 0 : mDoc->BindingManager()->ExecuteDetachedHandlers();
2743 : }
2744 0 : mIsDocumentLoaded = false;
2745 0 : } else if (aVisitor.mEvent->message == NS_LOAD &&
2746 : NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2747 : // This is page load event since load events don't propagate to |window|.
2748 : // @see nsDocument::PreHandleEvent.
2749 0 : mIsDocumentLoaded = true;
2750 :
2751 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(GetFrameElementInternal()));
2752 : nsCOMPtr<nsIDocShellTreeItem> treeItem =
2753 0 : do_QueryInterface(GetDocShell());
2754 :
2755 0 : PRInt32 itemType = nsIDocShellTreeItem::typeChrome;
2756 :
2757 0 : if (treeItem) {
2758 0 : treeItem->GetItemType(&itemType);
2759 : }
2760 :
2761 0 : if (content && GetParentInternal() &&
2762 : itemType != nsIDocShellTreeItem::typeChrome) {
2763 : // If we're not in chrome, or at a chrome boundary, fire the
2764 : // onload event for the frame element.
2765 :
2766 0 : nsEventStatus status = nsEventStatus_eIgnore;
2767 0 : nsEvent event(NS_IS_TRUSTED_EVENT(aVisitor.mEvent), NS_LOAD);
2768 0 : event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
2769 :
2770 : // Most of the time we could get a pres context to pass in here,
2771 : // but not always (i.e. if this window is not shown there won't
2772 : // be a pres context available). Since we're not firing a GUI
2773 : // event we don't need a pres context anyway so we just pass
2774 : // null as the pres context all the time here.
2775 0 : nsEventDispatcher::Dispatch(content, nsnull, &event, nsnull, &status);
2776 : }
2777 : }
2778 :
2779 0 : return NS_OK;
2780 : }
2781 :
2782 : nsresult
2783 0 : nsGlobalWindow::DispatchDOMEvent(nsEvent* aEvent,
2784 : nsIDOMEvent* aDOMEvent,
2785 : nsPresContext* aPresContext,
2786 : nsEventStatus* aEventStatus)
2787 : {
2788 : return
2789 : nsEventDispatcher::DispatchDOMEvent(static_cast<nsPIDOMWindow*>(this),
2790 : aEvent, aDOMEvent, aPresContext,
2791 0 : aEventStatus);
2792 : }
2793 :
2794 : void
2795 0 : nsGlobalWindow::OnFinalize(JSObject* aObject)
2796 : {
2797 0 : if (aObject == mJSObject) {
2798 0 : mJSObject = NULL;
2799 : }
2800 0 : }
2801 :
2802 : void
2803 0 : nsGlobalWindow::SetScriptsEnabled(bool aEnabled, bool aFireTimeouts)
2804 : {
2805 0 : FORWARD_TO_INNER_VOID(SetScriptsEnabled, (aEnabled, aFireTimeouts));
2806 :
2807 0 : if (aEnabled && aFireTimeouts) {
2808 : // Scripts are enabled (again?) on this context, run timeouts that
2809 : // fired on this context while scripts were disabled.
2810 0 : void (nsGlobalWindow::*run)() = &nsGlobalWindow::RunTimeout;
2811 0 : NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, run));
2812 : }
2813 : }
2814 :
2815 : nsresult
2816 0 : nsGlobalWindow::SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin)
2817 : {
2818 0 : FORWARD_TO_OUTER(SetArguments, (aArguments, aOrigin),
2819 : NS_ERROR_NOT_INITIALIZED);
2820 :
2821 : // Hold on to the arguments so that we can re-set them once the next
2822 : // document is loaded.
2823 0 : mArguments = aArguments;
2824 0 : mArgumentsOrigin = aOrigin;
2825 :
2826 0 : nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
2827 :
2828 0 : if (!mIsModalContentWindow) {
2829 0 : mArgumentsLast = aArguments;
2830 0 : } else if (currentInner) {
2831 : // SetArguments() is being called on a modal content window that
2832 : // already has an inner window. This can happen when loading
2833 : // javascript: URIs as modal content dialogs. In this case, we'll
2834 : // set up the dialog window, both inner and outer, before we call
2835 : // SetArguments() on the window, so to deal with that, make sure
2836 : // here that the arguments are propagated to the inner window.
2837 :
2838 0 : currentInner->mArguments = aArguments;
2839 0 : currentInner->mArgumentsOrigin = aOrigin;
2840 : }
2841 :
2842 : return currentInner ?
2843 0 : currentInner->DefineArgumentsProperty(aArguments) : NS_OK;
2844 : }
2845 :
2846 : nsresult
2847 0 : nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments)
2848 : {
2849 : JSContext *cx;
2850 0 : nsIScriptContext *ctx = GetOuterWindowInternal()->mContext;
2851 0 : NS_ENSURE_TRUE(aArguments && ctx &&
2852 : (cx = ctx->GetNativeContext()),
2853 : NS_ERROR_NOT_INITIALIZED);
2854 :
2855 0 : if (mIsModalContentWindow) {
2856 : // Modal content windows don't have an "arguments" property, they
2857 : // have a "dialogArguments" property which is handled
2858 : // separately. See nsWindowSH::NewResolve().
2859 :
2860 0 : return NS_OK;
2861 : }
2862 :
2863 0 : return GetContextInternal()->SetProperty(mJSObject, "arguments", aArguments);
2864 : }
2865 :
2866 : //*****************************************************************************
2867 : // nsGlobalWindow::nsIScriptObjectPrincipal
2868 : //*****************************************************************************
2869 :
2870 : nsIPrincipal*
2871 0 : nsGlobalWindow::GetPrincipal()
2872 : {
2873 0 : if (mDoc) {
2874 : // If we have a document, get the principal from the document
2875 0 : return mDoc->NodePrincipal();
2876 : }
2877 :
2878 0 : if (mDocumentPrincipal) {
2879 0 : return mDocumentPrincipal;
2880 : }
2881 :
2882 : // If we don't have a principal and we don't have a document we
2883 : // ask the parent window for the principal. This can happen when
2884 : // loading a frameset that has a <frame src="javascript:xxx">, in
2885 : // that case the global window is used in JS before we've loaded
2886 : // a document into the window.
2887 :
2888 : nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2889 0 : do_QueryInterface(GetParentInternal());
2890 :
2891 0 : if (objPrincipal) {
2892 0 : return objPrincipal->GetPrincipal();
2893 : }
2894 :
2895 0 : return nsnull;
2896 : }
2897 :
2898 : //*****************************************************************************
2899 : // nsGlobalWindow::nsIDOMWindow
2900 : //*****************************************************************************
2901 :
2902 : NS_IMETHODIMP
2903 0 : nsGlobalWindow::GetDocument(nsIDOMDocument** aDocument)
2904 : {
2905 : // This method *should* forward calls to the outer window, but since
2906 : // there's nothing here that *depends* on anything in the outer
2907 : // (GetDocShell() eliminates that dependency), we won't do that to
2908 : // avoid the extra virtual function call.
2909 :
2910 : // lazily instantiate an about:blank document if necessary, and if
2911 : // we have what it takes to do so. Note that domdoc here is the same
2912 : // thing as our mDocument, but we don't have to explicitly set the
2913 : // member variable because the docshell has already called
2914 : // SetNewDocument().
2915 : nsIDocShell *docShell;
2916 0 : if (!mDocument && (docShell = GetDocShell()))
2917 0 : nsCOMPtr<nsIDOMDocument> domdoc(do_GetInterface(docShell));
2918 :
2919 0 : NS_IF_ADDREF(*aDocument = mDocument);
2920 :
2921 0 : return NS_OK;
2922 : }
2923 :
2924 : NS_IMETHODIMP
2925 0 : nsGlobalWindow::GetWindow(nsIDOMWindow** aWindow)
2926 : {
2927 0 : FORWARD_TO_OUTER(GetWindow, (aWindow), NS_ERROR_NOT_INITIALIZED);
2928 :
2929 0 : *aWindow = static_cast<nsIDOMWindow*>(this);
2930 0 : NS_ADDREF(*aWindow);
2931 0 : return NS_OK;
2932 : }
2933 :
2934 : NS_IMETHODIMP
2935 0 : nsGlobalWindow::GetSelf(nsIDOMWindow** aWindow)
2936 : {
2937 0 : FORWARD_TO_OUTER(GetSelf, (aWindow), NS_ERROR_NOT_INITIALIZED);
2938 :
2939 0 : *aWindow = static_cast<nsIDOMWindow*>(this);
2940 0 : NS_ADDREF(*aWindow);
2941 0 : return NS_OK;
2942 : }
2943 :
2944 : NS_IMETHODIMP
2945 0 : nsGlobalWindow::GetNavigator(nsIDOMNavigator** aNavigator)
2946 : {
2947 0 : FORWARD_TO_INNER(GetNavigator, (aNavigator), NS_ERROR_NOT_INITIALIZED);
2948 :
2949 0 : *aNavigator = nsnull;
2950 :
2951 0 : if (!mNavigator) {
2952 0 : mNavigator = new Navigator(this);
2953 : }
2954 :
2955 0 : NS_ADDREF(*aNavigator = mNavigator);
2956 :
2957 0 : return NS_OK;
2958 : }
2959 :
2960 : NS_IMETHODIMP
2961 0 : nsGlobalWindow::GetScreen(nsIDOMScreen** aScreen)
2962 : {
2963 0 : FORWARD_TO_OUTER(GetScreen, (aScreen), NS_ERROR_NOT_INITIALIZED);
2964 :
2965 0 : *aScreen = nsnull;
2966 :
2967 0 : if (!mScreen && mDocShell) {
2968 0 : mScreen = new nsScreen(mDocShell);
2969 0 : if (!mScreen) {
2970 0 : return NS_ERROR_OUT_OF_MEMORY;
2971 : }
2972 : }
2973 :
2974 0 : NS_IF_ADDREF(*aScreen = mScreen);
2975 :
2976 0 : return NS_OK;
2977 : }
2978 :
2979 : NS_IMETHODIMP
2980 0 : nsGlobalWindow::GetHistory(nsIDOMHistory** aHistory)
2981 : {
2982 0 : FORWARD_TO_INNER(GetHistory, (aHistory), NS_ERROR_NOT_INITIALIZED);
2983 :
2984 0 : *aHistory = nsnull;
2985 :
2986 0 : if (!mHistory) {
2987 0 : mHistory = new nsHistory(this);
2988 0 : if (!mHistory) {
2989 0 : return NS_ERROR_OUT_OF_MEMORY;
2990 : }
2991 : }
2992 :
2993 0 : NS_IF_ADDREF(*aHistory = mHistory);
2994 0 : return NS_OK;
2995 : }
2996 :
2997 : NS_IMETHODIMP
2998 0 : nsGlobalWindow::GetPerformance(nsIDOMPerformance** aPerformance)
2999 : {
3000 0 : FORWARD_TO_INNER(GetPerformance, (aPerformance), NS_ERROR_NOT_INITIALIZED);
3001 :
3002 0 : *aPerformance = nsnull;
3003 :
3004 0 : if (nsGlobalWindow::HasPerformanceSupport()) {
3005 0 : if (!mPerformance) {
3006 0 : if (!mDoc) {
3007 0 : return NS_OK;
3008 : }
3009 0 : nsRefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
3010 0 : nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
3011 0 : bool timingEnabled = false;
3012 0 : if (!timedChannel ||
3013 0 : !NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) ||
3014 0 : !timingEnabled) {
3015 0 : timedChannel = nsnull;
3016 : }
3017 0 : if (timing) {
3018 0 : mPerformance = new nsPerformance(timing, timedChannel);
3019 : }
3020 : }
3021 0 : NS_IF_ADDREF(*aPerformance = mPerformance);
3022 : }
3023 0 : return NS_OK;
3024 : }
3025 :
3026 : /**
3027 : * GetScriptableParent is called when script reads window.parent.
3028 : *
3029 : * In contrast to GetRealParent, GetScriptableParent respects <iframe
3030 : * mozbrowser> boundaries, so if |this| is contained by an <iframe
3031 : * mozbrowser>, we will return |this| as its own parent.
3032 : */
3033 : NS_IMETHODIMP
3034 0 : nsGlobalWindow::GetScriptableParent(nsIDOMWindow** aParent)
3035 : {
3036 0 : FORWARD_TO_OUTER(GetScriptableParent, (aParent), NS_ERROR_NOT_INITIALIZED);
3037 :
3038 0 : *aParent = NULL;
3039 0 : if (!mDocShell) {
3040 0 : return NS_OK;
3041 : }
3042 :
3043 0 : bool isMozBrowser = false;
3044 0 : mDocShell->GetIsBrowserFrame(&isMozBrowser);
3045 0 : if (isMozBrowser) {
3046 0 : nsCOMPtr<nsIDOMWindow> parent = static_cast<nsIDOMWindow*>(this);
3047 0 : parent.swap(*aParent);
3048 0 : return NS_OK;
3049 : }
3050 :
3051 0 : return GetRealParent(aParent);
3052 : }
3053 :
3054 : /**
3055 : * nsIDOMWindow::GetParent (when called from C++) is just a wrapper around
3056 : * GetRealParent.
3057 : */
3058 : NS_IMETHODIMP
3059 0 : nsGlobalWindow::GetRealParent(nsIDOMWindow** aParent)
3060 : {
3061 0 : FORWARD_TO_OUTER(GetRealParent, (aParent), NS_ERROR_NOT_INITIALIZED);
3062 :
3063 0 : *aParent = nsnull;
3064 0 : if (!mDocShell) {
3065 0 : return NS_OK;
3066 : }
3067 :
3068 0 : nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3069 0 : NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
3070 :
3071 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
3072 0 : docShellAsItem->GetSameTypeParent(getter_AddRefs(parent));
3073 :
3074 0 : if (parent) {
3075 0 : nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(parent));
3076 0 : NS_ENSURE_SUCCESS(CallQueryInterface(globalObject.get(), aParent),
3077 : NS_ERROR_FAILURE);
3078 : }
3079 : else {
3080 0 : *aParent = static_cast<nsIDOMWindow*>(this);
3081 0 : NS_ADDREF(*aParent);
3082 : }
3083 0 : return NS_OK;
3084 : }
3085 :
3086 : /**
3087 : * GetScriptableTop is called when script reads window.top.
3088 : *
3089 : * In contrast to GetRealTop, GetScriptableTop respects <iframe mozbrowser>
3090 : * boundaries. If we encounter a window owned by an <iframe mozbrowser> while
3091 : * walking up the window hierarchy, we'll stop and return that window.
3092 : */
3093 : NS_IMETHODIMP
3094 0 : nsGlobalWindow::GetScriptableTop(nsIDOMWindow **aTop)
3095 : {
3096 0 : return GetTopImpl(aTop, /* aScriptable = */ true);
3097 : }
3098 :
3099 : /**
3100 : * nsIDOMWindow::GetTop (when called from C++) is just a wrapper around
3101 : * GetRealTop.
3102 : */
3103 : NS_IMETHODIMP
3104 0 : nsGlobalWindow::GetRealTop(nsIDOMWindow** aTop)
3105 : {
3106 0 : return GetTopImpl(aTop, /* aScriptable = */ false);
3107 : }
3108 :
3109 : nsresult
3110 0 : nsGlobalWindow::GetTopImpl(nsIDOMWindow** aTop, bool aScriptable)
3111 : {
3112 0 : FORWARD_TO_OUTER(GetTopImpl, (aTop, aScriptable), NS_ERROR_NOT_INITIALIZED);
3113 0 : *aTop = nsnull;
3114 :
3115 : // Walk up the parent chain.
3116 :
3117 0 : nsCOMPtr<nsIDOMWindow> prevParent = this;
3118 0 : nsCOMPtr<nsIDOMWindow> parent = this;
3119 0 : do {
3120 0 : if (!parent) {
3121 0 : break;
3122 : }
3123 :
3124 0 : prevParent = parent;
3125 :
3126 0 : nsCOMPtr<nsIDOMWindow> newParent;
3127 : nsresult rv;
3128 0 : if (aScriptable) {
3129 0 : rv = parent->GetScriptableParent(getter_AddRefs(newParent));
3130 : }
3131 : else {
3132 0 : rv = parent->GetParent(getter_AddRefs(newParent));
3133 : }
3134 0 : NS_ENSURE_SUCCESS(rv, rv);
3135 :
3136 0 : parent = newParent;
3137 :
3138 : } while (parent != prevParent);
3139 :
3140 0 : if (parent) {
3141 0 : parent.swap(*aTop);
3142 : }
3143 :
3144 0 : return NS_OK;
3145 : }
3146 :
3147 : NS_IMETHODIMP
3148 0 : nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
3149 : {
3150 0 : FORWARD_TO_OUTER(GetContent, (aContent), NS_ERROR_NOT_INITIALIZED);
3151 :
3152 0 : *aContent = nsnull;
3153 :
3154 0 : nsCOMPtr<nsIDocShellTreeItem> primaryContent;
3155 :
3156 0 : if (!nsContentUtils::IsCallerChrome()) {
3157 : // If we're called by non-chrome code, make sure we don't return
3158 : // the primary content window if the calling tab is hidden. In
3159 : // such a case we return the same-type root in the hidden tab,
3160 : // which is "good enough", for now.
3161 0 : nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mDocShell));
3162 :
3163 0 : if (baseWin) {
3164 0 : bool visible = false;
3165 0 : baseWin->GetVisibility(&visible);
3166 :
3167 0 : if (!visible) {
3168 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
3169 :
3170 0 : treeItem->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));
3171 : }
3172 : }
3173 : }
3174 :
3175 0 : if (!primaryContent) {
3176 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
3177 0 : GetTreeOwner(getter_AddRefs(treeOwner));
3178 0 : NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
3179 :
3180 0 : treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
3181 : }
3182 :
3183 0 : nsCOMPtr<nsIDOMWindow> domWindow(do_GetInterface(primaryContent));
3184 0 : NS_IF_ADDREF(*aContent = domWindow);
3185 :
3186 0 : return NS_OK;
3187 : }
3188 :
3189 : NS_IMETHODIMP
3190 0 : nsGlobalWindow::GetPrompter(nsIPrompt** aPrompt)
3191 : {
3192 0 : FORWARD_TO_OUTER(GetPrompter, (aPrompt), NS_ERROR_NOT_INITIALIZED);
3193 :
3194 0 : if (!mDocShell)
3195 0 : return NS_ERROR_FAILURE;
3196 :
3197 0 : nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
3198 0 : NS_ENSURE_TRUE(prompter, NS_ERROR_NO_INTERFACE);
3199 :
3200 0 : NS_ADDREF(*aPrompt = prompter);
3201 0 : return NS_OK;
3202 : }
3203 :
3204 : NS_IMETHODIMP
3205 0 : nsGlobalWindow::GetMenubar(nsIDOMBarProp** aMenubar)
3206 : {
3207 0 : FORWARD_TO_OUTER(GetMenubar, (aMenubar), NS_ERROR_NOT_INITIALIZED);
3208 :
3209 0 : *aMenubar = nsnull;
3210 :
3211 0 : if (!mMenubar) {
3212 0 : mMenubar = new nsMenubarProp(this);
3213 0 : if (!mMenubar) {
3214 0 : return NS_ERROR_OUT_OF_MEMORY;
3215 : }
3216 : }
3217 :
3218 0 : NS_ADDREF(*aMenubar = mMenubar);
3219 :
3220 0 : return NS_OK;
3221 : }
3222 :
3223 : NS_IMETHODIMP
3224 0 : nsGlobalWindow::GetToolbar(nsIDOMBarProp** aToolbar)
3225 : {
3226 0 : FORWARD_TO_OUTER(GetToolbar, (aToolbar), NS_ERROR_NOT_INITIALIZED);
3227 :
3228 0 : *aToolbar = nsnull;
3229 :
3230 0 : if (!mToolbar) {
3231 0 : mToolbar = new nsToolbarProp(this);
3232 0 : if (!mToolbar) {
3233 0 : return NS_ERROR_OUT_OF_MEMORY;
3234 : }
3235 : }
3236 :
3237 0 : NS_ADDREF(*aToolbar = mToolbar);
3238 :
3239 0 : return NS_OK;
3240 : }
3241 :
3242 : NS_IMETHODIMP
3243 0 : nsGlobalWindow::GetLocationbar(nsIDOMBarProp** aLocationbar)
3244 : {
3245 0 : FORWARD_TO_OUTER(GetLocationbar, (aLocationbar), NS_ERROR_NOT_INITIALIZED);
3246 :
3247 0 : *aLocationbar = nsnull;
3248 :
3249 0 : if (!mLocationbar) {
3250 0 : mLocationbar = new nsLocationbarProp(this);
3251 0 : if (!mLocationbar) {
3252 0 : return NS_ERROR_OUT_OF_MEMORY;
3253 : }
3254 : }
3255 :
3256 0 : NS_ADDREF(*aLocationbar = mLocationbar);
3257 :
3258 0 : return NS_OK;
3259 : }
3260 :
3261 : NS_IMETHODIMP
3262 0 : nsGlobalWindow::GetPersonalbar(nsIDOMBarProp** aPersonalbar)
3263 : {
3264 0 : FORWARD_TO_OUTER(GetPersonalbar, (aPersonalbar), NS_ERROR_NOT_INITIALIZED);
3265 :
3266 0 : *aPersonalbar = nsnull;
3267 :
3268 0 : if (!mPersonalbar) {
3269 0 : mPersonalbar = new nsPersonalbarProp(this);
3270 0 : if (!mPersonalbar) {
3271 0 : return NS_ERROR_OUT_OF_MEMORY;
3272 : }
3273 : }
3274 :
3275 0 : NS_ADDREF(*aPersonalbar = mPersonalbar);
3276 :
3277 0 : return NS_OK;
3278 : }
3279 :
3280 : NS_IMETHODIMP
3281 0 : nsGlobalWindow::GetStatusbar(nsIDOMBarProp** aStatusbar)
3282 : {
3283 0 : FORWARD_TO_OUTER(GetStatusbar, (aStatusbar), NS_ERROR_NOT_INITIALIZED);
3284 :
3285 0 : *aStatusbar = nsnull;
3286 :
3287 0 : if (!mStatusbar) {
3288 0 : mStatusbar = new nsStatusbarProp(this);
3289 0 : if (!mStatusbar) {
3290 0 : return NS_ERROR_OUT_OF_MEMORY;
3291 : }
3292 : }
3293 :
3294 0 : NS_ADDREF(*aStatusbar = mStatusbar);
3295 :
3296 0 : return NS_OK;
3297 : }
3298 :
3299 : NS_IMETHODIMP
3300 0 : nsGlobalWindow::GetScrollbars(nsIDOMBarProp** aScrollbars)
3301 : {
3302 0 : FORWARD_TO_OUTER(GetScrollbars, (aScrollbars), NS_ERROR_NOT_INITIALIZED);
3303 :
3304 0 : *aScrollbars = nsnull;
3305 :
3306 0 : if (!mScrollbars) {
3307 0 : mScrollbars = new nsScrollbarsProp(this);
3308 0 : if (!mScrollbars) {
3309 0 : return NS_ERROR_OUT_OF_MEMORY;
3310 : }
3311 : }
3312 :
3313 0 : NS_ADDREF(*aScrollbars = mScrollbars);
3314 :
3315 0 : return NS_OK;
3316 : }
3317 :
3318 : NS_IMETHODIMP
3319 0 : nsGlobalWindow::GetClosed(bool* aClosed)
3320 : {
3321 0 : FORWARD_TO_OUTER(GetClosed, (aClosed), NS_ERROR_NOT_INITIALIZED);
3322 :
3323 : // If someone called close(), or if we don't have a docshell, we're
3324 : // closed.
3325 0 : *aClosed = mIsClosed || !mDocShell;
3326 :
3327 0 : return NS_OK;
3328 : }
3329 :
3330 : NS_IMETHODIMP
3331 0 : nsGlobalWindow::GetFrames(nsIDOMWindowCollection** aFrames)
3332 : {
3333 0 : FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
3334 :
3335 0 : *aFrames = nsnull;
3336 :
3337 0 : if (!mFrames && mDocShell) {
3338 0 : mFrames = new nsDOMWindowList(mDocShell);
3339 0 : if (!mFrames) {
3340 0 : return NS_ERROR_OUT_OF_MEMORY;
3341 : }
3342 : }
3343 :
3344 0 : *aFrames = static_cast<nsIDOMWindowCollection *>(mFrames);
3345 0 : NS_IF_ADDREF(*aFrames);
3346 0 : return NS_OK;
3347 : }
3348 :
3349 : NS_IMETHODIMP
3350 0 : nsGlobalWindow::GetApplicationCache(nsIDOMOfflineResourceList **aApplicationCache)
3351 : {
3352 0 : FORWARD_TO_INNER(GetApplicationCache, (aApplicationCache), NS_ERROR_UNEXPECTED);
3353 :
3354 0 : NS_ENSURE_ARG_POINTER(aApplicationCache);
3355 :
3356 0 : if (!mApplicationCache) {
3357 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(GetDocShell()));
3358 0 : if (!webNav) {
3359 0 : return NS_ERROR_FAILURE;
3360 : }
3361 :
3362 0 : nsCOMPtr<nsIURI> uri;
3363 0 : nsresult rv = webNav->GetCurrentURI(getter_AddRefs(uri));
3364 0 : NS_ENSURE_SUCCESS(rv, rv);
3365 :
3366 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
3367 0 : nsCOMPtr<nsIURI> manifestURI;
3368 0 : nsContentUtils::GetOfflineAppManifest(doc, getter_AddRefs(manifestURI));
3369 :
3370 : nsRefPtr<nsDOMOfflineResourceList> applicationCache =
3371 0 : new nsDOMOfflineResourceList(manifestURI, uri, this);
3372 0 : NS_ENSURE_TRUE(applicationCache, NS_ERROR_OUT_OF_MEMORY);
3373 :
3374 0 : applicationCache->Init();
3375 :
3376 0 : mApplicationCache = applicationCache;
3377 : }
3378 :
3379 0 : NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
3380 :
3381 0 : return NS_OK;
3382 : }
3383 :
3384 : NS_IMETHODIMP
3385 0 : nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
3386 : {
3387 : #ifdef MOZ_DISABLE_DOMCRYPTO
3388 : return NS_ERROR_NOT_IMPLEMENTED;
3389 : #else
3390 0 : FORWARD_TO_OUTER(GetCrypto, (aCrypto), NS_ERROR_NOT_INITIALIZED);
3391 :
3392 0 : if (!mCrypto) {
3393 0 : mCrypto = do_CreateInstance(kCryptoContractID);
3394 : }
3395 :
3396 0 : NS_IF_ADDREF(*aCrypto = mCrypto);
3397 :
3398 0 : return NS_OK;
3399 : #endif
3400 : }
3401 :
3402 : NS_IMETHODIMP
3403 0 : nsGlobalWindow::GetPkcs11(nsIDOMPkcs11** aPkcs11)
3404 : {
3405 0 : *aPkcs11 = nsnull;
3406 0 : return NS_OK;
3407 : }
3408 :
3409 : NS_IMETHODIMP
3410 0 : nsGlobalWindow::GetControllers(nsIControllers** aResult)
3411 : {
3412 0 : FORWARD_TO_OUTER(GetControllers, (aResult), NS_ERROR_NOT_INITIALIZED);
3413 :
3414 0 : if (!mControllers) {
3415 : nsresult rv;
3416 0 : mControllers = do_CreateInstance(kXULControllersCID, &rv);
3417 0 : NS_ENSURE_SUCCESS(rv, rv);
3418 :
3419 : // Add in the default controller
3420 : nsCOMPtr<nsIController> controller = do_CreateInstance(
3421 0 : NS_WINDOWCONTROLLER_CONTRACTID, &rv);
3422 0 : NS_ENSURE_SUCCESS(rv, rv);
3423 :
3424 0 : mControllers->InsertControllerAt(0, controller);
3425 0 : nsCOMPtr<nsIControllerContext> controllerContext = do_QueryInterface(controller);
3426 0 : if (!controllerContext) return NS_ERROR_FAILURE;
3427 :
3428 0 : controllerContext->SetCommandContext(static_cast<nsIDOMWindow*>(this));
3429 : }
3430 :
3431 0 : *aResult = mControllers;
3432 0 : NS_ADDREF(*aResult);
3433 0 : return NS_OK;
3434 : }
3435 :
3436 : NS_IMETHODIMP
3437 0 : nsGlobalWindow::GetOpener(nsIDOMWindow** aOpener)
3438 : {
3439 0 : FORWARD_TO_OUTER(GetOpener, (aOpener), NS_ERROR_NOT_INITIALIZED);
3440 :
3441 0 : *aOpener = nsnull;
3442 :
3443 0 : nsCOMPtr<nsPIDOMWindow> opener = do_QueryReferent(mOpener);
3444 0 : if (!opener) {
3445 0 : return NS_OK;
3446 : }
3447 :
3448 : // First, check if we were called from a privileged chrome script
3449 0 : if (nsContentUtils::IsCallerTrustedForRead()) {
3450 0 : NS_ADDREF(*aOpener = opener);
3451 0 : return NS_OK;
3452 : }
3453 :
3454 0 : nsCOMPtr<nsPIDOMWindow> openerPwin(do_QueryInterface(opener));
3455 0 : if (!openerPwin) {
3456 0 : return NS_OK;
3457 : }
3458 :
3459 : // First, ensure that we're not handing back a chrome window.
3460 0 : nsGlobalWindow *win = static_cast<nsGlobalWindow *>(openerPwin.get());
3461 0 : if (win->IsChromeWindow()) {
3462 0 : return NS_OK;
3463 : }
3464 :
3465 : // We don't want to reveal the opener if the opener is a mail window,
3466 : // because opener can be used to spoof the contents of a message (bug 105050).
3467 : // So, we look in the opener's root docshell to see if it's a mail window.
3468 : nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
3469 0 : do_QueryInterface(openerPwin->GetDocShell());
3470 :
3471 0 : if (docShellAsItem) {
3472 0 : nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
3473 0 : docShellAsItem->GetRootTreeItem(getter_AddRefs(openerRootItem));
3474 0 : nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
3475 0 : if (openerRootDocShell) {
3476 : PRUint32 appType;
3477 0 : nsresult rv = openerRootDocShell->GetAppType(&appType);
3478 0 : if (NS_SUCCEEDED(rv) && appType != nsIDocShell::APP_TYPE_MAIL) {
3479 0 : *aOpener = opener;
3480 : }
3481 : }
3482 : }
3483 :
3484 0 : NS_IF_ADDREF(*aOpener);
3485 0 : return NS_OK;
3486 : }
3487 :
3488 : NS_IMETHODIMP
3489 0 : nsGlobalWindow::SetOpener(nsIDOMWindow* aOpener)
3490 : {
3491 : // check if we were called from a privileged chrome script.
3492 : // If not, opener is settable only to null.
3493 0 : if (aOpener && !nsContentUtils::IsCallerTrustedForWrite()) {
3494 0 : return NS_OK;
3495 : }
3496 :
3497 0 : SetOpenerWindow(aOpener, false);
3498 :
3499 0 : return NS_OK;
3500 : }
3501 :
3502 : NS_IMETHODIMP
3503 0 : nsGlobalWindow::GetStatus(nsAString& aStatus)
3504 : {
3505 0 : FORWARD_TO_OUTER(GetStatus, (aStatus), NS_ERROR_NOT_INITIALIZED);
3506 :
3507 0 : aStatus = mStatus;
3508 0 : return NS_OK;
3509 : }
3510 :
3511 : NS_IMETHODIMP
3512 0 : nsGlobalWindow::SetStatus(const nsAString& aStatus)
3513 : {
3514 0 : FORWARD_TO_OUTER(SetStatus, (aStatus), NS_ERROR_NOT_INITIALIZED);
3515 :
3516 : /*
3517 : * If caller is not chrome and dom.disable_window_status_change is true,
3518 : * prevent setting window.status by exiting early
3519 : */
3520 :
3521 0 : if (!CanSetProperty("dom.disable_window_status_change")) {
3522 0 : return NS_OK;
3523 : }
3524 :
3525 0 : mStatus = aStatus;
3526 :
3527 0 : nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3528 0 : GetWebBrowserChrome(getter_AddRefs(browserChrome));
3529 0 : if(browserChrome) {
3530 0 : browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
3531 0 : PromiseFlatString(aStatus).get());
3532 : }
3533 :
3534 0 : return NS_OK;
3535 : }
3536 :
3537 : NS_IMETHODIMP
3538 0 : nsGlobalWindow::GetDefaultStatus(nsAString& aDefaultStatus)
3539 : {
3540 0 : FORWARD_TO_OUTER(GetDefaultStatus, (aDefaultStatus),
3541 : NS_ERROR_NOT_INITIALIZED);
3542 :
3543 0 : aDefaultStatus = mDefaultStatus;
3544 0 : return NS_OK;
3545 : }
3546 :
3547 : NS_IMETHODIMP
3548 0 : nsGlobalWindow::SetDefaultStatus(const nsAString& aDefaultStatus)
3549 : {
3550 0 : FORWARD_TO_OUTER(SetDefaultStatus, (aDefaultStatus),
3551 : NS_ERROR_NOT_INITIALIZED);
3552 :
3553 : /*
3554 : * If caller is not chrome and dom.disable_window_status_change is true,
3555 : * prevent setting window.defaultStatus by exiting early
3556 : */
3557 :
3558 0 : if (!CanSetProperty("dom.disable_window_status_change")) {
3559 0 : return NS_OK;
3560 : }
3561 :
3562 0 : mDefaultStatus = aDefaultStatus;
3563 :
3564 0 : nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3565 0 : GetWebBrowserChrome(getter_AddRefs(browserChrome));
3566 0 : if (browserChrome) {
3567 0 : browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT_DEFAULT,
3568 0 : PromiseFlatString(aDefaultStatus).get());
3569 : }
3570 :
3571 0 : return NS_OK;
3572 : }
3573 :
3574 : NS_IMETHODIMP
3575 0 : nsGlobalWindow::GetName(nsAString& aName)
3576 : {
3577 0 : FORWARD_TO_OUTER(GetName, (aName), NS_ERROR_NOT_INITIALIZED);
3578 :
3579 0 : nsXPIDLString name;
3580 0 : nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3581 0 : if (docShellAsItem)
3582 0 : docShellAsItem->GetName(getter_Copies(name));
3583 :
3584 0 : aName.Assign(name);
3585 0 : return NS_OK;
3586 : }
3587 :
3588 : NS_IMETHODIMP
3589 0 : nsGlobalWindow::SetName(const nsAString& aName)
3590 : {
3591 0 : FORWARD_TO_OUTER(SetName, (aName), NS_ERROR_NOT_INITIALIZED);
3592 :
3593 0 : nsresult result = NS_OK;
3594 0 : nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3595 0 : if (docShellAsItem)
3596 0 : result = docShellAsItem->SetName(PromiseFlatString(aName).get());
3597 0 : return result;
3598 : }
3599 :
3600 : // Helper functions used by many methods below.
3601 : PRInt32
3602 0 : nsGlobalWindow::DevToCSSIntPixels(PRInt32 px)
3603 : {
3604 0 : if (!mDocShell)
3605 0 : return px; // assume 1:1
3606 :
3607 0 : nsRefPtr<nsPresContext> presContext;
3608 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
3609 0 : if (!presContext)
3610 0 : return px;
3611 :
3612 0 : return presContext->DevPixelsToIntCSSPixels(px);
3613 : }
3614 :
3615 : PRInt32
3616 0 : nsGlobalWindow::CSSToDevIntPixels(PRInt32 px)
3617 : {
3618 0 : if (!mDocShell)
3619 0 : return px; // assume 1:1
3620 :
3621 0 : nsRefPtr<nsPresContext> presContext;
3622 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
3623 0 : if (!presContext)
3624 0 : return px;
3625 :
3626 0 : return presContext->CSSPixelsToDevPixels(px);
3627 : }
3628 :
3629 : nsIntSize
3630 0 : nsGlobalWindow::DevToCSSIntPixels(nsIntSize px)
3631 : {
3632 0 : if (!mDocShell)
3633 0 : return px; // assume 1:1
3634 :
3635 0 : nsRefPtr<nsPresContext> presContext;
3636 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
3637 0 : if (!presContext)
3638 0 : return px;
3639 :
3640 : return nsIntSize(
3641 : presContext->DevPixelsToIntCSSPixels(px.width),
3642 0 : presContext->DevPixelsToIntCSSPixels(px.height));
3643 : }
3644 :
3645 : nsIntSize
3646 0 : nsGlobalWindow::CSSToDevIntPixels(nsIntSize px)
3647 : {
3648 0 : if (!mDocShell)
3649 0 : return px; // assume 1:1
3650 :
3651 0 : nsRefPtr<nsPresContext> presContext;
3652 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
3653 0 : if (!presContext)
3654 0 : return px;
3655 :
3656 : return nsIntSize(
3657 : presContext->CSSPixelsToDevPixels(px.width),
3658 0 : presContext->CSSPixelsToDevPixels(px.height));
3659 : }
3660 :
3661 :
3662 : NS_IMETHODIMP
3663 0 : nsGlobalWindow::GetInnerWidth(PRInt32* aInnerWidth)
3664 : {
3665 0 : FORWARD_TO_OUTER(GetInnerWidth, (aInnerWidth), NS_ERROR_NOT_INITIALIZED);
3666 :
3667 0 : NS_ENSURE_STATE(mDocShell);
3668 :
3669 0 : EnsureSizeUpToDate();
3670 :
3671 0 : nsRefPtr<nsPresContext> presContext;
3672 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
3673 :
3674 0 : if (presContext) {
3675 0 : nsRect shellArea = presContext->GetVisibleArea();
3676 0 : *aInnerWidth = nsPresContext::AppUnitsToIntCSSPixels(shellArea.width);
3677 : } else {
3678 0 : *aInnerWidth = 0;
3679 : }
3680 :
3681 0 : return NS_OK;
3682 : }
3683 :
3684 : NS_IMETHODIMP
3685 0 : nsGlobalWindow::SetInnerWidth(PRInt32 aInnerWidth)
3686 : {
3687 0 : FORWARD_TO_OUTER(SetInnerWidth, (aInnerWidth), NS_ERROR_NOT_INITIALIZED);
3688 :
3689 0 : NS_ENSURE_STATE(mDocShell);
3690 :
3691 : /*
3692 : * If caller is not chrome and the user has not explicitly exempted the site,
3693 : * prevent setting window.innerWidth by exiting early
3694 : */
3695 0 : if (!CanMoveResizeWindows() || IsFrame()) {
3696 0 : return NS_OK;
3697 : }
3698 :
3699 0 : NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&aInnerWidth, nsnull),
3700 : NS_ERROR_FAILURE);
3701 :
3702 :
3703 0 : nsRefPtr<nsIPresShell> presShell;
3704 0 : mDocShell->GetPresShell(getter_AddRefs(presShell));
3705 :
3706 0 : if (presShell && presShell->GetIsViewportOverridden())
3707 : {
3708 0 : nscoord height = 0;
3709 0 : nscoord width = 0;
3710 :
3711 0 : nsRefPtr<nsPresContext> presContext;
3712 0 : presContext = presShell->GetPresContext();
3713 :
3714 0 : nsRect shellArea = presContext->GetVisibleArea();
3715 0 : height = shellArea.height;
3716 0 : width = nsPresContext::CSSPixelsToAppUnits(aInnerWidth);
3717 0 : return SetCSSViewportWidthAndHeight(width, height);
3718 : }
3719 : else
3720 : {
3721 0 : PRInt32 height = 0;
3722 0 : PRInt32 width = 0;
3723 :
3724 0 : nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
3725 0 : docShellAsWin->GetSize(&width, &height);
3726 0 : width = CSSToDevIntPixels(aInnerWidth);
3727 0 : return SetDocShellWidthAndHeight(width, height);
3728 : }
3729 : }
3730 :
3731 : NS_IMETHODIMP
3732 0 : nsGlobalWindow::GetInnerHeight(PRInt32* aInnerHeight)
3733 : {
3734 0 : FORWARD_TO_OUTER(GetInnerHeight, (aInnerHeight), NS_ERROR_NOT_INITIALIZED);
3735 :
3736 0 : NS_ENSURE_STATE(mDocShell);
3737 :
3738 0 : EnsureSizeUpToDate();
3739 :
3740 0 : nsRefPtr<nsPresContext> presContext;
3741 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
3742 :
3743 0 : if (presContext) {
3744 0 : nsRect shellArea = presContext->GetVisibleArea();
3745 0 : *aInnerHeight = nsPresContext::AppUnitsToIntCSSPixels(shellArea.height);
3746 : } else {
3747 0 : *aInnerHeight = 0;
3748 : }
3749 0 : return NS_OK;
3750 : }
3751 :
3752 : NS_IMETHODIMP
3753 0 : nsGlobalWindow::SetInnerHeight(PRInt32 aInnerHeight)
3754 : {
3755 0 : FORWARD_TO_OUTER(SetInnerHeight, (aInnerHeight), NS_ERROR_NOT_INITIALIZED);
3756 :
3757 0 : NS_ENSURE_STATE(mDocShell);
3758 :
3759 : /*
3760 : * If caller is not chrome and the user has not explicitly exempted the site,
3761 : * prevent setting window.innerHeight by exiting early
3762 : */
3763 0 : if (!CanMoveResizeWindows() || IsFrame()) {
3764 0 : return NS_OK;
3765 : }
3766 :
3767 0 : NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(nsnull, &aInnerHeight),
3768 : NS_ERROR_FAILURE);
3769 :
3770 0 : nsRefPtr<nsIPresShell> presShell;
3771 0 : mDocShell->GetPresShell(getter_AddRefs(presShell));
3772 :
3773 0 : if (presShell && presShell->GetIsViewportOverridden())
3774 : {
3775 0 : nscoord height = 0;
3776 0 : nscoord width = 0;
3777 :
3778 0 : nsRefPtr<nsPresContext> presContext;
3779 0 : presContext = presShell->GetPresContext();
3780 :
3781 0 : nsRect shellArea = presContext->GetVisibleArea();
3782 0 : width = shellArea.width;
3783 0 : height = nsPresContext::CSSPixelsToAppUnits(aInnerHeight);
3784 0 : return SetCSSViewportWidthAndHeight(width, height);
3785 : }
3786 : else
3787 : {
3788 0 : PRInt32 height = 0;
3789 0 : PRInt32 width = 0;
3790 :
3791 0 : nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
3792 0 : docShellAsWin->GetSize(&width, &height);
3793 0 : height = CSSToDevIntPixels(aInnerHeight);
3794 0 : return SetDocShellWidthAndHeight(width, height);
3795 : }
3796 : }
3797 :
3798 : nsresult
3799 0 : nsGlobalWindow::GetOuterSize(nsIntSize* aSizeCSSPixels)
3800 : {
3801 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3802 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3803 0 : NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3804 :
3805 : nsGlobalWindow* rootWindow =
3806 0 : static_cast<nsGlobalWindow *>(GetPrivateRoot());
3807 0 : if (rootWindow) {
3808 0 : rootWindow->FlushPendingNotifications(Flush_Layout);
3809 : }
3810 :
3811 0 : nsIntSize sizeDevPixels;
3812 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&sizeDevPixels.width,
3813 : &sizeDevPixels.height),
3814 : NS_ERROR_FAILURE);
3815 :
3816 0 : *aSizeCSSPixels = DevToCSSIntPixels(sizeDevPixels);
3817 0 : return NS_OK;
3818 : }
3819 :
3820 : NS_IMETHODIMP
3821 0 : nsGlobalWindow::GetOuterWidth(PRInt32* aOuterWidth)
3822 : {
3823 0 : FORWARD_TO_OUTER(GetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
3824 :
3825 0 : nsIntSize sizeCSSPixels;
3826 0 : nsresult rv = GetOuterSize(&sizeCSSPixels);
3827 0 : NS_ENSURE_SUCCESS(rv, rv);
3828 :
3829 0 : *aOuterWidth = sizeCSSPixels.width;
3830 0 : return NS_OK;
3831 : }
3832 :
3833 : NS_IMETHODIMP
3834 0 : nsGlobalWindow::GetOuterHeight(PRInt32* aOuterHeight)
3835 : {
3836 0 : FORWARD_TO_OUTER(GetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
3837 :
3838 0 : nsIntSize sizeCSSPixels;
3839 0 : nsresult rv = GetOuterSize(&sizeCSSPixels);
3840 0 : NS_ENSURE_SUCCESS(rv, rv);
3841 :
3842 0 : *aOuterHeight = sizeCSSPixels.height;
3843 0 : return NS_OK;
3844 : }
3845 :
3846 : nsresult
3847 0 : nsGlobalWindow::SetOuterSize(PRInt32 aLengthCSSPixels, bool aIsWidth)
3848 : {
3849 : /*
3850 : * If caller is not chrome and the user has not explicitly exempted the site,
3851 : * prevent setting window.outerWidth by exiting early
3852 : */
3853 :
3854 0 : if (!CanMoveResizeWindows() || IsFrame()) {
3855 0 : return NS_OK;
3856 : }
3857 :
3858 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3859 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3860 0 : NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3861 :
3862 0 : NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(
3863 : aIsWidth ? &aLengthCSSPixels : nsnull,
3864 : aIsWidth ? nsnull : &aLengthCSSPixels),
3865 : NS_ERROR_FAILURE);
3866 :
3867 : PRInt32 width, height;
3868 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&width, &height), NS_ERROR_FAILURE);
3869 :
3870 0 : PRInt32 lengthDevPixels = CSSToDevIntPixels(aLengthCSSPixels);
3871 0 : if (aIsWidth) {
3872 0 : width = lengthDevPixels;
3873 : } else {
3874 0 : height = lengthDevPixels;
3875 : }
3876 0 : return treeOwnerAsWin->SetSize(width, height, true);
3877 : }
3878 :
3879 : NS_IMETHODIMP
3880 0 : nsGlobalWindow::SetOuterWidth(PRInt32 aOuterWidth)
3881 : {
3882 0 : FORWARD_TO_OUTER(SetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
3883 :
3884 0 : return SetOuterSize(aOuterWidth, true);
3885 : }
3886 :
3887 : NS_IMETHODIMP
3888 0 : nsGlobalWindow::SetOuterHeight(PRInt32 aOuterHeight)
3889 : {
3890 0 : FORWARD_TO_OUTER(SetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
3891 :
3892 0 : return SetOuterSize(aOuterHeight, false);
3893 : }
3894 :
3895 : NS_IMETHODIMP
3896 0 : nsGlobalWindow::GetScreenX(PRInt32* aScreenX)
3897 : {
3898 0 : FORWARD_TO_OUTER(GetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3899 :
3900 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3901 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3902 0 : NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3903 :
3904 : PRInt32 x, y;
3905 :
3906 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3907 : NS_ERROR_FAILURE);
3908 :
3909 0 : *aScreenX = DevToCSSIntPixels(x);
3910 0 : return NS_OK;
3911 : }
3912 :
3913 : nsRect
3914 0 : nsGlobalWindow::GetInnerScreenRect()
3915 : {
3916 0 : if (!mDocShell)
3917 0 : return nsRect();
3918 :
3919 : nsGlobalWindow* rootWindow =
3920 0 : static_cast<nsGlobalWindow*>(GetPrivateRoot());
3921 0 : if (rootWindow) {
3922 0 : rootWindow->FlushPendingNotifications(Flush_Layout);
3923 : }
3924 :
3925 0 : nsCOMPtr<nsIPresShell> presShell;
3926 0 : mDocShell->GetPresShell(getter_AddRefs(presShell));
3927 0 : if (!presShell)
3928 0 : return nsRect();
3929 0 : nsIFrame* rootFrame = presShell->GetRootFrame();
3930 0 : if (!rootFrame)
3931 0 : return nsRect();
3932 :
3933 0 : return rootFrame->GetScreenRectInAppUnits();
3934 : }
3935 :
3936 : NS_IMETHODIMP
3937 0 : nsGlobalWindow::GetMozInnerScreenX(float* aScreenX)
3938 : {
3939 0 : FORWARD_TO_OUTER(GetMozInnerScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3940 :
3941 0 : nsRect r = GetInnerScreenRect();
3942 0 : *aScreenX = nsPresContext::AppUnitsToFloatCSSPixels(r.x);
3943 0 : return NS_OK;
3944 : }
3945 :
3946 : NS_IMETHODIMP
3947 0 : nsGlobalWindow::GetMozInnerScreenY(float* aScreenY)
3948 : {
3949 0 : FORWARD_TO_OUTER(GetMozInnerScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
3950 :
3951 0 : nsRect r = GetInnerScreenRect();
3952 0 : *aScreenY = nsPresContext::AppUnitsToFloatCSSPixels(r.y);
3953 0 : return NS_OK;
3954 : }
3955 :
3956 : NS_IMETHODIMP
3957 0 : nsGlobalWindow::GetMozPaintCount(PRUint64* aResult)
3958 : {
3959 0 : FORWARD_TO_OUTER(GetMozPaintCount, (aResult), NS_ERROR_NOT_INITIALIZED);
3960 :
3961 0 : *aResult = 0;
3962 :
3963 0 : if (!mDocShell)
3964 0 : return NS_OK;
3965 :
3966 0 : nsCOMPtr<nsIPresShell> presShell;
3967 0 : mDocShell->GetPresShell(getter_AddRefs(presShell));
3968 0 : if (!presShell)
3969 0 : return NS_OK;
3970 :
3971 0 : *aResult = presShell->GetPaintCount();
3972 0 : return NS_OK;
3973 : }
3974 :
3975 : NS_IMETHODIMP
3976 0 : nsGlobalWindow::MozRequestAnimationFrame(nsIFrameRequestCallback* aCallback,
3977 : PRInt32 *aHandle)
3978 : {
3979 0 : FORWARD_TO_INNER(MozRequestAnimationFrame, (aCallback, aHandle),
3980 : NS_ERROR_NOT_INITIALIZED);
3981 :
3982 0 : if (!mDoc) {
3983 0 : return NS_OK;
3984 : }
3985 :
3986 0 : if (!aCallback) {
3987 0 : mDoc->WarnOnceAbout(nsIDocument::eMozBeforePaint);
3988 0 : return NS_ERROR_XPC_BAD_CONVERT_JS;
3989 : }
3990 :
3991 0 : return mDoc->ScheduleFrameRequestCallback(aCallback, aHandle);
3992 : }
3993 :
3994 : NS_IMETHODIMP
3995 0 : nsGlobalWindow::MozCancelRequestAnimationFrame(PRInt32 aHandle)
3996 : {
3997 0 : return MozCancelAnimationFrame(aHandle);
3998 : }
3999 :
4000 : NS_IMETHODIMP
4001 0 : nsGlobalWindow::MozCancelAnimationFrame(PRInt32 aHandle)
4002 : {
4003 0 : FORWARD_TO_INNER(MozCancelAnimationFrame, (aHandle),
4004 : NS_ERROR_NOT_INITIALIZED);
4005 :
4006 0 : if (!mDoc) {
4007 0 : return NS_OK;
4008 : }
4009 :
4010 0 : mDoc->CancelFrameRequestCallback(aHandle);
4011 0 : return NS_OK;
4012 : }
4013 :
4014 : NS_IMETHODIMP
4015 0 : nsGlobalWindow::GetMozAnimationStartTime(PRInt64 *aTime)
4016 : {
4017 0 : FORWARD_TO_INNER(GetMozAnimationStartTime, (aTime), NS_ERROR_NOT_INITIALIZED);
4018 :
4019 0 : if (mDoc) {
4020 0 : nsIPresShell* presShell = mDoc->GetShell();
4021 0 : if (presShell) {
4022 : *aTime = presShell->GetPresContext()->RefreshDriver()->
4023 0 : MostRecentRefreshEpochTime() / PR_USEC_PER_MSEC;
4024 0 : return NS_OK;
4025 : }
4026 : }
4027 :
4028 : // If all else fails, just be compatible with Date.now()
4029 0 : *aTime = JS_Now() / PR_USEC_PER_MSEC;
4030 0 : return NS_OK;
4031 : }
4032 :
4033 : NS_IMETHODIMP
4034 0 : nsGlobalWindow::MatchMedia(const nsAString& aMediaQueryList,
4035 : nsIDOMMediaQueryList** aResult)
4036 : {
4037 : // FIXME: This whole forward-to-outer and then get a pres
4038 : // shell/context off the docshell dance is sort of silly; it'd make
4039 : // more sense to forward to the inner, but it's what everyone else
4040 : // (GetSelection, GetScrollXY, etc.) does around here.
4041 0 : FORWARD_TO_OUTER(MatchMedia, (aMediaQueryList, aResult),
4042 : NS_ERROR_NOT_INITIALIZED);
4043 :
4044 0 : *aResult = nsnull;
4045 :
4046 0 : if (!mDocShell)
4047 0 : return NS_OK;
4048 :
4049 0 : nsRefPtr<nsPresContext> presContext;
4050 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
4051 :
4052 0 : if (!presContext)
4053 0 : return NS_OK;
4054 :
4055 0 : presContext->MatchMedia(aMediaQueryList, aResult);
4056 0 : return NS_OK;
4057 : }
4058 :
4059 : NS_IMETHODIMP
4060 0 : nsGlobalWindow::SetScreenX(PRInt32 aScreenX)
4061 : {
4062 0 : FORWARD_TO_OUTER(SetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
4063 :
4064 : /*
4065 : * If caller is not chrome and the user has not explicitly exempted the site,
4066 : * prevent setting window.screenX by exiting early
4067 : */
4068 :
4069 0 : if (!CanMoveResizeWindows() || IsFrame()) {
4070 0 : return NS_OK;
4071 : }
4072 :
4073 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4074 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4075 0 : NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
4076 :
4077 0 : NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&aScreenX, nsnull),
4078 : NS_ERROR_FAILURE);
4079 :
4080 : PRInt32 x, y;
4081 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
4082 : NS_ERROR_FAILURE);
4083 :
4084 0 : x = CSSToDevIntPixels(aScreenX);
4085 :
4086 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(x, y),
4087 : NS_ERROR_FAILURE);
4088 :
4089 0 : return NS_OK;
4090 : }
4091 :
4092 : NS_IMETHODIMP
4093 0 : nsGlobalWindow::GetScreenY(PRInt32* aScreenY)
4094 : {
4095 0 : FORWARD_TO_OUTER(GetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
4096 :
4097 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4098 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4099 0 : NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
4100 :
4101 : PRInt32 x, y;
4102 :
4103 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
4104 : NS_ERROR_FAILURE);
4105 :
4106 0 : *aScreenY = DevToCSSIntPixels(y);
4107 0 : return NS_OK;
4108 : }
4109 :
4110 : NS_IMETHODIMP
4111 0 : nsGlobalWindow::SetScreenY(PRInt32 aScreenY)
4112 : {
4113 0 : FORWARD_TO_OUTER(SetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
4114 :
4115 : /*
4116 : * If caller is not chrome and the user has not explicitly exempted the site,
4117 : * prevent setting window.screenY by exiting early
4118 : */
4119 :
4120 0 : if (!CanMoveResizeWindows() || IsFrame()) {
4121 0 : return NS_OK;
4122 : }
4123 :
4124 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4125 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4126 0 : NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
4127 :
4128 0 : NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(nsnull, &aScreenY),
4129 : NS_ERROR_FAILURE);
4130 :
4131 : PRInt32 x, y;
4132 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
4133 : NS_ERROR_FAILURE);
4134 :
4135 0 : y = CSSToDevIntPixels(aScreenY);
4136 :
4137 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(x, y),
4138 : NS_ERROR_FAILURE);
4139 :
4140 0 : return NS_OK;
4141 : }
4142 :
4143 : // NOTE: Arguments to this function should have values scaled to
4144 : // CSS pixels, not device pixels.
4145 : nsresult
4146 0 : nsGlobalWindow::CheckSecurityWidthAndHeight(PRInt32* aWidth, PRInt32* aHeight)
4147 : {
4148 : #ifdef MOZ_XUL
4149 0 : if (!nsContentUtils::IsCallerTrustedForWrite()) {
4150 : // if attempting to resize the window, hide any open popups
4151 0 : nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
4152 0 : nsContentUtils::HidePopupsInDocument(doc);
4153 : }
4154 : #endif
4155 :
4156 : // This one is easy. Just ensure the variable is greater than 100;
4157 0 : if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
4158 : // Check security state for use in determing window dimensions
4159 :
4160 0 : if (!nsContentUtils::IsCallerTrustedForWrite()) {
4161 : //sec check failed
4162 0 : if (aWidth && *aWidth < 100) {
4163 0 : *aWidth = 100;
4164 : }
4165 0 : if (aHeight && *aHeight < 100) {
4166 0 : *aHeight = 100;
4167 : }
4168 : }
4169 : }
4170 :
4171 0 : return NS_OK;
4172 : }
4173 :
4174 : // NOTE: Arguments to this function should have values in device pixels
4175 : nsresult
4176 0 : nsGlobalWindow::SetDocShellWidthAndHeight(PRInt32 aInnerWidth, PRInt32 aInnerHeight)
4177 : {
4178 0 : nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
4179 0 : NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
4180 :
4181 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
4182 0 : docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
4183 0 : NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
4184 :
4185 0 : NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(docShellAsItem, aInnerWidth, aInnerHeight),
4186 : NS_ERROR_FAILURE);
4187 :
4188 0 : return NS_OK;
4189 : }
4190 :
4191 : // NOTE: Arguments to this function should have values in app units
4192 : nsresult
4193 0 : nsGlobalWindow::SetCSSViewportWidthAndHeight(nscoord aInnerWidth, nscoord aInnerHeight)
4194 : {
4195 0 : nsRefPtr<nsPresContext> presContext;
4196 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
4197 :
4198 0 : nsRect shellArea = presContext->GetVisibleArea();
4199 0 : shellArea.height = aInnerHeight;
4200 0 : shellArea.width = aInnerWidth;
4201 :
4202 0 : presContext->SetVisibleArea(shellArea);
4203 0 : return NS_OK;
4204 : }
4205 :
4206 : // NOTE: Arguments to this function should have values scaled to
4207 : // CSS pixels, not device pixels.
4208 : nsresult
4209 0 : nsGlobalWindow::CheckSecurityLeftAndTop(PRInt32* aLeft, PRInt32* aTop)
4210 : {
4211 : // This one is harder. We have to get the screen size and window dimensions.
4212 :
4213 : // Check security state for use in determing window dimensions
4214 :
4215 0 : if (!nsContentUtils::IsCallerTrustedForWrite()) {
4216 : #ifdef MOZ_XUL
4217 : // if attempting to move the window, hide any open popups
4218 0 : nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
4219 0 : nsContentUtils::HidePopupsInDocument(doc);
4220 : #endif
4221 :
4222 : nsGlobalWindow* rootWindow =
4223 0 : static_cast<nsGlobalWindow*>(GetPrivateRoot());
4224 0 : if (rootWindow) {
4225 0 : rootWindow->FlushPendingNotifications(Flush_Layout);
4226 : }
4227 :
4228 0 : nsCOMPtr<nsIBaseWindow> treeOwner;
4229 0 : GetTreeOwner(getter_AddRefs(treeOwner));
4230 :
4231 0 : nsCOMPtr<nsIDOMScreen> screen;
4232 0 : GetScreen(getter_AddRefs(screen));
4233 :
4234 0 : if (treeOwner && screen) {
4235 : PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
4236 : PRInt32 winLeft, winTop, winWidth, winHeight;
4237 :
4238 : // Get the window size
4239 0 : treeOwner->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
4240 :
4241 : // convert those values to CSS pixels
4242 : // XXX four separate retrievals of the prescontext
4243 0 : winLeft = DevToCSSIntPixels(winLeft);
4244 0 : winTop = DevToCSSIntPixels(winTop);
4245 0 : winWidth = DevToCSSIntPixels(winWidth);
4246 0 : winHeight = DevToCSSIntPixels(winHeight);
4247 :
4248 : // Get the screen dimensions
4249 : // XXX This should use nsIScreenManager once it's fully fleshed out.
4250 0 : screen->GetAvailLeft(&screenLeft);
4251 0 : screen->GetAvailWidth(&screenWidth);
4252 0 : screen->GetAvailHeight(&screenHeight);
4253 : #if defined(XP_MACOSX)
4254 : /* The mac's coordinate system is different from the assumed Windows'
4255 : system. It offsets by the height of the menubar so that a window
4256 : placed at (0,0) will be entirely visible. Unfortunately that
4257 : correction is made elsewhere (in Widget) and the meaning of
4258 : the Avail... coordinates is overloaded. Here we allow a window
4259 : to be placed at (0,0) because it does make sense to do so.
4260 : */
4261 : screen->GetTop(&screenTop);
4262 : #else
4263 0 : screen->GetAvailTop(&screenTop);
4264 : #endif
4265 :
4266 0 : if (aLeft) {
4267 0 : if (screenLeft+screenWidth < *aLeft+winWidth)
4268 0 : *aLeft = screenLeft+screenWidth - winWidth;
4269 0 : if (screenLeft > *aLeft)
4270 0 : *aLeft = screenLeft;
4271 : }
4272 0 : if (aTop) {
4273 0 : if (screenTop+screenHeight < *aTop+winHeight)
4274 0 : *aTop = screenTop+screenHeight - winHeight;
4275 0 : if (screenTop > *aTop)
4276 0 : *aTop = screenTop;
4277 : }
4278 : } else {
4279 0 : if (aLeft)
4280 0 : *aLeft = 0;
4281 0 : if (aTop)
4282 0 : *aTop = 0;
4283 : }
4284 : }
4285 :
4286 0 : return NS_OK;
4287 : }
4288 :
4289 : NS_IMETHODIMP
4290 0 : nsGlobalWindow::GetPageXOffset(PRInt32* aPageXOffset)
4291 : {
4292 0 : return GetScrollX(aPageXOffset);
4293 : }
4294 :
4295 : NS_IMETHODIMP
4296 0 : nsGlobalWindow::GetPageYOffset(PRInt32* aPageYOffset)
4297 : {
4298 0 : return GetScrollY(aPageYOffset);
4299 : }
4300 :
4301 : nsresult
4302 0 : nsGlobalWindow::GetScrollMaxXY(PRInt32* aScrollMaxX, PRInt32* aScrollMaxY)
4303 : {
4304 0 : FORWARD_TO_OUTER(GetScrollMaxXY, (aScrollMaxX, aScrollMaxY),
4305 : NS_ERROR_NOT_INITIALIZED);
4306 :
4307 0 : FlushPendingNotifications(Flush_Layout);
4308 0 : nsIScrollableFrame *sf = GetScrollFrame();
4309 0 : if (!sf)
4310 0 : return NS_OK;
4311 :
4312 0 : nsRect scrollRange = sf->GetScrollRange();
4313 :
4314 0 : if (aScrollMaxX)
4315 : *aScrollMaxX = NS_MAX(0,
4316 0 : (PRInt32)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.XMost())));
4317 0 : if (aScrollMaxY)
4318 : *aScrollMaxY = NS_MAX(0,
4319 0 : (PRInt32)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.YMost())));
4320 :
4321 0 : return NS_OK;
4322 : }
4323 :
4324 : NS_IMETHODIMP
4325 0 : nsGlobalWindow::GetScrollMaxX(PRInt32* aScrollMaxX)
4326 : {
4327 0 : NS_ENSURE_ARG_POINTER(aScrollMaxX);
4328 0 : *aScrollMaxX = 0;
4329 0 : return GetScrollMaxXY(aScrollMaxX, nsnull);
4330 : }
4331 :
4332 : NS_IMETHODIMP
4333 0 : nsGlobalWindow::GetScrollMaxY(PRInt32* aScrollMaxY)
4334 : {
4335 0 : NS_ENSURE_ARG_POINTER(aScrollMaxY);
4336 0 : *aScrollMaxY = 0;
4337 0 : return GetScrollMaxXY(nsnull, aScrollMaxY);
4338 : }
4339 :
4340 : nsresult
4341 0 : nsGlobalWindow::GetScrollXY(PRInt32* aScrollX, PRInt32* aScrollY,
4342 : bool aDoFlush)
4343 : {
4344 0 : FORWARD_TO_OUTER(GetScrollXY, (aScrollX, aScrollY, aDoFlush),
4345 : NS_ERROR_NOT_INITIALIZED);
4346 :
4347 0 : if (aDoFlush) {
4348 0 : FlushPendingNotifications(Flush_Layout);
4349 : } else {
4350 0 : EnsureSizeUpToDate();
4351 : }
4352 :
4353 0 : nsIScrollableFrame *sf = GetScrollFrame();
4354 0 : if (!sf)
4355 0 : return NS_OK;
4356 :
4357 0 : nsPoint scrollPos = sf->GetScrollPosition();
4358 0 : if (scrollPos != nsPoint(0,0) && !aDoFlush) {
4359 : // Oh, well. This is the expensive case -- the window is scrolled and we
4360 : // didn't actually flush yet. Repeat, but with a flush, since the content
4361 : // may get shorter and hence our scroll position may decrease.
4362 0 : return GetScrollXY(aScrollX, aScrollY, true);
4363 : }
4364 :
4365 0 : if (aScrollX)
4366 0 : *aScrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x);
4367 0 : if (aScrollY)
4368 0 : *aScrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
4369 :
4370 0 : return NS_OK;
4371 : }
4372 :
4373 : NS_IMETHODIMP
4374 0 : nsGlobalWindow::GetScrollX(PRInt32* aScrollX)
4375 : {
4376 0 : NS_ENSURE_ARG_POINTER(aScrollX);
4377 0 : *aScrollX = 0;
4378 0 : return GetScrollXY(aScrollX, nsnull, false);
4379 : }
4380 :
4381 : NS_IMETHODIMP
4382 0 : nsGlobalWindow::GetScrollY(PRInt32* aScrollY)
4383 : {
4384 0 : NS_ENSURE_ARG_POINTER(aScrollY);
4385 0 : *aScrollY = 0;
4386 0 : return GetScrollXY(nsnull, aScrollY, false);
4387 : }
4388 :
4389 : NS_IMETHODIMP
4390 0 : nsGlobalWindow::GetLength(PRUint32* aLength)
4391 : {
4392 0 : nsCOMPtr<nsIDOMWindowCollection> frames;
4393 0 : if (NS_SUCCEEDED(GetFrames(getter_AddRefs(frames))) && frames) {
4394 0 : return frames->GetLength(aLength);
4395 : }
4396 0 : return NS_ERROR_FAILURE;
4397 : }
4398 :
4399 : bool
4400 0 : nsGlobalWindow::DispatchCustomEvent(const char *aEventName)
4401 : {
4402 0 : bool defaultActionEnabled = true;
4403 0 : nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
4404 : nsContentUtils::DispatchTrustedEvent(doc,
4405 0 : GetOuterWindow(),
4406 0 : NS_ConvertASCIItoUTF16(aEventName),
4407 0 : true, true, &defaultActionEnabled);
4408 :
4409 0 : return defaultActionEnabled;
4410 : }
4411 :
4412 : static already_AddRefed<nsIDocShellTreeItem>
4413 0 : GetCallerDocShellTreeItem()
4414 : {
4415 0 : JSContext *cx = nsContentUtils::GetCurrentJSContext();
4416 0 : nsIDocShellTreeItem *callerItem = nsnull;
4417 :
4418 0 : if (cx) {
4419 : nsCOMPtr<nsIWebNavigation> callerWebNav =
4420 0 : do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
4421 :
4422 0 : if (callerWebNav) {
4423 0 : CallQueryInterface(callerWebNav, &callerItem);
4424 : }
4425 : }
4426 :
4427 0 : return callerItem;
4428 : }
4429 :
4430 : bool
4431 0 : nsGlobalWindow::WindowExists(const nsAString& aName,
4432 : bool aLookForCallerOnJSStack)
4433 : {
4434 0 : NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
4435 0 : NS_PRECONDITION(mDocShell, "Must have docshell");
4436 :
4437 0 : nsCOMPtr<nsIDocShellTreeItem> caller;
4438 0 : if (aLookForCallerOnJSStack) {
4439 0 : caller = GetCallerDocShellTreeItem();
4440 : }
4441 :
4442 0 : nsCOMPtr<nsIDocShellTreeItem> docShell = do_QueryInterface(mDocShell);
4443 0 : NS_ASSERTION(docShell,
4444 : "Docshell doesn't implement nsIDocShellTreeItem?");
4445 :
4446 0 : if (!caller) {
4447 0 : caller = docShell;
4448 : }
4449 :
4450 0 : nsCOMPtr<nsIDocShellTreeItem> namedItem;
4451 0 : docShell->FindItemWithName(PromiseFlatString(aName).get(), nsnull, caller,
4452 0 : getter_AddRefs(namedItem));
4453 0 : return namedItem != nsnull;
4454 : }
4455 :
4456 : already_AddRefed<nsIWidget>
4457 0 : nsGlobalWindow::GetMainWidget()
4458 : {
4459 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4460 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4461 :
4462 0 : nsIWidget *widget = nsnull;
4463 :
4464 0 : if (treeOwnerAsWin) {
4465 0 : treeOwnerAsWin->GetMainWidget(&widget);
4466 : }
4467 :
4468 0 : return widget;
4469 : }
4470 :
4471 : nsIWidget*
4472 0 : nsGlobalWindow::GetNearestWidget()
4473 : {
4474 0 : nsIDocShell* docShell = GetDocShell();
4475 0 : NS_ENSURE_TRUE(docShell, nsnull);
4476 0 : nsCOMPtr<nsIPresShell> presShell;
4477 0 : docShell->GetPresShell(getter_AddRefs(presShell));
4478 0 : NS_ENSURE_TRUE(presShell, nsnull);
4479 0 : nsIFrame* rootFrame = presShell->GetRootFrame();
4480 0 : NS_ENSURE_TRUE(rootFrame, nsnull);
4481 0 : return rootFrame->GetView()->GetNearestWidget(nsnull);
4482 : }
4483 :
4484 : NS_IMETHODIMP
4485 0 : nsGlobalWindow::SetFullScreen(bool aFullScreen)
4486 : {
4487 0 : return SetFullScreenInternal(aFullScreen, true);
4488 : }
4489 :
4490 : nsresult
4491 0 : nsGlobalWindow::SetFullScreenInternal(bool aFullScreen, bool aRequireTrust)
4492 : {
4493 0 : FORWARD_TO_OUTER(SetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
4494 :
4495 0 : NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
4496 :
4497 : bool rootWinFullScreen;
4498 0 : GetFullScreen(&rootWinFullScreen);
4499 : // Only chrome can change our fullScreen mode, unless we're running in
4500 : // untrusted mode.
4501 0 : if (aFullScreen == rootWinFullScreen ||
4502 0 : (aRequireTrust && !nsContentUtils::IsCallerTrustedForWrite())) {
4503 0 : return NS_OK;
4504 : }
4505 :
4506 : // SetFullScreen needs to be called on the root window, so get that
4507 : // via the DocShell tree, and if we are not already the root,
4508 : // call SetFullScreen on that window instead.
4509 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
4510 0 : nsCOMPtr<nsIDocShellTreeItem> rootItem;
4511 0 : treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
4512 0 : nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(rootItem);
4513 0 : if (!window)
4514 0 : return NS_ERROR_FAILURE;
4515 0 : if (rootItem != treeItem)
4516 0 : return window->SetFullScreenInternal(aFullScreen, aRequireTrust);
4517 :
4518 : // make sure we don't try to set full screen on a non-chrome window,
4519 : // which might happen in embedding world
4520 : PRInt32 itemType;
4521 0 : treeItem->GetItemType(&itemType);
4522 0 : if (itemType != nsIDocShellTreeItem::typeChrome)
4523 0 : return NS_ERROR_FAILURE;
4524 :
4525 : // If we are already in full screen mode, just return.
4526 0 : if (mFullScreen == aFullScreen)
4527 0 : return NS_OK;
4528 :
4529 : // dispatch a "fullscreen" DOM event so that XUL apps can
4530 : // respond visually if we are kicked into full screen mode
4531 0 : if (!DispatchCustomEvent("fullscreen")) {
4532 0 : return NS_OK;
4533 : }
4534 :
4535 : // Prevent chrome documents which are still loading from resizing
4536 : // the window after we set fullscreen mode.
4537 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4538 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4539 0 : nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwnerAsWin));
4540 0 : if (aFullScreen && xulWin) {
4541 0 : xulWin->SetIntrinsicallySized(false);
4542 : }
4543 :
4544 : // Set this before so if widget sends an event indicating its
4545 : // gone full screen, the state trap above works.
4546 0 : mFullScreen = aFullScreen;
4547 :
4548 0 : nsCOMPtr<nsIWidget> widget = GetMainWidget();
4549 0 : if (widget)
4550 0 : widget->MakeFullScreen(aFullScreen);
4551 :
4552 0 : if (!mFullScreen) {
4553 : // Force exit from DOM full-screen mode. This is so that if we're in
4554 : // DOM full-screen mode and the user exits full-screen mode with
4555 : // the browser full-screen mode toggle keyboard-shortcut, we'll detect
4556 : // that and leave DOM API full-screen mode too.
4557 0 : nsIDocument::ExitFullScreen(false);
4558 : }
4559 :
4560 0 : return NS_OK;
4561 : }
4562 :
4563 : NS_IMETHODIMP
4564 0 : nsGlobalWindow::GetFullScreen(bool* aFullScreen)
4565 : {
4566 0 : FORWARD_TO_OUTER(GetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
4567 :
4568 : // Get the fullscreen value of the root window, to always have the value
4569 : // accurate, even when called from content.
4570 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
4571 0 : if (treeItem) {
4572 0 : nsCOMPtr<nsIDocShellTreeItem> rootItem;
4573 0 : treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
4574 0 : if (rootItem != treeItem) {
4575 0 : nsCOMPtr<nsIDOMWindow> window = do_GetInterface(rootItem);
4576 0 : if (window)
4577 0 : return window->GetFullScreen(aFullScreen);
4578 : }
4579 : }
4580 :
4581 : // We are the root window, or something went wrong. Return our internal value.
4582 0 : *aFullScreen = mFullScreen;
4583 0 : return NS_OK;
4584 : }
4585 :
4586 : bool
4587 0 : nsGlobalWindow::DOMWindowDumpEnabled()
4588 : {
4589 : #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
4590 : // In optimized builds we check a pref that controls if we should
4591 : // enable output from dump() or not, in debug builds it's always
4592 : // enabled.
4593 : return gDOMWindowDumpEnabled;
4594 : #else
4595 0 : return true;
4596 : #endif
4597 : }
4598 :
4599 : NS_IMETHODIMP
4600 0 : nsGlobalWindow::Dump(const nsAString& aStr)
4601 : {
4602 0 : if (!DOMWindowDumpEnabled()) {
4603 0 : return NS_OK;
4604 : }
4605 :
4606 0 : char *cstr = ToNewUTF8String(aStr);
4607 :
4608 : #if defined(XP_MACOSX)
4609 : // have to convert \r to \n so that printing to the console works
4610 : char *c = cstr, *cEnd = cstr + strlen(cstr);
4611 : while (c < cEnd) {
4612 : if (*c == '\r')
4613 : *c = '\n';
4614 : c++;
4615 : }
4616 : #endif
4617 :
4618 0 : if (cstr) {
4619 : #ifdef ANDROID
4620 : __android_log_write(ANDROID_LOG_INFO, "GeckoDump", cstr);
4621 : #endif
4622 0 : FILE *fp = gDumpFile ? gDumpFile : stdout;
4623 0 : fputs(cstr, fp);
4624 0 : fflush(fp);
4625 0 : nsMemory::Free(cstr);
4626 : }
4627 :
4628 0 : return NS_OK;
4629 : }
4630 :
4631 : void
4632 0 : nsGlobalWindow::EnsureReflowFlushAndPaint()
4633 : {
4634 0 : NS_ASSERTION(IsOuterWindow(), "EnsureReflowFlushAndPaint() must be called on"
4635 : "the outer window");
4636 0 : NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no "
4637 : "docshell!");
4638 :
4639 0 : if (!mDocShell)
4640 0 : return;
4641 :
4642 0 : nsCOMPtr<nsIPresShell> presShell;
4643 0 : mDocShell->GetPresShell(getter_AddRefs(presShell));
4644 :
4645 0 : if (!presShell)
4646 : return;
4647 :
4648 : // Flush pending reflows.
4649 0 : if (mDoc) {
4650 0 : mDoc->FlushPendingNotifications(Flush_Layout);
4651 : }
4652 :
4653 : // Unsuppress painting.
4654 0 : presShell->UnsuppressPainting();
4655 : }
4656 :
4657 : NS_IMETHODIMP
4658 0 : nsGlobalWindow::GetTextZoom(float *aZoom)
4659 : {
4660 0 : FORWARD_TO_OUTER(GetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
4661 :
4662 0 : if (mDocShell) {
4663 0 : nsCOMPtr<nsIContentViewer> contentViewer;
4664 0 : mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
4665 0 : nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
4666 :
4667 0 : if (markupViewer) {
4668 0 : return markupViewer->GetTextZoom(aZoom);
4669 : }
4670 : }
4671 0 : return NS_ERROR_FAILURE;
4672 : }
4673 :
4674 : NS_IMETHODIMP
4675 0 : nsGlobalWindow::SetTextZoom(float aZoom)
4676 : {
4677 0 : FORWARD_TO_OUTER(SetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
4678 :
4679 0 : if (mDocShell) {
4680 0 : nsCOMPtr<nsIContentViewer> contentViewer;
4681 0 : mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
4682 0 : nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
4683 :
4684 0 : if (markupViewer)
4685 0 : return markupViewer->SetTextZoom(aZoom);
4686 : }
4687 0 : return NS_ERROR_FAILURE;
4688 : }
4689 :
4690 : // static
4691 : void
4692 0 : nsGlobalWindow::MakeScriptDialogTitle(nsAString &aOutTitle)
4693 : {
4694 0 : aOutTitle.Truncate();
4695 :
4696 : // Try to get a host from the running principal -- this will do the
4697 : // right thing for javascript: and data: documents.
4698 :
4699 0 : nsresult rv = NS_OK;
4700 0 : NS_ASSERTION(nsContentUtils::GetSecurityManager(),
4701 : "Global Window has no security manager!");
4702 0 : if (nsContentUtils::GetSecurityManager()) {
4703 0 : nsCOMPtr<nsIPrincipal> principal;
4704 0 : rv = nsContentUtils::GetSecurityManager()->
4705 0 : GetSubjectPrincipal(getter_AddRefs(principal));
4706 :
4707 0 : if (NS_SUCCEEDED(rv) && principal) {
4708 0 : nsCOMPtr<nsIURI> uri;
4709 0 : rv = principal->GetURI(getter_AddRefs(uri));
4710 :
4711 0 : if (NS_SUCCEEDED(rv) && uri) {
4712 : // remove user:pass for privacy and spoof prevention
4713 :
4714 0 : nsCOMPtr<nsIURIFixup> fixup(do_GetService(NS_URIFIXUP_CONTRACTID));
4715 0 : if (fixup) {
4716 0 : nsCOMPtr<nsIURI> fixedURI;
4717 0 : rv = fixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
4718 0 : if (NS_SUCCEEDED(rv) && fixedURI) {
4719 0 : nsCAutoString host;
4720 0 : fixedURI->GetHost(host);
4721 :
4722 0 : if (!host.IsEmpty()) {
4723 : // if this URI has a host we'll show it. For other
4724 : // schemes (e.g. file:) we fall back to the localized
4725 : // generic string
4726 :
4727 0 : nsCAutoString prepath;
4728 0 : fixedURI->GetPrePath(prepath);
4729 :
4730 0 : NS_ConvertUTF8toUTF16 ucsPrePath(prepath);
4731 0 : const PRUnichar *formatStrings[] = { ucsPrePath.get() };
4732 0 : nsXPIDLString tempString;
4733 : nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4734 : "ScriptDlgHeading",
4735 : formatStrings,
4736 0 : tempString);
4737 0 : aOutTitle = tempString;
4738 : }
4739 : }
4740 : }
4741 : }
4742 : }
4743 : else { // failed to get subject principal
4744 0 : NS_WARNING("No script principal? Who is calling alert/confirm/prompt?!");
4745 : }
4746 : }
4747 :
4748 0 : if (aOutTitle.IsEmpty()) {
4749 : // We didn't find a host so use the generic heading
4750 0 : nsXPIDLString tempString;
4751 : nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4752 : "ScriptDlgGenericHeading",
4753 0 : tempString);
4754 0 : aOutTitle = tempString;
4755 : }
4756 :
4757 : // Just in case
4758 0 : if (aOutTitle.IsEmpty()) {
4759 0 : NS_WARNING("could not get ScriptDlgGenericHeading string from string bundle");
4760 0 : aOutTitle.AssignLiteral("[Script]");
4761 : }
4762 0 : }
4763 :
4764 : bool
4765 0 : nsGlobalWindow::CanMoveResizeWindows()
4766 : {
4767 : // When called from chrome, we can avoid the following checks.
4768 0 : if (!nsContentUtils::IsCallerTrustedForWrite()) {
4769 : // Don't allow scripts to move or resize windows that were not opened by a
4770 : // script.
4771 0 : if (!mHadOriginalOpener) {
4772 0 : return false;
4773 : }
4774 :
4775 0 : if (!CanSetProperty("dom.disable_window_move_resize")) {
4776 0 : return false;
4777 : }
4778 :
4779 : // Ignore the request if we have more than one tab in the window.
4780 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
4781 0 : GetTreeOwner(getter_AddRefs(treeOwner));
4782 0 : if (treeOwner) {
4783 : PRUint32 itemCount;
4784 0 : if (NS_SUCCEEDED(treeOwner->GetTargetableShellCount(&itemCount)) &&
4785 : itemCount > 1) {
4786 0 : return false;
4787 : }
4788 : }
4789 : }
4790 :
4791 0 : if (mDocShell) {
4792 : bool allow;
4793 0 : nsresult rv = mDocShell->GetAllowWindowControl(&allow);
4794 0 : if (NS_SUCCEEDED(rv) && !allow)
4795 0 : return false;
4796 : }
4797 :
4798 0 : if (gMouseDown && !gDragServiceDisabled) {
4799 : nsCOMPtr<nsIDragService> ds =
4800 0 : do_GetService("@mozilla.org/widget/dragservice;1");
4801 0 : if (ds) {
4802 0 : gDragServiceDisabled = true;
4803 0 : ds->Suppress();
4804 : }
4805 : }
4806 0 : return true;
4807 : }
4808 :
4809 : NS_IMETHODIMP
4810 0 : nsGlobalWindow::Alert(const nsAString& aString)
4811 : {
4812 0 : FORWARD_TO_OUTER(Alert, (aString), NS_ERROR_NOT_INITIALIZED);
4813 :
4814 0 : if (AreDialogsBlocked())
4815 0 : return NS_ERROR_NOT_AVAILABLE;
4816 :
4817 : // We have to capture this now so as not to get confused with the
4818 : // popup state we push next
4819 0 : bool shouldEnableDisableDialog = DialogOpenAttempted();
4820 :
4821 : // Reset popup state while opening a modal dialog, and firing events
4822 : // about the dialog, to prevent the current state from being active
4823 : // the whole time a modal dialog is open.
4824 0 : nsAutoPopupStatePusher popupStatePusher(openAbused, true);
4825 :
4826 : // Special handling for alert(null) in JS for backwards
4827 : // compatibility.
4828 :
4829 0 : NS_NAMED_LITERAL_STRING(null_str, "null");
4830 :
4831 0 : const nsAString *str = DOMStringIsNull(aString) ? &null_str : &aString;
4832 :
4833 : // Before bringing up the window, unsuppress painting and flush
4834 : // pending reflows.
4835 0 : EnsureReflowFlushAndPaint();
4836 :
4837 0 : nsAutoString title;
4838 0 : MakeScriptDialogTitle(title);
4839 :
4840 : // Remove non-terminating null characters from the
4841 : // string. See bug #310037.
4842 0 : nsAutoString final;
4843 0 : nsContentUtils::StripNullChars(*str, final);
4844 :
4845 : // Check if we're being called at a point where we can't use tab-modal
4846 : // prompts, because something doesn't want reentrancy.
4847 0 : bool allowTabModal = GetIsTabModalPromptAllowed();
4848 :
4849 : nsresult rv;
4850 : nsCOMPtr<nsIPromptFactory> promptFac =
4851 0 : do_GetService("@mozilla.org/prompter;1", &rv);
4852 0 : NS_ENSURE_SUCCESS(rv, rv);
4853 :
4854 0 : nsCOMPtr<nsIPrompt> prompt;
4855 0 : rv = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
4856 0 : reinterpret_cast<void**>(&prompt));
4857 0 : NS_ENSURE_SUCCESS(rv, rv);
4858 :
4859 0 : nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
4860 0 : if (promptBag)
4861 0 : promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), allowTabModal);
4862 :
4863 0 : if (shouldEnableDisableDialog) {
4864 0 : bool disallowDialog = false;
4865 0 : nsXPIDLString label;
4866 : nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4867 0 : "ScriptDialogLabel", label);
4868 :
4869 0 : rv = prompt->AlertCheck(title.get(), final.get(), label.get(),
4870 0 : &disallowDialog);
4871 0 : if (disallowDialog)
4872 0 : PreventFurtherDialogs();
4873 : } else {
4874 0 : rv = prompt->Alert(title.get(), final.get());
4875 : }
4876 :
4877 0 : return rv;
4878 : }
4879 :
4880 : NS_IMETHODIMP
4881 0 : nsGlobalWindow::Confirm(const nsAString& aString, bool* aReturn)
4882 : {
4883 0 : FORWARD_TO_OUTER(Confirm, (aString, aReturn), NS_ERROR_NOT_INITIALIZED);
4884 :
4885 0 : if (AreDialogsBlocked())
4886 0 : return NS_ERROR_NOT_AVAILABLE;
4887 :
4888 : // We have to capture this now so as not to get confused with the popup state
4889 : // we push next
4890 0 : bool shouldEnableDisableDialog = DialogOpenAttempted();
4891 :
4892 : // Reset popup state while opening a modal dialog, and firing events
4893 : // about the dialog, to prevent the current state from being active
4894 : // the whole time a modal dialog is open.
4895 0 : nsAutoPopupStatePusher popupStatePusher(openAbused, true);
4896 :
4897 0 : *aReturn = false;
4898 :
4899 : // Before bringing up the window, unsuppress painting and flush
4900 : // pending reflows.
4901 0 : EnsureReflowFlushAndPaint();
4902 :
4903 0 : nsAutoString title;
4904 0 : MakeScriptDialogTitle(title);
4905 :
4906 : // Remove non-terminating null characters from the
4907 : // string. See bug #310037.
4908 0 : nsAutoString final;
4909 0 : nsContentUtils::StripNullChars(aString, final);
4910 :
4911 : // Check if we're being called at a point where we can't use tab-modal
4912 : // prompts, because something doesn't want reentrancy.
4913 0 : bool allowTabModal = GetIsTabModalPromptAllowed();
4914 :
4915 : nsresult rv;
4916 : nsCOMPtr<nsIPromptFactory> promptFac =
4917 0 : do_GetService("@mozilla.org/prompter;1", &rv);
4918 0 : NS_ENSURE_SUCCESS(rv, rv);
4919 :
4920 0 : nsCOMPtr<nsIPrompt> prompt;
4921 0 : rv = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
4922 0 : reinterpret_cast<void**>(&prompt));
4923 0 : NS_ENSURE_SUCCESS(rv, rv);
4924 :
4925 0 : nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
4926 0 : if (promptBag)
4927 0 : promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), allowTabModal);
4928 :
4929 0 : if (shouldEnableDisableDialog) {
4930 0 : bool disallowDialog = false;
4931 0 : nsXPIDLString label;
4932 : nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4933 0 : "ScriptDialogLabel", label);
4934 :
4935 0 : rv = prompt->ConfirmCheck(title.get(), final.get(), label.get(),
4936 0 : &disallowDialog, aReturn);
4937 0 : if (disallowDialog)
4938 0 : PreventFurtherDialogs();
4939 : } else {
4940 0 : rv = prompt->Confirm(title.get(), final.get(), aReturn);
4941 : }
4942 :
4943 0 : return rv;
4944 : }
4945 :
4946 : NS_IMETHODIMP
4947 0 : nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
4948 : nsAString& aReturn)
4949 : {
4950 0 : FORWARD_TO_OUTER(Prompt, (aMessage, aInitial, aReturn),
4951 : NS_ERROR_NOT_INITIALIZED);
4952 :
4953 0 : SetDOMStringToNull(aReturn);
4954 :
4955 0 : if (AreDialogsBlocked())
4956 0 : return NS_ERROR_NOT_AVAILABLE;
4957 :
4958 : // We have to capture this now so as not to get confused with the popup state
4959 : // we push next
4960 0 : bool shouldEnableDisableDialog = DialogOpenAttempted();
4961 :
4962 : // Reset popup state while opening a modal dialog, and firing events
4963 : // about the dialog, to prevent the current state from being active
4964 : // the whole time a modal dialog is open.
4965 0 : nsAutoPopupStatePusher popupStatePusher(openAbused, true);
4966 :
4967 : // Before bringing up the window, unsuppress painting and flush
4968 : // pending reflows.
4969 0 : EnsureReflowFlushAndPaint();
4970 :
4971 0 : nsAutoString title;
4972 0 : MakeScriptDialogTitle(title);
4973 :
4974 : // Remove non-terminating null characters from the
4975 : // string. See bug #310037.
4976 0 : nsAutoString fixedMessage, fixedInitial;
4977 0 : nsContentUtils::StripNullChars(aMessage, fixedMessage);
4978 0 : nsContentUtils::StripNullChars(aInitial, fixedInitial);
4979 :
4980 : // Check if we're being called at a point where we can't use tab-modal
4981 : // prompts, because something doesn't want reentrancy.
4982 0 : bool allowTabModal = GetIsTabModalPromptAllowed();
4983 :
4984 : nsresult rv;
4985 : nsCOMPtr<nsIPromptFactory> promptFac =
4986 0 : do_GetService("@mozilla.org/prompter;1", &rv);
4987 0 : NS_ENSURE_SUCCESS(rv, rv);
4988 :
4989 0 : nsCOMPtr<nsIPrompt> prompt;
4990 0 : rv = promptFac->GetPrompt(this, NS_GET_IID(nsIPrompt),
4991 0 : reinterpret_cast<void**>(&prompt));
4992 0 : NS_ENSURE_SUCCESS(rv, rv);
4993 :
4994 0 : nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
4995 0 : if (promptBag)
4996 0 : promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), allowTabModal);
4997 :
4998 : // Pass in the default value, if any.
4999 0 : PRUnichar *inoutValue = ToNewUnicode(fixedInitial);
5000 0 : bool disallowDialog = false;
5001 :
5002 0 : nsXPIDLString label;
5003 0 : if (shouldEnableDisableDialog) {
5004 : nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
5005 0 : "ScriptDialogLabel", label);
5006 : }
5007 :
5008 : bool ok;
5009 0 : rv = prompt->Prompt(title.get(), fixedMessage.get(),
5010 0 : &inoutValue, label.get(), &disallowDialog, &ok);
5011 :
5012 0 : if (disallowDialog) {
5013 0 : PreventFurtherDialogs();
5014 : }
5015 :
5016 0 : NS_ENSURE_SUCCESS(rv, rv);
5017 :
5018 0 : nsAdoptingString outValue(inoutValue);
5019 :
5020 0 : if (ok && outValue) {
5021 0 : aReturn.Assign(outValue);
5022 : }
5023 :
5024 0 : return rv;
5025 : }
5026 :
5027 : NS_IMETHODIMP
5028 0 : nsGlobalWindow::Focus()
5029 : {
5030 0 : FORWARD_TO_OUTER(Focus, (), NS_ERROR_NOT_INITIALIZED);
5031 :
5032 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
5033 0 : if (!fm)
5034 0 : return NS_OK;
5035 :
5036 0 : nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
5037 :
5038 0 : bool isVisible = false;
5039 0 : if (baseWin) {
5040 0 : baseWin->GetVisibility(&isVisible);
5041 : }
5042 :
5043 0 : if (!isVisible) {
5044 : // A hidden tab is being focused, ignore this call.
5045 0 : return NS_OK;
5046 : }
5047 :
5048 0 : nsIDOMWindow *caller = nsContentUtils::GetWindowFromCaller();
5049 0 : nsCOMPtr<nsIDOMWindow> opener;
5050 0 : GetOpener(getter_AddRefs(opener));
5051 :
5052 : // Enforce dom.disable_window_flip (for non-chrome), but still allow the
5053 : // window which opened us to raise us at times when popups are allowed
5054 : // (bugs 355482 and 369306).
5055 0 : bool canFocus = CanSetProperty("dom.disable_window_flip") ||
5056 0 : (opener == caller &&
5057 0 : RevisePopupAbuseLevel(gPopupControlState) < openAbused);
5058 :
5059 0 : nsCOMPtr<nsIDOMWindow> activeWindow;
5060 0 : fm->GetActiveWindow(getter_AddRefs(activeWindow));
5061 :
5062 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
5063 0 : NS_ASSERTION(treeItem, "What happened?");
5064 0 : nsCOMPtr<nsIDocShellTreeItem> rootItem;
5065 0 : treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
5066 0 : nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
5067 0 : bool isActive = (rootWin == activeWindow);
5068 :
5069 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5070 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5071 0 : if (treeOwnerAsWin && (canFocus || isActive)) {
5072 0 : bool isEnabled = true;
5073 0 : if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled)) && !isEnabled) {
5074 0 : NS_WARNING( "Should not try to set the focus on a disabled window" );
5075 0 : return NS_OK;
5076 : }
5077 :
5078 : // XXXndeakin not sure what this is for or if it should go somewhere else
5079 0 : nsCOMPtr<nsIEmbeddingSiteWindow> embeddingWin(do_GetInterface(treeOwnerAsWin));
5080 0 : if (embeddingWin)
5081 0 : embeddingWin->SetFocus();
5082 : }
5083 :
5084 0 : if (!mDocShell)
5085 0 : return NS_OK;
5086 :
5087 0 : nsCOMPtr<nsIPresShell> presShell;
5088 : // Don't look for a presshell if we're a root chrome window that's got
5089 : // about:blank loaded. We don't want to focus our widget in that case.
5090 : // XXXbz should we really be checking for IsInitialDocument() instead?
5091 0 : bool lookForPresShell = true;
5092 0 : PRInt32 itemType = nsIDocShellTreeItem::typeContent;
5093 0 : treeItem->GetItemType(&itemType);
5094 0 : if (itemType == nsIDocShellTreeItem::typeChrome &&
5095 0 : GetPrivateRoot() == static_cast<nsIDOMWindow*>(this) &&
5096 0 : mDocument) {
5097 0 : nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
5098 0 : NS_ASSERTION(doc, "Bogus doc?");
5099 0 : nsIURI* ourURI = doc->GetDocumentURI();
5100 0 : if (ourURI) {
5101 0 : lookForPresShell = !NS_IsAboutBlank(ourURI);
5102 : }
5103 : }
5104 :
5105 0 : if (lookForPresShell) {
5106 0 : mDocShell->GetEldestPresShell(getter_AddRefs(presShell));
5107 : }
5108 :
5109 0 : nsCOMPtr<nsIDocShellTreeItem> parentDsti;
5110 0 : treeItem->GetParent(getter_AddRefs(parentDsti));
5111 :
5112 : // set the parent's current focus to the frame containing this window.
5113 0 : nsCOMPtr<nsIDOMWindow> parent(do_GetInterface(parentDsti));
5114 0 : if (parent) {
5115 0 : nsCOMPtr<nsIDOMDocument> parentdomdoc;
5116 0 : parent->GetDocument(getter_AddRefs(parentdomdoc));
5117 :
5118 0 : nsCOMPtr<nsIDocument> parentdoc = do_QueryInterface(parentdomdoc);
5119 0 : if (!parentdoc)
5120 0 : return NS_OK;
5121 :
5122 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
5123 0 : nsIContent* frame = parentdoc->FindContentForSubDocument(doc);
5124 0 : nsCOMPtr<nsIDOMElement> frameElement = do_QueryInterface(frame);
5125 0 : if (frameElement) {
5126 0 : PRUint32 flags = nsIFocusManager::FLAG_NOSCROLL;
5127 0 : if (canFocus)
5128 0 : flags |= nsIFocusManager::FLAG_RAISE;
5129 0 : return fm->SetFocus(frameElement, flags);
5130 : }
5131 : }
5132 0 : else if (canFocus) {
5133 : // if there is no parent, this must be a toplevel window, so raise the
5134 : // window if canFocus is true
5135 0 : return fm->SetActiveWindow(this);
5136 : }
5137 :
5138 0 : return NS_OK;
5139 : }
5140 :
5141 : NS_IMETHODIMP
5142 0 : nsGlobalWindow::Blur()
5143 : {
5144 0 : FORWARD_TO_OUTER(Blur, (), NS_ERROR_NOT_INITIALIZED);
5145 :
5146 : // If dom.disable_window_flip == true, then content should not be allowed
5147 : // to call this function (this would allow popunders, bug 369306)
5148 0 : if (!CanSetProperty("dom.disable_window_flip")) {
5149 0 : return NS_OK;
5150 : }
5151 :
5152 : // If embedding apps don't implement nsIEmbeddingSiteWindow2, we
5153 : // shouldn't throw exceptions to web content.
5154 0 : nsresult rv = NS_OK;
5155 :
5156 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
5157 0 : GetTreeOwner(getter_AddRefs(treeOwner));
5158 0 : nsCOMPtr<nsIEmbeddingSiteWindow2> siteWindow(do_GetInterface(treeOwner));
5159 0 : if (siteWindow) {
5160 : // This method call may cause mDocShell to become nsnull.
5161 0 : rv = siteWindow->Blur();
5162 :
5163 : // if the root is focused, clear the focus
5164 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
5165 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
5166 0 : if (fm && mDocument) {
5167 0 : nsCOMPtr<nsIDOMElement> element;
5168 0 : fm->GetFocusedElementForWindow(this, false, nsnull, getter_AddRefs(element));
5169 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(element);
5170 0 : if (content == doc->GetRootElement())
5171 0 : fm->ClearFocus(this);
5172 : }
5173 : }
5174 :
5175 0 : return rv;
5176 : }
5177 :
5178 : NS_IMETHODIMP
5179 0 : nsGlobalWindow::Back()
5180 : {
5181 0 : FORWARD_TO_OUTER(Back, (), NS_ERROR_NOT_INITIALIZED);
5182 :
5183 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
5184 0 : NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
5185 :
5186 0 : return webNav->GoBack();
5187 : }
5188 :
5189 : NS_IMETHODIMP
5190 0 : nsGlobalWindow::Forward()
5191 : {
5192 0 : FORWARD_TO_OUTER(Forward, (), NS_ERROR_NOT_INITIALIZED);
5193 :
5194 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
5195 0 : NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
5196 :
5197 0 : return webNav->GoForward();
5198 : }
5199 :
5200 : NS_IMETHODIMP
5201 0 : nsGlobalWindow::Home()
5202 : {
5203 0 : FORWARD_TO_OUTER(Home, (), NS_ERROR_NOT_INITIALIZED);
5204 :
5205 0 : if (!mDocShell)
5206 0 : return NS_OK;
5207 :
5208 : nsAdoptingString homeURL =
5209 0 : Preferences::GetLocalizedString(PREF_BROWSER_STARTUP_HOMEPAGE);
5210 :
5211 0 : if (homeURL.IsEmpty()) {
5212 : // if all else fails, use this
5213 : #ifdef DEBUG_seth
5214 : printf("all else failed. using %s as the home page\n", DEFAULT_HOME_PAGE);
5215 : #endif
5216 0 : CopyASCIItoUTF16(DEFAULT_HOME_PAGE, homeURL);
5217 : }
5218 :
5219 : #ifdef MOZ_PHOENIX
5220 : {
5221 : // Firefox lets the user specify multiple home pages to open in
5222 : // individual tabs by separating them with '|'. Since we don't
5223 : // have the machinery in place to easily open new tabs from here,
5224 : // simply truncate the homeURL at the first '|' character to
5225 : // prevent any possibilities of leaking the users list of home
5226 : // pages to the first home page.
5227 : //
5228 : // Once bug https://bugzilla.mozilla.org/show_bug.cgi?id=221445 is
5229 : // fixed we can revisit this.
5230 0 : PRInt32 firstPipe = homeURL.FindChar('|');
5231 :
5232 0 : if (firstPipe > 0) {
5233 0 : homeURL.Truncate(firstPipe);
5234 : }
5235 : }
5236 : #endif
5237 :
5238 : nsresult rv;
5239 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
5240 0 : NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
5241 0 : rv = webNav->LoadURI(homeURL.get(),
5242 : nsIWebNavigation::LOAD_FLAGS_NONE,
5243 : nsnull,
5244 : nsnull,
5245 0 : nsnull);
5246 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
5247 0 : return NS_OK;
5248 : }
5249 :
5250 : NS_IMETHODIMP
5251 0 : nsGlobalWindow::Stop()
5252 : {
5253 0 : FORWARD_TO_OUTER(Stop, (), NS_ERROR_NOT_INITIALIZED);
5254 :
5255 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
5256 0 : if (!webNav)
5257 0 : return NS_OK;
5258 :
5259 0 : return webNav->Stop(nsIWebNavigation::STOP_ALL);
5260 : }
5261 :
5262 : NS_IMETHODIMP
5263 0 : nsGlobalWindow::Print()
5264 : {
5265 : #ifdef NS_PRINTING
5266 0 : FORWARD_TO_OUTER(Print, (), NS_ERROR_NOT_INITIALIZED);
5267 :
5268 0 : if (AreDialogsBlocked() || !ConfirmDialogAllowed())
5269 0 : return NS_ERROR_NOT_AVAILABLE;
5270 :
5271 0 : nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
5272 0 : if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
5273 : getter_AddRefs(webBrowserPrint)))) {
5274 :
5275 : nsCOMPtr<nsIPrintSettingsService> printSettingsService =
5276 0 : do_GetService("@mozilla.org/gfx/printsettings-service;1");
5277 :
5278 0 : nsCOMPtr<nsIPrintSettings> printSettings;
5279 0 : if (printSettingsService) {
5280 : bool printSettingsAreGlobal =
5281 0 : Preferences::GetBool("print.use_global_printsettings", false);
5282 :
5283 0 : if (printSettingsAreGlobal) {
5284 0 : printSettingsService->GetGlobalPrintSettings(getter_AddRefs(printSettings));
5285 :
5286 0 : nsXPIDLString printerName;
5287 0 : printSettings->GetPrinterName(getter_Copies(printerName));
5288 0 : if (printerName.IsEmpty()) {
5289 0 : printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
5290 0 : printSettings->SetPrinterName(printerName);
5291 : }
5292 0 : printSettingsService->InitPrintSettingsFromPrinter(printerName, printSettings);
5293 0 : printSettingsService->InitPrintSettingsFromPrefs(printSettings,
5294 : true,
5295 0 : nsIPrintSettings::kInitSaveAll);
5296 : } else {
5297 0 : printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));
5298 : }
5299 :
5300 0 : nsCOMPtr<nsIDOMWindow> callerWin = EnterModalState();
5301 0 : webBrowserPrint->Print(printSettings, nsnull);
5302 0 : LeaveModalState(callerWin);
5303 :
5304 : bool savePrintSettings =
5305 0 : Preferences::GetBool("print.save_print_settings", false);
5306 0 : if (printSettingsAreGlobal && savePrintSettings) {
5307 0 : printSettingsService->
5308 : SavePrintSettingsToPrefs(printSettings,
5309 : true,
5310 0 : nsIPrintSettings::kInitSaveAll);
5311 0 : printSettingsService->
5312 : SavePrintSettingsToPrefs(printSettings,
5313 : false,
5314 0 : nsIPrintSettings::kInitSavePrinterName);
5315 : }
5316 : } else {
5317 0 : webBrowserPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));
5318 0 : webBrowserPrint->Print(printSettings, nsnull);
5319 : }
5320 : }
5321 : #endif //NS_PRINTING
5322 :
5323 0 : return NS_OK;
5324 : }
5325 :
5326 : NS_IMETHODIMP
5327 0 : nsGlobalWindow::MoveTo(PRInt32 aXPos, PRInt32 aYPos)
5328 : {
5329 0 : FORWARD_TO_OUTER(MoveTo, (aXPos, aYPos), NS_ERROR_NOT_INITIALIZED);
5330 :
5331 : /*
5332 : * If caller is not chrome and the user has not explicitly exempted the site,
5333 : * prevent window.moveTo() by exiting early
5334 : */
5335 :
5336 0 : if (!CanMoveResizeWindows() || IsFrame()) {
5337 0 : return NS_OK;
5338 : }
5339 :
5340 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5341 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5342 0 : NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
5343 :
5344 0 : NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&aXPos, &aYPos),
5345 : NS_ERROR_FAILURE);
5346 :
5347 : // mild abuse of a "size" object so we don't need more helper functions
5348 0 : nsIntSize devPos(CSSToDevIntPixels(nsIntSize(aXPos, aYPos)));
5349 :
5350 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(devPos.width, devPos.height),
5351 : NS_ERROR_FAILURE);
5352 :
5353 0 : return NS_OK;
5354 : }
5355 :
5356 : NS_IMETHODIMP
5357 0 : nsGlobalWindow::MoveBy(PRInt32 aXDif, PRInt32 aYDif)
5358 : {
5359 0 : FORWARD_TO_OUTER(MoveBy, (aXDif, aYDif), NS_ERROR_NOT_INITIALIZED);
5360 :
5361 : /*
5362 : * If caller is not chrome and the user has not explicitly exempted the site,
5363 : * prevent window.moveBy() by exiting early
5364 : */
5365 :
5366 0 : if (!CanMoveResizeWindows() || IsFrame()) {
5367 0 : return NS_OK;
5368 : }
5369 :
5370 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5371 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5372 0 : NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
5373 :
5374 : // To do this correctly we have to convert what we get from GetPosition
5375 : // into CSS pixels, add the arguments, do the security check, and
5376 : // then convert back to device pixels for the call to SetPosition.
5377 :
5378 : PRInt32 x, y;
5379 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y), NS_ERROR_FAILURE);
5380 :
5381 : // mild abuse of a "size" object so we don't need more helper functions
5382 0 : nsIntSize cssPos(DevToCSSIntPixels(nsIntSize(x, y)));
5383 :
5384 0 : cssPos.width += aXDif;
5385 0 : cssPos.height += aYDif;
5386 :
5387 0 : NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&cssPos.width,
5388 : &cssPos.height),
5389 : NS_ERROR_FAILURE);
5390 :
5391 0 : nsIntSize newDevPos(CSSToDevIntPixels(cssPos));
5392 :
5393 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(newDevPos.width,
5394 : newDevPos.height),
5395 : NS_ERROR_FAILURE);
5396 :
5397 0 : return NS_OK;
5398 : }
5399 :
5400 : NS_IMETHODIMP
5401 0 : nsGlobalWindow::ResizeTo(PRInt32 aWidth, PRInt32 aHeight)
5402 : {
5403 0 : FORWARD_TO_OUTER(ResizeTo, (aWidth, aHeight), NS_ERROR_NOT_INITIALIZED);
5404 :
5405 : /*
5406 : * If caller is not chrome and the user has not explicitly exempted the site,
5407 : * prevent window.resizeTo() by exiting early
5408 : */
5409 :
5410 0 : if (!CanMoveResizeWindows() || IsFrame()) {
5411 0 : return NS_OK;
5412 : }
5413 :
5414 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5415 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5416 0 : NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
5417 :
5418 0 : NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&aWidth, &aHeight),
5419 : NS_ERROR_FAILURE);
5420 :
5421 0 : nsIntSize devSz(CSSToDevIntPixels(nsIntSize(aWidth, aHeight)));
5422 :
5423 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(devSz.width, devSz.height, true),
5424 : NS_ERROR_FAILURE);
5425 :
5426 0 : return NS_OK;
5427 : }
5428 :
5429 : NS_IMETHODIMP
5430 0 : nsGlobalWindow::ResizeBy(PRInt32 aWidthDif, PRInt32 aHeightDif)
5431 : {
5432 0 : FORWARD_TO_OUTER(ResizeBy, (aWidthDif, aHeightDif), NS_ERROR_NOT_INITIALIZED);
5433 :
5434 : /*
5435 : * If caller is not chrome and the user has not explicitly exempted the site,
5436 : * prevent window.resizeBy() by exiting early
5437 : */
5438 :
5439 0 : if (!CanMoveResizeWindows() || IsFrame()) {
5440 0 : return NS_OK;
5441 : }
5442 :
5443 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5444 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5445 0 : NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
5446 :
5447 : PRInt32 width, height;
5448 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&width, &height), NS_ERROR_FAILURE);
5449 :
5450 : // To do this correctly we have to convert what we got from GetSize
5451 : // into CSS pixels, add the arguments, do the security check, and
5452 : // then convert back to device pixels for the call to SetSize.
5453 :
5454 0 : nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
5455 :
5456 0 : cssSize.width += aWidthDif;
5457 0 : cssSize.height += aHeightDif;
5458 :
5459 0 : NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&cssSize.width,
5460 : &cssSize.height),
5461 : NS_ERROR_FAILURE);
5462 :
5463 0 : nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
5464 :
5465 0 : NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(newDevSize.width,
5466 : newDevSize.height,
5467 : true),
5468 : NS_ERROR_FAILURE);
5469 :
5470 0 : return NS_OK;
5471 : }
5472 :
5473 : NS_IMETHODIMP
5474 0 : nsGlobalWindow::SizeToContent()
5475 : {
5476 0 : FORWARD_TO_OUTER(SizeToContent, (), NS_ERROR_NOT_INITIALIZED);
5477 :
5478 0 : if (!mDocShell) {
5479 0 : return NS_OK;
5480 : }
5481 :
5482 : /*
5483 : * If caller is not chrome and the user has not explicitly exempted the site,
5484 : * prevent window.sizeToContent() by exiting early
5485 : */
5486 :
5487 0 : if (!CanMoveResizeWindows() || IsFrame()) {
5488 0 : return NS_OK;
5489 : }
5490 :
5491 : // The content viewer does a check to make sure that it's a content
5492 : // viewer for a toplevel docshell.
5493 :
5494 0 : nsCOMPtr<nsIContentViewer> cv;
5495 0 : mDocShell->GetContentViewer(getter_AddRefs(cv));
5496 0 : nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(cv));
5497 0 : NS_ENSURE_TRUE(markupViewer, NS_ERROR_FAILURE);
5498 0 : NS_ENSURE_SUCCESS(markupViewer->SizeToContent(), NS_ERROR_FAILURE);
5499 :
5500 0 : return NS_OK;
5501 : }
5502 :
5503 : NS_IMETHODIMP
5504 0 : nsGlobalWindow::GetWindowRoot(nsIDOMEventTarget **aWindowRoot)
5505 : {
5506 0 : nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
5507 0 : return CallQueryInterface(root, aWindowRoot);
5508 : }
5509 :
5510 : already_AddRefed<nsPIWindowRoot>
5511 0 : nsGlobalWindow::GetTopWindowRoot()
5512 : {
5513 0 : nsIDOMWindow *rootWindow = GetPrivateRoot();
5514 0 : nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(rootWindow));
5515 0 : if (!piWin)
5516 0 : return nsnull;
5517 :
5518 0 : nsCOMPtr<nsPIWindowRoot> window = do_QueryInterface(piWin->GetChromeEventHandler());
5519 0 : return window.forget();
5520 : }
5521 :
5522 : NS_IMETHODIMP
5523 0 : nsGlobalWindow::Scroll(PRInt32 aXScroll, PRInt32 aYScroll)
5524 : {
5525 0 : return ScrollTo(aXScroll, aYScroll);
5526 : }
5527 :
5528 : NS_IMETHODIMP
5529 0 : nsGlobalWindow::ScrollTo(PRInt32 aXScroll, PRInt32 aYScroll)
5530 : {
5531 0 : FlushPendingNotifications(Flush_Layout);
5532 0 : nsIScrollableFrame *sf = GetScrollFrame();
5533 :
5534 0 : if (sf) {
5535 : // Here we calculate what the max pixel value is that we can
5536 : // scroll to, we do this by dividing maxint with the pixel to
5537 : // twips conversion factor, and substracting 4, the 4 comes from
5538 : // experimenting with this value, anything less makes the view
5539 : // code not scroll correctly, I have no idea why. -- jst
5540 0 : const PRInt32 maxpx = nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff) - 4;
5541 :
5542 0 : if (aXScroll > maxpx) {
5543 0 : aXScroll = maxpx;
5544 : }
5545 :
5546 0 : if (aYScroll > maxpx) {
5547 0 : aYScroll = maxpx;
5548 : }
5549 : sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aXScroll),
5550 : nsPresContext::CSSPixelsToAppUnits(aYScroll)),
5551 0 : nsIScrollableFrame::INSTANT);
5552 : }
5553 :
5554 0 : return NS_OK;
5555 : }
5556 :
5557 : NS_IMETHODIMP
5558 0 : nsGlobalWindow::ScrollBy(PRInt32 aXScrollDif, PRInt32 aYScrollDif)
5559 : {
5560 0 : FlushPendingNotifications(Flush_Layout);
5561 0 : nsIScrollableFrame *sf = GetScrollFrame();
5562 :
5563 0 : if (sf) {
5564 0 : nsPoint scrollPos = sf->GetScrollPosition();
5565 : // It seems like it would make more sense for ScrollBy to use
5566 : // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
5567 : // Perhaps Web content does too.
5568 0 : return ScrollTo(nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x) + aXScrollDif,
5569 0 : nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y) + aYScrollDif);
5570 : }
5571 :
5572 0 : return NS_OK;
5573 : }
5574 :
5575 : NS_IMETHODIMP
5576 0 : nsGlobalWindow::ScrollByLines(PRInt32 numLines)
5577 : {
5578 0 : FlushPendingNotifications(Flush_Layout);
5579 0 : nsIScrollableFrame *sf = GetScrollFrame();
5580 0 : if (sf) {
5581 : // It seems like it would make more sense for ScrollByLines to use
5582 : // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
5583 : // Perhaps Web content does too.
5584 : sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
5585 0 : nsIScrollableFrame::INSTANT);
5586 : }
5587 :
5588 0 : return NS_OK;
5589 : }
5590 :
5591 : NS_IMETHODIMP
5592 0 : nsGlobalWindow::ScrollByPages(PRInt32 numPages)
5593 : {
5594 0 : FlushPendingNotifications(Flush_Layout);
5595 0 : nsIScrollableFrame *sf = GetScrollFrame();
5596 0 : if (sf) {
5597 : // It seems like it would make more sense for ScrollByPages to use
5598 : // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
5599 : // Perhaps Web content does too.
5600 : sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
5601 0 : nsIScrollableFrame::INSTANT);
5602 : }
5603 :
5604 0 : return NS_OK;
5605 : }
5606 :
5607 : NS_IMETHODIMP
5608 0 : nsGlobalWindow::ClearTimeout(PRInt32 aHandle)
5609 : {
5610 0 : if (aHandle <= 0) {
5611 0 : return NS_OK;
5612 : }
5613 :
5614 0 : return ClearTimeoutOrInterval(aHandle);
5615 : }
5616 :
5617 : NS_IMETHODIMP
5618 0 : nsGlobalWindow::ClearInterval(PRInt32 aHandle)
5619 : {
5620 0 : if (aHandle <= 0) {
5621 0 : return NS_OK;
5622 : }
5623 :
5624 0 : return ClearTimeoutOrInterval(aHandle);
5625 : }
5626 :
5627 : NS_IMETHODIMP
5628 0 : nsGlobalWindow::SetTimeout(PRInt32 *_retval)
5629 : {
5630 0 : return SetTimeoutOrInterval(false, _retval);
5631 : }
5632 :
5633 : NS_IMETHODIMP
5634 0 : nsGlobalWindow::SetInterval(PRInt32 *_retval)
5635 : {
5636 0 : return SetTimeoutOrInterval(true, _retval);
5637 : }
5638 :
5639 : NS_IMETHODIMP
5640 0 : nsGlobalWindow::SetResizable(bool aResizable)
5641 : {
5642 : // nop
5643 :
5644 0 : return NS_OK;
5645 : }
5646 :
5647 : static void
5648 0 : ReportUseOfDeprecatedMethod(nsGlobalWindow* aWindow, const char* aWarning)
5649 : {
5650 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(aWindow->GetExtantDocument());
5651 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
5652 : "DOM Events", doc,
5653 : nsContentUtils::eDOM_PROPERTIES,
5654 0 : aWarning);
5655 0 : }
5656 :
5657 : NS_IMETHODIMP
5658 0 : nsGlobalWindow::CaptureEvents(PRInt32 aEventFlags)
5659 : {
5660 0 : ReportUseOfDeprecatedMethod(this, "UseOfCaptureEventsWarning");
5661 0 : return NS_OK;
5662 : }
5663 :
5664 : NS_IMETHODIMP
5665 0 : nsGlobalWindow::ReleaseEvents(PRInt32 aEventFlags)
5666 : {
5667 0 : ReportUseOfDeprecatedMethod(this, "UseOfReleaseEventsWarning");
5668 0 : return NS_OK;
5669 : }
5670 :
5671 : NS_IMETHODIMP
5672 0 : nsGlobalWindow::RouteEvent(nsIDOMEvent* aEvt)
5673 : {
5674 0 : ReportUseOfDeprecatedMethod(this, "UseOfRouteEventWarning");
5675 0 : return NS_OK;
5676 : }
5677 :
5678 : NS_IMETHODIMP
5679 0 : nsGlobalWindow::EnableExternalCapture()
5680 : {
5681 0 : return NS_ERROR_FAILURE;
5682 : }
5683 :
5684 : NS_IMETHODIMP
5685 0 : nsGlobalWindow::DisableExternalCapture()
5686 : {
5687 0 : return NS_ERROR_FAILURE;
5688 : }
5689 :
5690 : static
5691 0 : bool IsPopupBlocked(nsIDOMDocument* aDoc)
5692 : {
5693 : nsCOMPtr<nsIPopupWindowManager> pm =
5694 0 : do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
5695 :
5696 0 : if (!pm) {
5697 0 : return false;
5698 : }
5699 :
5700 0 : bool blocked = true;
5701 0 : nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
5702 :
5703 0 : if (doc) {
5704 0 : PRUint32 permission = nsIPopupWindowManager::ALLOW_POPUP;
5705 0 : pm->TestPermission(doc->GetDocumentURI(), &permission);
5706 0 : blocked = (permission == nsIPopupWindowManager::DENY_POPUP);
5707 : }
5708 0 : return blocked;
5709 : }
5710 :
5711 : /* static */
5712 : void
5713 0 : nsGlobalWindow::FirePopupBlockedEvent(nsIDOMDocument* aDoc,
5714 : nsIDOMWindow *aRequestingWindow, nsIURI *aPopupURI,
5715 : const nsAString &aPopupWindowName,
5716 : const nsAString &aPopupWindowFeatures)
5717 : {
5718 0 : if (aDoc) {
5719 : // Fire a "DOMPopupBlocked" event so that the UI can hear about
5720 : // blocked popups.
5721 0 : nsCOMPtr<nsIDOMEvent> event;
5722 0 : aDoc->CreateEvent(NS_LITERAL_STRING("PopupBlockedEvents"),
5723 0 : getter_AddRefs(event));
5724 0 : if (event) {
5725 0 : nsCOMPtr<nsIDOMPopupBlockedEvent> pbev(do_QueryInterface(event));
5726 0 : pbev->InitPopupBlockedEvent(NS_LITERAL_STRING("DOMPopupBlocked"),
5727 : true, true, aRequestingWindow,
5728 : aPopupURI, aPopupWindowName,
5729 0 : aPopupWindowFeatures);
5730 0 : nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
5731 0 : privateEvent->SetTrusted(true);
5732 :
5733 0 : nsCOMPtr<nsIDOMEventTarget> targ(do_QueryInterface(aDoc));
5734 : bool defaultActionEnabled;
5735 0 : targ->DispatchEvent(event, &defaultActionEnabled);
5736 : }
5737 : }
5738 0 : }
5739 :
5740 0 : void FirePopupWindowEvent(nsIDOMDocument* aDoc)
5741 : {
5742 : // Fire a "PopupWindow" event
5743 0 : nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
5744 : nsContentUtils::DispatchTrustedEvent(doc, aDoc,
5745 0 : NS_LITERAL_STRING("PopupWindow"),
5746 0 : true, true);
5747 0 : }
5748 :
5749 : // static
5750 : bool
5751 0 : nsGlobalWindow::CanSetProperty(const char *aPrefName)
5752 : {
5753 : // Chrome can set any property.
5754 0 : if (nsContentUtils::IsCallerTrustedForWrite()) {
5755 0 : return true;
5756 : }
5757 :
5758 : // If the pref is set to true, we can not set the property
5759 : // and vice versa.
5760 0 : return !Preferences::GetBool(aPrefName, true);
5761 : }
5762 :
5763 : bool
5764 0 : nsGlobalWindow::PopupWhitelisted()
5765 : {
5766 0 : if (!IsPopupBlocked(mDocument))
5767 0 : return true;
5768 :
5769 0 : nsCOMPtr<nsIDOMWindow> parent;
5770 :
5771 0 : if (NS_FAILED(GetParent(getter_AddRefs(parent))) ||
5772 0 : parent == static_cast<nsIDOMWindow*>(this))
5773 : {
5774 0 : return false;
5775 : }
5776 :
5777 : return static_cast<nsGlobalWindow*>
5778 : (static_cast<nsIDOMWindow*>
5779 0 : (parent.get()))->PopupWhitelisted();
5780 : }
5781 :
5782 : /*
5783 : * Examine the current document state to see if we're in a way that is
5784 : * typically abused by web designers. The window.open code uses this
5785 : * routine to determine whether to allow the new window.
5786 : * Returns a value from the PopupControlState enum.
5787 : */
5788 : PopupControlState
5789 0 : nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
5790 : {
5791 0 : FORWARD_TO_OUTER(RevisePopupAbuseLevel, (aControl), aControl);
5792 :
5793 0 : NS_ASSERTION(mDocShell, "Must have docshell");
5794 :
5795 0 : nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(mDocShell));
5796 :
5797 0 : NS_ASSERTION(item, "Docshell doesn't implement nsIDocShellTreeItem?");
5798 :
5799 0 : PRInt32 type = nsIDocShellTreeItem::typeChrome;
5800 0 : item->GetItemType(&type);
5801 0 : if (type != nsIDocShellTreeItem::typeContent)
5802 0 : return openAllowed;
5803 :
5804 0 : PopupControlState abuse = aControl;
5805 0 : switch (abuse) {
5806 : case openControlled:
5807 : case openAbused:
5808 : case openOverridden:
5809 0 : if (PopupWhitelisted())
5810 0 : abuse = PopupControlState(abuse - 1);
5811 0 : case openAllowed: break;
5812 : default:
5813 0 : NS_WARNING("Strange PopupControlState!");
5814 : }
5815 :
5816 : // limit the number of simultaneously open popups
5817 0 : if (abuse == openAbused || abuse == openControlled) {
5818 0 : PRInt32 popupMax = Preferences::GetInt("dom.popup_maximum", -1);
5819 0 : if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
5820 0 : abuse = openOverridden;
5821 : }
5822 :
5823 0 : return abuse;
5824 : }
5825 :
5826 : /* If a window open is blocked, fire the appropriate DOM events.
5827 : aBlocked signifies we just blocked a popup.
5828 : aWindow signifies we just opened what is probably a popup.
5829 : */
5830 : void
5831 0 : nsGlobalWindow::FireAbuseEvents(bool aBlocked, bool aWindow,
5832 : const nsAString &aPopupURL,
5833 : const nsAString &aPopupWindowName,
5834 : const nsAString &aPopupWindowFeatures)
5835 : {
5836 : // fetch the URI of the window requesting the opened window
5837 :
5838 0 : nsCOMPtr<nsIDOMWindow> topWindow;
5839 0 : GetTop(getter_AddRefs(topWindow));
5840 0 : if (!topWindow)
5841 : return;
5842 :
5843 0 : nsCOMPtr<nsIDOMDocument> topDoc;
5844 0 : topWindow->GetDocument(getter_AddRefs(topDoc));
5845 :
5846 0 : nsCOMPtr<nsIURI> popupURI;
5847 :
5848 : // build the URI of the would-have-been popup window
5849 : // (see nsWindowWatcher::URIfromURL)
5850 :
5851 : // first, fetch the opener's base URI
5852 :
5853 0 : nsIURI *baseURL = 0;
5854 :
5855 0 : JSContext *cx = nsContentUtils::GetCurrentJSContext();
5856 0 : nsCOMPtr<nsIDOMWindow> contextWindow;
5857 :
5858 0 : if (cx) {
5859 0 : nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
5860 0 : if (currentCX) {
5861 0 : contextWindow = do_QueryInterface(currentCX->GetGlobalObject());
5862 : }
5863 : }
5864 0 : if (!contextWindow)
5865 0 : contextWindow = static_cast<nsIDOMWindow*>(this);
5866 :
5867 0 : nsCOMPtr<nsIDOMDocument> domdoc;
5868 0 : contextWindow->GetDocument(getter_AddRefs(domdoc));
5869 0 : nsCOMPtr<nsIDocument> doc(do_QueryInterface(domdoc));
5870 0 : if (doc)
5871 0 : baseURL = doc->GetDocBaseURI();
5872 :
5873 : // use the base URI to build what would have been the popup's URI
5874 0 : nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
5875 0 : if (ios)
5876 0 : ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), 0, baseURL,
5877 0 : getter_AddRefs(popupURI));
5878 :
5879 : // fire an event chock full of informative URIs
5880 0 : if (aBlocked)
5881 : FirePopupBlockedEvent(topDoc, this, popupURI, aPopupWindowName,
5882 0 : aPopupWindowFeatures);
5883 0 : if (aWindow)
5884 0 : FirePopupWindowEvent(topDoc);
5885 : }
5886 :
5887 : NS_IMETHODIMP
5888 0 : nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
5889 : const nsAString& aOptions, nsIDOMWindow **_retval)
5890 : {
5891 : return OpenInternal(aUrl, aName, aOptions,
5892 : false, // aDialog
5893 : false, // aContentModal
5894 : true, // aCalledNoScript
5895 : false, // aDoJSFixups
5896 : nsnull, nsnull, // No args
5897 0 : GetPrincipal(), // aCalleePrincipal
5898 : nsnull, // aJSCallerContext
5899 0 : _retval);
5900 : }
5901 :
5902 : NS_IMETHODIMP
5903 0 : nsGlobalWindow::OpenJS(const nsAString& aUrl, const nsAString& aName,
5904 : const nsAString& aOptions, nsIDOMWindow **_retval)
5905 : {
5906 : return OpenInternal(aUrl, aName, aOptions,
5907 : false, // aDialog
5908 : false, // aContentModal
5909 : false, // aCalledNoScript
5910 : true, // aDoJSFixups
5911 : nsnull, nsnull, // No args
5912 0 : GetPrincipal(), // aCalleePrincipal
5913 : nsContentUtils::GetCurrentJSContext(), // aJSCallerContext
5914 0 : _retval);
5915 : }
5916 :
5917 : // like Open, but attaches to the new window any extra parameters past
5918 : // [features] as a JS property named "arguments"
5919 : NS_IMETHODIMP
5920 0 : nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
5921 : const nsAString& aOptions,
5922 : nsISupports* aExtraArgument, nsIDOMWindow** _retval)
5923 : {
5924 : return OpenInternal(aUrl, aName, aOptions,
5925 : true, // aDialog
5926 : false, // aContentModal
5927 : true, // aCalledNoScript
5928 : false, // aDoJSFixups
5929 : nsnull, aExtraArgument, // Arguments
5930 0 : GetPrincipal(), // aCalleePrincipal
5931 : nsnull, // aJSCallerContext
5932 0 : _retval);
5933 : }
5934 :
5935 : NS_IMETHODIMP
5936 0 : nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
5937 : const nsAString& aOptions, nsIDOMWindow** _retval)
5938 : {
5939 0 : if (!nsContentUtils::IsCallerTrustedForWrite()) {
5940 0 : return NS_ERROR_DOM_SECURITY_ERR;
5941 : }
5942 :
5943 0 : nsAXPCNativeCallContext *ncc = nsnull;
5944 0 : nsresult rv = nsContentUtils::XPConnect()->
5945 0 : GetCurrentNativeCallContext(&ncc);
5946 0 : NS_ENSURE_SUCCESS(rv, rv);
5947 :
5948 0 : if (!ncc)
5949 0 : return NS_ERROR_NOT_AVAILABLE;
5950 :
5951 0 : JSContext *cx = nsnull;
5952 :
5953 0 : rv = ncc->GetJSContext(&cx);
5954 0 : NS_ENSURE_SUCCESS(rv, rv);
5955 :
5956 : PRUint32 argc;
5957 0 : jsval *argv = nsnull;
5958 :
5959 : // XXX - need to get this as nsISupports?
5960 0 : ncc->GetArgc(&argc);
5961 0 : ncc->GetArgvPtr(&argv);
5962 :
5963 : // Strip the url, name and options from the args seen by scripts.
5964 0 : PRUint32 argOffset = argc < 3 ? argc : 3;
5965 0 : nsCOMPtr<nsIJSArgArray> argvArray;
5966 0 : rv = NS_CreateJSArgv(cx, argc - argOffset, argv + argOffset,
5967 0 : getter_AddRefs(argvArray));
5968 0 : NS_ENSURE_SUCCESS(rv, rv);
5969 :
5970 : return OpenInternal(aUrl, aName, aOptions,
5971 : true, // aDialog
5972 : false, // aContentModal
5973 : false, // aCalledNoScript
5974 : false, // aDoJSFixups
5975 : argvArray, nsnull, // Arguments
5976 0 : GetPrincipal(), // aCalleePrincipal
5977 : cx, // aJSCallerContext
5978 0 : _retval);
5979 : }
5980 :
5981 : NS_IMETHODIMP
5982 0 : nsGlobalWindow::GetFrames(nsIDOMWindow** aFrames)
5983 : {
5984 0 : FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
5985 :
5986 0 : *aFrames = this;
5987 0 : NS_ADDREF(*aFrames);
5988 :
5989 0 : FlushPendingNotifications(Flush_ContentAndNotify);
5990 :
5991 0 : return NS_OK;
5992 : }
5993 :
5994 : nsGlobalWindow*
5995 0 : nsGlobalWindow::CallerInnerWindow()
5996 : {
5997 0 : JSContext *cx = nsContentUtils::GetCurrentJSContext();
5998 0 : if (!cx) {
5999 0 : NS_ERROR("Please don't call this method from C++!");
6000 :
6001 0 : return nsnull;
6002 : }
6003 :
6004 0 : JSObject *scope = nsnull;
6005 0 : JSStackFrame *fp = nsnull;
6006 0 : JS_FrameIterator(cx, &fp);
6007 0 : if (fp) {
6008 0 : while (!JS_IsScriptFrame(cx, fp)) {
6009 0 : if (!JS_FrameIterator(cx, &fp))
6010 0 : break;
6011 : }
6012 :
6013 0 : if (fp)
6014 0 : scope = JS_GetGlobalForFrame(fp);
6015 : }
6016 :
6017 0 : if (!scope)
6018 0 : scope = JS_GetGlobalForScopeChain(cx);
6019 :
6020 0 : JSAutoEnterCompartment ac;
6021 0 : if (!ac.enter(cx, scope))
6022 0 : return nsnull;
6023 :
6024 0 : nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
6025 0 : nsContentUtils::XPConnect()->
6026 0 : GetWrappedNativeOfJSObject(cx, scope, getter_AddRefs(wrapper));
6027 0 : if (!wrapper)
6028 0 : return nsnull;
6029 :
6030 : // The calling window must be holding a reference, so we can just return a
6031 : // raw pointer here and let the QI's addref be balanced by the nsCOMPtr
6032 : // destructor's release.
6033 0 : nsCOMPtr<nsPIDOMWindow> win = do_QueryWrappedNative(wrapper);
6034 0 : if (!win)
6035 0 : return GetCurrentInnerWindowInternal();
6036 0 : return static_cast<nsGlobalWindow*>(win.get());
6037 : }
6038 :
6039 : /**
6040 : * Class used to represent events generated by calls to Window.postMessage,
6041 : * which asynchronously creates and dispatches events.
6042 : */
6043 : class PostMessageEvent : public nsRunnable
6044 : {
6045 : public:
6046 : NS_DECL_NSIRUNNABLE
6047 :
6048 0 : PostMessageEvent(nsGlobalWindow* aSource,
6049 : const nsAString& aCallerOrigin,
6050 : nsGlobalWindow* aTargetWindow,
6051 : nsIURI* aProvidedOrigin,
6052 : bool aTrustedCaller)
6053 : : mSource(aSource),
6054 : mCallerOrigin(aCallerOrigin),
6055 : mMessage(nsnull),
6056 : mMessageLen(0),
6057 : mTargetWindow(aTargetWindow),
6058 : mProvidedOrigin(aProvidedOrigin),
6059 0 : mTrustedCaller(aTrustedCaller)
6060 : {
6061 0 : MOZ_COUNT_CTOR(PostMessageEvent);
6062 0 : }
6063 :
6064 0 : ~PostMessageEvent()
6065 0 : {
6066 0 : NS_ASSERTION(!mMessage, "Message should have been deserialized!");
6067 0 : MOZ_COUNT_DTOR(PostMessageEvent);
6068 0 : }
6069 :
6070 0 : void SetJSData(JSAutoStructuredCloneBuffer& aBuffer)
6071 : {
6072 0 : NS_ASSERTION(!mMessage && mMessageLen == 0, "Don't call twice!");
6073 0 : aBuffer.steal(&mMessage, &mMessageLen);
6074 0 : }
6075 :
6076 0 : bool StoreISupports(nsISupports* aSupports)
6077 : {
6078 0 : mSupportsArray.AppendElement(aSupports);
6079 0 : return true;
6080 : }
6081 :
6082 : private:
6083 : nsRefPtr<nsGlobalWindow> mSource;
6084 : nsString mCallerOrigin;
6085 : uint64_t* mMessage;
6086 : size_t mMessageLen;
6087 : nsRefPtr<nsGlobalWindow> mTargetWindow;
6088 : nsCOMPtr<nsIURI> mProvidedOrigin;
6089 : bool mTrustedCaller;
6090 : nsTArray<nsCOMPtr<nsISupports> > mSupportsArray;
6091 : };
6092 :
6093 : namespace {
6094 :
6095 : struct StructuredCloneInfo {
6096 : PostMessageEvent* event;
6097 : bool subsumes;
6098 : };
6099 :
6100 : static JSObject*
6101 0 : PostMessageReadStructuredClone(JSContext* cx,
6102 : JSStructuredCloneReader* reader,
6103 : uint32 tag,
6104 : uint32 data,
6105 : void* closure)
6106 : {
6107 0 : NS_ASSERTION(closure, "Must have closure!");
6108 :
6109 0 : if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
6110 0 : NS_ASSERTION(!data, "Data should be empty");
6111 :
6112 : nsISupports* supports;
6113 0 : if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
6114 0 : JSObject* global = JS_GetGlobalForScopeChain(cx);
6115 0 : if (global) {
6116 : jsval val;
6117 0 : nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
6118 0 : if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, global, supports,
6119 : &val,
6120 : getter_AddRefs(wrapper)))) {
6121 0 : return JSVAL_TO_OBJECT(val);
6122 : }
6123 : }
6124 : }
6125 : }
6126 :
6127 : const JSStructuredCloneCallbacks* runtimeCallbacks =
6128 0 : js::GetContextStructuredCloneCallbacks(cx);
6129 :
6130 0 : if (runtimeCallbacks) {
6131 0 : return runtimeCallbacks->read(cx, reader, tag, data, nsnull);
6132 : }
6133 :
6134 0 : return JS_FALSE;
6135 : }
6136 :
6137 : static JSBool
6138 0 : PostMessageWriteStructuredClone(JSContext* cx,
6139 : JSStructuredCloneWriter* writer,
6140 : JSObject* obj,
6141 : void *closure)
6142 : {
6143 0 : StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
6144 0 : NS_ASSERTION(scInfo, "Must have scInfo!");
6145 :
6146 0 : nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
6147 0 : nsContentUtils::XPConnect()->
6148 0 : GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
6149 0 : if (wrappedNative) {
6150 0 : PRUint32 scTag = 0;
6151 0 : nsISupports* supports = wrappedNative->Native();
6152 :
6153 0 : nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
6154 0 : if (blob && scInfo->subsumes)
6155 0 : scTag = SCTAG_DOM_BLOB;
6156 :
6157 0 : nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
6158 0 : if (list && scInfo->subsumes)
6159 0 : scTag = SCTAG_DOM_FILELIST;
6160 :
6161 0 : if (scTag)
6162 0 : return JS_WriteUint32Pair(writer, scTag, 0) &&
6163 0 : JS_WriteBytes(writer, &supports, sizeof(supports)) &&
6164 0 : scInfo->event->StoreISupports(supports);
6165 : }
6166 :
6167 : const JSStructuredCloneCallbacks* runtimeCallbacks =
6168 0 : js::GetContextStructuredCloneCallbacks(cx);
6169 :
6170 0 : if (runtimeCallbacks) {
6171 0 : return runtimeCallbacks->write(cx, writer, obj, nsnull);
6172 : }
6173 :
6174 0 : return JS_FALSE;
6175 : }
6176 :
6177 : JSStructuredCloneCallbacks kPostMessageCallbacks = {
6178 : PostMessageReadStructuredClone,
6179 : PostMessageWriteStructuredClone,
6180 : nsnull
6181 : };
6182 :
6183 : } // anonymous namespace
6184 :
6185 : NS_IMETHODIMP
6186 0 : PostMessageEvent::Run()
6187 : {
6188 0 : NS_ABORT_IF_FALSE(mTargetWindow->IsOuterWindow(),
6189 : "should have been passed an outer window!");
6190 0 : NS_ABORT_IF_FALSE(!mSource || mSource->IsOuterWindow(),
6191 : "should have been passed an outer window!");
6192 :
6193 : // Get the JSContext for the target window
6194 0 : JSContext* cx = nsnull;
6195 0 : nsIScriptContext* scriptContext = mTargetWindow->GetContext();
6196 0 : if (scriptContext) {
6197 0 : cx = scriptContext->GetNativeContext();
6198 : }
6199 :
6200 0 : if (!cx) {
6201 : // This can happen if mTargetWindow has been closed. To avoid leaking,
6202 : // we need to find a JSContext.
6203 0 : nsIThreadJSContextStack* cxStack = nsContentUtils::ThreadJSContextStack();
6204 0 : if (cxStack) {
6205 0 : cxStack->GetSafeJSContext(&cx);
6206 : }
6207 :
6208 0 : if (!cx) {
6209 0 : NS_WARNING("Cannot find a JSContext! Leaking PostMessage buffer.");
6210 0 : return NS_ERROR_FAILURE;
6211 : }
6212 : }
6213 :
6214 : // If we bailed before this point we're going to leak mMessage, but
6215 : // that's probably better than crashing.
6216 :
6217 : // Ensure that the buffer is freed even if we fail to post the message
6218 0 : JSAutoStructuredCloneBuffer buffer;
6219 0 : buffer.adopt(mMessage, mMessageLen);
6220 0 : mMessage = nsnull;
6221 0 : mMessageLen = 0;
6222 :
6223 0 : nsRefPtr<nsGlobalWindow> targetWindow;
6224 0 : if (mTargetWindow->IsClosedOrClosing() ||
6225 0 : !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
6226 0 : targetWindow->IsClosedOrClosing())
6227 0 : return NS_OK;
6228 :
6229 0 : NS_ABORT_IF_FALSE(targetWindow->IsInnerWindow(),
6230 : "we ordered an inner window!");
6231 :
6232 : // Ensure that any origin which might have been provided is the origin of this
6233 : // window's document. Note that we do this *now* instead of when postMessage
6234 : // is called because the target window might have been navigated to a
6235 : // different location between then and now. If this check happened when
6236 : // postMessage was called, it would be fairly easy for a malicious webpage to
6237 : // intercept messages intended for another site by carefully timing navigation
6238 : // of the target window so it changed location after postMessage but before
6239 : // now.
6240 0 : if (mProvidedOrigin) {
6241 : // Get the target's origin either from its principal or, in the case the
6242 : // principal doesn't carry a URI (e.g. the system principal), the target's
6243 : // document.
6244 0 : nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
6245 0 : if (!targetPrin)
6246 0 : return NS_OK;
6247 0 : nsCOMPtr<nsIURI> targetURI;
6248 0 : if (NS_FAILED(targetPrin->GetURI(getter_AddRefs(targetURI))))
6249 0 : return NS_OK;
6250 0 : if (!targetURI) {
6251 0 : targetURI = targetWindow->mDoc->GetDocumentURI();
6252 0 : if (!targetURI)
6253 0 : return NS_OK;
6254 : }
6255 :
6256 : // Note: This is contrary to the spec with respect to file: URLs, which
6257 : // the spec groups into a single origin, but given we intentionally
6258 : // don't do that in other places it seems better to hold the line for
6259 : // now. Long-term, we want HTML5 to address this so that we can
6260 : // be compliant while being safer.
6261 0 : nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
6262 : nsresult rv =
6263 0 : ssm->CheckSameOriginURI(mProvidedOrigin, targetURI, true);
6264 0 : if (NS_FAILED(rv))
6265 0 : return NS_OK;
6266 : }
6267 :
6268 : // Deserialize the structured clone data
6269 : jsval messageData;
6270 : {
6271 0 : JSAutoRequest ar(cx);
6272 : StructuredCloneInfo scInfo;
6273 0 : scInfo.event = this;
6274 :
6275 0 : if (!buffer.read(cx, &messageData, &kPostMessageCallbacks, &scInfo))
6276 0 : return NS_ERROR_DOM_DATA_CLONE_ERR;
6277 : }
6278 :
6279 : // Create the event
6280 0 : nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(targetWindow->mDocument);
6281 0 : if (!domDoc)
6282 0 : return NS_OK;
6283 0 : nsCOMPtr<nsIDOMEvent> event;
6284 0 : domDoc->CreateEvent(NS_LITERAL_STRING("MessageEvent"),
6285 0 : getter_AddRefs(event));
6286 0 : if (!event)
6287 0 : return NS_OK;
6288 :
6289 0 : nsCOMPtr<nsIDOMMessageEvent> message = do_QueryInterface(event);
6290 0 : nsresult rv = message->InitMessageEvent(NS_LITERAL_STRING("message"),
6291 : false /* non-bubbling */,
6292 : true /* cancelable */,
6293 : messageData,
6294 : mCallerOrigin,
6295 0 : EmptyString(),
6296 0 : mSource);
6297 0 : if (NS_FAILED(rv))
6298 0 : return NS_OK;
6299 :
6300 :
6301 : // We can't simply call dispatchEvent on the window because doing so ends
6302 : // up flipping the trusted bit on the event, and we don't want that to
6303 : // happen because then untrusted content can call postMessage on a chrome
6304 : // window if it can get a reference to it.
6305 :
6306 0 : nsIPresShell *shell = targetWindow->mDoc->GetShell();
6307 0 : nsRefPtr<nsPresContext> presContext;
6308 0 : if (shell)
6309 0 : presContext = shell->GetPresContext();
6310 :
6311 0 : nsCOMPtr<nsIPrivateDOMEvent> privEvent = do_QueryInterface(message);
6312 0 : privEvent->SetTrusted(mTrustedCaller);
6313 0 : nsEvent *internalEvent = privEvent->GetInternalNSEvent();
6314 :
6315 0 : nsEventStatus status = nsEventStatus_eIgnore;
6316 0 : nsEventDispatcher::Dispatch(static_cast<nsPIDOMWindow*>(mTargetWindow),
6317 : presContext,
6318 : internalEvent,
6319 : message,
6320 0 : &status);
6321 0 : return NS_OK;
6322 : }
6323 :
6324 : NS_IMETHODIMP
6325 0 : nsGlobalWindow::PostMessageMoz(const jsval& aMessage,
6326 : const nsAString& aOrigin,
6327 : JSContext* aCx)
6328 : {
6329 0 : FORWARD_TO_OUTER(PostMessageMoz, (aMessage, aOrigin, aCx),
6330 : NS_ERROR_NOT_INITIALIZED);
6331 :
6332 : //
6333 : // Window.postMessage is an intentional subversion of the same-origin policy.
6334 : // As such, this code must be particularly careful in the information it
6335 : // exposes to calling code.
6336 : //
6337 : // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
6338 : //
6339 :
6340 : // First, get the caller's window
6341 0 : nsRefPtr<nsGlobalWindow> callerInnerWin = CallerInnerWindow();
6342 0 : if (!callerInnerWin)
6343 0 : return NS_OK;
6344 0 : NS_ABORT_IF_FALSE(callerInnerWin->IsInnerWindow(),
6345 : "should have gotten an inner window here");
6346 :
6347 : // Compute the caller's origin either from its principal or, in the case the
6348 : // principal doesn't carry a URI (e.g. the system principal), the caller's
6349 : // document. We must get this now instead of when the event is created and
6350 : // dispatched, because ultimately it is the identity of the calling window
6351 : // *now* that determines who sent the message (and not an identity which might
6352 : // have changed due to intervening navigations).
6353 0 : nsIPrincipal* callerPrin = callerInnerWin->GetPrincipal();
6354 0 : if (!callerPrin)
6355 0 : return NS_OK;
6356 :
6357 0 : nsCOMPtr<nsIURI> callerOuterURI;
6358 0 : if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerOuterURI))))
6359 0 : return NS_OK;
6360 :
6361 0 : nsAutoString origin;
6362 0 : if (callerOuterURI) {
6363 : // if the principal has a URI, use that to generate the origin
6364 0 : nsContentUtils::GetUTFOrigin(callerPrin, origin);
6365 : }
6366 : else {
6367 : // otherwise use the URI of the document to generate origin
6368 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(callerInnerWin->mDocument);
6369 0 : if (!doc)
6370 0 : return NS_OK;
6371 0 : callerOuterURI = doc->GetDocumentURI();
6372 : // if the principal has a URI, use that to generate the origin
6373 0 : nsContentUtils::GetUTFOrigin(callerOuterURI, origin);
6374 : }
6375 :
6376 : // Convert the provided origin string into a URI for comparison purposes.
6377 : // "*" indicates no specific origin is required.
6378 0 : nsCOMPtr<nsIURI> providedOrigin;
6379 0 : if (!aOrigin.EqualsASCII("*")) {
6380 0 : if (NS_FAILED(NS_NewURI(getter_AddRefs(providedOrigin), aOrigin)))
6381 0 : return NS_ERROR_DOM_SYNTAX_ERR;
6382 0 : if (NS_FAILED(providedOrigin->SetUserPass(EmptyCString())) ||
6383 0 : NS_FAILED(providedOrigin->SetPath(EmptyCString())))
6384 0 : return NS_OK;
6385 : }
6386 :
6387 : // Create and asynchronously dispatch a runnable which will handle actual DOM
6388 : // event creation and dispatch.
6389 : nsRefPtr<PostMessageEvent> event =
6390 0 : new PostMessageEvent(nsContentUtils::IsCallerChrome()
6391 : ? nsnull
6392 0 : : callerInnerWin->GetOuterWindowInternal(),
6393 : origin,
6394 : this,
6395 : providedOrigin,
6396 0 : nsContentUtils::IsCallerTrustedForWrite());
6397 :
6398 : // We *must* clone the data here, or the jsval could be modified
6399 : // by script
6400 0 : JSAutoStructuredCloneBuffer buffer;
6401 : StructuredCloneInfo scInfo;
6402 0 : scInfo.event = event;
6403 :
6404 0 : nsIPrincipal* principal = GetPrincipal();
6405 0 : if (NS_FAILED(callerPrin->Subsumes(principal, &scInfo.subsumes)))
6406 0 : return NS_ERROR_DOM_DATA_CLONE_ERR;
6407 :
6408 0 : if (!buffer.write(aCx, aMessage, &kPostMessageCallbacks, &scInfo))
6409 0 : return NS_ERROR_DOM_DATA_CLONE_ERR;
6410 :
6411 0 : event->SetJSData(buffer);
6412 :
6413 0 : return NS_DispatchToCurrentThread(event);
6414 : }
6415 :
6416 0 : class nsCloseEvent : public nsRunnable {
6417 :
6418 : nsRefPtr<nsGlobalWindow> mWindow;
6419 :
6420 0 : nsCloseEvent(nsGlobalWindow *aWindow)
6421 0 : : mWindow(aWindow)
6422 0 : {}
6423 :
6424 : public:
6425 :
6426 : static nsresult
6427 0 : PostCloseEvent(nsGlobalWindow* aWindow) {
6428 0 : nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow);
6429 0 : nsresult rv = NS_DispatchToCurrentThread(ev);
6430 0 : if (NS_SUCCEEDED(rv))
6431 0 : aWindow->MaybeForgiveSpamCount();
6432 0 : return rv;
6433 : }
6434 :
6435 0 : NS_IMETHOD Run() {
6436 0 : if (mWindow)
6437 0 : mWindow->ReallyCloseWindow();
6438 0 : return NS_OK;
6439 : }
6440 :
6441 : };
6442 :
6443 : bool
6444 0 : nsGlobalWindow::CanClose()
6445 : {
6446 0 : if (!mDocShell)
6447 0 : return true;
6448 :
6449 : // Ask the content viewer whether the toplevel window can close.
6450 : // If the content viewer returns false, it is responsible for calling
6451 : // Close() as soon as it is possible for the window to close.
6452 : // This allows us to not close the window while printing is happening.
6453 :
6454 0 : nsCOMPtr<nsIContentViewer> cv;
6455 0 : mDocShell->GetContentViewer(getter_AddRefs(cv));
6456 0 : if (cv) {
6457 : bool canClose;
6458 0 : nsresult rv = cv->PermitUnload(false, &canClose);
6459 0 : if (NS_SUCCEEDED(rv) && !canClose)
6460 0 : return false;
6461 :
6462 0 : rv = cv->RequestWindowClose(&canClose);
6463 0 : if (NS_SUCCEEDED(rv) && !canClose)
6464 0 : return false;
6465 : }
6466 :
6467 0 : return true;
6468 : }
6469 :
6470 : NS_IMETHODIMP
6471 0 : nsGlobalWindow::Close()
6472 : {
6473 0 : FORWARD_TO_OUTER(Close, (), NS_ERROR_NOT_INITIALIZED);
6474 :
6475 0 : if (IsFrame() || !mDocShell || IsInModalState()) {
6476 : // window.close() is called on a frame in a frameset, on a window
6477 : // that's already closed, or on a window for which there's
6478 : // currently a modal dialog open. Ignore such calls.
6479 :
6480 0 : return NS_OK;
6481 : }
6482 :
6483 0 : if (mHavePendingClose) {
6484 : // We're going to be closed anyway; do nothing since we don't want
6485 : // to double-close
6486 0 : return NS_OK;
6487 : }
6488 :
6489 0 : if (mBlockScriptedClosingFlag)
6490 : {
6491 : // A script's popup has been blocked and we don't want
6492 : // the window to be closed directly after this event,
6493 : // so the user can see that there was a blocked popup.
6494 0 : return NS_OK;
6495 : }
6496 :
6497 : // Don't allow scripts from content to close windows
6498 : // that were not opened by script
6499 0 : if (!mHadOriginalOpener && !nsContentUtils::IsCallerTrustedForWrite()) {
6500 : bool allowClose =
6501 0 : Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
6502 0 : if (!allowClose) {
6503 : // We're blocking the close operation
6504 : // report localized error msg in JS console
6505 : nsContentUtils::ReportToConsole(
6506 : nsIScriptError::warningFlag,
6507 : "DOM Window", mDoc, // Better name for the category?
6508 : nsContentUtils::eDOM_PROPERTIES,
6509 0 : "WindowCloseBlockedWarning");
6510 :
6511 0 : return NS_OK;
6512 : }
6513 : }
6514 :
6515 0 : if (!mInClose && !mIsClosed && !CanClose())
6516 0 : return NS_OK;
6517 :
6518 : // Fire a DOM event notifying listeners that this window is about to
6519 : // be closed. The tab UI code may choose to cancel the default
6520 : // action for this event, if so, we won't actually close the window
6521 : // (since the tab UI code will close the tab in stead). Sure, this
6522 : // could be abused by content code, but do we care? I don't think
6523 : // so...
6524 :
6525 0 : bool wasInClose = mInClose;
6526 0 : mInClose = true;
6527 :
6528 0 : if (!DispatchCustomEvent("DOMWindowClose")) {
6529 : // Someone chose to prevent the default action for this event, if
6530 : // so, let's not close this window after all...
6531 :
6532 0 : mInClose = wasInClose;
6533 0 : return NS_OK;
6534 : }
6535 :
6536 0 : return FinalClose();
6537 : }
6538 :
6539 : nsresult
6540 0 : nsGlobalWindow::ForceClose()
6541 : {
6542 0 : if (IsFrame() || !mDocShell) {
6543 : // This may be a frame in a frameset, or a window that's already closed.
6544 : // Ignore such calls.
6545 :
6546 0 : return NS_OK;
6547 : }
6548 :
6549 0 : if (mHavePendingClose) {
6550 : // We're going to be closed anyway; do nothing since we don't want
6551 : // to double-close
6552 0 : return NS_OK;
6553 : }
6554 :
6555 0 : mInClose = true;
6556 :
6557 0 : DispatchCustomEvent("DOMWindowClose");
6558 :
6559 0 : return FinalClose();
6560 : }
6561 :
6562 : nsresult
6563 0 : nsGlobalWindow::FinalClose()
6564 : {
6565 : // Flag that we were closed.
6566 0 : mIsClosed = true;
6567 :
6568 : nsCOMPtr<nsIJSContextStack> stack =
6569 0 : do_GetService(sJSStackContractID);
6570 :
6571 0 : JSContext *cx = nsnull;
6572 :
6573 0 : if (stack) {
6574 0 : stack->Peek(&cx);
6575 : }
6576 :
6577 0 : if (cx) {
6578 0 : nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
6579 :
6580 0 : if (currentCX && currentCX == GetContextInternal()) {
6581 0 : currentCX->SetTerminationFunction(CloseWindow, this);
6582 0 : mHavePendingClose = true;
6583 0 : return NS_OK;
6584 : }
6585 : }
6586 :
6587 : // We may have plugins on the page that have issued this close from their
6588 : // event loop and because we currently destroy the plugin window with
6589 : // frames, we crash. So, if we are called from Javascript, post an event
6590 : // to really close the window.
6591 0 : if (nsContentUtils::IsCallerChrome() ||
6592 0 : NS_FAILED(nsCloseEvent::PostCloseEvent(this))) {
6593 0 : ReallyCloseWindow();
6594 : } else {
6595 0 : mHavePendingClose = true;
6596 : }
6597 :
6598 0 : return NS_OK;
6599 : }
6600 :
6601 :
6602 : void
6603 0 : nsGlobalWindow::ReallyCloseWindow()
6604 : {
6605 0 : FORWARD_TO_OUTER_VOID(ReallyCloseWindow, ());
6606 :
6607 : // Make sure we never reenter this method.
6608 0 : mHavePendingClose = true;
6609 :
6610 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
6611 0 : GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
6612 :
6613 : // If there's no treeOwnerAsWin, this window must already be closed.
6614 :
6615 0 : if (treeOwnerAsWin) {
6616 :
6617 : // but if we're a browser window we could be in some nasty
6618 : // self-destroying cascade that we should mostly ignore
6619 :
6620 0 : nsCOMPtr<nsIDocShellTreeItem> docItem(do_QueryInterface(mDocShell));
6621 0 : if (docItem) {
6622 0 : nsCOMPtr<nsIBrowserDOMWindow> bwin;
6623 0 : nsCOMPtr<nsIDocShellTreeItem> rootItem;
6624 0 : docItem->GetRootTreeItem(getter_AddRefs(rootItem));
6625 0 : nsCOMPtr<nsIDOMWindow> rootWin(do_GetInterface(rootItem));
6626 0 : nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
6627 0 : if (chromeWin)
6628 0 : chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
6629 :
6630 0 : if (rootWin) {
6631 : /* Normally we destroy the entire window, but not if
6632 : this DOM window belongs to a tabbed browser and doesn't
6633 : correspond to a tab. This allows a well-behaved tab
6634 : to destroy the container as it should but is a final measure
6635 : to prevent an errant tab from doing so when it shouldn't.
6636 : This works because we reach this code when we shouldn't only
6637 : in the particular circumstance that we belong to a tab
6638 : that has just been closed (and is therefore already missing
6639 : from the list of browsers) (and has an unload handler
6640 : that closes the window). */
6641 : // XXXbz now that we have mHavePendingClose, is this needed?
6642 0 : bool isTab = false;
6643 0 : if (rootWin == this ||
6644 0 : !bwin || (bwin->IsTabContentWindow(GetOuterWindowInternal(),
6645 0 : &isTab), isTab))
6646 0 : treeOwnerAsWin->Destroy();
6647 : }
6648 : }
6649 :
6650 0 : CleanUp(false);
6651 : }
6652 : }
6653 :
6654 : nsIDOMWindow *
6655 0 : nsGlobalWindow::EnterModalState()
6656 : {
6657 0 : nsGlobalWindow* topWin = GetTop();
6658 :
6659 0 : if (!topWin) {
6660 0 : NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
6661 :
6662 0 : return nsnull;
6663 : }
6664 :
6665 : // If there is an active ESM in this window, clear it. Otherwise, this can
6666 : // cause a problem if a modal state is entered during a mouseup event.
6667 : nsEventStateManager* activeESM =
6668 0 : static_cast<nsEventStateManager*>(nsEventStateManager::GetActiveEventStateManager());
6669 0 : if (activeESM && activeESM->GetPresContext()) {
6670 0 : nsIPresShell* activeShell = activeESM->GetPresContext()->GetPresShell();
6671 0 : if (activeShell && (
6672 0 : nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(), mDoc) ||
6673 0 : nsContentUtils::ContentIsCrossDocDescendantOf(mDoc, activeShell->GetDocument()))) {
6674 0 : nsEventStateManager::ClearGlobalActiveContent(activeESM);
6675 :
6676 0 : activeShell->SetCapturingContent(nsnull, 0);
6677 :
6678 0 : if (activeShell) {
6679 0 : nsRefPtr<nsFrameSelection> frameSelection = activeShell->FrameSelection();
6680 0 : frameSelection->SetMouseDownState(false);
6681 : }
6682 : }
6683 : }
6684 :
6685 0 : if (topWin->mModalStateDepth == 0) {
6686 0 : NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
6687 :
6688 0 : mSuspendedDoc = do_QueryInterface(topWin->GetExtantDocument());
6689 0 : if (mSuspendedDoc && mSuspendedDoc->EventHandlingSuppressed()) {
6690 0 : mSuspendedDoc->SuppressEventHandling();
6691 : } else {
6692 0 : mSuspendedDoc = nsnull;
6693 : }
6694 : }
6695 0 : topWin->mModalStateDepth++;
6696 :
6697 0 : JSContext *cx = nsContentUtils::GetCurrentJSContext();
6698 :
6699 0 : nsCOMPtr<nsIDOMWindow> callerWin;
6700 : nsIScriptContext *scx;
6701 0 : if (cx && (scx = GetScriptContextFromJSContext(cx))) {
6702 0 : scx->EnterModalState();
6703 0 : callerWin = do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
6704 : }
6705 :
6706 0 : if (mContext) {
6707 0 : mContext->EnterModalState();
6708 : }
6709 :
6710 0 : return callerWin;
6711 : }
6712 :
6713 : // static
6714 : void
6715 0 : nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
6716 : nsGlobalWindow *aWindow)
6717 : {
6718 : nsGlobalWindow *inner;
6719 :
6720 : // Return early if we're frozen or have no inner window.
6721 0 : if (!(inner = aWindow->GetCurrentInnerWindowInternal()) ||
6722 0 : inner->IsFrozen()) {
6723 0 : return;
6724 : }
6725 :
6726 0 : inner->RunTimeout(nsnull);
6727 :
6728 : // Check again if we're frozen since running pending timeouts
6729 : // could've frozen us.
6730 0 : if (inner->IsFrozen()) {
6731 0 : return;
6732 : }
6733 :
6734 0 : nsCOMPtr<nsIDOMWindowCollection> frames;
6735 0 : aWindow->GetFrames(getter_AddRefs(frames));
6736 :
6737 0 : if (!frames) {
6738 : return;
6739 : }
6740 :
6741 : PRUint32 i, length;
6742 0 : if (NS_FAILED(frames->GetLength(&length)) || !length) {
6743 : return;
6744 : }
6745 :
6746 0 : for (i = 0; i < length && aTopWindow->mModalStateDepth == 0; i++) {
6747 0 : nsCOMPtr<nsIDOMWindow> child;
6748 0 : frames->Item(i, getter_AddRefs(child));
6749 :
6750 0 : if (!child) {
6751 : return;
6752 : }
6753 :
6754 : nsGlobalWindow *childWin =
6755 : static_cast<nsGlobalWindow *>
6756 : (static_cast<nsIDOMWindow *>
6757 0 : (child.get()));
6758 :
6759 0 : RunPendingTimeoutsRecursive(aTopWindow, childWin);
6760 : }
6761 : }
6762 :
6763 : class nsPendingTimeoutRunner : public nsRunnable
6764 0 : {
6765 : public:
6766 0 : nsPendingTimeoutRunner(nsGlobalWindow *aWindow)
6767 0 : : mWindow(aWindow)
6768 : {
6769 0 : NS_ASSERTION(mWindow, "mWindow is null.");
6770 0 : }
6771 :
6772 0 : NS_IMETHOD Run()
6773 : {
6774 0 : nsGlobalWindow::RunPendingTimeoutsRecursive(mWindow, mWindow);
6775 :
6776 0 : return NS_OK;
6777 : }
6778 :
6779 : private:
6780 : nsRefPtr<nsGlobalWindow> mWindow;
6781 : };
6782 :
6783 : void
6784 0 : nsGlobalWindow::LeaveModalState(nsIDOMWindow *aCallerWin)
6785 : {
6786 0 : nsGlobalWindow *topWin = GetTop();
6787 :
6788 0 : if (!topWin) {
6789 0 : NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
6790 0 : return;
6791 : }
6792 :
6793 0 : topWin->mModalStateDepth--;
6794 :
6795 0 : if (topWin->mModalStateDepth == 0) {
6796 0 : nsCOMPtr<nsIRunnable> runner = new nsPendingTimeoutRunner(topWin);
6797 0 : if (NS_FAILED(NS_DispatchToCurrentThread(runner)))
6798 0 : NS_WARNING("failed to dispatch pending timeout runnable");
6799 :
6800 0 : if (mSuspendedDoc) {
6801 : nsCOMPtr<nsIDocument> currentDoc =
6802 0 : do_QueryInterface(topWin->GetExtantDocument());
6803 0 : mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(currentDoc == mSuspendedDoc);
6804 0 : mSuspendedDoc = nsnull;
6805 : }
6806 : }
6807 :
6808 0 : if (aCallerWin) {
6809 0 : nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aCallerWin));
6810 0 : nsIScriptContext *scx = sgo->GetContext();
6811 0 : if (scx)
6812 0 : scx->LeaveModalState();
6813 : }
6814 :
6815 0 : if (mContext) {
6816 0 : mContext->LeaveModalState();
6817 : }
6818 :
6819 : // Remember the time of the last dialog quit.
6820 0 : nsGlobalWindow *inner = topWin->GetCurrentInnerWindowInternal();
6821 0 : if (inner)
6822 0 : inner->mLastDialogQuitTime = TimeStamp::Now();
6823 : }
6824 :
6825 : bool
6826 0 : nsGlobalWindow::IsInModalState()
6827 : {
6828 0 : nsGlobalWindow *topWin = GetTop();
6829 :
6830 0 : if (!topWin) {
6831 0 : NS_ERROR("Uh, IsInModalState() called w/o a reachable top window?");
6832 :
6833 0 : return false;
6834 : }
6835 :
6836 0 : return topWin->mModalStateDepth != 0;
6837 : }
6838 :
6839 : // static
6840 : void
6841 0 : nsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow) {
6842 : nsCOMPtr<nsIObserverService> observerService =
6843 0 : services::GetObserverService();
6844 0 : if (observerService) {
6845 0 : observerService->
6846 0 : NotifyObservers(static_cast<nsIScriptGlobalObject*>(aWindow),
6847 0 : DOM_WINDOW_DESTROYED_TOPIC, nsnull);
6848 : }
6849 0 : }
6850 :
6851 : class WindowDestroyedEvent : public nsRunnable
6852 0 : {
6853 : public:
6854 0 : WindowDestroyedEvent(PRUint64 aID, const char* aTopic) :
6855 0 : mID(aID), mTopic(aTopic) {}
6856 :
6857 0 : NS_IMETHOD Run()
6858 : {
6859 : nsCOMPtr<nsIObserverService> observerService =
6860 0 : do_GetService("@mozilla.org/observer-service;1");
6861 0 : if (observerService) {
6862 : nsCOMPtr<nsISupportsPRUint64> wrapper =
6863 0 : do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
6864 0 : if (wrapper) {
6865 0 : wrapper->SetData(mID);
6866 0 : observerService->NotifyObservers(wrapper, mTopic.get(), nsnull);
6867 : }
6868 : }
6869 0 : return NS_OK;
6870 : }
6871 :
6872 : private:
6873 : PRUint64 mID;
6874 : nsCString mTopic;
6875 : };
6876 :
6877 : void
6878 0 : nsGlobalWindow::NotifyWindowIDDestroyed(const char* aTopic)
6879 : {
6880 0 : nsRefPtr<nsIRunnable> runnable = new WindowDestroyedEvent(mWindowID, aTopic);
6881 0 : nsresult rv = NS_DispatchToCurrentThread(runnable);
6882 0 : if (NS_SUCCEEDED(rv)) {
6883 0 : mNotifiedIDDestroyed = true;
6884 : }
6885 0 : }
6886 :
6887 : // static
6888 : void
6889 0 : nsGlobalWindow::NotifyDOMWindowFrozen(nsGlobalWindow* aWindow) {
6890 0 : if (aWindow && aWindow->IsInnerWindow()) {
6891 : nsCOMPtr<nsIObserverService> observerService =
6892 0 : services::GetObserverService();
6893 0 : if (observerService) {
6894 0 : observerService->
6895 0 : NotifyObservers(static_cast<nsIScriptGlobalObject*>(aWindow),
6896 0 : DOM_WINDOW_FROZEN_TOPIC, nsnull);
6897 : }
6898 : }
6899 0 : }
6900 :
6901 : // static
6902 : void
6903 0 : nsGlobalWindow::NotifyDOMWindowThawed(nsGlobalWindow* aWindow) {
6904 0 : if (aWindow && aWindow->IsInnerWindow()) {
6905 : nsCOMPtr<nsIObserverService> observerService =
6906 0 : services::GetObserverService();
6907 0 : if (observerService) {
6908 0 : observerService->
6909 0 : NotifyObservers(static_cast<nsIScriptGlobalObject*>(aWindow),
6910 0 : DOM_WINDOW_THAWED_TOPIC, nsnull);
6911 : }
6912 : }
6913 0 : }
6914 :
6915 : void
6916 0 : nsGlobalWindow::InitJavaProperties()
6917 : {
6918 0 : nsIScriptContext *scx = GetContextInternal();
6919 :
6920 0 : if (mDidInitJavaProperties || IsOuterWindow() || !scx || !mJSObject) {
6921 0 : return;
6922 : }
6923 :
6924 : // Set mDidInitJavaProperties to true here even if initialization
6925 : // can fail. If it fails, we won't try again...
6926 0 : mDidInitJavaProperties = true;
6927 :
6928 0 : mDummyJavaPluginOwner = new nsDummyJavaPluginOwner(mDoc);
6929 0 : if (!mDummyJavaPluginOwner) {
6930 0 : return;
6931 : }
6932 :
6933 0 : nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
6934 0 : nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
6935 0 : if (!pluginHost) {
6936 : return;
6937 : }
6938 0 : pluginHost->InstantiateDummyJavaPlugin(mDummyJavaPluginOwner);
6939 :
6940 : // It's possible for us (or the Java plugin, rather) to process
6941 : // events during the above call, which can lead to this window being
6942 : // torn down or what not, so re-check that the dummy plugin is still
6943 : // around.
6944 0 : if (!mDummyJavaPluginOwner) {
6945 : return;
6946 : }
6947 :
6948 0 : nsRefPtr<nsNPAPIPluginInstance> dummyPlugin;
6949 0 : mDummyJavaPluginOwner->GetInstance(getter_AddRefs(dummyPlugin));
6950 :
6951 0 : if (dummyPlugin) {
6952 : // A dummy plugin was instantiated. This means we have a Java
6953 : // plugin that supports NPRuntime. For such a plugin, the plugin
6954 : // instantiation code defines the Java properties for us, so we're
6955 : // done here.
6956 :
6957 : return;
6958 : }
6959 :
6960 : // No NPRuntime enabled Java plugin found, null out the owner we
6961 : // would have used in that case as it's no longer needed.
6962 0 : mDummyJavaPluginOwner = nsnull;
6963 : }
6964 :
6965 : JSObject*
6966 0 : nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey)
6967 : {
6968 0 : JSObject* handler = nsnull;
6969 0 : if (mCachedXBLPrototypeHandlers.IsInitialized()) {
6970 0 : mCachedXBLPrototypeHandlers.Get(aKey, &handler);
6971 : }
6972 0 : return handler;
6973 : }
6974 :
6975 : void
6976 0 : nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
6977 : nsScriptObjectHolder<JSObject>& aHandler)
6978 : {
6979 0 : if (!mCachedXBLPrototypeHandlers.IsInitialized() &&
6980 0 : !mCachedXBLPrototypeHandlers.Init()) {
6981 0 : NS_ERROR("Failed to initiailize hashtable!");
6982 0 : return;
6983 : }
6984 :
6985 0 : if (!mCachedXBLPrototypeHandlers.Count()) {
6986 : // Can't use macros to get the participant because nsGlobalChromeWindow also
6987 : // runs through this code. Use QueryInterface to get the correct objects.
6988 : nsXPCOMCycleCollectionParticipant* participant;
6989 0 : CallQueryInterface(this, &participant);
6990 0 : NS_ASSERTION(participant,
6991 : "Failed to QI to nsXPCOMCycleCollectionParticipant!");
6992 :
6993 : nsISupports* thisSupports;
6994 : QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
6995 0 : reinterpret_cast<void**>(&thisSupports));
6996 0 : NS_ASSERTION(thisSupports, "Failed to QI to nsCycleCollectionISupports!");
6997 :
6998 0 : nsresult rv = nsContentUtils::HoldJSObjects(thisSupports, participant);
6999 0 : if (NS_FAILED(rv)) {
7000 0 : NS_ERROR("nsContentUtils::HoldJSObjects failed!");
7001 0 : return;
7002 : }
7003 : }
7004 :
7005 0 : mCachedXBLPrototypeHandlers.Put(aKey, aHandler.get());
7006 : }
7007 :
7008 : /**
7009 : * GetScriptableFrameElement is called when script reads
7010 : * nsIGlobalWindow::frameElement.
7011 : *
7012 : * In contrast to GetRealFrameElement, GetScriptableFrameElement says that the
7013 : * window contained by an <iframe mozbrowser> has no frame element
7014 : * (effectively treating a mozbrowser the same as a content/chrome boundary).
7015 : */
7016 : NS_IMETHODIMP
7017 0 : nsGlobalWindow::GetScriptableFrameElement(nsIDOMElement** aFrameElement)
7018 : {
7019 0 : FORWARD_TO_OUTER(GetScriptableFrameElement, (aFrameElement), NS_ERROR_NOT_INITIALIZED);
7020 0 : *aFrameElement = NULL;
7021 :
7022 0 : if (!mDocShell) {
7023 0 : return NS_OK;
7024 : }
7025 :
7026 0 : bool isMozBrowser = false;
7027 0 : mDocShell->GetIsBrowserFrame(&isMozBrowser);
7028 0 : if (isMozBrowser) {
7029 0 : return NS_OK;
7030 : }
7031 :
7032 0 : return GetFrameElement(aFrameElement);
7033 : }
7034 :
7035 : /**
7036 : * nsIGlobalWindow::GetFrameElement (when called from C++) is just a wrapper
7037 : * around GetRealFrameElement.
7038 : */
7039 : NS_IMETHODIMP
7040 0 : nsGlobalWindow::GetRealFrameElement(nsIDOMElement** aFrameElement)
7041 : {
7042 0 : FORWARD_TO_OUTER(GetRealFrameElement, (aFrameElement), NS_ERROR_NOT_INITIALIZED);
7043 :
7044 0 : *aFrameElement = NULL;
7045 :
7046 0 : nsCOMPtr<nsIDocShellTreeItem> docShellTI(do_QueryInterface(mDocShell));
7047 :
7048 0 : if (!docShellTI) {
7049 0 : return NS_OK;
7050 : }
7051 :
7052 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
7053 0 : docShellTI->GetSameTypeParent(getter_AddRefs(parent));
7054 :
7055 0 : if (!parent || parent == docShellTI) {
7056 : // We're at a chrome boundary, don't expose the chrome iframe
7057 : // element to content code.
7058 :
7059 0 : return NS_OK;
7060 : }
7061 :
7062 0 : *aFrameElement = mFrameElement;
7063 0 : NS_IF_ADDREF(*aFrameElement);
7064 :
7065 0 : return NS_OK;
7066 : }
7067 :
7068 : // Helper for converting window.showModalDialog() options (list of ';'
7069 : // separated name (:|=) value pairs) to a format that's parsable by
7070 : // our normal window opening code.
7071 :
7072 : void
7073 0 : ConvertDialogOptions(const nsAString& aOptions, nsAString& aResult)
7074 : {
7075 0 : nsAString::const_iterator end;
7076 0 : aOptions.EndReading(end);
7077 :
7078 0 : nsAString::const_iterator iter;
7079 0 : aOptions.BeginReading(iter);
7080 :
7081 0 : while (iter != end) {
7082 : // Skip whitespace.
7083 0 : while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
7084 0 : ++iter;
7085 : }
7086 :
7087 0 : nsAString::const_iterator name_start = iter;
7088 :
7089 : // Skip characters until we find whitespace, ';', ':', or '='
7090 0 : while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
7091 0 : *iter != ';' &&
7092 0 : *iter != ':' &&
7093 0 : *iter != '=') {
7094 0 : ++iter;
7095 : }
7096 :
7097 0 : nsAString::const_iterator name_end = iter;
7098 :
7099 : // Skip whitespace.
7100 0 : while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
7101 0 : ++iter;
7102 : }
7103 :
7104 0 : if (*iter == ';') {
7105 : // No value found, skip the ';' and keep going.
7106 0 : ++iter;
7107 :
7108 0 : continue;
7109 : }
7110 :
7111 0 : nsAString::const_iterator value_start = iter;
7112 0 : nsAString::const_iterator value_end = iter;
7113 :
7114 0 : if (*iter == ':' || *iter == '=') {
7115 : // We found name followed by ':' or '='. Look for a value.
7116 :
7117 0 : iter++; // Skip the ':' or '='
7118 :
7119 : // Skip whitespace.
7120 0 : while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
7121 0 : ++iter;
7122 : }
7123 :
7124 0 : value_start = iter;
7125 :
7126 : // Skip until we find whitespace, or ';'.
7127 0 : while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
7128 0 : *iter != ';') {
7129 0 : ++iter;
7130 : }
7131 :
7132 0 : value_end = iter;
7133 :
7134 : // Skip whitespace.
7135 0 : while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
7136 0 : ++iter;
7137 : }
7138 : }
7139 :
7140 0 : const nsDependentSubstring& name = Substring(name_start, name_end);
7141 0 : const nsDependentSubstring& value = Substring(value_start, value_end);
7142 :
7143 0 : if (name.LowerCaseEqualsLiteral("center")) {
7144 0 : if (value.LowerCaseEqualsLiteral("on") ||
7145 0 : value.LowerCaseEqualsLiteral("yes") ||
7146 0 : value.LowerCaseEqualsLiteral("1")) {
7147 0 : aResult.AppendLiteral(",centerscreen=1");
7148 : }
7149 0 : } else if (name.LowerCaseEqualsLiteral("dialogwidth")) {
7150 0 : if (!value.IsEmpty()) {
7151 0 : aResult.AppendLiteral(",width=");
7152 0 : aResult.Append(value);
7153 : }
7154 0 : } else if (name.LowerCaseEqualsLiteral("dialogheight")) {
7155 0 : if (!value.IsEmpty()) {
7156 0 : aResult.AppendLiteral(",height=");
7157 0 : aResult.Append(value);
7158 : }
7159 0 : } else if (name.LowerCaseEqualsLiteral("dialogtop")) {
7160 0 : if (!value.IsEmpty()) {
7161 0 : aResult.AppendLiteral(",top=");
7162 0 : aResult.Append(value);
7163 : }
7164 0 : } else if (name.LowerCaseEqualsLiteral("dialogleft")) {
7165 0 : if (!value.IsEmpty()) {
7166 0 : aResult.AppendLiteral(",left=");
7167 0 : aResult.Append(value);
7168 : }
7169 0 : } else if (name.LowerCaseEqualsLiteral("resizable")) {
7170 0 : if (value.LowerCaseEqualsLiteral("on") ||
7171 0 : value.LowerCaseEqualsLiteral("yes") ||
7172 0 : value.LowerCaseEqualsLiteral("1")) {
7173 0 : aResult.AppendLiteral(",resizable=1");
7174 : }
7175 0 : } else if (name.LowerCaseEqualsLiteral("scroll")) {
7176 0 : if (value.LowerCaseEqualsLiteral("off") ||
7177 0 : value.LowerCaseEqualsLiteral("no") ||
7178 0 : value.LowerCaseEqualsLiteral("0")) {
7179 0 : aResult.AppendLiteral(",scrollbars=0");
7180 : }
7181 : }
7182 :
7183 0 : if (iter == end) {
7184 : break;
7185 : }
7186 :
7187 0 : iter++;
7188 : }
7189 0 : }
7190 :
7191 : NS_IMETHODIMP
7192 0 : nsGlobalWindow::ShowModalDialog(const nsAString& aURI, nsIVariant *aArgs,
7193 : const nsAString& aOptions,
7194 : nsIVariant **aRetVal)
7195 : {
7196 0 : FORWARD_TO_OUTER(ShowModalDialog, (aURI, aArgs, aOptions, aRetVal),
7197 : NS_ERROR_NOT_INITIALIZED);
7198 :
7199 0 : *aRetVal = nsnull;
7200 :
7201 : // Before bringing up the window/dialog, unsuppress painting and flush
7202 : // pending reflows.
7203 0 : EnsureReflowFlushAndPaint();
7204 :
7205 0 : if (AreDialogsBlocked() || !ConfirmDialogAllowed())
7206 0 : return NS_ERROR_NOT_AVAILABLE;
7207 :
7208 0 : nsCOMPtr<nsIDOMWindow> dlgWin;
7209 0 : nsAutoString options(NS_LITERAL_STRING("-moz-internal-modal=1,status=1"));
7210 :
7211 0 : ConvertDialogOptions(aOptions, options);
7212 :
7213 0 : options.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0");
7214 :
7215 0 : nsCOMPtr<nsIDOMWindow> callerWin = EnterModalState();
7216 0 : nsresult rv = OpenInternal(aURI, EmptyString(), options,
7217 : false, // aDialog
7218 : true, // aContentModal
7219 : true, // aCalledNoScript
7220 : true, // aDoJSFixups
7221 : nsnull, aArgs, // args
7222 0 : GetPrincipal(), // aCalleePrincipal
7223 : nsnull, // aJSCallerContext
7224 0 : getter_AddRefs(dlgWin));
7225 0 : LeaveModalState(callerWin);
7226 :
7227 0 : NS_ENSURE_SUCCESS(rv, rv);
7228 :
7229 0 : if (dlgWin) {
7230 0 : nsCOMPtr<nsIPrincipal> subjectPrincipal;
7231 0 : rv = nsContentUtils::GetSecurityManager()->
7232 0 : GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
7233 0 : if (NS_FAILED(rv)) {
7234 0 : return rv;
7235 : }
7236 :
7237 0 : bool canAccess = true;
7238 :
7239 0 : if (subjectPrincipal) {
7240 : nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
7241 0 : do_QueryInterface(dlgWin);
7242 0 : nsCOMPtr<nsIPrincipal> dialogPrincipal;
7243 :
7244 0 : if (objPrincipal) {
7245 0 : dialogPrincipal = objPrincipal->GetPrincipal();
7246 :
7247 0 : rv = subjectPrincipal->Subsumes(dialogPrincipal, &canAccess);
7248 0 : NS_ENSURE_SUCCESS(rv, rv);
7249 : } else {
7250 : // Uh, not sure what kind of dialog this is. Prevent access to
7251 : // be on the safe side...
7252 :
7253 0 : canAccess = false;
7254 : }
7255 : }
7256 :
7257 0 : nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(dlgWin));
7258 :
7259 0 : if (canAccess) {
7260 0 : nsPIDOMWindow *inner = win->GetCurrentInnerWindow();
7261 :
7262 0 : nsCOMPtr<nsIDOMModalContentWindow> dlgInner(do_QueryInterface(inner));
7263 :
7264 0 : if (dlgInner) {
7265 0 : dlgInner->GetReturnValue(aRetVal);
7266 : }
7267 : }
7268 :
7269 : nsRefPtr<nsGlobalWindow> winInternal =
7270 0 : static_cast<nsGlobalWindow*>(win.get());
7271 0 : if (winInternal->mCallCleanUpAfterModalDialogCloses) {
7272 0 : winInternal->mCallCleanUpAfterModalDialogCloses = false;
7273 0 : winInternal->CleanUp(true);
7274 : }
7275 : }
7276 :
7277 0 : return NS_OK;
7278 : }
7279 :
7280 : class CommandDispatcher : public nsRunnable
7281 0 : {
7282 : public:
7283 0 : CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
7284 : const nsAString& aAction)
7285 0 : : mDispatcher(aDispatcher), mAction(aAction) {}
7286 :
7287 0 : NS_IMETHOD Run()
7288 : {
7289 0 : return mDispatcher->UpdateCommands(mAction);
7290 : }
7291 :
7292 : nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
7293 : nsString mAction;
7294 : };
7295 :
7296 : NS_IMETHODIMP
7297 0 : nsGlobalWindow::UpdateCommands(const nsAString& anAction)
7298 : {
7299 0 : nsPIDOMWindow *rootWindow = nsGlobalWindow::GetPrivateRoot();
7300 0 : if (!rootWindow)
7301 0 : return NS_OK;
7302 :
7303 : nsCOMPtr<nsIDOMXULDocument> xulDoc =
7304 0 : do_QueryInterface(rootWindow->GetExtantDocument());
7305 : // See if we contain a XUL document.
7306 0 : if (xulDoc) {
7307 : // Retrieve the command dispatcher and call updateCommands on it.
7308 0 : nsCOMPtr<nsIDOMXULCommandDispatcher> xulCommandDispatcher;
7309 0 : xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher));
7310 0 : if (xulCommandDispatcher) {
7311 : nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
7312 0 : anAction));
7313 : }
7314 : }
7315 :
7316 0 : return NS_OK;
7317 : }
7318 :
7319 : NS_IMETHODIMP
7320 0 : nsGlobalWindow::GetSelection(nsISelection** aSelection)
7321 : {
7322 0 : FORWARD_TO_OUTER(GetSelection, (aSelection), NS_ERROR_NOT_INITIALIZED);
7323 :
7324 0 : NS_ENSURE_ARG_POINTER(aSelection);
7325 0 : *aSelection = nsnull;
7326 :
7327 0 : if (!mDocShell)
7328 0 : return NS_OK;
7329 :
7330 0 : nsCOMPtr<nsIPresShell> presShell;
7331 0 : mDocShell->GetPresShell(getter_AddRefs(presShell));
7332 :
7333 0 : if (!presShell)
7334 0 : return NS_OK;
7335 :
7336 0 : *aSelection = presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
7337 :
7338 0 : NS_IF_ADDREF(*aSelection);
7339 :
7340 0 : return NS_OK;
7341 : }
7342 :
7343 : NS_IMETHODIMP
7344 0 : nsGlobalWindow::Find(const nsAString& aStr, bool aCaseSensitive,
7345 : bool aBackwards, bool aWrapAround, bool aWholeWord,
7346 : bool aSearchInFrames, bool aShowDialog,
7347 : bool *aDidFind)
7348 : {
7349 0 : FORWARD_TO_OUTER(Find, (aStr, aCaseSensitive, aBackwards, aWrapAround,
7350 : aWholeWord, aSearchInFrames, aShowDialog, aDidFind),
7351 : NS_ERROR_NOT_INITIALIZED);
7352 :
7353 0 : nsresult rv = NS_OK;
7354 0 : *aDidFind = false;
7355 :
7356 0 : nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
7357 0 : NS_ENSURE_TRUE(finder, NS_ERROR_FAILURE);
7358 :
7359 : // Set the options of the search
7360 0 : rv = finder->SetSearchString(PromiseFlatString(aStr).get());
7361 0 : NS_ENSURE_SUCCESS(rv, rv);
7362 0 : finder->SetMatchCase(aCaseSensitive);
7363 0 : finder->SetFindBackwards(aBackwards);
7364 0 : finder->SetWrapFind(aWrapAround);
7365 0 : finder->SetEntireWord(aWholeWord);
7366 0 : finder->SetSearchFrames(aSearchInFrames);
7367 :
7368 : // the nsIWebBrowserFind is initialized to use this window
7369 : // as the search root, but uses focus to set the current search
7370 : // frame. If we're being called from JS (as here), this window
7371 : // should be the current search frame.
7372 0 : nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
7373 0 : if (framesFinder) {
7374 0 : framesFinder->SetRootSearchFrame(this); // paranoia
7375 0 : framesFinder->SetCurrentSearchFrame(this);
7376 : }
7377 :
7378 : // The Find API does not accept empty strings. Launch the Find Dialog.
7379 0 : if (aStr.IsEmpty() || aShowDialog) {
7380 : // See if the find dialog is already up using nsIWindowMediator
7381 : nsCOMPtr<nsIWindowMediator> windowMediator =
7382 0 : do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
7383 :
7384 0 : nsCOMPtr<nsIDOMWindow> findDialog;
7385 :
7386 0 : if (windowMediator) {
7387 0 : windowMediator->GetMostRecentWindow(NS_LITERAL_STRING("findInPage").get(),
7388 0 : getter_AddRefs(findDialog));
7389 : }
7390 :
7391 0 : if (findDialog) {
7392 : // The Find dialog is already open, bring it to the top.
7393 0 : rv = findDialog->Focus();
7394 : } else { // Open a Find dialog
7395 0 : if (finder) {
7396 0 : nsCOMPtr<nsIDOMWindow> dialog;
7397 0 : rv = OpenDialog(NS_LITERAL_STRING("chrome://global/content/finddialog.xul"),
7398 0 : NS_LITERAL_STRING("_blank"),
7399 0 : NS_LITERAL_STRING("chrome, resizable=no, dependent=yes"),
7400 0 : finder, getter_AddRefs(dialog));
7401 : }
7402 : }
7403 : } else {
7404 : // Launch the search with the passed in search string
7405 0 : rv = finder->FindNext(aDidFind);
7406 0 : NS_ENSURE_SUCCESS(rv, rv);
7407 : }
7408 :
7409 0 : return rv;
7410 : }
7411 :
7412 : NS_IMETHODIMP
7413 0 : nsGlobalWindow::Atob(const nsAString& aAsciiBase64String,
7414 : nsAString& aBinaryData)
7415 : {
7416 0 : return nsContentUtils::Atob(aAsciiBase64String, aBinaryData);
7417 : }
7418 :
7419 : NS_IMETHODIMP
7420 0 : nsGlobalWindow::Btoa(const nsAString& aBinaryData,
7421 : nsAString& aAsciiBase64String)
7422 : {
7423 0 : return nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
7424 : }
7425 :
7426 : //*****************************************************************************
7427 : // nsGlobalWindow::nsIDOMEventTarget
7428 : //*****************************************************************************
7429 :
7430 : NS_IMETHODIMP
7431 0 : nsGlobalWindow::RemoveEventListener(const nsAString& aType,
7432 : nsIDOMEventListener* aListener,
7433 : bool aUseCapture)
7434 : {
7435 0 : nsRefPtr<nsEventListenerManager> elm = GetListenerManager(false);
7436 0 : if (elm) {
7437 0 : elm->RemoveEventListener(aType, aListener, aUseCapture);
7438 : }
7439 0 : return NS_OK;
7440 : }
7441 :
7442 0 : NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsGlobalWindow)
7443 :
7444 : NS_IMETHODIMP
7445 0 : nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
7446 : {
7447 0 : FORWARD_TO_INNER(DispatchEvent, (aEvent, aRetVal), NS_OK);
7448 :
7449 0 : if (!mDoc) {
7450 0 : return NS_ERROR_FAILURE;
7451 : }
7452 :
7453 : // Obtain a presentation shell
7454 0 : nsIPresShell *shell = mDoc->GetShell();
7455 0 : nsRefPtr<nsPresContext> presContext;
7456 0 : if (shell) {
7457 : // Retrieve the context
7458 0 : presContext = shell->GetPresContext();
7459 : }
7460 :
7461 0 : nsEventStatus status = nsEventStatus_eIgnore;
7462 : nsresult rv =
7463 0 : nsEventDispatcher::DispatchDOMEvent(GetOuterWindow(), nsnull, aEvent,
7464 0 : presContext, &status);
7465 :
7466 0 : *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
7467 0 : return rv;
7468 : }
7469 :
7470 : NS_IMETHODIMP
7471 0 : nsGlobalWindow::AddEventListener(const nsAString& aType,
7472 : nsIDOMEventListener *aListener,
7473 : bool aUseCapture, bool aWantsUntrusted,
7474 : PRUint8 aOptionalArgc)
7475 : {
7476 0 : NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
7477 : "Won't check if this is chrome, you want to set "
7478 : "aWantsUntrusted to false or make the aWantsUntrusted "
7479 : "explicit by making optional_argc non-zero.");
7480 :
7481 0 : if (IsOuterWindow() && mInnerWindow &&
7482 0 : !nsContentUtils::CanCallerAccess(mInnerWindow)) {
7483 0 : return NS_ERROR_DOM_SECURITY_ERR;
7484 : }
7485 :
7486 0 : if (!aWantsUntrusted &&
7487 0 : (aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) {
7488 0 : aWantsUntrusted = true;
7489 : }
7490 :
7491 0 : nsEventListenerManager* manager = GetListenerManager(true);
7492 0 : NS_ENSURE_STATE(manager);
7493 0 : manager->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
7494 0 : return NS_OK;
7495 : }
7496 :
7497 : NS_IMETHODIMP
7498 0 : nsGlobalWindow::AddSystemEventListener(const nsAString& aType,
7499 : nsIDOMEventListener *aListener,
7500 : bool aUseCapture,
7501 : bool aWantsUntrusted,
7502 : PRUint8 aOptionalArgc)
7503 : {
7504 0 : NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
7505 : "Won't check if this is chrome, you want to set "
7506 : "aWantsUntrusted to false or make the aWantsUntrusted "
7507 : "explicit by making optional_argc non-zero.");
7508 :
7509 0 : if (IsOuterWindow() && mInnerWindow &&
7510 0 : !nsContentUtils::CanCallerAccess(mInnerWindow)) {
7511 0 : return NS_ERROR_DOM_SECURITY_ERR;
7512 : }
7513 :
7514 0 : if (!aWantsUntrusted &&
7515 0 : (aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) {
7516 0 : aWantsUntrusted = true;
7517 : }
7518 :
7519 : return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
7520 0 : aWantsUntrusted);
7521 : }
7522 :
7523 : nsEventListenerManager*
7524 0 : nsGlobalWindow::GetListenerManager(bool aCreateIfNotFound)
7525 : {
7526 0 : FORWARD_TO_INNER_CREATE(GetListenerManager, (aCreateIfNotFound), nsnull);
7527 :
7528 0 : if (!mListenerManager && aCreateIfNotFound) {
7529 : mListenerManager =
7530 0 : new nsEventListenerManager(static_cast<nsIDOMEventTarget*>(this));
7531 : }
7532 :
7533 0 : return mListenerManager;
7534 : }
7535 :
7536 : nsIScriptContext*
7537 0 : nsGlobalWindow::GetContextForEventHandlers(nsresult* aRv)
7538 : {
7539 0 : *aRv = NS_ERROR_UNEXPECTED;
7540 0 : if (IsInnerWindow()) {
7541 0 : nsPIDOMWindow* outer = GetOuterWindow();
7542 0 : NS_ENSURE_TRUE(outer && outer->GetCurrentInnerWindow() == this, nsnull);
7543 : }
7544 :
7545 : nsIScriptContext* scx;
7546 0 : if ((scx = GetContext())) {
7547 0 : *aRv = NS_OK;
7548 0 : return scx;
7549 : }
7550 0 : return nsnull;
7551 : }
7552 :
7553 : //*****************************************************************************
7554 : // nsGlobalWindow::nsPIDOMWindow
7555 : //*****************************************************************************
7556 :
7557 : nsPIDOMWindow*
7558 0 : nsGlobalWindow::GetPrivateParent()
7559 : {
7560 0 : FORWARD_TO_OUTER(GetPrivateParent, (), nsnull);
7561 :
7562 0 : nsCOMPtr<nsIDOMWindow> parent;
7563 0 : GetParent(getter_AddRefs(parent));
7564 :
7565 0 : if (static_cast<nsIDOMWindow *>(this) == parent.get()) {
7566 0 : nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
7567 0 : if (!chromeElement)
7568 0 : return nsnull; // This is ok, just means a null parent.
7569 :
7570 0 : nsIDocument* doc = chromeElement->GetDocument();
7571 0 : if (!doc)
7572 0 : return nsnull; // This is ok, just means a null parent.
7573 :
7574 0 : nsIScriptGlobalObject *globalObject = doc->GetScriptGlobalObject();
7575 0 : if (!globalObject)
7576 0 : return nsnull; // This is ok, just means a null parent.
7577 :
7578 0 : parent = do_QueryInterface(globalObject);
7579 : }
7580 :
7581 0 : if (parent) {
7582 : return static_cast<nsGlobalWindow *>
7583 0 : (static_cast<nsIDOMWindow*>(parent.get()));
7584 : }
7585 :
7586 0 : return nsnull;
7587 : }
7588 :
7589 : nsPIDOMWindow*
7590 0 : nsGlobalWindow::GetPrivateRoot()
7591 : {
7592 0 : FORWARD_TO_OUTER(GetPrivateRoot, (), nsnull);
7593 :
7594 0 : nsCOMPtr<nsIDOMWindow> top;
7595 0 : GetTop(getter_AddRefs(top));
7596 :
7597 0 : nsCOMPtr<nsPIDOMWindow> ptop = do_QueryInterface(top);
7598 0 : NS_ASSERTION(ptop, "cannot get ptop");
7599 0 : if (!ptop)
7600 0 : return nsnull;
7601 :
7602 0 : nsIDocShell *docShell = ptop->GetDocShell();
7603 :
7604 : // Get the chrome event handler from the doc shell, since we only
7605 : // want to deal with XUL chrome handlers and not the new kind of
7606 : // window root handler.
7607 0 : nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
7608 0 : docShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
7609 :
7610 0 : nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
7611 0 : if (chromeElement) {
7612 0 : nsIDocument* doc = chromeElement->GetDocument();
7613 0 : if (doc) {
7614 0 : nsIDOMWindow *parent = doc->GetWindow();
7615 0 : if (parent) {
7616 0 : parent->GetTop(getter_AddRefs(top));
7617 : }
7618 : }
7619 : }
7620 :
7621 : return static_cast<nsGlobalWindow *>
7622 0 : (static_cast<nsIDOMWindow *>(top));
7623 : }
7624 :
7625 :
7626 : NS_IMETHODIMP
7627 0 : nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation)
7628 : {
7629 0 : FORWARD_TO_INNER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED);
7630 :
7631 0 : *aLocation = nsnull;
7632 :
7633 0 : nsIDocShell *docShell = GetDocShell();
7634 0 : if (!mLocation && docShell) {
7635 0 : mLocation = new nsLocation(docShell);
7636 0 : if (!mLocation) {
7637 0 : return NS_ERROR_OUT_OF_MEMORY;
7638 : }
7639 : }
7640 :
7641 0 : NS_IF_ADDREF(*aLocation = mLocation);
7642 :
7643 0 : return NS_OK;
7644 : }
7645 :
7646 : void
7647 0 : nsGlobalWindow::ActivateOrDeactivate(bool aActivate)
7648 : {
7649 : // Set / unset mIsActive on the top level window, which is used for the
7650 : // :-moz-window-inactive pseudoclass.
7651 0 : nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
7652 0 : if (!mainWidget)
7653 : return;
7654 :
7655 : // Get the top level widget (if the main widget is a sheet, this will
7656 : // be the sheet's top (non-sheet) parent).
7657 0 : nsCOMPtr<nsIWidget> topLevelWidget = mainWidget->GetSheetWindowParent();
7658 0 : if (!topLevelWidget) {
7659 0 : topLevelWidget = mainWidget;
7660 : }
7661 :
7662 : // Get the top level widget's nsGlobalWindow
7663 0 : nsCOMPtr<nsIDOMWindow> topLevelWindow;
7664 0 : if (topLevelWidget == mainWidget) {
7665 0 : topLevelWindow = static_cast<nsIDOMWindow*>(this);
7666 : } else {
7667 : // This is a workaround for the following problem:
7668 : // When a window with an open sheet loses focus, only the sheet window
7669 : // receives the NS_DEACTIVATE event. However, it's not the sheet that
7670 : // should lose the active styling, but the containing top level window.
7671 : void* clientData;
7672 0 : topLevelWidget->GetClientData(clientData); // clientData is nsXULWindow
7673 0 : nsISupports* data = static_cast<nsISupports*>(clientData);
7674 0 : nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(data));
7675 0 : topLevelWindow = do_GetInterface(req);
7676 : }
7677 0 : if (topLevelWindow) {
7678 0 : nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(topLevelWindow));
7679 0 : piWin->SetActive(aActivate);
7680 : }
7681 : }
7682 :
7683 : static bool
7684 0 : NotifyDocumentTree(nsIDocument* aDocument, void* aData)
7685 : {
7686 0 : aDocument->EnumerateSubDocuments(NotifyDocumentTree, nsnull);
7687 0 : aDocument->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
7688 0 : return true;
7689 : }
7690 :
7691 : void
7692 0 : nsGlobalWindow::SetActive(bool aActive)
7693 : {
7694 0 : nsPIDOMWindow::SetActive(aActive);
7695 0 : NotifyDocumentTree(mDoc, nsnull);
7696 0 : }
7697 :
7698 0 : void nsGlobalWindow::SetIsBackground(bool aIsBackground)
7699 : {
7700 0 : bool resetTimers = (!aIsBackground && IsBackground());
7701 0 : nsPIDOMWindow::SetIsBackground(aIsBackground);
7702 0 : if (resetTimers) {
7703 0 : ResetTimersForNonBackgroundWindow();
7704 : }
7705 0 : }
7706 :
7707 0 : void nsGlobalWindow::MaybeUpdateTouchState()
7708 : {
7709 0 : FORWARD_TO_INNER_VOID(MaybeUpdateTouchState, ());
7710 :
7711 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7712 :
7713 0 : nsCOMPtr<nsIDOMWindow> focusedWindow;
7714 0 : fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
7715 :
7716 0 : if(this == focusedWindow) {
7717 0 : UpdateTouchState();
7718 : }
7719 :
7720 0 : if (mMayHaveTouchEventListener) {
7721 : nsCOMPtr<nsIObserverService> observerService =
7722 0 : do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
7723 :
7724 0 : if (observerService) {
7725 0 : observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
7726 : DOM_TOUCH_LISTENER_ADDED,
7727 0 : nsnull);
7728 : }
7729 : }
7730 : }
7731 :
7732 0 : void nsGlobalWindow::UpdateTouchState()
7733 : {
7734 0 : FORWARD_TO_INNER_VOID(UpdateTouchState, ());
7735 :
7736 0 : nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
7737 0 : if (!mainWidget) {
7738 : return;
7739 : }
7740 :
7741 0 : if (mMayHaveTouchEventListener) {
7742 0 : mainWidget->RegisterTouchWindow();
7743 : } else {
7744 0 : mainWidget->UnregisterTouchWindow();
7745 : }
7746 : }
7747 :
7748 : void
7749 0 : nsGlobalWindow::EnableDeviceMotionUpdates()
7750 : {
7751 0 : if (mHasDeviceMotion) {
7752 : nsCOMPtr<nsIDeviceMotion> ac =
7753 0 : do_GetService(NS_DEVICE_MOTION_CONTRACTID);
7754 0 : if (ac) {
7755 0 : ac->AddWindowListener(this);
7756 : }
7757 : }
7758 0 : }
7759 :
7760 : void
7761 0 : nsGlobalWindow::DisableDeviceMotionUpdates()
7762 : {
7763 0 : if (mHasDeviceMotion) {
7764 : nsCOMPtr<nsIDeviceMotion> ac =
7765 0 : do_GetService(NS_DEVICE_MOTION_CONTRACTID);
7766 0 : if (ac) {
7767 0 : ac->RemoveWindowListener(this);
7768 : }
7769 : }
7770 0 : }
7771 :
7772 : void
7773 0 : nsGlobalWindow::SetChromeEventHandler(nsIDOMEventTarget* aChromeEventHandler)
7774 : {
7775 0 : SetChromeEventHandlerInternal(aChromeEventHandler);
7776 0 : if (IsOuterWindow()) {
7777 : // update the chrome event handler on all our inner windows
7778 0 : for (nsGlobalWindow *inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
7779 : inner != this;
7780 0 : inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
7781 0 : NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
7782 : "bad outer window pointer");
7783 0 : inner->SetChromeEventHandlerInternal(aChromeEventHandler);
7784 : }
7785 0 : } else if (mOuterWindow) {
7786 : // Need the cast to be able to call the protected method on a
7787 : // superclass. We could make the method public instead, but it's really
7788 : // better this way.
7789 0 : static_cast<nsGlobalWindow*>(mOuterWindow.get())->
7790 0 : SetChromeEventHandlerInternal(aChromeEventHandler);
7791 : }
7792 0 : }
7793 :
7794 0 : static bool IsLink(nsIContent* aContent)
7795 : {
7796 0 : nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = do_QueryInterface(aContent);
7797 : return (anchor || (aContent &&
7798 : aContent->AttrValueIs(kNameSpaceID_XLink, nsGkAtoms::type,
7799 0 : nsGkAtoms::simple, eCaseMatters)));
7800 : }
7801 :
7802 : void
7803 0 : nsGlobalWindow::SetFocusedNode(nsIContent* aNode,
7804 : PRUint32 aFocusMethod,
7805 : bool aNeedsFocus)
7806 : {
7807 0 : FORWARD_TO_INNER_VOID(SetFocusedNode, (aNode, aFocusMethod, aNeedsFocus));
7808 :
7809 0 : if (aNode && aNode->GetCurrentDoc() != mDoc) {
7810 0 : NS_WARNING("Trying to set focus to a node from a wrong document");
7811 0 : return;
7812 : }
7813 :
7814 0 : if (mCleanedUp) {
7815 0 : NS_ASSERTION(!aNode, "Trying to focus cleaned up window!");
7816 0 : aNode = nsnull;
7817 0 : aNeedsFocus = false;
7818 : }
7819 0 : if (mFocusedNode != aNode) {
7820 0 : UpdateCanvasFocus(false, aNode);
7821 0 : mFocusedNode = aNode;
7822 0 : mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
7823 0 : mShowFocusRingForContent = false;
7824 : }
7825 :
7826 0 : if (mFocusedNode) {
7827 : // if a node was focused by a keypress, turn on focus rings for the
7828 : // window.
7829 0 : if (mFocusMethod & nsIFocusManager::FLAG_BYKEY) {
7830 0 : mFocusByKeyOccurred = true;
7831 0 : } else if (
7832 : // otherwise, we set mShowFocusRingForContent, as we don't want this to
7833 : // be permanent for the window. On Windows, focus rings are only shown
7834 : // when the FLAG_SHOWRING flag is used. On other platforms, focus rings
7835 : // are only hidden for clicks on links.
7836 : #ifndef XP_WIN
7837 0 : !(mFocusMethod & nsIFocusManager::FLAG_BYMOUSE) || !IsLink(aNode) ||
7838 : #endif
7839 : aFocusMethod & nsIFocusManager::FLAG_SHOWRING) {
7840 0 : mShowFocusRingForContent = true;
7841 : }
7842 : }
7843 :
7844 0 : if (aNeedsFocus)
7845 0 : mNeedsFocus = aNeedsFocus;
7846 : }
7847 :
7848 : PRUint32
7849 0 : nsGlobalWindow::GetFocusMethod()
7850 : {
7851 0 : FORWARD_TO_INNER(GetFocusMethod, (), 0);
7852 :
7853 0 : return mFocusMethod;
7854 : }
7855 :
7856 : bool
7857 0 : nsGlobalWindow::ShouldShowFocusRing()
7858 : {
7859 0 : FORWARD_TO_INNER(ShouldShowFocusRing, (), false);
7860 :
7861 0 : return mShowFocusRings || mShowFocusRingForContent || mFocusByKeyOccurred;
7862 : }
7863 :
7864 : void
7865 0 : nsGlobalWindow::SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
7866 : UIStateChangeType aShowFocusRings)
7867 : {
7868 0 : FORWARD_TO_INNER_VOID(SetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
7869 :
7870 0 : bool oldShouldShowFocusRing = ShouldShowFocusRing();
7871 :
7872 : // only change the flags that have been modified
7873 0 : if (aShowAccelerators != UIStateChangeType_NoChange)
7874 0 : mShowAccelerators = aShowAccelerators == UIStateChangeType_Set;
7875 0 : if (aShowFocusRings != UIStateChangeType_NoChange)
7876 0 : mShowFocusRings = aShowFocusRings == UIStateChangeType_Set;
7877 :
7878 : // propagate the indicators to child windows
7879 0 : nsCOMPtr<nsIDocShellTreeNode> node = do_QueryInterface(GetDocShell());
7880 0 : if (node) {
7881 0 : PRInt32 childCount = 0;
7882 0 : node->GetChildCount(&childCount);
7883 :
7884 0 : for (PRInt32 i = 0; i < childCount; ++i) {
7885 0 : nsCOMPtr<nsIDocShellTreeItem> childShell;
7886 0 : node->GetChildAt(i, getter_AddRefs(childShell));
7887 0 : nsCOMPtr<nsPIDOMWindow> childWindow = do_GetInterface(childShell);
7888 0 : if (childWindow) {
7889 0 : childWindow->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
7890 : }
7891 : }
7892 : }
7893 :
7894 0 : bool newShouldShowFocusRing = ShouldShowFocusRing();
7895 0 : if (mHasFocus && mFocusedNode &&
7896 : oldShouldShowFocusRing != newShouldShowFocusRing &&
7897 0 : mFocusedNode->IsElement()) {
7898 : // Update mFocusedNode's state.
7899 0 : if (newShouldShowFocusRing) {
7900 0 : mFocusedNode->AsElement()->AddStates(NS_EVENT_STATE_FOCUSRING);
7901 : } else {
7902 0 : mFocusedNode->AsElement()->RemoveStates(NS_EVENT_STATE_FOCUSRING);
7903 : }
7904 : }
7905 : }
7906 :
7907 : void
7908 0 : nsGlobalWindow::GetKeyboardIndicators(bool* aShowAccelerators,
7909 : bool* aShowFocusRings)
7910 : {
7911 0 : FORWARD_TO_INNER_VOID(GetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
7912 :
7913 0 : *aShowAccelerators = mShowAccelerators;
7914 0 : *aShowFocusRings = mShowFocusRings;
7915 : }
7916 :
7917 : bool
7918 0 : nsGlobalWindow::TakeFocus(bool aFocus, PRUint32 aFocusMethod)
7919 : {
7920 0 : FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), false);
7921 :
7922 0 : if (mCleanedUp) {
7923 0 : return false;
7924 : }
7925 :
7926 0 : if (aFocus)
7927 0 : mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
7928 :
7929 0 : if (mHasFocus != aFocus) {
7930 0 : mHasFocus = aFocus;
7931 0 : UpdateCanvasFocus(true, mFocusedNode);
7932 : }
7933 :
7934 : // if mNeedsFocus is true, then the document has not yet received a
7935 : // document-level focus event. If there is a root content node, then return
7936 : // true to tell the calling focus manager that a focus event is expected. If
7937 : // there is no root content node, the document hasn't loaded enough yet, or
7938 : // there isn't one and there is no point in firing a focus event.
7939 0 : if (aFocus && mNeedsFocus && mDoc && mDoc->GetRootElement() != nsnull) {
7940 0 : mNeedsFocus = false;
7941 0 : return true;
7942 : }
7943 :
7944 0 : mNeedsFocus = false;
7945 0 : return false;
7946 : }
7947 :
7948 : void
7949 0 : nsGlobalWindow::SetReadyForFocus()
7950 : {
7951 0 : FORWARD_TO_INNER_VOID(SetReadyForFocus, ());
7952 :
7953 0 : bool oldNeedsFocus = mNeedsFocus;
7954 0 : mNeedsFocus = false;
7955 :
7956 : // update whether focus rings need to be shown using the state from the
7957 : // root window
7958 0 : nsPIDOMWindow* root = GetPrivateRoot();
7959 0 : if (root) {
7960 : bool showAccelerators, showFocusRings;
7961 0 : root->GetKeyboardIndicators(&showAccelerators, &showFocusRings);
7962 0 : mShowFocusRings = showFocusRings;
7963 : }
7964 :
7965 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7966 0 : if (fm)
7967 0 : fm->WindowShown(this, oldNeedsFocus);
7968 : }
7969 :
7970 : void
7971 0 : nsGlobalWindow::PageHidden()
7972 : {
7973 0 : FORWARD_TO_INNER_VOID(PageHidden, ());
7974 :
7975 : // the window is being hidden, so tell the focus manager that the frame is
7976 : // no longer valid. Use the persisted field to determine if the document
7977 : // is being destroyed.
7978 :
7979 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7980 0 : if (fm)
7981 0 : fm->WindowHidden(this);
7982 :
7983 0 : mNeedsFocus = true;
7984 : }
7985 :
7986 : class HashchangeCallback : public nsRunnable
7987 0 : {
7988 : public:
7989 0 : HashchangeCallback(const nsAString &aOldURL,
7990 : const nsAString &aNewURL,
7991 : nsGlobalWindow* aWindow)
7992 0 : : mWindow(aWindow)
7993 : {
7994 0 : mOldURL.Assign(aOldURL);
7995 0 : mNewURL.Assign(aNewURL);
7996 0 : }
7997 :
7998 0 : NS_IMETHOD Run()
7999 : {
8000 0 : NS_PRECONDITION(NS_IsMainThread(), "Should be called on the main thread.");
8001 0 : return mWindow->FireHashchange(mOldURL, mNewURL);
8002 : }
8003 :
8004 : private:
8005 : nsString mOldURL;
8006 : nsString mNewURL;
8007 : nsRefPtr<nsGlobalWindow> mWindow;
8008 : };
8009 :
8010 : nsresult
8011 0 : nsGlobalWindow::DispatchAsyncHashchange(nsIURI *aOldURI, nsIURI *aNewURI)
8012 : {
8013 0 : FORWARD_TO_INNER(DispatchAsyncHashchange, (aOldURI, aNewURI), NS_OK);
8014 :
8015 : // Make sure that aOldURI and aNewURI are identical up to the '#', and that
8016 : // their hashes are different.
8017 0 : nsCAutoString oldBeforeHash, oldHash, newBeforeHash, newHash;
8018 0 : nsContentUtils::SplitURIAtHash(aOldURI, oldBeforeHash, oldHash);
8019 0 : nsContentUtils::SplitURIAtHash(aNewURI, newBeforeHash, newHash);
8020 :
8021 0 : NS_ENSURE_STATE(oldBeforeHash.Equals(newBeforeHash));
8022 0 : NS_ENSURE_STATE(!oldHash.Equals(newHash));
8023 :
8024 0 : nsCAutoString oldSpec, newSpec;
8025 0 : aOldURI->GetSpec(oldSpec);
8026 0 : aNewURI->GetSpec(newSpec);
8027 :
8028 0 : NS_ConvertUTF8toUTF16 oldWideSpec(oldSpec);
8029 0 : NS_ConvertUTF8toUTF16 newWideSpec(newSpec);
8030 :
8031 : nsCOMPtr<nsIRunnable> callback =
8032 0 : new HashchangeCallback(oldWideSpec, newWideSpec, this);
8033 0 : return NS_DispatchToMainThread(callback);
8034 : }
8035 :
8036 : nsresult
8037 0 : nsGlobalWindow::FireHashchange(const nsAString &aOldURL,
8038 : const nsAString &aNewURL)
8039 : {
8040 0 : NS_ENSURE_TRUE(IsInnerWindow(), NS_ERROR_FAILURE);
8041 :
8042 : // Don't do anything if the window is frozen.
8043 0 : if (IsFrozen())
8044 0 : return NS_OK;
8045 :
8046 : // Get a presentation shell for use in creating the hashchange event.
8047 0 : NS_ENSURE_STATE(mDoc);
8048 :
8049 0 : nsIPresShell *shell = mDoc->GetShell();
8050 0 : nsRefPtr<nsPresContext> presContext;
8051 0 : if (shell) {
8052 0 : presContext = shell->GetPresContext();
8053 : }
8054 :
8055 : // Create a new hashchange event.
8056 0 : nsCOMPtr<nsIDOMEvent> domEvent;
8057 : nsresult rv =
8058 : nsEventDispatcher::CreateEvent(presContext, nsnull,
8059 0 : NS_LITERAL_STRING("hashchangeevent"),
8060 0 : getter_AddRefs(domEvent));
8061 0 : NS_ENSURE_SUCCESS(rv, rv);
8062 :
8063 0 : nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(domEvent);
8064 0 : NS_ENSURE_TRUE(privateEvent, NS_ERROR_UNEXPECTED);
8065 :
8066 0 : nsCOMPtr<nsIDOMHashChangeEvent> hashchangeEvent = do_QueryInterface(domEvent);
8067 0 : NS_ENSURE_TRUE(hashchangeEvent, NS_ERROR_UNEXPECTED);
8068 :
8069 : // The hashchange event bubbles and isn't cancellable.
8070 0 : rv = hashchangeEvent->InitHashChangeEvent(NS_LITERAL_STRING("hashchange"),
8071 : true, false,
8072 0 : aOldURL, aNewURL);
8073 0 : NS_ENSURE_SUCCESS(rv, rv);
8074 :
8075 0 : rv = privateEvent->SetTrusted(true);
8076 0 : NS_ENSURE_SUCCESS(rv, rv);
8077 :
8078 : bool dummy;
8079 0 : return DispatchEvent(hashchangeEvent, &dummy);
8080 : }
8081 :
8082 : nsresult
8083 0 : nsGlobalWindow::DispatchSyncPopState()
8084 : {
8085 0 : FORWARD_TO_INNER(DispatchSyncPopState, (), NS_OK);
8086 :
8087 0 : NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
8088 : "Must be safe to run script here.");
8089 :
8090 : // Check that PopState hasn't been pref'ed off.
8091 0 : if (!Preferences::GetBool(sPopStatePrefStr, false)) {
8092 0 : return NS_OK;
8093 : }
8094 :
8095 0 : nsresult rv = NS_OK;
8096 :
8097 : // Bail if the window is frozen.
8098 0 : if (IsFrozen()) {
8099 0 : return NS_OK;
8100 : }
8101 :
8102 : // Get the document's pending state object -- it contains the data we're
8103 : // going to send along with the popstate event. The object is serialized
8104 : // using structured clone.
8105 0 : nsCOMPtr<nsIVariant> stateObj;
8106 0 : rv = mDoc->GetStateObject(getter_AddRefs(stateObj));
8107 0 : NS_ENSURE_SUCCESS(rv, rv);
8108 :
8109 : // Obtain a presentation shell for use in creating a popstate event.
8110 0 : nsIPresShell *shell = mDoc->GetShell();
8111 0 : nsRefPtr<nsPresContext> presContext;
8112 0 : if (shell) {
8113 0 : presContext = shell->GetPresContext();
8114 : }
8115 :
8116 : // Create a new popstate event
8117 0 : nsCOMPtr<nsIDOMEvent> domEvent;
8118 : rv = nsEventDispatcher::CreateEvent(presContext, nsnull,
8119 0 : NS_LITERAL_STRING("popstateevent"),
8120 0 : getter_AddRefs(domEvent));
8121 0 : NS_ENSURE_SUCCESS(rv, rv);
8122 :
8123 0 : nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(domEvent);
8124 0 : NS_ENSURE_TRUE(privateEvent, NS_ERROR_FAILURE);
8125 :
8126 : // Initialize the popstate event, which does bubble but isn't cancellable.
8127 0 : nsCOMPtr<nsIDOMPopStateEvent> popstateEvent = do_QueryInterface(domEvent);
8128 0 : rv = popstateEvent->InitPopStateEvent(NS_LITERAL_STRING("popstate"),
8129 : true, false,
8130 0 : stateObj);
8131 0 : NS_ENSURE_SUCCESS(rv, rv);
8132 :
8133 0 : rv = privateEvent->SetTrusted(true);
8134 0 : NS_ENSURE_SUCCESS(rv, rv);
8135 :
8136 : nsCOMPtr<nsIDOMEventTarget> outerWindow =
8137 0 : do_QueryInterface(GetOuterWindow());
8138 0 : NS_ENSURE_TRUE(outerWindow, NS_ERROR_UNEXPECTED);
8139 :
8140 0 : rv = privateEvent->SetTarget(outerWindow);
8141 0 : NS_ENSURE_SUCCESS(rv, rv);
8142 :
8143 : bool dummy; // default action
8144 0 : return DispatchEvent(popstateEvent, &dummy);
8145 : }
8146 :
8147 : // Find an nsICanvasFrame under aFrame. Only search the principal
8148 : // child lists. aFrame must be non-null.
8149 0 : static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame)
8150 : {
8151 0 : nsCanvasFrame* canvasFrame = do_QueryFrame(aFrame);
8152 0 : if (canvasFrame) {
8153 0 : return canvasFrame;
8154 : }
8155 :
8156 0 : nsIFrame* kid = aFrame->GetFirstPrincipalChild();
8157 0 : while (kid) {
8158 0 : canvasFrame = FindCanvasFrame(kid);
8159 0 : if (canvasFrame) {
8160 0 : return canvasFrame;
8161 : }
8162 0 : kid = kid->GetNextSibling();
8163 : }
8164 :
8165 0 : return nsnull;
8166 : }
8167 :
8168 : //-------------------------------------------------------
8169 : // Tells the HTMLFrame/CanvasFrame that is now has focus
8170 : void
8171 0 : nsGlobalWindow::UpdateCanvasFocus(bool aFocusChanged, nsIContent* aNewContent)
8172 : {
8173 : // this is called from the inner window so use GetDocShell
8174 0 : nsIDocShell* docShell = GetDocShell();
8175 0 : if (!docShell)
8176 0 : return;
8177 :
8178 0 : nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell);
8179 0 : if (editorDocShell) {
8180 : bool editable;
8181 0 : editorDocShell->GetEditable(&editable);
8182 0 : if (editable)
8183 : return;
8184 : }
8185 :
8186 0 : nsCOMPtr<nsIPresShell> presShell;
8187 0 : docShell->GetPresShell(getter_AddRefs(presShell));
8188 0 : if (!presShell || !mDocument)
8189 : return;
8190 :
8191 0 : nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
8192 0 : Element *rootElement = doc->GetRootElement();
8193 0 : if (rootElement) {
8194 0 : if ((mHasFocus || aFocusChanged) &&
8195 0 : (mFocusedNode == rootElement || aNewContent == rootElement)) {
8196 0 : nsIFrame* frame = rootElement->GetPrimaryFrame();
8197 0 : if (frame) {
8198 0 : frame = frame->GetParent();
8199 0 : nsCanvasFrame* canvasFrame = do_QueryFrame(frame);
8200 0 : if (canvasFrame) {
8201 0 : canvasFrame->SetHasFocus(mHasFocus && rootElement == aNewContent);
8202 : }
8203 : }
8204 : }
8205 : } else {
8206 : // Look for the frame the hard way
8207 0 : nsIFrame* frame = presShell->GetRootFrame();
8208 0 : if (frame) {
8209 0 : nsCanvasFrame* canvasFrame = FindCanvasFrame(frame);
8210 0 : if (canvasFrame) {
8211 0 : canvasFrame->SetHasFocus(false);
8212 : }
8213 : }
8214 : }
8215 : }
8216 :
8217 : NS_IMETHODIMP
8218 0 : nsGlobalWindow::GetComputedStyle(nsIDOMElement* aElt,
8219 : const nsAString& aPseudoElt,
8220 : nsIDOMCSSStyleDeclaration** aReturn)
8221 : {
8222 0 : FORWARD_TO_OUTER(GetComputedStyle, (aElt, aPseudoElt, aReturn),
8223 : NS_ERROR_NOT_INITIALIZED);
8224 :
8225 0 : NS_ENSURE_ARG_POINTER(aReturn);
8226 0 : *aReturn = nsnull;
8227 :
8228 0 : if (!aElt) {
8229 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
8230 : }
8231 :
8232 0 : if (!mDocShell) {
8233 0 : return NS_OK;
8234 : }
8235 :
8236 0 : nsCOMPtr<nsIPresShell> presShell;
8237 0 : mDocShell->GetPresShell(getter_AddRefs(presShell));
8238 :
8239 0 : if (!presShell) {
8240 0 : return NS_OK;
8241 : }
8242 :
8243 0 : nsRefPtr<nsComputedDOMStyle> compStyle;
8244 : nsresult rv = NS_NewComputedDOMStyle(aElt, aPseudoElt, presShell,
8245 0 : getter_AddRefs(compStyle));
8246 0 : NS_ENSURE_SUCCESS(rv, rv);
8247 :
8248 0 : *aReturn = compStyle.forget().get();
8249 :
8250 0 : return NS_OK;
8251 : }
8252 :
8253 : NS_IMETHODIMP
8254 0 : nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
8255 : {
8256 0 : FORWARD_TO_INNER(GetSessionStorage, (aSessionStorage), NS_ERROR_UNEXPECTED);
8257 :
8258 0 : nsIPrincipal *principal = GetPrincipal();
8259 0 : nsIDocShell* docShell = GetDocShell();
8260 :
8261 0 : if (!principal || !docShell) {
8262 0 : *aSessionStorage = nsnull;
8263 0 : return NS_OK;
8264 : }
8265 :
8266 0 : if (!Preferences::GetBool(kStorageEnabled)) {
8267 0 : *aSessionStorage = nsnull;
8268 0 : return NS_OK;
8269 : }
8270 :
8271 0 : if (mSessionStorage) {
8272 : #ifdef PR_LOGGING
8273 0 : if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
8274 0 : PR_LogPrint("nsGlobalWindow %p has %p sessionStorage", this, mSessionStorage.get());
8275 : }
8276 : #endif
8277 0 : nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(mSessionStorage);
8278 0 : if (piStorage) {
8279 0 : bool canAccess = piStorage->CanAccess(principal);
8280 0 : NS_ASSERTION(canAccess,
8281 : "window %x owned sessionStorage "
8282 : "that could not be accessed!");
8283 0 : if (!canAccess) {
8284 0 : mSessionStorage = nsnull;
8285 : }
8286 : }
8287 : }
8288 :
8289 0 : if (!mSessionStorage) {
8290 0 : *aSessionStorage = nsnull;
8291 :
8292 0 : nsString documentURI;
8293 0 : if (mDocument) {
8294 0 : mDocument->GetDocumentURI(documentURI);
8295 : }
8296 :
8297 : nsresult rv = docShell->GetSessionStorageForPrincipal(principal,
8298 : documentURI,
8299 : true,
8300 0 : getter_AddRefs(mSessionStorage));
8301 0 : NS_ENSURE_SUCCESS(rv, rv);
8302 :
8303 : #ifdef PR_LOGGING
8304 0 : if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
8305 0 : PR_LogPrint("nsGlobalWindow %p tried to get a new sessionStorage %p", this, mSessionStorage.get());
8306 : }
8307 : #endif
8308 :
8309 0 : if (!mSessionStorage) {
8310 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
8311 : }
8312 : }
8313 :
8314 : #ifdef PR_LOGGING
8315 0 : if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
8316 0 : PR_LogPrint("nsGlobalWindow %p returns %p sessionStorage", this, mSessionStorage.get());
8317 : }
8318 : #endif
8319 :
8320 0 : NS_ADDREF(*aSessionStorage = mSessionStorage);
8321 0 : return NS_OK;
8322 : }
8323 :
8324 : NS_IMETHODIMP
8325 0 : nsGlobalWindow::GetGlobalStorage(nsIDOMStorageList ** aGlobalStorage)
8326 : {
8327 0 : NS_ENSURE_ARG_POINTER(aGlobalStorage);
8328 :
8329 0 : nsCOMPtr<nsIDocument> document = do_QueryInterface(GetExtantDocument());
8330 0 : if (document) {
8331 0 : document->WarnOnceAbout(nsIDocument::eGlobalStorage);
8332 : }
8333 :
8334 0 : if (!Preferences::GetBool(kStorageEnabled)) {
8335 0 : *aGlobalStorage = nsnull;
8336 0 : return NS_OK;
8337 : }
8338 :
8339 0 : if (!sGlobalStorageList) {
8340 0 : nsresult rv = NS_NewDOMStorageList(&sGlobalStorageList);
8341 0 : NS_ENSURE_SUCCESS(rv, rv);
8342 : }
8343 :
8344 0 : *aGlobalStorage = sGlobalStorageList;
8345 0 : NS_IF_ADDREF(*aGlobalStorage);
8346 :
8347 0 : return NS_OK;
8348 : }
8349 :
8350 : NS_IMETHODIMP
8351 0 : nsGlobalWindow::GetLocalStorage(nsIDOMStorage ** aLocalStorage)
8352 : {
8353 0 : FORWARD_TO_INNER(GetLocalStorage, (aLocalStorage), NS_ERROR_UNEXPECTED);
8354 :
8355 0 : NS_ENSURE_ARG(aLocalStorage);
8356 :
8357 0 : if (!Preferences::GetBool(kStorageEnabled)) {
8358 0 : *aLocalStorage = nsnull;
8359 0 : return NS_OK;
8360 : }
8361 :
8362 0 : if (!mLocalStorage) {
8363 0 : *aLocalStorage = nsnull;
8364 :
8365 : nsresult rv;
8366 :
8367 : bool unused;
8368 0 : if (!nsDOMStorage::CanUseStorage(&unused))
8369 0 : return NS_ERROR_DOM_SECURITY_ERR;
8370 :
8371 0 : nsIPrincipal *principal = GetPrincipal();
8372 0 : if (!principal)
8373 0 : return NS_OK;
8374 :
8375 : nsCOMPtr<nsIDOMStorageManager> storageManager =
8376 0 : do_GetService("@mozilla.org/dom/storagemanager;1", &rv);
8377 0 : NS_ENSURE_SUCCESS(rv, rv);
8378 :
8379 0 : nsString documentURI;
8380 0 : if (mDocument) {
8381 0 : mDocument->GetDocumentURI(documentURI);
8382 : }
8383 :
8384 0 : rv = storageManager->GetLocalStorageForPrincipal(principal,
8385 : documentURI,
8386 0 : getter_AddRefs(mLocalStorage));
8387 0 : NS_ENSURE_SUCCESS(rv, rv);
8388 : }
8389 :
8390 0 : NS_ADDREF(*aLocalStorage = mLocalStorage);
8391 0 : return NS_OK;
8392 : }
8393 :
8394 : //*****************************************************************************
8395 : // nsGlobalWindow::nsIDOMStorageIndexedDB
8396 : //*****************************************************************************
8397 :
8398 : NS_IMETHODIMP
8399 0 : nsGlobalWindow::GetMozIndexedDB(nsIIDBFactory** _retval)
8400 : {
8401 0 : if (!mIndexedDB) {
8402 0 : if (!IsChromeWindow()) {
8403 : nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
8404 0 : do_GetService(THIRDPARTYUTIL_CONTRACTID);
8405 0 : NS_ENSURE_TRUE(thirdPartyUtil, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
8406 :
8407 : bool isThirdParty;
8408 0 : nsresult rv = thirdPartyUtil->IsThirdPartyWindow(this, nsnull,
8409 0 : &isThirdParty);
8410 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
8411 :
8412 0 : if (isThirdParty) {
8413 0 : NS_WARNING("IndexedDB is not permitted in a third-party window.");
8414 0 : *_retval = nsnull;
8415 0 : return NS_OK;
8416 : }
8417 : }
8418 :
8419 0 : mIndexedDB = indexedDB::IDBFactory::Create(this);
8420 0 : NS_ENSURE_TRUE(mIndexedDB, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
8421 : }
8422 :
8423 0 : nsCOMPtr<nsIIDBFactory> request(mIndexedDB);
8424 0 : request.forget(_retval);
8425 0 : return NS_OK;
8426 : }
8427 :
8428 : //*****************************************************************************
8429 : // nsGlobalWindow::nsIInterfaceRequestor
8430 : //*****************************************************************************
8431 :
8432 : NS_IMETHODIMP
8433 0 : nsGlobalWindow::GetInterface(const nsIID & aIID, void **aSink)
8434 : {
8435 0 : NS_ENSURE_ARG_POINTER(aSink);
8436 0 : *aSink = nsnull;
8437 :
8438 0 : if (aIID.Equals(NS_GET_IID(nsIDocCharset))) {
8439 0 : FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
8440 :
8441 0 : if (mDocShell) {
8442 0 : nsCOMPtr<nsIDocCharset> docCharset(do_QueryInterface(mDocShell));
8443 0 : if (docCharset) {
8444 0 : NS_WARNING("Using deprecated nsIDocCharset: use nsIDocShell.GetCharset() instead ");
8445 0 : *aSink = docCharset;
8446 0 : NS_ADDREF(((nsISupports *) *aSink));
8447 : }
8448 : }
8449 : }
8450 0 : else if (aIID.Equals(NS_GET_IID(nsIWebNavigation))) {
8451 0 : FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
8452 :
8453 0 : if (mDocShell) {
8454 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
8455 0 : if (webNav) {
8456 0 : *aSink = webNav;
8457 0 : NS_ADDREF(((nsISupports *) *aSink));
8458 : }
8459 : }
8460 : }
8461 : #ifdef NS_PRINTING
8462 0 : else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
8463 0 : FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
8464 :
8465 0 : if (mDocShell) {
8466 0 : nsCOMPtr<nsIContentViewer> viewer;
8467 0 : mDocShell->GetContentViewer(getter_AddRefs(viewer));
8468 0 : if (viewer) {
8469 0 : nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
8470 0 : if (webBrowserPrint) {
8471 0 : *aSink = webBrowserPrint;
8472 0 : NS_ADDREF(((nsISupports *) *aSink));
8473 : }
8474 : }
8475 : }
8476 : }
8477 : #endif
8478 0 : else if (aIID.Equals(NS_GET_IID(nsIDOMWindowUtils))) {
8479 0 : FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
8480 :
8481 0 : nsCOMPtr<nsISupports> utils(do_QueryReferent(mWindowUtils));
8482 0 : if (utils) {
8483 0 : *aSink = utils;
8484 0 : NS_ADDREF(((nsISupports *) *aSink));
8485 : } else {
8486 0 : nsDOMWindowUtils *utilObj = new nsDOMWindowUtils(this);
8487 : nsCOMPtr<nsISupports> utilsIfc =
8488 0 : NS_ISUPPORTS_CAST(nsIDOMWindowUtils *, utilObj);
8489 0 : if (utilsIfc) {
8490 0 : mWindowUtils = do_GetWeakReference(utilsIfc);
8491 0 : *aSink = utilsIfc;
8492 0 : NS_ADDREF(((nsISupports *) *aSink));
8493 : }
8494 : }
8495 : }
8496 : else {
8497 0 : return QueryInterface(aIID, aSink);
8498 : }
8499 :
8500 0 : return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
8501 : }
8502 :
8503 : void
8504 0 : nsGlobalWindow::FireOfflineStatusEvent()
8505 : {
8506 0 : if (!mDoc)
8507 0 : return;
8508 0 : nsAutoString name;
8509 0 : if (NS_IsOffline()) {
8510 0 : name.AssignLiteral("offline");
8511 : } else {
8512 0 : name.AssignLiteral("online");
8513 : }
8514 : // The event is fired at the body element, or if there is no body element,
8515 : // at the document.
8516 0 : nsCOMPtr<nsISupports> eventTarget = mDoc.get();
8517 0 : nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDoc);
8518 0 : if (htmlDoc) {
8519 0 : nsCOMPtr<nsIDOMHTMLElement> body;
8520 0 : htmlDoc->GetBody(getter_AddRefs(body));
8521 0 : if (body) {
8522 0 : eventTarget = body;
8523 : }
8524 : }
8525 : else {
8526 0 : nsCOMPtr<nsIDOMElement> documentElement;
8527 0 : mDocument->GetDocumentElement(getter_AddRefs(documentElement));
8528 0 : if(documentElement) {
8529 0 : eventTarget = documentElement;
8530 : }
8531 : }
8532 0 : nsContentUtils::DispatchTrustedEvent(mDoc, eventTarget, name, true, false);
8533 : }
8534 :
8535 : nsresult
8536 0 : nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
8537 : const PRUnichar* aData)
8538 : {
8539 0 : if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
8540 0 : if (IsFrozen()) {
8541 : // if an even number of notifications arrive while we're frozen,
8542 : // we don't need to fire.
8543 0 : mFireOfflineStatusChangeEventOnThaw = !mFireOfflineStatusChangeEventOnThaw;
8544 : } else {
8545 0 : FireOfflineStatusEvent();
8546 : }
8547 0 : return NS_OK;
8548 : }
8549 :
8550 0 : if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage-changed")) {
8551 : nsIPrincipal *principal;
8552 : nsresult rv;
8553 :
8554 0 : principal = GetPrincipal();
8555 0 : if (principal) {
8556 : // A global storage object changed, check to see if it's one
8557 : // this window can access.
8558 :
8559 0 : nsCOMPtr<nsIURI> codebase;
8560 0 : principal->GetURI(getter_AddRefs(codebase));
8561 :
8562 0 : if (!codebase) {
8563 0 : return NS_OK;
8564 : }
8565 :
8566 0 : nsCAutoString currentDomain;
8567 0 : rv = codebase->GetAsciiHost(currentDomain);
8568 0 : if (NS_FAILED(rv)) {
8569 0 : return NS_OK;
8570 : }
8571 :
8572 0 : if (!nsDOMStorageList::CanAccessDomain(NS_ConvertUTF16toUTF8(aData),
8573 0 : currentDomain)) {
8574 : // This window can't reach the global storage object for the
8575 : // domain for which the change happened, so don't fire any
8576 : // events in this window.
8577 :
8578 0 : return NS_OK;
8579 : }
8580 : }
8581 :
8582 0 : nsAutoString domain(aData);
8583 :
8584 0 : if (IsFrozen()) {
8585 : // This window is frozen, rather than firing the events here,
8586 : // store the domain in which the change happened and fire the
8587 : // events if we're ever thawed.
8588 :
8589 0 : if (!mPendingStorageEventsObsolete) {
8590 0 : mPendingStorageEventsObsolete = new nsDataHashtable<nsStringHashKey, bool>;
8591 0 : NS_ENSURE_TRUE(mPendingStorageEventsObsolete, NS_ERROR_OUT_OF_MEMORY);
8592 :
8593 0 : rv = mPendingStorageEventsObsolete->Init();
8594 0 : NS_ENSURE_SUCCESS(rv, rv);
8595 : }
8596 :
8597 0 : mPendingStorageEventsObsolete->Put(domain, true);
8598 :
8599 0 : return NS_OK;
8600 : }
8601 :
8602 0 : nsRefPtr<nsDOMStorageEventObsolete> event = new nsDOMStorageEventObsolete();
8603 0 : NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
8604 :
8605 0 : rv = event->InitStorageEvent(NS_LITERAL_STRING("storage"), false, false, domain);
8606 0 : NS_ENSURE_SUCCESS(rv, rv);
8607 :
8608 0 : nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
8609 :
8610 0 : nsCOMPtr<nsIDOMEventTarget> target;
8611 :
8612 0 : if (htmlDoc) {
8613 0 : nsCOMPtr<nsIDOMHTMLElement> body;
8614 0 : htmlDoc->GetBody(getter_AddRefs(body));
8615 :
8616 0 : target = do_QueryInterface(body);
8617 : }
8618 :
8619 0 : if (!target) {
8620 0 : target = this;
8621 : }
8622 :
8623 : bool defaultActionEnabled;
8624 0 : target->DispatchEvent((nsIDOMStorageEventObsolete *)event, &defaultActionEnabled);
8625 :
8626 0 : return NS_OK;
8627 : }
8628 :
8629 0 : if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage2-changed")) {
8630 : nsIPrincipal *principal;
8631 : nsresult rv;
8632 :
8633 0 : nsCOMPtr<nsIDOMStorageEvent> event = do_QueryInterface(aSubject, &rv);
8634 0 : NS_ENSURE_SUCCESS(rv, rv);
8635 :
8636 0 : nsCOMPtr<nsIDOMStorage> changingStorage;
8637 0 : rv = event->GetStorageArea(getter_AddRefs(changingStorage));
8638 0 : NS_ENSURE_SUCCESS(rv, rv);
8639 :
8640 0 : nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(changingStorage);
8641 0 : nsPIDOMStorage::nsDOMStorageType storageType = pistorage->StorageType();
8642 :
8643 0 : principal = GetPrincipal();
8644 0 : switch (storageType)
8645 : {
8646 : case nsPIDOMStorage::SessionStorage:
8647 : {
8648 0 : if (SameCOMIdentity(mSessionStorage, changingStorage)) {
8649 : // Do not fire any events for the same storage object, it's not shared
8650 : // among windows, see nsGlobalWindow::GetSessionStoarge()
8651 0 : return NS_OK;
8652 : }
8653 :
8654 0 : nsCOMPtr<nsIDOMStorage> storage = mSessionStorage;
8655 0 : if (!storage) {
8656 0 : nsIDocShell* docShell = GetDocShell();
8657 0 : if (principal && docShell) {
8658 : // No need to pass documentURI here, it's only needed when we want
8659 : // to create a new storage, the third paramater would be true
8660 : docShell->GetSessionStorageForPrincipal(principal,
8661 0 : EmptyString(),
8662 : false,
8663 0 : getter_AddRefs(storage));
8664 : }
8665 : }
8666 :
8667 0 : if (!pistorage->IsForkOf(storage)) {
8668 : // This storage event is coming from a different doc shell,
8669 : // i.e. it is a clone, ignore this event.
8670 0 : return NS_OK;
8671 : }
8672 :
8673 : #ifdef PR_LOGGING
8674 0 : if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
8675 0 : PR_LogPrint("nsGlobalWindow %p with sessionStorage %p passing event from %p", this, mSessionStorage.get(), pistorage.get());
8676 : }
8677 : #endif
8678 :
8679 0 : break;
8680 : }
8681 : case nsPIDOMStorage::LocalStorage:
8682 : {
8683 0 : if (SameCOMIdentity(mLocalStorage, changingStorage)) {
8684 : // Do not fire any events for the same storage object, it's not shared
8685 : // among windows, see nsGlobalWindow::GetLocalStoarge()
8686 0 : return NS_OK;
8687 : }
8688 :
8689 : // Allow event fire only for the same principal storages
8690 : // XXX We have to use EqualsIgnoreDomain after bug 495337 lands
8691 0 : nsIPrincipal *storagePrincipal = pistorage->Principal();
8692 : bool equals;
8693 :
8694 0 : rv = storagePrincipal->Equals(principal, &equals);
8695 0 : NS_ENSURE_SUCCESS(rv, rv);
8696 :
8697 0 : if (!equals)
8698 0 : return NS_OK;
8699 :
8700 0 : break;
8701 : }
8702 : default:
8703 0 : return NS_OK;
8704 : }
8705 :
8706 0 : if (IsFrozen()) {
8707 : // This window is frozen, rather than firing the events here,
8708 : // store the domain in which the change happened and fire the
8709 : // events if we're ever thawed.
8710 :
8711 0 : mPendingStorageEvents.AppendObject(event);
8712 0 : return NS_OK;
8713 : }
8714 :
8715 : bool defaultActionEnabled;
8716 0 : DispatchEvent((nsIDOMStorageEvent *)event, &defaultActionEnabled);
8717 :
8718 0 : return NS_OK;
8719 : }
8720 :
8721 0 : if (!nsCRT::strcmp(aTopic, "offline-cache-update-added")) {
8722 0 : if (mApplicationCache)
8723 0 : return NS_OK;
8724 :
8725 : // Instantiate the application object now. It observes update belonging to
8726 : // this window's document and correctly updates the applicationCache object
8727 : // state.
8728 0 : nsCOMPtr<nsIDOMOfflineResourceList> applicationCache;
8729 0 : GetApplicationCache(getter_AddRefs(applicationCache));
8730 0 : nsCOMPtr<nsIObserver> observer = do_QueryInterface(applicationCache);
8731 0 : if (observer)
8732 0 : observer->Observe(aSubject, aTopic, aData);
8733 :
8734 0 : return NS_OK;
8735 : }
8736 :
8737 0 : NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");
8738 0 : return NS_ERROR_FAILURE;
8739 : }
8740 :
8741 : static PLDHashOperator
8742 0 : FirePendingStorageEvents(const nsAString& aKey, bool aData, void *userArg)
8743 : {
8744 0 : nsGlobalWindow *win = static_cast<nsGlobalWindow *>(userArg);
8745 :
8746 0 : nsCOMPtr<nsIDOMStorage> storage;
8747 0 : win->GetSessionStorage(getter_AddRefs(storage));
8748 :
8749 0 : if (storage) {
8750 : win->Observe(storage, "dom-storage-changed",
8751 0 : aKey.IsEmpty() ? nsnull : PromiseFlatString(aKey).get());
8752 : }
8753 :
8754 0 : return PL_DHASH_NEXT;
8755 : }
8756 :
8757 : nsresult
8758 0 : nsGlobalWindow::FireDelayedDOMEvents()
8759 : {
8760 0 : FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED);
8761 :
8762 0 : for (PRInt32 i = 0; i < mPendingStorageEvents.Count(); ++i) {
8763 0 : Observe(mPendingStorageEvents[i], "dom-storage2-changed", nsnull);
8764 : }
8765 :
8766 0 : if (mPendingStorageEventsObsolete) {
8767 : // Fire pending storage events.
8768 0 : mPendingStorageEventsObsolete->EnumerateRead(FirePendingStorageEvents, this);
8769 0 : mPendingStorageEventsObsolete = nsnull;
8770 : }
8771 :
8772 0 : if (mApplicationCache) {
8773 0 : static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents();
8774 : }
8775 :
8776 0 : if (mFireOfflineStatusChangeEventOnThaw) {
8777 0 : mFireOfflineStatusChangeEventOnThaw = false;
8778 0 : FireOfflineStatusEvent();
8779 : }
8780 :
8781 : nsCOMPtr<nsIDocShellTreeNode> node =
8782 0 : do_QueryInterface(GetDocShell());
8783 0 : if (node) {
8784 0 : PRInt32 childCount = 0;
8785 0 : node->GetChildCount(&childCount);
8786 :
8787 0 : for (PRInt32 i = 0; i < childCount; ++i) {
8788 0 : nsCOMPtr<nsIDocShellTreeItem> childShell;
8789 0 : node->GetChildAt(i, getter_AddRefs(childShell));
8790 0 : NS_ASSERTION(childShell, "null child shell");
8791 :
8792 0 : nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
8793 0 : if (pWin) {
8794 : nsGlobalWindow *win =
8795 : static_cast<nsGlobalWindow*>
8796 0 : (static_cast<nsPIDOMWindow*>(pWin));
8797 0 : win->FireDelayedDOMEvents();
8798 : }
8799 : }
8800 : }
8801 :
8802 0 : return NS_OK;
8803 : }
8804 :
8805 : //*****************************************************************************
8806 : // nsGlobalWindow: Window Control Functions
8807 : //*****************************************************************************
8808 :
8809 : nsIDOMWindow *
8810 0 : nsGlobalWindow::GetParentInternal()
8811 : {
8812 0 : FORWARD_TO_OUTER(GetParentInternal, (), nsnull);
8813 :
8814 0 : nsCOMPtr<nsIDOMWindow> parent;
8815 0 : GetParent(getter_AddRefs(parent));
8816 :
8817 0 : if (parent && parent != static_cast<nsIDOMWindow *>(this)) {
8818 0 : return parent;
8819 : }
8820 :
8821 0 : return NULL;
8822 : }
8823 :
8824 : // static
8825 : void
8826 0 : nsGlobalWindow::CloseBlockScriptTerminationFunc(nsISupports *aRef)
8827 : {
8828 : nsGlobalWindow* pwin = static_cast<nsGlobalWindow*>
8829 0 : (static_cast<nsPIDOMWindow*>(aRef));
8830 0 : pwin->mBlockScriptedClosingFlag = false;
8831 0 : }
8832 :
8833 : nsresult
8834 0 : nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
8835 : const nsAString& aOptions, bool aDialog,
8836 : bool aContentModal, bool aCalledNoScript,
8837 : bool aDoJSFixups, nsIArray *argv,
8838 : nsISupports *aExtraArgument,
8839 : nsIPrincipal *aCalleePrincipal,
8840 : JSContext *aJSCallerContext,
8841 : nsIDOMWindow **aReturn)
8842 : {
8843 0 : FORWARD_TO_OUTER(OpenInternal, (aUrl, aName, aOptions, aDialog,
8844 : aContentModal, aCalledNoScript, aDoJSFixups,
8845 : argv, aExtraArgument, aCalleePrincipal,
8846 : aJSCallerContext, aReturn),
8847 : NS_ERROR_NOT_INITIALIZED);
8848 :
8849 : #ifdef NS_DEBUG
8850 0 : PRUint32 argc = 0;
8851 0 : if (argv)
8852 0 : argv->GetLength(&argc);
8853 : #endif
8854 0 : NS_PRECONDITION(!aExtraArgument || (!argv && argc == 0),
8855 : "Can't pass in arguments both ways");
8856 0 : NS_PRECONDITION(!aCalledNoScript || (!argv && argc == 0),
8857 : "Can't pass JS args when called via the noscript methods");
8858 0 : NS_PRECONDITION(!aJSCallerContext || !aCalledNoScript,
8859 : "Shouldn't have caller context when called noscript");
8860 :
8861 0 : *aReturn = nsnull;
8862 :
8863 0 : nsCOMPtr<nsIWebBrowserChrome> chrome;
8864 0 : GetWebBrowserChrome(getter_AddRefs(chrome));
8865 0 : if (!chrome) {
8866 : // No chrome means we don't want to go through with this open call
8867 : // -- see nsIWindowWatcher.idl
8868 0 : return NS_ERROR_NOT_AVAILABLE;
8869 : }
8870 :
8871 0 : NS_ASSERTION(mDocShell, "Must have docshell here");
8872 :
8873 0 : const bool checkForPopup = !nsContentUtils::IsCallerChrome() &&
8874 0 : !aDialog && !WindowExists(aName, !aCalledNoScript);
8875 :
8876 : // Note: it's very important that this be an nsXPIDLCString, since we want
8877 : // .get() on it to return nsnull until we write stuff to it. The window
8878 : // watcher expects a null URL string if there is no URL to load.
8879 0 : nsXPIDLCString url;
8880 0 : nsresult rv = NS_OK;
8881 :
8882 : // It's important to do this security check before determining whether this
8883 : // window opening should be blocked, to ensure that we don't FireAbuseEvents
8884 : // for a window opening that wouldn't have succeeded in the first place.
8885 0 : if (!aUrl.IsEmpty()) {
8886 0 : AppendUTF16toUTF8(aUrl, url);
8887 :
8888 : /* Check whether the URI is allowed, but not for dialogs --
8889 : see bug 56851. The security of this function depends on
8890 : window.openDialog being inaccessible from web scripts */
8891 0 : if (url.get() && !aDialog)
8892 0 : rv = SecurityCheckURL(url.get());
8893 : }
8894 :
8895 0 : if (NS_FAILED(rv))
8896 0 : return rv;
8897 :
8898 0 : PopupControlState abuseLevel = gPopupControlState;
8899 0 : if (checkForPopup) {
8900 0 : abuseLevel = RevisePopupAbuseLevel(abuseLevel);
8901 0 : if (abuseLevel >= openAbused) {
8902 0 : if (aJSCallerContext) {
8903 : // If script in some other window is doing a window.open on us and
8904 : // it's being blocked, then it's OK to close us afterwards, probably.
8905 : // But if we're doing a window.open on ourselves and block the popup,
8906 : // prevent this window from closing until after this script terminates
8907 : // so that whatever popup blocker UI the app has will be visible.
8908 0 : if (mContext == GetScriptContextFromJSContext(aJSCallerContext)) {
8909 0 : mBlockScriptedClosingFlag = true;
8910 0 : mContext->SetTerminationFunction(CloseBlockScriptTerminationFunc,
8911 0 : this);
8912 : }
8913 : }
8914 :
8915 0 : FireAbuseEvents(true, false, aUrl, aName, aOptions);
8916 0 : return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
8917 : }
8918 : }
8919 :
8920 0 : nsCOMPtr<nsIDOMWindow> domReturn;
8921 :
8922 : nsCOMPtr<nsIWindowWatcher> wwatch =
8923 0 : do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
8924 0 : NS_ENSURE_TRUE(wwatch, rv);
8925 :
8926 0 : NS_ConvertUTF16toUTF8 options(aOptions);
8927 0 : NS_ConvertUTF16toUTF8 name(aName);
8928 :
8929 0 : const char *options_ptr = aOptions.IsEmpty() ? nsnull : options.get();
8930 0 : const char *name_ptr = aName.IsEmpty() ? nsnull : name.get();
8931 :
8932 : {
8933 : // Reset popup state while opening a window to prevent the
8934 : // current state from being active the whole time a modal
8935 : // dialog is open.
8936 0 : nsAutoPopupStatePusher popupStatePusher(openAbused, true);
8937 :
8938 0 : if (!aCalledNoScript) {
8939 0 : nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
8940 0 : NS_ASSERTION(pwwatch,
8941 : "Unable to open windows from JS because window watcher "
8942 : "is broken");
8943 0 : NS_ENSURE_TRUE(pwwatch, NS_ERROR_UNEXPECTED);
8944 :
8945 0 : rv = pwwatch->OpenWindowJS(this, url.get(), name_ptr, options_ptr,
8946 : aDialog, argv,
8947 0 : getter_AddRefs(domReturn));
8948 : } else {
8949 : // Push a null JSContext here so that the window watcher won't screw us
8950 : // up. We do NOT want this case looking at the JS context on the stack
8951 : // when searching. Compare comments on
8952 : // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
8953 0 : nsCOMPtr<nsIJSContextStack> stack;
8954 :
8955 0 : if (!aContentModal) {
8956 0 : stack = do_GetService(sJSStackContractID);
8957 : }
8958 :
8959 0 : if (stack) {
8960 0 : rv = stack->Push(nsnull);
8961 0 : NS_ENSURE_SUCCESS(rv, rv);
8962 : }
8963 :
8964 0 : rv = wwatch->OpenWindow(this, url.get(), name_ptr, options_ptr,
8965 0 : aExtraArgument, getter_AddRefs(domReturn));
8966 :
8967 0 : if (stack) {
8968 : JSContext* cx;
8969 0 : stack->Pop(&cx);
8970 0 : NS_ASSERTION(!cx, "Unexpected JSContext popped!");
8971 : }
8972 : }
8973 : }
8974 :
8975 0 : NS_ENSURE_SUCCESS(rv, rv);
8976 :
8977 : // success!
8978 :
8979 0 : domReturn.swap(*aReturn);
8980 :
8981 0 : if (aDoJSFixups) {
8982 0 : nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
8983 0 : if (!chrome_win) {
8984 : // A new non-chrome window was created from a call to
8985 : // window.open() from JavaScript, make sure there's a document in
8986 : // the new window. We do this by simply asking the new window for
8987 : // its document, this will synchronously create an empty document
8988 : // if there is no document in the window.
8989 : // XXXbz should this just use EnsureInnerWindow()?
8990 : #ifdef DEBUG_jst
8991 : {
8992 : nsCOMPtr<nsPIDOMWindow> pidomwin(do_QueryInterface(*aReturn));
8993 :
8994 : nsIDOMDocument *temp = pidomwin->GetExtantDocument();
8995 :
8996 : NS_ASSERTION(temp, "No document in new window!!!");
8997 : }
8998 : #endif
8999 :
9000 0 : nsCOMPtr<nsIDOMDocument> doc;
9001 0 : (*aReturn)->GetDocument(getter_AddRefs(doc));
9002 : }
9003 : }
9004 :
9005 0 : if (checkForPopup) {
9006 0 : if (abuseLevel >= openControlled) {
9007 0 : nsGlobalWindow *opened = static_cast<nsGlobalWindow *>(*aReturn);
9008 0 : if (!opened->IsPopupSpamWindow()) {
9009 0 : opened->SetPopupSpamWindow(true);
9010 0 : ++gOpenPopupSpamCount;
9011 : }
9012 : }
9013 0 : if (abuseLevel >= openAbused)
9014 0 : FireAbuseEvents(false, true, aUrl, aName, aOptions);
9015 : }
9016 :
9017 0 : return rv;
9018 : }
9019 :
9020 : // static
9021 : void
9022 0 : nsGlobalWindow::CloseWindow(nsISupports *aWindow)
9023 : {
9024 0 : nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aWindow));
9025 :
9026 : nsGlobalWindow* globalWin =
9027 : static_cast<nsGlobalWindow *>
9028 0 : (static_cast<nsPIDOMWindow*>(win));
9029 :
9030 : // Need to post an event for closing, otherwise window and
9031 : // presshell etc. may get destroyed while creating frames, bug 338897.
9032 0 : nsCloseEvent::PostCloseEvent(globalWin);
9033 : // else if OOM, better not to close. That might cause a crash.
9034 0 : }
9035 :
9036 : //*****************************************************************************
9037 : // nsGlobalWindow: Timeout Functions
9038 : //*****************************************************************************
9039 :
9040 : PRUint32 sNestingLevel;
9041 :
9042 : nsresult
9043 0 : nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
9044 : PRInt32 interval,
9045 : bool aIsInterval, PRInt32 *aReturn)
9046 : {
9047 0 : FORWARD_TO_INNER(SetTimeoutOrInterval, (aHandler, interval, aIsInterval, aReturn),
9048 : NS_ERROR_NOT_INITIALIZED);
9049 :
9050 : // If we don't have a document (we could have been unloaded since
9051 : // the call to setTimeout was made), do nothing.
9052 0 : if (!mDocument) {
9053 0 : return NS_OK;
9054 : }
9055 :
9056 : // Disallow negative intervals. If aIsInterval also disallow 0,
9057 : // because we use that as a "don't repeat" flag.
9058 0 : interval = NS_MAX(aIsInterval ? 1 : 0, interval);
9059 :
9060 : // Make sure we don't proceed with an interval larger than our timer
9061 : // code can handle. (Note: we already forced |interval| to be non-negative,
9062 : // so the PRUint32 cast (to avoid compiler warnings) is ok.)
9063 0 : PRUint32 maxTimeoutMs = PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE);
9064 0 : if (static_cast<PRUint32>(interval) > maxTimeoutMs) {
9065 0 : interval = maxTimeoutMs;
9066 : }
9067 :
9068 0 : nsRefPtr<nsTimeout> timeout = new nsTimeout();
9069 0 : timeout->mIsInterval = aIsInterval;
9070 0 : timeout->mInterval = interval;
9071 0 : timeout->mScriptHandler = aHandler;
9072 :
9073 : // Now clamp the actual interval we will use for the timer based on
9074 0 : PRUint32 nestingLevel = sNestingLevel + 1;
9075 0 : PRInt32 realInterval = interval;
9076 0 : if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL) {
9077 : // Don't allow timeouts less than DOMMinTimeoutValue() from
9078 : // now...
9079 0 : realInterval = NS_MAX(realInterval, DOMMinTimeoutValue());
9080 : }
9081 :
9082 : // Get principal of currently executing code, save for execution of timeout.
9083 : // If our principals subsume the subject principal then use the subject
9084 : // principal. Otherwise, use our principal to avoid running script in
9085 : // elevated principals.
9086 :
9087 0 : nsCOMPtr<nsIPrincipal> subjectPrincipal;
9088 : nsresult rv;
9089 0 : rv = nsContentUtils::GetSecurityManager()->
9090 0 : GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
9091 0 : if (NS_FAILED(rv)) {
9092 0 : return NS_ERROR_FAILURE;
9093 : }
9094 :
9095 0 : bool subsumes = false;
9096 0 : nsCOMPtr<nsIPrincipal> ourPrincipal = GetPrincipal();
9097 :
9098 : // Note the direction of this test: We don't allow setTimeouts running with
9099 : // chrome privileges on content windows, but we do allow setTimeouts running
9100 : // with content privileges on chrome windows (where they can't do very much,
9101 : // of course).
9102 0 : rv = ourPrincipal->Subsumes(subjectPrincipal, &subsumes);
9103 0 : if (NS_FAILED(rv)) {
9104 0 : return NS_ERROR_FAILURE;
9105 : }
9106 :
9107 0 : if (subsumes) {
9108 0 : timeout->mPrincipal = subjectPrincipal;
9109 : } else {
9110 0 : timeout->mPrincipal = ourPrincipal;
9111 : }
9112 :
9113 0 : ++gTimeoutsRecentlySet;
9114 0 : TimeDuration delta = TimeDuration::FromMilliseconds(realInterval);
9115 :
9116 0 : if (!IsFrozen() && !mTimeoutsSuspendDepth) {
9117 : // If we're not currently frozen, then we set timeout->mWhen to be the
9118 : // actual firing time of the timer (i.e., now + delta). We also actually
9119 : // create a timer and fire it off.
9120 :
9121 0 : timeout->mWhen = TimeStamp::Now() + delta;
9122 :
9123 0 : timeout->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
9124 0 : if (NS_FAILED(rv)) {
9125 0 : return rv;
9126 : }
9127 :
9128 0 : nsRefPtr<nsTimeout> copy = timeout;
9129 :
9130 0 : rv = timeout->mTimer->InitWithFuncCallback(TimerCallback, timeout,
9131 : realInterval,
9132 0 : nsITimer::TYPE_ONE_SHOT);
9133 0 : if (NS_FAILED(rv)) {
9134 0 : return rv;
9135 : }
9136 :
9137 : // The timeout is now also held in the timer's closure.
9138 0 : copy.forget();
9139 : } else {
9140 : // If we are frozen, however, then we instead simply set
9141 : // timeout->mTimeRemaining to be the "time remaining" in the timeout (i.e.,
9142 : // the interval itself). We don't create a timer for it, since that will
9143 : // happen when we are thawed and the timeout will then get a timer and run
9144 : // to completion.
9145 :
9146 0 : timeout->mTimeRemaining = delta;
9147 : }
9148 :
9149 0 : timeout->mWindow = this;
9150 :
9151 0 : if (!aIsInterval) {
9152 0 : timeout->mNestingLevel = nestingLevel;
9153 : }
9154 :
9155 : // No popups from timeouts by default
9156 0 : timeout->mPopupState = openAbused;
9157 :
9158 0 : if (gRunningTimeoutDepth == 0 && gPopupControlState < openAbused) {
9159 : // This timeout is *not* set from another timeout and it's set
9160 : // while popups are enabled. Propagate the state to the timeout if
9161 : // its delay (interval) is equal to or less than what
9162 : // "dom.disable_open_click_delay" is set to (in ms).
9163 :
9164 : PRInt32 delay =
9165 0 : Preferences::GetInt("dom.disable_open_click_delay");
9166 :
9167 : // This is checking |interval|, not realInterval, on purpose,
9168 : // because our lower bound for |realInterval| could be pretty high
9169 : // in some cases.
9170 0 : if (interval <= delay) {
9171 0 : timeout->mPopupState = gPopupControlState;
9172 : }
9173 : }
9174 :
9175 0 : InsertTimeoutIntoList(timeout);
9176 :
9177 0 : timeout->mPublicId = ++mTimeoutPublicIdCounter;
9178 0 : *aReturn = timeout->mPublicId;
9179 :
9180 0 : return NS_OK;
9181 :
9182 : }
9183 :
9184 : nsresult
9185 0 : nsGlobalWindow::SetTimeoutOrInterval(bool aIsInterval, PRInt32 *aReturn)
9186 : {
9187 : // This needs to forward to the inner window, but since the current
9188 : // inner may not be the inner in the calling scope, we need to treat
9189 : // this specially here as we don't want timeouts registered in a
9190 : // dying inner window to get registered and run on the current inner
9191 : // window. To get this right, we need to forward this call to the
9192 : // inner window that's calling window.setTimeout().
9193 :
9194 0 : if (IsOuterWindow()) {
9195 0 : nsGlobalWindow* callerInner = CallerInnerWindow();
9196 0 : NS_ENSURE_TRUE(callerInner, NS_ERROR_NOT_AVAILABLE);
9197 :
9198 : // If the caller and the callee share the same outer window,
9199 : // forward to the callee inner. Else, we forward to the current
9200 : // inner (e.g. someone is calling setTimeout() on a reference to
9201 : // some other window).
9202 :
9203 0 : if (callerInner->GetOuterWindow() == this &&
9204 0 : callerInner->IsInnerWindow()) {
9205 0 : return callerInner->SetTimeoutOrInterval(aIsInterval, aReturn);
9206 : }
9207 :
9208 0 : FORWARD_TO_INNER(SetTimeoutOrInterval, (aIsInterval, aReturn),
9209 : NS_ERROR_NOT_INITIALIZED);
9210 : }
9211 :
9212 0 : PRInt32 interval = 0;
9213 0 : bool isInterval = aIsInterval;
9214 0 : nsCOMPtr<nsIScriptTimeoutHandler> handler;
9215 : nsresult rv = NS_CreateJSTimeoutHandler(this,
9216 : &isInterval,
9217 : &interval,
9218 0 : getter_AddRefs(handler));
9219 0 : if (NS_FAILED(rv))
9220 0 : return (rv == NS_ERROR_DOM_TYPE_ERR) ? NS_OK : rv;
9221 :
9222 0 : return SetTimeoutOrInterval(handler, interval, isInterval, aReturn);
9223 : }
9224 :
9225 : // static
9226 : void
9227 0 : nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
9228 : {
9229 : // If a modal dialog is open for this window, return early. Pending
9230 : // timeouts will run when the modal dialog is dismissed.
9231 0 : if (IsInModalState() || mTimeoutsSuspendDepth) {
9232 0 : return;
9233 : }
9234 :
9235 : NS_TIME_FUNCTION;
9236 :
9237 0 : NS_ASSERTION(IsInnerWindow(), "Timeout running on outer window!");
9238 0 : NS_ASSERTION(!IsFrozen(), "Timeout running on a window in the bfcache!");
9239 :
9240 : nsTimeout *nextTimeout, *timeout;
9241 : nsTimeout *last_expired_timeout, *last_insertion_point;
9242 0 : nsTimeout dummy_timeout;
9243 0 : PRUint32 firingDepth = mTimeoutFiringDepth + 1;
9244 :
9245 : // Make sure that the window and the script context don't go away as
9246 : // a result of running timeouts
9247 0 : nsCOMPtr<nsIScriptGlobalObject> windowKungFuDeathGrip(this);
9248 :
9249 : // A native timer has gone off. See which of our timeouts need
9250 : // servicing
9251 0 : TimeStamp now = TimeStamp::Now();
9252 0 : TimeStamp deadline;
9253 :
9254 0 : if (aTimeout && aTimeout->mWhen > now) {
9255 : // The OS timer fired early (yikes!), and possibly out of order
9256 : // too. Set |deadline| to be the time when the OS timer *should*
9257 : // have fired so that any timers that *should* have fired before
9258 : // aTimeout *will* be fired now. This happens most of the time on
9259 : // Win2k.
9260 :
9261 0 : deadline = aTimeout->mWhen;
9262 : } else {
9263 0 : deadline = now;
9264 : }
9265 :
9266 : // The timeout list is kept in deadline order. Discover the latest
9267 : // timeout whose deadline has expired. On some platforms, native
9268 : // timeout events fire "early", so we need to test the timer as well
9269 : // as the deadline.
9270 0 : last_expired_timeout = nsnull;
9271 0 : for (timeout = FirstTimeout(); IsTimeout(timeout); timeout = timeout->Next()) {
9272 0 : if (((timeout == aTimeout) || (timeout->mWhen <= deadline)) &&
9273 : (timeout->mFiringDepth == 0)) {
9274 : // Mark any timeouts that are on the list to be fired with the
9275 : // firing depth so that we can reentrantly run timeouts
9276 0 : timeout->mFiringDepth = firingDepth;
9277 0 : last_expired_timeout = timeout;
9278 : }
9279 : }
9280 :
9281 : // Maybe the timeout that the event was fired for has been deleted
9282 : // and there are no others timeouts with deadlines that make them
9283 : // eligible for execution yet. Go away.
9284 0 : if (!last_expired_timeout) {
9285 : return;
9286 : }
9287 :
9288 : // Record telemetry information about timers set recently.
9289 0 : TimeDuration recordingInterval = TimeDuration::FromMilliseconds(STATISTICS_INTERVAL);
9290 0 : if (gLastRecordedRecentTimeouts.IsNull() ||
9291 0 : now - gLastRecordedRecentTimeouts > recordingInterval) {
9292 0 : PRUint32 count = gTimeoutsRecentlySet;
9293 0 : gTimeoutsRecentlySet = 0;
9294 0 : Telemetry::Accumulate(Telemetry::DOM_TIMERS_RECENTLY_SET, count);
9295 0 : gLastRecordedRecentTimeouts = now;
9296 : }
9297 :
9298 : // Insert a dummy timeout into the list of timeouts between the
9299 : // portion of the list that we are about to process now and those
9300 : // timeouts that will be processed in a future call to
9301 : // win_run_timeout(). This dummy timeout serves as the head of the
9302 : // list for any timeouts inserted as a result of running a timeout.
9303 0 : dummy_timeout.mFiringDepth = firingDepth;
9304 0 : dummy_timeout.mWhen = now;
9305 0 : PR_INSERT_AFTER(&dummy_timeout, last_expired_timeout);
9306 :
9307 : // Don't let ClearWindowTimeouts throw away our stack-allocated
9308 : // dummy timeout.
9309 0 : dummy_timeout.AddRef();
9310 0 : dummy_timeout.AddRef();
9311 :
9312 0 : last_insertion_point = mTimeoutInsertionPoint;
9313 : // If we ever start setting mTimeoutInsertionPoint to a non-dummy timeout,
9314 : // the logic in ResetTimersForNonBackgroundWindow will need to change.
9315 0 : mTimeoutInsertionPoint = &dummy_timeout;
9316 :
9317 0 : Telemetry::AutoCounter<Telemetry::DOM_TIMERS_FIRED_PER_NATIVE_TIMEOUT> timeoutsRan;
9318 :
9319 0 : for (timeout = FirstTimeout();
9320 0 : timeout != &dummy_timeout && !IsFrozen();
9321 : timeout = nextTimeout) {
9322 0 : nextTimeout = timeout->Next();
9323 :
9324 0 : if (timeout->mFiringDepth != firingDepth) {
9325 : // We skip the timeout since it's on the list to run at another
9326 : // depth.
9327 :
9328 0 : continue;
9329 : }
9330 :
9331 0 : if (mTimeoutsSuspendDepth) {
9332 : // Some timer did suspend us. Make sure the
9333 : // rest of the timers get executed later.
9334 0 : timeout->mFiringDepth = 0;
9335 0 : continue;
9336 : }
9337 :
9338 : // The timeout is on the list to run at this depth, go ahead and
9339 : // process it.
9340 :
9341 : // Get the script context (a strong ref to prevent it going away)
9342 : // for this timeout and ensure the script language is enabled.
9343 : nsCOMPtr<nsIScriptContext> scx = GetScriptContextInternal(
9344 0 : timeout->mScriptHandler->GetScriptTypeID());
9345 :
9346 0 : if (!scx) {
9347 : // No context means this window was closed or never properly
9348 : // initialized for this language.
9349 0 : continue;
9350 : }
9351 :
9352 : // The "scripts disabled" concept is still a little vague wrt
9353 : // multiple languages. Prepare for the day when languages can be
9354 : // disabled independently of the other languages...
9355 0 : if (!scx->GetScriptsEnabled()) {
9356 : // Scripts were enabled once in this window (unless aTimeout ==
9357 : // nsnull) but now scripts are disabled (we might be in
9358 : // print-preview, for instance), this means we shouldn't run any
9359 : // timeouts at this point.
9360 : //
9361 : // If scripts are enabled for this language in this window again
9362 : // we'll fire the timeouts that are due at that point.
9363 0 : continue;
9364 : }
9365 :
9366 : // This timeout is good to run
9367 0 : nsTimeout *last_running_timeout = mRunningTimeout;
9368 0 : mRunningTimeout = timeout;
9369 0 : timeout->mRunning = true;
9370 0 : ++timeoutsRan;
9371 :
9372 : // Push this timeout's popup control state, which should only be
9373 : // eabled the first time a timeout fires that was created while
9374 : // popups were enabled and with a delay less than
9375 : // "dom.disable_open_click_delay".
9376 0 : nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
9377 :
9378 : // Clear the timeout's popup state, if any, to prevent interval
9379 : // timeouts from repeatedly opening poups.
9380 0 : timeout->mPopupState = openAbused;
9381 :
9382 : // Hold on to the timeout in case mExpr or mFunObj releases its
9383 : // doc.
9384 0 : timeout->AddRef();
9385 :
9386 0 : ++gRunningTimeoutDepth;
9387 0 : ++mTimeoutFiringDepth;
9388 :
9389 0 : bool trackNestingLevel = !timeout->mIsInterval;
9390 : PRUint32 nestingLevel;
9391 0 : if (trackNestingLevel) {
9392 0 : nestingLevel = sNestingLevel;
9393 0 : sNestingLevel = timeout->mNestingLevel;
9394 : }
9395 :
9396 0 : nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
9397 0 : JSObject* scriptObject = handler->GetScriptObject();
9398 0 : if (!scriptObject) {
9399 : // Evaluate the timeout expression.
9400 0 : const PRUnichar *script = handler->GetHandlerText();
9401 0 : NS_ASSERTION(script, "timeout has no script nor handler text!");
9402 :
9403 0 : const char *filename = nsnull;
9404 0 : PRUint32 lineNo = 0;
9405 0 : handler->GetLocation(&filename, &lineNo);
9406 :
9407 : NS_TIME_FUNCTION_MARK("(file: %s, line: %d)", filename, lineNo);
9408 :
9409 : bool is_undefined;
9410 0 : scx->EvaluateString(nsDependentString(script), FastGetGlobalJSObject(),
9411 : timeout->mPrincipal, timeout->mPrincipal,
9412 : filename, lineNo,
9413 0 : handler->GetScriptVersion(), nsnull,
9414 0 : &is_undefined);
9415 : } else {
9416 0 : nsCOMPtr<nsIVariant> dummy;
9417 0 : nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
9418 0 : scx->CallEventHandler(me, FastGetGlobalJSObject(),
9419 0 : scriptObject, handler->GetArgv(),
9420 : // XXXmarkh - consider allowing CallEventHandler to
9421 : // accept nsnull?
9422 0 : getter_AddRefs(dummy));
9423 :
9424 : }
9425 0 : handler = nsnull; // drop reference before dropping timeout refs.
9426 :
9427 0 : if (trackNestingLevel) {
9428 0 : sNestingLevel = nestingLevel;
9429 : }
9430 :
9431 0 : --mTimeoutFiringDepth;
9432 0 : --gRunningTimeoutDepth;
9433 :
9434 0 : mRunningTimeout = last_running_timeout;
9435 0 : timeout->mRunning = false;
9436 :
9437 : // We ignore any failures from calling EvaluateString() or
9438 : // CallEventHandler() on the context here since we're in a loop
9439 : // where we're likely to be running timeouts whose OS timers
9440 : // didn't fire in time and we don't want to not fire those timers
9441 : // now just because execution of one timer failed. We can't
9442 : // propagate the error to anyone who cares about it from this
9443 : // point anyway, and the script context should have already reported
9444 : // the script error in the usual way - so we just drop it.
9445 :
9446 : // If all timeouts were cleared and |timeout != aTimeout| then
9447 : // |timeout| may be the last reference to the timeout so check if
9448 : // it was cleared before releasing it.
9449 0 : bool timeout_was_cleared = timeout->mCleared;
9450 :
9451 0 : timeout->Release();
9452 :
9453 0 : if (timeout_was_cleared) {
9454 : // The running timeout's window was cleared, this means that
9455 : // ClearAllTimeouts() was called from a *nested* call, possibly
9456 : // through a timeout that fired while a modal (to this window)
9457 : // dialog was open or through other non-obvious paths.
9458 :
9459 0 : mTimeoutInsertionPoint = last_insertion_point;
9460 :
9461 : return;
9462 : }
9463 :
9464 0 : bool isInterval = false;
9465 :
9466 : // If we have a regular interval timer, we re-schedule the
9467 : // timeout, accounting for clock drift.
9468 0 : if (timeout->mIsInterval) {
9469 : // Compute time to next timeout for interval timer.
9470 : // Make sure nextInterval is at least DOMMinTimeoutValue().
9471 : TimeDuration nextInterval =
9472 : TimeDuration::FromMilliseconds(NS_MAX(timeout->mInterval,
9473 0 : PRUint32(DOMMinTimeoutValue())));
9474 :
9475 : // If we're running pending timeouts because they've been temporarily
9476 : // disabled (!aTimeout), set the next interval to be relative to "now",
9477 : // and not to when the timeout that was pending should have fired.
9478 0 : TimeStamp firingTime;
9479 0 : if (!aTimeout)
9480 0 : firingTime = now + nextInterval;
9481 : else
9482 0 : firingTime = timeout->mWhen + nextInterval;
9483 :
9484 0 : TimeStamp currentNow = TimeStamp::Now();
9485 0 : TimeDuration delay = firingTime - currentNow;
9486 :
9487 : // And make sure delay is nonnegative; that might happen if the timer
9488 : // thread is firing our timers somewhat early or if they're taking a long
9489 : // time to run the callback.
9490 0 : if (delay < TimeDuration(0)) {
9491 0 : delay = TimeDuration(0);
9492 : }
9493 :
9494 0 : if (timeout->mTimer) {
9495 0 : timeout->mWhen = currentNow + delay; // firingTime unless delay got
9496 : // clamped, in which case it's
9497 : // currentNow.
9498 :
9499 : // Reschedule the OS timer. Don't bother returning any error
9500 : // codes if this fails since the callers of this method
9501 : // doesn't care about them nobody who cares about them
9502 : // anyways.
9503 :
9504 : // Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
9505 : // PRTime to make the division do the right thing on 64-bit
9506 : // platforms whether delay is positive or negative (which we
9507 : // know is always positive here, but cast anyways for
9508 : // consistency).
9509 0 : nsresult rv = timeout->mTimer->
9510 : InitWithFuncCallback(TimerCallback, timeout,
9511 0 : delay.ToMilliseconds(),
9512 0 : nsITimer::TYPE_ONE_SHOT);
9513 :
9514 0 : if (NS_FAILED(rv)) {
9515 0 : NS_ERROR("Error initializing timer for DOM timeout!");
9516 :
9517 : // We failed to initialize the new OS timer, this timer does
9518 : // us no good here so we just cancel it (just in case) and
9519 : // null out the pointer to the OS timer, this will release the
9520 : // OS timer. As we continue executing the code below we'll end
9521 : // up deleting the timeout since it's not an interval timeout
9522 : // any more (since timeout->mTimer == nsnull).
9523 0 : timeout->mTimer->Cancel();
9524 0 : timeout->mTimer = nsnull;
9525 :
9526 : // Now that the OS timer no longer has a reference to the
9527 : // timeout we need to drop that reference.
9528 0 : timeout->Release();
9529 : }
9530 : } else {
9531 0 : NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth,
9532 : "How'd our timer end up null if we're not frozen or "
9533 : "suspended?");
9534 :
9535 0 : timeout->mTimeRemaining = delay;
9536 0 : isInterval = true;
9537 : }
9538 : }
9539 :
9540 0 : if (timeout->mTimer) {
9541 0 : if (timeout->mIsInterval) {
9542 0 : isInterval = true;
9543 : } else {
9544 : // The timeout still has an OS timer, and it's not an
9545 : // interval, that means that the OS timer could still fire (if
9546 : // it didn't already, i.e. aTimeout == timeout), cancel the OS
9547 : // timer and release its reference to the timeout.
9548 0 : timeout->mTimer->Cancel();
9549 0 : timeout->mTimer = nsnull;
9550 :
9551 0 : timeout->Release();
9552 : }
9553 : }
9554 :
9555 : // Running a timeout can cause another timeout to be deleted, so
9556 : // we need to reset the pointer to the following timeout.
9557 0 : nextTimeout = timeout->Next();
9558 :
9559 0 : PR_REMOVE_LINK(timeout);
9560 :
9561 0 : if (isInterval) {
9562 : // Reschedule an interval timeout. Insert interval timeout
9563 : // onto list sorted in deadline order.
9564 : // AddRefs timeout.
9565 0 : InsertTimeoutIntoList(timeout);
9566 : }
9567 :
9568 : // Release the timeout struct since it's possibly out of the list
9569 0 : timeout->Release();
9570 : }
9571 :
9572 : // Take the dummy timeout off the head of the list
9573 0 : PR_REMOVE_LINK(&dummy_timeout);
9574 :
9575 0 : mTimeoutInsertionPoint = last_insertion_point;
9576 : }
9577 :
9578 : nsrefcnt
9579 0 : nsTimeout::Release()
9580 : {
9581 0 : if (--mRefCnt > 0)
9582 0 : return mRefCnt;
9583 :
9584 : // language specific cleanup done as mScriptHandler destructs...
9585 :
9586 : // Kill the timer if it is still alive.
9587 0 : if (mTimer) {
9588 0 : mTimer->Cancel();
9589 0 : mTimer = nsnull;
9590 : }
9591 :
9592 0 : delete this;
9593 0 : return 0;
9594 : }
9595 :
9596 : nsrefcnt
9597 0 : nsTimeout::AddRef()
9598 : {
9599 0 : return ++mRefCnt;
9600 : }
9601 :
9602 :
9603 : nsresult
9604 0 : nsGlobalWindow::ClearTimeoutOrInterval(PRInt32 aTimerID)
9605 : {
9606 0 : FORWARD_TO_INNER(ClearTimeoutOrInterval, (aTimerID), NS_ERROR_NOT_INITIALIZED);
9607 :
9608 0 : PRUint32 public_id = (PRUint32)aTimerID;
9609 : nsTimeout *timeout;
9610 :
9611 0 : for (timeout = FirstTimeout();
9612 0 : IsTimeout(timeout);
9613 : timeout = timeout->Next()) {
9614 0 : if (timeout->mPublicId == public_id) {
9615 0 : if (timeout->mRunning) {
9616 : /* We're running from inside the timeout. Mark this
9617 : timeout for deferred deletion by the code in
9618 : RunTimeout() */
9619 0 : timeout->mIsInterval = false;
9620 : }
9621 : else {
9622 : /* Delete the timeout from the pending timeout list */
9623 0 : PR_REMOVE_LINK(timeout);
9624 :
9625 0 : if (timeout->mTimer) {
9626 0 : timeout->mTimer->Cancel();
9627 0 : timeout->mTimer = nsnull;
9628 0 : timeout->Release();
9629 : }
9630 0 : timeout->Release();
9631 : }
9632 0 : break;
9633 : }
9634 : }
9635 :
9636 0 : return NS_OK;
9637 : }
9638 :
9639 0 : nsresult nsGlobalWindow::ResetTimersForNonBackgroundWindow()
9640 : {
9641 0 : FORWARD_TO_INNER(ResetTimersForNonBackgroundWindow, (),
9642 : NS_ERROR_NOT_INITIALIZED);
9643 :
9644 0 : if (IsFrozen() || mTimeoutsSuspendDepth) {
9645 0 : return NS_OK;
9646 : }
9647 :
9648 0 : TimeStamp now = TimeStamp::Now();
9649 :
9650 : // If mTimeoutInsertionPoint is non-null, we're in the middle of firing
9651 : // timers and the timers we're planning to fire all come before
9652 : // mTimeoutInsertionPoint; mTimeoutInsertionPoint itself is a dummy timeout
9653 : // with an mWhen that may be semi-bogus. In that case, we don't need to do
9654 : // anything with mTimeoutInsertionPoint or anything before it, so should
9655 : // start at the timer after mTimeoutInsertionPoint, if there is one.
9656 : // Otherwise, start at the beginning of the list.
9657 0 : for (nsTimeout *timeout = mTimeoutInsertionPoint ?
9658 0 : mTimeoutInsertionPoint->Next() : FirstTimeout();
9659 0 : IsTimeout(timeout); ) {
9660 : // It's important that this check be <= so that we guarantee that
9661 : // taking NS_MAX with |now| won't make a quantity equal to
9662 : // timeout->mWhen below.
9663 0 : if (timeout->mWhen <= now) {
9664 0 : timeout = timeout->Next();
9665 0 : continue;
9666 : }
9667 :
9668 0 : if (timeout->mWhen - now >
9669 0 : TimeDuration::FromMilliseconds(gMinBackgroundTimeoutValue)) {
9670 : // No need to loop further. Timeouts are sorted in mWhen order
9671 : // and the ones after this point were all set up for at least
9672 : // gMinBackgroundTimeoutValue ms and hence were not clamped.
9673 0 : break;
9674 : }
9675 :
9676 : /* We switched from background. Re-init the timer appropriately */
9677 : // Compute the interval the timer should have had if it had not been set in a
9678 : // background window
9679 : TimeDuration interval =
9680 : TimeDuration::FromMilliseconds(NS_MAX(timeout->mInterval,
9681 0 : PRUint32(DOMMinTimeoutValue())));
9682 0 : PRUint32 oldIntervalMillisecs = 0;
9683 0 : timeout->mTimer->GetDelay(&oldIntervalMillisecs);
9684 0 : TimeDuration oldInterval = TimeDuration::FromMilliseconds(oldIntervalMillisecs);
9685 0 : if (oldInterval > interval) {
9686 : // unclamp
9687 : TimeStamp firingTime =
9688 0 : NS_MAX(timeout->mWhen - oldInterval + interval, now);
9689 :
9690 0 : NS_ASSERTION(firingTime < timeout->mWhen,
9691 : "Our firing time should strictly decrease!");
9692 :
9693 0 : TimeDuration delay = firingTime - now;
9694 0 : timeout->mWhen = firingTime;
9695 :
9696 : // Since we reset mWhen we need to move |timeout| to the right
9697 : // place in the list so that it remains sorted by mWhen.
9698 :
9699 : // Get the pointer to the next timeout now, before we move the
9700 : // current timeout in the list.
9701 0 : nsTimeout* nextTimeout = timeout->Next();
9702 :
9703 : // It is safe to remove and re-insert because mWhen is now
9704 : // strictly smaller than it used to be, so we know we'll insert
9705 : // |timeout| before nextTimeout.
9706 0 : NS_ASSERTION(!IsTimeout(nextTimeout) ||
9707 : timeout->mWhen < nextTimeout->mWhen, "How did that happen?");
9708 0 : PR_REMOVE_LINK(timeout);
9709 : // InsertTimeoutIntoList will addref |timeout| and reset
9710 : // mFiringDepth. Make sure to undo that after calling it.
9711 0 : PRUint32 firingDepth = timeout->mFiringDepth;
9712 0 : InsertTimeoutIntoList(timeout);
9713 0 : timeout->mFiringDepth = firingDepth;
9714 0 : timeout->Release();
9715 :
9716 : nsresult rv =
9717 0 : timeout->mTimer->InitWithFuncCallback(TimerCallback,
9718 : timeout,
9719 0 : delay.ToMilliseconds(),
9720 0 : nsITimer::TYPE_ONE_SHOT);
9721 :
9722 0 : if (NS_FAILED(rv)) {
9723 0 : NS_WARNING("Error resetting non background timer for DOM timeout!");
9724 0 : return rv;
9725 : }
9726 :
9727 0 : timeout = nextTimeout;
9728 : } else {
9729 0 : timeout = timeout->Next();
9730 : }
9731 : }
9732 :
9733 0 : return NS_OK;
9734 : }
9735 :
9736 : void
9737 0 : nsGlobalWindow::ClearAllTimeouts()
9738 : {
9739 : nsTimeout *timeout, *nextTimeout;
9740 :
9741 0 : for (timeout = FirstTimeout(); IsTimeout(timeout); timeout = nextTimeout) {
9742 : /* If RunTimeout() is higher up on the stack for this
9743 : window, e.g. as a result of document.write from a timeout,
9744 : then we need to reset the list insertion point for
9745 : newly-created timeouts in case the user adds a timeout,
9746 : before we pop the stack back to RunTimeout. */
9747 0 : if (mRunningTimeout == timeout)
9748 0 : mTimeoutInsertionPoint = nsnull;
9749 :
9750 0 : nextTimeout = timeout->Next();
9751 :
9752 0 : if (timeout->mTimer) {
9753 0 : timeout->mTimer->Cancel();
9754 0 : timeout->mTimer = nsnull;
9755 :
9756 : // Drop the count since the timer isn't going to hold on
9757 : // anymore.
9758 0 : timeout->Release();
9759 : }
9760 :
9761 : // Set timeout->mCleared to true to indicate that the timeout was
9762 : // cleared and taken out of the list of timeouts
9763 0 : timeout->mCleared = true;
9764 :
9765 : // Drop the count since we're removing it from the list.
9766 0 : timeout->Release();
9767 : }
9768 :
9769 : // Clear out our list
9770 0 : PR_INIT_CLIST(&mTimeouts);
9771 0 : }
9772 :
9773 : void
9774 0 : nsGlobalWindow::InsertTimeoutIntoList(nsTimeout *aTimeout)
9775 : {
9776 0 : NS_ASSERTION(IsInnerWindow(),
9777 : "InsertTimeoutIntoList() called on outer window!");
9778 :
9779 : // Start at mLastTimeout and go backwards. Don't go further than
9780 : // mTimeoutInsertionPoint, though. This optimizes for the common case of
9781 : // insertion at the end.
9782 : nsTimeout* prevSibling;
9783 0 : for (prevSibling = LastTimeout();
9784 0 : IsTimeout(prevSibling) && prevSibling != mTimeoutInsertionPoint &&
9785 : // This condition needs to match the one in SetTimeoutOrInterval that
9786 : // determines whether to set mWhen or mTimeRemaining.
9787 0 : ((IsFrozen() || mTimeoutsSuspendDepth) ?
9788 0 : prevSibling->mTimeRemaining > aTimeout->mTimeRemaining :
9789 0 : prevSibling->mWhen > aTimeout->mWhen);
9790 : prevSibling = prevSibling->Prev()) {
9791 : /* Do nothing; just searching */
9792 : }
9793 :
9794 : // Now link in aTimeout after prevSibling.
9795 0 : PR_INSERT_AFTER(aTimeout, prevSibling);
9796 :
9797 0 : aTimeout->mFiringDepth = 0;
9798 :
9799 : // Increment the timeout's reference count since it's now held on to
9800 : // by the list
9801 0 : aTimeout->AddRef();
9802 0 : }
9803 :
9804 : // static
9805 : void
9806 0 : nsGlobalWindow::TimerCallback(nsITimer *aTimer, void *aClosure)
9807 : {
9808 0 : nsRefPtr<nsTimeout> timeout = (nsTimeout *)aClosure;
9809 :
9810 0 : timeout->mWindow->RunTimeout(timeout);
9811 0 : }
9812 :
9813 : //*****************************************************************************
9814 : // nsGlobalWindow: Helper Functions
9815 : //*****************************************************************************
9816 :
9817 : nsresult
9818 0 : nsGlobalWindow::GetTreeOwner(nsIDocShellTreeOwner **aTreeOwner)
9819 : {
9820 0 : FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
9821 :
9822 0 : nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
9823 :
9824 : // If there's no docShellAsItem, this window must have been closed,
9825 : // in that case there is no tree owner.
9826 :
9827 0 : if (!docShellAsItem) {
9828 0 : *aTreeOwner = nsnull;
9829 :
9830 0 : return NS_OK;
9831 : }
9832 :
9833 0 : return docShellAsItem->GetTreeOwner(aTreeOwner);
9834 : }
9835 :
9836 : nsresult
9837 0 : nsGlobalWindow::GetTreeOwner(nsIBaseWindow **aTreeOwner)
9838 : {
9839 0 : FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
9840 :
9841 0 : nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
9842 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
9843 :
9844 : // If there's no docShellAsItem, this window must have been closed,
9845 : // in that case there is no tree owner.
9846 :
9847 0 : if (docShellAsItem) {
9848 0 : docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
9849 : }
9850 :
9851 0 : if (!treeOwner) {
9852 0 : *aTreeOwner = nsnull;
9853 0 : return NS_OK;
9854 : }
9855 :
9856 0 : return CallQueryInterface(treeOwner, aTreeOwner);
9857 : }
9858 :
9859 : nsresult
9860 0 : nsGlobalWindow::GetWebBrowserChrome(nsIWebBrowserChrome **aBrowserChrome)
9861 : {
9862 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
9863 0 : GetTreeOwner(getter_AddRefs(treeOwner));
9864 :
9865 0 : nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner));
9866 0 : NS_IF_ADDREF(*aBrowserChrome = browserChrome);
9867 :
9868 0 : return NS_OK;
9869 : }
9870 :
9871 : nsIScrollableFrame *
9872 0 : nsGlobalWindow::GetScrollFrame()
9873 : {
9874 0 : FORWARD_TO_OUTER(GetScrollFrame, (), nsnull);
9875 :
9876 0 : if (!mDocShell) {
9877 0 : return nsnull;
9878 : }
9879 :
9880 0 : nsCOMPtr<nsIPresShell> presShell;
9881 0 : mDocShell->GetPresShell(getter_AddRefs(presShell));
9882 0 : if (presShell) {
9883 0 : return presShell->GetRootScrollFrameAsScrollable();
9884 : }
9885 0 : return nsnull;
9886 : }
9887 :
9888 : nsresult
9889 0 : nsGlobalWindow::BuildURIfromBase(const char *aURL, nsIURI **aBuiltURI,
9890 : bool *aFreeSecurityPass,
9891 : JSContext **aCXused)
9892 : {
9893 0 : nsIScriptContext *scx = GetContextInternal();
9894 0 : JSContext *cx = nsnull;
9895 :
9896 0 : *aBuiltURI = nsnull;
9897 0 : *aFreeSecurityPass = false;
9898 0 : if (aCXused)
9899 0 : *aCXused = nsnull;
9900 :
9901 : // get JSContext
9902 0 : NS_ASSERTION(scx, "opening window missing its context");
9903 0 : NS_ASSERTION(mDocument, "opening window missing its document");
9904 0 : if (!scx || !mDocument)
9905 0 : return NS_ERROR_FAILURE;
9906 :
9907 0 : nsCOMPtr<nsIDOMChromeWindow> chrome_win = do_QueryObject(this);
9908 :
9909 0 : if (nsContentUtils::IsCallerChrome() && !chrome_win) {
9910 : // If open() is called from chrome on a non-chrome window, we'll
9911 : // use the context from the window on which open() is being called
9912 : // to prevent giving chrome priveleges to new windows opened in
9913 : // such a way. This also makes us get the appropriate base URI for
9914 : // the below URI resolution code.
9915 :
9916 0 : cx = scx->GetNativeContext();
9917 : } else {
9918 : // get the JSContext from the call stack
9919 0 : nsCOMPtr<nsIThreadJSContextStack> stack(do_GetService(sJSStackContractID));
9920 0 : if (stack)
9921 0 : stack->Peek(&cx);
9922 : }
9923 :
9924 : /* resolve the URI, which could be relative to the calling window
9925 : (note the algorithm to get the base URI should match the one
9926 : used to actually kick off the load in nsWindowWatcher.cpp). */
9927 0 : nsCAutoString charset(NS_LITERAL_CSTRING("UTF-8")); // default to utf-8
9928 0 : nsIURI* baseURI = nsnull;
9929 0 : nsCOMPtr<nsIURI> uriToLoad;
9930 0 : nsCOMPtr<nsIDOMWindow> sourceWindow;
9931 :
9932 0 : if (cx) {
9933 0 : nsIScriptContext *scriptcx = nsJSUtils::GetDynamicScriptContext(cx);
9934 0 : if (scriptcx)
9935 0 : sourceWindow = do_QueryInterface(scriptcx->GetGlobalObject());
9936 : }
9937 :
9938 0 : if (!sourceWindow) {
9939 0 : sourceWindow = do_QueryInterface(NS_ISUPPORTS_CAST(nsIDOMWindow *, this));
9940 0 : *aFreeSecurityPass = true;
9941 : }
9942 :
9943 0 : if (sourceWindow) {
9944 0 : nsCOMPtr<nsIDOMDocument> domDoc;
9945 0 : sourceWindow->GetDocument(getter_AddRefs(domDoc));
9946 0 : nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
9947 0 : if (doc) {
9948 0 : baseURI = doc->GetDocBaseURI();
9949 0 : charset = doc->GetDocumentCharacterSet();
9950 : }
9951 : }
9952 :
9953 0 : if (aCXused)
9954 0 : *aCXused = cx;
9955 0 : return NS_NewURI(aBuiltURI, nsDependentCString(aURL), charset.get(), baseURI);
9956 : }
9957 :
9958 : nsresult
9959 0 : nsGlobalWindow::SecurityCheckURL(const char *aURL)
9960 : {
9961 : JSContext *cx;
9962 : bool freePass;
9963 0 : nsCOMPtr<nsIURI> uri;
9964 :
9965 0 : if (NS_FAILED(BuildURIfromBase(aURL, getter_AddRefs(uri), &freePass, &cx)))
9966 0 : return NS_ERROR_FAILURE;
9967 :
9968 0 : if (!freePass && NS_FAILED(nsContentUtils::GetSecurityManager()->
9969 : CheckLoadURIFromScript(cx, uri)))
9970 0 : return NS_ERROR_FAILURE;
9971 :
9972 0 : return NS_OK;
9973 : }
9974 :
9975 : void
9976 0 : nsGlobalWindow::FlushPendingNotifications(mozFlushType aType)
9977 : {
9978 0 : if (mDoc) {
9979 0 : mDoc->FlushPendingNotifications(aType);
9980 : }
9981 0 : }
9982 :
9983 : void
9984 0 : nsGlobalWindow::EnsureSizeUpToDate()
9985 : {
9986 : // If we're a subframe, make sure our size is up to date. It's OK that this
9987 : // crosses the content/chrome boundary, since chrome can have pending reflows
9988 : // too.
9989 : nsGlobalWindow *parent =
9990 0 : static_cast<nsGlobalWindow *>(GetPrivateParent());
9991 0 : if (parent) {
9992 0 : parent->FlushPendingNotifications(Flush_Layout);
9993 : }
9994 0 : }
9995 :
9996 : nsresult
9997 0 : nsGlobalWindow::SaveWindowState(nsISupports **aState)
9998 : {
9999 0 : NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
10000 :
10001 0 : *aState = nsnull;
10002 :
10003 0 : if (!mContext || !mJSObject) {
10004 : // The window may be getting torn down; don't bother saving state.
10005 0 : return NS_OK;
10006 : }
10007 :
10008 0 : nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
10009 0 : NS_ASSERTION(inner, "No inner window to save");
10010 :
10011 : // Don't do anything else to this inner window! After this point, all
10012 : // calls to SetTimeoutOrInterval will create entries in the timeout
10013 : // list that will only run after this window has come out of the bfcache.
10014 : // Also, while we're frozen, we won't dispatch online/offline events
10015 : // to the page.
10016 0 : inner->Freeze();
10017 :
10018 : // Remember the outer window's prototype.
10019 0 : JSContext *cx = mContext->GetNativeContext();
10020 0 : JSAutoRequest req(cx);
10021 :
10022 0 : nsIXPConnect *xpc = nsContentUtils::XPConnect();
10023 :
10024 : nsCOMPtr<nsIClassInfo> ci =
10025 0 : do_QueryInterface((nsIScriptGlobalObject *)this);
10026 0 : nsCOMPtr<nsIXPConnectJSObjectHolder> proto;
10027 : nsresult rv = xpc->GetWrappedNativePrototype(cx, mJSObject, ci,
10028 0 : getter_AddRefs(proto));
10029 0 : NS_ENSURE_SUCCESS(rv, rv);
10030 :
10031 0 : JSObject *realProto = JS_GetPrototype(mJSObject);
10032 0 : nsCOMPtr<nsIXPConnectJSObjectHolder> realProtoHolder;
10033 0 : if (realProto) {
10034 0 : rv = xpc->HoldObject(cx, realProto, getter_AddRefs(realProtoHolder));
10035 0 : NS_ENSURE_SUCCESS(rv, rv);
10036 : }
10037 :
10038 : nsCOMPtr<nsISupports> state = new WindowStateHolder(inner,
10039 : mInnerWindowHolder,
10040 : proto,
10041 0 : realProtoHolder);
10042 0 : NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY);
10043 :
10044 : JSObject *wnProto;
10045 0 : proto->GetJSObject(&wnProto);
10046 0 : if (!JS_SetPrototype(cx, mJSObject, wnProto)) {
10047 0 : return NS_ERROR_FAILURE;
10048 : }
10049 :
10050 : #ifdef DEBUG_PAGE_CACHE
10051 : printf("saving window state, state = %p\n", (void*)state);
10052 : #endif
10053 :
10054 0 : state.swap(*aState);
10055 0 : return NS_OK;
10056 : }
10057 :
10058 : nsresult
10059 0 : nsGlobalWindow::RestoreWindowState(nsISupports *aState)
10060 : {
10061 0 : NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window");
10062 :
10063 0 : if (!mContext || !mJSObject) {
10064 : // The window may be getting torn down; don't bother restoring state.
10065 0 : return NS_OK;
10066 : }
10067 :
10068 0 : nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
10069 0 : NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE);
10070 :
10071 : #ifdef DEBUG_PAGE_CACHE
10072 : printf("restoring window state, state = %p\n", (void*)holder);
10073 : #endif
10074 :
10075 : // And we're ready to go!
10076 0 : nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
10077 :
10078 : // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
10079 : // it easy to tell which link was last clicked when going back a page.
10080 0 : nsIContent* focusedNode = inner->GetFocusedNode();
10081 0 : if (IsLink(focusedNode)) {
10082 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
10083 0 : if (fm) {
10084 0 : nsCOMPtr<nsIDOMElement> focusedElement(do_QueryInterface(focusedNode));
10085 : fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
10086 0 : nsIFocusManager::FLAG_SHOWRING);
10087 : }
10088 : }
10089 :
10090 0 : inner->Thaw();
10091 :
10092 0 : holder->DidRestoreWindow();
10093 :
10094 0 : return NS_OK;
10095 : }
10096 :
10097 : void
10098 0 : nsGlobalWindow::SuspendTimeouts(PRUint32 aIncrease,
10099 : bool aFreezeChildren)
10100 : {
10101 0 : FORWARD_TO_INNER_VOID(SuspendTimeouts, (aIncrease, aFreezeChildren));
10102 :
10103 0 : bool suspended = (mTimeoutsSuspendDepth != 0);
10104 0 : mTimeoutsSuspendDepth += aIncrease;
10105 :
10106 0 : if (!suspended) {
10107 0 : DisableDeviceMotionUpdates();
10108 :
10109 : // Suspend all of the workers for this window.
10110 0 : nsIScriptContext *scx = GetContextInternal();
10111 0 : JSContext *cx = scx ? scx->GetNativeContext() : nsnull;
10112 0 : mozilla::dom::workers::SuspendWorkersForWindow(cx, this);
10113 :
10114 0 : TimeStamp now = TimeStamp::Now();
10115 0 : for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
10116 : // Set mTimeRemaining to be the time remaining for this timer.
10117 0 : if (t->mWhen > now)
10118 0 : t->mTimeRemaining = t->mWhen - now;
10119 : else
10120 0 : t->mTimeRemaining = TimeDuration(0);
10121 :
10122 : // Drop the XPCOM timer; we'll reschedule when restoring the state.
10123 0 : if (t->mTimer) {
10124 0 : t->mTimer->Cancel();
10125 0 : t->mTimer = nsnull;
10126 :
10127 : // Drop the reference that the timer's closure had on this timeout, we'll
10128 : // add it back in ResumeTimeouts. Note that it shouldn't matter that we're
10129 : // passing null for the context, since this shouldn't actually release this
10130 : // timeout.
10131 0 : t->Release();
10132 : }
10133 : }
10134 : }
10135 :
10136 : // Suspend our children as well.
10137 0 : nsCOMPtr<nsIDocShellTreeNode> node(do_QueryInterface(GetDocShell()));
10138 0 : if (node) {
10139 0 : PRInt32 childCount = 0;
10140 0 : node->GetChildCount(&childCount);
10141 :
10142 0 : for (PRInt32 i = 0; i < childCount; ++i) {
10143 0 : nsCOMPtr<nsIDocShellTreeItem> childShell;
10144 0 : node->GetChildAt(i, getter_AddRefs(childShell));
10145 0 : NS_ASSERTION(childShell, "null child shell");
10146 :
10147 0 : nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
10148 0 : if (pWin) {
10149 : nsGlobalWindow *win =
10150 : static_cast<nsGlobalWindow*>
10151 0 : (static_cast<nsPIDOMWindow*>(pWin));
10152 0 : NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
10153 0 : nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
10154 :
10155 : // This is a bit hackish. Only freeze/suspend windows which are truly our
10156 : // subwindows.
10157 0 : nsCOMPtr<nsIContent> frame = do_QueryInterface(pWin->GetFrameElementInternal());
10158 0 : if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) {
10159 0 : continue;
10160 : }
10161 :
10162 0 : win->SuspendTimeouts(aIncrease, aFreezeChildren);
10163 :
10164 0 : if (inner && aFreezeChildren) {
10165 0 : inner->Freeze();
10166 : }
10167 : }
10168 : }
10169 : }
10170 : }
10171 :
10172 : nsresult
10173 0 : nsGlobalWindow::ResumeTimeouts(bool aThawChildren)
10174 : {
10175 0 : FORWARD_TO_INNER(ResumeTimeouts, (), NS_ERROR_NOT_INITIALIZED);
10176 :
10177 0 : NS_ASSERTION(mTimeoutsSuspendDepth, "Mismatched calls to ResumeTimeouts!");
10178 0 : --mTimeoutsSuspendDepth;
10179 0 : bool shouldResume = (mTimeoutsSuspendDepth == 0);
10180 : nsresult rv;
10181 :
10182 0 : if (shouldResume) {
10183 0 : EnableDeviceMotionUpdates();
10184 :
10185 : // Resume all of the workers for this window.
10186 0 : nsIScriptContext *scx = GetContextInternal();
10187 0 : JSContext *cx = scx ? scx->GetNativeContext() : nsnull;
10188 0 : mozilla::dom::workers::ResumeWorkersForWindow(cx, this);
10189 :
10190 : // Restore all of the timeouts, using the stored time remaining
10191 : // (stored in timeout->mTimeRemaining).
10192 :
10193 0 : TimeStamp now = TimeStamp::Now();
10194 :
10195 : #ifdef DEBUG
10196 0 : bool _seenDummyTimeout = false;
10197 : #endif
10198 :
10199 0 : for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
10200 : // There's a chance we're being called with RunTimeout on the stack in which
10201 : // case we have a dummy timeout in the list that *must not* be resumed. It
10202 : // can be identified by a null mWindow.
10203 0 : if (!t->mWindow) {
10204 : #ifdef DEBUG
10205 0 : NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
10206 0 : _seenDummyTimeout = true;
10207 : #endif
10208 0 : continue;
10209 : }
10210 :
10211 : // XXXbz the combination of the way |delay| and |t->mWhen| are set here
10212 : // makes no sense. Are we trying to impose that min timeout value or
10213 : // not???
10214 : PRUint32 delay =
10215 0 : NS_MAX(PRInt32(t->mTimeRemaining.ToMilliseconds()),
10216 0 : DOMMinTimeoutValue());
10217 :
10218 : // Set mWhen back to the time when the timer is supposed to
10219 : // fire.
10220 0 : t->mWhen = now + t->mTimeRemaining;
10221 :
10222 0 : t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
10223 0 : NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY);
10224 :
10225 0 : rv = t->mTimer->InitWithFuncCallback(TimerCallback, t, delay,
10226 0 : nsITimer::TYPE_ONE_SHOT);
10227 0 : if (NS_FAILED(rv)) {
10228 0 : t->mTimer = nsnull;
10229 0 : return rv;
10230 : }
10231 :
10232 : // Add a reference for the new timer's closure.
10233 0 : t->AddRef();
10234 : }
10235 : }
10236 :
10237 : // Resume our children as well.
10238 : nsCOMPtr<nsIDocShellTreeNode> node =
10239 0 : do_QueryInterface(GetDocShell());
10240 0 : if (node) {
10241 0 : PRInt32 childCount = 0;
10242 0 : node->GetChildCount(&childCount);
10243 :
10244 0 : for (PRInt32 i = 0; i < childCount; ++i) {
10245 0 : nsCOMPtr<nsIDocShellTreeItem> childShell;
10246 0 : node->GetChildAt(i, getter_AddRefs(childShell));
10247 0 : NS_ASSERTION(childShell, "null child shell");
10248 :
10249 0 : nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
10250 0 : if (pWin) {
10251 : nsGlobalWindow *win =
10252 : static_cast<nsGlobalWindow*>
10253 0 : (static_cast<nsPIDOMWindow*>(pWin));
10254 :
10255 0 : NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
10256 0 : nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
10257 :
10258 : // This is a bit hackish. Only thaw/resume windows which are truly our
10259 : // subwindows.
10260 0 : nsCOMPtr<nsIContent> frame = do_QueryInterface(pWin->GetFrameElementInternal());
10261 0 : if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) {
10262 0 : continue;
10263 : }
10264 :
10265 0 : if (inner && aThawChildren) {
10266 0 : inner->Thaw();
10267 : }
10268 :
10269 0 : rv = win->ResumeTimeouts(aThawChildren);
10270 0 : NS_ENSURE_SUCCESS(rv, rv);
10271 : }
10272 : }
10273 : }
10274 :
10275 0 : return NS_OK;
10276 : }
10277 :
10278 : PRUint32
10279 0 : nsGlobalWindow::TimeoutSuspendCount()
10280 : {
10281 0 : FORWARD_TO_INNER(TimeoutSuspendCount, (), 0);
10282 0 : return mTimeoutsSuspendDepth;
10283 : }
10284 :
10285 : void
10286 0 : nsGlobalWindow::SetHasOrientationEventListener()
10287 : {
10288 0 : mHasDeviceMotion = true;
10289 0 : EnableDeviceMotionUpdates();
10290 0 : }
10291 :
10292 : void
10293 0 : nsGlobalWindow::RemoveOrientationEventListener() {
10294 0 : DisableDeviceMotionUpdates();
10295 0 : }
10296 :
10297 : NS_IMETHODIMP
10298 0 : nsGlobalWindow::GetURL(nsIDOMMozURLProperty** aURL)
10299 : {
10300 0 : FORWARD_TO_INNER(GetURL, (aURL), NS_ERROR_UNEXPECTED);
10301 :
10302 0 : if (!mURLProperty) {
10303 0 : mURLProperty = new nsDOMMozURLProperty(this);
10304 : }
10305 :
10306 0 : NS_ADDREF(*aURL = mURLProperty);
10307 :
10308 0 : return NS_OK;
10309 : }
10310 :
10311 : // static
10312 : bool
10313 612 : nsGlobalWindow::HasIndexedDBSupport()
10314 : {
10315 612 : return Preferences::GetBool("indexedDB.feature.enabled", true);
10316 : }
10317 :
10318 : // static
10319 : bool
10320 1836 : nsGlobalWindow::HasPerformanceSupport()
10321 : {
10322 1836 : return Preferences::GetBool("dom.enable_performance", false);
10323 : }
10324 :
10325 : void
10326 0 : nsGlobalWindow::SizeOfIncludingThis(nsWindowSizes* aWindowSizes) const
10327 : {
10328 0 : aWindowSizes->mDOM += aWindowSizes->mMallocSizeOf(this);
10329 :
10330 0 : if (IsInnerWindow()) {
10331 : nsEventListenerManager* elm =
10332 0 : const_cast<nsGlobalWindow*>(this)->GetListenerManager(false);
10333 0 : if (elm) {
10334 : aWindowSizes->mDOM +=
10335 0 : elm->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
10336 : }
10337 0 : if (mDoc) {
10338 0 : mDoc->DocSizeOfIncludingThis(aWindowSizes);
10339 : }
10340 : }
10341 :
10342 : aWindowSizes->mDOM +=
10343 : mNavigator ?
10344 0 : mNavigator->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf) : 0;
10345 0 : }
10346 :
10347 : // nsGlobalChromeWindow implementation
10348 :
10349 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
10350 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
10351 : nsGlobalWindow)
10352 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBrowserDOMWindow)
10353 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMessageManager)
10354 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
10355 :
10356 :
10357 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalChromeWindow,
10358 : nsGlobalWindow)
10359 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mBrowserDOMWindow)
10360 0 : if (tmp->mMessageManager) {
10361 : static_cast<nsFrameMessageManager*>(
10362 0 : tmp->mMessageManager.get())->Disconnect();
10363 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mMessageManager)
10364 : }
10365 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
10366 :
10367 : DOMCI_DATA(ChromeWindow, nsGlobalChromeWindow)
10368 :
10369 : // QueryInterface implementation for nsGlobalChromeWindow
10370 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow)
10371 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)
10372 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ChromeWindow)
10373 0 : NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
10374 :
10375 0 : NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
10376 0 : NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
10377 :
10378 : NS_IMETHODIMP
10379 0 : nsGlobalChromeWindow::GetWindowState(PRUint16* aWindowState)
10380 : {
10381 0 : *aWindowState = nsIDOMChromeWindow::STATE_NORMAL;
10382 :
10383 0 : nsCOMPtr<nsIWidget> widget = GetMainWidget();
10384 :
10385 0 : PRInt32 aMode = 0;
10386 :
10387 0 : if (widget) {
10388 0 : nsresult rv = widget->GetSizeMode(&aMode);
10389 0 : NS_ENSURE_SUCCESS(rv, rv);
10390 : }
10391 :
10392 0 : switch (aMode) {
10393 : case nsSizeMode_Minimized:
10394 0 : *aWindowState = nsIDOMChromeWindow::STATE_MINIMIZED;
10395 0 : break;
10396 : case nsSizeMode_Maximized:
10397 0 : *aWindowState = nsIDOMChromeWindow::STATE_MAXIMIZED;
10398 0 : break;
10399 : case nsSizeMode_Fullscreen:
10400 0 : *aWindowState = nsIDOMChromeWindow::STATE_FULLSCREEN;
10401 0 : break;
10402 : case nsSizeMode_Normal:
10403 0 : *aWindowState = nsIDOMChromeWindow::STATE_NORMAL;
10404 0 : break;
10405 : default:
10406 0 : NS_WARNING("Illegal window state for this chrome window");
10407 0 : break;
10408 : }
10409 :
10410 0 : return NS_OK;
10411 : }
10412 :
10413 : NS_IMETHODIMP
10414 0 : nsGlobalChromeWindow::Maximize()
10415 : {
10416 0 : nsCOMPtr<nsIWidget> widget = GetMainWidget();
10417 0 : nsresult rv = NS_OK;
10418 :
10419 0 : if (widget) {
10420 0 : rv = widget->SetSizeMode(nsSizeMode_Maximized);
10421 : }
10422 :
10423 0 : return rv;
10424 : }
10425 :
10426 : NS_IMETHODIMP
10427 0 : nsGlobalChromeWindow::Minimize()
10428 : {
10429 0 : nsCOMPtr<nsIWidget> widget = GetMainWidget();
10430 0 : nsresult rv = NS_OK;
10431 :
10432 0 : if (widget)
10433 0 : rv = widget->SetSizeMode(nsSizeMode_Minimized);
10434 :
10435 0 : return rv;
10436 : }
10437 :
10438 : NS_IMETHODIMP
10439 0 : nsGlobalChromeWindow::Restore()
10440 : {
10441 0 : nsCOMPtr<nsIWidget> widget = GetMainWidget();
10442 0 : nsresult rv = NS_OK;
10443 :
10444 0 : if (widget) {
10445 0 : rv = widget->SetSizeMode(nsSizeMode_Normal);
10446 : }
10447 :
10448 0 : return rv;
10449 : }
10450 :
10451 : NS_IMETHODIMP
10452 0 : nsGlobalChromeWindow::GetAttention()
10453 : {
10454 0 : return GetAttentionWithCycleCount(-1);
10455 : }
10456 :
10457 : NS_IMETHODIMP
10458 0 : nsGlobalChromeWindow::GetAttentionWithCycleCount(PRInt32 aCycleCount)
10459 : {
10460 0 : nsCOMPtr<nsIWidget> widget = GetMainWidget();
10461 0 : nsresult rv = NS_OK;
10462 :
10463 0 : if (widget) {
10464 0 : rv = widget->GetAttention(aCycleCount);
10465 : }
10466 :
10467 0 : return rv;
10468 : }
10469 :
10470 : NS_IMETHODIMP
10471 0 : nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent, nsIDOMElement* aPanel)
10472 : {
10473 0 : nsCOMPtr<nsIWidget> widget;
10474 :
10475 : // if a panel was supplied, use its widget instead.
10476 : #ifdef MOZ_XUL
10477 0 : if (aPanel) {
10478 0 : nsCOMPtr<nsIContent> panel = do_QueryInterface(aPanel);
10479 0 : NS_ENSURE_TRUE(panel, NS_ERROR_FAILURE);
10480 :
10481 0 : nsIFrame* frame = panel->GetPrimaryFrame();
10482 0 : NS_ENSURE_TRUE(frame && frame->GetType() == nsGkAtoms::menuPopupFrame, NS_OK);
10483 :
10484 0 : widget = (static_cast<nsMenuPopupFrame*>(frame))->GetWidget();
10485 : }
10486 : else {
10487 : #endif
10488 0 : widget = GetMainWidget();
10489 : #ifdef MOZ_XUL
10490 : }
10491 : #endif
10492 :
10493 0 : if (!widget) {
10494 0 : return NS_OK;
10495 : }
10496 :
10497 0 : nsCOMPtr<nsIPrivateDOMEvent> privEvent = do_QueryInterface(aMouseDownEvent);
10498 0 : NS_ENSURE_TRUE(privEvent, NS_ERROR_FAILURE);
10499 0 : nsEvent *internalEvent = privEvent->GetInternalNSEvent();
10500 0 : NS_ENSURE_TRUE(internalEvent &&
10501 : internalEvent->eventStructType == NS_MOUSE_EVENT,
10502 : NS_ERROR_FAILURE);
10503 0 : nsMouseEvent *mouseEvent = static_cast<nsMouseEvent*>(internalEvent);
10504 :
10505 0 : return widget->BeginMoveDrag(mouseEvent);
10506 : }
10507 :
10508 : //Note: This call will lock the cursor, it will not change as it moves.
10509 : //To unlock, the cursor must be set back to CURSOR_AUTO.
10510 : NS_IMETHODIMP
10511 0 : nsGlobalChromeWindow::SetCursor(const nsAString& aCursor)
10512 : {
10513 0 : FORWARD_TO_OUTER_CHROME(SetCursor, (aCursor), NS_ERROR_NOT_INITIALIZED);
10514 :
10515 0 : nsresult rv = NS_OK;
10516 : PRInt32 cursor;
10517 :
10518 : // use C strings to keep the code/data size down
10519 0 : NS_ConvertUTF16toUTF8 cursorString(aCursor);
10520 :
10521 0 : if (cursorString.Equals("auto"))
10522 0 : cursor = NS_STYLE_CURSOR_AUTO;
10523 : else {
10524 0 : nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
10525 0 : if (eCSSKeyword_UNKNOWN == keyword ||
10526 0 : !nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, cursor)) {
10527 : // XXX remove the following three values (leave return NS_OK) after 1.8
10528 : // XXX since they should have been -moz- prefixed (covered by FindKeyword).
10529 : // XXX (also remove |cursorString| at that point?).
10530 0 : if (cursorString.Equals("grab"))
10531 0 : cursor = NS_STYLE_CURSOR_GRAB;
10532 0 : else if (cursorString.Equals("grabbing"))
10533 0 : cursor = NS_STYLE_CURSOR_GRABBING;
10534 0 : else if (cursorString.Equals("spinning"))
10535 0 : cursor = NS_STYLE_CURSOR_SPINNING;
10536 : else
10537 0 : return NS_OK;
10538 : }
10539 : }
10540 :
10541 0 : nsRefPtr<nsPresContext> presContext;
10542 0 : if (mDocShell) {
10543 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
10544 : }
10545 :
10546 0 : if (presContext) {
10547 : // Need root widget.
10548 0 : nsCOMPtr<nsIPresShell> presShell;
10549 0 : mDocShell->GetPresShell(getter_AddRefs(presShell));
10550 0 : NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
10551 :
10552 0 : nsIViewManager* vm = presShell->GetViewManager();
10553 0 : NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
10554 :
10555 0 : nsIView* rootView = vm->GetRootView();
10556 0 : NS_ENSURE_TRUE(rootView, NS_ERROR_FAILURE);
10557 :
10558 0 : nsIWidget* widget = rootView->GetNearestWidget(nsnull);
10559 0 : NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
10560 :
10561 : // Call esm and set cursor.
10562 : rv = presContext->EventStateManager()->SetCursor(cursor, nsnull,
10563 : false, 0.0f, 0.0f,
10564 0 : widget, true);
10565 : }
10566 :
10567 0 : return rv;
10568 : }
10569 :
10570 : NS_IMETHODIMP
10571 0 : nsGlobalChromeWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow)
10572 : {
10573 0 : FORWARD_TO_OUTER_CHROME(GetBrowserDOMWindow, (aBrowserWindow),
10574 : NS_ERROR_NOT_INITIALIZED);
10575 :
10576 0 : NS_ENSURE_ARG_POINTER(aBrowserWindow);
10577 :
10578 0 : *aBrowserWindow = mBrowserDOMWindow;
10579 0 : NS_IF_ADDREF(*aBrowserWindow);
10580 0 : return NS_OK;
10581 : }
10582 :
10583 : NS_IMETHODIMP
10584 0 : nsGlobalChromeWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow *aBrowserWindow)
10585 : {
10586 0 : FORWARD_TO_OUTER_CHROME(SetBrowserDOMWindow, (aBrowserWindow),
10587 : NS_ERROR_NOT_INITIALIZED);
10588 :
10589 0 : mBrowserDOMWindow = aBrowserWindow;
10590 0 : return NS_OK;
10591 : }
10592 :
10593 : NS_IMETHODIMP
10594 0 : nsGlobalChromeWindow::NotifyDefaultButtonLoaded(nsIDOMElement* aDefaultButton)
10595 : {
10596 : #ifdef MOZ_XUL
10597 0 : NS_ENSURE_ARG(aDefaultButton);
10598 :
10599 : // Don't snap to a disabled button.
10600 : nsCOMPtr<nsIDOMXULControlElement> xulControl =
10601 0 : do_QueryInterface(aDefaultButton);
10602 0 : NS_ENSURE_TRUE(xulControl, NS_ERROR_FAILURE);
10603 : bool disabled;
10604 0 : nsresult rv = xulControl->GetDisabled(&disabled);
10605 0 : NS_ENSURE_SUCCESS(rv, rv);
10606 0 : if (disabled)
10607 0 : return NS_OK;
10608 :
10609 : // Get the button rect in screen coordinates.
10610 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aDefaultButton));
10611 0 : NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
10612 0 : nsIFrame *frame = content->GetPrimaryFrame();
10613 0 : NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
10614 0 : nsIntRect buttonRect = frame->GetScreenRect();
10615 :
10616 : // Get the widget rect in screen coordinates.
10617 0 : nsIWidget *widget = GetNearestWidget();
10618 0 : NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
10619 0 : nsIntRect widgetRect;
10620 0 : rv = widget->GetScreenBounds(widgetRect);
10621 0 : NS_ENSURE_SUCCESS(rv, rv);
10622 :
10623 : // Convert the buttonRect coordinates from screen to the widget.
10624 0 : buttonRect -= widgetRect.TopLeft();
10625 0 : rv = widget->OnDefaultButtonLoaded(buttonRect);
10626 0 : if (rv == NS_ERROR_NOT_IMPLEMENTED)
10627 0 : return NS_OK;
10628 0 : return rv;
10629 : #else
10630 : return NS_ERROR_NOT_IMPLEMENTED;
10631 : #endif
10632 : }
10633 :
10634 : NS_IMETHODIMP
10635 0 : nsGlobalChromeWindow::GetMessageManager(nsIChromeFrameMessageManager** aManager)
10636 : {
10637 0 : FORWARD_TO_INNER_CHROME(GetMessageManager, (aManager), NS_ERROR_FAILURE);
10638 0 : if (!mMessageManager) {
10639 0 : nsIScriptContext* scx = GetContextInternal();
10640 0 : NS_ENSURE_STATE(scx);
10641 0 : JSContext* cx = scx->GetNativeContext();
10642 0 : NS_ENSURE_STATE(cx);
10643 : nsCOMPtr<nsIChromeFrameMessageManager> globalMM =
10644 0 : do_GetService("@mozilla.org/globalmessagemanager;1");
10645 : mMessageManager =
10646 : new nsFrameMessageManager(true,
10647 : nsnull,
10648 : nsnull,
10649 : nsnull,
10650 : nsnull,
10651 0 : static_cast<nsFrameMessageManager*>(globalMM.get()),
10652 0 : cx);
10653 0 : NS_ENSURE_TRUE(mMessageManager, NS_ERROR_OUT_OF_MEMORY);
10654 : }
10655 0 : CallQueryInterface(mMessageManager, aManager);
10656 0 : return NS_OK;
10657 : }
10658 :
10659 : // nsGlobalModalWindow implementation
10660 :
10661 : // QueryInterface implementation for nsGlobalModalWindow
10662 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalModalWindow)
10663 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalModalWindow,
10664 : nsGlobalWindow)
10665 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mReturnValue)
10666 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
10667 :
10668 : DOMCI_DATA(ModalContentWindow, nsGlobalModalWindow)
10669 :
10670 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalModalWindow)
10671 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow)
10672 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ModalContentWindow)
10673 0 : NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
10674 :
10675 0 : NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
10676 0 : NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
10677 :
10678 :
10679 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalModalWindow,
10680 : nsGlobalWindow)
10681 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReturnValue)
10682 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
10683 :
10684 :
10685 : NS_IMETHODIMP
10686 0 : nsGlobalModalWindow::GetDialogArguments(nsIArray **aArguments)
10687 : {
10688 0 : FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(GetDialogArguments, (aArguments),
10689 : NS_ERROR_NOT_INITIALIZED);
10690 :
10691 0 : bool subsumes = false;
10692 0 : nsIPrincipal *self = GetPrincipal();
10693 0 : if (self && NS_SUCCEEDED(self->Subsumes(mArgumentsOrigin, &subsumes)) &&
10694 : subsumes) {
10695 0 : NS_IF_ADDREF(*aArguments = mArguments);
10696 : } else {
10697 0 : *aArguments = nsnull;
10698 : }
10699 :
10700 0 : return NS_OK;
10701 : }
10702 :
10703 : NS_IMETHODIMP
10704 0 : nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
10705 : {
10706 0 : FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
10707 :
10708 0 : NS_IF_ADDREF(*aRetVal = mReturnValue);
10709 :
10710 0 : return NS_OK;
10711 : }
10712 :
10713 : NS_IMETHODIMP
10714 0 : nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
10715 : {
10716 0 : FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aRetVal), NS_OK);
10717 :
10718 0 : mReturnValue = aRetVal;
10719 :
10720 0 : return NS_OK;
10721 : }
10722 :
10723 : nsresult
10724 0 : nsGlobalModalWindow::SetNewDocument(nsIDocument *aDocument,
10725 : nsISupports *aState,
10726 : bool aForceReuseInnerWindow)
10727 : {
10728 : // If we're loading a new document into a modal dialog, clear the
10729 : // return value that was set, if any, by the current document.
10730 0 : if (aDocument) {
10731 0 : mReturnValue = nsnull;
10732 : }
10733 :
10734 : return nsGlobalWindow::SetNewDocument(aDocument, aState,
10735 0 : aForceReuseInnerWindow);
10736 : }
10737 :
10738 : void
10739 0 : nsGlobalWindow::SetHasAudioAvailableEventListeners()
10740 : {
10741 0 : if (mDoc) {
10742 0 : mDoc->NotifyAudioAvailableListener();
10743 : }
10744 0 : }
10745 :
10746 : //*****************************************************************************
10747 : // nsGlobalWindow: Creator Function (This should go away)
10748 : //*****************************************************************************
10749 :
10750 : nsresult
10751 0 : NS_NewScriptGlobalObject(bool aIsChrome, bool aIsModalContentWindow,
10752 : nsIScriptGlobalObject **aResult)
10753 : {
10754 0 : *aResult = nsnull;
10755 :
10756 : nsGlobalWindow *global;
10757 :
10758 0 : if (aIsChrome) {
10759 0 : global = new nsGlobalChromeWindow(nsnull);
10760 0 : } else if (aIsModalContentWindow) {
10761 0 : global = new nsGlobalModalWindow(nsnull);
10762 : } else {
10763 0 : global = new nsGlobalWindow(nsnull);
10764 : }
10765 :
10766 0 : NS_ENSURE_TRUE(global, NS_ERROR_OUT_OF_MEMORY);
10767 :
10768 0 : NS_ADDREF(*aResult = global);
10769 :
10770 0 : return NS_OK;
10771 : }
10772 :
10773 : #define EVENT(name_, id_, type_, struct_) \
10774 : NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx, \
10775 : jsval *vp) { \
10776 : nsEventListenerManager *elm = GetListenerManager(false); \
10777 : if (elm) { \
10778 : elm->GetJSEventListener(nsGkAtoms::on##name_, vp); \
10779 : } else { \
10780 : *vp = JSVAL_NULL; \
10781 : } \
10782 : return NS_OK; \
10783 : } \
10784 : NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx, \
10785 : const jsval &v) { \
10786 : nsEventListenerManager *elm = GetListenerManager(true); \
10787 : if (!elm) { \
10788 : return NS_ERROR_OUT_OF_MEMORY; \
10789 : } \
10790 : \
10791 : JSObject *obj = mJSObject; \
10792 : if (!obj) { \
10793 : return NS_ERROR_UNEXPECTED; \
10794 : } \
10795 : return elm->SetJSEventListenerToJsval(nsGkAtoms::on##name_, cx, obj, v); \
10796 : }
10797 : #define WINDOW_ONLY_EVENT EVENT
10798 : #define TOUCH_EVENT EVENT
10799 : #include "nsEventNameList.h"
10800 : #undef TOUCH_EVENT
10801 : #undef WINDOW_ONLY_EVENT
10802 : #undef EVENT
10803 :
|