/src/mozilla-central/dom/base/nsGlobalWindowInner.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "nsGlobalWindow.h" |
8 | | |
9 | | #include <algorithm> |
10 | | |
11 | | #include "mozilla/MemoryReporting.h" |
12 | | |
13 | | // Local Includes |
14 | | #include "Navigator.h" |
15 | | #include "nsContentSecurityManager.h" |
16 | | #include "nsScreen.h" |
17 | | #include "nsHistory.h" |
18 | | #include "nsDOMNavigationTiming.h" |
19 | | #include "nsIDOMStorageManager.h" |
20 | | #include "mozilla/AutoplayPermissionManager.h" |
21 | | #include "mozilla/dom/ContentFrameMessageManager.h" |
22 | | #include "mozilla/dom/DOMJSProxyHandler.h" |
23 | | #include "mozilla/dom/DOMPrefs.h" |
24 | | #include "mozilla/dom/EventTarget.h" |
25 | | #include "mozilla/dom/LocalStorage.h" |
26 | | #include "mozilla/dom/Storage.h" |
27 | | #include "mozilla/dom/IdleRequest.h" |
28 | | #include "mozilla/dom/Performance.h" |
29 | | #include "mozilla/dom/StorageEvent.h" |
30 | | #include "mozilla/dom/StorageEventBinding.h" |
31 | | #include "mozilla/dom/StorageNotifierService.h" |
32 | | #include "mozilla/dom/StorageUtils.h" |
33 | | #include "mozilla/dom/Timeout.h" |
34 | | #include "mozilla/dom/TimeoutHandler.h" |
35 | | #include "mozilla/dom/TimeoutManager.h" |
36 | | #include "mozilla/dom/VisualViewport.h" |
37 | | #include "mozilla/IntegerPrintfMacros.h" |
38 | | #if defined(MOZ_WIDGET_ANDROID) |
39 | | #include "mozilla/dom/WindowOrientationObserver.h" |
40 | | #endif |
41 | | #include "nsDOMOfflineResourceList.h" |
42 | | #include "nsError.h" |
43 | | #include "nsIIdleService.h" |
44 | | #include "nsISizeOfEventTarget.h" |
45 | | #include "nsDOMJSUtils.h" |
46 | | #include "nsArrayUtils.h" |
47 | | #include "nsDOMWindowList.h" |
48 | | #include "mozilla/dom/WakeLock.h" |
49 | | #include "mozilla/dom/power/PowerManagerService.h" |
50 | | #include "nsIDocShellTreeOwner.h" |
51 | | #include "nsIDocumentLoader.h" |
52 | | #include "nsIInterfaceRequestorUtils.h" |
53 | | #include "nsIPermission.h" |
54 | | #include "nsIPermissionManager.h" |
55 | | #include "nsIScriptContext.h" |
56 | | #include "nsIScriptTimeoutHandler.h" |
57 | | #include "nsITimeoutHandler.h" |
58 | | #include "nsIController.h" |
59 | | #include "nsISlowScriptDebug.h" |
60 | | #include "nsWindowMemoryReporter.h" |
61 | | #include "nsWindowSizes.h" |
62 | | #include "WindowNamedPropertiesHandler.h" |
63 | | #include "nsFrameSelection.h" |
64 | | #include "nsNetUtil.h" |
65 | | #include "nsVariant.h" |
66 | | #include "nsPrintfCString.h" |
67 | | #include "mozilla/intl/LocaleService.h" |
68 | | #include "WindowDestroyedEvent.h" |
69 | | |
70 | | // Helper Classes |
71 | | #include "nsJSUtils.h" |
72 | | #include "jsapi.h" |
73 | | #include "js/Wrapper.h" |
74 | | #include "nsCharSeparatedTokenizer.h" |
75 | | #include "nsReadableUtils.h" |
76 | | #include "nsJSEnvironment.h" |
77 | | #include "mozilla/dom/ScriptSettings.h" |
78 | | #include "mozilla/Preferences.h" |
79 | | #include "mozilla/Likely.h" |
80 | | #include "mozilla/Sprintf.h" |
81 | | #include "mozilla/Unused.h" |
82 | | |
83 | | // Other Classes |
84 | | #include "mozilla/dom/BarProps.h" |
85 | | #include "nsContentCID.h" |
86 | | #include "nsLayoutStatics.h" |
87 | | #include "nsCCUncollectableMarker.h" |
88 | | #include "mozilla/dom/WorkerCommon.h" |
89 | | #include "mozilla/dom/ToJSValue.h" |
90 | | #include "nsJSPrincipals.h" |
91 | | #include "mozilla/Attributes.h" |
92 | | #include "mozilla/Debug.h" |
93 | | #include "mozilla/EventListenerManager.h" |
94 | | #include "mozilla/EventStates.h" |
95 | | #include "mozilla/MouseEvents.h" |
96 | | #include "mozilla/ProcessHangMonitor.h" |
97 | | #include "mozilla/ThrottledEventQueue.h" |
98 | | #include "AudioChannelService.h" |
99 | | #include "nsAboutProtocolUtils.h" |
100 | | #include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE |
101 | | #include "PostMessageEvent.h" |
102 | | #include "mozilla/dom/DocGroup.h" |
103 | | #include "mozilla/dom/TabGroup.h" |
104 | | #include "mozilla/StaticPrefs.h" |
105 | | |
106 | | // Interfaces Needed |
107 | | #include "nsIFrame.h" |
108 | | #include "nsCanvasFrame.h" |
109 | | #include "nsIWidget.h" |
110 | | #include "nsIWidgetListener.h" |
111 | | #include "nsIBaseWindow.h" |
112 | | #include "nsIDeviceSensors.h" |
113 | | #include "nsIContent.h" |
114 | | #include "nsIDocShell.h" |
115 | | #include "nsIDocument.h" |
116 | | #include "Crypto.h" |
117 | | #include "nsDOMString.h" |
118 | | #include "nsIEmbeddingSiteWindow.h" |
119 | | #include "nsThreadUtils.h" |
120 | | #include "nsILoadContext.h" |
121 | | #include "nsIPresShell.h" |
122 | | #include "nsIScrollableFrame.h" |
123 | | #include "nsView.h" |
124 | | #include "nsViewManager.h" |
125 | | #include "nsISelectionController.h" |
126 | | #include "nsIPrompt.h" |
127 | | #include "nsIPromptService.h" |
128 | | #include "nsIPromptFactory.h" |
129 | | #include "nsIAddonPolicyService.h" |
130 | | #include "nsIWritablePropertyBag2.h" |
131 | | #include "nsIWebNavigation.h" |
132 | | #include "nsIWebBrowserChrome.h" |
133 | | #include "nsIWebBrowserFind.h" // For window.find() |
134 | | #include "nsIWindowMediator.h" // For window.find() |
135 | | #include "nsDOMCID.h" |
136 | | #include "nsDOMWindowUtils.h" |
137 | | #include "nsIWindowWatcher.h" |
138 | | #include "nsPIWindowWatcher.h" |
139 | | #include "nsIContentViewer.h" |
140 | | #include "nsIScriptError.h" |
141 | | #include "nsIControllers.h" |
142 | | #include "nsIControllerContext.h" |
143 | | #include "nsGlobalWindowCommands.h" |
144 | | #include "nsQueryObject.h" |
145 | | #include "nsContentUtils.h" |
146 | | #include "nsCSSProps.h" |
147 | | #include "nsIURIFixup.h" |
148 | | #ifndef DEBUG |
149 | | #include "nsIAppStartup.h" |
150 | | #include "nsToolkitCompsCID.h" |
151 | | #endif |
152 | | #include "nsCDefaultURIFixup.h" |
153 | | #include "mozilla/EventDispatcher.h" |
154 | | #include "mozilla/EventStateManager.h" |
155 | | #include "nsIObserverService.h" |
156 | | #include "nsFocusManager.h" |
157 | | #include "nsIXULWindow.h" |
158 | | #include "nsITimedChannel.h" |
159 | | #include "nsServiceManagerUtils.h" |
160 | | #ifdef MOZ_XUL |
161 | | #include "nsIDOMXULControlElement.h" |
162 | | #include "nsMenuPopupFrame.h" |
163 | | #endif |
164 | | #include "mozilla/dom/CustomEvent.h" |
165 | | #include "nsIJARChannel.h" |
166 | | #include "nsIScreenManager.h" |
167 | | #include "nsIEffectiveTLDService.h" |
168 | | #include "nsICSSDeclaration.h" |
169 | | |
170 | | #include "xpcprivate.h" |
171 | | |
172 | | #ifdef NS_PRINTING |
173 | | #include "nsIPrintSettings.h" |
174 | | #include "nsIPrintSettingsService.h" |
175 | | #include "nsIWebBrowserPrint.h" |
176 | | #endif |
177 | | |
178 | | #include "nsWindowRoot.h" |
179 | | #include "nsNetCID.h" |
180 | | #include "nsIArray.h" |
181 | | |
182 | | #include "nsBindingManager.h" |
183 | | #include "nsXBLService.h" |
184 | | |
185 | | #include "nsIDragService.h" |
186 | | #include "mozilla/dom/Element.h" |
187 | | #include "mozilla/dom/Selection.h" |
188 | | #include "nsFrameLoader.h" |
189 | | #include "nsISupportsPrimitives.h" |
190 | | #include "nsXPCOMCID.h" |
191 | | #include "mozilla/Logging.h" |
192 | | #include "prenv.h" |
193 | | |
194 | | #include "mozilla/dom/IDBFactory.h" |
195 | | #include "mozilla/dom/MessageChannel.h" |
196 | | #include "mozilla/dom/Promise.h" |
197 | | |
198 | | #include "mozilla/dom/Gamepad.h" |
199 | | #include "mozilla/dom/GamepadManager.h" |
200 | | |
201 | | #include "gfxVR.h" |
202 | | #include "mozilla/dom/VRDisplay.h" |
203 | | #include "mozilla/dom/VRDisplayEvent.h" |
204 | | #include "mozilla/dom/VRDisplayEventBinding.h" |
205 | | #include "mozilla/dom/VREventObserver.h" |
206 | | |
207 | | #include "nsRefreshDriver.h" |
208 | | #include "Layers.h" |
209 | | |
210 | | #include "mozilla/BasePrincipal.h" |
211 | | #include "mozilla/Services.h" |
212 | | #include "mozilla/Telemetry.h" |
213 | | #include "mozilla/dom/Location.h" |
214 | | #include "nsHTMLDocument.h" |
215 | | #include "nsWrapperCacheInlines.h" |
216 | | #include "mozilla/DOMEventTargetHelper.h" |
217 | | #include "prrng.h" |
218 | | #include "nsSandboxFlags.h" |
219 | | #include "mozilla/dom/AudioContext.h" |
220 | | #include "mozilla/dom/BrowserElementDictionariesBinding.h" |
221 | | #include "mozilla/dom/cache/CacheStorage.h" |
222 | | #include "mozilla/dom/Console.h" |
223 | | #include "mozilla/dom/Fetch.h" |
224 | | #include "mozilla/dom/FunctionBinding.h" |
225 | | #include "mozilla/dom/HashChangeEvent.h" |
226 | | #include "mozilla/dom/IntlUtils.h" |
227 | | #include "mozilla/dom/PopStateEvent.h" |
228 | | #include "mozilla/dom/PopupBlockedEvent.h" |
229 | | #include "mozilla/dom/PrimitiveConversions.h" |
230 | | #include "mozilla/dom/WindowBinding.h" |
231 | | #include "nsITabChild.h" |
232 | | #include "mozilla/dom/MediaQueryList.h" |
233 | | #include "mozilla/dom/ScriptSettings.h" |
234 | | #include "mozilla/dom/NavigatorBinding.h" |
235 | | #include "mozilla/dom/ImageBitmap.h" |
236 | | #include "mozilla/dom/ImageBitmapBinding.h" |
237 | | #include "mozilla/dom/InstallTriggerBinding.h" |
238 | | #include "mozilla/dom/ServiceWorker.h" |
239 | | #include "mozilla/dom/ServiceWorkerRegistration.h" |
240 | | #include "mozilla/dom/ServiceWorkerRegistrationDescriptor.h" |
241 | | #include "mozilla/dom/U2F.h" |
242 | | #include "mozilla/dom/WebIDLGlobalNameHash.h" |
243 | | #include "mozilla/dom/Worklet.h" |
244 | | #ifdef HAVE_SIDEBAR |
245 | | #include "mozilla/dom/ExternalBinding.h" |
246 | | #endif |
247 | | |
248 | | #ifdef MOZ_WEBSPEECH |
249 | | #include "mozilla/dom/SpeechSynthesis.h" |
250 | | #endif |
251 | | |
252 | | #include "mozilla/dom/ClientManager.h" |
253 | | #include "mozilla/dom/ClientSource.h" |
254 | | #include "mozilla/dom/ClientState.h" |
255 | | |
256 | | // Apple system headers seem to have a check() macro. <sigh> |
257 | | #ifdef check |
258 | | class nsIScriptTimeoutHandler; |
259 | | #undef check |
260 | | #endif // check |
261 | | #include "AccessCheck.h" |
262 | | |
263 | | #ifdef ANDROID |
264 | | #include <android/log.h> |
265 | | #endif |
266 | | |
267 | | #ifdef XP_WIN |
268 | | #include <process.h> |
269 | | #define getpid _getpid |
270 | | #else |
271 | | #include <unistd.h> // for getpid() |
272 | | #endif |
273 | | |
274 | | using namespace mozilla; |
275 | | using namespace mozilla::dom; |
276 | | using namespace mozilla::dom::ipc; |
277 | | using mozilla::TimeStamp; |
278 | | using mozilla::TimeDuration; |
279 | | using mozilla::dom::cache::CacheStorage; |
280 | | |
281 | | #define FORWARD_TO_OUTER(method, args, err_rval) \ |
282 | 0 | PR_BEGIN_MACRO \ |
283 | 0 | nsGlobalWindowOuter *outer = GetOuterWindowInternal(); \ |
284 | 0 | if (!HasActiveDocument()) { \ |
285 | 0 | NS_WARNING(outer ? \ |
286 | 0 | "Inner window does not have active document." : \ |
287 | 0 | "No outer window available!"); \ |
288 | 0 | return err_rval; \ |
289 | 0 | } \ |
290 | 0 | return outer->method args; \ |
291 | 0 | PR_END_MACRO |
292 | | |
293 | | #define FORWARD_TO_OUTER_OR_THROW(method, args, errorresult, err_rval) \ |
294 | 0 | PR_BEGIN_MACRO \ |
295 | 0 | nsGlobalWindowOuter *outer = GetOuterWindowInternal(); \ |
296 | 0 | if (MOZ_LIKELY(HasActiveDocument())) { \ |
297 | 0 | return outer->method args; \ |
298 | 0 | } \ |
299 | 0 | if (!outer) { \ |
300 | 0 | NS_WARNING("No outer window available!"); \ |
301 | 0 | errorresult.Throw(NS_ERROR_NOT_INITIALIZED); \ |
302 | 0 | } else { \ |
303 | 0 | errorresult.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO); \ |
304 | 0 | } \ |
305 | 0 | return err_rval; \ |
306 | 0 | PR_END_MACRO |
307 | | |
308 | | #define FORWARD_TO_OUTER_VOID(method, args) \ |
309 | 0 | PR_BEGIN_MACRO \ |
310 | 0 | nsGlobalWindowOuter *outer = GetOuterWindowInternal(); \ |
311 | 0 | if (!HasActiveDocument()) { \ |
312 | 0 | NS_WARNING(outer ? \ |
313 | 0 | "Inner window does not have active document." : \ |
314 | 0 | "No outer window available!"); \ |
315 | 0 | return; \ |
316 | 0 | } \ |
317 | 0 | outer->method args; \ |
318 | 0 | return; \ |
319 | 0 | PR_END_MACRO |
320 | | |
321 | 0 | #define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added" |
322 | 0 | #define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure" |
323 | | |
324 | | // Amount of time allowed between alert/prompt/confirm before enabling |
325 | | // the stop dialog checkbox. |
326 | 0 | #define DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT 3 // 3 sec |
327 | | |
328 | | // Maximum number of successive dialogs before we prompt users to disable |
329 | | // dialogs for this window. |
330 | 0 | #define MAX_SUCCESSIVE_DIALOG_COUNT 5 |
331 | | |
332 | | // Idle fuzz time upper limit |
333 | 0 | #define MAX_IDLE_FUZZ_TIME_MS 90000 |
334 | | |
335 | | // Min idle notification time in seconds. |
336 | 0 | #define MIN_IDLE_NOTIFICATION_TIME_S 1 |
337 | | |
338 | | static LazyLogModule gDOMLeakPRLogInner("DOMLeakInner"); |
339 | | |
340 | | static bool gIdleObserversAPIFuzzTimeDisabled = false; |
341 | | static FILE *gDumpFile = nullptr; |
342 | | |
343 | | nsGlobalWindowInner::InnerWindowByIdTable *nsGlobalWindowInner::sInnerWindowsById = nullptr; |
344 | | |
345 | | bool nsGlobalWindowInner::sDragServiceDisabled = false; |
346 | | bool nsGlobalWindowInner::sMouseDown = false; |
347 | | |
348 | | /** |
349 | | * An indirect observer object that means we don't have to implement nsIObserver |
350 | | * on nsGlobalWindow, where any script could see it. |
351 | | */ |
352 | | class nsGlobalWindowObserver final : public nsIObserver |
353 | | , public nsIInterfaceRequestor |
354 | | , public StorageNotificationObserver |
355 | | { |
356 | | public: |
357 | 0 | explicit nsGlobalWindowObserver(nsGlobalWindowInner* aWindow) : mWindow(aWindow) {} |
358 | | NS_DECL_ISUPPORTS |
359 | | NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) override |
360 | 0 | { |
361 | 0 | if (!mWindow) |
362 | 0 | return NS_OK; |
363 | 0 | return mWindow->Observe(aSubject, aTopic, aData); |
364 | 0 | } |
365 | 0 | void Forget() { mWindow = nullptr; } |
366 | | NS_IMETHOD GetInterface(const nsIID& aIID, void** aResult) override |
367 | 0 | { |
368 | 0 | if (mWindow && aIID.Equals(NS_GET_IID(nsIDOMWindow)) && mWindow) { |
369 | 0 | return mWindow->QueryInterface(aIID, aResult); |
370 | 0 | } |
371 | 0 | return NS_NOINTERFACE; |
372 | 0 | } |
373 | | |
374 | | void |
375 | | ObserveStorageNotification(StorageEvent* aEvent, |
376 | | const char16_t* aStorageType, |
377 | | bool aPrivateBrowsing) override |
378 | 0 | { |
379 | 0 | if (mWindow) { |
380 | 0 | mWindow->ObserveStorageNotification(aEvent, aStorageType, |
381 | 0 | aPrivateBrowsing); |
382 | 0 | } |
383 | 0 | } |
384 | | |
385 | | nsIPrincipal* |
386 | | GetPrincipal() const override |
387 | 0 | { |
388 | 0 | return mWindow ? mWindow->GetPrincipal() : nullptr; |
389 | 0 | } |
390 | | |
391 | | bool |
392 | | IsPrivateBrowsing() const override |
393 | 0 | { |
394 | 0 | return mWindow ? mWindow->IsPrivateBrowsing() : false; |
395 | 0 | } |
396 | | |
397 | | nsIEventTarget* |
398 | | GetEventTarget() const override |
399 | 0 | { |
400 | 0 | return mWindow ? mWindow->EventTargetFor(TaskCategory::Other) : nullptr; |
401 | 0 | } |
402 | | |
403 | | private: |
404 | | ~nsGlobalWindowObserver() = default; |
405 | | |
406 | | // This reference is non-owning and safe because it's cleared by |
407 | | // nsGlobalWindowInner::FreeInnerObjects(). |
408 | | nsGlobalWindowInner* MOZ_NON_OWNING_REF mWindow; |
409 | | }; |
410 | | |
411 | | NS_IMPL_ISUPPORTS(nsGlobalWindowObserver, nsIObserver, nsIInterfaceRequestor) |
412 | | |
413 | | class IdleRequestExecutor; |
414 | | |
415 | | class IdleRequestExecutorTimeoutHandler final : public TimeoutHandler |
416 | | { |
417 | | public: |
418 | | explicit IdleRequestExecutorTimeoutHandler(IdleRequestExecutor* aExecutor) |
419 | | : mExecutor(aExecutor) |
420 | 0 | { |
421 | 0 | } |
422 | | |
423 | | NS_DECL_ISUPPORTS_INHERITED |
424 | | NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IdleRequestExecutorTimeoutHandler, |
425 | | TimeoutHandler) |
426 | | |
427 | | nsresult Call() override; |
428 | | |
429 | | private: |
430 | 0 | ~IdleRequestExecutorTimeoutHandler() override {} |
431 | | RefPtr<IdleRequestExecutor> mExecutor; |
432 | | }; |
433 | | |
434 | | NS_IMPL_CYCLE_COLLECTION_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler, mExecutor) |
435 | | |
436 | | NS_IMPL_ADDREF_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler) |
437 | | NS_IMPL_RELEASE_INHERITED(IdleRequestExecutorTimeoutHandler, TimeoutHandler) |
438 | | |
439 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler) |
440 | 0 | NS_INTERFACE_MAP_END_INHERITING(TimeoutHandler) |
441 | | |
442 | | |
443 | | class IdleRequestExecutor final : public nsIRunnable |
444 | | , public nsICancelableRunnable |
445 | | , public nsINamed |
446 | | , public nsIIdleRunnable |
447 | | { |
448 | | public: |
449 | | explicit IdleRequestExecutor(nsGlobalWindowInner* aWindow) |
450 | | : mDispatched(false) |
451 | | , mDeadline(TimeStamp::Now()) |
452 | | , mWindow(aWindow) |
453 | 0 | { |
454 | 0 | MOZ_DIAGNOSTIC_ASSERT(mWindow); |
455 | 0 |
|
456 | 0 | mIdlePeriodLimit = { mDeadline, mWindow->LastIdleRequestHandle() }; |
457 | 0 | mDelayedExecutorDispatcher = new IdleRequestExecutorTimeoutHandler(this); |
458 | 0 | } |
459 | | |
460 | | NS_DECL_CYCLE_COLLECTING_ISUPPORTS |
461 | | NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequestExecutor, nsIRunnable) |
462 | | |
463 | | NS_DECL_NSIRUNNABLE |
464 | | NS_DECL_NSINAMED |
465 | | nsresult Cancel() override; |
466 | | void SetDeadline(TimeStamp aDeadline) override; |
467 | | |
468 | 0 | bool IsCancelled() const { return !mWindow || mWindow->IsDying(); } |
469 | | // Checks if aRequest shouldn't execute in the current idle period |
470 | | // since it has been queued from a chained call to |
471 | | // requestIdleCallback from within a running idle callback. |
472 | | bool IneligibleForCurrentIdlePeriod(IdleRequest* aRequest) const |
473 | 0 | { |
474 | 0 | return aRequest->Handle() >= mIdlePeriodLimit.mLastRequestIdInIdlePeriod && |
475 | 0 | TimeStamp::Now() <= mIdlePeriodLimit.mEndOfIdlePeriod; |
476 | 0 | } |
477 | | |
478 | | void MaybeUpdateIdlePeriodLimit(); |
479 | | |
480 | | // Maybe dispatch the IdleRequestExecutor. MabyeDispatch will |
481 | | // schedule a delayed dispatch if the associated window is in the |
482 | | // background or if given a time to wait until dispatching. |
483 | | void MaybeDispatch(TimeStamp aDelayUntil = TimeStamp()); |
484 | | void ScheduleDispatch(); |
485 | | private: |
486 | | struct IdlePeriodLimit |
487 | | { |
488 | | TimeStamp mEndOfIdlePeriod; |
489 | | uint32_t mLastRequestIdInIdlePeriod; |
490 | | }; |
491 | | |
492 | | void DelayedDispatch(uint32_t aDelay); |
493 | | |
494 | 0 | ~IdleRequestExecutor() override {} |
495 | | |
496 | | bool mDispatched; |
497 | | TimeStamp mDeadline; |
498 | | IdlePeriodLimit mIdlePeriodLimit; |
499 | | RefPtr<nsGlobalWindowInner> mWindow; |
500 | | // The timeout handler responsible for dispatching this executor in |
501 | | // the case of immediate dispatch to the idle queue isn't |
502 | | // desirable. This is used if we've dispatched all idle callbacks |
503 | | // that are allowed to run in the current idle period, or if the |
504 | | // associated window is currently in the background. |
505 | | nsCOMPtr<nsITimeoutHandler> mDelayedExecutorDispatcher; |
506 | | // If not Nothing() then this value is the handle to the currently |
507 | | // scheduled delayed executor dispatcher. This is needed to be able |
508 | | // to cancel the timeout handler in case of the executor being |
509 | | // cancelled. |
510 | | Maybe<int32_t> mDelayedExecutorHandle; |
511 | | }; |
512 | | |
513 | | NS_IMPL_CYCLE_COLLECTION_CLASS(IdleRequestExecutor) |
514 | | |
515 | | NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutor) |
516 | | NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutor) |
517 | | |
518 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IdleRequestExecutor) |
519 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) |
520 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mDelayedExecutorDispatcher) |
521 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
522 | | |
523 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IdleRequestExecutor) |
524 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) |
525 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDelayedExecutorDispatcher) |
526 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
527 | | |
528 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutor) |
529 | 0 | NS_INTERFACE_MAP_ENTRY(nsIRunnable) |
530 | 0 | NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable) |
531 | 0 | NS_INTERFACE_MAP_ENTRY(nsINamed) |
532 | 0 | NS_INTERFACE_MAP_ENTRY(nsIIdleRunnable) |
533 | 0 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRunnable) |
534 | 0 | NS_INTERFACE_MAP_END |
535 | | |
536 | | NS_IMETHODIMP |
537 | | IdleRequestExecutor::GetName(nsACString& aName) |
538 | 0 | { |
539 | 0 | aName.AssignLiteral("IdleRequestExecutor"); |
540 | 0 | return NS_OK; |
541 | 0 | } |
542 | | |
543 | | NS_IMETHODIMP |
544 | | IdleRequestExecutor::Run() |
545 | 0 | { |
546 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
547 | 0 |
|
548 | 0 | mDispatched = false; |
549 | 0 | if (mWindow) { |
550 | 0 | return mWindow->ExecuteIdleRequest(mDeadline); |
551 | 0 | } |
552 | 0 | |
553 | 0 | return NS_OK; |
554 | 0 | } |
555 | | |
556 | | nsresult |
557 | | IdleRequestExecutor::Cancel() |
558 | 0 | { |
559 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
560 | 0 |
|
561 | 0 | if (mDelayedExecutorHandle && mWindow) { |
562 | 0 | mWindow->TimeoutManager().ClearTimeout( |
563 | 0 | mDelayedExecutorHandle.value(), |
564 | 0 | Timeout::Reason::eIdleCallbackTimeout); |
565 | 0 | } |
566 | 0 |
|
567 | 0 | mWindow = nullptr; |
568 | 0 | return NS_OK; |
569 | 0 | } |
570 | | |
571 | | void |
572 | | IdleRequestExecutor::SetDeadline(TimeStamp aDeadline) |
573 | 0 | { |
574 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
575 | 0 |
|
576 | 0 | if (!mWindow) { |
577 | 0 | return; |
578 | 0 | } |
579 | 0 | |
580 | 0 | mDeadline = aDeadline; |
581 | 0 | } |
582 | | |
583 | | void |
584 | | IdleRequestExecutor::MaybeUpdateIdlePeriodLimit() |
585 | 0 | { |
586 | 0 | if (TimeStamp::Now() > mIdlePeriodLimit.mEndOfIdlePeriod) { |
587 | 0 | mIdlePeriodLimit = { mDeadline, mWindow->LastIdleRequestHandle() }; |
588 | 0 | } |
589 | 0 | } |
590 | | |
591 | | void |
592 | | IdleRequestExecutor::MaybeDispatch(TimeStamp aDelayUntil) |
593 | 0 | { |
594 | 0 | // If we've already dispatched the executor we don't want to do it |
595 | 0 | // again. Also, if we've called IdleRequestExecutor::Cancel mWindow |
596 | 0 | // will be null, which indicates that we shouldn't dispatch this |
597 | 0 | // executor either. |
598 | 0 | if (mDispatched || IsCancelled()) { |
599 | 0 | return; |
600 | 0 | } |
601 | 0 | |
602 | 0 | mDispatched = true; |
603 | 0 |
|
604 | 0 | nsPIDOMWindowOuter* outer = mWindow->GetOuterWindow(); |
605 | 0 | if (outer && outer->AsOuter()->IsBackground()) { |
606 | 0 | // Set a timeout handler with a timeout of 0 ms to throttle idle |
607 | 0 | // callback requests coming from a backround window using |
608 | 0 | // background timeout throttling. |
609 | 0 | DelayedDispatch(0); |
610 | 0 | return; |
611 | 0 | } |
612 | 0 | |
613 | 0 | TimeStamp now = TimeStamp::Now(); |
614 | 0 | if (!aDelayUntil || aDelayUntil < now) { |
615 | 0 | ScheduleDispatch(); |
616 | 0 | return; |
617 | 0 | } |
618 | 0 | |
619 | 0 | TimeDuration delay = aDelayUntil - now; |
620 | 0 | DelayedDispatch(static_cast<uint32_t>(delay.ToMilliseconds())); |
621 | 0 | } |
622 | | |
623 | | void |
624 | | IdleRequestExecutor::ScheduleDispatch() |
625 | 0 | { |
626 | 0 | MOZ_ASSERT(mWindow); |
627 | 0 | mDelayedExecutorHandle = Nothing(); |
628 | 0 | RefPtr<IdleRequestExecutor> request = this; |
629 | 0 | NS_IdleDispatchToCurrentThread(request.forget()); |
630 | 0 | } |
631 | | |
632 | | void |
633 | | IdleRequestExecutor::DelayedDispatch(uint32_t aDelay) |
634 | 0 | { |
635 | 0 | MOZ_ASSERT(mWindow); |
636 | 0 | MOZ_ASSERT(mDelayedExecutorHandle.isNothing()); |
637 | 0 | int32_t handle; |
638 | 0 | mWindow->TimeoutManager().SetTimeout( |
639 | 0 | mDelayedExecutorDispatcher, aDelay, false, Timeout::Reason::eIdleCallbackTimeout, &handle); |
640 | 0 | mDelayedExecutorHandle = Some(handle); |
641 | 0 | } |
642 | | |
643 | | nsresult |
644 | | IdleRequestExecutorTimeoutHandler::Call() |
645 | 0 | { |
646 | 0 | if (!mExecutor->IsCancelled()) { |
647 | 0 | mExecutor->ScheduleDispatch(); |
648 | 0 | } |
649 | 0 | return NS_OK; |
650 | 0 | } |
651 | | |
652 | | void |
653 | | nsGlobalWindowInner::ScheduleIdleRequestDispatch() |
654 | 0 | { |
655 | 0 | AssertIsOnMainThread(); |
656 | 0 |
|
657 | 0 | if (!mIdleRequestExecutor) { |
658 | 0 | mIdleRequestExecutor = new IdleRequestExecutor(this); |
659 | 0 | } |
660 | 0 |
|
661 | 0 | mIdleRequestExecutor->MaybeDispatch(); |
662 | 0 | } |
663 | | |
664 | | void |
665 | | nsGlobalWindowInner::SuspendIdleRequests() |
666 | 0 | { |
667 | 0 | if (mIdleRequestExecutor) { |
668 | 0 | mIdleRequestExecutor->Cancel(); |
669 | 0 | mIdleRequestExecutor = nullptr; |
670 | 0 | } |
671 | 0 | } |
672 | | |
673 | | void |
674 | | nsGlobalWindowInner::ResumeIdleRequests() |
675 | 0 | { |
676 | 0 | MOZ_ASSERT(!mIdleRequestExecutor); |
677 | 0 |
|
678 | 0 | ScheduleIdleRequestDispatch(); |
679 | 0 | } |
680 | | |
681 | | void |
682 | | nsGlobalWindowInner::RemoveIdleCallback(mozilla::dom::IdleRequest* aRequest) |
683 | 0 | { |
684 | 0 | AssertIsOnMainThread(); |
685 | 0 |
|
686 | 0 | if (aRequest->HasTimeout()) { |
687 | 0 | mTimeoutManager->ClearTimeout(aRequest->GetTimeoutHandle(), |
688 | 0 | Timeout::Reason::eIdleCallbackTimeout); |
689 | 0 | } |
690 | 0 |
|
691 | 0 | aRequest->removeFrom(mIdleRequestCallbacks); |
692 | 0 | } |
693 | | |
694 | | nsresult |
695 | | nsGlobalWindowInner::RunIdleRequest(IdleRequest* aRequest, |
696 | | DOMHighResTimeStamp aDeadline, |
697 | | bool aDidTimeout) |
698 | 0 | { |
699 | 0 | AssertIsOnMainThread(); |
700 | 0 | RefPtr<IdleRequest> request(aRequest); |
701 | 0 | RemoveIdleCallback(request); |
702 | 0 | return request->IdleRun(this, aDeadline, aDidTimeout); |
703 | 0 | } |
704 | | |
705 | | nsresult |
706 | | nsGlobalWindowInner::ExecuteIdleRequest(TimeStamp aDeadline) |
707 | 0 | { |
708 | 0 | AssertIsOnMainThread(); |
709 | 0 | RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst(); |
710 | 0 |
|
711 | 0 | if (!request) { |
712 | 0 | // There are no more idle requests, so stop scheduling idle |
713 | 0 | // request callbacks. |
714 | 0 | return NS_OK; |
715 | 0 | } |
716 | 0 | |
717 | 0 | // If the request that we're trying to execute has been queued |
718 | 0 | // during the current idle period, then dispatch it again at the end |
719 | 0 | // of the idle period. |
720 | 0 | if (mIdleRequestExecutor->IneligibleForCurrentIdlePeriod(request)) { |
721 | 0 | mIdleRequestExecutor->MaybeDispatch(aDeadline); |
722 | 0 | return NS_OK; |
723 | 0 | } |
724 | 0 | |
725 | 0 | DOMHighResTimeStamp deadline = 0.0; |
726 | 0 |
|
727 | 0 | if (Performance* perf = GetPerformance()) { |
728 | 0 | deadline = perf->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline); |
729 | 0 | } |
730 | 0 |
|
731 | 0 | mIdleRequestExecutor->MaybeUpdateIdlePeriodLimit(); |
732 | 0 | nsresult result = RunIdleRequest(request, deadline, false); |
733 | 0 |
|
734 | 0 | // Running the idle callback could've suspended the window, in which |
735 | 0 | // case mIdleRequestExecutor will be null. |
736 | 0 | if (mIdleRequestExecutor) { |
737 | 0 | mIdleRequestExecutor->MaybeDispatch(); |
738 | 0 | } |
739 | 0 | return result; |
740 | 0 | } |
741 | | |
742 | | class IdleRequestTimeoutHandler final : public TimeoutHandler |
743 | | { |
744 | | public: |
745 | | IdleRequestTimeoutHandler(JSContext* aCx, |
746 | | IdleRequest* aIdleRequest, |
747 | | nsPIDOMWindowInner* aWindow) |
748 | | : TimeoutHandler(aCx) |
749 | | , mIdleRequest(aIdleRequest) |
750 | | , mWindow(aWindow) |
751 | 0 | { |
752 | 0 | } |
753 | | |
754 | | NS_DECL_ISUPPORTS_INHERITED |
755 | | NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IdleRequestTimeoutHandler, |
756 | | TimeoutHandler) |
757 | | |
758 | | nsresult Call() override |
759 | 0 | { |
760 | 0 | return nsGlobalWindowInner::Cast(mWindow)->RunIdleRequest(mIdleRequest, 0.0, true); |
761 | 0 | } |
762 | | |
763 | | private: |
764 | 0 | ~IdleRequestTimeoutHandler() override {} |
765 | | |
766 | | RefPtr<IdleRequest> mIdleRequest; |
767 | | nsCOMPtr<nsPIDOMWindowInner> mWindow; |
768 | | }; |
769 | | |
770 | | NS_IMPL_CYCLE_COLLECTION_INHERITED(IdleRequestTimeoutHandler, |
771 | | TimeoutHandler, |
772 | | mIdleRequest, |
773 | | mWindow) |
774 | | |
775 | | NS_IMPL_ADDREF_INHERITED(IdleRequestTimeoutHandler, TimeoutHandler) |
776 | | NS_IMPL_RELEASE_INHERITED(IdleRequestTimeoutHandler, TimeoutHandler) |
777 | | |
778 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestTimeoutHandler) |
779 | 0 | NS_INTERFACE_MAP_END_INHERITING(TimeoutHandler) |
780 | | |
781 | | uint32_t |
782 | | nsGlobalWindowInner::RequestIdleCallback(JSContext* aCx, |
783 | | IdleRequestCallback& aCallback, |
784 | | const IdleRequestOptions& aOptions, |
785 | | ErrorResult& aError) |
786 | 0 | { |
787 | 0 | AssertIsOnMainThread(); |
788 | 0 |
|
789 | 0 | if (IsDying()) { |
790 | 0 | return 0; |
791 | 0 | } |
792 | 0 | |
793 | 0 | uint32_t handle = mIdleRequestCallbackCounter++; |
794 | 0 |
|
795 | 0 | RefPtr<IdleRequest> request = |
796 | 0 | new IdleRequest(&aCallback, handle); |
797 | 0 |
|
798 | 0 | if (aOptions.mTimeout.WasPassed()) { |
799 | 0 | int32_t timeoutHandle; |
800 | 0 | nsCOMPtr<nsITimeoutHandler> handler(new IdleRequestTimeoutHandler(aCx, request, this)); |
801 | 0 |
|
802 | 0 | nsresult rv = mTimeoutManager->SetTimeout( |
803 | 0 | handler, aOptions.mTimeout.Value(), false, |
804 | 0 | Timeout::Reason::eIdleCallbackTimeout, &timeoutHandle); |
805 | 0 |
|
806 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
807 | 0 | return 0; |
808 | 0 | } |
809 | 0 | |
810 | 0 | request->SetTimeoutHandle(timeoutHandle); |
811 | 0 | } |
812 | 0 |
|
813 | 0 | mIdleRequestCallbacks.insertBack(request); |
814 | 0 |
|
815 | 0 | if (!IsSuspended()) { |
816 | 0 | ScheduleIdleRequestDispatch(); |
817 | 0 | } |
818 | 0 |
|
819 | 0 | return handle; |
820 | 0 | } |
821 | | |
822 | | void |
823 | | nsGlobalWindowInner::CancelIdleCallback(uint32_t aHandle) |
824 | 0 | { |
825 | 0 | for (IdleRequest* r : mIdleRequestCallbacks) { |
826 | 0 | if (r->Handle() == aHandle) { |
827 | 0 | RemoveIdleCallback(r); |
828 | 0 | break; |
829 | 0 | } |
830 | 0 | } |
831 | 0 | } |
832 | | |
833 | | void |
834 | | nsGlobalWindowInner::DisableIdleCallbackRequests() |
835 | 0 | { |
836 | 0 | if (mIdleRequestExecutor) { |
837 | 0 | mIdleRequestExecutor->Cancel(); |
838 | 0 | mIdleRequestExecutor = nullptr; |
839 | 0 | } |
840 | 0 |
|
841 | 0 | while (!mIdleRequestCallbacks.isEmpty()) { |
842 | 0 | RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst(); |
843 | 0 | RemoveIdleCallback(request); |
844 | 0 | } |
845 | 0 | } |
846 | | |
847 | | bool |
848 | | nsGlobalWindowInner::IsBackgroundInternal() const |
849 | 0 | { |
850 | 0 | return !mOuterWindow || mOuterWindow->IsBackground(); |
851 | 0 | } |
852 | | |
853 | | class PromiseDocumentFlushedResolver final { |
854 | | public: |
855 | | PromiseDocumentFlushedResolver(Promise* aPromise, |
856 | | PromiseDocumentFlushedCallback& aCallback) |
857 | | : mPromise(aPromise) |
858 | | , mCallback(&aCallback) |
859 | 0 | { |
860 | 0 | } |
861 | | |
862 | 0 | virtual ~PromiseDocumentFlushedResolver() = default; |
863 | | |
864 | | void Call() |
865 | 0 | { |
866 | 0 | ErrorResult error; |
867 | 0 | JS::Rooted<JS::Value> returnVal(RootingCx()); |
868 | 0 | mCallback->Call(&returnVal, error); |
869 | 0 |
|
870 | 0 | if (error.Failed()) { |
871 | 0 | mPromise->MaybeReject(error); |
872 | 0 | } else { |
873 | 0 | mPromise->MaybeResolve(returnVal); |
874 | 0 | } |
875 | 0 | } |
876 | | |
877 | | void Cancel() |
878 | 0 | { |
879 | 0 | mPromise->MaybeReject(NS_ERROR_ABORT); |
880 | 0 | } |
881 | | |
882 | | RefPtr<Promise> mPromise; |
883 | | RefPtr<PromiseDocumentFlushedCallback> mCallback; |
884 | | }; |
885 | | |
886 | | //***************************************************************************** |
887 | | //*** nsGlobalWindowInner: Object Management |
888 | | //***************************************************************************** |
889 | | |
890 | | nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter *aOuterWindow) |
891 | | : nsPIDOMWindowInner(aOuterWindow->AsOuter()), |
892 | | mozilla::webgpu::InstanceProvider(this), |
893 | | mIdleFuzzFactor(0), |
894 | | mIdleCallbackIndex(-1), |
895 | | mCurrentlyIdle(false), |
896 | | mAddActiveEventFuzzTime(true), |
897 | | mWasOffline(false), |
898 | | mHasHadSlowScript(false), |
899 | | mNotifyIdleObserversIdleOnThaw(false), |
900 | | mNotifyIdleObserversActiveOnThaw(false), |
901 | | mIsChrome(false), |
902 | | mCleanMessageManager(false), |
903 | | mNeedsFocus(true), |
904 | | mHasFocus(false), |
905 | | mShowFocusRingForContent(false), |
906 | | mFocusByKeyOccurred(false), |
907 | | mHasGamepad(false), |
908 | | mHasVREvents(false), |
909 | | mHasVRDisplayActivateEvents(false), |
910 | | mHasSeenGamepadInput(false), |
911 | | mSuspendDepth(0), |
912 | | mFreezeDepth(0), |
913 | | mFocusMethod(0), |
914 | | mSerial(0), |
915 | | mIdleRequestCallbackCounter(1), |
916 | | mIdleRequestExecutor(nullptr), |
917 | | mDialogAbuseCount(0), |
918 | | mAreDialogsEnabled(true), |
919 | | mObservingDidRefresh(false), |
920 | | mIteratingDocumentFlushedResolvers(false), |
921 | | mCanSkipCCGeneration(0), |
922 | | mBeforeUnloadListenerCount(0) |
923 | 0 | { |
924 | 0 | mIsInnerWindow = true; |
925 | 0 |
|
926 | 0 | AssertIsOnMainThread(); |
927 | 0 | nsLayoutStatics::AddRef(); |
928 | 0 |
|
929 | 0 | // Initialize the PRCList (this). |
930 | 0 | PR_INIT_CLIST(this); |
931 | 0 |
|
932 | 0 | // add this inner window to the outer window list of inners. |
933 | 0 | PR_INSERT_AFTER(this, aOuterWindow); |
934 | 0 |
|
935 | 0 | mTimeoutManager = MakeUnique<dom::TimeoutManager>(*this); |
936 | 0 |
|
937 | 0 | mObserver = new nsGlobalWindowObserver(this); |
938 | 0 | nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); |
939 | 0 | if (os) { |
940 | 0 | // Watch for online/offline status changes so we can fire events. Use |
941 | 0 | // a strong reference. |
942 | 0 | os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC, |
943 | 0 | false); |
944 | 0 |
|
945 | 0 | os->AddObserver(mObserver, MEMORY_PRESSURE_OBSERVER_TOPIC, false); |
946 | 0 |
|
947 | 0 | if (aOuterWindow->IsTopLevelWindow()) { |
948 | 0 | os->AddObserver(mObserver, "clear-site-data-reload-needed", false); |
949 | 0 | } |
950 | 0 | } |
951 | 0 |
|
952 | 0 | Preferences::AddStrongObserver(mObserver, "intl.accept_languages"); |
953 | 0 |
|
954 | 0 | // Watch for storage notifications so we can fire storage events. |
955 | 0 | RefPtr<StorageNotifierService> sns = |
956 | 0 | StorageNotifierService::GetOrCreate(); |
957 | 0 | if (sns) { |
958 | 0 | sns->Register(mObserver); |
959 | 0 | } |
960 | 0 |
|
961 | 0 | if (XRE_IsContentProcess()) { |
962 | 0 | nsCOMPtr<nsIDocShell> docShell = GetDocShell(); |
963 | 0 | if (docShell) { |
964 | 0 | mTabChild = docShell->GetTabChild(); |
965 | 0 | } |
966 | 0 | } |
967 | 0 |
|
968 | 0 | // We could have failed the first time through trying |
969 | 0 | // to create the entropy collector, so we should |
970 | 0 | // try to get one until we succeed. |
971 | 0 |
|
972 | 0 | mSerial = nsContentUtils::InnerOrOuterWindowCreated(); |
973 | 0 |
|
974 | 0 | static bool sFirstTime = true; |
975 | 0 | if (sFirstTime) { |
976 | 0 | sFirstTime = false; |
977 | 0 | TimeoutManager::Initialize(); |
978 | 0 | Preferences::AddBoolVarCache(&gIdleObserversAPIFuzzTimeDisabled, |
979 | 0 | "dom.idle-observers-api.fuzz_time.disabled", |
980 | 0 | false); |
981 | 0 | } |
982 | 0 |
|
983 | 0 | if (gDumpFile == nullptr) { |
984 | 0 | nsAutoCString fname; |
985 | 0 | Preferences::GetCString("browser.dom.window.dump.file", fname); |
986 | 0 | if (!fname.IsEmpty()) { |
987 | 0 | // If this fails to open, Dump() knows to just go to stdout on null. |
988 | 0 | gDumpFile = fopen(fname.get(), "wb+"); |
989 | 0 | } else { |
990 | 0 | gDumpFile = stdout; |
991 | 0 | } |
992 | 0 | } |
993 | 0 |
|
994 | | #ifdef DEBUG |
995 | | if (!PR_GetEnv("MOZ_QUIET")) { |
996 | | printf_stderr("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n", |
997 | | nsContentUtils::GetCurrentInnerOrOuterWindowCount(), |
998 | | static_cast<void*>(ToCanonicalSupports(this)), |
999 | | getpid(), |
1000 | | mSerial, |
1001 | | static_cast<void*>(ToCanonicalSupports(aOuterWindow))); |
1002 | | } |
1003 | | #endif |
1004 | |
|
1005 | 0 | MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug, |
1006 | 0 | ("DOMWINDOW %p created outer=%p", this, aOuterWindow)); |
1007 | 0 |
|
1008 | 0 | // Add ourselves to the inner windows list. |
1009 | 0 | MOZ_ASSERT(sInnerWindowsById, "Inner Windows hash table must be created!"); |
1010 | 0 | MOZ_ASSERT(!sInnerWindowsById->Get(mWindowID), |
1011 | 0 | "This window shouldn't be in the hash table yet!"); |
1012 | 0 | // We seem to see crashes in release builds because of null |sInnerWindowsById|. |
1013 | 0 | if (sInnerWindowsById) { |
1014 | 0 | sInnerWindowsById->Put(mWindowID, this); |
1015 | 0 | } |
1016 | 0 | } |
1017 | | |
1018 | | #ifdef DEBUG |
1019 | | |
1020 | | /* static */ |
1021 | | void |
1022 | | nsGlobalWindowInner::AssertIsOnMainThread() |
1023 | | { |
1024 | | MOZ_ASSERT(NS_IsMainThread()); |
1025 | | } |
1026 | | |
1027 | | #endif // DEBUG |
1028 | | |
1029 | | /* static */ |
1030 | | void |
1031 | | nsGlobalWindowInner::Init() |
1032 | 3 | { |
1033 | 3 | AssertIsOnMainThread(); |
1034 | 3 | |
1035 | 3 | NS_ASSERTION(gDOMLeakPRLogInner, "gDOMLeakPRLogInner should have been initialized!"); |
1036 | 3 | |
1037 | 3 | sInnerWindowsById = new InnerWindowByIdTable(); |
1038 | 3 | } |
1039 | | |
1040 | | nsGlobalWindowInner::~nsGlobalWindowInner() |
1041 | 0 | { |
1042 | 0 | AssertIsOnMainThread(); |
1043 | 0 |
|
1044 | 0 | if (IsChromeWindow()) { |
1045 | 0 | MOZ_ASSERT(mCleanMessageManager, |
1046 | 0 | "chrome windows may always disconnect the msg manager"); |
1047 | 0 |
|
1048 | 0 | DisconnectAndClearGroupMessageManagers(); |
1049 | 0 |
|
1050 | 0 | if (mChromeFields.mMessageManager) { |
1051 | 0 | static_cast<nsFrameMessageManager *>( |
1052 | 0 | mChromeFields.mMessageManager.get())->Disconnect(); |
1053 | 0 | } |
1054 | 0 |
|
1055 | 0 | mCleanMessageManager = false; |
1056 | 0 | } |
1057 | 0 |
|
1058 | 0 | // In most cases this should already have been called, but call it again |
1059 | 0 | // here to catch any corner cases. |
1060 | 0 | FreeInnerObjects(); |
1061 | 0 |
|
1062 | 0 | if (sInnerWindowsById) { |
1063 | 0 | MOZ_ASSERT(sInnerWindowsById->Get(mWindowID), |
1064 | 0 | "This window should be in the hash table"); |
1065 | 0 | sInnerWindowsById->Remove(mWindowID); |
1066 | 0 | } |
1067 | 0 |
|
1068 | 0 | // If AutoplayPermissionManager is going to be destroyed before getting the |
1069 | 0 | // request's result, we would treat it as user deny. |
1070 | 0 | if (mAutoplayPermissionManager) { |
1071 | 0 | mAutoplayPermissionManager->DenyPlayRequestIfExists(); |
1072 | 0 | } |
1073 | 0 |
|
1074 | 0 | nsContentUtils::InnerOrOuterWindowDestroyed(); |
1075 | 0 |
|
1076 | | #ifdef DEBUG |
1077 | | if (!PR_GetEnv("MOZ_QUIET")) { |
1078 | | nsAutoCString url; |
1079 | | if (mLastOpenedURI) { |
1080 | | url = mLastOpenedURI->GetSpecOrDefault(); |
1081 | | |
1082 | | // Data URLs can be very long, so truncate to avoid flooding the log. |
1083 | | const uint32_t maxURLLength = 1000; |
1084 | | if (url.Length() > maxURLLength) { |
1085 | | url.Truncate(maxURLLength); |
1086 | | } |
1087 | | } |
1088 | | |
1089 | | nsGlobalWindowOuter* outer = nsGlobalWindowOuter::Cast(mOuterWindow); |
1090 | | printf_stderr("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = %s]\n", |
1091 | | nsContentUtils::GetCurrentInnerOrOuterWindowCount(), |
1092 | | static_cast<void*>(ToCanonicalSupports(this)), |
1093 | | getpid(), |
1094 | | mSerial, |
1095 | | static_cast<void*>(ToCanonicalSupports(outer)), |
1096 | | url.get()); |
1097 | | } |
1098 | | #endif |
1099 | |
|
1100 | 0 | MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug, ("DOMWINDOW %p destroyed", this)); |
1101 | 0 |
|
1102 | 0 | Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS, |
1103 | 0 | mMutationBits ? 1 : 0); |
1104 | 0 |
|
1105 | 0 | // An inner window is destroyed, pull it out of the outer window's |
1106 | 0 | // list if inner windows. |
1107 | 0 |
|
1108 | 0 | PR_REMOVE_LINK(this); |
1109 | 0 |
|
1110 | 0 | // If our outer window's inner window is this window, null out the |
1111 | 0 | // outer window's reference to this window that's being deleted. |
1112 | 0 | nsGlobalWindowOuter *outer = GetOuterWindowInternal(); |
1113 | 0 | if (outer) { |
1114 | 0 | outer->MaybeClearInnerWindow(this); |
1115 | 0 | } |
1116 | 0 |
|
1117 | 0 | // We don't have to leave the tab group if we are an inner window. |
1118 | 0 |
|
1119 | 0 | nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID); |
1120 | 0 | if (ac) |
1121 | 0 | ac->RemoveWindowAsListener(this); |
1122 | 0 |
|
1123 | 0 | nsLayoutStatics::Release(); |
1124 | 0 | } |
1125 | | |
1126 | | // static |
1127 | | void |
1128 | | nsGlobalWindowInner::ShutDown() |
1129 | 0 | { |
1130 | 0 | AssertIsOnMainThread(); |
1131 | 0 |
|
1132 | 0 | if (gDumpFile && gDumpFile != stdout) { |
1133 | 0 | fclose(gDumpFile); |
1134 | 0 | } |
1135 | 0 | gDumpFile = nullptr; |
1136 | 0 |
|
1137 | 0 | delete sInnerWindowsById; |
1138 | 0 | sInnerWindowsById = nullptr; |
1139 | 0 | } |
1140 | | |
1141 | | // static |
1142 | | void |
1143 | | nsGlobalWindowInner::CleanupCachedXBLHandlers() |
1144 | 0 | { |
1145 | 0 | if (mCachedXBLPrototypeHandlers && |
1146 | 0 | mCachedXBLPrototypeHandlers->Count() > 0) { |
1147 | 0 | mCachedXBLPrototypeHandlers->Clear(); |
1148 | 0 | } |
1149 | 0 | } |
1150 | | |
1151 | | void |
1152 | | nsGlobalWindowInner::FreeInnerObjects() |
1153 | 0 | { |
1154 | 0 | if (IsDying()) { |
1155 | 0 | return; |
1156 | 0 | } |
1157 | 0 | StartDying(); |
1158 | 0 |
|
1159 | 0 | // Make sure that this is called before we null out the document and |
1160 | 0 | // other members that the window destroyed observers could |
1161 | 0 | // re-create. |
1162 | 0 | NotifyDOMWindowDestroyed(this); |
1163 | 0 | if (auto* reporter = nsWindowMemoryReporter::Get()) { |
1164 | 0 | reporter->ObserveDOMWindowDetached(this); |
1165 | 0 | } |
1166 | 0 |
|
1167 | 0 | // Kill all of the workers for this window. |
1168 | 0 | CancelWorkersForWindow(this); |
1169 | 0 |
|
1170 | 0 | if (mTimeoutManager) { |
1171 | 0 | mTimeoutManager->ClearAllTimeouts(); |
1172 | 0 | } |
1173 | 0 |
|
1174 | 0 | if (mIdleTimer) { |
1175 | 0 | mIdleTimer->Cancel(); |
1176 | 0 | mIdleTimer = nullptr; |
1177 | 0 | } |
1178 | 0 |
|
1179 | 0 | mIdleObservers.Clear(); |
1180 | 0 |
|
1181 | 0 | DisableIdleCallbackRequests(); |
1182 | 0 |
|
1183 | 0 | mChromeEventHandler = nullptr; |
1184 | 0 |
|
1185 | 0 | if (mListenerManager) { |
1186 | 0 | mListenerManager->Disconnect(); |
1187 | 0 | mListenerManager = nullptr; |
1188 | 0 | } |
1189 | 0 |
|
1190 | 0 | mHistory = nullptr; |
1191 | 0 |
|
1192 | 0 | if (mNavigator) { |
1193 | 0 | mNavigator->OnNavigation(); |
1194 | 0 | mNavigator->Invalidate(); |
1195 | 0 | mNavigator = nullptr; |
1196 | 0 | } |
1197 | 0 |
|
1198 | 0 | mScreen = nullptr; |
1199 | 0 |
|
1200 | | #if defined(MOZ_WIDGET_ANDROID) |
1201 | | mOrientationChangeObserver = nullptr; |
1202 | | #endif |
1203 | |
|
1204 | 0 | if (mDoc) { |
1205 | 0 | // Remember the document's principal and URI. |
1206 | 0 | mDocumentPrincipal = mDoc->NodePrincipal(); |
1207 | 0 | mDocumentURI = mDoc->GetDocumentURI(); |
1208 | 0 | mDocBaseURI = mDoc->GetDocBaseURI(); |
1209 | 0 |
|
1210 | 0 | while (mDoc->EventHandlingSuppressed()) { |
1211 | 0 | mDoc->UnsuppressEventHandlingAndFireEvents(false); |
1212 | 0 | } |
1213 | 0 |
|
1214 | 0 | if (mObservingDidRefresh) { |
1215 | 0 | nsIPresShell* shell = mDoc->GetShell(); |
1216 | 0 | if (shell) { |
1217 | 0 | Unused << shell->RemovePostRefreshObserver(this); |
1218 | 0 | } |
1219 | 0 | } |
1220 | 0 | } |
1221 | 0 |
|
1222 | 0 | // Remove our reference to the document and the document principal. |
1223 | 0 | mFocusedElement = nullptr; |
1224 | 0 |
|
1225 | 0 | if (mApplicationCache) { |
1226 | 0 | static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect(); |
1227 | 0 | mApplicationCache = nullptr; |
1228 | 0 | } |
1229 | 0 |
|
1230 | 0 | if (mIndexedDB) { |
1231 | 0 | mIndexedDB->DisconnectFromWindow(this); |
1232 | 0 | mIndexedDB = nullptr; |
1233 | 0 | } |
1234 | 0 |
|
1235 | 0 | UnlinkHostObjectURIs(); |
1236 | 0 |
|
1237 | 0 | NotifyWindowIDDestroyed("inner-window-destroyed"); |
1238 | 0 |
|
1239 | 0 | CleanupCachedXBLHandlers(); |
1240 | 0 |
|
1241 | 0 | for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) { |
1242 | 0 | mAudioContexts[i]->Shutdown(); |
1243 | 0 | } |
1244 | 0 | mAudioContexts.Clear(); |
1245 | 0 |
|
1246 | 0 | DisableGamepadUpdates(); |
1247 | 0 | mHasGamepad = false; |
1248 | 0 | mGamepads.Clear(); |
1249 | 0 | DisableVRUpdates(); |
1250 | 0 | mHasVREvents = false; |
1251 | 0 | mHasVRDisplayActivateEvents = false; |
1252 | 0 | mVRDisplays.Clear(); |
1253 | 0 |
|
1254 | 0 | // This breaks a cycle between the window and the ClientSource object. |
1255 | 0 | mClientSource.reset(); |
1256 | 0 |
|
1257 | 0 | if (mTabChild) { |
1258 | 0 | // Remove any remaining listeners, and reset mBeforeUnloadListenerCount. |
1259 | 0 | for (int i = 0; i < mBeforeUnloadListenerCount; ++i) { |
1260 | 0 | mTabChild->BeforeUnloadRemoved(); |
1261 | 0 | } |
1262 | 0 | mBeforeUnloadListenerCount = 0; |
1263 | 0 | } |
1264 | 0 |
|
1265 | 0 | // If we have any promiseDocumentFlushed callbacks, fire them now so |
1266 | 0 | // that the Promises can resolve. |
1267 | 0 | CallDocumentFlushedResolvers(); |
1268 | 0 | mObservingDidRefresh = false; |
1269 | 0 |
|
1270 | 0 | DisconnectEventTargetObjects(); |
1271 | 0 |
|
1272 | 0 | if (mObserver) { |
1273 | 0 | nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); |
1274 | 0 | if (os) { |
1275 | 0 | os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC); |
1276 | 0 | os->RemoveObserver(mObserver, MEMORY_PRESSURE_OBSERVER_TOPIC); |
1277 | 0 |
|
1278 | 0 | if (GetOuterWindowInternal() && |
1279 | 0 | GetOuterWindowInternal()->IsTopLevelWindow()) { |
1280 | 0 | os->RemoveObserver(mObserver, "clear-site-data-reload-needed"); |
1281 | 0 | } |
1282 | 0 | } |
1283 | 0 |
|
1284 | 0 | RefPtr<StorageNotifierService> sns = StorageNotifierService::GetOrCreate(); |
1285 | 0 | if (sns) { |
1286 | 0 | sns->Unregister(mObserver); |
1287 | 0 | } |
1288 | 0 |
|
1289 | 0 | if (mIdleService) { |
1290 | 0 | mIdleService->RemoveIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S); |
1291 | 0 | } |
1292 | 0 |
|
1293 | 0 | Preferences::RemoveObserver(mObserver, "intl.accept_languages"); |
1294 | 0 |
|
1295 | 0 | // Drop its reference to this dying window, in case for some bogus reason |
1296 | 0 | // the object stays around. |
1297 | 0 | mObserver->Forget(); |
1298 | 0 | } |
1299 | 0 |
|
1300 | 0 | mMenubar = nullptr; |
1301 | 0 | mToolbar = nullptr; |
1302 | 0 | mLocationbar = nullptr; |
1303 | 0 | mPersonalbar = nullptr; |
1304 | 0 | mStatusbar = nullptr; |
1305 | 0 | mScrollbars = nullptr; |
1306 | 0 |
|
1307 | 0 | mConsole = nullptr; |
1308 | 0 |
|
1309 | 0 | mPaintWorklet = nullptr; |
1310 | 0 |
|
1311 | 0 | mExternal = nullptr; |
1312 | 0 | mInstallTrigger = nullptr; |
1313 | 0 |
|
1314 | 0 | mPerformance = nullptr; |
1315 | 0 |
|
1316 | 0 | #ifdef MOZ_WEBSPEECH |
1317 | 0 | mSpeechSynthesis = nullptr; |
1318 | 0 | #endif |
1319 | 0 |
|
1320 | 0 | mParentTarget = nullptr; |
1321 | 0 |
|
1322 | 0 | if (mCleanMessageManager) { |
1323 | 0 | MOZ_ASSERT(mIsChrome, "only chrome should have msg manager cleaned"); |
1324 | 0 | if (mChromeFields.mMessageManager) { |
1325 | 0 | mChromeFields.mMessageManager->Disconnect(); |
1326 | 0 | } |
1327 | 0 | } |
1328 | 0 |
|
1329 | 0 | mIntlUtils = nullptr; |
1330 | 0 | } |
1331 | | |
1332 | | //***************************************************************************** |
1333 | | // nsGlobalWindowInner::nsISupports |
1334 | | //***************************************************************************** |
1335 | | |
1336 | | // QueryInterface implementation for nsGlobalWindowInner |
1337 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindowInner) |
1338 | 0 | NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
1339 | 0 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget) |
1340 | 0 | NS_INTERFACE_MAP_ENTRY(nsIDOMWindow) |
1341 | 0 | NS_INTERFACE_MAP_ENTRY(nsIGlobalObject) |
1342 | 0 | NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject) |
1343 | 0 | NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal) |
1344 | 0 | NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget) |
1345 | 0 | NS_INTERFACE_MAP_ENTRY(nsPIDOMWindowInner) |
1346 | 0 | NS_INTERFACE_MAP_ENTRY(mozIDOMWindow) |
1347 | 0 | NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMChromeWindow, IsChromeWindow()) |
1348 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) |
1349 | 0 | NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) |
1350 | 0 | NS_INTERFACE_MAP_END |
1351 | | |
1352 | | |
1353 | | NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindowInner) |
1354 | | NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindowInner) |
1355 | | |
1356 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindowInner) |
1357 | 0 | if (tmp->IsBlackForCC(false)) { |
1358 | 0 | if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) { |
1359 | 0 | return true; |
1360 | 0 | } |
1361 | 0 | tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration; |
1362 | 0 | if (tmp->mCachedXBLPrototypeHandlers) { |
1363 | 0 | for (auto iter = tmp->mCachedXBLPrototypeHandlers->Iter(); |
1364 | 0 | !iter.Done(); |
1365 | 0 | iter.Next()) { |
1366 | 0 | iter.Data().exposeToActiveJS(); |
1367 | 0 | } |
1368 | 0 | } |
1369 | 0 | if (EventListenerManager* elm = tmp->GetExistingListenerManager()) { |
1370 | 0 | elm->MarkForCC(); |
1371 | 0 | } |
1372 | 0 | if (tmp->mTimeoutManager) { |
1373 | 0 | tmp->mTimeoutManager->UnmarkGrayTimers(); |
1374 | 0 | } |
1375 | 0 | return true; |
1376 | 0 | } |
1377 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END |
1378 | 0 |
|
1379 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindowInner) |
1380 | 0 | return tmp->IsBlackForCC(true); |
1381 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END |
1382 | | |
1383 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindowInner) |
1384 | 0 | return tmp->IsBlackForCC(false); |
1385 | 0 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END |
1386 | | |
1387 | | NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindowInner) |
1388 | | |
1389 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner) |
1390 | 0 | if (MOZ_UNLIKELY(cb.WantDebugInfo())) { |
1391 | 0 | char name[512]; |
1392 | 0 | nsAutoCString uri; |
1393 | 0 | if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) { |
1394 | 0 | uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault(); |
1395 | 0 | } |
1396 | 0 | SprintfLiteral(name, "nsGlobalWindowInner # %" PRIu64 " inner %s", tmp->mWindowID, |
1397 | 0 | uri.get()); |
1398 | 0 | cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name); |
1399 | 0 | } else { |
1400 | 0 | NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindowInner, tmp->mRefCnt.get()) |
1401 | 0 | } |
1402 | 0 |
|
1403 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator) |
1404 | 0 |
|
1405 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance) |
1406 | 0 |
|
1407 | 0 | #ifdef MOZ_WEBSPEECH |
1408 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis) |
1409 | 0 | #endif |
1410 | 0 |
|
1411 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow) |
1412 | 0 |
|
1413 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTopInnerWindow) |
1414 | 0 |
|
1415 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager) |
1416 | 0 |
|
1417 | 0 | if (tmp->mTimeoutManager) { |
1418 | 0 | tmp->mTimeoutManager->ForEachUnorderedTimeout([&cb](Timeout* timeout) { |
1419 | 0 | cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(Timeout)); |
1420 | 0 | }); |
1421 | 0 | } |
1422 | 0 |
|
1423 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation) |
1424 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory) |
1425 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements) |
1426 | 0 |
|
1427 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage) |
1428 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage) |
1429 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache) |
1430 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB) |
1431 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal) |
1432 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChild) |
1433 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc) |
1434 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService) |
1435 | 0 |
|
1436 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor) |
1437 | 0 | for (IdleRequest* request : tmp->mIdleRequestCallbacks) { |
1438 | 0 | cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest)); |
1439 | 0 | } |
1440 | 0 |
|
1441 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers) |
1442 | 0 |
|
1443 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClientSource) |
1444 | 0 |
|
1445 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads) |
1446 | 0 |
|
1447 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage) |
1448 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRDisplays) |
1449 | 0 |
|
1450 | 0 | // Traverse stuff from nsPIDOMWindow |
1451 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler) |
1452 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget) |
1453 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedElement) |
1454 | 0 |
|
1455 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar) |
1456 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar) |
1457 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar) |
1458 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar) |
1459 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar) |
1460 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars) |
1461 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto) |
1462 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mU2F) |
1463 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole) |
1464 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPaintWorklet) |
1465 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal) |
1466 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInstallTrigger) |
1467 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntlUtils) |
1468 | 0 |
|
1469 | 0 | tmp->TraverseHostObjectURIs(cb); |
1470 | 0 |
|
1471 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mMessageManager) |
1472 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mGroupMessageManagers) |
1473 | 0 |
|
1474 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingPromises) |
1475 | 0 |
|
1476 | 0 | for (size_t i = 0; i < tmp->mDocumentFlushedResolvers.Length(); i++) { |
1477 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentFlushedResolvers[i]->mPromise); |
1478 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentFlushedResolvers[i]->mCallback); |
1479 | 0 | } |
1480 | 0 |
|
1481 | 0 | static_cast<mozilla::webgpu::InstanceProvider*>(tmp)->CcTraverse(cb); |
1482 | 0 |
|
1483 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
1484 | | |
1485 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner) |
1486 | 0 | tmp->CleanupCachedXBLHandlers(); |
1487 | 0 |
|
1488 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator) |
1489 | 0 |
|
1490 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance) |
1491 | 0 |
|
1492 | 0 |
|
1493 | 0 | #ifdef MOZ_WEBSPEECH |
1494 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis) |
1495 | 0 | #endif |
1496 | 0 |
|
1497 | 0 | if (tmp->mOuterWindow) { |
1498 | 0 | nsGlobalWindowOuter::Cast(tmp->mOuterWindow)-> |
1499 | 0 | MaybeClearInnerWindow(tmp); |
1500 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow) |
1501 | 0 | } |
1502 | 0 |
|
1503 | 0 | if (tmp->mListenerManager) { |
1504 | 0 | tmp->mListenerManager->Disconnect(); |
1505 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager) |
1506 | 0 | } |
1507 | 0 |
|
1508 | 0 | // Here the Timeouts list would've been unlinked, but we rely on |
1509 | 0 | // that Timeout objects have been traced and will remove themselves |
1510 | 0 | // while unlinking. |
1511 | 0 |
|
1512 | 0 | tmp->UpdateTopInnerWindow(); |
1513 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mTopInnerWindow) |
1514 | 0 |
|
1515 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation) |
1516 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory) |
1517 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomElements) |
1518 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage) |
1519 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage) |
1520 | 0 | if (tmp->mApplicationCache) { |
1521 | 0 | static_cast<nsDOMOfflineResourceList*>(tmp->mApplicationCache.get())->Disconnect(); |
1522 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache) |
1523 | 0 | } |
1524 | 0 | if (tmp->mIndexedDB) { |
1525 | 0 | tmp->mIndexedDB->DisconnectFromWindow(tmp); |
1526 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB) |
1527 | 0 | } |
1528 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal) |
1529 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChild) |
1530 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc) |
1531 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService) |
1532 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers) |
1533 | 0 |
|
1534 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads) |
1535 | 0 |
|
1536 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage) |
1537 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mVRDisplays) |
1538 | 0 |
|
1539 | 0 | // Unlink stuff from nsPIDOMWindow |
1540 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler) |
1541 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget) |
1542 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedElement) |
1543 | 0 |
|
1544 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar) |
1545 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar) |
1546 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar) |
1547 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar) |
1548 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar) |
1549 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars) |
1550 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto) |
1551 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mU2F) |
1552 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole) |
1553 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mPaintWorklet) |
1554 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal) |
1555 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mInstallTrigger) |
1556 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils) |
1557 | 0 |
|
1558 | 0 | tmp->UnlinkHostObjectURIs(); |
1559 | 0 |
|
1560 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor) |
1561 | 0 |
|
1562 | 0 | // Here the IdleRequest list would've been unlinked, but we rely on |
1563 | 0 | // that IdleRequest objects have been traced and will remove |
1564 | 0 | // themselves while unlinking. |
1565 | 0 |
|
1566 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mClientSource) |
1567 | 0 |
|
1568 | 0 | if (tmp->IsChromeWindow()) { |
1569 | 0 | if (tmp->mChromeFields.mMessageManager) { |
1570 | 0 | static_cast<nsFrameMessageManager*>( |
1571 | 0 | tmp->mChromeFields.mMessageManager.get())->Disconnect(); |
1572 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mMessageManager) |
1573 | 0 | } |
1574 | 0 | tmp->DisconnectAndClearGroupMessageManagers(); |
1575 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mGroupMessageManagers) |
1576 | 0 | } |
1577 | 0 |
|
1578 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingPromises) |
1579 | 0 | for (size_t i = 0; i < tmp->mDocumentFlushedResolvers.Length(); i++) { |
1580 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentFlushedResolvers[i]->mPromise); |
1581 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentFlushedResolvers[i]->mCallback); |
1582 | 0 | } |
1583 | 0 | tmp->mDocumentFlushedResolvers.Clear(); |
1584 | 0 |
|
1585 | 0 | static_cast<mozilla::webgpu::InstanceProvider*>(tmp)->CcUnlink(); |
1586 | 0 |
|
1587 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER |
1588 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
1589 | | |
1590 | | #ifdef DEBUG |
1591 | | void |
1592 | | nsGlobalWindowInner::RiskyUnlink() |
1593 | | { |
1594 | | NS_CYCLE_COLLECTION_INNERNAME.Unlink(this); |
1595 | | } |
1596 | | #endif |
1597 | | |
1598 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindowInner) |
1599 | 0 | if (tmp->mCachedXBLPrototypeHandlers) { |
1600 | 0 | for (auto iter = tmp->mCachedXBLPrototypeHandlers->Iter(); |
1601 | 0 | !iter.Done(); |
1602 | 0 | iter.Next()) { |
1603 | 0 | aCallbacks.Trace(&iter.Data(), "Cached XBL prototype handler", aClosure); |
1604 | 0 | } |
1605 | 0 | } |
1606 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER |
1607 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_END |
1608 | | |
1609 | | bool |
1610 | | nsGlobalWindowInner::IsBlackForCC(bool aTracingNeeded) |
1611 | 0 | { |
1612 | 0 | if (!nsCCUncollectableMarker::sGeneration) { |
1613 | 0 | return false; |
1614 | 0 | } |
1615 | 0 | |
1616 | 0 | return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) || |
1617 | 0 | HasKnownLiveWrapper()) && |
1618 | 0 | (!aTracingNeeded || |
1619 | 0 | HasNothingToTrace(ToSupports(this))); |
1620 | 0 | } |
1621 | | |
1622 | | //***************************************************************************** |
1623 | | // nsGlobalWindowInner::nsIScriptGlobalObject |
1624 | | //***************************************************************************** |
1625 | | |
1626 | | nsresult |
1627 | | nsGlobalWindowInner::EnsureScriptEnvironment() |
1628 | 0 | { |
1629 | 0 | // NOTE: We can't use FORWARD_TO_OUTER here because we don't want to fail if |
1630 | 0 | // we're called on an inactive inner window. |
1631 | 0 | nsGlobalWindowOuter* outer = GetOuterWindowInternal(); |
1632 | 0 | if (!outer) { |
1633 | 0 | NS_WARNING("No outer window available!"); |
1634 | 0 | return NS_ERROR_FAILURE; |
1635 | 0 | } |
1636 | 0 | return outer->EnsureScriptEnvironment(); |
1637 | 0 | } |
1638 | | |
1639 | | nsIScriptContext * |
1640 | | nsGlobalWindowInner::GetScriptContext() |
1641 | 0 | { |
1642 | 0 | nsGlobalWindowOuter* outer = GetOuterWindowInternal(); |
1643 | 0 | if (!outer) { |
1644 | 0 | return nullptr; |
1645 | 0 | } |
1646 | 0 | return outer->GetScriptContext(); |
1647 | 0 | } |
1648 | | |
1649 | | JSObject * |
1650 | | nsGlobalWindowInner::GetGlobalJSObject() |
1651 | 0 | { |
1652 | 0 | return FastGetGlobalJSObject(); |
1653 | 0 | } |
1654 | | |
1655 | | void |
1656 | | nsGlobalWindowInner::TraceGlobalJSObject(JSTracer* aTrc) |
1657 | 0 | { |
1658 | 0 | TraceWrapper(aTrc, "active window global"); |
1659 | 0 | } |
1660 | | |
1661 | | PopupControlState |
1662 | | nsGlobalWindowInner::GetPopupControlState() const |
1663 | 0 | { |
1664 | 0 | return nsContentUtils::GetPopupControlState(); |
1665 | 0 | } |
1666 | | |
1667 | | nsresult |
1668 | | nsGlobalWindowInner::SetNewDocument(nsIDocument* aDocument, |
1669 | | nsISupports* aState, |
1670 | | bool aForceReuseInnerWindow) |
1671 | 0 | { |
1672 | 0 | MOZ_ASSERT(mDocumentPrincipal == nullptr, |
1673 | 0 | "mDocumentPrincipal prematurely set!"); |
1674 | 0 | MOZ_ASSERT(aDocument); |
1675 | 0 |
|
1676 | 0 | if (!mOuterWindow) { |
1677 | 0 | return NS_ERROR_NOT_INITIALIZED; |
1678 | 0 | } |
1679 | 0 | |
1680 | 0 | // Refuse to set a new document if the call came from an inner |
1681 | 0 | // window that's not the current inner window. |
1682 | 0 | if (mOuterWindow->GetCurrentInnerWindow() != this) { |
1683 | 0 | return NS_ERROR_NOT_AVAILABLE; |
1684 | 0 | } |
1685 | 0 | |
1686 | 0 | return GetOuterWindowInternal()->SetNewDocument(aDocument, aState, |
1687 | 0 | aForceReuseInnerWindow); |
1688 | 0 | } |
1689 | | |
1690 | | void |
1691 | | nsGlobalWindowInner::InnerSetNewDocument(JSContext* aCx, nsIDocument* aDocument) |
1692 | 0 | { |
1693 | 0 | MOZ_ASSERT(aDocument); |
1694 | 0 |
|
1695 | 0 | if (MOZ_LOG_TEST(gDOMLeakPRLogInner, LogLevel::Debug)) { |
1696 | 0 | nsIURI *uri = aDocument->GetDocumentURI(); |
1697 | 0 | MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug, |
1698 | 0 | ("DOMWINDOW %p SetNewDocument %s", |
1699 | 0 | this, uri ? uri->GetSpecOrDefault().get() : "")); |
1700 | 0 | } |
1701 | 0 |
|
1702 | 0 | mDoc = aDocument; |
1703 | 0 | mFocusedElement = nullptr; |
1704 | 0 | mLocalStorage = nullptr; |
1705 | 0 | mSessionStorage = nullptr; |
1706 | 0 | mPerformance = nullptr; |
1707 | 0 |
|
1708 | 0 | // This must be called after nullifying the internal objects because here we |
1709 | 0 | // could recreate them, calling the getter methods, and store them into the JS |
1710 | 0 | // slots. If we nullify them after, the slot values and the objects will be |
1711 | 0 | // out of sync. |
1712 | 0 | ClearDocumentDependentSlots(aCx); |
1713 | 0 |
|
1714 | | #ifdef DEBUG |
1715 | | mLastOpenedURI = aDocument->GetDocumentURI(); |
1716 | | #endif |
1717 | |
|
1718 | 0 | Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS, |
1719 | 0 | mMutationBits ? 1 : 0); |
1720 | 0 |
|
1721 | 0 | // Clear our mutation bitfield. |
1722 | 0 | mMutationBits = 0; |
1723 | 0 | } |
1724 | | |
1725 | | nsresult |
1726 | | nsGlobalWindowInner::EnsureClientSource() |
1727 | 0 | { |
1728 | 0 | MOZ_DIAGNOSTIC_ASSERT(mDoc); |
1729 | 0 |
|
1730 | 0 | bool newClientSource = false; |
1731 | 0 |
|
1732 | 0 | // Get the load info for the document if we performed a load. Be careful not |
1733 | 0 | // to look at local URLs, though. Local URLs are those that have a scheme of: |
1734 | 0 | // * about: |
1735 | 0 | // * data: |
1736 | 0 | // * blob: |
1737 | 0 | // We also do an additional check here so that we only treat about:blank |
1738 | 0 | // and about:srcdoc as local URLs. Other internal firefox about: URLs should |
1739 | 0 | // not be treated this way. |
1740 | 0 | nsCOMPtr<nsILoadInfo> loadInfo; |
1741 | 0 | nsCOMPtr<nsIChannel> channel = mDoc->GetChannel(); |
1742 | 0 | if (channel) { |
1743 | 0 | nsCOMPtr<nsIURI> uri; |
1744 | 0 | Unused << channel->GetURI(getter_AddRefs(uri)); |
1745 | 0 |
|
1746 | 0 | bool ignoreLoadInfo = false; |
1747 | 0 |
|
1748 | 0 | // Note, this is mostly copied from NS_IsAboutBlank(). Its duplicated |
1749 | 0 | // here so we can efficiently check about:srcdoc as well. |
1750 | 0 | bool isAbout = false; |
1751 | 0 | if (NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) { |
1752 | 0 | nsCString spec = uri->GetSpecOrDefault(); |
1753 | 0 | ignoreLoadInfo = spec.EqualsLiteral("about:blank") || |
1754 | 0 | spec.EqualsLiteral("about:srcdoc"); |
1755 | 0 | } else { |
1756 | 0 | // Its not an about: URL, so now check for our other URL types. |
1757 | 0 | bool isData = false; |
1758 | 0 | bool isBlob = false; |
1759 | 0 | ignoreLoadInfo = (NS_SUCCEEDED(uri->SchemeIs("data", &isData)) && isData) || |
1760 | 0 | (NS_SUCCEEDED(uri->SchemeIs("blob", &isBlob)) && isBlob); |
1761 | 0 | } |
1762 | 0 |
|
1763 | 0 | if (!ignoreLoadInfo) { |
1764 | 0 | loadInfo = channel->GetLoadInfo(); |
1765 | 0 | } |
1766 | 0 | } |
1767 | 0 |
|
1768 | 0 | // Take the initial client source from the docshell immediately. Even if we |
1769 | 0 | // don't end up using it here we should consume it. |
1770 | 0 | UniquePtr<ClientSource> initialClientSource; |
1771 | 0 | nsIDocShell* docshell = GetDocShell(); |
1772 | 0 | if (docshell) { |
1773 | 0 | initialClientSource = docshell->TakeInitialClientSource(); |
1774 | 0 | } |
1775 | 0 |
|
1776 | 0 | // Try to get the reserved client from the LoadInfo. A Client is |
1777 | 0 | // reserved at the start of the channel load if there is not an |
1778 | 0 | // initial about:blank document that will be reused. It is also |
1779 | 0 | // created if the channel load encounters a cross-origin redirect. |
1780 | 0 | if (loadInfo) { |
1781 | 0 | UniquePtr<ClientSource> reservedClient = loadInfo->TakeReservedClientSource(); |
1782 | 0 | if (reservedClient) { |
1783 | 0 | mClientSource.reset(); |
1784 | 0 | mClientSource = std::move(reservedClient); |
1785 | 0 | newClientSource = true; |
1786 | 0 | } |
1787 | 0 | } |
1788 | 0 |
|
1789 | 0 | // We don't have a LoadInfo reserved client, but maybe we should |
1790 | 0 | // be inheriting an initial one from the docshell. This means |
1791 | 0 | // that the docshell started the channel load before creating the |
1792 | 0 | // initial about:blank document. This is an optimization, though, |
1793 | 0 | // and it created an initial Client as a placeholder for the document. |
1794 | 0 | // In this case we want to inherit this placeholder Client here. |
1795 | 0 | if (!mClientSource) { |
1796 | 0 | mClientSource = std::move(initialClientSource); |
1797 | 0 | if (mClientSource) { |
1798 | 0 | newClientSource = true; |
1799 | 0 | } |
1800 | 0 | } |
1801 | 0 |
|
1802 | 0 | // Verify the final ClientSource principal matches the final document |
1803 | 0 | // principal. The ClientChannelHelper handles things like network |
1804 | 0 | // redirects, but there are other ways the document principal can change. |
1805 | 0 | // For example, if something sets the nsIChannel.owner property, then |
1806 | 0 | // the final channel principal can be anything. Unfortunately there is |
1807 | 0 | // no good way to detect this until after the channel completes loading. |
1808 | 0 | // |
1809 | 0 | // For now we handle this just by reseting the ClientSource. This will |
1810 | 0 | // result in a new ClientSource with the correct principal being created. |
1811 | 0 | // To APIs like ServiceWorker and Clients API it will look like there was |
1812 | 0 | // an initial content page created that was then immediately replaced. |
1813 | 0 | // This is pretty close to what we are actually doing. |
1814 | 0 | if (mClientSource) { |
1815 | 0 | nsCOMPtr<nsIPrincipal> clientPrincipal(mClientSource->Info().GetPrincipal()); |
1816 | 0 | if (!clientPrincipal || !clientPrincipal->Equals(mDoc->NodePrincipal())) { |
1817 | 0 | mClientSource.reset(); |
1818 | 0 | } |
1819 | 0 | } |
1820 | 0 |
|
1821 | 0 | // If we don't have a reserved client or an initial client, then create |
1822 | 0 | // one now. This can happen in certain cases where we avoid preallocating |
1823 | 0 | // the client in the docshell. This mainly occurs in situations where |
1824 | 0 | // the principal is not clearly inherited from the parent; e.g. sandboxed |
1825 | 0 | // iframes, window.open(), etc. |
1826 | 0 | // |
1827 | 0 | // We also do this late ClientSource creation if the final document ended |
1828 | 0 | // up with a different principal. |
1829 | 0 | // |
1830 | 0 | // TODO: We may not be marking initial about:blank documents created |
1831 | 0 | // this way as controlled by a service worker properly. The |
1832 | 0 | // controller should be coming from the same place as the inheritted |
1833 | 0 | // principal. We do this in docshell, but as mentioned we aren't |
1834 | 0 | // smart enough to handle all cases yet. For example, a |
1835 | 0 | // window.open() with new URL should inherit the controller from |
1836 | 0 | // the opener, but we probably don't handle that yet. |
1837 | 0 | if (!mClientSource) { |
1838 | 0 | mClientSource = ClientManager::CreateSource(ClientType::Window, |
1839 | 0 | EventTargetFor(TaskCategory::Other), |
1840 | 0 | mDoc->NodePrincipal()); |
1841 | 0 | MOZ_DIAGNOSTIC_ASSERT(mClientSource); |
1842 | 0 | newClientSource = true; |
1843 | 0 |
|
1844 | 0 | // Note, we don't apply the loadinfo controller below if we create |
1845 | 0 | // the ClientSource here. |
1846 | 0 | } |
1847 | 0 | |
1848 | 0 | // The load may have started controlling the Client as well. If |
1849 | 0 | // so, mark it as controlled immediately here. The actor may |
1850 | 0 | // or may not have been notified by the parent side about being |
1851 | 0 | // controlled yet. |
1852 | 0 | // |
1853 | 0 | // Note: We should be careful not to control a client that was created late. |
1854 | 0 | // These clients were not seen by the ServiceWorkerManager when it |
1855 | 0 | // marked the LoadInfo controlled and it won't know about them. Its |
1856 | 0 | // also possible we are creating the client late due to the final |
1857 | 0 | // principal changing and these clients should definitely not be |
1858 | 0 | // controlled by a service worker with a different principal. |
1859 | 0 | else if (loadInfo) { |
1860 | 0 | const Maybe<ServiceWorkerDescriptor> controller = loadInfo->GetController(); |
1861 | 0 | if (controller.isSome()) { |
1862 | 0 | mClientSource->SetController(controller.ref()); |
1863 | 0 | } |
1864 | 0 | |
1865 | 0 | // We also have to handle the case where te initial about:blank is |
1866 | 0 | // controlled due to inheritting the service worker from its parent, |
1867 | 0 | // but the actual nsIChannel load is not covered by any service worker. |
1868 | 0 | // In this case we want the final page to be uncontrolled. There is |
1869 | 0 | // an open spec issue about how exactly this should be handled, but for |
1870 | 0 | // now we just force creation of a new ClientSource to clear the |
1871 | 0 | // controller. |
1872 | 0 | // |
1873 | 0 | // https://github.com/w3c/ServiceWorker/issues/1232 |
1874 | 0 | // |
1875 | 0 | else if (mClientSource->GetController().isSome()) { |
1876 | 0 | mClientSource.reset(); |
1877 | 0 | mClientSource = |
1878 | 0 | ClientManager::CreateSource(ClientType::Window, |
1879 | 0 | EventTargetFor(TaskCategory::Other), |
1880 | 0 | mDoc->NodePrincipal()); |
1881 | 0 | MOZ_DIAGNOSTIC_ASSERT(mClientSource); |
1882 | 0 | newClientSource = true; |
1883 | 0 | } |
1884 | 0 | } |
1885 | 0 |
|
1886 | 0 | // Its possible that we got a client just after being frozen in |
1887 | 0 | // the bfcache. In that case freeze the client immediately. |
1888 | 0 | if (newClientSource && IsFrozen()) { |
1889 | 0 | mClientSource->Freeze(); |
1890 | 0 | } |
1891 | 0 |
|
1892 | 0 | return NS_OK; |
1893 | 0 | } |
1894 | | |
1895 | | nsresult |
1896 | | nsGlobalWindowInner::ExecutionReady() |
1897 | 0 | { |
1898 | 0 | nsresult rv = EnsureClientSource(); |
1899 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1900 | 0 |
|
1901 | 0 | rv = mClientSource->WindowExecutionReady(AsInner()); |
1902 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1903 | 0 |
|
1904 | 0 | return NS_OK; |
1905 | 0 | } |
1906 | | |
1907 | | void |
1908 | | nsGlobalWindowInner::SetOpenerWindow(nsPIDOMWindowOuter* aOpener, |
1909 | | bool aOriginalOpener) |
1910 | 0 | { |
1911 | 0 | FORWARD_TO_OUTER_VOID(SetOpenerWindow, (aOpener, aOriginalOpener)); |
1912 | 0 | } |
1913 | | |
1914 | | void |
1915 | | nsGlobalWindowInner::UpdateParentTarget() |
1916 | 0 | { |
1917 | 0 | // NOTE: This method is identical to |
1918 | 0 | // nsGlobalWindowOuter::UpdateParentTarget(). IF YOU UPDATE THIS METHOD, |
1919 | 0 | // UPDATE THE OTHER ONE TOO! |
1920 | 0 |
|
1921 | 0 | // Try to get our frame element's tab child global (its in-process message |
1922 | 0 | // manager). If that fails, fall back to the chrome event handler's tab |
1923 | 0 | // child global, and if it doesn't have one, just use the chrome event |
1924 | 0 | // handler itself. |
1925 | 0 |
|
1926 | 0 | nsCOMPtr<Element> frameElement = GetOuterWindow()->GetFrameElementInternal(); |
1927 | 0 | nsCOMPtr<EventTarget> eventTarget = |
1928 | 0 | nsContentUtils::TryGetTabChildGlobal(frameElement); |
1929 | 0 |
|
1930 | 0 | if (!eventTarget) { |
1931 | 0 | nsGlobalWindowOuter* topWin = GetScriptableTopInternal(); |
1932 | 0 | if (topWin) { |
1933 | 0 | frameElement = topWin->AsOuter()->GetFrameElementInternal(); |
1934 | 0 | eventTarget = nsContentUtils::TryGetTabChildGlobal(frameElement); |
1935 | 0 | } |
1936 | 0 | } |
1937 | 0 |
|
1938 | 0 | if (!eventTarget) { |
1939 | 0 | eventTarget = nsContentUtils::TryGetTabChildGlobal(mChromeEventHandler); |
1940 | 0 | } |
1941 | 0 |
|
1942 | 0 | if (!eventTarget) { |
1943 | 0 | eventTarget = mChromeEventHandler; |
1944 | 0 | } |
1945 | 0 |
|
1946 | 0 | mParentTarget = eventTarget; |
1947 | 0 | } |
1948 | | |
1949 | | EventTarget* |
1950 | | nsGlobalWindowInner::GetTargetForDOMEvent() |
1951 | 0 | { |
1952 | 0 | return GetOuterWindowInternal(); |
1953 | 0 | } |
1954 | | |
1955 | | void |
1956 | | nsGlobalWindowInner::GetEventTargetParent(EventChainPreVisitor& aVisitor) |
1957 | 0 | { |
1958 | 0 | EventMessage msg = aVisitor.mEvent->mMessage; |
1959 | 0 |
|
1960 | 0 | aVisitor.mCanHandle = true; |
1961 | 0 | aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119 |
1962 | 0 | if (msg == eResize && aVisitor.mEvent->IsTrusted()) { |
1963 | 0 | // QIing to window so that we can keep the old behavior also in case |
1964 | 0 | // a child window is handling resize. |
1965 | 0 | nsCOMPtr<nsPIDOMWindowInner> window = |
1966 | 0 | do_QueryInterface(aVisitor.mEvent->mOriginalTarget); |
1967 | 0 | if (window) { |
1968 | 0 | mIsHandlingResizeEvent = true; |
1969 | 0 | } |
1970 | 0 | } else if (msg == eMouseDown && aVisitor.mEvent->IsTrusted()) { |
1971 | 0 | sMouseDown = true; |
1972 | 0 | } else if ((msg == eMouseUp || msg == eDragEnd) && |
1973 | 0 | aVisitor.mEvent->IsTrusted()) { |
1974 | 0 | sMouseDown = false; |
1975 | 0 | if (sDragServiceDisabled) { |
1976 | 0 | nsCOMPtr<nsIDragService> ds = |
1977 | 0 | do_GetService("@mozilla.org/widget/dragservice;1"); |
1978 | 0 | if (ds) { |
1979 | 0 | sDragServiceDisabled = false; |
1980 | 0 | ds->Unsuppress(); |
1981 | 0 | } |
1982 | 0 | } |
1983 | 0 | } |
1984 | 0 |
|
1985 | 0 | aVisitor.SetParentTarget(GetParentTarget(), true); |
1986 | 0 |
|
1987 | 0 | // Handle 'active' event. |
1988 | 0 | if (!mIdleObservers.IsEmpty() && |
1989 | 0 | aVisitor.mEvent->IsTrusted() && |
1990 | 0 | (aVisitor.mEvent->HasMouseEventMessage() || |
1991 | 0 | aVisitor.mEvent->HasDragEventMessage())) { |
1992 | 0 | mAddActiveEventFuzzTime = false; |
1993 | 0 | } |
1994 | 0 | } |
1995 | | |
1996 | | bool |
1997 | | nsGlobalWindowInner::DialogsAreBeingAbused() |
1998 | 0 | { |
1999 | 0 | NS_ASSERTION(GetScriptableTopInternal() && |
2000 | 0 | GetScriptableTopInternal()->GetCurrentInnerWindowInternal() == this, |
2001 | 0 | "DialogsAreBeingAbused called with invalid window"); |
2002 | 0 |
|
2003 | 0 | if (mLastDialogQuitTime.IsNull() || |
2004 | 0 | nsContentUtils::IsCallerChrome()) { |
2005 | 0 | return false; |
2006 | 0 | } |
2007 | 0 | |
2008 | 0 | TimeDuration dialogInterval(TimeStamp::Now() - mLastDialogQuitTime); |
2009 | 0 | if (dialogInterval.ToSeconds() < |
2010 | 0 | Preferences::GetInt("dom.successive_dialog_time_limit", |
2011 | 0 | DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT)) { |
2012 | 0 | mDialogAbuseCount++; |
2013 | 0 |
|
2014 | 0 | return GetPopupControlState() > openAllowed || |
2015 | 0 | mDialogAbuseCount > MAX_SUCCESSIVE_DIALOG_COUNT; |
2016 | 0 | } |
2017 | 0 |
|
2018 | 0 | // Reset the abuse counter |
2019 | 0 | mDialogAbuseCount = 0; |
2020 | 0 |
|
2021 | 0 | return false; |
2022 | 0 | } |
2023 | | |
2024 | | nsresult |
2025 | | nsGlobalWindowInner::PostHandleEvent(EventChainPostVisitor& aVisitor) |
2026 | 0 | { |
2027 | 0 | // Return early if there is nothing to do. |
2028 | 0 | switch (aVisitor.mEvent->mMessage) { |
2029 | 0 | case eResize: |
2030 | 0 | case eUnload: |
2031 | 0 | case eLoad: |
2032 | 0 | break; |
2033 | 0 | default: |
2034 | 0 | return NS_OK; |
2035 | 0 | } |
2036 | 0 | |
2037 | 0 | /* mChromeEventHandler and mContext go dangling in the middle of this |
2038 | 0 | function under some circumstances (events that destroy the window) |
2039 | 0 | without this addref. */ |
2040 | 0 | RefPtr<EventTarget> kungFuDeathGrip1(mChromeEventHandler); |
2041 | 0 | mozilla::Unused << kungFuDeathGrip1; // These aren't referred to through the function |
2042 | 0 | nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal()); |
2043 | 0 | mozilla::Unused << kungFuDeathGrip2; // These aren't referred to through the function |
2044 | 0 |
|
2045 | 0 |
|
2046 | 0 | if (aVisitor.mEvent->mMessage == eResize) { |
2047 | 0 | mIsHandlingResizeEvent = false; |
2048 | 0 | } else if (aVisitor.mEvent->mMessage == eUnload && |
2049 | 0 | aVisitor.mEvent->IsTrusted()) { |
2050 | 0 |
|
2051 | 0 | // If any VR display presentation is active at unload, the next page |
2052 | 0 | // will receive a vrdisplayactive event to indicate that it should |
2053 | 0 | // immediately begin vr presentation. This should occur when navigating |
2054 | 0 | // forwards, navigating backwards, and on page reload. |
2055 | 0 | for (const auto& display : mVRDisplays) { |
2056 | 0 | if (display->IsPresenting()) { |
2057 | 0 | display->StartVRNavigation(); |
2058 | 0 | // Save this VR display ID to trigger vrdisplayactivate event |
2059 | 0 | // after the next load event. |
2060 | 0 | nsGlobalWindowOuter* outer = GetOuterWindowInternal(); |
2061 | 0 | if (outer) { |
2062 | 0 | outer->SetAutoActivateVRDisplayID(display->DisplayId()); |
2063 | 0 | } |
2064 | 0 |
|
2065 | 0 | // XXX The WebVR 1.1 spec does not define which of multiple VR |
2066 | 0 | // presenting VR displays will be chosen during navigation. |
2067 | 0 | // As the underlying platform VR API's currently only allow a single |
2068 | 0 | // VR display, it is safe to choose the first VR display for now. |
2069 | 0 | break; |
2070 | 0 | } |
2071 | 0 | } |
2072 | 0 | // Execute bindingdetached handlers before we tear ourselves |
2073 | 0 | // down. |
2074 | 0 | if (mDoc) { |
2075 | 0 | mDoc->BindingManager()->ExecuteDetachedHandlers(); |
2076 | 0 | } |
2077 | 0 | mIsDocumentLoaded = false; |
2078 | 0 | } else if (aVisitor.mEvent->mMessage == eLoad && |
2079 | 0 | aVisitor.mEvent->IsTrusted()) { |
2080 | 0 | // This is page load event since load events don't propagate to |window|. |
2081 | 0 | // @see nsDocument::GetEventTargetParent. |
2082 | 0 | mIsDocumentLoaded = true; |
2083 | 0 |
|
2084 | 0 | mTimeoutManager->OnDocumentLoaded(); |
2085 | 0 |
|
2086 | 0 | nsCOMPtr<Element> element = GetOuterWindow()->GetFrameElementInternal(); |
2087 | 0 | nsIDocShell* docShell = GetDocShell(); |
2088 | 0 | if (element && GetParentInternal() && |
2089 | 0 | docShell && docShell->ItemType() != nsIDocShellTreeItem::typeChrome) { |
2090 | 0 | // If we're not in chrome, or at a chrome boundary, fire the |
2091 | 0 | // onload event for the frame element. |
2092 | 0 |
|
2093 | 0 | nsEventStatus status = nsEventStatus_eIgnore; |
2094 | 0 | WidgetEvent event(aVisitor.mEvent->IsTrusted(), eLoad); |
2095 | 0 | event.mFlags.mBubbles = false; |
2096 | 0 | event.mFlags.mCancelable = false; |
2097 | 0 |
|
2098 | 0 | // Most of the time we could get a pres context to pass in here, |
2099 | 0 | // but not always (i.e. if this window is not shown there won't |
2100 | 0 | // be a pres context available). Since we're not firing a GUI |
2101 | 0 | // event we don't need a pres context anyway so we just pass |
2102 | 0 | // null as the pres context all the time here. |
2103 | 0 | EventDispatcher::Dispatch(element, nullptr, &event, nullptr, &status); |
2104 | 0 | } |
2105 | 0 |
|
2106 | 0 | if (mVREventObserver) { |
2107 | 0 | mVREventObserver->NotifyAfterLoad(); |
2108 | 0 | } |
2109 | 0 |
|
2110 | 0 | uint32_t autoActivateVRDisplayID = 0; |
2111 | 0 | nsGlobalWindowOuter* outer = GetOuterWindowInternal(); |
2112 | 0 | if (outer) { |
2113 | 0 | autoActivateVRDisplayID = outer->GetAutoActivateVRDisplayID(); |
2114 | 0 | } |
2115 | 0 | if (autoActivateVRDisplayID) { |
2116 | 0 | DispatchVRDisplayActivate(autoActivateVRDisplayID, |
2117 | 0 | VRDisplayEventReason::Navigation); |
2118 | 0 | } |
2119 | 0 | } |
2120 | 0 |
|
2121 | 0 | return NS_OK; |
2122 | 0 | } |
2123 | | |
2124 | | nsresult |
2125 | | nsGlobalWindowInner::DefineArgumentsProperty(nsIArray *aArguments) |
2126 | 0 | { |
2127 | 0 | nsIScriptContext *ctx = GetOuterWindowInternal()->mContext; |
2128 | 0 | NS_ENSURE_TRUE(aArguments && ctx, NS_ERROR_NOT_INITIALIZED); |
2129 | 0 |
|
2130 | 0 | JS::Rooted<JSObject*> obj(RootingCx(), GetWrapperPreserveColor()); |
2131 | 0 | return ctx->SetProperty(obj, "arguments", aArguments); |
2132 | 0 | } |
2133 | | |
2134 | | //***************************************************************************** |
2135 | | // nsGlobalWindowInner::nsIScriptObjectPrincipal |
2136 | | //***************************************************************************** |
2137 | | |
2138 | | nsIPrincipal* |
2139 | | nsGlobalWindowInner::GetPrincipal() |
2140 | 0 | { |
2141 | 0 | if (mDoc) { |
2142 | 0 | // If we have a document, get the principal from the document |
2143 | 0 | return mDoc->NodePrincipal(); |
2144 | 0 | } |
2145 | 0 | |
2146 | 0 | if (mDocumentPrincipal) { |
2147 | 0 | return mDocumentPrincipal; |
2148 | 0 | } |
2149 | 0 | |
2150 | 0 | // If we don't have a principal and we don't have a document we |
2151 | 0 | // ask the parent window for the principal. This can happen when |
2152 | 0 | // loading a frameset that has a <frame src="javascript:xxx">, in |
2153 | 0 | // that case the global window is used in JS before we've loaded |
2154 | 0 | // a document into the window. |
2155 | 0 | |
2156 | 0 | nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal = |
2157 | 0 | do_QueryInterface(GetParentInternal()); |
2158 | 0 |
|
2159 | 0 | if (objPrincipal) { |
2160 | 0 | return objPrincipal->GetPrincipal(); |
2161 | 0 | } |
2162 | 0 | |
2163 | 0 | return nullptr; |
2164 | 0 | } |
2165 | | |
2166 | | //***************************************************************************** |
2167 | | // nsGlobalWindowInner::nsIDOMWindow |
2168 | | //***************************************************************************** |
2169 | | |
2170 | | bool |
2171 | | nsPIDOMWindowInner::AddAudioContext(AudioContext* aAudioContext) |
2172 | 0 | { |
2173 | 0 | mAudioContexts.AppendElement(aAudioContext); |
2174 | 0 |
|
2175 | 0 | // Return true if the context should be muted and false if not. |
2176 | 0 | nsIDocShell* docShell = GetDocShell(); |
2177 | 0 | return docShell && !docShell->GetAllowMedia() && !aAudioContext->IsOffline(); |
2178 | 0 | } |
2179 | | |
2180 | | void |
2181 | | nsPIDOMWindowInner::RemoveAudioContext(AudioContext* aAudioContext) |
2182 | 0 | { |
2183 | 0 | mAudioContexts.RemoveElement(aAudioContext); |
2184 | 0 | } |
2185 | | |
2186 | | void |
2187 | | nsPIDOMWindowInner::MuteAudioContexts() |
2188 | 0 | { |
2189 | 0 | for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) { |
2190 | 0 | if (!mAudioContexts[i]->IsOffline()) { |
2191 | 0 | mAudioContexts[i]->Mute(); |
2192 | 0 | } |
2193 | 0 | } |
2194 | 0 | } |
2195 | | |
2196 | | void |
2197 | | nsPIDOMWindowInner::UnmuteAudioContexts() |
2198 | 0 | { |
2199 | 0 | for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) { |
2200 | 0 | if (!mAudioContexts[i]->IsOffline()) { |
2201 | 0 | mAudioContexts[i]->Unmute(); |
2202 | 0 | } |
2203 | 0 | } |
2204 | 0 | } |
2205 | | |
2206 | | nsGlobalWindowInner* |
2207 | | nsGlobalWindowInner::Window() |
2208 | 0 | { |
2209 | 0 | return this; |
2210 | 0 | } |
2211 | | |
2212 | | nsGlobalWindowInner* |
2213 | | nsGlobalWindowInner::Self() |
2214 | 0 | { |
2215 | 0 | return this; |
2216 | 0 | } |
2217 | | |
2218 | | Navigator* |
2219 | | nsPIDOMWindowInner::Navigator() |
2220 | 0 | { |
2221 | 0 | if (!mNavigator) { |
2222 | 0 | mNavigator = new mozilla::dom::Navigator(this); |
2223 | 0 | } |
2224 | 0 |
|
2225 | 0 | return mNavigator; |
2226 | 0 | } |
2227 | | |
2228 | | VisualViewport* nsGlobalWindowInner::VisualViewport() |
2229 | 0 | { |
2230 | 0 | if (!mVisualViewport) { |
2231 | 0 | mVisualViewport = new mozilla::dom::VisualViewport(this); |
2232 | 0 | } |
2233 | 0 |
|
2234 | 0 | return mVisualViewport; |
2235 | 0 | } |
2236 | | |
2237 | | nsScreen* |
2238 | | nsGlobalWindowInner::GetScreen(ErrorResult& aError) |
2239 | 0 | { |
2240 | 0 | if (!mScreen) { |
2241 | 0 | mScreen = nsScreen::Create(this); |
2242 | 0 | if (!mScreen) { |
2243 | 0 | aError.Throw(NS_ERROR_UNEXPECTED); |
2244 | 0 | return nullptr; |
2245 | 0 | } |
2246 | 0 | } |
2247 | 0 | |
2248 | 0 | return mScreen; |
2249 | 0 | } |
2250 | | |
2251 | | nsHistory* |
2252 | | nsGlobalWindowInner::GetHistory(ErrorResult& aError) |
2253 | 0 | { |
2254 | 0 | if (!mHistory) { |
2255 | 0 | mHistory = new nsHistory(this); |
2256 | 0 | } |
2257 | 0 |
|
2258 | 0 | return mHistory; |
2259 | 0 | } |
2260 | | |
2261 | | CustomElementRegistry* |
2262 | | nsGlobalWindowInner::CustomElements() |
2263 | 0 | { |
2264 | 0 | if (!mCustomElements) { |
2265 | 0 | mCustomElements = new CustomElementRegistry(this); |
2266 | 0 | } |
2267 | 0 |
|
2268 | 0 | return mCustomElements; |
2269 | 0 | } |
2270 | | |
2271 | | Performance* |
2272 | | nsPIDOMWindowInner::GetPerformance() |
2273 | 0 | { |
2274 | 0 | CreatePerformanceObjectIfNeeded(); |
2275 | 0 | return mPerformance; |
2276 | 0 | } |
2277 | | |
2278 | | void |
2279 | | nsPIDOMWindowInner::QueuePerformanceNavigationTiming() |
2280 | 0 | { |
2281 | 0 | CreatePerformanceObjectIfNeeded(); |
2282 | 0 | if (mPerformance) { |
2283 | 0 | mPerformance->QueueNavigationTimingEntry(); |
2284 | 0 | } |
2285 | 0 | } |
2286 | | |
2287 | | void |
2288 | | nsPIDOMWindowInner::CreatePerformanceObjectIfNeeded() |
2289 | 0 | { |
2290 | 0 | if (mPerformance || !mDoc) { |
2291 | 0 | return; |
2292 | 0 | } |
2293 | 0 | RefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming(); |
2294 | 0 | nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel())); |
2295 | 0 | bool timingEnabled = false; |
2296 | 0 | if (!timedChannel || |
2297 | 0 | !NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) || |
2298 | 0 | !timingEnabled) { |
2299 | 0 | timedChannel = nullptr; |
2300 | 0 | } |
2301 | 0 | if (timing) { |
2302 | 0 | mPerformance = Performance::CreateForMainThread(this, mDoc->NodePrincipal(), timing, timedChannel); |
2303 | 0 | } |
2304 | 0 | } |
2305 | | |
2306 | | bool |
2307 | | nsPIDOMWindowInner::IsSecureContext() const |
2308 | 0 | { |
2309 | 0 | return nsGlobalWindowInner::Cast(this)->IsSecureContext(); |
2310 | 0 | } |
2311 | | |
2312 | | void |
2313 | | nsPIDOMWindowInner::Suspend() |
2314 | 0 | { |
2315 | 0 | nsGlobalWindowInner::Cast(this)->Suspend(); |
2316 | 0 | } |
2317 | | |
2318 | | void |
2319 | | nsPIDOMWindowInner::Resume() |
2320 | 0 | { |
2321 | 0 | nsGlobalWindowInner::Cast(this)->Resume(); |
2322 | 0 | } |
2323 | | |
2324 | | void |
2325 | | nsPIDOMWindowInner::SyncStateFromParentWindow() |
2326 | 0 | { |
2327 | 0 | nsGlobalWindowInner::Cast(this)->SyncStateFromParentWindow(); |
2328 | 0 | } |
2329 | | |
2330 | | Maybe<ClientInfo> |
2331 | | nsPIDOMWindowInner::GetClientInfo() const |
2332 | 0 | { |
2333 | 0 | return nsGlobalWindowInner::Cast(this)->GetClientInfo(); |
2334 | 0 | } |
2335 | | |
2336 | | Maybe<ClientState> |
2337 | | nsPIDOMWindowInner::GetClientState() const |
2338 | 0 | { |
2339 | 0 | return nsGlobalWindowInner::Cast(this)->GetClientState(); |
2340 | 0 | } |
2341 | | |
2342 | | Maybe<ServiceWorkerDescriptor> |
2343 | | nsPIDOMWindowInner::GetController() const |
2344 | 0 | { |
2345 | 0 | return nsGlobalWindowInner::Cast(this)->GetController(); |
2346 | 0 | } |
2347 | | |
2348 | | void |
2349 | | nsPIDOMWindowInner::NoteCalledRegisterForServiceWorkerScope(const nsACString& aScope) |
2350 | 0 | { |
2351 | 0 | nsGlobalWindowInner::Cast(this)->NoteCalledRegisterForServiceWorkerScope(aScope); |
2352 | 0 | } |
2353 | | |
2354 | | void |
2355 | | nsPIDOMWindowInner::NoteDOMContentLoaded() |
2356 | 0 | { |
2357 | 0 | nsGlobalWindowInner::Cast(this)->NoteDOMContentLoaded(); |
2358 | 0 | } |
2359 | | |
2360 | | bool |
2361 | | nsGlobalWindowInner::ShouldReportForServiceWorkerScope(const nsAString& aScope) |
2362 | 0 | { |
2363 | 0 | bool result = false; |
2364 | 0 |
|
2365 | 0 | nsPIDOMWindowOuter* topOuter = GetScriptableTop(); |
2366 | 0 | NS_ENSURE_TRUE(topOuter, false); |
2367 | 0 |
|
2368 | 0 | nsGlobalWindowInner* topInner = |
2369 | 0 | nsGlobalWindowInner::Cast(topOuter->GetCurrentInnerWindow()); |
2370 | 0 | NS_ENSURE_TRUE(topInner, false); |
2371 | 0 |
|
2372 | 0 | topInner->ShouldReportForServiceWorkerScopeInternal(NS_ConvertUTF16toUTF8(aScope), |
2373 | 0 | &result); |
2374 | 0 | return result; |
2375 | 0 | } |
2376 | | |
2377 | | already_AddRefed<InstallTriggerImpl> |
2378 | | nsGlobalWindowInner::GetInstallTrigger() |
2379 | 0 | { |
2380 | 0 | if (!mInstallTrigger) { |
2381 | 0 | JS::Rooted<JSObject*> jsImplObj(RootingCx()); |
2382 | 0 | ErrorResult rv; |
2383 | 0 | ConstructJSImplementation("@mozilla.org/addons/installtrigger;1", this, |
2384 | 0 | &jsImplObj, rv); |
2385 | 0 | if (rv.Failed()) { |
2386 | 0 | rv.SuppressException(); |
2387 | 0 | return nullptr; |
2388 | 0 | } |
2389 | 0 | MOZ_RELEASE_ASSERT(!js::IsWrapper(jsImplObj)); |
2390 | 0 | JS::Rooted<JSObject*> jsImplGlobal(RootingCx(), |
2391 | 0 | JS::GetNonCCWObjectGlobal(jsImplObj)); |
2392 | 0 | mInstallTrigger = new InstallTriggerImpl(jsImplObj, jsImplGlobal, this); |
2393 | 0 | } |
2394 | 0 |
|
2395 | 0 | return do_AddRef(mInstallTrigger); |
2396 | 0 | } |
2397 | | |
2398 | | nsIDOMWindowUtils* |
2399 | | nsGlobalWindowInner::GetWindowUtils(ErrorResult& aRv) |
2400 | 0 | { |
2401 | 0 | FORWARD_TO_OUTER_OR_THROW(WindowUtils, (), aRv, nullptr); |
2402 | 0 | } |
2403 | | |
2404 | | nsGlobalWindowInner::CallState |
2405 | | nsGlobalWindowInner::ShouldReportForServiceWorkerScopeInternal(const nsACString& aScope, |
2406 | | bool* aResultOut) |
2407 | 0 | { |
2408 | 0 | MOZ_DIAGNOSTIC_ASSERT(aResultOut); |
2409 | 0 |
|
2410 | 0 | // First check to see if this window is controlled. If so, then we have |
2411 | 0 | // found a match and are done. |
2412 | 0 | const Maybe<ServiceWorkerDescriptor> swd = GetController(); |
2413 | 0 | if (swd.isSome() && swd.ref().Scope() == aScope) { |
2414 | 0 | *aResultOut = true; |
2415 | 0 | return CallState::Stop; |
2416 | 0 | } |
2417 | 0 | |
2418 | 0 | // Next, check to see if this window has called navigator.serviceWorker.register() |
2419 | 0 | // for this scope. If so, then treat this as a match so console reports |
2420 | 0 | // appear in the devtools console. |
2421 | 0 | if (mClientSource && mClientSource->CalledRegisterForServiceWorkerScope(aScope)) { |
2422 | 0 | *aResultOut = true; |
2423 | 0 | return CallState::Stop; |
2424 | 0 | } |
2425 | 0 | |
2426 | 0 | // Finally check the current docshell nsILoadGroup to see if there are any |
2427 | 0 | // outstanding navigation requests. If so, match the scope against the |
2428 | 0 | // channel's URL. We want to show console reports during the FetchEvent |
2429 | 0 | // intercepting the navigation itself. |
2430 | 0 | nsCOMPtr<nsIDocumentLoader> loader(do_QueryInterface(GetDocShell())); |
2431 | 0 | if (loader) { |
2432 | 0 | nsCOMPtr<nsILoadGroup> loadgroup; |
2433 | 0 | Unused << loader->GetLoadGroup(getter_AddRefs(loadgroup)); |
2434 | 0 | if (loadgroup) { |
2435 | 0 | nsCOMPtr<nsISimpleEnumerator> iter; |
2436 | 0 | Unused << loadgroup->GetRequests(getter_AddRefs(iter)); |
2437 | 0 | if (iter) { |
2438 | 0 | nsCOMPtr<nsISupports> tmp; |
2439 | 0 | bool hasMore = true; |
2440 | 0 | // Check each network request in the load group. |
2441 | 0 | while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) { |
2442 | 0 | iter->GetNext(getter_AddRefs(tmp)); |
2443 | 0 | nsCOMPtr<nsIChannel> loadingChannel(do_QueryInterface(tmp)); |
2444 | 0 | // Ignore subresource requests. Logging for a subresource |
2445 | 0 | // FetchEvent should be handled above since the client is |
2446 | 0 | // already controlled. |
2447 | 0 | if (!loadingChannel || |
2448 | 0 | !nsContentUtils::IsNonSubresourceRequest(loadingChannel)) { |
2449 | 0 | continue; |
2450 | 0 | } |
2451 | 0 | nsCOMPtr<nsIURI> loadingURL; |
2452 | 0 | Unused << loadingChannel->GetURI(getter_AddRefs(loadingURL)); |
2453 | 0 | if (!loadingURL) { |
2454 | 0 | continue; |
2455 | 0 | } |
2456 | 0 | nsAutoCString loadingSpec; |
2457 | 0 | Unused << loadingURL->GetSpec(loadingSpec); |
2458 | 0 | // Perform a simple substring comparison to match the scope |
2459 | 0 | // against the channel URL. |
2460 | 0 | if (StringBeginsWith(loadingSpec, aScope)) { |
2461 | 0 | *aResultOut = true; |
2462 | 0 | return CallState::Stop; |
2463 | 0 | } |
2464 | 0 | } |
2465 | 0 | } |
2466 | 0 | } |
2467 | 0 | } |
2468 | 0 |
|
2469 | 0 | // The current window doesn't care about this service worker, but maybe |
2470 | 0 | // one of our child frames does. |
2471 | 0 | return CallOnChildren(&nsGlobalWindowInner::ShouldReportForServiceWorkerScopeInternal, |
2472 | 0 | aScope, aResultOut); |
2473 | 0 | } |
2474 | | |
2475 | | void |
2476 | | nsGlobalWindowInner::NoteCalledRegisterForServiceWorkerScope(const nsACString& aScope) |
2477 | 0 | { |
2478 | 0 | if (!mClientSource) { |
2479 | 0 | return; |
2480 | 0 | } |
2481 | 0 | |
2482 | 0 | mClientSource->NoteCalledRegisterForServiceWorkerScope(aScope); |
2483 | 0 | } |
2484 | | |
2485 | | void |
2486 | | nsGlobalWindowInner::NoteDOMContentLoaded() |
2487 | 0 | { |
2488 | 0 | if (!mClientSource) { |
2489 | 0 | return; |
2490 | 0 | } |
2491 | 0 | |
2492 | 0 | mClientSource->NoteDOMContentLoaded(); |
2493 | 0 | } |
2494 | | |
2495 | | void |
2496 | | nsGlobalWindowInner::MigrateStateForDocumentOpen(nsGlobalWindowInner* aOldInner) |
2497 | 0 | { |
2498 | 0 | MOZ_DIAGNOSTIC_ASSERT(aOldInner); |
2499 | 0 | MOZ_DIAGNOSTIC_ASSERT(aOldInner != this); |
2500 | 0 | MOZ_DIAGNOSTIC_ASSERT(mDoc); |
2501 | 0 |
|
2502 | 0 | // Rebind DETH objects to the new global created by document.open(). |
2503 | 0 | // XXX: Is this correct? We should consider if the spec and our |
2504 | 0 | // implementation should change to match other browsers by |
2505 | 0 | // just reusing the current window. (Bug 1449992) |
2506 | 0 | aOldInner->ForEachEventTargetObject( |
2507 | 0 | [&] (DOMEventTargetHelper* aDETH, bool* aDoneOut) { |
2508 | 0 | aDETH->BindToOwner(this->AsInner()); |
2509 | 0 | }); |
2510 | 0 |
|
2511 | 0 | // Move the old Performance object from the old window to the new window. |
2512 | 0 | // The Performance object was also rebound in the DETH loop above. |
2513 | 0 | mPerformance = aOldInner->mPerformance.forget(); |
2514 | 0 |
|
2515 | 0 | if (aOldInner->mIndexedDB) { |
2516 | 0 | aOldInner->mIndexedDB->RebindToNewWindow(this); |
2517 | 0 | mIndexedDB = aOldInner->mIndexedDB.forget(); |
2518 | 0 | } |
2519 | 0 | } |
2520 | | |
2521 | | void |
2522 | | nsGlobalWindowInner::UpdateTopInnerWindow() |
2523 | 0 | { |
2524 | 0 | if (IsTopInnerWindow() || !mTopInnerWindow) { |
2525 | 0 | return; |
2526 | 0 | } |
2527 | 0 | |
2528 | 0 | mTopInnerWindow->UpdateWebSocketCount(-(int32_t)mNumOfOpenWebSockets); |
2529 | 0 | } |
2530 | | |
2531 | | void |
2532 | | nsPIDOMWindowInner::AddPeerConnection() |
2533 | 0 | { |
2534 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
2535 | 0 | mTopInnerWindow ? mTopInnerWindow->mActivePeerConnections++ |
2536 | 0 | : mActivePeerConnections++; |
2537 | 0 | } |
2538 | | |
2539 | | void |
2540 | | nsPIDOMWindowInner::RemovePeerConnection() |
2541 | 0 | { |
2542 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
2543 | 0 | MOZ_ASSERT(mTopInnerWindow ? mTopInnerWindow->mActivePeerConnections |
2544 | 0 | : mActivePeerConnections); |
2545 | 0 |
|
2546 | 0 | mTopInnerWindow ? mTopInnerWindow->mActivePeerConnections-- |
2547 | 0 | : mActivePeerConnections--; |
2548 | 0 | } |
2549 | | |
2550 | | bool |
2551 | | nsPIDOMWindowInner::HasActivePeerConnections() |
2552 | 0 | { |
2553 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
2554 | 0 | return mTopInnerWindow ? mTopInnerWindow->mActivePeerConnections |
2555 | 0 | : mActivePeerConnections; |
2556 | 0 | } |
2557 | | |
2558 | | bool |
2559 | | nsPIDOMWindowInner::IsPlayingAudio() |
2560 | 0 | { |
2561 | 0 | for (uint32_t i = 0; i < mAudioContexts.Length(); i++) { |
2562 | 0 | if (mAudioContexts[i]->IsRunning()) { |
2563 | 0 | return true; |
2564 | 0 | } |
2565 | 0 | } |
2566 | 0 | RefPtr<AudioChannelService> acs = AudioChannelService::Get(); |
2567 | 0 | if (!acs) { |
2568 | 0 | return false; |
2569 | 0 | } |
2570 | 0 | auto outer = GetOuterWindow(); |
2571 | 0 | if (!outer) { |
2572 | 0 | // We've been unlinked and are about to die. Not a good time to pretend to |
2573 | 0 | // be playing audio. |
2574 | 0 | return false; |
2575 | 0 | } |
2576 | 0 | return acs->IsWindowActive(outer); |
2577 | 0 | } |
2578 | | |
2579 | | bool |
2580 | | nsPIDOMWindowInner::IsDocumentLoaded() const |
2581 | 0 | { |
2582 | 0 | return mIsDocumentLoaded; |
2583 | 0 | } |
2584 | | |
2585 | | mozilla::dom::TimeoutManager& |
2586 | | nsPIDOMWindowInner::TimeoutManager() |
2587 | 0 | { |
2588 | 0 | return *mTimeoutManager; |
2589 | 0 | } |
2590 | | |
2591 | | bool |
2592 | | nsPIDOMWindowInner::IsRunningTimeout() |
2593 | 0 | { |
2594 | 0 | return TimeoutManager().IsRunningTimeout(); |
2595 | 0 | } |
2596 | | |
2597 | | void |
2598 | | nsPIDOMWindowInner::TryToCacheTopInnerWindow() |
2599 | 0 | { |
2600 | 0 | if (mHasTriedToCacheTopInnerWindow) { |
2601 | 0 | return; |
2602 | 0 | } |
2603 | 0 | |
2604 | 0 | nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(this); |
2605 | 0 |
|
2606 | 0 | MOZ_ASSERT(!window->IsDying()); |
2607 | 0 |
|
2608 | 0 | mHasTriedToCacheTopInnerWindow = true; |
2609 | 0 |
|
2610 | 0 | MOZ_ASSERT(window); |
2611 | 0 |
|
2612 | 0 | if (nsCOMPtr<nsPIDOMWindowOuter> topOutter = window->GetScriptableTop()) { |
2613 | 0 | mTopInnerWindow = topOutter->GetCurrentInnerWindow(); |
2614 | 0 | } |
2615 | 0 | } |
2616 | | |
2617 | | void |
2618 | | nsPIDOMWindowInner::UpdateActiveIndexedDBTransactionCount(int32_t aDelta) |
2619 | 0 | { |
2620 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
2621 | 0 |
|
2622 | 0 | if (aDelta == 0) { |
2623 | 0 | return; |
2624 | 0 | } |
2625 | 0 | |
2626 | 0 | TabGroup()->IndexedDBTransactionCounter() += aDelta; |
2627 | 0 | } |
2628 | | |
2629 | | void |
2630 | | nsPIDOMWindowInner::UpdateActiveIndexedDBDatabaseCount(int32_t aDelta) |
2631 | 0 | { |
2632 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
2633 | 0 |
|
2634 | 0 | if (aDelta == 0) { |
2635 | 0 | return; |
2636 | 0 | } |
2637 | 0 | |
2638 | 0 | // We count databases but not transactions because only active databases |
2639 | 0 | // could block throttling. |
2640 | 0 | uint32_t& counter = mTopInnerWindow ? |
2641 | 0 | mTopInnerWindow->mNumOfIndexedDBDatabases : mNumOfIndexedDBDatabases; |
2642 | 0 |
|
2643 | 0 | counter+= aDelta; |
2644 | 0 |
|
2645 | 0 | TabGroup()->IndexedDBDatabaseCounter() += aDelta; |
2646 | 0 | } |
2647 | | |
2648 | | bool |
2649 | | nsPIDOMWindowInner::HasActiveIndexedDBDatabases() |
2650 | 0 | { |
2651 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
2652 | 0 |
|
2653 | 0 | return mTopInnerWindow ? |
2654 | 0 | mTopInnerWindow->mNumOfIndexedDBDatabases > 0 : |
2655 | 0 | mNumOfIndexedDBDatabases > 0; |
2656 | 0 | } |
2657 | | |
2658 | | void |
2659 | | nsPIDOMWindowInner::UpdateWebSocketCount(int32_t aDelta) |
2660 | 0 | { |
2661 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
2662 | 0 |
|
2663 | 0 | if (aDelta == 0) { |
2664 | 0 | return; |
2665 | 0 | } |
2666 | 0 | |
2667 | 0 | if (mTopInnerWindow && !IsTopInnerWindow()) { |
2668 | 0 | mTopInnerWindow->UpdateWebSocketCount(aDelta); |
2669 | 0 | } |
2670 | 0 |
|
2671 | 0 | MOZ_DIAGNOSTIC_ASSERT( |
2672 | 0 | aDelta > 0 || ((aDelta + mNumOfOpenWebSockets) < mNumOfOpenWebSockets)); |
2673 | 0 |
|
2674 | 0 | mNumOfOpenWebSockets += aDelta; |
2675 | 0 | } |
2676 | | |
2677 | | bool |
2678 | | nsPIDOMWindowInner::HasOpenWebSockets() const |
2679 | 0 | { |
2680 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
2681 | 0 |
|
2682 | 0 | return mNumOfOpenWebSockets || |
2683 | 0 | (mTopInnerWindow && mTopInnerWindow->mNumOfOpenWebSockets); |
2684 | 0 | } |
2685 | | |
2686 | | bool |
2687 | | nsPIDOMWindowInner::GetAudioCaptured() const |
2688 | 0 | { |
2689 | 0 | return mAudioCaptured; |
2690 | 0 | } |
2691 | | |
2692 | | nsresult |
2693 | | nsPIDOMWindowInner::SetAudioCapture(bool aCapture) |
2694 | 0 | { |
2695 | 0 | mAudioCaptured = aCapture; |
2696 | 0 |
|
2697 | 0 | RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate(); |
2698 | 0 | if (service) { |
2699 | 0 | service->SetWindowAudioCaptured(GetOuterWindow(), mWindowID, aCapture); |
2700 | 0 | } |
2701 | 0 |
|
2702 | 0 | return NS_OK; |
2703 | 0 | } |
2704 | | |
2705 | | // nsISpeechSynthesisGetter |
2706 | | |
2707 | | #ifdef MOZ_WEBSPEECH |
2708 | | SpeechSynthesis* |
2709 | | nsGlobalWindowInner::GetSpeechSynthesis(ErrorResult& aError) |
2710 | 0 | { |
2711 | 0 | if (!mSpeechSynthesis) { |
2712 | 0 | mSpeechSynthesis = new SpeechSynthesis(this); |
2713 | 0 | } |
2714 | 0 |
|
2715 | 0 | return mSpeechSynthesis; |
2716 | 0 | } |
2717 | | |
2718 | | bool |
2719 | | nsGlobalWindowInner::HasActiveSpeechSynthesis() |
2720 | 0 | { |
2721 | 0 | if (mSpeechSynthesis) { |
2722 | 0 | return !mSpeechSynthesis->HasEmptyQueue(); |
2723 | 0 | } |
2724 | 0 | |
2725 | 0 | return false; |
2726 | 0 | } |
2727 | | |
2728 | | #endif |
2729 | | |
2730 | | already_AddRefed<nsPIDOMWindowOuter> |
2731 | | nsGlobalWindowInner::GetParent(ErrorResult& aError) |
2732 | 0 | { |
2733 | 0 | FORWARD_TO_OUTER_OR_THROW(GetParentOuter, (), aError, nullptr); |
2734 | 0 | } |
2735 | | |
2736 | | /** |
2737 | | * GetScriptableParent is called when script reads window.parent. |
2738 | | * |
2739 | | * In contrast to GetRealParent, GetScriptableParent respects <iframe |
2740 | | * mozbrowser> boundaries, so if |this| is contained by an <iframe |
2741 | | * mozbrowser>, we will return |this| as its own parent. |
2742 | | */ |
2743 | | nsPIDOMWindowOuter* |
2744 | | nsGlobalWindowInner::GetScriptableParent() |
2745 | 0 | { |
2746 | 0 | FORWARD_TO_OUTER(GetScriptableParent, (), nullptr); |
2747 | 0 | } |
2748 | | |
2749 | | /** |
2750 | | * GetScriptableTop is called when script reads window.top. |
2751 | | * |
2752 | | * In contrast to GetRealTop, GetScriptableTop respects <iframe mozbrowser> |
2753 | | * boundaries. If we encounter a window owned by an <iframe mozbrowser> while |
2754 | | * walking up the window hierarchy, we'll stop and return that window. |
2755 | | */ |
2756 | | nsPIDOMWindowOuter* |
2757 | | nsGlobalWindowInner::GetScriptableTop() |
2758 | 0 | { |
2759 | 0 | FORWARD_TO_OUTER(GetScriptableTop, (), nullptr); |
2760 | 0 | } |
2761 | | |
2762 | | void |
2763 | | nsGlobalWindowInner::GetContent(JSContext* aCx, |
2764 | | JS::MutableHandle<JSObject*> aRetval, |
2765 | | CallerType aCallerType, |
2766 | | ErrorResult& aError) |
2767 | 0 | { |
2768 | 0 | FORWARD_TO_OUTER_OR_THROW(GetContentOuter, |
2769 | 0 | (aCx, aRetval, aCallerType, aError), aError, ); |
2770 | 0 | } |
2771 | | |
2772 | | BarProp* |
2773 | | nsGlobalWindowInner::GetMenubar(ErrorResult& aError) |
2774 | 0 | { |
2775 | 0 | if (!mMenubar) { |
2776 | 0 | mMenubar = new MenubarProp(this); |
2777 | 0 | } |
2778 | 0 |
|
2779 | 0 | return mMenubar; |
2780 | 0 | } |
2781 | | |
2782 | | BarProp* |
2783 | | nsGlobalWindowInner::GetToolbar(ErrorResult& aError) |
2784 | 0 | { |
2785 | 0 | if (!mToolbar) { |
2786 | 0 | mToolbar = new ToolbarProp(this); |
2787 | 0 | } |
2788 | 0 |
|
2789 | 0 | return mToolbar; |
2790 | 0 | } |
2791 | | |
2792 | | BarProp* |
2793 | | nsGlobalWindowInner::GetLocationbar(ErrorResult& aError) |
2794 | 0 | { |
2795 | 0 | if (!mLocationbar) { |
2796 | 0 | mLocationbar = new LocationbarProp(this); |
2797 | 0 | } |
2798 | 0 | return mLocationbar; |
2799 | 0 | } |
2800 | | |
2801 | | BarProp* |
2802 | | nsGlobalWindowInner::GetPersonalbar(ErrorResult& aError) |
2803 | 0 | { |
2804 | 0 | if (!mPersonalbar) { |
2805 | 0 | mPersonalbar = new PersonalbarProp(this); |
2806 | 0 | } |
2807 | 0 | return mPersonalbar; |
2808 | 0 | } |
2809 | | |
2810 | | BarProp* |
2811 | | nsGlobalWindowInner::GetStatusbar(ErrorResult& aError) |
2812 | 0 | { |
2813 | 0 | if (!mStatusbar) { |
2814 | 0 | mStatusbar = new StatusbarProp(this); |
2815 | 0 | } |
2816 | 0 | return mStatusbar; |
2817 | 0 | } |
2818 | | |
2819 | | BarProp* |
2820 | | nsGlobalWindowInner::GetScrollbars(ErrorResult& aError) |
2821 | 0 | { |
2822 | 0 | if (!mScrollbars) { |
2823 | 0 | mScrollbars = new ScrollbarsProp(this); |
2824 | 0 | } |
2825 | 0 |
|
2826 | 0 | return mScrollbars; |
2827 | 0 | } |
2828 | | |
2829 | | bool |
2830 | | nsGlobalWindowInner::GetClosed(ErrorResult& aError) |
2831 | 0 | { |
2832 | 0 | FORWARD_TO_OUTER_OR_THROW(GetClosedOuter, (), aError, false); |
2833 | 0 | } |
2834 | | |
2835 | | nsDOMWindowList* |
2836 | | nsGlobalWindowInner::GetFrames() |
2837 | 0 | { |
2838 | 0 | FORWARD_TO_OUTER(GetFrames, (), nullptr); |
2839 | 0 | } |
2840 | | |
2841 | | already_AddRefed<nsPIDOMWindowOuter> |
2842 | | nsGlobalWindowInner::IndexedGetter(uint32_t aIndex) |
2843 | 0 | { |
2844 | 0 | FORWARD_TO_OUTER(IndexedGetterOuter, (aIndex), nullptr); |
2845 | 0 | } |
2846 | | |
2847 | | namespace { |
2848 | | |
2849 | | struct InterfaceShimEntry { |
2850 | | const char *geckoName; |
2851 | | const char *domName; |
2852 | | }; |
2853 | | |
2854 | | } // anonymous namespace |
2855 | | |
2856 | | // We add shims from Components.interfaces.nsIDOMFoo to window.Foo for each |
2857 | | // interface that has interface constants that sites might be getting off |
2858 | | // of Ci. |
2859 | | const InterfaceShimEntry kInterfaceShimMap[] = |
2860 | | { { "nsIXMLHttpRequest", "XMLHttpRequest" }, |
2861 | | { "nsIDOMDOMException", "DOMException" }, |
2862 | | { "nsIDOMNode", "Node" }, |
2863 | | { "nsIDOMCSSRule", "CSSRule" }, |
2864 | | { "nsIDOMEvent", "Event" }, |
2865 | | { "nsIDOMNSEvent", "Event" }, |
2866 | | { "nsIDOMKeyEvent", "KeyEvent" }, |
2867 | | { "nsIDOMMouseEvent", "MouseEvent" }, |
2868 | | { "nsIDOMMouseScrollEvent", "MouseScrollEvent" }, |
2869 | | { "nsIDOMMutationEvent", "MutationEvent" }, |
2870 | | { "nsIDOMUIEvent", "UIEvent" }, |
2871 | | { "nsIDOMHTMLMediaElement", "HTMLMediaElement" }, |
2872 | | { "nsIDOMRange", "Range" }, |
2873 | | { "nsIDOMSVGLength", "SVGLength" }, |
2874 | | // Think about whether Ci.nsINodeFilter can just go away for websites! |
2875 | | { "nsIDOMNodeFilter", "NodeFilter" }, |
2876 | | { "nsIDOMXPathResult", "XPathResult" } }; |
2877 | | |
2878 | | bool |
2879 | | nsGlobalWindowInner::ResolveComponentsShim( |
2880 | | JSContext *aCx, |
2881 | | JS::Handle<JSObject*> aGlobal, |
2882 | | JS::MutableHandle<JS::PropertyDescriptor> aDesc) |
2883 | 0 | { |
2884 | 0 | // Keep track of how often this happens. |
2885 | 0 | Telemetry::Accumulate(Telemetry::COMPONENTS_SHIM_ACCESSED_BY_CONTENT, true); |
2886 | 0 |
|
2887 | 0 | // Warn once. |
2888 | 0 | nsCOMPtr<nsIDocument> doc = GetExtantDoc(); |
2889 | 0 | if (doc) { |
2890 | 0 | doc->WarnOnceAbout(nsIDocument::eComponents, /* asError = */ true); |
2891 | 0 | } |
2892 | 0 |
|
2893 | 0 | // Create a fake Components object. |
2894 | 0 | AssertSameCompartment(aCx, aGlobal); |
2895 | 0 | JS::Rooted<JSObject*> components(aCx, JS_NewPlainObject(aCx)); |
2896 | 0 | if (NS_WARN_IF(!components)) { |
2897 | 0 | return false; |
2898 | 0 | } |
2899 | 0 | |
2900 | 0 | // Create a fake interfaces object. |
2901 | 0 | JS::Rooted<JSObject*> interfaces(aCx, JS_NewPlainObject(aCx)); |
2902 | 0 | if (NS_WARN_IF(!interfaces)) { |
2903 | 0 | return false; |
2904 | 0 | } |
2905 | 0 | bool ok = |
2906 | 0 | JS_DefineProperty(aCx, components, "interfaces", interfaces, |
2907 | 0 | JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); |
2908 | 0 | if (NS_WARN_IF(!ok)) { |
2909 | 0 | return false; |
2910 | 0 | } |
2911 | 0 | |
2912 | 0 | // Define a bunch of shims from the Ci.nsIDOMFoo to window.Foo for DOM |
2913 | 0 | // interfaces with constants. |
2914 | 0 | for (uint32_t i = 0; i < ArrayLength(kInterfaceShimMap); ++i) { |
2915 | 0 |
|
2916 | 0 | // Grab the names from the table. |
2917 | 0 | const char *geckoName = kInterfaceShimMap[i].geckoName; |
2918 | 0 | const char *domName = kInterfaceShimMap[i].domName; |
2919 | 0 |
|
2920 | 0 | // Look up the appopriate interface object on the global. |
2921 | 0 | JS::Rooted<JS::Value> v(aCx, JS::UndefinedValue()); |
2922 | 0 | ok = JS_GetProperty(aCx, aGlobal, domName, &v); |
2923 | 0 | if (NS_WARN_IF(!ok)) { |
2924 | 0 | return false; |
2925 | 0 | } |
2926 | 0 | if (!v.isObject()) { |
2927 | 0 | NS_WARNING("Unable to find interface object on global"); |
2928 | 0 | continue; |
2929 | 0 | } |
2930 | 0 |
|
2931 | 0 | // Define the shim on the interfaces object. |
2932 | 0 | ok = JS_DefineProperty(aCx, interfaces, geckoName, v, |
2933 | 0 | JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); |
2934 | 0 | if (NS_WARN_IF(!ok)) { |
2935 | 0 | return false; |
2936 | 0 | } |
2937 | 0 | } |
2938 | 0 |
|
2939 | 0 | FillPropertyDescriptor(aDesc, aGlobal, JS::ObjectValue(*components), false); |
2940 | 0 |
|
2941 | 0 | return true; |
2942 | 0 | } |
2943 | | |
2944 | | #ifdef RELEASE_OR_BETA |
2945 | | #define USE_CONTROLLERS_SHIM |
2946 | | #endif |
2947 | | |
2948 | | #ifdef USE_CONTROLLERS_SHIM |
2949 | | static const JSClass ControllersShimClass = { |
2950 | | "Controllers", 0 |
2951 | | }; |
2952 | | static const JSClass XULControllersShimClass = { |
2953 | | "XULControllers", 0 |
2954 | | }; |
2955 | | #endif |
2956 | | |
2957 | | bool |
2958 | | nsGlobalWindowInner::DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObj, |
2959 | | JS::Handle<jsid> aId, |
2960 | | JS::MutableHandle<JS::PropertyDescriptor> aDesc) |
2961 | 0 | { |
2962 | 0 | // Note: Keep this in sync with MayResolve. |
2963 | 0 |
|
2964 | 0 | // Note: The infallibleInit call in GlobalResolve depends on this check. |
2965 | 0 | if (!JSID_IS_STRING(aId)) { |
2966 | 0 | return true; |
2967 | 0 | } |
2968 | 0 | |
2969 | 0 | bool found; |
2970 | 0 | if (!WebIDLGlobalNameHash::DefineIfEnabled(aCx, aObj, aId, aDesc, &found)) { |
2971 | 0 | return false; |
2972 | 0 | } |
2973 | 0 | |
2974 | 0 | if (found) { |
2975 | 0 | return true; |
2976 | 0 | } |
2977 | 0 | |
2978 | 0 | // We support a cut-down Components.interfaces in case websites are |
2979 | 0 | // using Components.interfaces.nsIFoo.CONSTANT_NAME for the ones |
2980 | 0 | // that have constants. |
2981 | 0 | static bool watchingComponentsPref = false; |
2982 | 0 | static bool useComponentsShim = false; |
2983 | 0 | if (!watchingComponentsPref) { |
2984 | 0 | watchingComponentsPref = true; |
2985 | 0 | Preferences::AddBoolVarCache(&useComponentsShim, "dom.use_components_shim", |
2986 | 0 | true); |
2987 | 0 | } |
2988 | 0 | if (useComponentsShim && |
2989 | 0 | aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS)) { |
2990 | 0 | return ResolveComponentsShim(aCx, aObj, aDesc); |
2991 | 0 | } |
2992 | 0 | |
2993 | 0 | // We also support a "window.controllers" thing; apparently some |
2994 | 0 | // sites use it for browser-sniffing. See bug 1010577. |
2995 | | #ifdef USE_CONTROLLERS_SHIM |
2996 | | // Note: We use |aObj| rather than |this| to get the principal here, because |
2997 | | // this is called during Window setup when the Document isn't necessarily |
2998 | | // hooked up yet. |
2999 | | if ((aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS) || |
3000 | | aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS_CLASS)) && |
3001 | | !xpc::IsXrayWrapper(aObj) && |
3002 | | !nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(aObj))) |
3003 | | { |
3004 | | if (GetExtantDoc()) { |
3005 | | GetExtantDoc()->WarnOnceAbout(nsIDocument::eWindow_Cc_ontrollers); |
3006 | | } |
3007 | | const JSClass* clazz; |
3008 | | if (aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS)) { |
3009 | | clazz = &XULControllersShimClass; |
3010 | | } else { |
3011 | | clazz = &ControllersShimClass; |
3012 | | } |
3013 | | MOZ_ASSERT(JS_IsGlobalObject(aObj)); |
3014 | | JS::Rooted<JSObject*> shim(aCx, JS_NewObject(aCx, clazz)); |
3015 | | if (NS_WARN_IF(!shim)) { |
3016 | | return false; |
3017 | | } |
3018 | | FillPropertyDescriptor(aDesc, aObj, JS::ObjectValue(*shim), |
3019 | | /* readOnly = */ false); |
3020 | | return true; |
3021 | | } |
3022 | | #endif |
3023 | | |
3024 | 0 | return true; |
3025 | 0 | } |
3026 | | |
3027 | | /* static */ |
3028 | | bool |
3029 | | nsGlobalWindowInner::MayResolve(jsid aId) |
3030 | 0 | { |
3031 | 0 | // Note: This function does not fail and may not have any side-effects. |
3032 | 0 | // Note: Keep this in sync with DoResolve. |
3033 | 0 | if (!JSID_IS_STRING(aId)) { |
3034 | 0 | return false; |
3035 | 0 | } |
3036 | 0 | |
3037 | 0 | if (aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS)) { |
3038 | 0 | return true; |
3039 | 0 | } |
3040 | 0 | |
3041 | 0 | if (aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS) || |
3042 | 0 | aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS_CLASS)) { |
3043 | 0 | // We only resolve .controllers/.Controllers in release builds and on non-chrome |
3044 | 0 | // windows, but let's not worry about any of that stuff. |
3045 | 0 | return true; |
3046 | 0 | } |
3047 | 0 | |
3048 | 0 | return WebIDLGlobalNameHash::MayResolve(aId); |
3049 | 0 | } |
3050 | | |
3051 | | void |
3052 | | nsGlobalWindowInner::GetOwnPropertyNames(JSContext* aCx, JS::AutoIdVector& aNames, |
3053 | | bool aEnumerableOnly, ErrorResult& aRv) |
3054 | 0 | { |
3055 | 0 | if (aEnumerableOnly) { |
3056 | 0 | // The names we would return from here get defined on the window via one of |
3057 | 0 | // two codepaths. The ones coming from the WebIDLGlobalNameHash will end up |
3058 | 0 | // in the DefineConstructor function in BindingUtils, which always defines |
3059 | 0 | // things as non-enumerable. The ones coming from the script namespace |
3060 | 0 | // manager get defined by our resolve hook using FillPropertyDescriptor with |
3061 | 0 | // 0 for the property attributes, so non-enumerable as well. |
3062 | 0 | // |
3063 | 0 | // So in the aEnumerableOnly case we have nothing to do. |
3064 | 0 | return; |
3065 | 0 | } |
3066 | 0 | |
3067 | 0 | // "Components" is marked as enumerable but only resolved on demand :-/. |
3068 | 0 | //aNames.AppendElement(NS_LITERAL_STRING("Components")); |
3069 | 0 | |
3070 | 0 | JS::Rooted<JSObject*> wrapper(aCx, GetWrapper()); |
3071 | 0 |
|
3072 | 0 | // There are actually two ways we can get called here: For normal |
3073 | 0 | // enumeration or for Xray enumeration. In the latter case, we want to |
3074 | 0 | // return all possible WebIDL names, because we don't really support |
3075 | 0 | // deleting these names off our Xray; trying to resolve them will just make |
3076 | 0 | // them come back. In the former case, we want to avoid returning deleted |
3077 | 0 | // names. But the JS engine already knows about the non-deleted |
3078 | 0 | // already-resolved names, so we can just return the so-far-unresolved ones. |
3079 | 0 | // |
3080 | 0 | // We can tell which case we're in by whether aCx is in our wrapper's |
3081 | 0 | // compartment. If not, we're in the Xray case. |
3082 | 0 | WebIDLGlobalNameHash::NameType nameType = |
3083 | 0 | js::IsObjectInContextCompartment(wrapper, aCx) ? |
3084 | 0 | WebIDLGlobalNameHash::UnresolvedNamesOnly : |
3085 | 0 | WebIDLGlobalNameHash::AllNames; |
3086 | 0 | if (!WebIDLGlobalNameHash::GetNames(aCx, wrapper, nameType, aNames)) { |
3087 | 0 | aRv.NoteJSContextException(aCx); |
3088 | 0 | } |
3089 | 0 | } |
3090 | | |
3091 | | /* static */ bool |
3092 | | nsGlobalWindowInner::IsPrivilegedChromeWindow(JSContext* aCx, JSObject* aObj) |
3093 | 0 | { |
3094 | 0 | // For now, have to deal with XPConnect objects here. |
3095 | 0 | return xpc::WindowOrNull(aObj)->IsChromeWindow() && |
3096 | 0 | nsContentUtils::ObjectPrincipal(aObj) == nsContentUtils::GetSystemPrincipal(); |
3097 | 0 | } |
3098 | | |
3099 | | /* static */ bool |
3100 | | nsGlobalWindowInner::OfflineCacheAllowedForContext(JSContext* aCx, JSObject* aObj) |
3101 | 0 | { |
3102 | 0 | return IsSecureContextOrObjectIsFromSecureContext(aCx, aObj) || |
3103 | 0 | Preferences::GetBool("browser.cache.offline.insecure.enable"); |
3104 | 0 | } |
3105 | | |
3106 | | /* static */ bool |
3107 | | nsGlobalWindowInner::IsRequestIdleCallbackEnabled(JSContext* aCx, JSObject* aObj) |
3108 | 0 | { |
3109 | 0 | // The requestIdleCallback should always be enabled for system code. |
3110 | 0 | return nsContentUtils::RequestIdleCallbackEnabled() || |
3111 | 0 | nsContentUtils::IsSystemCaller(aCx); |
3112 | 0 | } |
3113 | | |
3114 | | /* static */ bool |
3115 | | nsGlobalWindowInner::RegisterProtocolHandlerAllowedForContext(JSContext* aCx, JSObject* aObj) |
3116 | 0 | { |
3117 | 0 | return IsSecureContextOrObjectIsFromSecureContext(aCx, aObj) || |
3118 | 0 | Preferences::GetBool("dom.registerProtocolHandler.insecure.enabled"); |
3119 | 0 | } |
3120 | | |
3121 | | /* static */ bool |
3122 | | nsGlobalWindowInner::DeviceSensorsEnabled(JSContext* aCx, JSObject* aObj) |
3123 | 0 | { |
3124 | 0 | return Preferences::GetBool("device.sensors.enabled"); |
3125 | 0 | } |
3126 | | |
3127 | | nsDOMOfflineResourceList* |
3128 | | nsGlobalWindowInner::GetApplicationCache(ErrorResult& aError) |
3129 | 0 | { |
3130 | 0 | if (!mApplicationCache) { |
3131 | 0 | nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(GetDocShell())); |
3132 | 0 | if (!webNav || !mDoc) { |
3133 | 0 | aError.Throw(NS_ERROR_FAILURE); |
3134 | 0 | return nullptr; |
3135 | 0 | } |
3136 | 0 | |
3137 | 0 | nsCOMPtr<nsIURI> uri; |
3138 | 0 | aError = webNav->GetCurrentURI(getter_AddRefs(uri)); |
3139 | 0 | if (aError.Failed()) { |
3140 | 0 | return nullptr; |
3141 | 0 | } |
3142 | 0 | |
3143 | 0 | nsCOMPtr<nsIURI> manifestURI; |
3144 | 0 | nsContentUtils::GetOfflineAppManifest(mDoc, getter_AddRefs(manifestURI)); |
3145 | 0 |
|
3146 | 0 | RefPtr<nsDOMOfflineResourceList> applicationCache = |
3147 | 0 | new nsDOMOfflineResourceList(manifestURI, uri, mDoc->NodePrincipal(), |
3148 | 0 | this); |
3149 | 0 |
|
3150 | 0 | applicationCache->Init(); |
3151 | 0 |
|
3152 | 0 | mApplicationCache = applicationCache; |
3153 | 0 | } |
3154 | 0 |
|
3155 | 0 | return mApplicationCache; |
3156 | 0 | } |
3157 | | |
3158 | | nsDOMOfflineResourceList* |
3159 | | nsGlobalWindowInner::GetApplicationCache() |
3160 | 0 | { |
3161 | 0 | return GetApplicationCache(IgnoreErrors()); |
3162 | 0 | } |
3163 | | |
3164 | | Crypto* |
3165 | | nsGlobalWindowInner::GetCrypto(ErrorResult& aError) |
3166 | 0 | { |
3167 | 0 | if (!mCrypto) { |
3168 | 0 | mCrypto = new Crypto(this); |
3169 | 0 | } |
3170 | 0 | return mCrypto; |
3171 | 0 | } |
3172 | | |
3173 | | mozilla::dom::U2F* |
3174 | | nsGlobalWindowInner::GetU2f(ErrorResult& aError) |
3175 | 0 | { |
3176 | 0 | if (!mU2F) { |
3177 | 0 | RefPtr<U2F> u2f = new U2F(this); |
3178 | 0 | u2f->Init(aError); |
3179 | 0 | if (NS_WARN_IF(aError.Failed())) { |
3180 | 0 | return nullptr; |
3181 | 0 | } |
3182 | 0 | |
3183 | 0 | mU2F = u2f; |
3184 | 0 | } |
3185 | 0 | return mU2F; |
3186 | 0 | } |
3187 | | |
3188 | | nsIControllers* |
3189 | | nsGlobalWindowInner::GetControllers(ErrorResult& aError) |
3190 | 0 | { |
3191 | 0 | FORWARD_TO_OUTER_OR_THROW(GetControllersOuter, (aError), aError, nullptr); |
3192 | 0 | } |
3193 | | |
3194 | | nsresult |
3195 | | nsGlobalWindowInner::GetControllers(nsIControllers** aResult) |
3196 | 0 | { |
3197 | 0 | ErrorResult rv; |
3198 | 0 | nsCOMPtr<nsIControllers> controllers = GetControllers(rv); |
3199 | 0 | controllers.forget(aResult); |
3200 | 0 |
|
3201 | 0 | return rv.StealNSResult(); |
3202 | 0 | } |
3203 | | |
3204 | | nsPIDOMWindowOuter* |
3205 | | nsGlobalWindowInner::GetOpenerWindow(ErrorResult& aError) |
3206 | 0 | { |
3207 | 0 | FORWARD_TO_OUTER_OR_THROW(GetOpenerWindowOuter, (), aError, nullptr); |
3208 | 0 | } |
3209 | | |
3210 | | void |
3211 | | nsGlobalWindowInner::GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval, |
3212 | | ErrorResult& aError) |
3213 | 0 | { |
3214 | 0 | nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpenerWindow(aError); |
3215 | 0 | if (aError.Failed() || !opener) { |
3216 | 0 | aRetval.setNull(); |
3217 | 0 | return; |
3218 | 0 | } |
3219 | 0 | |
3220 | 0 | aError = nsContentUtils::WrapNative(aCx, opener, aRetval); |
3221 | 0 | } |
3222 | | |
3223 | | void |
3224 | | nsGlobalWindowInner::SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener, |
3225 | | ErrorResult& aError) |
3226 | 0 | { |
3227 | 0 | if (aOpener.isNull()) { |
3228 | 0 | SetOpenerWindow(nullptr, false); |
3229 | 0 | return; |
3230 | 0 | } |
3231 | 0 | |
3232 | 0 | // If something other than null is passed, just define aOpener on our inner |
3233 | 0 | // window's JS object, wrapped into the current compartment so that for Xrays |
3234 | 0 | // we define on the Xray expando object, but don't set it on the outer window, |
3235 | 0 | // so that it'll get reset on navigation. This is just like replaceable |
3236 | 0 | // properties, but we're not quite readonly. |
3237 | 0 | RedefineProperty(aCx, "opener", aOpener, aError); |
3238 | 0 | } |
3239 | | |
3240 | | void |
3241 | | nsGlobalWindowInner::GetEvent(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval) |
3242 | 0 | { |
3243 | 0 | if (mEvent) { |
3244 | 0 | Unused << nsContentUtils::WrapNative(aCx, mEvent, aRetval); |
3245 | 0 | } else { |
3246 | 0 | aRetval.setUndefined(); |
3247 | 0 | } |
3248 | 0 | } |
3249 | | |
3250 | | void |
3251 | | nsGlobalWindowInner::GetStatus(nsAString& aStatus, ErrorResult& aError) |
3252 | 0 | { |
3253 | 0 | FORWARD_TO_OUTER_OR_THROW(GetStatusOuter, (aStatus), aError, ); |
3254 | 0 | } |
3255 | | |
3256 | | void |
3257 | | nsGlobalWindowInner::SetStatus(const nsAString& aStatus, ErrorResult& aError) |
3258 | 0 | { |
3259 | 0 | FORWARD_TO_OUTER_OR_THROW(SetStatusOuter, (aStatus), aError, ); |
3260 | 0 | } |
3261 | | |
3262 | | void |
3263 | | nsGlobalWindowInner::GetName(nsAString& aName, ErrorResult& aError) |
3264 | 0 | { |
3265 | 0 | FORWARD_TO_OUTER_OR_THROW(GetNameOuter, (aName), aError, ); |
3266 | 0 | } |
3267 | | |
3268 | | void |
3269 | | nsGlobalWindowInner::SetName(const nsAString& aName, mozilla::ErrorResult& aError) |
3270 | 0 | { |
3271 | 0 | FORWARD_TO_OUTER_OR_THROW(SetNameOuter, (aName, aError), aError, ); |
3272 | 0 | } |
3273 | | |
3274 | | int32_t |
3275 | | nsGlobalWindowInner::GetInnerWidth(CallerType aCallerType, ErrorResult& aError) |
3276 | 0 | { |
3277 | 0 | // We ignore aCallerType; we only have that argument because some other things |
3278 | 0 | // called by GetReplaceableWindowCoord need it. If this ever changes, fix |
3279 | 0 | // nsresult nsGlobalWindowInner::GetInnerWidth(int32_t* aInnerWidth) |
3280 | 0 | // to actually take a useful CallerType and pass it in here. |
3281 | 0 | FORWARD_TO_OUTER_OR_THROW(GetInnerWidthOuter, (aError), aError, 0); |
3282 | 0 | } |
3283 | | |
3284 | | void |
3285 | | nsGlobalWindowInner::GetInnerWidth(JSContext* aCx, |
3286 | | JS::MutableHandle<JS::Value> aValue, |
3287 | | CallerType aCallerType, |
3288 | | ErrorResult& aError) |
3289 | 0 | { |
3290 | 0 | GetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::GetInnerWidth, aValue, |
3291 | 0 | aCallerType, aError); |
3292 | 0 | } |
3293 | | |
3294 | | nsresult |
3295 | | nsGlobalWindowInner::GetInnerWidth(int32_t* aInnerWidth) |
3296 | 0 | { |
3297 | 0 | ErrorResult rv; |
3298 | 0 | // Callee doesn't care about the caller type, but play it safe. |
3299 | 0 | *aInnerWidth = GetInnerWidth(CallerType::NonSystem, rv); |
3300 | 0 |
|
3301 | 0 | return rv.StealNSResult(); |
3302 | 0 | } |
3303 | | |
3304 | | void |
3305 | | nsGlobalWindowInner::SetInnerWidth(int32_t aInnerWidth, CallerType aCallerType, |
3306 | | ErrorResult& aError) |
3307 | 0 | { |
3308 | 0 | FORWARD_TO_OUTER_OR_THROW(SetInnerWidthOuter, |
3309 | 0 | (aInnerWidth, aCallerType, aError), aError, ); |
3310 | 0 | } |
3311 | | |
3312 | | void |
3313 | | nsGlobalWindowInner::SetInnerWidth(JSContext* aCx, JS::Handle<JS::Value> aValue, |
3314 | | CallerType aCallerType, |
3315 | | ErrorResult& aError) |
3316 | 0 | { |
3317 | 0 | SetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::SetInnerWidth, |
3318 | 0 | aValue, "innerWidth", aCallerType, aError); |
3319 | 0 | } |
3320 | | |
3321 | | int32_t |
3322 | | nsGlobalWindowInner::GetInnerHeight(CallerType aCallerType, ErrorResult& aError) |
3323 | 0 | { |
3324 | 0 | // We ignore aCallerType; we only have that argument because some other things |
3325 | 0 | // called by GetReplaceableWindowCoord need it. If this ever changes, fix |
3326 | 0 | // nsresult nsGlobalWindowInner::GetInnerHeight(int32_t* aInnerWidth) |
3327 | 0 | // to actually take a useful CallerType and pass it in here. |
3328 | 0 | FORWARD_TO_OUTER_OR_THROW(GetInnerHeightOuter, (aError), aError, 0); |
3329 | 0 | } |
3330 | | |
3331 | | void |
3332 | | nsGlobalWindowInner::GetInnerHeight(JSContext* aCx, |
3333 | | JS::MutableHandle<JS::Value> aValue, |
3334 | | CallerType aCallerType, |
3335 | | ErrorResult& aError) |
3336 | 0 | { |
3337 | 0 | GetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::GetInnerHeight, aValue, |
3338 | 0 | aCallerType, aError); |
3339 | 0 | } |
3340 | | |
3341 | | nsresult |
3342 | | nsGlobalWindowInner::GetInnerHeight(int32_t* aInnerHeight) |
3343 | 0 | { |
3344 | 0 | ErrorResult rv; |
3345 | 0 | // Callee doesn't care about the caller type, but play it safe. |
3346 | 0 | *aInnerHeight = GetInnerHeight(CallerType::NonSystem, rv); |
3347 | 0 |
|
3348 | 0 | return rv.StealNSResult(); |
3349 | 0 | } |
3350 | | |
3351 | | void |
3352 | | nsGlobalWindowInner::SetInnerHeight(int32_t aInnerHeight, |
3353 | | CallerType aCallerType, |
3354 | | ErrorResult& aError) |
3355 | 0 | { |
3356 | 0 | FORWARD_TO_OUTER_OR_THROW(SetInnerHeightOuter, |
3357 | 0 | (aInnerHeight, aCallerType, aError), aError, ); |
3358 | 0 | } |
3359 | | |
3360 | | void |
3361 | | nsGlobalWindowInner::SetInnerHeight(JSContext* aCx, JS::Handle<JS::Value> aValue, |
3362 | | CallerType aCallerType, ErrorResult& aError) |
3363 | 0 | { |
3364 | 0 | SetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::SetInnerHeight, |
3365 | 0 | aValue, "innerHeight", aCallerType, aError); |
3366 | 0 | } |
3367 | | |
3368 | | int32_t |
3369 | | nsGlobalWindowInner::GetOuterWidth(CallerType aCallerType, ErrorResult& aError) |
3370 | 0 | { |
3371 | 0 | FORWARD_TO_OUTER_OR_THROW(GetOuterWidthOuter, (aCallerType, aError), |
3372 | 0 | aError, 0); |
3373 | 0 | } |
3374 | | |
3375 | | void |
3376 | | nsGlobalWindowInner::GetOuterWidth(JSContext* aCx, |
3377 | | JS::MutableHandle<JS::Value> aValue, |
3378 | | CallerType aCallerType, |
3379 | | ErrorResult& aError) |
3380 | 0 | { |
3381 | 0 | GetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::GetOuterWidth, aValue, |
3382 | 0 | aCallerType, aError); |
3383 | 0 | } |
3384 | | |
3385 | | int32_t |
3386 | | nsGlobalWindowInner::GetOuterHeight(CallerType aCallerType, ErrorResult& aError) |
3387 | 0 | { |
3388 | 0 | FORWARD_TO_OUTER_OR_THROW(GetOuterHeightOuter, (aCallerType, aError), |
3389 | 0 | aError, 0); |
3390 | 0 | } |
3391 | | |
3392 | | void |
3393 | | nsGlobalWindowInner::GetOuterHeight(JSContext* aCx, |
3394 | | JS::MutableHandle<JS::Value> aValue, |
3395 | | CallerType aCallerType, |
3396 | | ErrorResult& aError) |
3397 | 0 | { |
3398 | 0 | GetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::GetOuterHeight, aValue, |
3399 | 0 | aCallerType, aError); |
3400 | 0 | } |
3401 | | |
3402 | | void |
3403 | | nsGlobalWindowInner::SetOuterWidth(int32_t aOuterWidth, |
3404 | | CallerType aCallerType, |
3405 | | ErrorResult& aError) |
3406 | 0 | { |
3407 | 0 | FORWARD_TO_OUTER_OR_THROW(SetOuterWidthOuter, |
3408 | 0 | (aOuterWidth, aCallerType, aError), aError, ); |
3409 | 0 | } |
3410 | | |
3411 | | void |
3412 | | nsGlobalWindowInner::SetOuterWidth(JSContext* aCx, JS::Handle<JS::Value> aValue, |
3413 | | CallerType aCallerType, |
3414 | | ErrorResult& aError) |
3415 | 0 | { |
3416 | 0 | SetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::SetOuterWidth, |
3417 | 0 | aValue, "outerWidth", aCallerType, aError); |
3418 | 0 | } |
3419 | | |
3420 | | void |
3421 | | nsGlobalWindowInner::SetOuterHeight(int32_t aOuterHeight, |
3422 | | CallerType aCallerType, |
3423 | | ErrorResult& aError) |
3424 | 0 | { |
3425 | 0 | FORWARD_TO_OUTER_OR_THROW(SetOuterHeightOuter, |
3426 | 0 | (aOuterHeight, aCallerType, aError), aError, ); |
3427 | 0 | } |
3428 | | |
3429 | | void |
3430 | | nsGlobalWindowInner::SetOuterHeight(JSContext* aCx, JS::Handle<JS::Value> aValue, |
3431 | | CallerType aCallerType, |
3432 | | ErrorResult& aError) |
3433 | 0 | { |
3434 | 0 | SetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::SetOuterHeight, |
3435 | 0 | aValue, "outerHeight", aCallerType, aError); |
3436 | 0 | } |
3437 | | |
3438 | | int32_t |
3439 | | nsGlobalWindowInner::GetScreenX(CallerType aCallerType, ErrorResult& aError) |
3440 | 0 | { |
3441 | 0 | FORWARD_TO_OUTER_OR_THROW(GetScreenXOuter, (aCallerType, aError), aError, 0); |
3442 | 0 | } |
3443 | | |
3444 | | void |
3445 | | nsGlobalWindowInner::GetScreenX(JSContext* aCx, |
3446 | | JS::MutableHandle<JS::Value> aValue, |
3447 | | CallerType aCallerType, |
3448 | | ErrorResult& aError) |
3449 | 0 | { |
3450 | 0 | GetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::GetScreenX, aValue, |
3451 | 0 | aCallerType, aError); |
3452 | 0 | } |
3453 | | |
3454 | | float |
3455 | | nsGlobalWindowInner::GetMozInnerScreenX(CallerType aCallerType, ErrorResult& aError) |
3456 | 0 | { |
3457 | 0 | FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenXOuter, (aCallerType), aError, 0); |
3458 | 0 | } |
3459 | | |
3460 | | float |
3461 | | nsGlobalWindowInner::GetMozInnerScreenY(CallerType aCallerType, ErrorResult& aError) |
3462 | 0 | { |
3463 | 0 | FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenYOuter, (aCallerType), aError, 0); |
3464 | 0 | } |
3465 | | |
3466 | | double |
3467 | | nsGlobalWindowInner::GetDevicePixelRatio(CallerType aCallerType, ErrorResult& aError) |
3468 | 0 | { |
3469 | 0 | FORWARD_TO_OUTER_OR_THROW(GetDevicePixelRatioOuter, (aCallerType), aError, 0.0); |
3470 | 0 | } |
3471 | | |
3472 | | uint64_t |
3473 | | nsGlobalWindowInner::GetMozPaintCount(ErrorResult& aError) |
3474 | 0 | { |
3475 | 0 | FORWARD_TO_OUTER_OR_THROW(GetMozPaintCountOuter, (), aError, 0); |
3476 | 0 | } |
3477 | | |
3478 | | int32_t |
3479 | | nsGlobalWindowInner::RequestAnimationFrame(FrameRequestCallback& aCallback, |
3480 | | ErrorResult& aError) |
3481 | 0 | { |
3482 | 0 | if (!mDoc) { |
3483 | 0 | return 0; |
3484 | 0 | } |
3485 | 0 | |
3486 | 0 | if (GetWrapperPreserveColor()) { |
3487 | 0 | js::NotifyAnimationActivity(GetWrapperPreserveColor()); |
3488 | 0 | } |
3489 | 0 |
|
3490 | 0 | int32_t handle; |
3491 | 0 | aError = mDoc->ScheduleFrameRequestCallback(aCallback, &handle); |
3492 | 0 | return handle; |
3493 | 0 | } |
3494 | | |
3495 | | void |
3496 | | nsGlobalWindowInner::CancelAnimationFrame(int32_t aHandle, ErrorResult& aError) |
3497 | 0 | { |
3498 | 0 | if (!mDoc) { |
3499 | 0 | return; |
3500 | 0 | } |
3501 | 0 | |
3502 | 0 | mDoc->CancelFrameRequestCallback(aHandle); |
3503 | 0 | } |
3504 | | |
3505 | | already_AddRefed<MediaQueryList> |
3506 | | nsGlobalWindowInner::MatchMedia(const nsAString& aMediaQueryList, |
3507 | | CallerType aCallerType, |
3508 | | ErrorResult& aError) |
3509 | 0 | { |
3510 | 0 | // FIXME: This whole forward-to-outer and then get a pres |
3511 | 0 | // shell/context off the docshell dance is sort of silly; it'd make |
3512 | 0 | // more sense to forward to the inner, but it's what everyone else |
3513 | 0 | // (GetSelection, GetScrollXY, etc.) does around here. |
3514 | 0 | FORWARD_TO_OUTER_OR_THROW(MatchMediaOuter, (aMediaQueryList, aCallerType), aError, nullptr); |
3515 | 0 | } |
3516 | | |
3517 | | void |
3518 | | nsGlobalWindowInner::SetScreenX(int32_t aScreenX, |
3519 | | CallerType aCallerType, |
3520 | | ErrorResult& aError) |
3521 | 0 | { |
3522 | 0 | FORWARD_TO_OUTER_OR_THROW(SetScreenXOuter, |
3523 | 0 | (aScreenX, aCallerType, aError), aError, ); |
3524 | 0 | } |
3525 | | |
3526 | | void |
3527 | | nsGlobalWindowInner::SetScreenX(JSContext* aCx, JS::Handle<JS::Value> aValue, |
3528 | | CallerType aCallerType, ErrorResult& aError) |
3529 | 0 | { |
3530 | 0 | SetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::SetScreenX, |
3531 | 0 | aValue, "screenX", aCallerType, aError); |
3532 | 0 | } |
3533 | | |
3534 | | int32_t |
3535 | | nsGlobalWindowInner::GetScreenY(CallerType aCallerType, ErrorResult& aError) |
3536 | 0 | { |
3537 | 0 | FORWARD_TO_OUTER_OR_THROW(GetScreenYOuter, (aCallerType, aError), aError, 0); |
3538 | 0 | } |
3539 | | |
3540 | | void |
3541 | | nsGlobalWindowInner::GetScreenY(JSContext* aCx, |
3542 | | JS::MutableHandle<JS::Value> aValue, |
3543 | | CallerType aCallerType, ErrorResult& aError) |
3544 | 0 | { |
3545 | 0 | GetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::GetScreenY, aValue, |
3546 | 0 | aCallerType, aError); |
3547 | 0 | } |
3548 | | |
3549 | | void |
3550 | | nsGlobalWindowInner::SetScreenY(int32_t aScreenY, |
3551 | | CallerType aCallerType, |
3552 | | ErrorResult& aError) |
3553 | 0 | { |
3554 | 0 | FORWARD_TO_OUTER_OR_THROW(SetScreenYOuter, |
3555 | 0 | (aScreenY, aCallerType, aError), aError, ); |
3556 | 0 | } |
3557 | | |
3558 | | void |
3559 | | nsGlobalWindowInner::SetScreenY(JSContext* aCx, JS::Handle<JS::Value> aValue, |
3560 | | CallerType aCallerType, |
3561 | | ErrorResult& aError) |
3562 | 0 | { |
3563 | 0 | SetReplaceableWindowCoord(aCx, &nsGlobalWindowInner::SetScreenY, |
3564 | 0 | aValue, "screenY", aCallerType, aError); |
3565 | 0 | } |
3566 | | |
3567 | | int32_t |
3568 | | nsGlobalWindowInner::GetScrollMinX(ErrorResult& aError) |
3569 | 0 | { |
3570 | 0 | FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideLeft), aError, 0); |
3571 | 0 | } |
3572 | | |
3573 | | int32_t |
3574 | | nsGlobalWindowInner::GetScrollMinY(ErrorResult& aError) |
3575 | 0 | { |
3576 | 0 | FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideTop), aError, 0); |
3577 | 0 | } |
3578 | | |
3579 | | int32_t |
3580 | | nsGlobalWindowInner::GetScrollMaxX(ErrorResult& aError) |
3581 | 0 | { |
3582 | 0 | FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideRight), aError, 0); |
3583 | 0 | } |
3584 | | |
3585 | | int32_t |
3586 | | nsGlobalWindowInner::GetScrollMaxY(ErrorResult& aError) |
3587 | 0 | { |
3588 | 0 | FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideBottom), aError, 0); |
3589 | 0 | } |
3590 | | |
3591 | | double |
3592 | | nsGlobalWindowInner::GetScrollX(ErrorResult& aError) |
3593 | 0 | { |
3594 | 0 | FORWARD_TO_OUTER_OR_THROW(GetScrollXOuter, (), aError, 0); |
3595 | 0 | } |
3596 | | |
3597 | | double |
3598 | | nsGlobalWindowInner::GetScrollY(ErrorResult& aError) |
3599 | 0 | { |
3600 | 0 | FORWARD_TO_OUTER_OR_THROW(GetScrollYOuter, (), aError, 0); |
3601 | 0 | } |
3602 | | |
3603 | | uint32_t |
3604 | | nsGlobalWindowInner::Length() |
3605 | 0 | { |
3606 | 0 | FORWARD_TO_OUTER(Length, (), 0); |
3607 | 0 | } |
3608 | | |
3609 | | already_AddRefed<nsPIDOMWindowOuter> |
3610 | | nsGlobalWindowInner::GetTop(mozilla::ErrorResult& aError) |
3611 | 0 | { |
3612 | 0 | FORWARD_TO_OUTER_OR_THROW(GetTopOuter, (), aError, nullptr); |
3613 | 0 | } |
3614 | | |
3615 | | nsPIDOMWindowOuter* |
3616 | | nsGlobalWindowInner::GetChildWindow(const nsAString& aName) |
3617 | 0 | { |
3618 | 0 | if (GetOuterWindowInternal()) { |
3619 | 0 | return GetOuterWindowInternal()->GetChildWindow(aName); |
3620 | 0 | } |
3621 | 0 | return nullptr; |
3622 | 0 | } |
3623 | | |
3624 | | void |
3625 | | nsGlobalWindowInner::RefreshRealmPrincipal() |
3626 | 0 | { |
3627 | 0 | JS::SetRealmPrincipals(js::GetNonCCWObjectRealm(GetWrapperPreserveColor()), |
3628 | 0 | nsJSPrincipals::get(mDoc->NodePrincipal())); |
3629 | 0 | } |
3630 | | |
3631 | | already_AddRefed<nsIWidget> |
3632 | | nsGlobalWindowInner::GetMainWidget() |
3633 | 0 | { |
3634 | 0 | FORWARD_TO_OUTER(GetMainWidget, (), nullptr); |
3635 | 0 | } |
3636 | | |
3637 | | nsIWidget* |
3638 | | nsGlobalWindowInner::GetNearestWidget() const |
3639 | 0 | { |
3640 | 0 | if (GetOuterWindowInternal()) { |
3641 | 0 | return GetOuterWindowInternal()->GetNearestWidget(); |
3642 | 0 | } |
3643 | 0 | return nullptr; |
3644 | 0 | } |
3645 | | |
3646 | | void |
3647 | | nsGlobalWindowInner::SetFullScreen(bool aFullscreen, mozilla::ErrorResult& aError) |
3648 | 0 | { |
3649 | 0 | FORWARD_TO_OUTER_OR_THROW(SetFullscreenOuter, (aFullscreen, aError), aError, /* void */); |
3650 | 0 | } |
3651 | | |
3652 | | bool |
3653 | | nsGlobalWindowInner::GetFullScreen(ErrorResult& aError) |
3654 | 0 | { |
3655 | 0 | FORWARD_TO_OUTER_OR_THROW(GetFullscreenOuter, (), aError, false); |
3656 | 0 | } |
3657 | | |
3658 | | bool |
3659 | | nsGlobalWindowInner::GetFullScreen() |
3660 | 0 | { |
3661 | 0 | ErrorResult dummy; |
3662 | 0 | bool fullscreen = GetFullScreen(dummy); |
3663 | 0 | dummy.SuppressException(); |
3664 | 0 | return fullscreen; |
3665 | 0 | } |
3666 | | |
3667 | | void |
3668 | | nsGlobalWindowInner::Dump(const nsAString& aStr) |
3669 | 0 | { |
3670 | 0 | if (!DOMPrefs::DumpEnabled()) { |
3671 | 0 | return; |
3672 | 0 | } |
3673 | 0 | |
3674 | 0 | char *cstr = ToNewUTF8String(aStr); |
3675 | 0 |
|
3676 | | #if defined(XP_MACOSX) |
3677 | | // have to convert \r to \n so that printing to the console works |
3678 | | char *c = cstr, *cEnd = cstr + strlen(cstr); |
3679 | | while (c < cEnd) { |
3680 | | if (*c == '\r') |
3681 | | *c = '\n'; |
3682 | | c++; |
3683 | | } |
3684 | | #endif |
3685 | |
|
3686 | 0 | if (cstr) { |
3687 | 0 | MOZ_LOG(nsContentUtils::DOMDumpLog(), LogLevel::Debug, ("[Window.Dump] %s", cstr)); |
3688 | | #ifdef XP_WIN |
3689 | | PrintToDebugger(cstr); |
3690 | | #endif |
3691 | | #ifdef ANDROID |
3692 | | __android_log_write(ANDROID_LOG_INFO, "GeckoDump", cstr); |
3693 | | #endif |
3694 | 0 | FILE *fp = gDumpFile ? gDumpFile : stdout; |
3695 | 0 | fputs(cstr, fp); |
3696 | 0 | fflush(fp); |
3697 | 0 | free(cstr); |
3698 | 0 | } |
3699 | 0 | } |
3700 | | |
3701 | | void |
3702 | | nsGlobalWindowInner::Alert(nsIPrincipal& aSubjectPrincipal, |
3703 | | ErrorResult& aError) |
3704 | 0 | { |
3705 | 0 | Alert(EmptyString(), aSubjectPrincipal, aError); |
3706 | 0 | } |
3707 | | |
3708 | | void |
3709 | | nsGlobalWindowInner::Alert(const nsAString& aMessage, |
3710 | | nsIPrincipal& aSubjectPrincipal, |
3711 | | ErrorResult& aError) |
3712 | 0 | { |
3713 | 0 | FORWARD_TO_OUTER_OR_THROW(AlertOuter, (aMessage, aSubjectPrincipal, aError), |
3714 | 0 | aError, ); |
3715 | 0 | } |
3716 | | |
3717 | | bool |
3718 | | nsGlobalWindowInner::Confirm(const nsAString& aMessage, |
3719 | | nsIPrincipal& aSubjectPrincipal, |
3720 | | ErrorResult& aError) |
3721 | 0 | { |
3722 | 0 | FORWARD_TO_OUTER_OR_THROW(ConfirmOuter, (aMessage, aSubjectPrincipal, aError), |
3723 | 0 | aError, false); |
3724 | 0 | } |
3725 | | |
3726 | | already_AddRefed<Promise> |
3727 | | nsGlobalWindowInner::Fetch(const RequestOrUSVString& aInput, |
3728 | | const RequestInit& aInit, |
3729 | | CallerType aCallerType, ErrorResult& aRv) |
3730 | 0 | { |
3731 | 0 | return FetchRequest(this, aInput, aInit, aCallerType, aRv); |
3732 | 0 | } |
3733 | | |
3734 | | void |
3735 | | nsGlobalWindowInner::Prompt(const nsAString& aMessage, const nsAString& aInitial, |
3736 | | nsAString& aReturn, |
3737 | | nsIPrincipal& aSubjectPrincipal, |
3738 | | ErrorResult& aError) |
3739 | 0 | { |
3740 | 0 | FORWARD_TO_OUTER_OR_THROW(PromptOuter, |
3741 | 0 | (aMessage, aInitial, aReturn, aSubjectPrincipal, |
3742 | 0 | aError), |
3743 | 0 | aError, ); |
3744 | 0 | } |
3745 | | |
3746 | | void |
3747 | | nsGlobalWindowInner::Focus(ErrorResult& aError) |
3748 | 0 | { |
3749 | 0 | FORWARD_TO_OUTER_OR_THROW(FocusOuter, (aError), aError, ); |
3750 | 0 | } |
3751 | | |
3752 | | nsresult |
3753 | | nsGlobalWindowInner::Focus() |
3754 | 0 | { |
3755 | 0 | ErrorResult rv; |
3756 | 0 | Focus(rv); |
3757 | 0 |
|
3758 | 0 | return rv.StealNSResult(); |
3759 | 0 | } |
3760 | | |
3761 | | void |
3762 | | nsGlobalWindowInner::Blur(ErrorResult& aError) |
3763 | 0 | { |
3764 | 0 | FORWARD_TO_OUTER_OR_THROW(BlurOuter, (), aError, ); |
3765 | 0 | } |
3766 | | |
3767 | | void |
3768 | | nsGlobalWindowInner::Stop(ErrorResult& aError) |
3769 | 0 | { |
3770 | 0 | FORWARD_TO_OUTER_OR_THROW(StopOuter, (aError), aError, ); |
3771 | 0 | } |
3772 | | |
3773 | | /* static */ |
3774 | | bool |
3775 | | nsGlobalWindowInner::IsWindowPrintEnabled(JSContext*, JSObject*) |
3776 | 0 | { |
3777 | 0 | static bool called = false; |
3778 | 0 | static bool printDisabled = false; |
3779 | 0 | if (!called) { |
3780 | 0 | called = true; |
3781 | 0 | Preferences::AddBoolVarCache(&printDisabled, "dom.disable_window_print"); |
3782 | 0 | } |
3783 | 0 | return !printDisabled; |
3784 | 0 | } |
3785 | | |
3786 | | void |
3787 | | nsGlobalWindowInner::Print(ErrorResult& aError) |
3788 | 0 | { |
3789 | 0 | FORWARD_TO_OUTER_OR_THROW(PrintOuter, (aError), aError, ); |
3790 | 0 | } |
3791 | | |
3792 | | void |
3793 | | nsGlobalWindowInner::MoveTo(int32_t aXPos, int32_t aYPos, |
3794 | | CallerType aCallerType, ErrorResult& aError) |
3795 | 0 | { |
3796 | 0 | FORWARD_TO_OUTER_OR_THROW(MoveToOuter, |
3797 | 0 | (aXPos, aYPos, aCallerType, aError), aError, ); |
3798 | 0 | } |
3799 | | |
3800 | | void |
3801 | | nsGlobalWindowInner::MoveBy(int32_t aXDif, int32_t aYDif, |
3802 | | CallerType aCallerType, ErrorResult& aError) |
3803 | 0 | { |
3804 | 0 | FORWARD_TO_OUTER_OR_THROW(MoveByOuter, |
3805 | 0 | (aXDif, aYDif, aCallerType, aError), aError, ); |
3806 | 0 | } |
3807 | | |
3808 | | void |
3809 | | nsGlobalWindowInner::ResizeTo(int32_t aWidth, int32_t aHeight, |
3810 | | CallerType aCallerType, ErrorResult& aError) |
3811 | 0 | { |
3812 | 0 | FORWARD_TO_OUTER_OR_THROW(ResizeToOuter, |
3813 | 0 | (aWidth, aHeight, aCallerType, aError), aError, ); |
3814 | 0 | } |
3815 | | |
3816 | | void |
3817 | | nsGlobalWindowInner::ResizeBy(int32_t aWidthDif, int32_t aHeightDif, |
3818 | | CallerType aCallerType, ErrorResult& aError) |
3819 | 0 | { |
3820 | 0 | FORWARD_TO_OUTER_OR_THROW(ResizeByOuter, |
3821 | 0 | (aWidthDif, aHeightDif, aCallerType, aError), |
3822 | 0 | aError, ); |
3823 | 0 | } |
3824 | | |
3825 | | void |
3826 | | nsGlobalWindowInner::SizeToContent(CallerType aCallerType, ErrorResult& aError) |
3827 | 0 | { |
3828 | 0 | FORWARD_TO_OUTER_OR_THROW(SizeToContentOuter, (aCallerType, aError), |
3829 | 0 | aError, ); |
3830 | 0 | } |
3831 | | |
3832 | | already_AddRefed<nsPIWindowRoot> |
3833 | | nsGlobalWindowInner::GetTopWindowRoot() |
3834 | 0 | { |
3835 | 0 | nsGlobalWindowOuter* outer = GetOuterWindowInternal(); |
3836 | 0 | if (!outer) { |
3837 | 0 | return nullptr; |
3838 | 0 | } |
3839 | 0 | return outer->GetTopWindowRoot(); |
3840 | 0 | } |
3841 | | |
3842 | | void |
3843 | | nsGlobalWindowInner::Scroll(double aXScroll, double aYScroll) |
3844 | 0 | { |
3845 | 0 | // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast. |
3846 | 0 | auto scrollPos = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll), |
3847 | 0 | mozilla::ToZeroIfNonfinite(aYScroll)); |
3848 | 0 | ScrollTo(scrollPos, ScrollOptions()); |
3849 | 0 | } |
3850 | | |
3851 | | void |
3852 | | nsGlobalWindowInner::ScrollTo(double aXScroll, double aYScroll) |
3853 | 0 | { |
3854 | 0 | // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast. |
3855 | 0 | auto scrollPos = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll), |
3856 | 0 | mozilla::ToZeroIfNonfinite(aYScroll)); |
3857 | 0 | ScrollTo(scrollPos, ScrollOptions()); |
3858 | 0 | } |
3859 | | |
3860 | | void |
3861 | | nsGlobalWindowInner::ScrollTo(const ScrollToOptions& aOptions) |
3862 | 0 | { |
3863 | 0 | // When scrolling to a non-zero offset, we need to determine whether that |
3864 | 0 | // position is within our scrollable range, so we need updated layout |
3865 | 0 | // information which requires a layout flush, otherwise all we need is to |
3866 | 0 | // flush frames to be able to access our scrollable frame here. |
3867 | 0 | FlushType flushType = ((aOptions.mLeft.WasPassed() && |
3868 | 0 | aOptions.mLeft.Value() > 0) || |
3869 | 0 | (aOptions.mTop.WasPassed() && |
3870 | 0 | aOptions.mTop.Value() > 0)) ? |
3871 | 0 | FlushType::Layout : |
3872 | 0 | FlushType::Frames; |
3873 | 0 | FlushPendingNotifications(flushType); |
3874 | 0 | nsIScrollableFrame *sf = GetScrollFrame(); |
3875 | 0 |
|
3876 | 0 | if (sf) { |
3877 | 0 | CSSIntPoint scrollPos = sf->GetScrollPositionCSSPixels(); |
3878 | 0 | if (aOptions.mLeft.WasPassed()) { |
3879 | 0 | scrollPos.x = mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value()); |
3880 | 0 | } |
3881 | 0 | if (aOptions.mTop.WasPassed()) { |
3882 | 0 | scrollPos.y = mozilla::ToZeroIfNonfinite(aOptions.mTop.Value()); |
3883 | 0 | } |
3884 | 0 |
|
3885 | 0 | ScrollTo(scrollPos, aOptions); |
3886 | 0 | } |
3887 | 0 | } |
3888 | | |
3889 | | void |
3890 | | nsGlobalWindowInner::Scroll(const ScrollToOptions& aOptions) |
3891 | 0 | { |
3892 | 0 | ScrollTo(aOptions); |
3893 | 0 | } |
3894 | | |
3895 | | void |
3896 | | nsGlobalWindowInner::ScrollTo(const CSSIntPoint& aScroll, |
3897 | | const ScrollOptions& aOptions) |
3898 | 0 | { |
3899 | 0 | // When scrolling to a non-zero offset, we need to determine whether that |
3900 | 0 | // position is within our scrollable range, so we need updated layout |
3901 | 0 | // information which requires a layout flush, otherwise all we need is to |
3902 | 0 | // flush frames to be able to access our scrollable frame here. |
3903 | 0 | FlushType flushType = (aScroll.x || aScroll.y) ? |
3904 | 0 | FlushType::Layout : |
3905 | 0 | FlushType::Frames; |
3906 | 0 | FlushPendingNotifications(flushType); |
3907 | 0 | nsIScrollableFrame *sf = GetScrollFrame(); |
3908 | 0 |
|
3909 | 0 | if (sf) { |
3910 | 0 | // Here we calculate what the max pixel value is that we can |
3911 | 0 | // scroll to, we do this by dividing maxint with the pixel to |
3912 | 0 | // twips conversion factor, and subtracting 4, the 4 comes from |
3913 | 0 | // experimenting with this value, anything less makes the view |
3914 | 0 | // code not scroll correctly, I have no idea why. -- jst |
3915 | 0 | const int32_t maxpx = nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff) - 4; |
3916 | 0 |
|
3917 | 0 | CSSIntPoint scroll(aScroll); |
3918 | 0 | if (scroll.x > maxpx) { |
3919 | 0 | scroll.x = maxpx; |
3920 | 0 | } |
3921 | 0 |
|
3922 | 0 | if (scroll.y > maxpx) { |
3923 | 0 | scroll.y = maxpx; |
3924 | 0 | } |
3925 | 0 |
|
3926 | 0 | bool smoothScroll = sf->GetScrollStyles().IsSmoothScroll(aOptions.mBehavior); |
3927 | 0 |
|
3928 | 0 | sf->ScrollToCSSPixels(scroll, smoothScroll |
3929 | 0 | ? nsIScrollableFrame::SMOOTH_MSD |
3930 | 0 | : nsIScrollableFrame::INSTANT); |
3931 | 0 | } |
3932 | 0 | } |
3933 | | |
3934 | | void |
3935 | | nsGlobalWindowInner::ScrollBy(double aXScrollDif, double aYScrollDif) |
3936 | 0 | { |
3937 | 0 | FlushPendingNotifications(FlushType::Layout); |
3938 | 0 | nsIScrollableFrame *sf = GetScrollFrame(); |
3939 | 0 |
|
3940 | 0 | if (sf) { |
3941 | 0 | // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast. |
3942 | 0 | auto scrollDif = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScrollDif), |
3943 | 0 | mozilla::ToZeroIfNonfinite(aYScrollDif)); |
3944 | 0 | // It seems like it would make more sense for ScrollBy to use |
3945 | 0 | // SMOOTH mode, but tests seem to depend on the synchronous behaviour. |
3946 | 0 | // Perhaps Web content does too. |
3947 | 0 | ScrollTo(sf->GetScrollPositionCSSPixels() + scrollDif, ScrollOptions()); |
3948 | 0 | } |
3949 | 0 | } |
3950 | | |
3951 | | void |
3952 | | nsGlobalWindowInner::ScrollBy(const ScrollToOptions& aOptions) |
3953 | 0 | { |
3954 | 0 | FlushPendingNotifications(FlushType::Layout); |
3955 | 0 | nsIScrollableFrame *sf = GetScrollFrame(); |
3956 | 0 |
|
3957 | 0 | if (sf) { |
3958 | 0 | CSSIntPoint scrollPos = sf->GetScrollPositionCSSPixels(); |
3959 | 0 | if (aOptions.mLeft.WasPassed()) { |
3960 | 0 | scrollPos.x += mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value()); |
3961 | 0 | } |
3962 | 0 | if (aOptions.mTop.WasPassed()) { |
3963 | 0 | scrollPos.y += mozilla::ToZeroIfNonfinite(aOptions.mTop.Value()); |
3964 | 0 | } |
3965 | 0 |
|
3966 | 0 | ScrollTo(scrollPos, aOptions); |
3967 | 0 | } |
3968 | 0 | } |
3969 | | |
3970 | | void |
3971 | | nsGlobalWindowInner::ScrollByLines(int32_t numLines, |
3972 | | const ScrollOptions& aOptions) |
3973 | 0 | { |
3974 | 0 | FlushPendingNotifications(FlushType::Layout); |
3975 | 0 | nsIScrollableFrame *sf = GetScrollFrame(); |
3976 | 0 | if (sf) { |
3977 | 0 | // It seems like it would make more sense for ScrollByLines to use |
3978 | 0 | // SMOOTH mode, but tests seem to depend on the synchronous behaviour. |
3979 | 0 | // Perhaps Web content does too. |
3980 | 0 | bool smoothScroll = sf->GetScrollStyles().IsSmoothScroll(aOptions.mBehavior); |
3981 | 0 |
|
3982 | 0 | sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES, |
3983 | 0 | smoothScroll |
3984 | 0 | ? nsIScrollableFrame::SMOOTH_MSD |
3985 | 0 | : nsIScrollableFrame::INSTANT); |
3986 | 0 | } |
3987 | 0 | } |
3988 | | |
3989 | | void |
3990 | | nsGlobalWindowInner::ScrollByPages(int32_t numPages, |
3991 | | const ScrollOptions& aOptions) |
3992 | 0 | { |
3993 | 0 | FlushPendingNotifications(FlushType::Layout); |
3994 | 0 | nsIScrollableFrame *sf = GetScrollFrame(); |
3995 | 0 | if (sf) { |
3996 | 0 | // It seems like it would make more sense for ScrollByPages to use |
3997 | 0 | // SMOOTH mode, but tests seem to depend on the synchronous behaviour. |
3998 | 0 | // Perhaps Web content does too. |
3999 | 0 | bool smoothScroll = sf->GetScrollStyles().IsSmoothScroll(aOptions.mBehavior); |
4000 | 0 |
|
4001 | 0 | sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES, |
4002 | 0 | smoothScroll |
4003 | 0 | ? nsIScrollableFrame::SMOOTH_MSD |
4004 | 0 | : nsIScrollableFrame::INSTANT); |
4005 | 0 | } |
4006 | 0 | } |
4007 | | |
4008 | | void |
4009 | | nsGlobalWindowInner::MozScrollSnap() |
4010 | 0 | { |
4011 | 0 | FlushPendingNotifications(FlushType::Layout); |
4012 | 0 | nsIScrollableFrame *sf = GetScrollFrame(); |
4013 | 0 | if (sf) { |
4014 | 0 | sf->ScrollSnap(); |
4015 | 0 | } |
4016 | 0 | } |
4017 | | |
4018 | | void |
4019 | | nsGlobalWindowInner::ClearTimeout(int32_t aHandle) |
4020 | 0 | { |
4021 | 0 | if (aHandle > 0) { |
4022 | 0 | mTimeoutManager->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval); |
4023 | 0 | } |
4024 | 0 | } |
4025 | | |
4026 | | void |
4027 | | nsGlobalWindowInner::ClearInterval(int32_t aHandle) |
4028 | 0 | { |
4029 | 0 | if (aHandle > 0) { |
4030 | 0 | mTimeoutManager->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval); |
4031 | 0 | } |
4032 | 0 | } |
4033 | | |
4034 | | void |
4035 | | nsGlobalWindowInner::SetResizable(bool aResizable) const |
4036 | 0 | { |
4037 | 0 | // nop |
4038 | 0 | } |
4039 | | |
4040 | | void |
4041 | | nsGlobalWindowInner::CaptureEvents() |
4042 | 0 | { |
4043 | 0 | if (mDoc) { |
4044 | 0 | mDoc->WarnOnceAbout(nsIDocument::eUseOfCaptureEvents); |
4045 | 0 | } |
4046 | 0 | } |
4047 | | |
4048 | | void |
4049 | | nsGlobalWindowInner::ReleaseEvents() |
4050 | 0 | { |
4051 | 0 | if (mDoc) { |
4052 | 0 | mDoc->WarnOnceAbout(nsIDocument::eUseOfReleaseEvents); |
4053 | 0 | } |
4054 | 0 | } |
4055 | | |
4056 | | already_AddRefed<nsPIDOMWindowOuter> |
4057 | | nsGlobalWindowInner::Open(const nsAString& aUrl, const nsAString& aName, |
4058 | | const nsAString& aOptions, ErrorResult& aError) |
4059 | 0 | { |
4060 | 0 | FORWARD_TO_OUTER_OR_THROW(OpenOuter, (aUrl, aName, aOptions, aError), aError, |
4061 | 0 | nullptr); |
4062 | 0 | } |
4063 | | |
4064 | | already_AddRefed<nsPIDOMWindowOuter> |
4065 | | nsGlobalWindowInner::OpenDialog(JSContext* aCx, const nsAString& aUrl, |
4066 | | const nsAString& aName, const nsAString& aOptions, |
4067 | | const Sequence<JS::Value>& aExtraArgument, |
4068 | | ErrorResult& aError) |
4069 | 0 | { |
4070 | 0 | FORWARD_TO_OUTER_OR_THROW(OpenDialogOuter, |
4071 | 0 | (aCx, aUrl, aName, aOptions, aExtraArgument, aError), |
4072 | 0 | aError, nullptr); |
4073 | 0 | } |
4074 | | |
4075 | | already_AddRefed<nsPIDOMWindowOuter> |
4076 | | nsGlobalWindowInner::GetFrames(ErrorResult& aError) |
4077 | 0 | { |
4078 | 0 | FORWARD_TO_OUTER_OR_THROW(GetFramesOuter, (), aError, nullptr); |
4079 | 0 | } |
4080 | | |
4081 | | void |
4082 | | nsGlobalWindowInner::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage, |
4083 | | const nsAString& aTargetOrigin, |
4084 | | JS::Handle<JS::Value> aTransfer, |
4085 | | nsIPrincipal& aSubjectPrincipal, |
4086 | | ErrorResult& aError) |
4087 | 0 | { |
4088 | 0 | FORWARD_TO_OUTER_OR_THROW(PostMessageMozOuter, |
4089 | 0 | (aCx, aMessage, aTargetOrigin, aTransfer, |
4090 | 0 | aSubjectPrincipal, aError), |
4091 | 0 | aError, ); |
4092 | 0 | } |
4093 | | |
4094 | | void |
4095 | | nsGlobalWindowInner::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage, |
4096 | | const nsAString& aTargetOrigin, |
4097 | | const Sequence<JSObject*>& aTransfer, |
4098 | | nsIPrincipal& aSubjectPrincipal, |
4099 | | ErrorResult& aRv) |
4100 | 0 | { |
4101 | 0 | JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue()); |
4102 | 0 |
|
4103 | 0 | aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransfer, |
4104 | 0 | &transferArray); |
4105 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
4106 | 0 | return; |
4107 | 0 | } |
4108 | 0 | |
4109 | 0 | PostMessageMoz(aCx, aMessage, aTargetOrigin, transferArray, |
4110 | 0 | aSubjectPrincipal, aRv); |
4111 | 0 | } |
4112 | | |
4113 | | void |
4114 | | nsGlobalWindowInner::Close(ErrorResult& aError) |
4115 | 0 | { |
4116 | 0 | FORWARD_TO_OUTER_OR_THROW(CloseOuter, (nsContentUtils::IsCallerChrome()), aError, ); |
4117 | 0 | } |
4118 | | |
4119 | | nsresult |
4120 | | nsGlobalWindowInner::Close() |
4121 | 0 | { |
4122 | 0 | FORWARD_TO_OUTER(Close, (), NS_ERROR_UNEXPECTED); |
4123 | 0 | } |
4124 | | |
4125 | | bool |
4126 | | nsGlobalWindowInner::IsInModalState() |
4127 | 0 | { |
4128 | 0 | FORWARD_TO_OUTER(IsInModalState, (), false); |
4129 | 0 | } |
4130 | | |
4131 | | // static |
4132 | | void |
4133 | | nsGlobalWindowInner::NotifyDOMWindowDestroyed(nsGlobalWindowInner* aWindow) |
4134 | 0 | { |
4135 | 0 | nsCOMPtr<nsIObserverService> observerService = |
4136 | 0 | services::GetObserverService(); |
4137 | 0 | if (observerService) { |
4138 | 0 | observerService-> |
4139 | 0 | NotifyObservers(ToSupports(aWindow), |
4140 | 0 | DOM_WINDOW_DESTROYED_TOPIC, nullptr); |
4141 | 0 | } |
4142 | 0 | } |
4143 | | |
4144 | | void |
4145 | | nsGlobalWindowInner::NotifyWindowIDDestroyed(const char* aTopic) |
4146 | 0 | { |
4147 | 0 | nsCOMPtr<nsIRunnable> runnable = |
4148 | 0 | new WindowDestroyedEvent(this, mWindowID, aTopic); |
4149 | 0 | Dispatch(TaskCategory::Other, runnable.forget()); |
4150 | 0 | } |
4151 | | |
4152 | | // static |
4153 | | void |
4154 | | nsGlobalWindowInner::NotifyDOMWindowFrozen(nsGlobalWindowInner* aWindow) |
4155 | 0 | { |
4156 | 0 | if (aWindow) { |
4157 | 0 | nsCOMPtr<nsIObserverService> observerService = |
4158 | 0 | services::GetObserverService(); |
4159 | 0 | if (observerService) { |
4160 | 0 | observerService-> |
4161 | 0 | NotifyObservers(ToSupports(aWindow), |
4162 | 0 | DOM_WINDOW_FROZEN_TOPIC, nullptr); |
4163 | 0 | } |
4164 | 0 | } |
4165 | 0 | } |
4166 | | |
4167 | | // static |
4168 | | void |
4169 | | nsGlobalWindowInner::NotifyDOMWindowThawed(nsGlobalWindowInner* aWindow) |
4170 | 0 | { |
4171 | 0 | if (aWindow) { |
4172 | 0 | nsCOMPtr<nsIObserverService> observerService = |
4173 | 0 | services::GetObserverService(); |
4174 | 0 | if (observerService) { |
4175 | 0 | observerService-> |
4176 | 0 | NotifyObservers(ToSupports(aWindow), |
4177 | 0 | DOM_WINDOW_THAWED_TOPIC, nullptr); |
4178 | 0 | } |
4179 | 0 | } |
4180 | 0 | } |
4181 | | |
4182 | | JSObject* |
4183 | | nsGlobalWindowInner::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey) |
4184 | 0 | { |
4185 | 0 | JS::Rooted<JSObject*> handler(RootingCx()); |
4186 | 0 | if (mCachedXBLPrototypeHandlers) { |
4187 | 0 | mCachedXBLPrototypeHandlers->Get(aKey, handler.address()); |
4188 | 0 | } |
4189 | 0 | return handler; |
4190 | 0 | } |
4191 | | |
4192 | | void |
4193 | | nsGlobalWindowInner::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey, |
4194 | | JS::Handle<JSObject*> aHandler) |
4195 | 0 | { |
4196 | 0 | if (!mCachedXBLPrototypeHandlers) { |
4197 | 0 | mCachedXBLPrototypeHandlers = MakeUnique<XBLPrototypeHandlerTable>(); |
4198 | 0 | PreserveWrapper(ToSupports(this)); |
4199 | 0 | } |
4200 | 0 |
|
4201 | 0 | mCachedXBLPrototypeHandlers->Put(aKey, aHandler); |
4202 | 0 | } |
4203 | | |
4204 | | Element* |
4205 | | nsGlobalWindowInner::GetFrameElement(nsIPrincipal& aSubjectPrincipal, |
4206 | | ErrorResult& aError) |
4207 | 0 | { |
4208 | 0 | FORWARD_TO_OUTER_OR_THROW(GetFrameElementOuter, (aSubjectPrincipal), aError, |
4209 | 0 | nullptr); |
4210 | 0 | } |
4211 | | |
4212 | | Element* |
4213 | | nsGlobalWindowInner::GetRealFrameElement(ErrorResult& aError) |
4214 | 0 | { |
4215 | 0 | FORWARD_TO_OUTER_OR_THROW(GetRealFrameElementOuter, (), aError, nullptr); |
4216 | 0 | } |
4217 | | |
4218 | | /** |
4219 | | * nsIGlobalWindow::GetFrameElement (when called from C++) is just a wrapper |
4220 | | * around GetRealFrameElement. |
4221 | | */ |
4222 | | Element* |
4223 | | nsGlobalWindowInner::GetFrameElement() |
4224 | 0 | { |
4225 | 0 | return GetRealFrameElement(IgnoreErrors()); |
4226 | 0 | } |
4227 | | |
4228 | | void |
4229 | | nsGlobalWindowInner::UpdateCommands(const nsAString& anAction, |
4230 | | Selection* aSel, |
4231 | | int16_t aReason) |
4232 | 0 | { |
4233 | 0 | if (GetOuterWindowInternal()) { |
4234 | 0 | GetOuterWindowInternal()->UpdateCommands(anAction, aSel, aReason); |
4235 | 0 | } |
4236 | 0 | } |
4237 | | |
4238 | | Selection* |
4239 | | nsGlobalWindowInner::GetSelection(ErrorResult& aError) |
4240 | 0 | { |
4241 | 0 | FORWARD_TO_OUTER_OR_THROW(GetSelectionOuter, (), aError, nullptr); |
4242 | 0 | } |
4243 | | |
4244 | | bool |
4245 | | nsGlobalWindowInner::Find(const nsAString& aString, bool aCaseSensitive, |
4246 | | bool aBackwards, bool aWrapAround, bool aWholeWord, |
4247 | | bool aSearchInFrames, bool aShowDialog, |
4248 | | ErrorResult& aError) |
4249 | 0 | { |
4250 | 0 | FORWARD_TO_OUTER_OR_THROW(FindOuter, |
4251 | 0 | (aString, aCaseSensitive, aBackwards, aWrapAround, |
4252 | 0 | aWholeWord, aSearchInFrames, aShowDialog, aError), |
4253 | 0 | aError, false); |
4254 | 0 | } |
4255 | | |
4256 | | void |
4257 | | nsGlobalWindowInner::GetOrigin(nsAString& aOrigin) |
4258 | 0 | { |
4259 | 0 | nsContentUtils::GetUTFOrigin(GetPrincipal(), aOrigin); |
4260 | 0 | } |
4261 | | |
4262 | | void |
4263 | | nsGlobalWindowInner::Atob(const nsAString& aAsciiBase64String, |
4264 | | nsAString& aBinaryData, ErrorResult& aError) |
4265 | 0 | { |
4266 | 0 | aError = nsContentUtils::Atob(aAsciiBase64String, aBinaryData); |
4267 | 0 | } |
4268 | | |
4269 | | void |
4270 | | nsGlobalWindowInner::Btoa(const nsAString& aBinaryData, |
4271 | | nsAString& aAsciiBase64String, ErrorResult& aError) |
4272 | 0 | { |
4273 | 0 | aError = nsContentUtils::Btoa(aBinaryData, aAsciiBase64String); |
4274 | 0 | } |
4275 | | |
4276 | | //***************************************************************************** |
4277 | | // EventTarget |
4278 | | //***************************************************************************** |
4279 | | |
4280 | | nsPIDOMWindowOuter* |
4281 | | nsGlobalWindowInner::GetOwnerGlobalForBindings() |
4282 | 0 | { |
4283 | 0 | return nsPIDOMWindowOuter::GetFromCurrentInner(this); |
4284 | 0 | } |
4285 | | |
4286 | | bool |
4287 | | nsGlobalWindowInner::DispatchEvent(Event& aEvent, |
4288 | | CallerType aCallerType, |
4289 | | ErrorResult& aRv) |
4290 | 0 | { |
4291 | 0 | if (!IsCurrentInnerWindow()) { |
4292 | 0 | NS_WARNING("DispatchEvent called on non-current inner window, dropping. " |
4293 | 0 | "Please check the window in the caller instead."); |
4294 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
4295 | 0 | return false; |
4296 | 0 | } |
4297 | 0 |
|
4298 | 0 | if (!mDoc) { |
4299 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
4300 | 0 | return false; |
4301 | 0 | } |
4302 | 0 | |
4303 | 0 | // Obtain a presentation shell |
4304 | 0 | RefPtr<nsPresContext> presContext = mDoc->GetPresContext(); |
4305 | 0 |
|
4306 | 0 | nsEventStatus status = nsEventStatus_eIgnore; |
4307 | 0 | nsresult rv = EventDispatcher::DispatchDOMEvent(ToSupports(this), nullptr, |
4308 | 0 | &aEvent, presContext, &status); |
4309 | 0 | bool retval = !aEvent.DefaultPrevented(aCallerType); |
4310 | 0 | if (NS_FAILED(rv)) { |
4311 | 0 | aRv.Throw(rv); |
4312 | 0 | } |
4313 | 0 | return retval; |
4314 | 0 | } |
4315 | | |
4316 | | bool |
4317 | | nsGlobalWindowInner::ComputeDefaultWantsUntrusted(ErrorResult& aRv) |
4318 | 0 | { |
4319 | 0 | return !nsContentUtils::IsChromeDoc(mDoc); |
4320 | 0 | } |
4321 | | |
4322 | | EventListenerManager* |
4323 | | nsGlobalWindowInner::GetOrCreateListenerManager() |
4324 | 0 | { |
4325 | 0 | if (!mListenerManager) { |
4326 | 0 | mListenerManager = |
4327 | 0 | new EventListenerManager(static_cast<EventTarget*>(this)); |
4328 | 0 | } |
4329 | 0 |
|
4330 | 0 | return mListenerManager; |
4331 | 0 | } |
4332 | | |
4333 | | EventListenerManager* |
4334 | | nsGlobalWindowInner::GetExistingListenerManager() const |
4335 | 0 | { |
4336 | 0 | return mListenerManager; |
4337 | 0 | } |
4338 | | |
4339 | | //***************************************************************************** |
4340 | | // nsGlobalWindowInner::nsPIDOMWindow |
4341 | | //***************************************************************************** |
4342 | | |
4343 | | nsPIDOMWindowOuter* |
4344 | | nsGlobalWindowInner::GetPrivateRoot() |
4345 | 0 | { |
4346 | 0 | nsGlobalWindowOuter* outer = GetOuterWindowInternal(); |
4347 | 0 | if (!outer) { |
4348 | 0 | NS_WARNING("No outer window available!"); |
4349 | 0 | return nullptr; |
4350 | 0 | } |
4351 | 0 | return outer->GetPrivateRoot(); |
4352 | 0 | } |
4353 | | |
4354 | | Location* |
4355 | | nsGlobalWindowInner::GetLocation() |
4356 | 0 | { |
4357 | 0 | if (!mLocation) { |
4358 | 0 | mLocation = new dom::Location(this, GetDocShell()); |
4359 | 0 | } |
4360 | 0 |
|
4361 | 0 | return mLocation; |
4362 | 0 | } |
4363 | | |
4364 | | bool |
4365 | | nsGlobalWindowInner::IsTopLevelWindowActive() |
4366 | 0 | { |
4367 | 0 | if (GetOuterWindowInternal()) { |
4368 | 0 | return GetOuterWindowInternal()->IsTopLevelWindowActive(); |
4369 | 0 | } |
4370 | 0 | return false; |
4371 | 0 | } |
4372 | | |
4373 | | void |
4374 | | nsGlobalWindowInner::MaybeUpdateTouchState() |
4375 | 0 | { |
4376 | 0 | if (mMayHaveTouchEventListener) { |
4377 | 0 | nsCOMPtr<nsIObserverService> observerService = |
4378 | 0 | services::GetObserverService(); |
4379 | 0 |
|
4380 | 0 | if (observerService) { |
4381 | 0 | observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this), |
4382 | 0 | DOM_TOUCH_LISTENER_ADDED, |
4383 | 0 | nullptr); |
4384 | 0 | } |
4385 | 0 | } |
4386 | 0 | } |
4387 | | |
4388 | | void |
4389 | | nsGlobalWindowInner::EnableGamepadUpdates() |
4390 | 0 | { |
4391 | 0 | if (mHasGamepad) { |
4392 | 0 | RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService()); |
4393 | 0 | if (gamepadManager) { |
4394 | 0 | gamepadManager->AddListener(this); |
4395 | 0 | } |
4396 | 0 | } |
4397 | 0 | } |
4398 | | |
4399 | | void |
4400 | | nsGlobalWindowInner::DisableGamepadUpdates() |
4401 | 0 | { |
4402 | 0 | if (mHasGamepad) { |
4403 | 0 | RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService()); |
4404 | 0 | if (gamepadManager) { |
4405 | 0 | gamepadManager->RemoveListener(this); |
4406 | 0 | } |
4407 | 0 | } |
4408 | 0 | } |
4409 | | |
4410 | | void |
4411 | | nsGlobalWindowInner::EnableVRUpdates() |
4412 | 0 | { |
4413 | 0 | if (mHasVREvents && !mVREventObserver) { |
4414 | 0 | mVREventObserver = new VREventObserver(this); |
4415 | 0 | } |
4416 | 0 | } |
4417 | | |
4418 | | void |
4419 | | nsGlobalWindowInner::DisableVRUpdates() |
4420 | 0 | { |
4421 | 0 | if (mVREventObserver) { |
4422 | 0 | mVREventObserver->DisconnectFromOwner(); |
4423 | 0 | mVREventObserver = nullptr; |
4424 | 0 | } |
4425 | 0 | } |
4426 | | |
4427 | | void |
4428 | | nsGlobalWindowInner::ResetVRTelemetry(bool aUpdate) |
4429 | 0 | { |
4430 | 0 | if (mVREventObserver) { |
4431 | 0 | mVREventObserver->UpdateSpentTimeIn2DTelemetry(aUpdate); |
4432 | 0 | } |
4433 | 0 | } |
4434 | | |
4435 | | #ifndef XP_WIN // This guard should match the guard at the callsite. |
4436 | | static bool ShouldShowFocusRingIfFocusedByMouse(nsIContent* aNode) |
4437 | 0 | { |
4438 | 0 | if (!aNode) { |
4439 | 0 | return true; |
4440 | 0 | } |
4441 | 0 | return !nsContentUtils::ContentIsLink(aNode) && |
4442 | 0 | !aNode->IsAnyOfHTMLElements(nsGkAtoms::video, nsGkAtoms::audio); |
4443 | 0 | } |
4444 | | #endif |
4445 | | |
4446 | | void |
4447 | | nsGlobalWindowInner::SetFocusedElement(Element* aElement, |
4448 | | uint32_t aFocusMethod, |
4449 | | bool aNeedsFocus) |
4450 | 0 | { |
4451 | 0 | if (aElement && aElement->GetComposedDoc() != mDoc) { |
4452 | 0 | NS_WARNING("Trying to set focus to a node from a wrong document"); |
4453 | 0 | return; |
4454 | 0 | } |
4455 | 0 |
|
4456 | 0 | if (IsDying()) { |
4457 | 0 | NS_ASSERTION(!aElement, "Trying to focus cleaned up window!"); |
4458 | 0 | aElement = nullptr; |
4459 | 0 | aNeedsFocus = false; |
4460 | 0 | } |
4461 | 0 | if (mFocusedElement != aElement) { |
4462 | 0 | UpdateCanvasFocus(false, aElement); |
4463 | 0 | mFocusedElement = aElement; |
4464 | 0 | mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK; |
4465 | 0 | mShowFocusRingForContent = false; |
4466 | 0 | } |
4467 | 0 |
|
4468 | 0 | if (mFocusedElement) { |
4469 | 0 | // if a node was focused by a keypress, turn on focus rings for the |
4470 | 0 | // window. |
4471 | 0 | if (mFocusMethod & nsIFocusManager::FLAG_BYKEY) { |
4472 | 0 | mFocusByKeyOccurred = true; |
4473 | 0 | } else if ( |
4474 | 0 | // otherwise, we set mShowFocusRingForContent, as we don't want this to |
4475 | 0 | // be permanent for the window. On Windows, focus rings are only shown |
4476 | 0 | // when the FLAG_SHOWRING flag is used. On other platforms, focus rings |
4477 | 0 | // are only visible on some elements. |
4478 | 0 | #ifndef XP_WIN |
4479 | 0 | !(mFocusMethod & nsIFocusManager::FLAG_BYMOUSE) || |
4480 | 0 | ShouldShowFocusRingIfFocusedByMouse(aElement) || |
4481 | 0 | #endif |
4482 | 0 | aFocusMethod & nsIFocusManager::FLAG_SHOWRING) { |
4483 | 0 | mShowFocusRingForContent = true; |
4484 | 0 | } |
4485 | 0 | } |
4486 | 0 |
|
4487 | 0 | if (aNeedsFocus) |
4488 | 0 | mNeedsFocus = aNeedsFocus; |
4489 | 0 | } |
4490 | | |
4491 | | uint32_t |
4492 | | nsGlobalWindowInner::GetFocusMethod() |
4493 | 0 | { |
4494 | 0 | return mFocusMethod; |
4495 | 0 | } |
4496 | | |
4497 | | bool |
4498 | | nsGlobalWindowInner::ShouldShowFocusRing() |
4499 | 0 | { |
4500 | 0 | if (mShowFocusRingForContent || mFocusByKeyOccurred) { |
4501 | 0 | return true; |
4502 | 0 | } |
4503 | 0 | |
4504 | 0 | nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot(); |
4505 | 0 | return root ? root->ShowFocusRings() : false; |
4506 | 0 | } |
4507 | | |
4508 | | bool |
4509 | | nsGlobalWindowInner::TakeFocus(bool aFocus, uint32_t aFocusMethod) |
4510 | 0 | { |
4511 | 0 | if (IsDying()) { |
4512 | 0 | return false; |
4513 | 0 | } |
4514 | 0 | |
4515 | 0 | if (aFocus) |
4516 | 0 | mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK; |
4517 | 0 |
|
4518 | 0 | if (mHasFocus != aFocus) { |
4519 | 0 | mHasFocus = aFocus; |
4520 | 0 | UpdateCanvasFocus(true, mFocusedElement); |
4521 | 0 | } |
4522 | 0 |
|
4523 | 0 | // if mNeedsFocus is true, then the document has not yet received a |
4524 | 0 | // document-level focus event. If there is a root content node, then return |
4525 | 0 | // true to tell the calling focus manager that a focus event is expected. If |
4526 | 0 | // there is no root content node, the document hasn't loaded enough yet, or |
4527 | 0 | // there isn't one and there is no point in firing a focus event. |
4528 | 0 | if (aFocus && mNeedsFocus && mDoc && mDoc->GetRootElement() != nullptr) { |
4529 | 0 | mNeedsFocus = false; |
4530 | 0 | return true; |
4531 | 0 | } |
4532 | 0 | |
4533 | 0 | mNeedsFocus = false; |
4534 | 0 | return false; |
4535 | 0 | } |
4536 | | |
4537 | | void |
4538 | | nsGlobalWindowInner::SetReadyForFocus() |
4539 | 0 | { |
4540 | 0 | bool oldNeedsFocus = mNeedsFocus; |
4541 | 0 | mNeedsFocus = false; |
4542 | 0 |
|
4543 | 0 | nsIFocusManager* fm = nsFocusManager::GetFocusManager(); |
4544 | 0 | if (fm) { |
4545 | 0 | fm->WindowShown(GetOuterWindow(), oldNeedsFocus); |
4546 | 0 | } |
4547 | 0 | } |
4548 | | |
4549 | | void |
4550 | | nsGlobalWindowInner::PageHidden() |
4551 | 0 | { |
4552 | 0 | // the window is being hidden, so tell the focus manager that the frame is |
4553 | 0 | // no longer valid. Use the persisted field to determine if the document |
4554 | 0 | // is being destroyed. |
4555 | 0 |
|
4556 | 0 | nsIFocusManager* fm = nsFocusManager::GetFocusManager(); |
4557 | 0 | if (fm) { |
4558 | 0 | fm->WindowHidden(GetOuterWindow()); |
4559 | 0 | } |
4560 | 0 |
|
4561 | 0 | mNeedsFocus = true; |
4562 | 0 | } |
4563 | | |
4564 | | class HashchangeCallback : public Runnable |
4565 | | { |
4566 | | public: |
4567 | | HashchangeCallback(const nsAString& aOldURL, |
4568 | | const nsAString& aNewURL, |
4569 | | nsGlobalWindowInner* aWindow) |
4570 | | : mozilla::Runnable("HashchangeCallback") |
4571 | | , mWindow(aWindow) |
4572 | 0 | { |
4573 | 0 | MOZ_ASSERT(mWindow); |
4574 | 0 | mOldURL.Assign(aOldURL); |
4575 | 0 | mNewURL.Assign(aNewURL); |
4576 | 0 | } |
4577 | | |
4578 | | NS_IMETHOD Run() override |
4579 | 0 | { |
4580 | 0 | MOZ_ASSERT(NS_IsMainThread(), "Should be called on the main thread."); |
4581 | 0 | return mWindow->FireHashchange(mOldURL, mNewURL); |
4582 | 0 | } |
4583 | | |
4584 | | private: |
4585 | | nsString mOldURL; |
4586 | | nsString mNewURL; |
4587 | | RefPtr<nsGlobalWindowInner> mWindow; |
4588 | | }; |
4589 | | |
4590 | | nsresult |
4591 | | nsGlobalWindowInner::DispatchAsyncHashchange(nsIURI *aOldURI, nsIURI *aNewURI) |
4592 | 0 | { |
4593 | 0 | // Make sure that aOldURI and aNewURI are identical up to the '#', and that |
4594 | 0 | // their hashes are different. |
4595 | 0 | bool equal = false; |
4596 | 0 | NS_ENSURE_STATE(NS_SUCCEEDED(aOldURI->EqualsExceptRef(aNewURI, &equal)) && equal); |
4597 | 0 | nsAutoCString oldHash, newHash; |
4598 | 0 | bool oldHasHash, newHasHash; |
4599 | 0 | NS_ENSURE_STATE(NS_SUCCEEDED(aOldURI->GetRef(oldHash)) && |
4600 | 0 | NS_SUCCEEDED(aNewURI->GetRef(newHash)) && |
4601 | 0 | NS_SUCCEEDED(aOldURI->GetHasRef(&oldHasHash)) && |
4602 | 0 | NS_SUCCEEDED(aNewURI->GetHasRef(&newHasHash)) && |
4603 | 0 | (oldHasHash != newHasHash || !oldHash.Equals(newHash))); |
4604 | 0 |
|
4605 | 0 | nsAutoCString oldSpec, newSpec; |
4606 | 0 | nsresult rv = aOldURI->GetSpec(oldSpec); |
4607 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4608 | 0 | rv = aNewURI->GetSpec(newSpec); |
4609 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4610 | 0 |
|
4611 | 0 | NS_ConvertUTF8toUTF16 oldWideSpec(oldSpec); |
4612 | 0 | NS_ConvertUTF8toUTF16 newWideSpec(newSpec); |
4613 | 0 |
|
4614 | 0 | nsCOMPtr<nsIRunnable> callback = |
4615 | 0 | new HashchangeCallback(oldWideSpec, newWideSpec, this); |
4616 | 0 | return Dispatch(TaskCategory::Other, callback.forget()); |
4617 | 0 | } |
4618 | | |
4619 | | nsresult |
4620 | | nsGlobalWindowInner::FireHashchange(const nsAString &aOldURL, |
4621 | | const nsAString &aNewURL) |
4622 | 0 | { |
4623 | 0 | // Don't do anything if the window is frozen. |
4624 | 0 | if (IsFrozen()) { |
4625 | 0 | return NS_OK; |
4626 | 0 | } |
4627 | 0 | |
4628 | 0 | // Get a presentation shell for use in creating the hashchange event. |
4629 | 0 | NS_ENSURE_STATE(IsCurrentInnerWindow()); |
4630 | 0 |
|
4631 | 0 | HashChangeEventInit init; |
4632 | 0 | init.mBubbles = true; |
4633 | 0 | init.mCancelable = false; |
4634 | 0 | init.mNewURL = aNewURL; |
4635 | 0 | init.mOldURL = aOldURL; |
4636 | 0 |
|
4637 | 0 | RefPtr<HashChangeEvent> event = |
4638 | 0 | HashChangeEvent::Constructor(this, NS_LITERAL_STRING("hashchange"), |
4639 | 0 | init); |
4640 | 0 |
|
4641 | 0 | event->SetTrusted(true); |
4642 | 0 |
|
4643 | 0 | ErrorResult rv; |
4644 | 0 | DispatchEvent(*event, rv); |
4645 | 0 | return rv.StealNSResult(); |
4646 | 0 | } |
4647 | | |
4648 | | nsresult |
4649 | | nsGlobalWindowInner::DispatchSyncPopState() |
4650 | 0 | { |
4651 | 0 | NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), |
4652 | 0 | "Must be safe to run script here."); |
4653 | 0 |
|
4654 | 0 | // Bail if the window is frozen. |
4655 | 0 | if (IsFrozen()) { |
4656 | 0 | return NS_OK; |
4657 | 0 | } |
4658 | 0 | |
4659 | 0 | // Get the document's pending state object -- it contains the data we're |
4660 | 0 | // going to send along with the popstate event. The object is serialized |
4661 | 0 | // using structured clone. |
4662 | 0 | nsCOMPtr<nsIVariant> stateObj; |
4663 | 0 | nsresult rv = mDoc->GetStateObject(getter_AddRefs(stateObj)); |
4664 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
4665 | 0 |
|
4666 | 0 | AutoJSAPI jsapi; |
4667 | 0 | bool result = jsapi.Init(this); |
4668 | 0 | NS_ENSURE_TRUE(result, NS_ERROR_FAILURE); |
4669 | 0 |
|
4670 | 0 | JSContext* cx = jsapi.cx(); |
4671 | 0 | JS::Rooted<JS::Value> stateJSValue(cx, JS::NullValue()); |
4672 | 0 | result = stateObj ? VariantToJsval(cx, stateObj, &stateJSValue) : true; |
4673 | 0 | NS_ENSURE_TRUE(result, NS_ERROR_FAILURE); |
4674 | 0 |
|
4675 | 0 | RootedDictionary<PopStateEventInit> init(cx); |
4676 | 0 | init.mBubbles = true; |
4677 | 0 | init.mCancelable = false; |
4678 | 0 | init.mState = stateJSValue; |
4679 | 0 |
|
4680 | 0 | RefPtr<PopStateEvent> event = |
4681 | 0 | PopStateEvent::Constructor(this, NS_LITERAL_STRING("popstate"), |
4682 | 0 | init); |
4683 | 0 | event->SetTrusted(true); |
4684 | 0 | event->SetTarget(this); |
4685 | 0 |
|
4686 | 0 | ErrorResult err; |
4687 | 0 | DispatchEvent(*event, err); |
4688 | 0 | return err.StealNSResult(); |
4689 | 0 | } |
4690 | | |
4691 | | //------------------------------------------------------- |
4692 | | // Tells the HTMLFrame/CanvasFrame that is now has focus |
4693 | | void |
4694 | | nsGlobalWindowInner::UpdateCanvasFocus(bool aFocusChanged, nsIContent* aNewContent) |
4695 | 0 | { |
4696 | 0 | // this is called from the inner window so use GetDocShell |
4697 | 0 | nsIDocShell* docShell = GetDocShell(); |
4698 | 0 | if (!docShell) |
4699 | 0 | return; |
4700 | 0 | |
4701 | 0 | bool editable; |
4702 | 0 | docShell->GetEditable(&editable); |
4703 | 0 | if (editable) |
4704 | 0 | return; |
4705 | 0 | |
4706 | 0 | nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell(); |
4707 | 0 | if (!presShell || !mDoc) |
4708 | 0 | return; |
4709 | 0 | |
4710 | 0 | Element *rootElement = mDoc->GetRootElement(); |
4711 | 0 | if (rootElement) { |
4712 | 0 | if ((mHasFocus || aFocusChanged) && |
4713 | 0 | (mFocusedElement == rootElement || aNewContent == rootElement)) { |
4714 | 0 | nsCanvasFrame* canvasFrame = presShell->GetCanvasFrame(); |
4715 | 0 | if (canvasFrame) { |
4716 | 0 | canvasFrame->SetHasFocus(mHasFocus && rootElement == aNewContent); |
4717 | 0 | } |
4718 | 0 | } |
4719 | 0 | } else { |
4720 | 0 | // XXXbz I would expect that there is never a canvasFrame in this case... |
4721 | 0 | nsCanvasFrame* canvasFrame = presShell->GetCanvasFrame(); |
4722 | 0 | if (canvasFrame) { |
4723 | 0 | canvasFrame->SetHasFocus(false); |
4724 | 0 | } |
4725 | 0 | } |
4726 | 0 | } |
4727 | | |
4728 | | already_AddRefed<nsICSSDeclaration> |
4729 | | nsGlobalWindowInner::GetComputedStyle(Element& aElt, const nsAString& aPseudoElt, |
4730 | | ErrorResult& aError) |
4731 | 0 | { |
4732 | 0 | return GetComputedStyleHelper(aElt, aPseudoElt, false, aError); |
4733 | 0 | } |
4734 | | |
4735 | | already_AddRefed<nsICSSDeclaration> |
4736 | | nsGlobalWindowInner::GetDefaultComputedStyle(Element& aElt, |
4737 | | const nsAString& aPseudoElt, |
4738 | | ErrorResult& aError) |
4739 | 0 | { |
4740 | 0 | return GetComputedStyleHelper(aElt, aPseudoElt, true, aError); |
4741 | 0 | } |
4742 | | |
4743 | | already_AddRefed<nsICSSDeclaration> |
4744 | | nsGlobalWindowInner::GetComputedStyleHelper(Element& aElt, |
4745 | | const nsAString& aPseudoElt, |
4746 | | bool aDefaultStylesOnly, |
4747 | | ErrorResult& aError) |
4748 | 0 | { |
4749 | 0 | FORWARD_TO_OUTER_OR_THROW(GetComputedStyleHelperOuter, |
4750 | 0 | (aElt, aPseudoElt, aDefaultStylesOnly), |
4751 | 0 | aError, nullptr); |
4752 | 0 | } |
4753 | | |
4754 | | Storage* |
4755 | | nsGlobalWindowInner::GetSessionStorage(ErrorResult& aError) |
4756 | 0 | { |
4757 | 0 | nsIPrincipal *principal = GetPrincipal(); |
4758 | 0 | nsIDocShell* docShell = GetDocShell(); |
4759 | 0 |
|
4760 | 0 | if (!principal || !docShell || !Storage::StoragePrefIsEnabled()) { |
4761 | 0 | return nullptr; |
4762 | 0 | } |
4763 | 0 | |
4764 | 0 | if (mSessionStorage) { |
4765 | 0 | MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug, |
4766 | 0 | ("nsGlobalWindowInner %p has %p sessionStorage", this, mSessionStorage.get())); |
4767 | 0 | bool canAccess = principal->Subsumes(mSessionStorage->Principal()); |
4768 | 0 | NS_ASSERTION(canAccess, |
4769 | 0 | "This window owned sessionStorage " |
4770 | 0 | "that could not be accessed!"); |
4771 | 0 | if (!canAccess) { |
4772 | 0 | mSessionStorage = nullptr; |
4773 | 0 | } |
4774 | 0 | } |
4775 | 0 |
|
4776 | 0 | if (!mSessionStorage) { |
4777 | 0 | nsString documentURI; |
4778 | 0 | if (mDoc) { |
4779 | 0 | aError = mDoc->GetDocumentURI(documentURI); |
4780 | 0 | if (NS_WARN_IF(aError.Failed())) { |
4781 | 0 | return nullptr; |
4782 | 0 | } |
4783 | 0 | } |
4784 | 0 | |
4785 | 0 | // If the document has the sandboxed origin flag set |
4786 | 0 | // don't allow access to sessionStorage. |
4787 | 0 | if (!mDoc) { |
4788 | 0 | aError.Throw(NS_ERROR_FAILURE); |
4789 | 0 | return nullptr; |
4790 | 0 | } |
4791 | 0 | |
4792 | 0 | if (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN) { |
4793 | 0 | aError.Throw(NS_ERROR_DOM_SECURITY_ERR); |
4794 | 0 | return nullptr; |
4795 | 0 | } |
4796 | 0 | |
4797 | 0 | nsresult rv; |
4798 | 0 |
|
4799 | 0 | nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(docShell, &rv); |
4800 | 0 | if (NS_FAILED(rv)) { |
4801 | 0 | aError.Throw(rv); |
4802 | 0 | return nullptr; |
4803 | 0 | } |
4804 | 0 | |
4805 | 0 | RefPtr<Storage> storage; |
4806 | 0 | aError = storageManager->CreateStorage(this, principal, documentURI, |
4807 | 0 | IsPrivateBrowsing(), |
4808 | 0 | getter_AddRefs(storage)); |
4809 | 0 | if (aError.Failed()) { |
4810 | 0 | return nullptr; |
4811 | 0 | } |
4812 | 0 | |
4813 | 0 | mSessionStorage = storage; |
4814 | 0 | MOZ_ASSERT(mSessionStorage); |
4815 | 0 |
|
4816 | 0 | MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug, |
4817 | 0 | ("nsGlobalWindowInner %p tried to get a new sessionStorage %p", this, mSessionStorage.get())); |
4818 | 0 |
|
4819 | 0 | if (!mSessionStorage) { |
4820 | 0 | aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
4821 | 0 | return nullptr; |
4822 | 0 | } |
4823 | 0 | } |
4824 | 0 | |
4825 | 0 | MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug, |
4826 | 0 | ("nsGlobalWindowInner %p returns %p sessionStorage", this, mSessionStorage.get())); |
4827 | 0 |
|
4828 | 0 | return mSessionStorage; |
4829 | 0 | } |
4830 | | |
4831 | | Storage* |
4832 | | nsGlobalWindowInner::GetLocalStorage(ErrorResult& aError) |
4833 | 0 | { |
4834 | 0 | if (!Storage::StoragePrefIsEnabled()) { |
4835 | 0 | return nullptr; |
4836 | 0 | } |
4837 | 0 | |
4838 | 0 | if (!mLocalStorage) { |
4839 | 0 | if (nsContentUtils::StorageAllowedForWindow(this) == |
4840 | 0 | nsContentUtils::StorageAccess::eDeny) { |
4841 | 0 | aError.Throw(NS_ERROR_DOM_SECURITY_ERR); |
4842 | 0 | return nullptr; |
4843 | 0 | } |
4844 | 0 | |
4845 | 0 | nsIPrincipal *principal = GetPrincipal(); |
4846 | 0 | if (!principal) { |
4847 | 0 | return nullptr; |
4848 | 0 | } |
4849 | 0 | |
4850 | 0 | nsresult rv; |
4851 | 0 | nsCOMPtr<nsIDOMStorageManager> storageManager = |
4852 | 0 | do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv); |
4853 | 0 | if (NS_FAILED(rv)) { |
4854 | 0 | aError.Throw(rv); |
4855 | 0 | return nullptr; |
4856 | 0 | } |
4857 | 0 | |
4858 | 0 | nsString documentURI; |
4859 | 0 | if (mDoc) { |
4860 | 0 | aError = mDoc->GetDocumentURI(documentURI); |
4861 | 0 | if (NS_WARN_IF(aError.Failed())) { |
4862 | 0 | return nullptr; |
4863 | 0 | } |
4864 | 0 | } |
4865 | 0 | |
4866 | 0 | RefPtr<Storage> storage; |
4867 | 0 | aError = storageManager->CreateStorage(this, principal, documentURI, |
4868 | 0 | IsPrivateBrowsing(), |
4869 | 0 | getter_AddRefs(storage)); |
4870 | 0 | if (aError.Failed()) { |
4871 | 0 | return nullptr; |
4872 | 0 | } |
4873 | 0 | |
4874 | 0 | mLocalStorage = storage; |
4875 | 0 | MOZ_ASSERT(mLocalStorage); |
4876 | 0 | } |
4877 | 0 |
|
4878 | 0 | return mLocalStorage; |
4879 | 0 | } |
4880 | | |
4881 | | IDBFactory* |
4882 | | nsGlobalWindowInner::GetIndexedDB(ErrorResult& aError) |
4883 | 0 | { |
4884 | 0 | if (!mIndexedDB) { |
4885 | 0 | // This may keep mIndexedDB null without setting an error. |
4886 | 0 | aError = IDBFactory::CreateForWindow(this, |
4887 | 0 | getter_AddRefs(mIndexedDB)); |
4888 | 0 | } |
4889 | 0 |
|
4890 | 0 | return mIndexedDB; |
4891 | 0 | } |
4892 | | |
4893 | | //***************************************************************************** |
4894 | | // nsGlobalWindowInner::nsIInterfaceRequestor |
4895 | | //***************************************************************************** |
4896 | | |
4897 | | NS_IMETHODIMP |
4898 | | nsGlobalWindowInner::GetInterface(const nsIID & aIID, void **aSink) |
4899 | 0 | { |
4900 | 0 | nsGlobalWindowOuter* outer = GetOuterWindowInternal(); |
4901 | 0 | NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED); |
4902 | 0 |
|
4903 | 0 | nsresult rv = outer->GetInterfaceInternal(aIID, aSink); |
4904 | 0 | if (rv == NS_ERROR_NO_INTERFACE) { |
4905 | 0 | return QueryInterface(aIID, aSink); |
4906 | 0 | } |
4907 | 0 | return rv; |
4908 | 0 | } |
4909 | | |
4910 | | void |
4911 | | nsGlobalWindowInner::GetInterface(JSContext* aCx, nsIJSID* aIID, |
4912 | | JS::MutableHandle<JS::Value> aRetval, |
4913 | | ErrorResult& aError) |
4914 | 0 | { |
4915 | 0 | dom::GetInterface(aCx, this, aIID, aRetval, aError); |
4916 | 0 | } |
4917 | | |
4918 | | already_AddRefed<CacheStorage> |
4919 | | nsGlobalWindowInner::GetCaches(ErrorResult& aRv) |
4920 | 0 | { |
4921 | 0 | if (!mCacheStorage) { |
4922 | 0 | bool forceTrustedOrigin = |
4923 | 0 | GetOuterWindow()->GetServiceWorkersTestingEnabled(); |
4924 | 0 | mCacheStorage = CacheStorage::CreateOnMainThread(cache::DEFAULT_NAMESPACE, |
4925 | 0 | this, GetPrincipal(), |
4926 | 0 | forceTrustedOrigin, aRv); |
4927 | 0 | } |
4928 | 0 |
|
4929 | 0 | RefPtr<CacheStorage> ref = mCacheStorage; |
4930 | 0 | return ref.forget(); |
4931 | 0 | } |
4932 | | |
4933 | | void |
4934 | | nsGlobalWindowInner::FireOfflineStatusEventIfChanged() |
4935 | 0 | { |
4936 | 0 | if (!IsCurrentInnerWindow()) |
4937 | 0 | return; |
4938 | 0 | |
4939 | 0 | // Don't fire an event if the status hasn't changed |
4940 | 0 | if (mWasOffline == NS_IsOffline()) { |
4941 | 0 | return; |
4942 | 0 | } |
4943 | 0 | |
4944 | 0 | mWasOffline = !mWasOffline; |
4945 | 0 |
|
4946 | 0 | nsAutoString name; |
4947 | 0 | if (mWasOffline) { |
4948 | 0 | name.AssignLiteral("offline"); |
4949 | 0 | } else { |
4950 | 0 | name.AssignLiteral("online"); |
4951 | 0 | } |
4952 | 0 | nsContentUtils::DispatchTrustedEvent(mDoc, |
4953 | 0 | static_cast<EventTarget*>(this), |
4954 | 0 | name, |
4955 | 0 | CanBubble::eNo, |
4956 | 0 | Cancelable::eNo); |
4957 | 0 | } |
4958 | | |
4959 | | class NotifyIdleObserverRunnable : public Runnable |
4960 | | { |
4961 | | public: |
4962 | | NotifyIdleObserverRunnable(MozIdleObserver& aIdleObserver, |
4963 | | uint32_t aTimeInS, |
4964 | | bool aCallOnidle, |
4965 | | nsGlobalWindowInner* aIdleWindow) |
4966 | | : mozilla::Runnable("NotifyIdleObserverRunnable") |
4967 | | , mIdleObserver(aIdleObserver) |
4968 | | , mTimeInS(aTimeInS) |
4969 | | , mIdleWindow(aIdleWindow) |
4970 | | , mCallOnidle(aCallOnidle) |
4971 | 0 | { } |
4972 | | |
4973 | | NS_IMETHOD Run() override |
4974 | 0 | { |
4975 | 0 | if (mIdleWindow->ContainsIdleObserver(mIdleObserver, mTimeInS)) { |
4976 | 0 | if (mCallOnidle) { |
4977 | 0 | mIdleObserver->Onidle(IgnoreErrors()); |
4978 | 0 | } else { |
4979 | 0 | mIdleObserver->Onactive(IgnoreErrors()); |
4980 | 0 | } |
4981 | 0 | } |
4982 | 0 | return NS_OK; |
4983 | 0 | } |
4984 | | |
4985 | | private: |
4986 | | OwningNonNull<MozIdleObserver> mIdleObserver; |
4987 | | uint32_t mTimeInS; |
4988 | | RefPtr<nsGlobalWindowInner> mIdleWindow; |
4989 | | |
4990 | | // If false then call on active |
4991 | | bool mCallOnidle; |
4992 | | }; |
4993 | | |
4994 | | void |
4995 | | nsGlobalWindowInner::NotifyIdleObserver(IdleObserverHolder* aIdleObserverHolder, |
4996 | | bool aCallOnidle) |
4997 | 0 | { |
4998 | 0 | MOZ_ASSERT(aIdleObserverHolder); |
4999 | 0 | aIdleObserverHolder->mPrevNotificationIdle = aCallOnidle; |
5000 | 0 |
|
5001 | 0 | nsCOMPtr<nsIRunnable> caller = |
5002 | 0 | new NotifyIdleObserverRunnable(aIdleObserverHolder->mIdleObserver, |
5003 | 0 | aIdleObserverHolder->mTimeInS, |
5004 | 0 | aCallOnidle, this); |
5005 | 0 | if (NS_FAILED(Dispatch(TaskCategory::Other, caller.forget()))) { |
5006 | 0 | NS_WARNING("Failed to dispatch thread for idle observer notification."); |
5007 | 0 | } |
5008 | 0 | } |
5009 | | |
5010 | | bool |
5011 | | nsGlobalWindowInner::ContainsIdleObserver(MozIdleObserver& aIdleObserver, |
5012 | | uint32_t aTimeInS) |
5013 | 0 | { |
5014 | 0 | bool found = false; |
5015 | 0 | nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers); |
5016 | 0 | while (iter.HasMore()) { |
5017 | 0 | IdleObserverHolder& idleObserver = iter.GetNext(); |
5018 | 0 | if (idleObserver.mIdleObserver.ref() == aIdleObserver && |
5019 | 0 | idleObserver.mTimeInS == aTimeInS) { |
5020 | 0 | found = true; |
5021 | 0 | break; |
5022 | 0 | } |
5023 | 0 | } |
5024 | 0 | return found; |
5025 | 0 | } |
5026 | | |
5027 | | void |
5028 | | IdleActiveTimerCallback(nsITimer* aTimer, void* aClosure) |
5029 | 0 | { |
5030 | 0 | RefPtr<nsGlobalWindowInner> idleWindow = |
5031 | 0 | static_cast<nsGlobalWindowInner*>(aClosure); |
5032 | 0 | MOZ_ASSERT(idleWindow, "Idle window has not been instantiated."); |
5033 | 0 | idleWindow->HandleIdleActiveEvent(); |
5034 | 0 | } |
5035 | | |
5036 | | void |
5037 | | IdleObserverTimerCallback(nsITimer* aTimer, void* aClosure) |
5038 | 0 | { |
5039 | 0 | RefPtr<nsGlobalWindowInner> idleWindow = |
5040 | 0 | static_cast<nsGlobalWindowInner*>(aClosure); |
5041 | 0 | MOZ_ASSERT(idleWindow, "Idle window has not been instantiated."); |
5042 | 0 | idleWindow->HandleIdleObserverCallback(); |
5043 | 0 | } |
5044 | | |
5045 | | void |
5046 | | nsGlobalWindowInner::HandleIdleObserverCallback() |
5047 | 0 | { |
5048 | 0 | MOZ_ASSERT(static_cast<uint32_t>(mIdleCallbackIndex) < mIdleObservers.Length(), |
5049 | 0 | "Idle callback index exceeds array bounds!"); |
5050 | 0 | IdleObserverHolder& idleObserver = mIdleObservers.ElementAt(mIdleCallbackIndex); |
5051 | 0 | NotifyIdleObserver(&idleObserver, true); |
5052 | 0 | mIdleCallbackIndex++; |
5053 | 0 | if (NS_FAILED(ScheduleNextIdleObserverCallback())) { |
5054 | 0 | NS_WARNING("Failed to set next idle observer callback."); |
5055 | 0 | } |
5056 | 0 | } |
5057 | | |
5058 | | nsresult |
5059 | | nsGlobalWindowInner::ScheduleNextIdleObserverCallback() |
5060 | 0 | { |
5061 | 0 | MOZ_ASSERT(mIdleService, "No idle service!"); |
5062 | 0 |
|
5063 | 0 | if (mIdleCallbackIndex < 0 || |
5064 | 0 | static_cast<uint32_t>(mIdleCallbackIndex) >= mIdleObservers.Length()) { |
5065 | 0 | return NS_OK; |
5066 | 0 | } |
5067 | 0 | |
5068 | 0 | IdleObserverHolder& idleObserver = |
5069 | 0 | mIdleObservers.ElementAt(mIdleCallbackIndex); |
5070 | 0 |
|
5071 | 0 | uint32_t userIdleTimeMS = 0; |
5072 | 0 | nsresult rv = mIdleService->GetIdleTime(&userIdleTimeMS); |
5073 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5074 | 0 |
|
5075 | 0 | uint32_t callbackTimeMS = 0; |
5076 | 0 | if (idleObserver.mTimeInS * 1000 + mIdleFuzzFactor > userIdleTimeMS) { |
5077 | 0 | callbackTimeMS = idleObserver.mTimeInS * 1000 - userIdleTimeMS + mIdleFuzzFactor; |
5078 | 0 | } |
5079 | 0 |
|
5080 | 0 | mIdleTimer->Cancel(); |
5081 | 0 | rv = mIdleTimer->InitWithNamedFuncCallback( |
5082 | 0 | IdleObserverTimerCallback, |
5083 | 0 | this, |
5084 | 0 | callbackTimeMS, |
5085 | 0 | nsITimer::TYPE_ONE_SHOT, |
5086 | 0 | "nsGlobalWindowInner::ScheduleNextIdleObserverCallback"); |
5087 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5088 | 0 |
|
5089 | 0 | return NS_OK; |
5090 | 0 | } |
5091 | | |
5092 | | uint32_t |
5093 | | nsGlobalWindowInner::GetFuzzTimeMS() |
5094 | 0 | { |
5095 | 0 | if (gIdleObserversAPIFuzzTimeDisabled) { |
5096 | 0 | return 0; |
5097 | 0 | } |
5098 | 0 | |
5099 | 0 | uint32_t randNum = MAX_IDLE_FUZZ_TIME_MS; |
5100 | 0 | size_t nbytes = PR_GetRandomNoise(&randNum, sizeof(randNum)); |
5101 | 0 | if (nbytes != sizeof(randNum)) { |
5102 | 0 | NS_WARNING("PR_GetRandomNoise(...) Not implemented or no available noise!"); |
5103 | 0 | return MAX_IDLE_FUZZ_TIME_MS; |
5104 | 0 | } |
5105 | 0 |
|
5106 | 0 | if (randNum > MAX_IDLE_FUZZ_TIME_MS) { |
5107 | 0 | randNum %= MAX_IDLE_FUZZ_TIME_MS; |
5108 | 0 | } |
5109 | 0 |
|
5110 | 0 | return randNum; |
5111 | 0 | } |
5112 | | |
5113 | | nsresult |
5114 | | nsGlobalWindowInner::ScheduleActiveTimerCallback() |
5115 | 0 | { |
5116 | 0 | if (!mAddActiveEventFuzzTime) { |
5117 | 0 | return HandleIdleActiveEvent(); |
5118 | 0 | } |
5119 | 0 | |
5120 | 0 | MOZ_ASSERT(mIdleTimer); |
5121 | 0 | mIdleTimer->Cancel(); |
5122 | 0 |
|
5123 | 0 | uint32_t fuzzFactorInMS = GetFuzzTimeMS(); |
5124 | 0 | nsresult rv = mIdleTimer->InitWithNamedFuncCallback( |
5125 | 0 | IdleActiveTimerCallback, |
5126 | 0 | this, |
5127 | 0 | fuzzFactorInMS, |
5128 | 0 | nsITimer::TYPE_ONE_SHOT, |
5129 | 0 | "nsGlobalWindowInner::ScheduleActiveTimerCallback"); |
5130 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5131 | 0 | return NS_OK; |
5132 | 0 | } |
5133 | | |
5134 | | nsresult |
5135 | | nsGlobalWindowInner::HandleIdleActiveEvent() |
5136 | 0 | { |
5137 | 0 | if (mCurrentlyIdle) { |
5138 | 0 | mIdleCallbackIndex = 0; |
5139 | 0 | mIdleFuzzFactor = GetFuzzTimeMS(); |
5140 | 0 | nsresult rv = ScheduleNextIdleObserverCallback(); |
5141 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5142 | 0 | return NS_OK; |
5143 | 0 | } |
5144 | 0 | |
5145 | 0 | mIdleCallbackIndex = -1; |
5146 | 0 | MOZ_ASSERT(mIdleTimer); |
5147 | 0 | mIdleTimer->Cancel(); |
5148 | 0 | nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers); |
5149 | 0 | while (iter.HasMore()) { |
5150 | 0 | IdleObserverHolder& idleObserver = iter.GetNext(); |
5151 | 0 | if (idleObserver.mPrevNotificationIdle) { |
5152 | 0 | NotifyIdleObserver(&idleObserver, false); |
5153 | 0 | } |
5154 | 0 | } |
5155 | 0 |
|
5156 | 0 | return NS_OK; |
5157 | 0 | } |
5158 | | |
5159 | | nsGlobalWindowInner::SlowScriptResponse |
5160 | | nsGlobalWindowInner::ShowSlowScriptDialog(const nsString& aAddonId) |
5161 | 0 | { |
5162 | 0 | nsresult rv; |
5163 | 0 | AutoJSContext cx; |
5164 | 0 |
|
5165 | 0 | if (Preferences::GetBool("dom.always_stop_slow_scripts")) { |
5166 | 0 | return KillSlowScript; |
5167 | 0 | } |
5168 | 0 | |
5169 | 0 | // If it isn't safe to run script, then it isn't safe to bring up the prompt |
5170 | 0 | // (since that spins the event loop). In that (rare) case, we just kill the |
5171 | 0 | // script and report a warning. |
5172 | 0 | if (!nsContentUtils::IsSafeToRunScript()) { |
5173 | 0 | JS_ReportWarningASCII(cx, "A long running script was terminated"); |
5174 | 0 | return KillSlowScript; |
5175 | 0 | } |
5176 | 0 | |
5177 | 0 | // If our document is not active, just kill the script: we've been unloaded |
5178 | 0 | if (!HasActiveDocument()) { |
5179 | 0 | return KillSlowScript; |
5180 | 0 | } |
5181 | 0 | |
5182 | 0 | // Check if we should offer the option to debug |
5183 | 0 | JS::AutoFilename filename; |
5184 | 0 | unsigned lineno; |
5185 | 0 | // Computing the line number can be very expensive (see bug 1330231 for |
5186 | 0 | // example), and we don't use the line number anywhere except than in the |
5187 | 0 | // parent process, so we avoid computing it elsewhere. This gives us most of |
5188 | 0 | // the wins we are interested in, since the source of the slowness here is |
5189 | 0 | // minified scripts which is more common in Web content that is loaded in the |
5190 | 0 | // content process. |
5191 | 0 | unsigned* linenop = XRE_IsParentProcess() ? &lineno : nullptr; |
5192 | 0 | bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, linenop); |
5193 | 0 |
|
5194 | 0 | // Record the slow script event if we haven't done so already for this inner window |
5195 | 0 | // (which represents a particular page to the user). |
5196 | 0 | if (!mHasHadSlowScript) { |
5197 | 0 | Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_PAGE_COUNT, 1); |
5198 | 0 | } |
5199 | 0 | mHasHadSlowScript = true; |
5200 | 0 |
|
5201 | 0 | if (XRE_IsContentProcess() && |
5202 | 0 | ProcessHangMonitor::Get()) { |
5203 | 0 | ProcessHangMonitor::SlowScriptAction action; |
5204 | 0 | RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get(); |
5205 | 0 | nsIDocShell* docShell = GetDocShell(); |
5206 | 0 | nsCOMPtr<nsITabChild> child = docShell ? docShell->GetTabChild() : nullptr; |
5207 | 0 | action = monitor->NotifySlowScript(child, |
5208 | 0 | filename.get(), |
5209 | 0 | aAddonId); |
5210 | 0 | if (action == ProcessHangMonitor::Terminate) { |
5211 | 0 | return KillSlowScript; |
5212 | 0 | } |
5213 | 0 | if (action == ProcessHangMonitor::TerminateGlobal) { |
5214 | 0 | return KillScriptGlobal; |
5215 | 0 | } |
5216 | 0 | |
5217 | 0 | if (action == ProcessHangMonitor::StartDebugger) { |
5218 | 0 | // Spin a nested event loop so that the debugger in the parent can fetch |
5219 | 0 | // any information it needs. Once the debugger has started, return to the |
5220 | 0 | // script. |
5221 | 0 | RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowInternal(); |
5222 | 0 | outer->EnterModalState(); |
5223 | 0 | SpinEventLoopUntil([&]() { return monitor->IsDebuggerStartupComplete(); }); |
5224 | 0 | outer->LeaveModalState(); |
5225 | 0 | return ContinueSlowScript; |
5226 | 0 | } |
5227 | 0 |
|
5228 | 0 | return ContinueSlowScriptAndKeepNotifying; |
5229 | 0 | } |
5230 | 0 | |
5231 | 0 | // Reached only on non-e10s - once per slow script dialog. |
5232 | 0 | // On e10s - we probe once at ProcessHangsMonitor.jsm |
5233 | 0 | Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_NOTICE_COUNT, 1); |
5234 | 0 |
|
5235 | 0 | // Get the nsIPrompt interface from the docshell |
5236 | 0 | nsCOMPtr<nsIDocShell> ds = GetDocShell(); |
5237 | 0 | NS_ENSURE_TRUE(ds, KillSlowScript); |
5238 | 0 | nsCOMPtr<nsIPrompt> prompt = do_GetInterface(ds); |
5239 | 0 | NS_ENSURE_TRUE(prompt, KillSlowScript); |
5240 | 0 |
|
5241 | 0 | // Prioritize the SlowScriptDebug interface over JSD1. |
5242 | 0 | nsCOMPtr<nsISlowScriptDebugCallback> debugCallback; |
5243 | 0 |
|
5244 | 0 | if (hasFrame) { |
5245 | 0 | const char *debugCID = "@mozilla.org/dom/slow-script-debug;1"; |
5246 | 0 | nsCOMPtr<nsISlowScriptDebug> debugService = do_GetService(debugCID, &rv); |
5247 | 0 | if (NS_SUCCEEDED(rv)) { |
5248 | 0 | debugService->GetActivationHandler(getter_AddRefs(debugCallback)); |
5249 | 0 | } |
5250 | 0 | } |
5251 | 0 |
|
5252 | 0 | bool failed = false; |
5253 | 0 | auto getString = [&] (const char* name, |
5254 | 0 | nsContentUtils::PropertiesFile propFile = nsContentUtils::eDOM_PROPERTIES) { |
5255 | 0 | nsAutoString result; |
5256 | 0 | nsresult rv = nsContentUtils::GetLocalizedString( |
5257 | 0 | propFile, name, result); |
5258 | 0 |
|
5259 | 0 | // GetStringFromName can return NS_OK and still give nullptr string |
5260 | 0 | failed = failed || NS_FAILED(rv) || result.IsEmpty(); |
5261 | 0 | return result; |
5262 | 0 | }; |
5263 | 0 |
|
5264 | 0 | bool isAddonScript = !aAddonId.IsEmpty(); |
5265 | 0 | bool showDebugButton = debugCallback && !isAddonScript; |
5266 | 0 |
|
5267 | 0 | // Get localizable strings |
5268 | 0 |
|
5269 | 0 | nsAutoString title, checkboxMsg, debugButton, msg; |
5270 | 0 | if (isAddonScript) { |
5271 | 0 | title = getString("KillAddonScriptTitle"); |
5272 | 0 | checkboxMsg = getString("KillAddonScriptGlobalMessage"); |
5273 | 0 |
|
5274 | 0 | auto appName = getString("brandShortName", nsContentUtils::eBRAND_PROPERTIES); |
5275 | 0 |
|
5276 | 0 | nsCOMPtr<nsIAddonPolicyService> aps = do_GetService("@mozilla.org/addons/policy-service;1"); |
5277 | 0 | nsString addonName; |
5278 | 0 | if (!aps || NS_FAILED(aps->GetExtensionName(aAddonId, addonName))) { |
5279 | 0 | addonName = aAddonId; |
5280 | 0 | } |
5281 | 0 |
|
5282 | 0 | const char16_t* params[] = {addonName.get(), appName.get()}; |
5283 | 0 | rv = nsContentUtils::FormatLocalizedString( |
5284 | 0 | nsContentUtils::eDOM_PROPERTIES, "KillAddonScriptMessage", |
5285 | 0 | params, msg); |
5286 | 0 |
|
5287 | 0 | failed = failed || NS_FAILED(rv); |
5288 | 0 | } else { |
5289 | 0 | title = getString("KillScriptTitle"); |
5290 | 0 | checkboxMsg = getString("DontAskAgain"); |
5291 | 0 |
|
5292 | 0 | if (showDebugButton) { |
5293 | 0 | debugButton = getString("DebugScriptButton"); |
5294 | 0 | msg = getString("KillScriptWithDebugMessage"); |
5295 | 0 | } else { |
5296 | 0 | msg = getString("KillScriptMessage"); |
5297 | 0 | } |
5298 | 0 | } |
5299 | 0 |
|
5300 | 0 | auto stopButton = getString("StopScriptButton"); |
5301 | 0 | auto waitButton = getString("WaitForScriptButton"); |
5302 | 0 |
|
5303 | 0 | if (failed) { |
5304 | 0 | NS_ERROR("Failed to get localized strings."); |
5305 | 0 | return ContinueSlowScript; |
5306 | 0 | } |
5307 | 0 |
|
5308 | 0 | // Append file and line number information, if available |
5309 | 0 | if (filename.get()) { |
5310 | 0 | nsAutoString scriptLocation; |
5311 | 0 | // We want to drop the middle part of too-long locations. We'll |
5312 | 0 | // define "too-long" as longer than 60 UTF-16 code units. Just |
5313 | 0 | // have to be a bit careful about unpaired surrogates. |
5314 | 0 | NS_ConvertUTF8toUTF16 filenameUTF16(filename.get()); |
5315 | 0 | if (filenameUTF16.Length() > 60) { |
5316 | 0 | // XXXbz Do we need to insert any bidi overrides here? |
5317 | 0 | size_t cutStart = 30; |
5318 | 0 | size_t cutLength = filenameUTF16.Length() - 60; |
5319 | 0 | MOZ_ASSERT(cutLength > 0); |
5320 | 0 | if (NS_IS_LOW_SURROGATE(filenameUTF16[cutStart])) { |
5321 | 0 | // Don't truncate before the low surrogate, in case it's preceded by a |
5322 | 0 | // high surrogate and forms a single Unicode character. Instead, just |
5323 | 0 | // include the low surrogate. |
5324 | 0 | ++cutStart; |
5325 | 0 | --cutLength; |
5326 | 0 | } |
5327 | 0 | if (NS_IS_LOW_SURROGATE(filenameUTF16[cutStart + cutLength])) { |
5328 | 0 | // Likewise, don't drop a trailing low surrogate here. We want to |
5329 | 0 | // increase cutLength, since it might be 0 already so we can't very well |
5330 | 0 | // decrease it. |
5331 | 0 | ++cutLength; |
5332 | 0 | } |
5333 | 0 |
|
5334 | 0 | // Insert U+2026 HORIZONTAL ELLIPSIS |
5335 | 0 | filenameUTF16.ReplaceLiteral(cutStart, cutLength, u"\x2026"); |
5336 | 0 | } |
5337 | 0 | const char16_t *formatParams[] = { filenameUTF16.get() }; |
5338 | 0 | rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES, |
5339 | 0 | "KillScriptLocation", |
5340 | 0 | formatParams, |
5341 | 0 | scriptLocation); |
5342 | 0 |
|
5343 | 0 | if (NS_SUCCEEDED(rv)) { |
5344 | 0 | msg.AppendLiteral("\n\n"); |
5345 | 0 | msg.Append(scriptLocation); |
5346 | 0 | msg.Append(':'); |
5347 | 0 | msg.AppendInt(lineno); |
5348 | 0 | } |
5349 | 0 | } |
5350 | 0 |
|
5351 | 0 | uint32_t buttonFlags = nsIPrompt::BUTTON_POS_1_DEFAULT + |
5352 | 0 | (nsIPrompt::BUTTON_TITLE_IS_STRING * |
5353 | 0 | (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1)); |
5354 | 0 |
|
5355 | 0 | // Add a third button if necessary. |
5356 | 0 | if (showDebugButton) |
5357 | 0 | buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2; |
5358 | 0 |
|
5359 | 0 | bool checkboxValue = false; |
5360 | 0 | int32_t buttonPressed = 0; // In case the user exits dialog by clicking X. |
5361 | 0 | { |
5362 | 0 | // Null out the operation callback while we're re-entering JS here. |
5363 | 0 | AutoDisableJSInterruptCallback disabler(cx); |
5364 | 0 |
|
5365 | 0 | // Open the dialog. |
5366 | 0 | rv = prompt->ConfirmEx(title.get(), msg.get(), buttonFlags, |
5367 | 0 | waitButton.get(), stopButton.get(), |
5368 | 0 | debugButton.get(), checkboxMsg.get(), |
5369 | 0 | &checkboxValue, &buttonPressed); |
5370 | 0 | } |
5371 | 0 |
|
5372 | 0 | if (buttonPressed == 0) { |
5373 | 0 | if (checkboxValue && !isAddonScript && NS_SUCCEEDED(rv)) |
5374 | 0 | return AlwaysContinueSlowScript; |
5375 | 0 | return ContinueSlowScript; |
5376 | 0 | } |
5377 | 0 | |
5378 | 0 | if (buttonPressed == 2) { |
5379 | 0 | MOZ_RELEASE_ASSERT(debugCallback); |
5380 | 0 |
|
5381 | 0 | rv = debugCallback->HandleSlowScriptDebug(this); |
5382 | 0 | return NS_SUCCEEDED(rv) ? ContinueSlowScript : KillSlowScript; |
5383 | 0 | } |
5384 | 0 | |
5385 | 0 | JS_ClearPendingException(cx); |
5386 | 0 |
|
5387 | 0 | if (checkboxValue && isAddonScript) |
5388 | 0 | return KillScriptGlobal; |
5389 | 0 | return KillSlowScript; |
5390 | 0 | } |
5391 | | |
5392 | | uint32_t |
5393 | | nsGlobalWindowInner::FindInsertionIndex(IdleObserverHolder* aIdleObserver) |
5394 | 0 | { |
5395 | 0 | MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated."); |
5396 | 0 |
|
5397 | 0 | uint32_t i = 0; |
5398 | 0 | nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers); |
5399 | 0 | while (iter.HasMore()) { |
5400 | 0 | IdleObserverHolder& idleObserver = iter.GetNext(); |
5401 | 0 | if (idleObserver.mTimeInS > aIdleObserver->mTimeInS) { |
5402 | 0 | break; |
5403 | 0 | } |
5404 | 0 | i++; |
5405 | 0 | MOZ_ASSERT(i <= mIdleObservers.Length(), "Array index out of bounds error."); |
5406 | 0 | } |
5407 | 0 |
|
5408 | 0 | return i; |
5409 | 0 | } |
5410 | | |
5411 | | nsresult |
5412 | | nsGlobalWindowInner::RegisterIdleObserver(MozIdleObserver& aIdleObserver) |
5413 | 0 | { |
5414 | 0 | nsresult rv; |
5415 | 0 | if (mIdleObservers.IsEmpty()) { |
5416 | 0 | mIdleService = do_GetService("@mozilla.org/widget/idleservice;1", &rv); |
5417 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5418 | 0 |
|
5419 | 0 | rv = mIdleService->AddIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S); |
5420 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5421 | 0 |
|
5422 | 0 | if (!mIdleTimer) { |
5423 | 0 | mIdleTimer = NS_NewTimer(); |
5424 | 0 | NS_ENSURE_TRUE(mIdleTimer, NS_ERROR_OUT_OF_MEMORY); |
5425 | 0 | } else { |
5426 | 0 | mIdleTimer->Cancel(); |
5427 | 0 | } |
5428 | 0 | } |
5429 | 0 |
|
5430 | 0 | MOZ_ASSERT(mIdleService); |
5431 | 0 | MOZ_ASSERT(mIdleTimer); |
5432 | 0 |
|
5433 | 0 | IdleObserverHolder tmpIdleObserver; |
5434 | 0 | tmpIdleObserver.mIdleObserver = aIdleObserver; |
5435 | 0 | ErrorResult err; |
5436 | 0 | tmpIdleObserver.mTimeInS = aIdleObserver.GetTime(err); |
5437 | 0 | if (NS_WARN_IF(err.Failed())) { |
5438 | 0 | return err.StealNSResult(); |
5439 | 0 | } |
5440 | 0 | NS_ENSURE_ARG_MAX(tmpIdleObserver.mTimeInS, UINT32_MAX / 1000); |
5441 | 0 | NS_ENSURE_ARG_MIN(tmpIdleObserver.mTimeInS, MIN_IDLE_NOTIFICATION_TIME_S); |
5442 | 0 |
|
5443 | 0 | uint32_t insertAtIndex = FindInsertionIndex(&tmpIdleObserver); |
5444 | 0 | if (insertAtIndex == mIdleObservers.Length()) { |
5445 | 0 | mIdleObservers.AppendElement(tmpIdleObserver); |
5446 | 0 | } |
5447 | 0 | else { |
5448 | 0 | mIdleObservers.InsertElementAt(insertAtIndex, tmpIdleObserver); |
5449 | 0 | } |
5450 | 0 |
|
5451 | 0 | bool userIsIdle = false; |
5452 | 0 | rv = nsContentUtils::IsUserIdle(MIN_IDLE_NOTIFICATION_TIME_S, &userIsIdle); |
5453 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5454 | 0 |
|
5455 | 0 | // Special case. First idle observer added to empty list while the user is idle. |
5456 | 0 | // Haven't received 'idle' topic notification from slow idle service yet. |
5457 | 0 | // Need to wait for the idle notification and then notify idle observers in the list. |
5458 | 0 | if (userIsIdle && mIdleCallbackIndex == -1) { |
5459 | 0 | return NS_OK; |
5460 | 0 | } |
5461 | 0 | |
5462 | 0 | if (!mCurrentlyIdle) { |
5463 | 0 | return NS_OK; |
5464 | 0 | } |
5465 | 0 | |
5466 | 0 | MOZ_ASSERT(mIdleCallbackIndex >= 0); |
5467 | 0 |
|
5468 | 0 | if (static_cast<int32_t>(insertAtIndex) < mIdleCallbackIndex) { |
5469 | 0 | IdleObserverHolder& idleObserver = mIdleObservers.ElementAt(insertAtIndex); |
5470 | 0 | NotifyIdleObserver(&idleObserver, true); |
5471 | 0 | mIdleCallbackIndex++; |
5472 | 0 | return NS_OK; |
5473 | 0 | } |
5474 | 0 | |
5475 | 0 | if (static_cast<int32_t>(insertAtIndex) == mIdleCallbackIndex) { |
5476 | 0 | mIdleTimer->Cancel(); |
5477 | 0 | rv = ScheduleNextIdleObserverCallback(); |
5478 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5479 | 0 | } |
5480 | 0 | return NS_OK; |
5481 | 0 | } |
5482 | | |
5483 | | nsresult |
5484 | | nsGlobalWindowInner::FindIndexOfElementToRemove(MozIdleObserver& aIdleObserver, |
5485 | | int32_t* aRemoveElementIndex) |
5486 | 0 | { |
5487 | 0 | *aRemoveElementIndex = 0; |
5488 | 0 | if (mIdleObservers.IsEmpty()) { |
5489 | 0 | return NS_ERROR_FAILURE; |
5490 | 0 | } |
5491 | 0 | |
5492 | 0 | ErrorResult rv; |
5493 | 0 | uint32_t aIdleObserverTimeInS = aIdleObserver.GetTime(rv); |
5494 | 0 | if (NS_WARN_IF(rv.Failed())) { |
5495 | 0 | return rv.StealNSResult(); |
5496 | 0 | } |
5497 | 0 | NS_ENSURE_ARG_MIN(aIdleObserverTimeInS, MIN_IDLE_NOTIFICATION_TIME_S); |
5498 | 0 |
|
5499 | 0 | nsTObserverArray<IdleObserverHolder>::ForwardIterator iter(mIdleObservers); |
5500 | 0 | while (iter.HasMore()) { |
5501 | 0 | IdleObserverHolder& idleObserver = iter.GetNext(); |
5502 | 0 | if (idleObserver.mTimeInS == aIdleObserverTimeInS && |
5503 | 0 | idleObserver.mIdleObserver.ref() == aIdleObserver ) { |
5504 | 0 | break; |
5505 | 0 | } |
5506 | 0 | (*aRemoveElementIndex)++; |
5507 | 0 | } |
5508 | 0 | return static_cast<uint32_t>(*aRemoveElementIndex) >= mIdleObservers.Length() ? |
5509 | 0 | NS_ERROR_FAILURE : NS_OK; |
5510 | 0 | } |
5511 | | |
5512 | | nsresult |
5513 | | nsGlobalWindowInner::UnregisterIdleObserver(MozIdleObserver& aIdleObserver) |
5514 | 0 | { |
5515 | 0 | int32_t removeElementIndex; |
5516 | 0 | nsresult rv = FindIndexOfElementToRemove(aIdleObserver, &removeElementIndex); |
5517 | 0 | if (NS_FAILED(rv)) { |
5518 | 0 | NS_WARNING("Idle observer not found in list of idle observers. No idle observer removed."); |
5519 | 0 | return NS_OK; |
5520 | 0 | } |
5521 | 0 | mIdleObservers.RemoveElementAt(removeElementIndex); |
5522 | 0 |
|
5523 | 0 | MOZ_ASSERT(mIdleTimer); |
5524 | 0 | if (mIdleObservers.IsEmpty() && mIdleService) { |
5525 | 0 | rv = mIdleService->RemoveIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S); |
5526 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5527 | 0 | mIdleService = nullptr; |
5528 | 0 |
|
5529 | 0 | mIdleTimer->Cancel(); |
5530 | 0 | mIdleCallbackIndex = -1; |
5531 | 0 | return NS_OK; |
5532 | 0 | } |
5533 | 0 | |
5534 | 0 | if (!mCurrentlyIdle) { |
5535 | 0 | return NS_OK; |
5536 | 0 | } |
5537 | 0 | |
5538 | 0 | if (removeElementIndex < mIdleCallbackIndex) { |
5539 | 0 | mIdleCallbackIndex--; |
5540 | 0 | return NS_OK; |
5541 | 0 | } |
5542 | 0 | |
5543 | 0 | if (removeElementIndex != mIdleCallbackIndex) { |
5544 | 0 | return NS_OK; |
5545 | 0 | } |
5546 | 0 | |
5547 | 0 | mIdleTimer->Cancel(); |
5548 | 0 |
|
5549 | 0 | // If the last element in the array had been notified then decrement |
5550 | 0 | // mIdleCallbackIndex because an idle was removed from the list of |
5551 | 0 | // idle observers. |
5552 | 0 | // Example: add idle observer with time 1, 2, 3, |
5553 | 0 | // Idle notifications for idle observers with time 1, 2, 3 are complete |
5554 | 0 | // Remove idle observer with time 3 while the user is still idle. |
5555 | 0 | // The user never transitioned to active state. |
5556 | 0 | // Add an idle observer with idle time 4 |
5557 | 0 | if (static_cast<uint32_t>(mIdleCallbackIndex) == mIdleObservers.Length()) { |
5558 | 0 | mIdleCallbackIndex--; |
5559 | 0 | } |
5560 | 0 | rv = ScheduleNextIdleObserverCallback(); |
5561 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
5562 | 0 |
|
5563 | 0 | return NS_OK; |
5564 | 0 | } |
5565 | | |
5566 | | nsresult |
5567 | | nsGlobalWindowInner::Observe(nsISupports* aSubject, const char* aTopic, |
5568 | | const char16_t* aData) |
5569 | 0 | { |
5570 | 0 | if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) { |
5571 | 0 | if (!IsFrozen()) { |
5572 | 0 | // Fires an offline status event if the offline status has changed |
5573 | 0 | FireOfflineStatusEventIfChanged(); |
5574 | 0 | } |
5575 | 0 | return NS_OK; |
5576 | 0 | } |
5577 | 0 |
|
5578 | 0 | if (!nsCRT::strcmp(aTopic, MEMORY_PRESSURE_OBSERVER_TOPIC)) { |
5579 | 0 | if (mPerformance) { |
5580 | 0 | mPerformance->MemoryPressure(); |
5581 | 0 | } |
5582 | 0 | return NS_OK; |
5583 | 0 | } |
5584 | 0 |
|
5585 | 0 | if (!nsCRT::strcmp(aTopic, "clear-site-data-reload-needed")) { |
5586 | 0 | // The reload is propagated from the top-level window only. |
5587 | 0 | NS_ConvertUTF16toUTF8 otherOrigin(aData); |
5588 | 0 | PropagateClearSiteDataReload(otherOrigin); |
5589 | 0 | return NS_OK; |
5590 | 0 | } |
5591 | 0 | |
5592 | 0 | if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_IDLE)) { |
5593 | 0 | mCurrentlyIdle = true; |
5594 | 0 | if (IsFrozen()) { |
5595 | 0 | // need to fire only one idle event while the window is frozen. |
5596 | 0 | mNotifyIdleObserversIdleOnThaw = true; |
5597 | 0 | mNotifyIdleObserversActiveOnThaw = false; |
5598 | 0 | } else if (IsCurrentInnerWindow()) { |
5599 | 0 | HandleIdleActiveEvent(); |
5600 | 0 | } |
5601 | 0 | return NS_OK; |
5602 | 0 | } |
5603 | 0 |
|
5604 | 0 | if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_ACTIVE)) { |
5605 | 0 | mCurrentlyIdle = false; |
5606 | 0 | if (IsFrozen()) { |
5607 | 0 | mNotifyIdleObserversActiveOnThaw = true; |
5608 | 0 | mNotifyIdleObserversIdleOnThaw = false; |
5609 | 0 | } else if (IsCurrentInnerWindow()) { |
5610 | 0 | ScheduleActiveTimerCallback(); |
5611 | 0 | } |
5612 | 0 | return NS_OK; |
5613 | 0 | } |
5614 | 0 |
|
5615 | 0 | if (!nsCRT::strcmp(aTopic, "offline-cache-update-added")) { |
5616 | 0 | if (mApplicationCache) |
5617 | 0 | return NS_OK; |
5618 | 0 | |
5619 | 0 | // Instantiate the application object now. It observes update belonging to |
5620 | 0 | // this window's document and correctly updates the applicationCache object |
5621 | 0 | // state. |
5622 | 0 | nsCOMPtr<nsIObserver> observer = GetApplicationCache(); |
5623 | 0 | if (observer) |
5624 | 0 | observer->Observe(aSubject, aTopic, aData); |
5625 | 0 |
|
5626 | 0 | return NS_OK; |
5627 | 0 | } |
5628 | 0 |
|
5629 | 0 | if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { |
5630 | 0 | MOZ_ASSERT(!NS_strcmp(aData, u"intl.accept_languages")); |
5631 | 0 |
|
5632 | 0 | // The user preferred languages have changed, we need to fire an event on |
5633 | 0 | // Window object and invalidate the cache for navigator.languages. It is |
5634 | 0 | // done for every change which can be a waste of cycles but those should be |
5635 | 0 | // fairly rare. |
5636 | 0 | // We MUST invalidate navigator.languages before sending the event in the |
5637 | 0 | // very likely situation where an event handler will try to read its value. |
5638 | 0 |
|
5639 | 0 | if (mNavigator) { |
5640 | 0 | Navigator_Binding::ClearCachedLanguageValue(mNavigator); |
5641 | 0 | Navigator_Binding::ClearCachedLanguagesValue(mNavigator); |
5642 | 0 | } |
5643 | 0 |
|
5644 | 0 | // The event has to be dispatched only to the current inner window. |
5645 | 0 | if (!IsCurrentInnerWindow()) { |
5646 | 0 | return NS_OK; |
5647 | 0 | } |
5648 | 0 | |
5649 | 0 | RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr); |
5650 | 0 | event->InitEvent(NS_LITERAL_STRING("languagechange"), false, false); |
5651 | 0 | event->SetTrusted(true); |
5652 | 0 |
|
5653 | 0 | ErrorResult rv; |
5654 | 0 | DispatchEvent(*event, rv); |
5655 | 0 | return rv.StealNSResult(); |
5656 | 0 | } |
5657 | 0 |
|
5658 | 0 | NS_WARNING("unrecognized topic in nsGlobalWindowInner::Observe"); |
5659 | 0 | return NS_ERROR_FAILURE; |
5660 | 0 | } |
5661 | | |
5662 | | void |
5663 | | nsGlobalWindowInner::ObserveStorageNotification(StorageEvent* aEvent, |
5664 | | const char16_t* aStorageType, |
5665 | | bool aPrivateBrowsing) |
5666 | 0 | { |
5667 | 0 | MOZ_ASSERT(aEvent); |
5668 | 0 |
|
5669 | 0 | // The private browsing check must be done here again because this window |
5670 | 0 | // could have changed its state before the notification check and now. This |
5671 | 0 | // happens in case this window did have a docShell at that time. |
5672 | 0 | if (aPrivateBrowsing != IsPrivateBrowsing()) { |
5673 | 0 | return; |
5674 | 0 | } |
5675 | 0 | |
5676 | 0 | // LocalStorage can only exist on an inner window, and we don't want to |
5677 | 0 | // generate events on frozen or otherwise-navigated-away from windows. |
5678 | 0 | // (Actually, this code used to try and buffer events for frozen windows, |
5679 | 0 | // but it never worked, so we've removed it. See bug 1285898.) |
5680 | 0 | if (!IsCurrentInnerWindow() || IsFrozen()) { |
5681 | 0 | return; |
5682 | 0 | } |
5683 | 0 | |
5684 | 0 | nsIPrincipal *principal = GetPrincipal(); |
5685 | 0 | if (!principal) { |
5686 | 0 | return; |
5687 | 0 | } |
5688 | 0 | |
5689 | 0 | bool fireMozStorageChanged = false; |
5690 | 0 | nsAutoString eventType; |
5691 | 0 | eventType.AssignLiteral("storage"); |
5692 | 0 |
|
5693 | 0 | if (!NS_strcmp(aStorageType, u"sessionStorage")) { |
5694 | 0 | RefPtr<Storage> changingStorage = aEvent->GetStorageArea(); |
5695 | 0 | MOZ_ASSERT(changingStorage); |
5696 | 0 |
|
5697 | 0 | bool check = false; |
5698 | 0 |
|
5699 | 0 | nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(GetDocShell()); |
5700 | 0 | if (storageManager) { |
5701 | 0 | nsresult rv = storageManager->CheckStorage(principal, changingStorage, |
5702 | 0 | &check); |
5703 | 0 | if (NS_FAILED(rv)) { |
5704 | 0 | return; |
5705 | 0 | } |
5706 | 0 | } |
5707 | 0 | |
5708 | 0 | if (!check) { |
5709 | 0 | // This storage event is not coming from our storage or is coming |
5710 | 0 | // from a different docshell, i.e. it is a clone, ignore this event. |
5711 | 0 | return; |
5712 | 0 | } |
5713 | 0 | |
5714 | 0 | MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug, |
5715 | 0 | ("nsGlobalWindowInner %p with sessionStorage %p passing event from %p", |
5716 | 0 | this, mSessionStorage.get(), changingStorage.get())); |
5717 | 0 |
|
5718 | 0 | fireMozStorageChanged = mSessionStorage == changingStorage; |
5719 | 0 | if (fireMozStorageChanged) { |
5720 | 0 | eventType.AssignLiteral("MozSessionStorageChanged"); |
5721 | 0 | } |
5722 | 0 | } |
5723 | 0 |
|
5724 | 0 | else { |
5725 | 0 | MOZ_ASSERT(!NS_strcmp(aStorageType, u"localStorage")); |
5726 | 0 |
|
5727 | 0 | MOZ_DIAGNOSTIC_ASSERT(StorageUtils::PrincipalsEqual(aEvent->GetPrincipal(), |
5728 | 0 | principal)); |
5729 | 0 |
|
5730 | 0 | fireMozStorageChanged = mLocalStorage == aEvent->GetStorageArea(); |
5731 | 0 |
|
5732 | 0 | if (fireMozStorageChanged) { |
5733 | 0 | eventType.AssignLiteral("MozLocalStorageChanged"); |
5734 | 0 | } |
5735 | 0 | } |
5736 | 0 |
|
5737 | 0 | // Clone the storage event included in the observer notification. We want |
5738 | 0 | // to dispatch clones rather than the original event. |
5739 | 0 | IgnoredErrorResult error; |
5740 | 0 | RefPtr<StorageEvent> clonedEvent = |
5741 | 0 | CloneStorageEvent(eventType, aEvent, error); |
5742 | 0 | if (error.Failed()) { |
5743 | 0 | return; |
5744 | 0 | } |
5745 | 0 | |
5746 | 0 | clonedEvent->SetTrusted(true); |
5747 | 0 |
|
5748 | 0 | if (fireMozStorageChanged) { |
5749 | 0 | WidgetEvent* internalEvent = clonedEvent->WidgetEventPtr(); |
5750 | 0 | internalEvent->mFlags.mOnlyChromeDispatch = true; |
5751 | 0 | } |
5752 | 0 |
|
5753 | 0 | DispatchEvent(*clonedEvent); |
5754 | 0 | } |
5755 | | |
5756 | | already_AddRefed<StorageEvent> |
5757 | | nsGlobalWindowInner::CloneStorageEvent(const nsAString& aType, |
5758 | | const RefPtr<StorageEvent>& aEvent, |
5759 | | ErrorResult& aRv) |
5760 | 0 | { |
5761 | 0 | StorageEventInit dict; |
5762 | 0 |
|
5763 | 0 | dict.mBubbles = aEvent->Bubbles(); |
5764 | 0 | dict.mCancelable = aEvent->Cancelable(); |
5765 | 0 | aEvent->GetKey(dict.mKey); |
5766 | 0 | aEvent->GetOldValue(dict.mOldValue); |
5767 | 0 | aEvent->GetNewValue(dict.mNewValue); |
5768 | 0 | aEvent->GetUrl(dict.mUrl); |
5769 | 0 |
|
5770 | 0 | RefPtr<Storage> storageArea = aEvent->GetStorageArea(); |
5771 | 0 |
|
5772 | 0 | RefPtr<Storage> storage; |
5773 | 0 |
|
5774 | 0 | // If null, this is a localStorage event received by IPC. |
5775 | 0 | if (!storageArea) { |
5776 | 0 | storage = GetLocalStorage(aRv); |
5777 | 0 | if (aRv.Failed() || !storage) { |
5778 | 0 | return nullptr; |
5779 | 0 | } |
5780 | 0 | |
5781 | 0 | MOZ_ASSERT(storage->Type() == Storage::eLocalStorage); |
5782 | 0 | RefPtr<LocalStorage> localStorage = |
5783 | 0 | static_cast<LocalStorage*>(storage.get()); |
5784 | 0 |
|
5785 | 0 | // We must apply the current change to the 'local' localStorage. |
5786 | 0 | localStorage->ApplyEvent(aEvent); |
5787 | 0 | } else if (storageArea->Type() == Storage::eSessionStorage) { |
5788 | 0 | storage = GetSessionStorage(aRv); |
5789 | 0 | } else { |
5790 | 0 | MOZ_ASSERT(storageArea->Type() == Storage::eLocalStorage); |
5791 | 0 | storage = GetLocalStorage(aRv); |
5792 | 0 | } |
5793 | 0 |
|
5794 | 0 | if (aRv.Failed() || !storage) { |
5795 | 0 | return nullptr; |
5796 | 0 | } |
5797 | 0 | |
5798 | 0 | MOZ_ASSERT(storage); |
5799 | 0 | MOZ_ASSERT_IF(storageArea, storage->IsForkOf(storageArea)); |
5800 | 0 |
|
5801 | 0 | dict.mStorageArea = storage; |
5802 | 0 |
|
5803 | 0 | RefPtr<StorageEvent> event = StorageEvent::Constructor(this, aType, dict); |
5804 | 0 | return event.forget(); |
5805 | 0 | } |
5806 | | |
5807 | | void |
5808 | | nsGlobalWindowInner::Suspend() |
5809 | 0 | { |
5810 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5811 | 0 |
|
5812 | 0 | // We can only safely suspend windows that are the current inner window. If |
5813 | 0 | // its not the current inner, then we are in one of two different cases. |
5814 | 0 | // Either we are in the bfcache or we are doomed window that is going away. |
5815 | 0 | // When a window becomes inactive we purposely avoid placing already suspended |
5816 | 0 | // windows into the bfcache. It only expects windows suspended due to the |
5817 | 0 | // Freeze() method which occurs while the window is still the current inner. |
5818 | 0 | // So we must not call Suspend() on bfcache windows at this point or this |
5819 | 0 | // invariant will be broken. If the window is doomed there is no point in |
5820 | 0 | // suspending it since it will soon be gone. |
5821 | 0 | if (!IsCurrentInnerWindow()) { |
5822 | 0 | return; |
5823 | 0 | } |
5824 | 0 | |
5825 | 0 | // All children are also suspended. This ensure mSuspendDepth is |
5826 | 0 | // set properly and the timers are properly canceled for each child. |
5827 | 0 | CallOnChildren(&nsGlobalWindowInner::Suspend); |
5828 | 0 |
|
5829 | 0 | mSuspendDepth += 1; |
5830 | 0 | if (mSuspendDepth != 1) { |
5831 | 0 | return; |
5832 | 0 | } |
5833 | 0 | |
5834 | 0 | nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID); |
5835 | 0 | if (ac) { |
5836 | 0 | for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) |
5837 | 0 | ac->RemoveWindowListener(mEnabledSensors[i], this); |
5838 | 0 | } |
5839 | 0 | DisableGamepadUpdates(); |
5840 | 0 | DisableVRUpdates(); |
5841 | 0 |
|
5842 | 0 | SuspendWorkersForWindow(this); |
5843 | 0 |
|
5844 | 0 | SuspendIdleRequests(); |
5845 | 0 |
|
5846 | 0 | mTimeoutManager->Suspend(); |
5847 | 0 |
|
5848 | 0 | // Suspend all of the AudioContexts for this window |
5849 | 0 | for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) { |
5850 | 0 | ErrorResult dummy; |
5851 | 0 | RefPtr<Promise> d = mAudioContexts[i]->Suspend(dummy); |
5852 | 0 | } |
5853 | 0 | } |
5854 | | |
5855 | | void |
5856 | | nsGlobalWindowInner::Resume() |
5857 | 0 | { |
5858 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5859 | 0 |
|
5860 | 0 | // We can only safely resume a window if its the current inner window. If |
5861 | 0 | // its not the current inner, then we are in one of two different cases. |
5862 | 0 | // Either we are in the bfcache or we are doomed window that is going away. |
5863 | 0 | // If a window is suspended when it becomes inactive we purposely do not |
5864 | 0 | // put it in the bfcache, so Resume should never be needed in that case. |
5865 | 0 | // If the window is doomed then there is no point in resuming it. |
5866 | 0 | if (!IsCurrentInnerWindow()) { |
5867 | 0 | return; |
5868 | 0 | } |
5869 | 0 | |
5870 | 0 | // Resume all children. This restores timers recursively canceled |
5871 | 0 | // in Suspend() and ensures all children have the correct mSuspendDepth. |
5872 | 0 | CallOnChildren(&nsGlobalWindowInner::Resume); |
5873 | 0 |
|
5874 | 0 | MOZ_ASSERT(mSuspendDepth != 0); |
5875 | 0 | mSuspendDepth -= 1; |
5876 | 0 | if (mSuspendDepth != 0) { |
5877 | 0 | return; |
5878 | 0 | } |
5879 | 0 | |
5880 | 0 | // We should not be able to resume a frozen window. It must be Thaw()'d first. |
5881 | 0 | MOZ_ASSERT(mFreezeDepth == 0); |
5882 | 0 |
|
5883 | 0 | nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID); |
5884 | 0 | if (ac) { |
5885 | 0 | for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) |
5886 | 0 | ac->AddWindowListener(mEnabledSensors[i], this); |
5887 | 0 | } |
5888 | 0 | EnableGamepadUpdates(); |
5889 | 0 | EnableVRUpdates(); |
5890 | 0 |
|
5891 | 0 | // Resume all of the AudioContexts for this window |
5892 | 0 | for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) { |
5893 | 0 | ErrorResult dummy; |
5894 | 0 | RefPtr<Promise> d = mAudioContexts[i]->Resume(dummy); |
5895 | 0 | } |
5896 | 0 |
|
5897 | 0 | mTimeoutManager->Resume(); |
5898 | 0 |
|
5899 | 0 | ResumeIdleRequests(); |
5900 | 0 |
|
5901 | 0 | // Resume all of the workers for this window. We must do this |
5902 | 0 | // after timeouts since workers may have queued events that can trigger |
5903 | 0 | // a setTimeout(). |
5904 | 0 | ResumeWorkersForWindow(this); |
5905 | 0 | } |
5906 | | |
5907 | | bool |
5908 | | nsGlobalWindowInner::IsSuspended() const |
5909 | 0 | { |
5910 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5911 | 0 | return mSuspendDepth != 0; |
5912 | 0 | } |
5913 | | |
5914 | | void |
5915 | | nsGlobalWindowInner::Freeze() |
5916 | 0 | { |
5917 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5918 | 0 | Suspend(); |
5919 | 0 | FreezeInternal(); |
5920 | 0 | } |
5921 | | |
5922 | | void |
5923 | | nsGlobalWindowInner::FreezeInternal() |
5924 | 0 | { |
5925 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5926 | 0 | MOZ_DIAGNOSTIC_ASSERT(IsCurrentInnerWindow()); |
5927 | 0 | MOZ_DIAGNOSTIC_ASSERT(IsSuspended()); |
5928 | 0 |
|
5929 | 0 | CallOnChildren(&nsGlobalWindowInner::FreezeInternal); |
5930 | 0 |
|
5931 | 0 | mFreezeDepth += 1; |
5932 | 0 | MOZ_ASSERT(mSuspendDepth >= mFreezeDepth); |
5933 | 0 | if (mFreezeDepth != 1) { |
5934 | 0 | return; |
5935 | 0 | } |
5936 | 0 | |
5937 | 0 | FreezeWorkersForWindow(this); |
5938 | 0 |
|
5939 | 0 | mTimeoutManager->Freeze(); |
5940 | 0 | if (mClientSource) { |
5941 | 0 | mClientSource->Freeze(); |
5942 | 0 | } |
5943 | 0 |
|
5944 | 0 | NotifyDOMWindowFrozen(this); |
5945 | 0 | } |
5946 | | |
5947 | | void |
5948 | | nsGlobalWindowInner::Thaw() |
5949 | 0 | { |
5950 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5951 | 0 | ThawInternal(); |
5952 | 0 | Resume(); |
5953 | 0 | } |
5954 | | |
5955 | | void |
5956 | | nsGlobalWindowInner::ThawInternal() |
5957 | 0 | { |
5958 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5959 | 0 | MOZ_DIAGNOSTIC_ASSERT(IsCurrentInnerWindow()); |
5960 | 0 | MOZ_DIAGNOSTIC_ASSERT(IsSuspended()); |
5961 | 0 |
|
5962 | 0 | CallOnChildren(&nsGlobalWindowInner::ThawInternal); |
5963 | 0 |
|
5964 | 0 | MOZ_ASSERT(mFreezeDepth != 0); |
5965 | 0 | mFreezeDepth -= 1; |
5966 | 0 | MOZ_ASSERT(mSuspendDepth >= mFreezeDepth); |
5967 | 0 | if (mFreezeDepth != 0) { |
5968 | 0 | return; |
5969 | 0 | } |
5970 | 0 | |
5971 | 0 | if (mClientSource) { |
5972 | 0 | mClientSource->Thaw(); |
5973 | 0 | } |
5974 | 0 | mTimeoutManager->Thaw(); |
5975 | 0 |
|
5976 | 0 | ThawWorkersForWindow(this); |
5977 | 0 |
|
5978 | 0 | NotifyDOMWindowThawed(this); |
5979 | 0 | } |
5980 | | |
5981 | | bool |
5982 | | nsGlobalWindowInner::IsFrozen() const |
5983 | 0 | { |
5984 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
5985 | 0 | bool frozen = mFreezeDepth != 0; |
5986 | 0 | MOZ_ASSERT_IF(frozen, IsSuspended()); |
5987 | 0 | return frozen; |
5988 | 0 | } |
5989 | | |
5990 | | void |
5991 | | nsGlobalWindowInner::SyncStateFromParentWindow() |
5992 | 0 | { |
5993 | 0 | // This method should only be called on an inner window that has been |
5994 | 0 | // assigned to an outer window already. |
5995 | 0 | MOZ_ASSERT(IsCurrentInnerWindow()); |
5996 | 0 | nsPIDOMWindowOuter* outer = GetOuterWindow(); |
5997 | 0 | MOZ_ASSERT(outer); |
5998 | 0 |
|
5999 | 0 | // Attempt to find our parent windows. |
6000 | 0 | nsCOMPtr<Element> frame = outer->GetFrameElementInternal(); |
6001 | 0 | nsPIDOMWindowOuter* parentOuter = frame ? frame->OwnerDoc()->GetWindow() |
6002 | 0 | : nullptr; |
6003 | 0 | nsGlobalWindowInner* parentInner = |
6004 | 0 | parentOuter ? nsGlobalWindowInner::Cast(parentOuter->GetCurrentInnerWindow()) |
6005 | 0 | : nullptr; |
6006 | 0 |
|
6007 | 0 | // If our outer is in a modal state, but our parent is not in a modal |
6008 | 0 | // state, then we must apply the suspend directly. If our parent is |
6009 | 0 | // in a modal state then we should get the suspend automatically |
6010 | 0 | // via the parentSuspendDepth application below. |
6011 | 0 | if ((!parentInner || !parentInner->IsInModalState()) && IsInModalState()) { |
6012 | 0 | Suspend(); |
6013 | 0 | } |
6014 | 0 |
|
6015 | 0 | uint32_t parentFreezeDepth = parentInner ? parentInner->mFreezeDepth : 0; |
6016 | 0 | uint32_t parentSuspendDepth = parentInner ? parentInner->mSuspendDepth : 0; |
6017 | 0 |
|
6018 | 0 | // Since every Freeze() calls Suspend(), the suspend count must |
6019 | 0 | // be equal or greater to the freeze count. |
6020 | 0 | MOZ_ASSERT(parentFreezeDepth <= parentSuspendDepth); |
6021 | 0 |
|
6022 | 0 | // First apply the Freeze() calls. |
6023 | 0 | for (uint32_t i = 0; i < parentFreezeDepth; ++i) { |
6024 | 0 | Freeze(); |
6025 | 0 | } |
6026 | 0 |
|
6027 | 0 | // Now apply only the number of Suspend() calls to reach the target |
6028 | 0 | // suspend count after applying the Freeze() calls. |
6029 | 0 | for (uint32_t i = 0; i < (parentSuspendDepth - parentFreezeDepth); ++i) { |
6030 | 0 | Suspend(); |
6031 | 0 | } |
6032 | 0 | } |
6033 | | |
6034 | | template<typename Method, typename... Args> |
6035 | | nsGlobalWindowInner::CallState |
6036 | | nsGlobalWindowInner::CallOnChildren(Method aMethod, Args& ...aArgs) |
6037 | 0 | { |
6038 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
6039 | 0 | MOZ_ASSERT(IsCurrentInnerWindow()); |
6040 | 0 |
|
6041 | 0 | CallState state = CallState::Continue; |
6042 | 0 |
|
6043 | 0 | nsCOMPtr<nsIDocShell> docShell = GetDocShell(); |
6044 | 0 | if (!docShell) { |
6045 | 0 | return state; |
6046 | 0 | } |
6047 | 0 | |
6048 | 0 | int32_t childCount = 0; |
6049 | 0 | docShell->GetChildCount(&childCount); |
6050 | 0 |
|
6051 | 0 | // Take a copy of the current children so that modifications to |
6052 | 0 | // the child list don't affect to the iteration. |
6053 | 0 | AutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> children; |
6054 | 0 | for (int32_t i = 0; i < childCount; ++i) { |
6055 | 0 | nsCOMPtr<nsIDocShellTreeItem> childShell; |
6056 | 0 | docShell->GetChildAt(i, getter_AddRefs(childShell)); |
6057 | 0 | if (childShell) { |
6058 | 0 | children.AppendElement(childShell); |
6059 | 0 | } |
6060 | 0 | } |
6061 | 0 |
|
6062 | 0 | for (nsCOMPtr<nsIDocShellTreeItem> childShell : children) { |
6063 | 0 | nsCOMPtr<nsPIDOMWindowOuter> pWin = childShell->GetWindow(); |
6064 | 0 | if (!pWin) { |
6065 | 0 | continue; |
6066 | 0 | } |
6067 | 0 | |
6068 | 0 | auto* win = nsGlobalWindowOuter::Cast(pWin); |
6069 | 0 | nsGlobalWindowInner* inner = win->GetCurrentInnerWindowInternal(); |
6070 | 0 |
|
6071 | 0 | // This is a bit hackish. Only freeze/suspend windows which are truly our |
6072 | 0 | // subwindows. |
6073 | 0 | nsCOMPtr<Element> frame = pWin->GetFrameElementInternal(); |
6074 | 0 | if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) { |
6075 | 0 | continue; |
6076 | 0 | } |
6077 | 0 | |
6078 | 0 | // Call the child method using our helper CallChild() template method. |
6079 | 0 | // This allows us to handle both void returning methods and methods |
6080 | 0 | // that return CallState explicitly. For void returning methods we |
6081 | 0 | // assume CallState::Continue. |
6082 | 0 | typedef decltype((inner->*aMethod)(aArgs...)) returnType; |
6083 | 0 | state = CallChild<returnType>(inner, aMethod, aArgs...); |
6084 | 0 |
|
6085 | 0 | if (state == CallState::Stop) { |
6086 | 0 | return state; |
6087 | 0 | } |
6088 | 0 | } |
6089 | 0 |
|
6090 | 0 | return state; |
6091 | 0 | } Unexecuted instantiation: nsGlobalWindowInner::CallState nsGlobalWindowInner::CallOnChildren<nsGlobalWindowInner::CallState (nsGlobalWindowInner::*)(nsTSubstring<char> const&, bool*), nsTSubstring<char> const, bool*>(nsGlobalWindowInner::CallState (nsGlobalWindowInner::*)(nsTSubstring<char> const&, bool*), nsTSubstring<char> const&, bool*&) Unexecuted instantiation: nsGlobalWindowInner::CallState nsGlobalWindowInner::CallOnChildren<void (nsGlobalWindowInner::*)()>(void (nsGlobalWindowInner::*)()) Unexecuted instantiation: nsGlobalWindowInner::CallState nsGlobalWindowInner::CallOnChildren<void (nsGlobalWindowInner::*)(nsTSubstring<char> const&), nsTSubstring<char> const>(void (nsGlobalWindowInner::*)(nsTSubstring<char> const&), nsTSubstring<char> const&) |
6092 | | |
6093 | | Maybe<ClientInfo> |
6094 | | nsGlobalWindowInner::GetClientInfo() const |
6095 | 0 | { |
6096 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
6097 | 0 | Maybe<ClientInfo> clientInfo; |
6098 | 0 | if (mClientSource) { |
6099 | 0 | clientInfo.emplace(mClientSource->Info()); |
6100 | 0 | } |
6101 | 0 | return clientInfo; |
6102 | 0 | } |
6103 | | |
6104 | | Maybe<ClientState> |
6105 | | nsGlobalWindowInner::GetClientState() const |
6106 | 0 | { |
6107 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
6108 | 0 | Maybe<ClientState> clientState; |
6109 | 0 | if (mClientSource) { |
6110 | 0 | ClientState state; |
6111 | 0 | nsresult rv = mClientSource->SnapshotState(&state); |
6112 | 0 | if (NS_SUCCEEDED(rv)) { |
6113 | 0 | clientState.emplace(state); |
6114 | 0 | } |
6115 | 0 | } |
6116 | 0 | return clientState; |
6117 | 0 | } |
6118 | | |
6119 | | Maybe<ServiceWorkerDescriptor> |
6120 | | nsGlobalWindowInner::GetController() const |
6121 | 0 | { |
6122 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
6123 | 0 | Maybe<ServiceWorkerDescriptor> controller; |
6124 | 0 | if (mClientSource) { |
6125 | 0 | controller = mClientSource->GetController(); |
6126 | 0 | } |
6127 | 0 | return controller; |
6128 | 0 | } |
6129 | | |
6130 | | RefPtr<ServiceWorker> |
6131 | | nsGlobalWindowInner::GetOrCreateServiceWorker(const ServiceWorkerDescriptor& aDescriptor) |
6132 | 0 | { |
6133 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
6134 | 0 | RefPtr<ServiceWorker> ref; |
6135 | 0 | ForEachEventTargetObject([&] (DOMEventTargetHelper* aTarget, bool* aDoneOut) { |
6136 | 0 | RefPtr<ServiceWorker> sw = do_QueryObject(aTarget); |
6137 | 0 | if (!sw || !sw->Descriptor().Matches(aDescriptor)) { |
6138 | 0 | return; |
6139 | 0 | } |
6140 | 0 | |
6141 | 0 | ref = sw.forget(); |
6142 | 0 | *aDoneOut = true; |
6143 | 0 | }); |
6144 | 0 |
|
6145 | 0 | if (!ref) { |
6146 | 0 | ref = ServiceWorker::Create(this, aDescriptor); |
6147 | 0 | } |
6148 | 0 |
|
6149 | 0 | return ref.forget(); |
6150 | 0 | } |
6151 | | |
6152 | | RefPtr<mozilla::dom::ServiceWorkerRegistration> |
6153 | | nsGlobalWindowInner::GetServiceWorkerRegistration(const mozilla::dom::ServiceWorkerRegistrationDescriptor& aDescriptor) const |
6154 | 0 | { |
6155 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
6156 | 0 | RefPtr<ServiceWorkerRegistration> ref; |
6157 | 0 | ForEachEventTargetObject([&] (DOMEventTargetHelper* aTarget, bool* aDoneOut) { |
6158 | 0 | RefPtr<ServiceWorkerRegistration> swr = do_QueryObject(aTarget); |
6159 | 0 | if (!swr || !swr->MatchesDescriptor(aDescriptor)) { |
6160 | 0 | return; |
6161 | 0 | } |
6162 | 0 | |
6163 | 0 | ref = swr.forget(); |
6164 | 0 | *aDoneOut = true; |
6165 | 0 | }); |
6166 | 0 | return ref.forget(); |
6167 | 0 | } |
6168 | | |
6169 | | RefPtr<ServiceWorkerRegistration> |
6170 | | nsGlobalWindowInner::GetOrCreateServiceWorkerRegistration(const ServiceWorkerRegistrationDescriptor& aDescriptor) |
6171 | 0 | { |
6172 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
6173 | 0 | RefPtr<ServiceWorkerRegistration> ref = GetServiceWorkerRegistration(aDescriptor); |
6174 | 0 | if (!ref) { |
6175 | 0 | ref = ServiceWorkerRegistration::CreateForMainThread(this, aDescriptor); |
6176 | 0 | } |
6177 | 0 | return ref.forget(); |
6178 | 0 | } |
6179 | | |
6180 | | nsresult |
6181 | | nsGlobalWindowInner::FireDelayedDOMEvents() |
6182 | 0 | { |
6183 | 0 | if (mApplicationCache) { |
6184 | 0 | static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents(); |
6185 | 0 | } |
6186 | 0 |
|
6187 | 0 | // Fires an offline status event if the offline status has changed |
6188 | 0 | FireOfflineStatusEventIfChanged(); |
6189 | 0 |
|
6190 | 0 | if (mNotifyIdleObserversIdleOnThaw) { |
6191 | 0 | mNotifyIdleObserversIdleOnThaw = false; |
6192 | 0 | HandleIdleActiveEvent(); |
6193 | 0 | } |
6194 | 0 |
|
6195 | 0 | if (mNotifyIdleObserversActiveOnThaw) { |
6196 | 0 | mNotifyIdleObserversActiveOnThaw = false; |
6197 | 0 | ScheduleActiveTimerCallback(); |
6198 | 0 | } |
6199 | 0 |
|
6200 | 0 | nsCOMPtr<nsIDocShell> docShell = GetDocShell(); |
6201 | 0 | if (docShell) { |
6202 | 0 | int32_t childCount = 0; |
6203 | 0 | docShell->GetChildCount(&childCount); |
6204 | 0 |
|
6205 | 0 | // Take a copy of the current children so that modifications to |
6206 | 0 | // the child list don't affect to the iteration. |
6207 | 0 | AutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> children; |
6208 | 0 | for (int32_t i = 0; i < childCount; ++i) { |
6209 | 0 | nsCOMPtr<nsIDocShellTreeItem> childShell; |
6210 | 0 | docShell->GetChildAt(i, getter_AddRefs(childShell)); |
6211 | 0 | if (childShell) { |
6212 | 0 | children.AppendElement(childShell); |
6213 | 0 | } |
6214 | 0 | } |
6215 | 0 |
|
6216 | 0 | for (nsCOMPtr<nsIDocShellTreeItem> childShell : children) { |
6217 | 0 | if (nsCOMPtr<nsPIDOMWindowOuter> pWin = childShell->GetWindow()) { |
6218 | 0 | auto* win = nsGlobalWindowOuter::Cast(pWin); |
6219 | 0 | win->FireDelayedDOMEvents(); |
6220 | 0 | } |
6221 | 0 | } |
6222 | 0 | } |
6223 | 0 |
|
6224 | 0 | return NS_OK; |
6225 | 0 | } |
6226 | | |
6227 | | //***************************************************************************** |
6228 | | // nsGlobalWindowInner: Window Control Functions |
6229 | | //***************************************************************************** |
6230 | | |
6231 | | nsPIDOMWindowOuter* |
6232 | | nsGlobalWindowInner::GetParentInternal() |
6233 | 0 | { |
6234 | 0 | nsGlobalWindowOuter* outer = GetOuterWindowInternal(); |
6235 | 0 | if (!outer) { |
6236 | 0 | // No outer window available! |
6237 | 0 | return nullptr; |
6238 | 0 | } |
6239 | 0 | return outer->GetParentInternal(); |
6240 | 0 | } |
6241 | | |
6242 | | nsIPrincipal* |
6243 | | nsGlobalWindowInner::GetTopLevelPrincipal() |
6244 | 0 | { |
6245 | 0 | nsPIDOMWindowOuter* outerWindow = GetOuterWindowInternal(); |
6246 | 0 | if (!outerWindow) { |
6247 | 0 | return nullptr; |
6248 | 0 | } |
6249 | 0 | |
6250 | 0 | nsPIDOMWindowOuter* topLevelOuterWindow = GetTopInternal(); |
6251 | 0 | if (!topLevelOuterWindow) { |
6252 | 0 | return nullptr; |
6253 | 0 | } |
6254 | 0 | |
6255 | 0 | if (topLevelOuterWindow == outerWindow) { |
6256 | 0 | return nullptr; |
6257 | 0 | } |
6258 | 0 | |
6259 | 0 | nsPIDOMWindowInner* topLevelInnerWindow = |
6260 | 0 | topLevelOuterWindow->GetCurrentInnerWindow(); |
6261 | 0 | if (NS_WARN_IF(!topLevelInnerWindow)) { |
6262 | 0 | return nullptr; |
6263 | 0 | } |
6264 | 0 | |
6265 | 0 | nsIPrincipal* topLevelPrincipal = |
6266 | 0 | nsGlobalWindowInner::Cast(topLevelInnerWindow)->GetPrincipal(); |
6267 | 0 | if (NS_WARN_IF(!topLevelPrincipal)) { |
6268 | 0 | return nullptr; |
6269 | 0 | } |
6270 | 0 | |
6271 | 0 | return topLevelPrincipal; |
6272 | 0 | } |
6273 | | |
6274 | | nsIPrincipal* |
6275 | | nsGlobalWindowInner::GetTopLevelStorageAreaPrincipal() |
6276 | 0 | { |
6277 | 0 | if (mDoc && ((mDoc->GetSandboxFlags() & SANDBOXED_STORAGE_ACCESS) != 0 || |
6278 | 0 | nsContentUtils::IsInPrivateBrowsing(mDoc))) { |
6279 | 0 | // Storage access is disabled |
6280 | 0 | return nullptr; |
6281 | 0 | } |
6282 | 0 | |
6283 | 0 | nsPIDOMWindowOuter* outerWindow = GetParentInternal(); |
6284 | 0 | if (!outerWindow) { |
6285 | 0 | // No outer window available! |
6286 | 0 | return nullptr; |
6287 | 0 | } |
6288 | 0 | |
6289 | 0 | if (!outerWindow->IsTopLevelWindow()) { |
6290 | 0 | return nullptr; |
6291 | 0 | } |
6292 | 0 | |
6293 | 0 | nsPIDOMWindowInner* innerWindow = outerWindow->GetCurrentInnerWindow(); |
6294 | 0 | if (NS_WARN_IF(!innerWindow)) { |
6295 | 0 | return nullptr; |
6296 | 0 | } |
6297 | 0 | |
6298 | 0 | nsIPrincipal* parentPrincipal = |
6299 | 0 | nsGlobalWindowInner::Cast(innerWindow)->GetPrincipal(); |
6300 | 0 | if (NS_WARN_IF(!parentPrincipal)) { |
6301 | 0 | return nullptr; |
6302 | 0 | } |
6303 | 0 | |
6304 | 0 | return parentPrincipal; |
6305 | 0 | } |
6306 | | |
6307 | | |
6308 | | //***************************************************************************** |
6309 | | // nsGlobalWindowInner: Timeout Functions |
6310 | | //***************************************************************************** |
6311 | | |
6312 | | nsGlobalWindowInner* |
6313 | | nsGlobalWindowInner::InnerForSetTimeoutOrInterval(ErrorResult& aError) |
6314 | 0 | { |
6315 | 0 | nsGlobalWindowOuter* outer = GetOuterWindowInternal(); |
6316 | 0 | nsGlobalWindowInner* currentInner = outer ? outer->GetCurrentInnerWindowInternal() : this; |
6317 | 0 |
|
6318 | 0 | // If forwardTo is not the window with an active document then we want the |
6319 | 0 | // call to setTimeout/Interval to be a noop, so return null but don't set an |
6320 | 0 | // error. |
6321 | 0 | return HasActiveDocument() ? currentInner : nullptr; |
6322 | 0 | } |
6323 | | |
6324 | | int32_t |
6325 | | nsGlobalWindowInner::SetTimeout(JSContext* aCx, Function& aFunction, |
6326 | | int32_t aTimeout, |
6327 | | const Sequence<JS::Value>& aArguments, |
6328 | | ErrorResult& aError) |
6329 | 0 | { |
6330 | 0 | return SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments, false, |
6331 | 0 | aError); |
6332 | 0 | } |
6333 | | |
6334 | | int32_t |
6335 | | nsGlobalWindowInner::SetTimeout(JSContext* aCx, const nsAString& aHandler, |
6336 | | int32_t aTimeout, |
6337 | | const Sequence<JS::Value>& /* unused */, |
6338 | | ErrorResult& aError) |
6339 | 0 | { |
6340 | 0 | return SetTimeoutOrInterval(aCx, aHandler, aTimeout, false, aError); |
6341 | 0 | } |
6342 | | |
6343 | | int32_t |
6344 | | nsGlobalWindowInner::SetInterval(JSContext* aCx, Function& aFunction, |
6345 | | const int32_t aTimeout, |
6346 | | const Sequence<JS::Value>& aArguments, |
6347 | | ErrorResult& aError) |
6348 | 0 | { |
6349 | 0 | return SetTimeoutOrInterval( |
6350 | 0 | aCx, aFunction, aTimeout, aArguments, true, aError); |
6351 | 0 | } |
6352 | | |
6353 | | int32_t |
6354 | | nsGlobalWindowInner::SetInterval(JSContext* aCx, const nsAString& aHandler, |
6355 | | const int32_t aTimeout, |
6356 | | const Sequence<JS::Value>& /* unused */, |
6357 | | ErrorResult& aError) |
6358 | 0 | { |
6359 | 0 | return SetTimeoutOrInterval(aCx, aHandler, aTimeout, true, aError); |
6360 | 0 | } |
6361 | | |
6362 | | int32_t |
6363 | | nsGlobalWindowInner::SetTimeoutOrInterval(JSContext *aCx, Function& aFunction, |
6364 | | int32_t aTimeout, |
6365 | | const Sequence<JS::Value>& aArguments, |
6366 | | bool aIsInterval, ErrorResult& aError) |
6367 | 0 | { |
6368 | 0 | nsGlobalWindowInner* inner = InnerForSetTimeoutOrInterval(aError); |
6369 | 0 | if (!inner) { |
6370 | 0 | return -1; |
6371 | 0 | } |
6372 | 0 | |
6373 | 0 | if (inner != this) { |
6374 | 0 | return inner->SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments, |
6375 | 0 | aIsInterval, aError); |
6376 | 0 | } |
6377 | 0 | |
6378 | 0 | nsCOMPtr<nsIScriptTimeoutHandler> handler = |
6379 | 0 | NS_CreateJSTimeoutHandler(aCx, this, aFunction, aArguments, aError); |
6380 | 0 | if (!handler) { |
6381 | 0 | return 0; |
6382 | 0 | } |
6383 | 0 | |
6384 | 0 | int32_t result; |
6385 | 0 | aError = mTimeoutManager->SetTimeout(handler, aTimeout, aIsInterval, |
6386 | 0 | Timeout::Reason::eTimeoutOrInterval, |
6387 | 0 | &result); |
6388 | 0 | return result; |
6389 | 0 | } |
6390 | | |
6391 | | int32_t |
6392 | | nsGlobalWindowInner::SetTimeoutOrInterval(JSContext* aCx, const nsAString& aHandler, |
6393 | | int32_t aTimeout, bool aIsInterval, |
6394 | | ErrorResult& aError) |
6395 | 0 | { |
6396 | 0 | nsGlobalWindowInner* inner = InnerForSetTimeoutOrInterval(aError); |
6397 | 0 | if (!inner) { |
6398 | 0 | return -1; |
6399 | 0 | } |
6400 | 0 | |
6401 | 0 | if (inner != this) { |
6402 | 0 | return inner->SetTimeoutOrInterval(aCx, aHandler, aTimeout, aIsInterval, |
6403 | 0 | aError); |
6404 | 0 | } |
6405 | 0 | |
6406 | 0 | nsCOMPtr<nsIScriptTimeoutHandler> handler = |
6407 | 0 | NS_CreateJSTimeoutHandler(aCx, this, aHandler, aError); |
6408 | 0 | if (!handler) { |
6409 | 0 | return 0; |
6410 | 0 | } |
6411 | 0 | |
6412 | 0 | int32_t result; |
6413 | 0 | aError = mTimeoutManager->SetTimeout(handler, aTimeout, aIsInterval, |
6414 | 0 | Timeout::Reason::eTimeoutOrInterval, |
6415 | 0 | &result); |
6416 | 0 | return result; |
6417 | 0 | } |
6418 | | |
6419 | | bool |
6420 | | nsGlobalWindowInner::RunTimeoutHandler(Timeout* aTimeout, |
6421 | | nsIScriptContext* aScx) |
6422 | 0 | { |
6423 | 0 | // Hold on to the timeout in case mExpr or mFunObj releases its |
6424 | 0 | // doc. |
6425 | 0 | RefPtr<Timeout> timeout = aTimeout; |
6426 | 0 | Timeout* last_running_timeout = mTimeoutManager->BeginRunningTimeout(timeout); |
6427 | 0 | timeout->mRunning = true; |
6428 | 0 |
|
6429 | 0 | // Push this timeout's popup control state, which should only be |
6430 | 0 | // eabled the first time a timeout fires that was created while |
6431 | 0 | // popups were enabled and with a delay less than |
6432 | 0 | // "dom.disable_open_click_delay". |
6433 | 0 | nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState); |
6434 | 0 |
|
6435 | 0 | // Clear the timeout's popup state, if any, to prevent interval |
6436 | 0 | // timeouts from repeatedly opening poups. |
6437 | 0 | timeout->mPopupState = openAbused; |
6438 | 0 |
|
6439 | 0 | bool trackNestingLevel = !timeout->mIsInterval; |
6440 | 0 | uint32_t nestingLevel; |
6441 | 0 | if (trackNestingLevel) { |
6442 | 0 | nestingLevel = TimeoutManager::GetNestingLevel(); |
6443 | 0 | TimeoutManager::SetNestingLevel(timeout->mNestingLevel); |
6444 | 0 | } |
6445 | 0 |
|
6446 | 0 | const char *reason; |
6447 | 0 | if (timeout->mIsInterval) { |
6448 | 0 | reason = "setInterval handler"; |
6449 | 0 | } else { |
6450 | 0 | reason = "setTimeout handler"; |
6451 | 0 | } |
6452 | 0 |
|
6453 | 0 | bool abortIntervalHandler = false; |
6454 | 0 | nsCOMPtr<nsIScriptTimeoutHandler> handler(do_QueryInterface(timeout->mScriptHandler)); |
6455 | 0 | if (handler) { |
6456 | 0 | RefPtr<Function> callback = handler->GetCallback(); |
6457 | 0 |
|
6458 | 0 | if (!callback) { |
6459 | 0 | // Evaluate the timeout expression. |
6460 | 0 | const nsAString& script = handler->GetHandlerText(); |
6461 | 0 |
|
6462 | 0 | const char* filename = nullptr; |
6463 | 0 | uint32_t lineNo = 0, dummyColumn = 0; |
6464 | 0 | handler->GetLocation(&filename, &lineNo, &dummyColumn); |
6465 | 0 |
|
6466 | 0 | // New script entry point required, due to the "Create a script" sub-step of |
6467 | 0 | // http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-steps |
6468 | 0 | nsAutoMicroTask mt; |
6469 | 0 | AutoEntryScript aes(this, reason, true); |
6470 | 0 | JS::CompileOptions options(aes.cx()); |
6471 | 0 | options.setFileAndLine(filename, lineNo); |
6472 | 0 | options.setNoScriptRval(true); |
6473 | 0 | JS::Rooted<JSObject*> global(aes.cx(), FastGetGlobalJSObject()); |
6474 | 0 | nsresult rv; |
6475 | 0 | { |
6476 | 0 | nsJSUtils::ExecutionContext exec(aes.cx(), global); |
6477 | 0 | rv = exec.CompileAndExec(options, script); |
6478 | 0 | } |
6479 | 0 |
|
6480 | 0 | if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) { |
6481 | 0 | abortIntervalHandler = true; |
6482 | 0 | } |
6483 | 0 | } else { |
6484 | 0 | // Hold strong ref to ourselves while we call the callback. |
6485 | 0 | nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow*>(this)); |
6486 | 0 | ErrorResult rv; |
6487 | 0 | JS::Rooted<JS::Value> ignoredVal(RootingCx()); |
6488 | 0 | callback->Call(me, handler->GetArgs(), &ignoredVal, rv, reason); |
6489 | 0 | if (rv.IsUncatchableException()) { |
6490 | 0 | abortIntervalHandler = true; |
6491 | 0 | } |
6492 | 0 |
|
6493 | 0 | rv.SuppressException(); |
6494 | 0 | } |
6495 | 0 | } else { |
6496 | 0 | nsCOMPtr<nsITimeoutHandler> basicHandler(timeout->mScriptHandler); |
6497 | 0 | nsCOMPtr<nsISupports> kungFuDeathGrip(static_cast<nsIDOMWindow*>(this)); |
6498 | 0 | mozilla::Unused << kungFuDeathGrip; |
6499 | 0 | basicHandler->Call(); |
6500 | 0 | } |
6501 | 0 |
|
6502 | 0 | // If we received an uncatchable exception, do not schedule the timeout again. |
6503 | 0 | // This allows the slow script dialog to break easy DoS attacks like |
6504 | 0 | // setInterval(function() { while(1); }, 100); |
6505 | 0 | if (abortIntervalHandler) { |
6506 | 0 | // If it wasn't an interval timer to begin with, this does nothing. If it |
6507 | 0 | // was, we'll treat it as a timeout that we just ran and discard it when |
6508 | 0 | // we return. |
6509 | 0 | timeout->mIsInterval = false; |
6510 | 0 | } |
6511 | 0 |
|
6512 | 0 | // We ignore any failures from calling EvaluateString() on the context or |
6513 | 0 | // Call() on a Function here since we're in a loop |
6514 | 0 | // where we're likely to be running timeouts whose OS timers |
6515 | 0 | // didn't fire in time and we don't want to not fire those timers |
6516 | 0 | // now just because execution of one timer failed. We can't |
6517 | 0 | // propagate the error to anyone who cares about it from this |
6518 | 0 | // point anyway, and the script context should have already reported |
6519 | 0 | // the script error in the usual way - so we just drop it. |
6520 | 0 |
|
6521 | 0 | if (trackNestingLevel) { |
6522 | 0 | TimeoutManager::SetNestingLevel(nestingLevel); |
6523 | 0 | } |
6524 | 0 |
|
6525 | 0 | mTimeoutManager->EndRunningTimeout(last_running_timeout); |
6526 | 0 | timeout->mRunning = false; |
6527 | 0 |
|
6528 | 0 | return timeout->mCleared; |
6529 | 0 | } |
6530 | | |
6531 | | //***************************************************************************** |
6532 | | // nsGlobalWindowInner: Helper Functions |
6533 | | //***************************************************************************** |
6534 | | |
6535 | | already_AddRefed<nsIDocShellTreeOwner> |
6536 | | nsGlobalWindowInner::GetTreeOwner() |
6537 | 0 | { |
6538 | 0 | FORWARD_TO_OUTER(GetTreeOwner, (), nullptr); |
6539 | 0 | } |
6540 | | |
6541 | | already_AddRefed<nsIWebBrowserChrome> |
6542 | | nsGlobalWindowInner::GetWebBrowserChrome() |
6543 | 0 | { |
6544 | 0 | nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner(); |
6545 | 0 |
|
6546 | 0 | nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(treeOwner); |
6547 | 0 | return browserChrome.forget(); |
6548 | 0 | } |
6549 | | |
6550 | | nsIScrollableFrame * |
6551 | | nsGlobalWindowInner::GetScrollFrame() |
6552 | 0 | { |
6553 | 0 | FORWARD_TO_OUTER(GetScrollFrame, (), nullptr); |
6554 | 0 | } |
6555 | | |
6556 | | bool |
6557 | | nsGlobalWindowInner::IsPrivateBrowsing() |
6558 | 0 | { |
6559 | 0 | nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(GetDocShell()); |
6560 | 0 | return loadContext && loadContext->UsePrivateBrowsing(); |
6561 | 0 | } |
6562 | | |
6563 | | void |
6564 | | nsGlobalWindowInner::FlushPendingNotifications(FlushType aType) |
6565 | 0 | { |
6566 | 0 | if (mDoc) { |
6567 | 0 | mDoc->FlushPendingNotifications(aType); |
6568 | 0 | } |
6569 | 0 | } |
6570 | | |
6571 | | void |
6572 | | nsGlobalWindowInner::EnableDeviceSensor(uint32_t aType) |
6573 | 0 | { |
6574 | 0 | bool alreadyEnabled = false; |
6575 | 0 | for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) { |
6576 | 0 | if (mEnabledSensors[i] == aType) { |
6577 | 0 | alreadyEnabled = true; |
6578 | 0 | break; |
6579 | 0 | } |
6580 | 0 | } |
6581 | 0 |
|
6582 | 0 | mEnabledSensors.AppendElement(aType); |
6583 | 0 |
|
6584 | 0 | if (alreadyEnabled) { |
6585 | 0 | return; |
6586 | 0 | } |
6587 | 0 | |
6588 | 0 | nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID); |
6589 | 0 | if (ac) { |
6590 | 0 | ac->AddWindowListener(aType, this); |
6591 | 0 | } |
6592 | 0 | } |
6593 | | |
6594 | | void |
6595 | | nsGlobalWindowInner::DisableDeviceSensor(uint32_t aType) |
6596 | 0 | { |
6597 | 0 | int32_t doomedElement = -1; |
6598 | 0 | int32_t listenerCount = 0; |
6599 | 0 | for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) { |
6600 | 0 | if (mEnabledSensors[i] == aType) { |
6601 | 0 | doomedElement = i; |
6602 | 0 | listenerCount++; |
6603 | 0 | } |
6604 | 0 | } |
6605 | 0 |
|
6606 | 0 | if (doomedElement == -1) { |
6607 | 0 | return; |
6608 | 0 | } |
6609 | 0 | |
6610 | 0 | mEnabledSensors.RemoveElementAt(doomedElement); |
6611 | 0 |
|
6612 | 0 | if (listenerCount > 1) { |
6613 | 0 | return; |
6614 | 0 | } |
6615 | 0 | |
6616 | 0 | nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID); |
6617 | 0 | if (ac) { |
6618 | 0 | ac->RemoveWindowListener(aType, this); |
6619 | 0 | } |
6620 | 0 | } |
6621 | | |
6622 | | #if defined(MOZ_WIDGET_ANDROID) |
6623 | | void |
6624 | | nsGlobalWindowInner::EnableOrientationChangeListener() |
6625 | | { |
6626 | | // XXX: mDocShell is never set on the inner window? |
6627 | | nsIDocShell* docShell = nullptr; |
6628 | | if (!nsContentUtils::ShouldResistFingerprinting(docShell) && |
6629 | | !mOrientationChangeObserver) { |
6630 | | mOrientationChangeObserver = |
6631 | | MakeUnique<WindowOrientationObserver>(this); |
6632 | | } |
6633 | | } |
6634 | | |
6635 | | void |
6636 | | nsGlobalWindowInner::DisableOrientationChangeListener() |
6637 | | { |
6638 | | mOrientationChangeObserver = nullptr; |
6639 | | } |
6640 | | #endif |
6641 | | |
6642 | | void |
6643 | | nsGlobalWindowInner::SetHasGamepadEventListener(bool aHasGamepad/* = true*/) |
6644 | 0 | { |
6645 | 0 | mHasGamepad = aHasGamepad; |
6646 | 0 | if (aHasGamepad) { |
6647 | 0 | EnableGamepadUpdates(); |
6648 | 0 | } |
6649 | 0 | } |
6650 | | |
6651 | | |
6652 | | void |
6653 | | nsGlobalWindowInner::EventListenerAdded(nsAtom* aType) |
6654 | 0 | { |
6655 | 0 | if (aType == nsGkAtoms::onvrdisplayactivate || |
6656 | 0 | aType == nsGkAtoms::onvrdisplayconnect || |
6657 | 0 | aType == nsGkAtoms::onvrdisplaydeactivate || |
6658 | 0 | aType == nsGkAtoms::onvrdisplaydisconnect || |
6659 | 0 | aType == nsGkAtoms::onvrdisplaypresentchange) { |
6660 | 0 | NotifyVREventListenerAdded(); |
6661 | 0 | } |
6662 | 0 |
|
6663 | 0 | if (aType == nsGkAtoms::onvrdisplayactivate) { |
6664 | 0 | mHasVRDisplayActivateEvents = true; |
6665 | 0 | } |
6666 | 0 |
|
6667 | 0 | if (aType == nsGkAtoms::onbeforeunload && |
6668 | 0 | mTabChild && |
6669 | 0 | (!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS))) { |
6670 | 0 | mBeforeUnloadListenerCount++; |
6671 | 0 | MOZ_ASSERT(mBeforeUnloadListenerCount > 0); |
6672 | 0 | mTabChild->BeforeUnloadAdded(); |
6673 | 0 | } |
6674 | 0 |
|
6675 | 0 | // We need to initialize localStorage in order to receive notifications. |
6676 | 0 | if (aType == nsGkAtoms::onstorage) { |
6677 | 0 | ErrorResult rv; |
6678 | 0 | GetLocalStorage(rv); |
6679 | 0 | rv.SuppressException(); |
6680 | 0 | } |
6681 | 0 | } |
6682 | | |
6683 | | void |
6684 | | nsGlobalWindowInner::EventListenerRemoved(nsAtom* aType) |
6685 | 0 | { |
6686 | 0 | if (aType == nsGkAtoms::onbeforeunload && |
6687 | 0 | mTabChild && |
6688 | 0 | (!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS))) { |
6689 | 0 | mBeforeUnloadListenerCount--; |
6690 | 0 | MOZ_ASSERT(mBeforeUnloadListenerCount >= 0); |
6691 | 0 | mTabChild->BeforeUnloadRemoved(); |
6692 | 0 | } |
6693 | 0 | } |
6694 | | |
6695 | | void |
6696 | | nsGlobalWindowInner::NotifyVREventListenerAdded() |
6697 | 0 | { |
6698 | 0 | mHasVREvents = true; |
6699 | 0 | EnableVRUpdates(); |
6700 | 0 | } |
6701 | | |
6702 | | bool |
6703 | | nsGlobalWindowInner::HasUsedVR() const |
6704 | 0 | { |
6705 | 0 | // Returns true only if any WebVR API call or related event |
6706 | 0 | // has been used |
6707 | 0 | return mHasVREvents; |
6708 | 0 | } |
6709 | | |
6710 | | bool |
6711 | | nsGlobalWindowInner::IsVRContentDetected() const |
6712 | 0 | { |
6713 | 0 | // Returns true only if the content will respond to |
6714 | 0 | // the VRDisplayActivate event. |
6715 | 0 | return mHasVRDisplayActivateEvents; |
6716 | 0 | } |
6717 | | |
6718 | | bool |
6719 | | nsGlobalWindowInner::IsVRContentPresenting() const |
6720 | 0 | { |
6721 | 0 | for (const auto& display : mVRDisplays) { |
6722 | 0 | if (display->IsAnyPresenting(gfx::kVRGroupAll)) { |
6723 | 0 | return true; |
6724 | 0 | } |
6725 | 0 | } |
6726 | 0 | return false; |
6727 | 0 | } |
6728 | | |
6729 | | void |
6730 | | nsGlobalWindowInner::AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes) const |
6731 | 0 | { |
6732 | 0 | aWindowSizes.mDOMOtherSize += aWindowSizes.mState.mMallocSizeOf(this); |
6733 | 0 | aWindowSizes.mDOMOtherSize += |
6734 | 0 | nsIGlobalObject::ShallowSizeOfExcludingThis(aWindowSizes.mState.mMallocSizeOf); |
6735 | 0 |
|
6736 | 0 | EventListenerManager* elm = GetExistingListenerManager(); |
6737 | 0 | if (elm) { |
6738 | 0 | aWindowSizes.mDOMOtherSize += |
6739 | 0 | elm->SizeOfIncludingThis(aWindowSizes.mState.mMallocSizeOf); |
6740 | 0 | aWindowSizes.mDOMEventListenersCount += elm->ListenerCount(); |
6741 | 0 | } |
6742 | 0 | if (mDoc) { |
6743 | 0 | // Multiple global windows can share a document. So only measure the |
6744 | 0 | // document if it (a) doesn't have a global window, or (b) it's the |
6745 | 0 | // primary document for the window. |
6746 | 0 | if (!mDoc->GetInnerWindow() || |
6747 | 0 | mDoc->GetInnerWindow() == this) { |
6748 | 0 | mDoc->DocAddSizeOfIncludingThis(aWindowSizes); |
6749 | 0 | } |
6750 | 0 | } |
6751 | 0 |
|
6752 | 0 | if (mNavigator) { |
6753 | 0 | aWindowSizes.mDOMOtherSize += |
6754 | 0 | mNavigator->SizeOfIncludingThis(aWindowSizes.mState.mMallocSizeOf); |
6755 | 0 | } |
6756 | 0 |
|
6757 | 0 | ForEachEventTargetObject([&] (DOMEventTargetHelper* et, bool* aDoneOut) { |
6758 | 0 | if (nsCOMPtr<nsISizeOfEventTarget> iSizeOf = do_QueryObject(et)) { |
6759 | 0 | aWindowSizes.mDOMEventTargetsSize += |
6760 | 0 | iSizeOf->SizeOfEventTargetIncludingThis( |
6761 | 0 | aWindowSizes.mState.mMallocSizeOf); |
6762 | 0 | } |
6763 | 0 | if (EventListenerManager* elm = et->GetExistingListenerManager()) { |
6764 | 0 | aWindowSizes.mDOMEventListenersCount += elm->ListenerCount(); |
6765 | 0 | } |
6766 | 0 | ++aWindowSizes.mDOMEventTargetsCount; |
6767 | 0 | }); |
6768 | 0 |
|
6769 | 0 | if (mPerformance) { |
6770 | 0 | aWindowSizes.mDOMPerformanceUserEntries = |
6771 | 0 | mPerformance->SizeOfUserEntries(aWindowSizes.mState.mMallocSizeOf); |
6772 | 0 | aWindowSizes.mDOMPerformanceResourceEntries = |
6773 | 0 | mPerformance->SizeOfResourceEntries(aWindowSizes.mState.mMallocSizeOf); |
6774 | 0 | } |
6775 | 0 |
|
6776 | 0 | aWindowSizes.mDOMOtherSize += |
6777 | 0 | mPendingPromises.ShallowSizeOfExcludingThis(aWindowSizes.mState.mMallocSizeOf); |
6778 | 0 | } |
6779 | | |
6780 | | void |
6781 | | nsGlobalWindowInner::AddGamepad(uint32_t aIndex, Gamepad* aGamepad) |
6782 | 0 | { |
6783 | 0 | // Create the index we will present to content based on which indices are |
6784 | 0 | // already taken, as required by the spec. |
6785 | 0 | // https://w3c.github.io/gamepad/gamepad.html#widl-Gamepad-index |
6786 | 0 | int index = 0; |
6787 | 0 | while(mGamepadIndexSet.Contains(index)) { |
6788 | 0 | ++index; |
6789 | 0 | } |
6790 | 0 | mGamepadIndexSet.Put(index); |
6791 | 0 | aGamepad->SetIndex(index); |
6792 | 0 | mGamepads.Put(aIndex, aGamepad); |
6793 | 0 | } |
6794 | | |
6795 | | void |
6796 | | nsGlobalWindowInner::RemoveGamepad(uint32_t aIndex) |
6797 | 0 | { |
6798 | 0 | RefPtr<Gamepad> gamepad; |
6799 | 0 | if (!mGamepads.Get(aIndex, getter_AddRefs(gamepad))) { |
6800 | 0 | return; |
6801 | 0 | } |
6802 | 0 | // Free up the index we were using so it can be reused |
6803 | 0 | mGamepadIndexSet.Remove(gamepad->Index()); |
6804 | 0 | mGamepads.Remove(aIndex); |
6805 | 0 | } |
6806 | | |
6807 | | void |
6808 | | nsGlobalWindowInner::GetGamepads(nsTArray<RefPtr<Gamepad> >& aGamepads) |
6809 | 0 | { |
6810 | 0 | aGamepads.Clear(); |
6811 | 0 |
|
6812 | 0 | // navigator.getGamepads() always returns an empty array when |
6813 | 0 | // privacy.resistFingerprinting is true. |
6814 | 0 | if (nsContentUtils::ShouldResistFingerprinting()) { |
6815 | 0 | return; |
6816 | 0 | } |
6817 | 0 | |
6818 | 0 | // mGamepads.Count() may not be sufficient, but it's not harmful. |
6819 | 0 | aGamepads.SetCapacity(mGamepads.Count()); |
6820 | 0 | for (auto iter = mGamepads.Iter(); !iter.Done(); iter.Next()) { |
6821 | 0 | Gamepad* gamepad = iter.UserData(); |
6822 | 0 | aGamepads.EnsureLengthAtLeast(gamepad->Index() + 1); |
6823 | 0 | aGamepads[gamepad->Index()] = gamepad; |
6824 | 0 | } |
6825 | 0 | } |
6826 | | |
6827 | | already_AddRefed<Gamepad> |
6828 | | nsGlobalWindowInner::GetGamepad(uint32_t aIndex) |
6829 | 0 | { |
6830 | 0 | RefPtr<Gamepad> gamepad; |
6831 | 0 |
|
6832 | 0 | if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) { |
6833 | 0 | return gamepad.forget(); |
6834 | 0 | } |
6835 | 0 | |
6836 | 0 | return nullptr; |
6837 | 0 | } |
6838 | | |
6839 | | void |
6840 | | nsGlobalWindowInner::SetHasSeenGamepadInput(bool aHasSeen) |
6841 | 0 | { |
6842 | 0 | mHasSeenGamepadInput = aHasSeen; |
6843 | 0 | } |
6844 | | |
6845 | | bool |
6846 | | nsGlobalWindowInner::HasSeenGamepadInput() |
6847 | 0 | { |
6848 | 0 | return mHasSeenGamepadInput; |
6849 | 0 | } |
6850 | | |
6851 | | void |
6852 | | nsGlobalWindowInner::SyncGamepadState() |
6853 | 0 | { |
6854 | 0 | if (mHasSeenGamepadInput) { |
6855 | 0 | RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService()); |
6856 | 0 | for (auto iter = mGamepads.Iter(); !iter.Done(); iter.Next()) { |
6857 | 0 | gamepadManager->SyncGamepadState(iter.Key(), iter.UserData()); |
6858 | 0 | } |
6859 | 0 | } |
6860 | 0 | } |
6861 | | |
6862 | | void |
6863 | | nsGlobalWindowInner::StopGamepadHaptics() |
6864 | 0 | { |
6865 | 0 | if (mHasSeenGamepadInput) { |
6866 | 0 | RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService()); |
6867 | 0 | gamepadManager->StopHaptics(); |
6868 | 0 | } |
6869 | 0 | } |
6870 | | |
6871 | | bool |
6872 | | nsGlobalWindowInner::UpdateVRDisplays(nsTArray<RefPtr<mozilla::dom::VRDisplay>>& aDevices) |
6873 | 0 | { |
6874 | 0 | VRDisplay::UpdateVRDisplays(mVRDisplays, this); |
6875 | 0 | aDevices = mVRDisplays; |
6876 | 0 | return true; |
6877 | 0 | } |
6878 | | |
6879 | | void |
6880 | | nsGlobalWindowInner::NotifyActiveVRDisplaysChanged() |
6881 | 0 | { |
6882 | 0 | if (mNavigator) { |
6883 | 0 | mNavigator->NotifyActiveVRDisplaysChanged(); |
6884 | 0 | } |
6885 | 0 | } |
6886 | | |
6887 | | void |
6888 | 0 | nsGlobalWindowInner::NotifyPresentationGenerationChanged(uint32_t aDisplayID) { |
6889 | 0 | for (const auto& display : mVRDisplays) { |
6890 | 0 | if (display->DisplayId() == aDisplayID) { |
6891 | 0 | display->OnPresentationGenerationChanged(); |
6892 | 0 | } |
6893 | 0 | } |
6894 | 0 | } |
6895 | | |
6896 | | void |
6897 | | nsGlobalWindowInner::DispatchVRDisplayActivate(uint32_t aDisplayID, |
6898 | | mozilla::dom::VRDisplayEventReason aReason) |
6899 | 0 | { |
6900 | 0 | // Ensure that our list of displays is up to date |
6901 | 0 | VRDisplay::UpdateVRDisplays(mVRDisplays, this); |
6902 | 0 |
|
6903 | 0 | // Search for the display identified with aDisplayID and fire the |
6904 | 0 | // event if found. |
6905 | 0 | for (const auto& display : mVRDisplays) { |
6906 | 0 | if (display->DisplayId() == aDisplayID) { |
6907 | 0 | if (aReason != VRDisplayEventReason::Navigation && |
6908 | 0 | display->IsAnyPresenting(gfx::kVRGroupContent)) { |
6909 | 0 | // We only want to trigger this event if nobody is presenting to the |
6910 | 0 | // display already or when a page is loaded by navigating away |
6911 | 0 | // from a page with an active VR Presentation. |
6912 | 0 | continue; |
6913 | 0 | } |
6914 | 0 | |
6915 | 0 | VRDisplayEventInit init; |
6916 | 0 | init.mBubbles = false; |
6917 | 0 | init.mCancelable = false; |
6918 | 0 | init.mDisplay = display; |
6919 | 0 | init.mReason.Construct(aReason); |
6920 | 0 |
|
6921 | 0 | RefPtr<VRDisplayEvent> event = |
6922 | 0 | VRDisplayEvent::Constructor(this, |
6923 | 0 | NS_LITERAL_STRING("vrdisplayactivate"), |
6924 | 0 | init); |
6925 | 0 | // vrdisplayactivate is a trusted event, allowing VRDisplay.requestPresent |
6926 | 0 | // to be used in response to link traversal, user request (chrome UX), and |
6927 | 0 | // HMD mounting detection sensors. |
6928 | 0 | event->SetTrusted(true); |
6929 | 0 | // VRDisplay.requestPresent normally requires a user gesture; however, an |
6930 | 0 | // exception is made to allow it to be called in response to vrdisplayactivate |
6931 | 0 | // during VR link traversal. |
6932 | 0 | display->StartHandlingVRNavigationEvent(); |
6933 | 0 | DispatchEvent(*event); |
6934 | 0 | display->StopHandlingVRNavigationEvent(); |
6935 | 0 | // Once we dispatch the event, we must not access any members as an event |
6936 | 0 | // listener can do anything, including closing windows. |
6937 | 0 | return; |
6938 | 0 | } |
6939 | 0 | } |
6940 | 0 | } |
6941 | | |
6942 | | void |
6943 | | nsGlobalWindowInner::DispatchVRDisplayDeactivate(uint32_t aDisplayID, |
6944 | | mozilla::dom::VRDisplayEventReason aReason) |
6945 | 0 | { |
6946 | 0 | // Ensure that our list of displays is up to date |
6947 | 0 | VRDisplay::UpdateVRDisplays(mVRDisplays, this); |
6948 | 0 |
|
6949 | 0 | // Search for the display identified with aDisplayID and fire the |
6950 | 0 | // event if found. |
6951 | 0 | for (const auto& display : mVRDisplays) { |
6952 | 0 | if (display->DisplayId() == aDisplayID && display->IsPresenting()) { |
6953 | 0 | // We only want to trigger this event to content that is presenting to |
6954 | 0 | // the display already. |
6955 | 0 |
|
6956 | 0 | VRDisplayEventInit init; |
6957 | 0 | init.mBubbles = false; |
6958 | 0 | init.mCancelable = false; |
6959 | 0 | init.mDisplay = display; |
6960 | 0 | init.mReason.Construct(aReason); |
6961 | 0 |
|
6962 | 0 | RefPtr<VRDisplayEvent> event = |
6963 | 0 | VRDisplayEvent::Constructor(this, |
6964 | 0 | NS_LITERAL_STRING("vrdisplaydeactivate"), |
6965 | 0 | init); |
6966 | 0 | event->SetTrusted(true); |
6967 | 0 | DispatchEvent(*event); |
6968 | 0 | // Once we dispatch the event, we must not access any members as an event |
6969 | 0 | // listener can do anything, including closing windows. |
6970 | 0 | return; |
6971 | 0 | } |
6972 | 0 | } |
6973 | 0 | } |
6974 | | |
6975 | | void |
6976 | | nsGlobalWindowInner::DispatchVRDisplayConnect(uint32_t aDisplayID) |
6977 | 0 | { |
6978 | 0 | // Ensure that our list of displays is up to date |
6979 | 0 | VRDisplay::UpdateVRDisplays(mVRDisplays, this); |
6980 | 0 |
|
6981 | 0 | // Search for the display identified with aDisplayID and fire the |
6982 | 0 | // event if found. |
6983 | 0 | for (const auto& display : mVRDisplays) { |
6984 | 0 | if (display->DisplayId() == aDisplayID) { |
6985 | 0 | // Fire event even if not presenting to the display. |
6986 | 0 | VRDisplayEventInit init; |
6987 | 0 | init.mBubbles = false; |
6988 | 0 | init.mCancelable = false; |
6989 | 0 | init.mDisplay = display; |
6990 | 0 | // VRDisplayEvent.reason is not set for vrdisplayconnect |
6991 | 0 |
|
6992 | 0 | RefPtr<VRDisplayEvent> event = |
6993 | 0 | VRDisplayEvent::Constructor(this, |
6994 | 0 | NS_LITERAL_STRING("vrdisplayconnect"), |
6995 | 0 | init); |
6996 | 0 | event->SetTrusted(true); |
6997 | 0 | DispatchEvent(*event); |
6998 | 0 | // Once we dispatch the event, we must not access any members as an event |
6999 | 0 | // listener can do anything, including closing windows. |
7000 | 0 | return; |
7001 | 0 | } |
7002 | 0 | } |
7003 | 0 | } |
7004 | | |
7005 | | void |
7006 | | nsGlobalWindowInner::DispatchVRDisplayDisconnect(uint32_t aDisplayID) |
7007 | 0 | { |
7008 | 0 | // Ensure that our list of displays is up to date |
7009 | 0 | VRDisplay::UpdateVRDisplays(mVRDisplays, this); |
7010 | 0 |
|
7011 | 0 | // Search for the display identified with aDisplayID and fire the |
7012 | 0 | // event if found. |
7013 | 0 | for (const auto& display : mVRDisplays) { |
7014 | 0 | if (display->DisplayId() == aDisplayID) { |
7015 | 0 | // Fire event even if not presenting to the display. |
7016 | 0 | VRDisplayEventInit init; |
7017 | 0 | init.mBubbles = false; |
7018 | 0 | init.mCancelable = false; |
7019 | 0 | init.mDisplay = display; |
7020 | 0 | // VRDisplayEvent.reason is not set for vrdisplaydisconnect |
7021 | 0 |
|
7022 | 0 | RefPtr<VRDisplayEvent> event = |
7023 | 0 | VRDisplayEvent::Constructor(this, |
7024 | 0 | NS_LITERAL_STRING("vrdisplaydisconnect"), |
7025 | 0 | init); |
7026 | 0 | event->SetTrusted(true); |
7027 | 0 | DispatchEvent(*event); |
7028 | 0 | // Once we dispatch the event, we must not access any members as an event |
7029 | 0 | // listener can do anything, including closing windows. |
7030 | 0 | return; |
7031 | 0 | } |
7032 | 0 | } |
7033 | 0 | } |
7034 | | |
7035 | | void |
7036 | | nsGlobalWindowInner::DispatchVRDisplayPresentChange(uint32_t aDisplayID) |
7037 | 0 | { |
7038 | 0 | // Ensure that our list of displays is up to date |
7039 | 0 | VRDisplay::UpdateVRDisplays(mVRDisplays, this); |
7040 | 0 |
|
7041 | 0 | // Search for the display identified with aDisplayID and fire the |
7042 | 0 | // event if found. |
7043 | 0 | for (const auto& display : mVRDisplays) { |
7044 | 0 | if (display->DisplayId() == aDisplayID) { |
7045 | 0 | // Fire event even if not presenting to the display. |
7046 | 0 | VRDisplayEventInit init; |
7047 | 0 | init.mBubbles = false; |
7048 | 0 | init.mCancelable = false; |
7049 | 0 | init.mDisplay = display; |
7050 | 0 | // VRDisplayEvent.reason is not set for vrdisplaypresentchange |
7051 | 0 | RefPtr<VRDisplayEvent> event = |
7052 | 0 | VRDisplayEvent::Constructor(this, |
7053 | 0 | NS_LITERAL_STRING("vrdisplaypresentchange"), |
7054 | 0 | init); |
7055 | 0 | event->SetTrusted(true); |
7056 | 0 | DispatchEvent(*event); |
7057 | 0 | // Once we dispatch the event, we must not access any members as an event |
7058 | 0 | // listener can do anything, including closing windows. |
7059 | 0 | return; |
7060 | 0 | } |
7061 | 0 | } |
7062 | 0 | } |
7063 | | |
7064 | | enum WindowState { |
7065 | | // These constants need to match the constants in Window.webidl |
7066 | | STATE_MAXIMIZED = 1, |
7067 | | STATE_MINIMIZED = 2, |
7068 | | STATE_NORMAL = 3, |
7069 | | STATE_FULLSCREEN = 4 |
7070 | | }; |
7071 | | |
7072 | | uint16_t |
7073 | | nsGlobalWindowInner::WindowState() |
7074 | 0 | { |
7075 | 0 | nsCOMPtr<nsIWidget> widget = GetMainWidget(); |
7076 | 0 |
|
7077 | 0 | int32_t mode = widget ? widget->SizeMode() : 0; |
7078 | 0 |
|
7079 | 0 | switch (mode) { |
7080 | 0 | case nsSizeMode_Minimized: |
7081 | 0 | return STATE_MINIMIZED; |
7082 | 0 | case nsSizeMode_Maximized: |
7083 | 0 | return STATE_MAXIMIZED; |
7084 | 0 | case nsSizeMode_Fullscreen: |
7085 | 0 | return STATE_FULLSCREEN; |
7086 | 0 | case nsSizeMode_Normal: |
7087 | 0 | return STATE_NORMAL; |
7088 | 0 | default: |
7089 | 0 | NS_WARNING("Illegal window state for this chrome window"); |
7090 | 0 | break; |
7091 | 0 | } |
7092 | 0 |
|
7093 | 0 | return STATE_NORMAL; |
7094 | 0 | } |
7095 | | |
7096 | | bool |
7097 | | nsGlobalWindowInner::IsFullyOccluded() |
7098 | 0 | { |
7099 | 0 | nsCOMPtr<nsIWidget> widget = GetMainWidget(); |
7100 | 0 | return widget && widget->IsFullyOccluded(); |
7101 | 0 | } |
7102 | | |
7103 | | void |
7104 | | nsGlobalWindowInner::Maximize() |
7105 | 0 | { |
7106 | 0 | nsCOMPtr<nsIWidget> widget = GetMainWidget(); |
7107 | 0 |
|
7108 | 0 | if (widget) { |
7109 | 0 | widget->SetSizeMode(nsSizeMode_Maximized); |
7110 | 0 | } |
7111 | 0 | } |
7112 | | |
7113 | | void |
7114 | | nsGlobalWindowInner::Minimize() |
7115 | 0 | { |
7116 | 0 | nsCOMPtr<nsIWidget> widget = GetMainWidget(); |
7117 | 0 |
|
7118 | 0 | if (widget) { |
7119 | 0 | widget->SetSizeMode(nsSizeMode_Minimized); |
7120 | 0 | } |
7121 | 0 | } |
7122 | | |
7123 | | void |
7124 | | nsGlobalWindowInner::Restore() |
7125 | 0 | { |
7126 | 0 | nsCOMPtr<nsIWidget> widget = GetMainWidget(); |
7127 | 0 |
|
7128 | 0 | if (widget) { |
7129 | 0 | widget->SetSizeMode(nsSizeMode_Normal); |
7130 | 0 | } |
7131 | 0 | } |
7132 | | |
7133 | | void |
7134 | | nsGlobalWindowInner::GetAttention(ErrorResult& aResult) |
7135 | 0 | { |
7136 | 0 | return GetAttentionWithCycleCount(-1, aResult); |
7137 | 0 | } |
7138 | | |
7139 | | void |
7140 | | nsGlobalWindowInner::GetAttentionWithCycleCount(int32_t aCycleCount, |
7141 | | ErrorResult& aError) |
7142 | 0 | { |
7143 | 0 | nsCOMPtr<nsIWidget> widget = GetMainWidget(); |
7144 | 0 |
|
7145 | 0 | if (widget) { |
7146 | 0 | aError = widget->GetAttention(aCycleCount); |
7147 | 0 | } |
7148 | 0 | } |
7149 | | |
7150 | | void |
7151 | | nsGlobalWindowInner::BeginWindowMove(Event& aMouseDownEvent, |
7152 | | ErrorResult& aError) |
7153 | 0 | { |
7154 | 0 | nsCOMPtr<nsIWidget> widget = GetMainWidget(); |
7155 | 0 |
|
7156 | 0 | if (!widget) { |
7157 | 0 | return; |
7158 | 0 | } |
7159 | 0 | |
7160 | 0 | WidgetMouseEvent* mouseEvent = |
7161 | 0 | aMouseDownEvent.WidgetEventPtr()->AsMouseEvent(); |
7162 | 0 | if (!mouseEvent || mouseEvent->mClass != eMouseEventClass) { |
7163 | 0 | aError.Throw(NS_ERROR_FAILURE); |
7164 | 0 | return; |
7165 | 0 | } |
7166 | 0 | |
7167 | 0 | aError = widget->BeginMoveDrag(mouseEvent); |
7168 | 0 | } |
7169 | | |
7170 | | already_AddRefed<Promise> |
7171 | | nsGlobalWindowInner::PromiseDocumentFlushed(PromiseDocumentFlushedCallback& aCallback, |
7172 | | ErrorResult& aError) |
7173 | 0 | { |
7174 | 0 | MOZ_RELEASE_ASSERT(IsChromeWindow()); |
7175 | 0 |
|
7176 | 0 | if (!IsCurrentInnerWindow()) { |
7177 | 0 | aError.Throw(NS_ERROR_FAILURE); |
7178 | 0 | return nullptr; |
7179 | 0 | } |
7180 | 0 | |
7181 | 0 | if (mIteratingDocumentFlushedResolvers) { |
7182 | 0 | aError.Throw(NS_ERROR_FAILURE); |
7183 | 0 | return nullptr; |
7184 | 0 | } |
7185 | 0 | |
7186 | 0 | if (!mDoc) { |
7187 | 0 | aError.Throw(NS_ERROR_FAILURE); |
7188 | 0 | return nullptr; |
7189 | 0 | } |
7190 | 0 | |
7191 | 0 | nsIPresShell* shell = mDoc->GetShell(); |
7192 | 0 | if (!shell) { |
7193 | 0 | aError.Throw(NS_ERROR_FAILURE); |
7194 | 0 | return nullptr; |
7195 | 0 | } |
7196 | 0 | |
7197 | 0 | // We need to associate the lifetime of the Promise to the lifetime |
7198 | 0 | // of the caller's global. That way, if the window we're observing |
7199 | 0 | // refresh driver ticks on goes away before our observer is fired, |
7200 | 0 | // we can still resolve the Promise. |
7201 | 0 | nsIGlobalObject* global = GetIncumbentGlobal(); |
7202 | 0 | if (!global) { |
7203 | 0 | aError.Throw(NS_ERROR_FAILURE); |
7204 | 0 | return nullptr; |
7205 | 0 | } |
7206 | 0 | |
7207 | 0 | RefPtr<Promise> resultPromise = Promise::Create(global, aError); |
7208 | 0 | if (aError.Failed()) { |
7209 | 0 | return nullptr; |
7210 | 0 | } |
7211 | 0 | |
7212 | 0 | UniquePtr<PromiseDocumentFlushedResolver> flushResolver( |
7213 | 0 | new PromiseDocumentFlushedResolver(resultPromise, aCallback)); |
7214 | 0 |
|
7215 | 0 | if (!shell->NeedStyleFlush() && !shell->NeedLayoutFlush()) { |
7216 | 0 | flushResolver->Call(); |
7217 | 0 | return resultPromise.forget(); |
7218 | 0 | } |
7219 | 0 | |
7220 | 0 | if (!mObservingDidRefresh) { |
7221 | 0 | bool success = shell->AddPostRefreshObserver(this); |
7222 | 0 | if (!success) { |
7223 | 0 | aError.Throw(NS_ERROR_FAILURE); |
7224 | 0 | return nullptr; |
7225 | 0 | } |
7226 | 0 | mObservingDidRefresh = true; |
7227 | 0 | } |
7228 | 0 |
|
7229 | 0 | mDocumentFlushedResolvers.AppendElement(std::move(flushResolver)); |
7230 | 0 | return resultPromise.forget(); |
7231 | 0 | } |
7232 | | |
7233 | | template<bool call> |
7234 | | void |
7235 | | nsGlobalWindowInner::CallOrCancelDocumentFlushedResolvers() |
7236 | 0 | { |
7237 | 0 | MOZ_ASSERT(!mIteratingDocumentFlushedResolvers); |
7238 | 0 |
|
7239 | 0 | while (true) { |
7240 | 0 | { |
7241 | 0 | // To coalesce MicroTask checkpoints inside callback call, enclose the |
7242 | 0 | // inner loop with nsAutoMicroTask, and perform a MicroTask checkpoint |
7243 | 0 | // after the loop. |
7244 | 0 | nsAutoMicroTask mt; |
7245 | 0 |
|
7246 | 0 | mIteratingDocumentFlushedResolvers = true; |
7247 | 0 | for (const auto& documentFlushedResolver : mDocumentFlushedResolvers) { |
7248 | 0 | if (call) { |
7249 | 0 | documentFlushedResolver->Call(); |
7250 | 0 | } else { |
7251 | 0 | documentFlushedResolver->Cancel(); |
7252 | 0 | } |
7253 | 0 | } |
7254 | 0 | mDocumentFlushedResolvers.Clear(); |
7255 | 0 | mIteratingDocumentFlushedResolvers = false; |
7256 | 0 | } |
7257 | 0 |
|
7258 | 0 | // Leaving nsAutoMicroTask above will perform MicroTask checkpoint, and |
7259 | 0 | // Promise callbacks there may create mDocumentFlushedResolvers items. |
7260 | 0 |
|
7261 | 0 | // If there's no new item, there's nothing to do here. |
7262 | 0 | if (!mDocumentFlushedResolvers.Length()) { |
7263 | 0 | break; |
7264 | 0 | } |
7265 | 0 | |
7266 | 0 | // If there are new items, the observer is not added for them when calling |
7267 | 0 | // PromiseDocumentFlushed. Add here and leave. |
7268 | 0 | // FIXME: Handle this case inside PromiseDocumentFlushed (bug 1442824). |
7269 | 0 | if (mDoc) { |
7270 | 0 | nsIPresShell* shell = mDoc->GetShell(); |
7271 | 0 | if (shell) { |
7272 | 0 | (void) shell->AddPostRefreshObserver(this); |
7273 | 0 | break; |
7274 | 0 | } |
7275 | 0 | } |
7276 | 0 |
|
7277 | 0 | // If we fail adding observer, keep looping to resolve or reject all |
7278 | 0 | // promises. This case happens while destroying window. |
7279 | 0 | // This violates the constraint that the promiseDocumentFlushed callback |
7280 | 0 | // only ever run when no flush needed, but it's necessary to resolve |
7281 | 0 | // Promise returned by that. |
7282 | 0 | } |
7283 | 0 | } Unexecuted instantiation: void nsGlobalWindowInner::CallOrCancelDocumentFlushedResolvers<true>() Unexecuted instantiation: void nsGlobalWindowInner::CallOrCancelDocumentFlushedResolvers<false>() |
7284 | | |
7285 | | void |
7286 | | nsGlobalWindowInner::CallDocumentFlushedResolvers() |
7287 | 0 | { |
7288 | 0 | CallOrCancelDocumentFlushedResolvers<true>(); |
7289 | 0 | } |
7290 | | |
7291 | | void |
7292 | | nsGlobalWindowInner::CancelDocumentFlushedResolvers() |
7293 | 0 | { |
7294 | 0 | CallOrCancelDocumentFlushedResolvers<false>(); |
7295 | 0 | } |
7296 | | |
7297 | | void |
7298 | | nsGlobalWindowInner::DidRefresh() |
7299 | 0 | { |
7300 | 0 | auto rejectionGuard = MakeScopeExit([&] { |
7301 | 0 | CancelDocumentFlushedResolvers(); |
7302 | 0 | mObservingDidRefresh = false; |
7303 | 0 | }); |
7304 | 0 |
|
7305 | 0 | MOZ_ASSERT(mDoc); |
7306 | 0 |
|
7307 | 0 | nsIPresShell* shell = mDoc->GetShell(); |
7308 | 0 | MOZ_ASSERT(shell); |
7309 | 0 |
|
7310 | 0 | if (shell->NeedStyleFlush() || shell->NeedLayoutFlush()) { |
7311 | 0 | // By the time our observer fired, something has already invalidated |
7312 | 0 | // style or layout - or perhaps we're still in the middle of a flush that |
7313 | 0 | // was interrupted. In either case, we'll wait until the next refresh driver |
7314 | 0 | // tick instead and try again. |
7315 | 0 | rejectionGuard.release(); |
7316 | 0 | return; |
7317 | 0 | } |
7318 | 0 | |
7319 | 0 | bool success = shell->RemovePostRefreshObserver(this); |
7320 | 0 | if (!success) { |
7321 | 0 | return; |
7322 | 0 | } |
7323 | 0 | |
7324 | 0 | rejectionGuard.release(); |
7325 | 0 |
|
7326 | 0 | CallDocumentFlushedResolvers(); |
7327 | 0 | mObservingDidRefresh = false; |
7328 | 0 | } |
7329 | | |
7330 | | already_AddRefed<nsWindowRoot> |
7331 | | nsGlobalWindowInner::GetWindowRoot(mozilla::ErrorResult& aError) |
7332 | 0 | { |
7333 | 0 | FORWARD_TO_OUTER_OR_THROW(GetWindowRootOuter, (), aError, nullptr); |
7334 | 0 | } |
7335 | | |
7336 | | void |
7337 | | nsGlobalWindowInner::SetCursor(const nsAString& aCursor, ErrorResult& aError) |
7338 | 0 | { |
7339 | 0 | FORWARD_TO_OUTER_OR_THROW(SetCursorOuter, (aCursor, aError), aError, ); |
7340 | 0 | } |
7341 | | |
7342 | | NS_IMETHODIMP |
7343 | | nsGlobalWindowInner::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow) |
7344 | 0 | { |
7345 | 0 | MOZ_RELEASE_ASSERT(IsChromeWindow()); |
7346 | 0 |
|
7347 | 0 | ErrorResult rv; |
7348 | 0 | NS_IF_ADDREF(*aBrowserWindow = GetBrowserDOMWindow(rv)); |
7349 | 0 | return rv.StealNSResult(); |
7350 | 0 | } |
7351 | | |
7352 | | nsIBrowserDOMWindow* |
7353 | | nsGlobalWindowInner::GetBrowserDOMWindow(ErrorResult& aError) |
7354 | 0 | { |
7355 | 0 | FORWARD_TO_OUTER_OR_THROW(GetBrowserDOMWindowOuter, (), aError, nullptr); |
7356 | 0 | } |
7357 | | |
7358 | | void |
7359 | | nsGlobalWindowInner::SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserWindow, |
7360 | | ErrorResult& aError) |
7361 | 0 | { |
7362 | 0 | FORWARD_TO_OUTER_OR_THROW(SetBrowserDOMWindowOuter, (aBrowserWindow), aError, ); |
7363 | 0 | } |
7364 | | |
7365 | | void |
7366 | | nsGlobalWindowInner::NotifyDefaultButtonLoaded(Element& aDefaultButton, |
7367 | | ErrorResult& aError) |
7368 | 0 | { |
7369 | 0 | #ifdef MOZ_XUL |
7370 | 0 | // Don't snap to a disabled button. |
7371 | 0 | nsCOMPtr<nsIDOMXULControlElement> xulControl = |
7372 | 0 | do_QueryInterface(&aDefaultButton); |
7373 | 0 | if (!xulControl) { |
7374 | 0 | aError.Throw(NS_ERROR_FAILURE); |
7375 | 0 | return; |
7376 | 0 | } |
7377 | 0 | bool disabled; |
7378 | 0 | aError = xulControl->GetDisabled(&disabled); |
7379 | 0 | if (aError.Failed() || disabled) { |
7380 | 0 | return; |
7381 | 0 | } |
7382 | 0 | |
7383 | 0 | // Get the button rect in screen coordinates. |
7384 | 0 | nsIFrame *frame = aDefaultButton.GetPrimaryFrame(); |
7385 | 0 | if (!frame) { |
7386 | 0 | aError.Throw(NS_ERROR_FAILURE); |
7387 | 0 | return; |
7388 | 0 | } |
7389 | 0 | LayoutDeviceIntRect buttonRect = |
7390 | 0 | LayoutDeviceIntRect::FromAppUnitsToNearest( |
7391 | 0 | frame->GetScreenRectInAppUnits(), |
7392 | 0 | frame->PresContext()->AppUnitsPerDevPixel()); |
7393 | 0 |
|
7394 | 0 | // Get the widget rect in screen coordinates. |
7395 | 0 | nsIWidget *widget = GetNearestWidget(); |
7396 | 0 | if (!widget) { |
7397 | 0 | aError.Throw(NS_ERROR_FAILURE); |
7398 | 0 | return; |
7399 | 0 | } |
7400 | 0 | LayoutDeviceIntRect widgetRect = widget->GetScreenBounds(); |
7401 | 0 |
|
7402 | 0 | // Convert the buttonRect coordinates from screen to the widget. |
7403 | 0 | buttonRect -= widgetRect.TopLeft(); |
7404 | 0 | nsresult rv = widget->OnDefaultButtonLoaded(buttonRect); |
7405 | 0 | if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) { |
7406 | 0 | aError.Throw(rv); |
7407 | 0 | } |
7408 | | #else |
7409 | | aError.Throw(NS_ERROR_NOT_IMPLEMENTED); |
7410 | | #endif |
7411 | | } |
7412 | | |
7413 | | ChromeMessageBroadcaster* |
7414 | | nsGlobalWindowInner::MessageManager() |
7415 | 0 | { |
7416 | 0 | MOZ_ASSERT(IsChromeWindow()); |
7417 | 0 | if (!mChromeFields.mMessageManager) { |
7418 | 0 | RefPtr<ChromeMessageBroadcaster> globalMM = |
7419 | 0 | nsFrameMessageManager::GetGlobalMessageManager(); |
7420 | 0 | mChromeFields.mMessageManager = new ChromeMessageBroadcaster(globalMM); |
7421 | 0 | } |
7422 | 0 | return mChromeFields.mMessageManager; |
7423 | 0 | } |
7424 | | |
7425 | | ChromeMessageBroadcaster* |
7426 | | nsGlobalWindowInner::GetGroupMessageManager(const nsAString& aGroup) |
7427 | 0 | { |
7428 | 0 | MOZ_ASSERT(IsChromeWindow()); |
7429 | 0 |
|
7430 | 0 | RefPtr<ChromeMessageBroadcaster> messageManager = |
7431 | 0 | mChromeFields.mGroupMessageManagers.LookupForAdd(aGroup).OrInsert( |
7432 | 0 | [this] () { |
7433 | 0 | return new ChromeMessageBroadcaster(MessageManager()); |
7434 | 0 | }); |
7435 | 0 | return messageManager; |
7436 | 0 | } |
7437 | | |
7438 | | void |
7439 | | nsGlobalWindowInner::InitWasOffline() |
7440 | 0 | { |
7441 | 0 | mWasOffline = NS_IsOffline(); |
7442 | 0 | } |
7443 | | |
7444 | | #if defined(MOZ_WIDGET_ANDROID) |
7445 | | int16_t |
7446 | | nsGlobalWindowInner::Orientation(CallerType aCallerType) const |
7447 | | { |
7448 | | return nsContentUtils::ResistFingerprinting(aCallerType) ? |
7449 | | 0 : WindowOrientationObserver::OrientationAngle(); |
7450 | | } |
7451 | | #endif |
7452 | | |
7453 | | already_AddRefed<Console> |
7454 | | nsGlobalWindowInner::GetConsole(JSContext* aCx, ErrorResult& aRv) |
7455 | 0 | { |
7456 | 0 | if (!mConsole) { |
7457 | 0 | mConsole = Console::Create(aCx, this, aRv); |
7458 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
7459 | 0 | return nullptr; |
7460 | 0 | } |
7461 | 0 | } |
7462 | 0 | |
7463 | 0 | RefPtr<Console> console = mConsole; |
7464 | 0 | return console.forget(); |
7465 | 0 | } |
7466 | | |
7467 | | bool |
7468 | | nsGlobalWindowInner::IsSecureContext() const |
7469 | 0 | { |
7470 | 0 | JS::Realm* realm = js::GetNonCCWObjectRealm(GetWrapperPreserveColor()); |
7471 | 0 | return JS::GetIsSecureContext(realm); |
7472 | 0 | } |
7473 | | |
7474 | | already_AddRefed<External> |
7475 | | nsGlobalWindowInner::GetExternal(ErrorResult& aRv) |
7476 | 0 | { |
7477 | 0 | #ifdef HAVE_SIDEBAR |
7478 | 0 | if (!mExternal) { |
7479 | 0 | JS::Rooted<JSObject*> jsImplObj(RootingCx()); |
7480 | 0 | ConstructJSImplementation("@mozilla.org/sidebar;1", this, &jsImplObj, aRv); |
7481 | 0 | if (aRv.Failed()) { |
7482 | 0 | return nullptr; |
7483 | 0 | } |
7484 | 0 | MOZ_RELEASE_ASSERT(!js::IsWrapper(jsImplObj)); |
7485 | 0 | JS::Rooted<JSObject*> jsImplGlobal(RootingCx(), |
7486 | 0 | JS::GetNonCCWObjectGlobal(jsImplObj)); |
7487 | 0 | mExternal = new External(jsImplObj, jsImplGlobal, this); |
7488 | 0 | } |
7489 | 0 |
|
7490 | 0 | RefPtr<External> external = static_cast<External*>(mExternal.get()); |
7491 | 0 | return external.forget(); |
7492 | | #else |
7493 | | aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); |
7494 | | return nullptr; |
7495 | | #endif |
7496 | | } |
7497 | | |
7498 | | void |
7499 | | nsGlobalWindowInner::GetSidebar(OwningExternalOrWindowProxy& aResult, |
7500 | | ErrorResult& aRv) |
7501 | 0 | { |
7502 | 0 | #ifdef HAVE_SIDEBAR |
7503 | 0 | // First check for a named frame named "sidebar" |
7504 | 0 | nsCOMPtr<nsPIDOMWindowOuter> domWindow = GetChildWindow(NS_LITERAL_STRING("sidebar")); |
7505 | 0 | if (domWindow) { |
7506 | 0 | aResult.SetAsWindowProxy() = domWindow.forget(); |
7507 | 0 | return; |
7508 | 0 | } |
7509 | 0 | |
7510 | 0 | RefPtr<External> external = GetExternal(aRv); |
7511 | 0 | if (external) { |
7512 | 0 | aResult.SetAsExternal() = external; |
7513 | 0 | } |
7514 | | #else |
7515 | | aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); |
7516 | | #endif |
7517 | | } |
7518 | | |
7519 | | void |
7520 | | nsGlobalWindowInner::ClearDocumentDependentSlots(JSContext* aCx) |
7521 | 0 | { |
7522 | 0 | // If JSAPI OOMs here, there is basically nothing we can do to recover safely. |
7523 | 0 | if (!Window_Binding::ClearCachedDocumentValue(aCx, this) || |
7524 | 0 | !Window_Binding::ClearCachedPerformanceValue(aCx, this)) { |
7525 | 0 | MOZ_CRASH("Unhandlable OOM while clearing document dependent slots."); |
7526 | 0 | } |
7527 | 0 | } |
7528 | | |
7529 | | /* static */ |
7530 | | JSObject* |
7531 | | nsGlobalWindowInner::CreateNamedPropertiesObject(JSContext *aCx, |
7532 | | JS::Handle<JSObject*> aProto) |
7533 | 0 | { |
7534 | 0 | return WindowNamedPropertiesHandler::Create(aCx, aProto); |
7535 | 0 | } |
7536 | | |
7537 | | void |
7538 | | nsGlobalWindowInner::RedefineProperty(JSContext* aCx, const char* aPropName, |
7539 | | JS::Handle<JS::Value> aValue, |
7540 | | ErrorResult& aError) |
7541 | 0 | { |
7542 | 0 | JS::Rooted<JSObject*> thisObj(aCx, GetWrapperPreserveColor()); |
7543 | 0 | if (!thisObj) { |
7544 | 0 | aError.Throw(NS_ERROR_UNEXPECTED); |
7545 | 0 | return; |
7546 | 0 | } |
7547 | 0 | |
7548 | 0 | if (!JS_WrapObject(aCx, &thisObj) || |
7549 | 0 | !JS_DefineProperty(aCx, thisObj, aPropName, aValue, JSPROP_ENUMERATE)) { |
7550 | 0 | aError.Throw(NS_ERROR_FAILURE); |
7551 | 0 | } |
7552 | 0 | } |
7553 | | |
7554 | | void |
7555 | | nsGlobalWindowInner::GetReplaceableWindowCoord(JSContext* aCx, |
7556 | | nsGlobalWindowInner::WindowCoordGetter aGetter, |
7557 | | JS::MutableHandle<JS::Value> aRetval, |
7558 | | CallerType aCallerType, |
7559 | | ErrorResult& aError) |
7560 | 0 | { |
7561 | 0 | int32_t coord = (this->*aGetter)(aCallerType, aError); |
7562 | 0 | if (!aError.Failed() && |
7563 | 0 | !ToJSValue(aCx, coord, aRetval)) { |
7564 | 0 | aError.Throw(NS_ERROR_FAILURE); |
7565 | 0 | } |
7566 | 0 | } |
7567 | | |
7568 | | void |
7569 | | nsGlobalWindowInner::SetReplaceableWindowCoord(JSContext* aCx, |
7570 | | nsGlobalWindowInner::WindowCoordSetter aSetter, |
7571 | | JS::Handle<JS::Value> aValue, |
7572 | | const char* aPropName, |
7573 | | CallerType aCallerType, |
7574 | | ErrorResult& aError) |
7575 | 0 | { |
7576 | 0 | /* |
7577 | 0 | * If caller is not chrome and the user has not explicitly exempted the site, |
7578 | 0 | * just treat this the way we would an IDL replaceable property. |
7579 | 0 | */ |
7580 | 0 | nsGlobalWindowOuter* outer = GetOuterWindowInternal(); |
7581 | 0 | if (!outer || |
7582 | 0 | !outer->CanMoveResizeWindows(aCallerType) || |
7583 | 0 | outer->IsFrame()) { |
7584 | 0 | RedefineProperty(aCx, aPropName, aValue, aError); |
7585 | 0 | return; |
7586 | 0 | } |
7587 | 0 | |
7588 | 0 | int32_t value; |
7589 | 0 | if (!ValueToPrimitive<int32_t, eDefault>(aCx, aValue, &value)) { |
7590 | 0 | aError.Throw(NS_ERROR_UNEXPECTED); |
7591 | 0 | return; |
7592 | 0 | } |
7593 | 0 | |
7594 | 0 | if (nsContentUtils::ShouldResistFingerprinting(GetDocShell())) { |
7595 | 0 | bool innerWidthSpecified = false; |
7596 | 0 | bool innerHeightSpecified = false; |
7597 | 0 | bool outerWidthSpecified = false; |
7598 | 0 | bool outerHeightSpecified = false; |
7599 | 0 |
|
7600 | 0 | if (strcmp(aPropName, "innerWidth") == 0) { |
7601 | 0 | innerWidthSpecified = true; |
7602 | 0 | } else if (strcmp(aPropName, "innerHeight") == 0) { |
7603 | 0 | innerHeightSpecified = true; |
7604 | 0 | } else if (strcmp(aPropName, "outerWidth") == 0) { |
7605 | 0 | outerWidthSpecified = true; |
7606 | 0 | } else if (strcmp(aPropName, "outerHeight") == 0) { |
7607 | 0 | outerHeightSpecified = true; |
7608 | 0 | } |
7609 | 0 |
|
7610 | 0 | if (innerWidthSpecified || innerHeightSpecified || |
7611 | 0 | outerWidthSpecified || outerHeightSpecified) |
7612 | 0 | { |
7613 | 0 | nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = outer->GetTreeOwnerWindow(); |
7614 | 0 | nsCOMPtr<nsIScreen> screen; |
7615 | 0 | nsCOMPtr<nsIScreenManager> screenMgr( |
7616 | 0 | do_GetService("@mozilla.org/gfx/screenmanager;1")); |
7617 | 0 | int32_t winLeft = 0; |
7618 | 0 | int32_t winTop = 0; |
7619 | 0 | int32_t winWidth = 0; |
7620 | 0 | int32_t winHeight = 0; |
7621 | 0 | double scale = 1.0; |
7622 | 0 |
|
7623 | 0 |
|
7624 | 0 | if (treeOwnerAsWin && screenMgr) { |
7625 | 0 | // Acquire current window size. |
7626 | 0 | treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&scale); |
7627 | 0 | treeOwnerAsWin->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight); |
7628 | 0 | winLeft = NSToIntRound(winHeight / scale); |
7629 | 0 | winTop = NSToIntRound(winWidth / scale); |
7630 | 0 | winWidth = NSToIntRound(winWidth / scale); |
7631 | 0 | winHeight = NSToIntRound(winHeight / scale); |
7632 | 0 |
|
7633 | 0 | // Acquire content window size. |
7634 | 0 | CSSIntSize contentSize; |
7635 | 0 | outer->GetInnerSize(contentSize); |
7636 | 0 |
|
7637 | 0 | screenMgr->ScreenForRect(winLeft, winTop, winWidth, winHeight, |
7638 | 0 | getter_AddRefs(screen)); |
7639 | 0 |
|
7640 | 0 | if (screen) { |
7641 | 0 | int32_t* targetContentWidth = nullptr; |
7642 | 0 | int32_t* targetContentHeight = nullptr; |
7643 | 0 | int32_t screenWidth = 0; |
7644 | 0 | int32_t screenHeight = 0; |
7645 | 0 | int32_t chromeWidth = 0; |
7646 | 0 | int32_t chromeHeight = 0; |
7647 | 0 | int32_t inputWidth = 0; |
7648 | 0 | int32_t inputHeight = 0; |
7649 | 0 | int32_t unused = 0; |
7650 | 0 |
|
7651 | 0 | // Get screen dimensions (in device pixels) |
7652 | 0 | screen->GetAvailRect(&unused, &unused, &screenWidth, |
7653 | 0 | &screenHeight); |
7654 | 0 | // Convert them to CSS pixels |
7655 | 0 | screenWidth = NSToIntRound(screenWidth / scale); |
7656 | 0 | screenHeight = NSToIntRound(screenHeight / scale); |
7657 | 0 |
|
7658 | 0 | // Calculate the chrome UI size. |
7659 | 0 | chromeWidth = winWidth - contentSize.width; |
7660 | 0 | chromeHeight = winHeight - contentSize.height; |
7661 | 0 |
|
7662 | 0 | if (innerWidthSpecified || outerWidthSpecified) { |
7663 | 0 | inputWidth = value; |
7664 | 0 | targetContentWidth = &value; |
7665 | 0 | targetContentHeight = &unused; |
7666 | 0 | } else if (innerHeightSpecified || outerHeightSpecified) { |
7667 | 0 | inputHeight = value; |
7668 | 0 | targetContentWidth = &unused; |
7669 | 0 | targetContentHeight = &value; |
7670 | 0 | } |
7671 | 0 |
|
7672 | 0 | nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting( |
7673 | 0 | chromeWidth, |
7674 | 0 | chromeHeight, |
7675 | 0 | screenWidth, |
7676 | 0 | screenHeight, |
7677 | 0 | inputWidth, |
7678 | 0 | inputHeight, |
7679 | 0 | outerWidthSpecified, |
7680 | 0 | outerHeightSpecified, |
7681 | 0 | targetContentWidth, |
7682 | 0 | targetContentHeight |
7683 | 0 | ); |
7684 | 0 | } |
7685 | 0 | } |
7686 | 0 | } |
7687 | 0 | } |
7688 | 0 |
|
7689 | 0 | (this->*aSetter)(value, aCallerType, aError); |
7690 | 0 | } |
7691 | | |
7692 | | void |
7693 | | nsGlobalWindowInner::FireOnNewGlobalObject() |
7694 | 0 | { |
7695 | 0 | // AutoEntryScript required to invoke debugger hook, which is a |
7696 | 0 | // Gecko-specific concept at present. |
7697 | 0 | AutoEntryScript aes(this, "nsGlobalWindowInner report new global"); |
7698 | 0 | JS::Rooted<JSObject*> global(aes.cx(), GetWrapper()); |
7699 | 0 | JS_FireOnNewGlobalObject(aes.cx(), global); |
7700 | 0 | } |
7701 | | |
7702 | | #ifdef _WINDOWS_ |
7703 | | #error "Never include windows.h in this file!" |
7704 | | #endif |
7705 | | |
7706 | | already_AddRefed<Promise> |
7707 | | nsGlobalWindowInner::CreateImageBitmap(JSContext* aCx, |
7708 | | const ImageBitmapSource& aImage, |
7709 | | ErrorResult& aRv) |
7710 | 0 | { |
7711 | 0 | if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) { |
7712 | 0 | aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); |
7713 | 0 | return nullptr; |
7714 | 0 | } |
7715 | 0 | |
7716 | 0 | return ImageBitmap::Create(this, aImage, Nothing(), aRv); |
7717 | 0 | } |
7718 | | |
7719 | | already_AddRefed<Promise> |
7720 | | nsGlobalWindowInner::CreateImageBitmap(JSContext* aCx, |
7721 | | const ImageBitmapSource& aImage, |
7722 | | int32_t aSx, int32_t aSy, int32_t aSw, int32_t aSh, |
7723 | | ErrorResult& aRv) |
7724 | 0 | { |
7725 | 0 | if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) { |
7726 | 0 | aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); |
7727 | 0 | return nullptr; |
7728 | 0 | } |
7729 | 0 | |
7730 | 0 | return ImageBitmap::Create(this, aImage, Some(gfx::IntRect(aSx, aSy, aSw, aSh)), aRv); |
7731 | 0 | } |
7732 | | |
7733 | | already_AddRefed<mozilla::dom::Promise> |
7734 | | nsGlobalWindowInner::CreateImageBitmap(JSContext* aCx, |
7735 | | const ImageBitmapSource& aImage, |
7736 | | int32_t aOffset, int32_t aLength, |
7737 | | ImageBitmapFormat aFormat, |
7738 | | const Sequence<ChannelPixelLayout>& aLayout, |
7739 | | ErrorResult& aRv) |
7740 | 0 | { |
7741 | 0 | if (!StaticPrefs::canvas_imagebitmap_extensions_enabled()) { |
7742 | 0 | aRv.Throw(NS_ERROR_TYPE_ERR); |
7743 | 0 | return nullptr; |
7744 | 0 | } |
7745 | 0 | if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) { |
7746 | 0 | return ImageBitmap::Create(this, aImage, aOffset, aLength, aFormat, aLayout, |
7747 | 0 | aRv); |
7748 | 0 | } |
7749 | 0 | aRv.Throw(NS_ERROR_TYPE_ERR); |
7750 | 0 | return nullptr; |
7751 | 0 | } |
7752 | | |
7753 | | mozilla::dom::TabGroup* |
7754 | | nsGlobalWindowInner::TabGroupInner() |
7755 | 0 | { |
7756 | 0 | // If we don't have a TabGroup yet, try to get it from the outer window and |
7757 | 0 | // cache it. |
7758 | 0 | if (!mTabGroup) { |
7759 | 0 | nsGlobalWindowOuter* outer = GetOuterWindowInternal(); |
7760 | 0 | // This will never be called without either an outer window, or a cached tab group. |
7761 | 0 | // This is because of the following: |
7762 | 0 | // * This method is only called on inner windows |
7763 | 0 | // * This method is called as a document is attached to it's script global |
7764 | 0 | // by the document |
7765 | 0 | // * Inner windows are created in nsGlobalWindowInner::SetNewDocument, which |
7766 | 0 | // immediately sets a document, which will call this method, causing |
7767 | 0 | // the TabGroup to be cached. |
7768 | 0 | MOZ_RELEASE_ASSERT(outer, "Inner window without outer window has no cached tab group!"); |
7769 | 0 | mTabGroup = outer->TabGroup(); |
7770 | 0 | } |
7771 | 0 | MOZ_ASSERT(mTabGroup); |
7772 | 0 |
|
7773 | | #ifdef DEBUG |
7774 | | nsGlobalWindowOuter* outer = GetOuterWindowInternal(); |
7775 | | MOZ_ASSERT_IF(outer, outer->TabGroup() == mTabGroup); |
7776 | | #endif |
7777 | |
|
7778 | 0 | return mTabGroup; |
7779 | 0 | } |
7780 | | |
7781 | | nsresult |
7782 | | nsGlobalWindowInner::Dispatch(TaskCategory aCategory, |
7783 | | already_AddRefed<nsIRunnable>&& aRunnable) |
7784 | 0 | { |
7785 | 0 | MOZ_RELEASE_ASSERT(NS_IsMainThread()); |
7786 | 0 | if (GetDocGroup()) { |
7787 | 0 | return GetDocGroup()->Dispatch(aCategory, std::move(aRunnable)); |
7788 | 0 | } |
7789 | 0 | return DispatcherTrait::Dispatch(aCategory, std::move(aRunnable)); |
7790 | 0 | } |
7791 | | |
7792 | | nsISerialEventTarget* |
7793 | | nsGlobalWindowInner::EventTargetFor(TaskCategory aCategory) const |
7794 | 0 | { |
7795 | 0 | MOZ_RELEASE_ASSERT(NS_IsMainThread()); |
7796 | 0 | if (GetDocGroup()) { |
7797 | 0 | return GetDocGroup()->EventTargetFor(aCategory); |
7798 | 0 | } |
7799 | 0 | return DispatcherTrait::EventTargetFor(aCategory); |
7800 | 0 | } |
7801 | | |
7802 | | AbstractThread* |
7803 | | nsGlobalWindowInner::AbstractMainThreadFor(TaskCategory aCategory) |
7804 | 0 | { |
7805 | 0 | MOZ_RELEASE_ASSERT(NS_IsMainThread()); |
7806 | 0 | if (GetDocGroup()) { |
7807 | 0 | return GetDocGroup()->AbstractMainThreadFor(aCategory); |
7808 | 0 | } |
7809 | 0 | return DispatcherTrait::AbstractMainThreadFor(aCategory); |
7810 | 0 | } |
7811 | | |
7812 | | Worklet* |
7813 | | nsGlobalWindowInner::GetPaintWorklet(ErrorResult& aRv) |
7814 | 0 | { |
7815 | 0 | if (!mPaintWorklet) { |
7816 | 0 | nsIPrincipal* principal = GetPrincipal(); |
7817 | 0 | if (!principal) { |
7818 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
7819 | 0 | return nullptr; |
7820 | 0 | } |
7821 | 0 | |
7822 | 0 | mPaintWorklet = new Worklet(this, principal, Worklet::ePaintWorklet); |
7823 | 0 | } |
7824 | 0 |
|
7825 | 0 | return mPaintWorklet; |
7826 | 0 | } |
7827 | | |
7828 | | void |
7829 | | nsGlobalWindowInner::GetRegionalPrefsLocales(nsTArray<nsString>& aLocales) |
7830 | 0 | { |
7831 | 0 | AutoTArray<nsCString, 10> rpLocales; |
7832 | 0 | mozilla::intl::LocaleService::GetInstance()->GetRegionalPrefsLocales(rpLocales); |
7833 | 0 |
|
7834 | 0 | for (const auto& loc : rpLocales) { |
7835 | 0 | aLocales.AppendElement(NS_ConvertUTF8toUTF16(loc)); |
7836 | 0 | } |
7837 | 0 | } |
7838 | | |
7839 | | IntlUtils* |
7840 | | nsGlobalWindowInner::GetIntlUtils(ErrorResult& aError) |
7841 | 0 | { |
7842 | 0 | if (!mIntlUtils) { |
7843 | 0 | mIntlUtils = new IntlUtils(this); |
7844 | 0 | } |
7845 | 0 |
|
7846 | 0 | return mIntlUtils; |
7847 | 0 | } |
7848 | | |
7849 | | mozilla::dom::TabGroup* |
7850 | | nsPIDOMWindowInner::TabGroup() |
7851 | 0 | { |
7852 | 0 | return nsGlobalWindowInner::Cast(this)->TabGroupInner(); |
7853 | 0 | } |
7854 | | |
7855 | | /* static */ already_AddRefed<nsGlobalWindowInner> |
7856 | | nsGlobalWindowInner::Create(nsGlobalWindowOuter *aOuterWindow, bool aIsChrome) |
7857 | 0 | { |
7858 | 0 | RefPtr<nsGlobalWindowInner> window = new nsGlobalWindowInner(aOuterWindow); |
7859 | 0 | if (aIsChrome) { |
7860 | 0 | window->mIsChrome = true; |
7861 | 0 | window->mCleanMessageManager = true; |
7862 | 0 | } |
7863 | 0 |
|
7864 | 0 | window->InitWasOffline(); |
7865 | 0 | return window.forget(); |
7866 | 0 | } |
7867 | | |
7868 | | nsIURI* |
7869 | | nsPIDOMWindowInner::GetDocumentURI() const |
7870 | 0 | { |
7871 | 0 | return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get(); |
7872 | 0 | } |
7873 | | |
7874 | | nsIURI* |
7875 | | nsPIDOMWindowInner::GetDocBaseURI() const |
7876 | 0 | { |
7877 | 0 | return mDoc ? mDoc->GetDocBaseURI() : mDocBaseURI.get(); |
7878 | 0 | } |
7879 | | |
7880 | | void |
7881 | | nsPIDOMWindowInner::MaybeCreateDoc() |
7882 | 0 | { |
7883 | 0 | // XXX: Forward to outer? |
7884 | 0 | MOZ_ASSERT(!mDoc); |
7885 | 0 | if (nsIDocShell* docShell = GetDocShell()) { |
7886 | 0 | // Note that |document| here is the same thing as our mDoc, but we |
7887 | 0 | // don't have to explicitly set the member variable because the docshell |
7888 | 0 | // has already called SetNewDocument(). |
7889 | 0 | nsCOMPtr<nsIDocument> document = docShell->GetDocument(); |
7890 | 0 | Unused << document; |
7891 | 0 | } |
7892 | 0 | } |
7893 | | |
7894 | | void |
7895 | | nsGlobalWindowInner::PropagateClearSiteDataReload(const nsACString& aOrigin) |
7896 | 0 | { |
7897 | 0 | if (!IsCurrentInnerWindow()) { |
7898 | 0 | return; |
7899 | 0 | } |
7900 | 0 | |
7901 | 0 | nsIPrincipal* principal = GetPrincipal(); |
7902 | 0 | if (!principal) { |
7903 | 0 | return; |
7904 | 0 | } |
7905 | 0 | |
7906 | 0 | nsAutoCString origin; |
7907 | 0 | nsresult rv = principal->GetOrigin(origin); |
7908 | 0 | NS_ENSURE_SUCCESS_VOID(rv); |
7909 | 0 |
|
7910 | 0 | // If the URL of this window matches, let's refresh this window only. |
7911 | 0 | // We don't need to traverse the DOM tree. |
7912 | 0 | if (origin.Equals(aOrigin)) { |
7913 | 0 | nsCOMPtr<nsIDocShell> docShell = GetDocShell(); |
7914 | 0 | nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell)); |
7915 | 0 | if (NS_WARN_IF(!webNav)) { |
7916 | 0 | return; |
7917 | 0 | } |
7918 | 0 | |
7919 | 0 | // We don't need any special reload flags, because this notification is |
7920 | 0 | // dispatched by Clear-Site-Data header, which should have already cleaned |
7921 | 0 | // up all the needed data. |
7922 | 0 | rv = webNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE); |
7923 | 0 | NS_ENSURE_SUCCESS_VOID(rv); |
7924 | 0 |
|
7925 | 0 | return; |
7926 | 0 | } |
7927 | 0 | |
7928 | 0 | CallOnChildren(&nsGlobalWindowInner::PropagateClearSiteDataReload, aOrigin); |
7929 | 0 | } |
7930 | | |
7931 | | mozilla::dom::DocGroup* |
7932 | | nsPIDOMWindowInner::GetDocGroup() const |
7933 | 0 | { |
7934 | 0 | nsIDocument* doc = GetExtantDoc(); |
7935 | 0 | if (doc) { |
7936 | 0 | return doc->GetDocGroup(); |
7937 | 0 | } |
7938 | 0 | return nullptr; |
7939 | 0 | } |
7940 | | |
7941 | | nsIGlobalObject* |
7942 | | nsPIDOMWindowInner::AsGlobal() |
7943 | 0 | { |
7944 | 0 | return nsGlobalWindowInner::Cast(this); |
7945 | 0 | } |
7946 | | |
7947 | | const nsIGlobalObject* |
7948 | | nsPIDOMWindowInner::AsGlobal() const |
7949 | 0 | { |
7950 | 0 | return nsGlobalWindowInner::Cast(this); |
7951 | 0 | } |
7952 | | |
7953 | | static nsPIDOMWindowInner* |
7954 | | GetTopLevelInnerWindow(nsPIDOMWindowInner* aWindow) |
7955 | 0 | { |
7956 | 0 | if (!aWindow) { |
7957 | 0 | return nullptr; |
7958 | 0 | } |
7959 | 0 | nsIDocShell* docShell = aWindow->GetDocShell(); |
7960 | 0 | if (!docShell) { |
7961 | 0 | return nullptr; |
7962 | 0 | } |
7963 | 0 | nsCOMPtr<nsIDocShellTreeItem> rootTreeItem; |
7964 | 0 | docShell->GetSameTypeRootTreeItem(getter_AddRefs(rootTreeItem)); |
7965 | 0 | if (!rootTreeItem || !rootTreeItem->GetDocument()) { |
7966 | 0 | return nullptr; |
7967 | 0 | } |
7968 | 0 | return rootTreeItem->GetDocument()->GetInnerWindow(); |
7969 | 0 | } |
7970 | | |
7971 | | already_AddRefed<mozilla::AutoplayPermissionManager> |
7972 | | nsPIDOMWindowInner::GetAutoplayPermissionManager() |
7973 | 0 | { |
7974 | 0 | // The AutoplayPermissionManager is stored on the top level window. |
7975 | 0 | nsPIDOMWindowInner* window = GetTopLevelInnerWindow(this); |
7976 | 0 | if (!window) { |
7977 | 0 | return nullptr; |
7978 | 0 | } |
7979 | 0 | if (!window->mAutoplayPermissionManager) { |
7980 | 0 | window->mAutoplayPermissionManager = |
7981 | 0 | new AutoplayPermissionManager(nsGlobalWindowInner::Cast(window)); |
7982 | 0 | } |
7983 | 0 | RefPtr<mozilla::AutoplayPermissionManager> manager = |
7984 | 0 | window->mAutoplayPermissionManager; |
7985 | 0 | return manager.forget(); |
7986 | 0 | } |
7987 | | |
7988 | | // XXX: Can we define this in a header instead of here? |
7989 | | namespace mozilla { |
7990 | | namespace dom { |
7991 | | extern uint64_t |
7992 | | NextWindowID(); |
7993 | | } // namespace dom |
7994 | | } // namespace mozilla |
7995 | | |
7996 | | nsPIDOMWindowInner::nsPIDOMWindowInner(nsPIDOMWindowOuter *aOuterWindow) |
7997 | | : mMutationBits(0), mActivePeerConnections(0), mIsDocumentLoaded(false), |
7998 | | mIsHandlingResizeEvent(false), |
7999 | | mMayHavePaintEventListener(false), mMayHaveTouchEventListener(false), |
8000 | | mMayHaveSelectionChangeEventListener(false), |
8001 | | mMayHaveMouseEnterLeaveEventListener(false), |
8002 | | mMayHavePointerEnterLeaveEventListener(false), |
8003 | | mAudioCaptured(false), |
8004 | | mOuterWindow(aOuterWindow), |
8005 | | // Make sure no actual window ends up with mWindowID == 0 |
8006 | | mWindowID(NextWindowID()), mHasNotifiedGlobalCreated(false), |
8007 | | mMarkedCCGeneration(0), |
8008 | | mHasTriedToCacheTopInnerWindow(false), |
8009 | | mNumOfIndexedDBDatabases(0), |
8010 | | mNumOfOpenWebSockets(0), |
8011 | | mEvent(nullptr) |
8012 | 0 | { |
8013 | 0 | MOZ_ASSERT(aOuterWindow); |
8014 | 0 | } |
8015 | | |
8016 | 0 | nsPIDOMWindowInner::~nsPIDOMWindowInner() {} |
8017 | | |
8018 | | #undef FORWARD_TO_OUTER |
8019 | | #undef FORWARD_TO_OUTER_OR_THROW |
8020 | | #undef FORWARD_TO_OUTER_VOID |