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