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 "base/basictypes.h"
8 
9 #include "BrowserChild.h"
10 
11 #ifdef ACCESSIBILITY
12 #  include "mozilla/a11y/DocAccessibleChild.h"
13 #endif
14 #include <algorithm>
15 #include <utility>
16 
17 #include "BrowserParent.h"
18 #include "ContentChild.h"
19 #include "DocumentInlines.h"
20 #include "EventStateManager.h"
21 #include "Layers.h"
22 #include "MMPrinter.h"
23 #include "PermissionMessageUtils.h"
24 #include "PuppetWidget.h"
25 #include "StructuredCloneData.h"
26 #include "UnitTransforms.h"
27 #include "Units.h"
28 #include "VRManagerChild.h"
29 #include "ipc/nsGUIEventIPC.h"
30 #include "js/JSON.h"
31 #include "mozilla/Assertions.h"
32 #include "mozilla/AsyncEventDispatcher.h"
33 #include "mozilla/BasePrincipal.h"
34 #include "mozilla/ClearOnShutdown.h"
35 #include "mozilla/EventForwards.h"
36 #include "mozilla/EventListenerManager.h"
37 #include "mozilla/HoldDropJSObjects.h"
38 #include "mozilla/IMEStateManager.h"
39 #include "mozilla/LookAndFeel.h"
40 #include "mozilla/MouseEvents.h"
41 #include "mozilla/NativeKeyBindingsType.h"
42 #include "mozilla/NullPrincipal.h"
43 #include "mozilla/Preferences.h"
44 #include "mozilla/PresShell.h"
45 #include "mozilla/ProcessHangMonitor.h"
46 #include "mozilla/ProfilerLabels.h"
47 #include "mozilla/ResultExtensions.h"
48 #include "mozilla/ScopeExit.h"
49 #include "mozilla/Services.h"
50 #include "mozilla/StaticPrefs_dom.h"
51 #include "mozilla/StaticPrefs_fission.h"
52 #include "mozilla/StaticPtr.h"
53 #include "mozilla/Telemetry.h"
54 #include "mozilla/TextEvents.h"
55 #include "mozilla/TouchEvents.h"
56 #include "mozilla/ToString.h"
57 #include "mozilla/Unused.h"
58 #include "mozilla/dom/AutoPrintEventDispatcher.h"
59 #include "mozilla/dom/BrowserBridgeChild.h"
60 #include "mozilla/dom/DataTransfer.h"
61 #include "mozilla/dom/DocGroup.h"
62 #include "mozilla/dom/Element.h"
63 #include "mozilla/dom/Event.h"
64 #include "mozilla/dom/JSWindowActorChild.h"
65 #include "mozilla/dom/LoadURIOptionsBinding.h"
66 #include "mozilla/dom/MessageManagerBinding.h"
67 #include "mozilla/dom/MouseEventBinding.h"
68 #include "mozilla/dom/Nullable.h"
69 #include "mozilla/dom/PBrowser.h"
70 #include "mozilla/dom/PaymentRequestChild.h"
71 #include "mozilla/dom/PointerEventHandler.h"
72 #include "mozilla/dom/SessionStoreChangeListener.h"
73 #include "mozilla/dom/SessionStoreDataCollector.h"
74 #include "mozilla/dom/SessionStoreListener.h"
75 #include "mozilla/dom/SessionStoreUtils.h"
76 #include "mozilla/dom/WindowGlobalChild.h"
77 #include "mozilla/dom/WindowProxyHolder.h"
78 #include "mozilla/gfx/CrossProcessPaint.h"
79 #include "mozilla/gfx/Matrix.h"
80 #include "mozilla/gfx/gfxVars.h"
81 #include "mozilla/ipc/BackgroundChild.h"
82 #include "mozilla/ipc/BackgroundUtils.h"
83 #include "mozilla/ipc/PBackgroundChild.h"
84 #include "mozilla/ipc/URIUtils.h"
85 #include "mozilla/layers/APZCCallbackHelper.h"
86 #include "mozilla/layers/TouchActionHelper.h"
87 #include "mozilla/layers/APZCTreeManagerChild.h"
88 #include "mozilla/layers/APZChild.h"
89 #include "mozilla/layers/APZEventState.h"
90 #include "mozilla/layers/CompositorBridgeChild.h"
91 #include "mozilla/layers/ContentProcessController.h"
92 #include "mozilla/layers/DoubleTapToZoom.h"
93 #include "mozilla/layers/IAPZCTreeManager.h"
94 #include "mozilla/layers/ImageBridgeChild.h"
95 #include "mozilla/layers/InputAPZContext.h"
96 #include "mozilla/layers/WebRenderLayerManager.h"
97 #include "nsBrowserStatusFilter.h"
98 #include "nsColorPickerProxy.h"
99 #include "nsCommandParams.h"
100 #include "nsContentPermissionHelper.h"
101 #include "nsContentUtils.h"
102 #include "nsDeviceContext.h"
103 #include "nsDocShell.h"
104 #include "nsDocShellLoadState.h"
105 #include "nsEmbedCID.h"
106 #include "nsExceptionHandler.h"
107 #include "nsFilePickerProxy.h"
108 #include "nsFocusManager.h"
109 #include "nsGlobalWindow.h"
110 #include "nsIBaseWindow.h"
111 #include "nsIBrowserDOMWindow.h"
112 #include "nsIClassifiedChannel.h"
113 #include "nsIDocShell.h"
114 #include "nsIFrame.h"
115 #include "nsILoadContext.h"
116 #include "nsISHEntry.h"
117 #include "nsISHistory.h"
118 #include "nsIScreenManager.h"
119 #include "nsIScriptError.h"
120 #include "nsISecureBrowserUI.h"
121 #include "nsIURI.h"
122 #include "nsIURIMutator.h"
123 #include "nsIWeakReferenceUtils.h"
124 #include "nsIWebBrowser.h"
125 #include "nsIWebProgress.h"
126 #include "nsLayoutUtils.h"
127 #include "nsNetUtil.h"
128 #include "nsIOpenWindowInfo.h"
129 #include "nsPIDOMWindow.h"
130 #include "nsPIWindowRoot.h"
131 #include "nsPointerHashKeys.h"
132 #include "nsPrintfCString.h"
133 #include "nsQueryActor.h"
134 #include "nsQueryObject.h"
135 #include "nsRefreshDriver.h"
136 #include "nsSandboxFlags.h"
137 #include "nsString.h"
138 #include "nsTHashtable.h"
139 #include "nsThreadManager.h"
140 #include "nsThreadUtils.h"
141 #include "nsViewManager.h"
142 #include "nsViewportInfo.h"
143 #include "nsWebBrowser.h"
144 #include "nsWindowWatcher.h"
145 #include "nsIXULRuntime.h"
146 
147 #ifdef MOZ_WAYLAND
148 #  include "nsAppRunner.h"
149 #endif
150 
151 #ifdef NS_PRINTING
152 #  include "nsIPrintSession.h"
153 #  include "nsIPrintSettings.h"
154 #  include "nsIPrintSettingsService.h"
155 #  include "nsIWebBrowserPrint.h"
156 #endif
157 
158 static mozilla::LazyLogModule sApzChildLog("apz.child");
159 
160 using namespace mozilla;
161 using namespace mozilla::dom;
162 using namespace mozilla::dom::ipc;
163 using namespace mozilla::ipc;
164 using namespace mozilla::layers;
165 using namespace mozilla::layout;
166 using namespace mozilla::widget;
167 using mozilla::layers::GeckoContentController;
168 
169 NS_IMPL_ISUPPORTS(ContentListener, nsIDOMEventListener)
170 
171 static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
172 
173 static uint32_t sConsecutiveTouchMoveCount = 0;
174 
175 using BrowserChildMap = nsTHashMap<nsUint64HashKey, BrowserChild*>;
176 static BrowserChildMap* sBrowserChildren;
177 StaticMutex sBrowserChildrenMutex;
178 
GetTopLevelDocument() const179 already_AddRefed<Document> BrowserChild::GetTopLevelDocument() const {
180   nsCOMPtr<Document> doc;
181   WebNavigation()->GetDocument(getter_AddRefs(doc));
182   return doc.forget();
183 }
184 
GetTopLevelPresShell() const185 PresShell* BrowserChild::GetTopLevelPresShell() const {
186   if (RefPtr<Document> doc = GetTopLevelDocument()) {
187     return doc->GetPresShell();
188   }
189   return nullptr;
190 }
191 
UpdateFrame(const RepaintRequest & aRequest)192 bool BrowserChild::UpdateFrame(const RepaintRequest& aRequest) {
193   MOZ_ASSERT(aRequest.GetScrollId() != ScrollableLayerGuid::NULL_SCROLL_ID);
194 
195   if (aRequest.IsRootContent()) {
196     if (PresShell* presShell = GetTopLevelPresShell()) {
197       // Guard against stale updates (updates meant for a pres shell which
198       // has since been torn down and destroyed).
199       if (aRequest.GetPresShellId() == presShell->GetPresShellId()) {
200         APZCCallbackHelper::UpdateRootFrame(aRequest);
201         return true;
202       }
203     }
204   } else {
205     // aRequest.mIsRoot is false, so we are trying to update a subframe.
206     // This requires special handling.
207     APZCCallbackHelper::UpdateSubFrame(aRequest);
208     return true;
209   }
210   return true;
211 }
212 
213 NS_IMETHODIMP
HandleEvent(Event * aEvent)214 ContentListener::HandleEvent(Event* aEvent) {
215   RemoteDOMEvent remoteEvent;
216   remoteEvent.mEvent = aEvent;
217   NS_ENSURE_STATE(remoteEvent.mEvent);
218   mBrowserChild->SendEvent(remoteEvent);
219   return NS_OK;
220 }
221 
222 class BrowserChild::DelayedDeleteRunnable final : public Runnable,
223                                                   public nsIRunnablePriority {
224   RefPtr<BrowserChild> mBrowserChild;
225 
226   // In order to try that this runnable runs after everything that could
227   // possibly touch this tab, we send it through the event queue twice.
228   bool mReadyToDelete = false;
229 
230  public:
DelayedDeleteRunnable(BrowserChild * aBrowserChild)231   explicit DelayedDeleteRunnable(BrowserChild* aBrowserChild)
232       : Runnable("BrowserChild::DelayedDeleteRunnable"),
233         mBrowserChild(aBrowserChild) {
234     MOZ_ASSERT(NS_IsMainThread());
235     MOZ_ASSERT(aBrowserChild);
236   }
237 
238   NS_DECL_ISUPPORTS_INHERITED
239 
240  private:
~DelayedDeleteRunnable()241   ~DelayedDeleteRunnable() {
242     MOZ_ASSERT(NS_IsMainThread());
243     MOZ_ASSERT(!mBrowserChild);
244   }
245 
GetPriority(uint32_t * aPriority)246   NS_IMETHOD GetPriority(uint32_t* aPriority) override {
247     *aPriority = nsIRunnablePriority::PRIORITY_NORMAL;
248     return NS_OK;
249   }
250 
251   NS_IMETHOD
Run()252   Run() override {
253     MOZ_ASSERT(NS_IsMainThread());
254     MOZ_ASSERT(mBrowserChild);
255 
256     if (!mReadyToDelete) {
257       // This time run this runnable at input priority.
258       mReadyToDelete = true;
259       MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(this));
260       return NS_OK;
261     }
262 
263     // Check in case ActorDestroy was called after RecvDestroy message.
264     if (mBrowserChild->IPCOpen()) {
265       Unused << PBrowserChild::Send__delete__(mBrowserChild);
266     }
267 
268     mBrowserChild = nullptr;
269     return NS_OK;
270   }
271 };
272 
273 NS_IMPL_ISUPPORTS_INHERITED(BrowserChild::DelayedDeleteRunnable, Runnable,
274                             nsIRunnablePriority)
275 
276 namespace {
NestedBrowserChildMap()277 std::map<TabId, RefPtr<BrowserChild>>& NestedBrowserChildMap() {
278   MOZ_ASSERT(NS_IsMainThread());
279   static std::map<TabId, RefPtr<BrowserChild>> sNestedBrowserChildMap;
280   return sNestedBrowserChildMap;
281 }
282 }  // namespace
283 
FindBrowserChild(const TabId & aTabId)284 already_AddRefed<BrowserChild> BrowserChild::FindBrowserChild(
285     const TabId& aTabId) {
286   auto iter = NestedBrowserChildMap().find(aTabId);
287   if (iter == NestedBrowserChildMap().end()) {
288     return nullptr;
289   }
290   RefPtr<BrowserChild> browserChild = iter->second;
291   return browserChild.forget();
292 }
293 
294 /*static*/
Create(ContentChild * aManager,const TabId & aTabId,const TabContext & aContext,BrowsingContext * aBrowsingContext,uint32_t aChromeFlags,bool aIsTopLevel)295 already_AddRefed<BrowserChild> BrowserChild::Create(
296     ContentChild* aManager, const TabId& aTabId, const TabContext& aContext,
297     BrowsingContext* aBrowsingContext, uint32_t aChromeFlags,
298     bool aIsTopLevel) {
299   RefPtr<BrowserChild> iframe = new BrowserChild(
300       aManager, aTabId, aContext, aBrowsingContext, aChromeFlags, aIsTopLevel);
301   return iframe.forget();
302 }
303 
BrowserChild(ContentChild * aManager,const TabId & aTabId,const TabContext & aContext,BrowsingContext * aBrowsingContext,uint32_t aChromeFlags,bool aIsTopLevel)304 BrowserChild::BrowserChild(ContentChild* aManager, const TabId& aTabId,
305                            const TabContext& aContext,
306                            BrowsingContext* aBrowsingContext,
307                            uint32_t aChromeFlags, bool aIsTopLevel)
308     : TabContext(aContext),
309       mBrowserChildMessageManager(nullptr),
310       mManager(aManager),
311       mBrowsingContext(aBrowsingContext),
312       mChromeFlags(aChromeFlags),
313       mMaxTouchPoints(0),
314       mLayersId{0},
315       mEffectsInfo{EffectsInfo::FullyHidden()},
316       mDynamicToolbarMaxHeight(0),
317       mUniqueId(aTabId),
318       mDidFakeShow(false),
319       mTriedBrowserInit(false),
320       mIgnoreKeyPressEvent(false),
321       mHasValidInnerSize(false),
322       mDestroyed(false),
323       mIsTopLevel(aIsTopLevel),
324       mHasSiblings(false),
325       mIsTransparent(false),
326       mIPCOpen(false),
327       mDidSetRealShowInfo(false),
328       mDidLoadURLInit(false),
329       mSkipKeyPress(false),
330       mDidSetEffectsInfo(false),
331       mShouldSendWebProgressEventsToParent(false),
332       mRenderLayers(true),
333       mIsPreservingLayers(false),
334       mPendingDocShellIsActive(false),
335       mPendingDocShellReceivedMessage(false),
336       mPendingRenderLayers(false),
337       mPendingRenderLayersReceivedMessage(false),
338       mLayersObserverEpoch{1},
339 #if defined(XP_WIN) && defined(ACCESSIBILITY)
340       mNativeWindowHandle(0),
341 #endif
342 #if defined(ACCESSIBILITY)
343       mTopLevelDocAccessibleChild(nullptr),
344 #endif
345       mPendingLayersObserverEpoch{0},
346       mPendingDocShellBlockers(0),
347       mCancelContentJSEpoch(0) {
348   mozilla::HoldJSObjects(this);
349 
350   // preloaded BrowserChild should not be added to child map
351   if (mUniqueId) {
352     MOZ_ASSERT(NestedBrowserChildMap().find(mUniqueId) ==
353                NestedBrowserChildMap().end());
354     NestedBrowserChildMap()[mUniqueId] = this;
355   }
356   mCoalesceMouseMoveEvents = StaticPrefs::dom_events_coalesce_mousemove();
357   if (mCoalesceMouseMoveEvents) {
358     mCoalescedMouseEventFlusher = new CoalescedMouseMoveFlusher(this);
359   }
360 
361   if (StaticPrefs::dom_events_coalesce_touchmove()) {
362     mCoalescedTouchMoveEventFlusher = new CoalescedTouchMoveFlusher(this);
363   }
364 }
365 
GetCompositorOptions() const366 const CompositorOptions& BrowserChild::GetCompositorOptions() const {
367   // If you're calling this before mCompositorOptions is set, well.. don't.
368   MOZ_ASSERT(mCompositorOptions);
369   return mCompositorOptions.ref();
370 }
371 
AsyncPanZoomEnabled() const372 bool BrowserChild::AsyncPanZoomEnabled() const {
373   // This might get called by the TouchEvent::PrefEnabled code before we have
374   // mCompositorOptions populated (bug 1370089). In that case we just assume
375   // APZ is enabled because we're in a content process (because BrowserChild)
376   // and APZ is probably going to be enabled here since e10s is enabled.
377   return mCompositorOptions ? mCompositorOptions->UseAPZ() : true;
378 }
379 
380 NS_IMETHODIMP
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)381 BrowserChild::Observe(nsISupports* aSubject, const char* aTopic,
382                       const char16_t* aData) {
383   if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) {
384     if (AsyncPanZoomEnabled()) {
385       nsCOMPtr<Document> subject(do_QueryInterface(aSubject));
386       nsCOMPtr<Document> doc(GetTopLevelDocument());
387 
388       if (subject == doc) {
389         RefPtr<PresShell> presShell = doc->GetPresShell();
390         if (presShell) {
391           presShell->SetIsFirstPaint(true);
392         }
393 
394         APZCCallbackHelper::InitializeRootDisplayport(presShell);
395       }
396     }
397   }
398 
399   return NS_OK;
400 }
401 
ContentReceivedInputBlock(uint64_t aInputBlockId,bool aPreventDefault) const402 void BrowserChild::ContentReceivedInputBlock(uint64_t aInputBlockId,
403                                              bool aPreventDefault) const {
404   if (mApzcTreeManager) {
405     mApzcTreeManager->ContentReceivedInputBlock(aInputBlockId, aPreventDefault);
406   }
407 }
408 
SetTargetAPZC(uint64_t aInputBlockId,const nsTArray<ScrollableLayerGuid> & aTargets) const409 void BrowserChild::SetTargetAPZC(
410     uint64_t aInputBlockId,
411     const nsTArray<ScrollableLayerGuid>& aTargets) const {
412   if (mApzcTreeManager) {
413     mApzcTreeManager->SetTargetAPZC(aInputBlockId, aTargets);
414   }
415 }
416 
DoUpdateZoomConstraints(const uint32_t & aPresShellId,const ViewID & aViewId,const Maybe<ZoomConstraints> & aConstraints)417 bool BrowserChild::DoUpdateZoomConstraints(
418     const uint32_t& aPresShellId, const ViewID& aViewId,
419     const Maybe<ZoomConstraints>& aConstraints) {
420   if (!mApzcTreeManager || mDestroyed) {
421     return false;
422   }
423 
424   ScrollableLayerGuid guid =
425       ScrollableLayerGuid(mLayersId, aPresShellId, aViewId);
426 
427   mApzcTreeManager->UpdateZoomConstraints(guid, aConstraints);
428   return true;
429 }
430 
Init(mozIDOMWindowProxy * aParent,WindowGlobalChild * aInitialWindowChild)431 nsresult BrowserChild::Init(mozIDOMWindowProxy* aParent,
432                             WindowGlobalChild* aInitialWindowChild) {
433   MOZ_ASSERT_IF(aInitialWindowChild,
434                 aInitialWindowChild->BrowsingContext() == mBrowsingContext);
435 
436   nsCOMPtr<nsIWidget> widget = nsIWidget::CreatePuppetWidget(this);
437   mPuppetWidget = static_cast<PuppetWidget*>(widget.get());
438   if (!mPuppetWidget) {
439     NS_ERROR("couldn't create fake widget");
440     return NS_ERROR_FAILURE;
441   }
442   mPuppetWidget->InfallibleCreate(nullptr,
443                                   nullptr,  // no parents
444                                   LayoutDeviceIntRect(0, 0, 0, 0),
445                                   nullptr);  // HandleWidgetEvent
446 
447   mWebBrowser = nsWebBrowser::Create(this, mPuppetWidget, mBrowsingContext,
448                                      aInitialWindowChild);
449   nsIWebBrowser* webBrowser = mWebBrowser;
450 
451   mWebNav = do_QueryInterface(webBrowser);
452   NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
453 
454   // IPC uses a WebBrowser object for which DNS prefetching is turned off
455   // by default. But here we really want it, so enable it explicitly
456   mWebBrowser->SetAllowDNSPrefetch(true);
457 
458   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
459   MOZ_ASSERT(docShell);
460 
461   mStatusFilter = new nsBrowserStatusFilter();
462 
463   nsresult rv =
464       mStatusFilter->AddProgressListener(this, nsIWebProgress::NOTIFY_ALL);
465   NS_ENSURE_SUCCESS(rv, rv);
466 
467   {
468     nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(docShell);
469     rv = webProgress->AddProgressListener(mStatusFilter,
470                                           nsIWebProgress::NOTIFY_ALL);
471     NS_ENSURE_SUCCESS(rv, rv);
472   }
473 
474 #ifdef DEBUG
475   nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(WebNavigation());
476   MOZ_ASSERT(loadContext);
477   MOZ_ASSERT(loadContext->UseRemoteTabs() ==
478              !!(mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW));
479   MOZ_ASSERT(loadContext->UseRemoteSubframes() ==
480              !!(mChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW));
481 #endif  // defined(DEBUG)
482 
483   // Few lines before, baseWindow->Create() will end up creating a new
484   // window root in nsGlobalWindow::SetDocShell.
485   // Then this chrome event handler, will be inherited to inner windows.
486   // We want to also set it to the docshell so that inner windows
487   // and any code that has access to the docshell
488   // can all listen to the same chrome event handler.
489   // XXX: ideally, we would set a chrome event handler earlier,
490   // and all windows, even the root one, will use the docshell one.
491   nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
492   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
493   nsCOMPtr<EventTarget> chromeHandler = window->GetChromeEventHandler();
494   docShell->SetChromeEventHandler(chromeHandler);
495 
496   if (window->GetCurrentInnerWindow()) {
497     window->SetKeyboardIndicators(ShowFocusRings());
498   } else {
499     // Skip ShouldShowFocusRing check if no inner window is available
500     window->SetInitialKeyboardIndicators(ShowFocusRings());
501   }
502 
503   // Window scrollbar flags only affect top level remote frames, not fission
504   // frames.
505   if (mIsTopLevel) {
506     nsContentUtils::SetScrollbarsVisibility(
507         docShell, !!(mChromeFlags & nsIWebBrowserChrome::CHROME_SCROLLBARS));
508   }
509 
510   nsWeakPtr weakPtrThis = do_GetWeakReference(
511       static_cast<nsIBrowserChild*>(this));  // for capture by the lambda
512   ContentReceivedInputBlockCallback callback(
513       [weakPtrThis](uint64_t aInputBlockId, bool aPreventDefault) {
514         if (nsCOMPtr<nsIBrowserChild> browserChild =
515                 do_QueryReferent(weakPtrThis)) {
516           static_cast<BrowserChild*>(browserChild.get())
517               ->ContentReceivedInputBlock(aInputBlockId, aPreventDefault);
518         }
519       });
520   mAPZEventState = new APZEventState(mPuppetWidget, std::move(callback));
521 
522   mIPCOpen = true;
523 
524   if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
525     mSessionStoreListener = new TabListener(docShell, nullptr);
526     rv = mSessionStoreListener->Init();
527     NS_ENSURE_SUCCESS(rv, rv);
528 
529     mSessionStoreChangeListener =
530         SessionStoreChangeListener::Create(mBrowsingContext);
531   }
532 
533   // We've all set up, make sure our visibility state is consistent. This is
534   // important for OOP iframes, which start off as hidden.
535   UpdateVisibility();
536 
537   return NS_OK;
538 }
539 
540 NS_IMPL_CYCLE_COLLECTION_CLASS(BrowserChild)
541 
542 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowserChild)
543   NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChildMessageManager)
544   tmp->nsMessageManagerScriptExecutor::Unlink();
545   NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusFilter)
546   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebNav)
547   NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
548   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStoreListener)
549   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStoreChangeListener)
550   NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
551 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
552 
553 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowserChild)
554   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChildMessageManager)
555   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusFilter)
556   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebNav)
557   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
558   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStoreListener)
559   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStoreChangeListener)
560 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
561 
562 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(BrowserChild)
563   tmp->nsMessageManagerScriptExecutor::Trace(aCallbacks, aClosure);
564 NS_IMPL_CYCLE_COLLECTION_TRACE_END
565 
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserChild)566 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserChild)
567   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
568   NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
569   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus)
570   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
571   NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
572   NS_INTERFACE_MAP_ENTRY(nsIBrowserChild)
573   NS_INTERFACE_MAP_ENTRY(nsIObserver)
574   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
575   NS_INTERFACE_MAP_ENTRY(nsITooltipListener)
576   NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
577   NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener2)
578   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIBrowserChild)
579 NS_INTERFACE_MAP_END
580 
581 NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowserChild)
582 NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowserChild)
583 
584 NS_IMETHODIMP
585 BrowserChild::GetChromeFlags(uint32_t* aChromeFlags) {
586   *aChromeFlags = mChromeFlags;
587   return NS_OK;
588 }
589 
590 NS_IMETHODIMP
SetChromeFlags(uint32_t aChromeFlags)591 BrowserChild::SetChromeFlags(uint32_t aChromeFlags) {
592   NS_WARNING("trying to SetChromeFlags from content process?");
593 
594   return NS_ERROR_NOT_IMPLEMENTED;
595 }
596 
597 NS_IMETHODIMP
RemoteSizeShellTo(int32_t aWidth,int32_t aHeight,int32_t aShellItemWidth,int32_t aShellItemHeight)598 BrowserChild::RemoteSizeShellTo(int32_t aWidth, int32_t aHeight,
599                                 int32_t aShellItemWidth,
600                                 int32_t aShellItemHeight) {
601   nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
602   nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(ourDocShell));
603   NS_ENSURE_STATE(docShellAsWin);
604 
605   int32_t width, height;
606   docShellAsWin->GetSize(&width, &height);
607 
608   uint32_t flags = 0;
609   if (width == aWidth) {
610     flags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX;
611   }
612 
613   if (height == aHeight) {
614     flags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY;
615   }
616 
617   bool sent = SendSizeShellTo(flags, aWidth, aHeight, aShellItemWidth,
618                               aShellItemHeight);
619 
620   return sent ? NS_OK : NS_ERROR_FAILURE;
621 }
622 
623 NS_IMETHODIMP
RemoteDropLinks(const nsTArray<RefPtr<nsIDroppedLinkItem>> & aLinks)624 BrowserChild::RemoteDropLinks(
625     const nsTArray<RefPtr<nsIDroppedLinkItem>>& aLinks) {
626   nsTArray<nsString> linksArray;
627   nsresult rv = NS_OK;
628   for (nsIDroppedLinkItem* link : aLinks) {
629     nsString tmp;
630     rv = link->GetUrl(tmp);
631     if (NS_FAILED(rv)) {
632       return rv;
633     }
634     linksArray.AppendElement(tmp);
635 
636     rv = link->GetName(tmp);
637     if (NS_FAILED(rv)) {
638       return rv;
639     }
640     linksArray.AppendElement(tmp);
641 
642     rv = link->GetType(tmp);
643     if (NS_FAILED(rv)) {
644       return rv;
645     }
646     linksArray.AppendElement(tmp);
647   }
648   bool sent = SendDropLinks(linksArray);
649 
650   return sent ? NS_OK : NS_ERROR_FAILURE;
651 }
652 
653 NS_IMETHODIMP
ShowAsModal()654 BrowserChild::ShowAsModal() {
655   NS_WARNING("BrowserChild::ShowAsModal not supported in BrowserChild");
656 
657   return NS_ERROR_NOT_IMPLEMENTED;
658 }
659 
660 NS_IMETHODIMP
IsWindowModal(bool * aRetVal)661 BrowserChild::IsWindowModal(bool* aRetVal) {
662   *aRetVal = false;
663   return NS_OK;
664 }
665 
666 NS_IMETHODIMP
SetLinkStatus(const nsAString & aStatusText)667 BrowserChild::SetLinkStatus(const nsAString& aStatusText) {
668   // We can only send the status after the ipc machinery is set up
669   if (IPCOpen()) {
670     SendSetLinkStatus(nsString(aStatusText));
671   }
672   return NS_OK;
673 }
674 
675 NS_IMETHODIMP
SetDimensions(uint32_t aFlags,int32_t aX,int32_t aY,int32_t aCx,int32_t aCy)676 BrowserChild::SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY,
677                             int32_t aCx, int32_t aCy) {
678   // The parent is in charge of the dimension changes. If JS code wants to
679   // change the dimensions (moveTo, screenX, etc.) we send a message to the
680   // parent about the new requested dimension, the parent does the resize/move
681   // then send a message to the child to update itself. For APIs like screenX
682   // this function is called with the current value for the non-changed values.
683   // In a series of calls like window.screenX = 10; window.screenY = 10; for
684   // the second call, since screenX is not yet updated we might accidentally
685   // reset back screenX to it's old value. To avoid this if a parameter did not
686   // change we want the parent to ignore its value.
687   int32_t x, y, cx, cy;
688   GetDimensions(aFlags, &x, &y, &cx, &cy);
689 
690   if (x == aX) {
691     aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_X;
692   }
693 
694   if (y == aY) {
695     aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_Y;
696   }
697 
698   if (cx == aCx) {
699     aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX;
700   }
701 
702   if (cy == aCy) {
703     aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY;
704   }
705 
706   double scale = mPuppetWidget ? mPuppetWidget->GetDefaultScale().scale : 1.0;
707 
708   Unused << SendSetDimensions(aFlags, aX, aY, aCx, aCy, scale);
709 
710   return NS_OK;
711 }
712 
713 NS_IMETHODIMP
GetDimensions(uint32_t aFlags,int32_t * aX,int32_t * aY,int32_t * aCx,int32_t * aCy)714 BrowserChild::GetDimensions(uint32_t aFlags, int32_t* aX, int32_t* aY,
715                             int32_t* aCx, int32_t* aCy) {
716   ScreenIntRect rect = GetOuterRect();
717   if (aX) {
718     *aX = rect.x;
719   }
720   if (aY) {
721     *aY = rect.y;
722   }
723   if (aCx) {
724     *aCx = rect.width;
725   }
726   if (aCy) {
727     *aCy = rect.height;
728   }
729 
730   return NS_OK;
731 }
732 
733 NS_IMETHODIMP
GetVisibility(bool * aVisibility)734 BrowserChild::GetVisibility(bool* aVisibility) {
735   *aVisibility = true;
736   return NS_OK;
737 }
738 
739 NS_IMETHODIMP
SetVisibility(bool aVisibility)740 BrowserChild::SetVisibility(bool aVisibility) {
741   // should the platform support this? Bug 666365
742   return NS_OK;
743 }
744 
745 NS_IMETHODIMP
GetTitle(nsAString & aTitle)746 BrowserChild::GetTitle(nsAString& aTitle) {
747   NS_WARNING("BrowserChild::GetTitle not supported in BrowserChild");
748 
749   return NS_ERROR_NOT_IMPLEMENTED;
750 }
751 
752 NS_IMETHODIMP
SetTitle(const nsAString & aTitle)753 BrowserChild::SetTitle(const nsAString& aTitle) {
754   // JavaScript sends the "DOMTitleChanged" event to the parent
755   // via the message manager.
756   return NS_OK;
757 }
758 
759 NS_IMETHODIMP
GetSiteWindow(void ** aSiteWindow)760 BrowserChild::GetSiteWindow(void** aSiteWindow) {
761   NS_WARNING("BrowserChild::GetSiteWindow not supported in BrowserChild");
762 
763   return NS_ERROR_NOT_IMPLEMENTED;
764 }
765 
766 NS_IMETHODIMP
Blur()767 BrowserChild::Blur() { return NS_ERROR_NOT_IMPLEMENTED; }
768 
769 NS_IMETHODIMP
FocusNextElement(bool aForDocumentNavigation)770 BrowserChild::FocusNextElement(bool aForDocumentNavigation) {
771   SendMoveFocus(true, aForDocumentNavigation);
772   return NS_OK;
773 }
774 
775 NS_IMETHODIMP
FocusPrevElement(bool aForDocumentNavigation)776 BrowserChild::FocusPrevElement(bool aForDocumentNavigation) {
777   SendMoveFocus(false, aForDocumentNavigation);
778   return NS_OK;
779 }
780 
781 NS_IMETHODIMP
GetInterface(const nsIID & aIID,void ** aSink)782 BrowserChild::GetInterface(const nsIID& aIID, void** aSink) {
783   if (aIID.Equals(NS_GET_IID(nsITopLevelNavigationDelegate))) {
784     nsCOMPtr<nsITopLevelNavigationDelegate> delegate =
785         GetTopLevelNavigationDelegate();
786     if (delegate) {
787       delegate.forget(aSink);
788       return NS_OK;
789     }
790   }
791 
792   // XXXbz should we restrict the set of interfaces we hand out here?
793   // See bug 537429
794   return QueryInterface(aIID, aSink);
795 }
796 
797 NS_IMETHODIMP
ProvideWindow(nsIOpenWindowInfo * aOpenWindowInfo,uint32_t aChromeFlags,bool aCalledFromJS,nsIURI * aURI,const nsAString & aName,const nsACString & aFeatures,bool aForceNoOpener,bool aForceNoReferrer,bool aIsPopupRequested,nsDocShellLoadState * aLoadState,bool * aWindowIsNew,BrowsingContext ** aReturn)798 BrowserChild::ProvideWindow(nsIOpenWindowInfo* aOpenWindowInfo,
799                             uint32_t aChromeFlags, bool aCalledFromJS,
800                             nsIURI* aURI, const nsAString& aName,
801                             const nsACString& aFeatures, bool aForceNoOpener,
802                             bool aForceNoReferrer, bool aIsPopupRequested,
803                             nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
804                             BrowsingContext** aReturn) {
805   *aReturn = nullptr;
806 
807   RefPtr<BrowsingContext> parent = aOpenWindowInfo->GetParent();
808 
809   int32_t openLocation = nsWindowWatcher::GetWindowOpenLocation(
810       parent->GetDOMWindow(), aChromeFlags, aCalledFromJS,
811       aOpenWindowInfo->GetIsForPrinting());
812 
813   // If it turns out we're opening in the current browser, just hand over the
814   // current browser's docshell.
815   if (openLocation == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
816     nsCOMPtr<nsIWebBrowser> browser = do_GetInterface(WebNavigation());
817     *aWindowIsNew = false;
818 
819     nsCOMPtr<mozIDOMWindowProxy> win;
820     MOZ_TRY(browser->GetContentDOMWindow(getter_AddRefs(win)));
821 
822     RefPtr<BrowsingContext> bc(
823         nsPIDOMWindowOuter::From(win)->GetBrowsingContext());
824     bc.forget(aReturn);
825     return NS_OK;
826   }
827 
828   // Note that ProvideWindowCommon may return NS_ERROR_ABORT if the
829   // open window call was canceled.  It's important that we pass this error
830   // code back to our caller.
831   ContentChild* cc = ContentChild::GetSingleton();
832   return cc->ProvideWindowCommon(
833       this, aOpenWindowInfo, aChromeFlags, aCalledFromJS, aURI, aName,
834       aFeatures, aForceNoOpener, aForceNoReferrer, aIsPopupRequested,
835       aLoadState, aWindowIsNew, aReturn);
836 }
837 
DestroyWindow()838 void BrowserChild::DestroyWindow() {
839   mBrowsingContext = nullptr;
840 
841   if (mStatusFilter) {
842     if (nsCOMPtr<nsIWebProgress> webProgress =
843             do_QueryInterface(WebNavigation())) {
844       webProgress->RemoveProgressListener(mStatusFilter);
845     }
846 
847     mStatusFilter->RemoveProgressListener(this);
848     mStatusFilter = nullptr;
849   }
850 
851   if (mCoalescedMouseEventFlusher) {
852     mCoalescedMouseEventFlusher->RemoveObserver();
853     mCoalescedMouseEventFlusher = nullptr;
854   }
855 
856   if (mCoalescedTouchMoveEventFlusher) {
857     mCoalescedTouchMoveEventFlusher->RemoveObserver();
858     mCoalescedTouchMoveEventFlusher = nullptr;
859   }
860 
861   if (mSessionStoreListener) {
862     mSessionStoreListener->RemoveListeners();
863     mSessionStoreListener = nullptr;
864   }
865 
866   if (mSessionStoreChangeListener) {
867     mSessionStoreChangeListener->Stop();
868     mSessionStoreChangeListener = nullptr;
869   }
870 
871   // In case we don't have chance to process all entries, clean all data in
872   // the queue.
873   while (mToBeDispatchedMouseData.GetSize() > 0) {
874     UniquePtr<CoalescedMouseData> data(
875         static_cast<CoalescedMouseData*>(mToBeDispatchedMouseData.PopFront()));
876     data.reset();
877   }
878 
879   nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
880   if (baseWindow) baseWindow->Destroy();
881 
882   if (mPuppetWidget) {
883     mPuppetWidget->Destroy();
884   }
885 
886   mLayersConnected = Nothing();
887 
888   if (mLayersId.IsValid()) {
889     StaticMutexAutoLock lock(sBrowserChildrenMutex);
890 
891     MOZ_ASSERT(sBrowserChildren);
892     sBrowserChildren->Remove(uint64_t(mLayersId));
893     if (!sBrowserChildren->Count()) {
894       delete sBrowserChildren;
895       sBrowserChildren = nullptr;
896     }
897     mLayersId = layers::LayersId{0};
898   }
899 }
900 
ActorDestroy(ActorDestroyReason why)901 void BrowserChild::ActorDestroy(ActorDestroyReason why) {
902   mIPCOpen = false;
903 
904   DestroyWindow();
905 
906   if (mBrowserChildMessageManager) {
907     // We should have a message manager if the global is alive, but it
908     // seems sometimes we don't.  Assert in aurora/nightly, but don't
909     // crash in release builds.
910     MOZ_DIAGNOSTIC_ASSERT(mBrowserChildMessageManager->GetMessageManager());
911     if (mBrowserChildMessageManager->GetMessageManager()) {
912       // The messageManager relays messages via the BrowserChild which
913       // no longer exists.
914       mBrowserChildMessageManager->DisconnectMessageManager();
915     }
916   }
917 
918   if (GetTabId() != 0) {
919     NestedBrowserChildMap().erase(GetTabId());
920   }
921 }
922 
~BrowserChild()923 BrowserChild::~BrowserChild() {
924   mAnonymousGlobalScopes.Clear();
925 
926   DestroyWindow();
927 
928   nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(WebNavigation());
929   if (webBrowser) {
930     webBrowser->SetContainerWindow(nullptr);
931   }
932 
933   mozilla::DropJSObjects(this);
934 }
935 
RecvWillChangeProcess()936 mozilla::ipc::IPCResult BrowserChild::RecvWillChangeProcess() {
937   if (mWebBrowser) {
938     mWebBrowser->SetWillChangeProcess();
939   }
940   return IPC_OK();
941 }
942 
RecvLoadURL(nsDocShellLoadState * aLoadState,const ParentShowInfo & aInfo)943 mozilla::ipc::IPCResult BrowserChild::RecvLoadURL(
944     nsDocShellLoadState* aLoadState, const ParentShowInfo& aInfo) {
945   if (!mDidLoadURLInit) {
946     mDidLoadURLInit = true;
947     if (!InitBrowserChildMessageManager()) {
948       return IPC_FAIL_NO_REASON(this);
949     }
950 
951     ApplyParentShowInfo(aInfo);
952   }
953   nsAutoCString spec;
954   aLoadState->URI()->GetSpec(spec);
955 
956   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
957   if (!docShell) {
958     NS_WARNING("WebNavigation does not have a docshell");
959     return IPC_OK();
960   }
961   docShell->LoadURI(aLoadState, true);
962 
963   nsDocShell::Cast(docShell)->MaybeClearStorageAccessFlag();
964 
965   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL, spec);
966   return IPC_OK();
967 }
968 
RecvCreateAboutBlankContentViewer(nsIPrincipal * aPrincipal,nsIPrincipal * aPartitionedPrincipal)969 mozilla::ipc::IPCResult BrowserChild::RecvCreateAboutBlankContentViewer(
970     nsIPrincipal* aPrincipal, nsIPrincipal* aPartitionedPrincipal) {
971   if (aPrincipal->GetIsExpandedPrincipal() ||
972       aPartitionedPrincipal->GetIsExpandedPrincipal()) {
973     return IPC_FAIL(this, "Cannot create document with an expanded principal");
974   }
975   if (aPrincipal->IsSystemPrincipal() ||
976       aPartitionedPrincipal->IsSystemPrincipal()) {
977     MOZ_ASSERT_UNREACHABLE(
978         "Cannot use CreateAboutBlankContentViewer to create system principal "
979         "document in content");
980     return IPC_OK();
981   }
982 
983   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
984   if (!docShell) {
985     MOZ_ASSERT_UNREACHABLE("WebNavigation does not have a docshell");
986     return IPC_OK();
987   }
988 
989   nsCOMPtr<nsIURI> currentURI;
990   MOZ_ALWAYS_SUCCEEDS(
991       WebNavigation()->GetCurrentURI(getter_AddRefs(currentURI)));
992   if (!currentURI || !NS_IsAboutBlank(currentURI)) {
993     NS_WARNING("Can't create a ContentViewer unless on about:blank");
994     return IPC_OK();
995   }
996 
997   docShell->CreateAboutBlankContentViewer(aPrincipal, aPartitionedPrincipal,
998                                           nullptr);
999   return IPC_OK();
1000 }
1001 
RecvResumeLoad(const uint64_t & aPendingSwitchID,const ParentShowInfo & aInfo)1002 mozilla::ipc::IPCResult BrowserChild::RecvResumeLoad(
1003     const uint64_t& aPendingSwitchID, const ParentShowInfo& aInfo) {
1004   if (!mDidLoadURLInit) {
1005     mDidLoadURLInit = true;
1006     if (!InitBrowserChildMessageManager()) {
1007       return IPC_FAIL_NO_REASON(this);
1008     }
1009 
1010     ApplyParentShowInfo(aInfo);
1011   }
1012 
1013   nsresult rv = WebNavigation()->ResumeRedirectedLoad(aPendingSwitchID, -1);
1014   if (NS_FAILED(rv)) {
1015     NS_WARNING("WebNavigation()->ResumeRedirectedLoad failed");
1016   }
1017 
1018   return IPC_OK();
1019 }
1020 
CloneDocumentTreeIntoSelf(const MaybeDiscarded<BrowsingContext> & aSourceBC,const embedding::PrintData & aPrintData)1021 nsresult BrowserChild::CloneDocumentTreeIntoSelf(
1022     const MaybeDiscarded<BrowsingContext>& aSourceBC,
1023     const embedding::PrintData& aPrintData) {
1024 #ifdef NS_PRINTING
1025   if (NS_WARN_IF(aSourceBC.IsNullOrDiscarded())) {
1026     return NS_ERROR_FAILURE;
1027   }
1028   nsCOMPtr<Document> sourceDocument = aSourceBC.get()->GetDocument();
1029   if (NS_WARN_IF(!sourceDocument)) {
1030     return NS_ERROR_FAILURE;
1031   }
1032 
1033   nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
1034   if (NS_WARN_IF(!ourDocShell)) {
1035     return NS_ERROR_FAILURE;
1036   }
1037 
1038   nsCOMPtr<nsIContentViewer> cv;
1039   ourDocShell->GetContentViewer(getter_AddRefs(cv));
1040   if (NS_WARN_IF(!cv)) {
1041     return NS_ERROR_FAILURE;
1042   }
1043 
1044   nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
1045       do_GetService("@mozilla.org/gfx/printsettings-service;1");
1046   if (NS_WARN_IF(!printSettingsSvc)) {
1047     return NS_ERROR_FAILURE;
1048   }
1049 
1050   nsCOMPtr<nsIPrintSettings> printSettings;
1051   nsresult rv =
1052       printSettingsSvc->GetNewPrintSettings(getter_AddRefs(printSettings));
1053   if (NS_WARN_IF(NS_FAILED(rv))) {
1054     return rv;
1055   }
1056 
1057   printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
1058 
1059   RefPtr<Document> clone;
1060   {
1061     AutoPrintEventDispatcher dispatcher(*sourceDocument);
1062     nsAutoScriptBlocker scriptBlocker;
1063     bool hasInProcessCallbacks = false;
1064     clone = sourceDocument->CreateStaticClone(ourDocShell, cv, printSettings,
1065                                               &hasInProcessCallbacks);
1066     if (NS_WARN_IF(!clone)) {
1067       return NS_ERROR_FAILURE;
1068     }
1069   }
1070 
1071   rv = UpdateRemotePrintSettings(aPrintData);
1072   if (NS_FAILED(rv)) {
1073     return rv;
1074   }
1075 
1076 #endif
1077   return NS_OK;
1078 }
1079 
RecvCloneDocumentTreeIntoSelf(const MaybeDiscarded<BrowsingContext> & aSourceBC,const embedding::PrintData & aPrintData,CloneDocumentTreeIntoSelfResolver && aResolve)1080 mozilla::ipc::IPCResult BrowserChild::RecvCloneDocumentTreeIntoSelf(
1081     const MaybeDiscarded<BrowsingContext>& aSourceBC,
1082     const embedding::PrintData& aPrintData,
1083     CloneDocumentTreeIntoSelfResolver&& aResolve) {
1084   nsresult rv = NS_OK;
1085 
1086 #ifdef NS_PRINTING
1087   rv = CloneDocumentTreeIntoSelf(aSourceBC, aPrintData);
1088 #endif
1089 
1090   aResolve(NS_SUCCEEDED(rv));
1091   return IPC_OK();
1092 }
1093 
UpdateRemotePrintSettings(const embedding::PrintData & aPrintData)1094 nsresult BrowserChild::UpdateRemotePrintSettings(
1095     const embedding::PrintData& aPrintData) {
1096 #ifdef NS_PRINTING
1097   nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
1098   if (NS_WARN_IF(!ourDocShell)) {
1099     return NS_ERROR_FAILURE;
1100   }
1101 
1102   RefPtr<Document> doc = ourDocShell->GetExtantDocument();
1103   if (NS_WARN_IF(!doc) || NS_WARN_IF(!doc->IsStaticDocument())) {
1104     return NS_ERROR_FAILURE;
1105   }
1106 
1107   RefPtr<BrowsingContext> bc = ourDocShell->GetBrowsingContext();
1108   if (NS_WARN_IF(!bc)) {
1109     return NS_ERROR_FAILURE;
1110   }
1111 
1112   nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
1113       do_GetService("@mozilla.org/gfx/printsettings-service;1");
1114   if (NS_WARN_IF(!printSettingsSvc)) {
1115     return NS_ERROR_FAILURE;
1116   }
1117 
1118   nsCOMPtr<nsIPrintSettings> printSettings;
1119   nsresult rv =
1120       printSettingsSvc->GetNewPrintSettings(getter_AddRefs(printSettings));
1121   if (NS_WARN_IF(NS_FAILED(rv))) {
1122     return rv;
1123   }
1124 
1125   printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
1126 
1127   bc->PreOrderWalk([&](BrowsingContext* aBc) {
1128     if (nsCOMPtr<nsIDocShell> inProcess = aBc->GetDocShell()) {
1129       nsCOMPtr<nsIContentViewer> cv;
1130       inProcess->GetContentViewer(getter_AddRefs(cv));
1131       if (NS_WARN_IF(!cv)) {
1132         return BrowsingContext::WalkFlag::Skip;
1133       }
1134       // The CanRunScript analysis is not smart enough to see across
1135       // the std::function PreOrderWalk uses, so we cheat a bit here, but it is
1136       // fine because PreOrderWalk does deal with arbitrary script changing the
1137       // BC tree, and our code above is simple enough and keeps strong refs to
1138       // everything.
1139       ([&]() MOZ_CAN_RUN_SCRIPT_BOUNDARY {
1140         cv->SetPrintSettingsForSubdocument(printSettings);
1141       }());
1142     } else if (RefPtr<BrowserBridgeChild> remoteChild =
1143                    BrowserBridgeChild::GetFrom(aBc->GetEmbedderElement())) {
1144       Unused << remoteChild->SendUpdateRemotePrintSettings(aPrintData);
1145       return BrowsingContext::WalkFlag::Skip;
1146     }
1147     return BrowsingContext::WalkFlag::Next;
1148   });
1149 #endif
1150 
1151   return NS_OK;
1152 }
1153 
RecvUpdateRemotePrintSettings(const embedding::PrintData & aPrintData)1154 mozilla::ipc::IPCResult BrowserChild::RecvUpdateRemotePrintSettings(
1155     const embedding::PrintData& aPrintData) {
1156 #ifdef NS_PRINTING
1157   UpdateRemotePrintSettings(aPrintData);
1158 #endif
1159 
1160   return IPC_OK();
1161 }
1162 
DoFakeShow(const ParentShowInfo & aParentShowInfo)1163 void BrowserChild::DoFakeShow(const ParentShowInfo& aParentShowInfo) {
1164   OwnerShowInfo ownerInfo{ScreenIntSize(), ScrollbarPreference::Auto,
1165                           nsSizeMode_Normal};
1166   RecvShow(aParentShowInfo, ownerInfo);
1167   mDidFakeShow = true;
1168 }
1169 
ApplyParentShowInfo(const ParentShowInfo & aInfo)1170 void BrowserChild::ApplyParentShowInfo(const ParentShowInfo& aInfo) {
1171   // Even if we already set real show info, the dpi / rounding & scale may still
1172   // be invalid (if BrowserParent wasn't able to get widget it would just send
1173   // 0). So better to always set up-to-date values here.
1174   if (aInfo.dpi() > 0) {
1175     mPuppetWidget->UpdateBackingScaleCache(aInfo.dpi(), aInfo.widgetRounding(),
1176                                            aInfo.defaultScale());
1177   }
1178 
1179   if (mDidSetRealShowInfo) {
1180     return;
1181   }
1182 
1183   if (!aInfo.fakeShowInfo()) {
1184     // Once we've got one ShowInfo from parent, no need to update the values
1185     // anymore.
1186     mDidSetRealShowInfo = true;
1187   }
1188 
1189   mIsTransparent = aInfo.isTransparent();
1190 }
1191 
RecvShow(const ParentShowInfo & aParentInfo,const OwnerShowInfo & aOwnerInfo)1192 mozilla::ipc::IPCResult BrowserChild::RecvShow(
1193     const ParentShowInfo& aParentInfo, const OwnerShowInfo& aOwnerInfo) {
1194   bool res = true;
1195 
1196   mPuppetWidget->SetSizeMode(aOwnerInfo.sizeMode());
1197   if (!mDidFakeShow) {
1198     nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
1199     if (!baseWindow) {
1200       NS_ERROR("WebNavigation() doesn't QI to nsIBaseWindow");
1201       return IPC_FAIL_NO_REASON(this);
1202     }
1203 
1204     baseWindow->SetVisibility(true);
1205     res = InitBrowserChildMessageManager();
1206   }
1207 
1208   ApplyParentShowInfo(aParentInfo);
1209 
1210   if (!mIsTopLevel) {
1211     RecvScrollbarPreferenceChanged(aOwnerInfo.scrollbarPreference());
1212   }
1213 
1214   if (!res) {
1215     return IPC_FAIL_NO_REASON(this);
1216   }
1217 
1218   UpdateVisibility();
1219 
1220   return IPC_OK();
1221 }
1222 
RecvInitRendering(const TextureFactoryIdentifier & aTextureFactoryIdentifier,const layers::LayersId & aLayersId,const CompositorOptions & aCompositorOptions,const bool & aLayersConnected)1223 mozilla::ipc::IPCResult BrowserChild::RecvInitRendering(
1224     const TextureFactoryIdentifier& aTextureFactoryIdentifier,
1225     const layers::LayersId& aLayersId,
1226     const CompositorOptions& aCompositorOptions, const bool& aLayersConnected) {
1227   mLayersConnected = Some(aLayersConnected);
1228   InitRenderingState(aTextureFactoryIdentifier, aLayersId, aCompositorOptions);
1229   return IPC_OK();
1230 }
1231 
RecvScrollbarPreferenceChanged(ScrollbarPreference aPreference)1232 mozilla::ipc::IPCResult BrowserChild::RecvScrollbarPreferenceChanged(
1233     ScrollbarPreference aPreference) {
1234   MOZ_ASSERT(!mIsTopLevel,
1235              "Scrollbar visibility should be derived from chrome flags for "
1236              "top-level windows");
1237   if (nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation())) {
1238     nsDocShell::Cast(docShell)->SetScrollbarPreference(aPreference);
1239   }
1240   return IPC_OK();
1241 }
1242 
RecvCompositorOptionsChanged(const CompositorOptions & aNewOptions)1243 mozilla::ipc::IPCResult BrowserChild::RecvCompositorOptionsChanged(
1244     const CompositorOptions& aNewOptions) {
1245   MOZ_ASSERT(mCompositorOptions);
1246 
1247   // The only compositor option we currently support changing is APZ
1248   // enablement. Even that is only partially supported for now:
1249   //   * Going from APZ to non-APZ is fine - we just flip the stored flag.
1250   //     Note that we keep the actors (mApzcTreeManager, and the APZChild
1251   //     created in InitAPZState()) around (read on for why).
1252   //   * Going from non-APZ to APZ is only supported if we were using
1253   //     APZ initially (at InitRendering() time) and we are transitioning
1254   //     back. In this case, we just reuse the actors which we kept around.
1255   //     Fully supporting a non-APZ to APZ transition (i.e. even in cases
1256   //     where we initialized as non-APZ) would require setting up the actors
1257   //     here. (In that case, we would also have the options of destroying
1258   //     the actors in the APZ --> non-APZ case, and always re-creating them
1259   //     during a non-APZ --> APZ transition).
1260   mCompositorOptions->SetUseAPZ(aNewOptions.UseAPZ());
1261   return IPC_OK();
1262 }
1263 
RecvUpdateDimensions(const DimensionInfo & aDimensionInfo)1264 mozilla::ipc::IPCResult BrowserChild::RecvUpdateDimensions(
1265     const DimensionInfo& aDimensionInfo) {
1266   if (mLayersConnected.isNothing()) {
1267     return IPC_OK();
1268   }
1269 
1270   mUnscaledOuterRect = aDimensionInfo.rect();
1271   mClientOffset = aDimensionInfo.clientOffset();
1272   mChromeOffset = aDimensionInfo.chromeOffset();
1273   MOZ_ASSERT_IF(!IsTopLevel(), mChromeOffset == LayoutDeviceIntPoint());
1274 
1275   SetUnscaledInnerSize(aDimensionInfo.size());
1276   if (!mHasValidInnerSize && aDimensionInfo.size().width != 0 &&
1277       aDimensionInfo.size().height != 0) {
1278     mHasValidInnerSize = true;
1279   }
1280 
1281   ScreenIntSize screenSize = GetInnerSize();
1282   ScreenIntRect screenRect = GetOuterRect();
1283 
1284   // Make sure to set the size on the document viewer first.  The
1285   // MobileViewportManager needs the content viewer size to be updated before
1286   // the reflow, otherwise it gets a stale size when it computes a new CSS
1287   // viewport.
1288   nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
1289   baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height,
1290                               nsIBaseWindow::eRepaint);
1291 
1292   mPuppetWidget->Resize(screenRect.x + mClientOffset.x + mChromeOffset.x,
1293                         screenRect.y + mClientOffset.y + mChromeOffset.y,
1294                         screenSize.width, screenSize.height, true);
1295 
1296   RecvSafeAreaInsetsChanged(mPuppetWidget->GetSafeAreaInsets());
1297 
1298   return IPC_OK();
1299 }
1300 
RecvSizeModeChanged(const nsSizeMode & aSizeMode)1301 mozilla::ipc::IPCResult BrowserChild::RecvSizeModeChanged(
1302     const nsSizeMode& aSizeMode) {
1303   mPuppetWidget->SetSizeMode(aSizeMode);
1304   if (!mPuppetWidget->IsVisible()) {
1305     return IPC_OK();
1306   }
1307   nsCOMPtr<Document> document(GetTopLevelDocument());
1308   if (!document) {
1309     return IPC_OK();
1310   }
1311   nsPresContext* presContext = document->GetPresContext();
1312   if (presContext) {
1313     presContext->SizeModeChanged(aSizeMode);
1314   }
1315   return IPC_OK();
1316 }
1317 
RecvChildToParentMatrix(const Maybe<gfx::Matrix4x4> & aMatrix,const ScreenRect & aTopLevelViewportVisibleRectInBrowserCoords)1318 mozilla::ipc::IPCResult BrowserChild::RecvChildToParentMatrix(
1319     const Maybe<gfx::Matrix4x4>& aMatrix,
1320     const ScreenRect& aTopLevelViewportVisibleRectInBrowserCoords) {
1321   mChildToParentConversionMatrix =
1322       LayoutDeviceToLayoutDeviceMatrix4x4::FromUnknownMatrix(aMatrix);
1323   mTopLevelViewportVisibleRectInBrowserCoords =
1324       aTopLevelViewportVisibleRectInBrowserCoords;
1325 
1326   // Trigger an intersection observation update since ancestor viewports
1327   // changed.
1328   if (RefPtr<Document> toplevelDoc = GetTopLevelDocument()) {
1329     if (nsPresContext* pc = toplevelDoc->GetPresContext()) {
1330       pc->RefreshDriver()->EnsureIntersectionObservationsUpdateHappens();
1331     }
1332   }
1333 
1334   return IPC_OK();
1335 }
1336 
RecvSetIsUnderHiddenEmbedderElement(const bool & aIsUnderHiddenEmbedderElement)1337 mozilla::ipc::IPCResult BrowserChild::RecvSetIsUnderHiddenEmbedderElement(
1338     const bool& aIsUnderHiddenEmbedderElement) {
1339   if (RefPtr<PresShell> presShell = GetTopLevelPresShell()) {
1340     presShell->SetIsUnderHiddenEmbedderElement(aIsUnderHiddenEmbedderElement);
1341   }
1342   return IPC_OK();
1343 }
1344 
RecvDynamicToolbarMaxHeightChanged(const ScreenIntCoord & aHeight)1345 mozilla::ipc::IPCResult BrowserChild::RecvDynamicToolbarMaxHeightChanged(
1346     const ScreenIntCoord& aHeight) {
1347 #if defined(MOZ_WIDGET_ANDROID)
1348   mDynamicToolbarMaxHeight = aHeight;
1349 
1350   RefPtr<Document> document = GetTopLevelDocument();
1351   if (!document) {
1352     return IPC_OK();
1353   }
1354 
1355   if (RefPtr<nsPresContext> presContext = document->GetPresContext()) {
1356     presContext->SetDynamicToolbarMaxHeight(aHeight);
1357   }
1358 #endif
1359   return IPC_OK();
1360 }
1361 
RecvDynamicToolbarOffsetChanged(const ScreenIntCoord & aOffset)1362 mozilla::ipc::IPCResult BrowserChild::RecvDynamicToolbarOffsetChanged(
1363     const ScreenIntCoord& aOffset) {
1364 #if defined(MOZ_WIDGET_ANDROID)
1365   RefPtr<Document> document = GetTopLevelDocument();
1366   if (!document) {
1367     return IPC_OK();
1368   }
1369 
1370   if (nsPresContext* presContext = document->GetPresContext()) {
1371     presContext->UpdateDynamicToolbarOffset(aOffset);
1372   }
1373 #endif
1374   return IPC_OK();
1375 }
1376 
RecvSuppressDisplayport(const bool & aEnabled)1377 mozilla::ipc::IPCResult BrowserChild::RecvSuppressDisplayport(
1378     const bool& aEnabled) {
1379   if (RefPtr<PresShell> presShell = GetTopLevelPresShell()) {
1380     presShell->SuppressDisplayport(aEnabled);
1381   }
1382   return IPC_OK();
1383 }
1384 
HandleDoubleTap(const CSSPoint & aPoint,const Modifiers & aModifiers,const ScrollableLayerGuid & aGuid)1385 void BrowserChild::HandleDoubleTap(const CSSPoint& aPoint,
1386                                    const Modifiers& aModifiers,
1387                                    const ScrollableLayerGuid& aGuid) {
1388   MOZ_LOG(
1389       sApzChildLog, LogLevel::Debug,
1390       ("Handling double tap at %s with %p %p\n", ToString(aPoint).c_str(),
1391        mBrowserChildMessageManager ? mBrowserChildMessageManager->GetWrapper()
1392                                    : nullptr,
1393        mBrowserChildMessageManager.get()));
1394 
1395   if (!mBrowserChildMessageManager) {
1396     return;
1397   }
1398 
1399   // Note: there is nothing to do with the modifiers here, as we are not
1400   // synthesizing any sort of mouse event.
1401   RefPtr<Document> document = GetTopLevelDocument();
1402   ZoomTarget zoomTarget = CalculateRectToZoomTo(document, aPoint);
1403   // The double-tap can be dispatched by any scroll frame (so |aGuid| could be
1404   // the guid of any scroll frame), but the zoom-to-rect operation must be
1405   // performed by the root content scroll frame, so query its identifiers
1406   // for the SendZoomToRect() call rather than using the ones from |aGuid|.
1407   uint32_t presShellId;
1408   ViewID viewId;
1409   if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(
1410           document->GetDocumentElement(), &presShellId, &viewId) &&
1411       mApzcTreeManager) {
1412     ScrollableLayerGuid guid(mLayersId, presShellId, viewId);
1413 
1414     mApzcTreeManager->ZoomToRect(guid, zoomTarget,
1415                                  ZoomToRectBehavior::DEFAULT_BEHAVIOR);
1416   }
1417 }
1418 
RecvHandleTap(const GeckoContentController::TapType & aType,const LayoutDevicePoint & aPoint,const Modifiers & aModifiers,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1419 mozilla::ipc::IPCResult BrowserChild::RecvHandleTap(
1420     const GeckoContentController::TapType& aType,
1421     const LayoutDevicePoint& aPoint, const Modifiers& aModifiers,
1422     const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId) {
1423   // IPDL doesn't hold a strong reference to protocols as they're not required
1424   // to be refcounted. This function can run script, which may trigger a nested
1425   // event loop, which may release this, so we hold a strong reference here.
1426   RefPtr<BrowserChild> kungFuDeathGrip(this);
1427   RefPtr<PresShell> presShell = GetTopLevelPresShell();
1428   if (!presShell) {
1429     return IPC_OK();
1430   }
1431   if (!presShell->GetPresContext()) {
1432     return IPC_OK();
1433   }
1434   CSSToLayoutDeviceScale scale(
1435       presShell->GetPresContext()->CSSToDevPixelScale());
1436   CSSPoint point = aPoint / scale;
1437 
1438   // Stash the guid in InputAPZContext so that when the visual-to-layout
1439   // transform is applied to the event's coordinates, we use the right transform
1440   // based on the scroll frame being targeted.
1441   // The other values don't really matter.
1442   InputAPZContext context(aGuid, aInputBlockId, nsEventStatus_eSentinel);
1443 
1444   switch (aType) {
1445     case GeckoContentController::TapType::eSingleTap:
1446       if (mBrowserChildMessageManager) {
1447         mAPZEventState->ProcessSingleTap(point, scale, aModifiers, 1);
1448       }
1449       break;
1450     case GeckoContentController::TapType::eDoubleTap:
1451       HandleDoubleTap(point, aModifiers, aGuid);
1452       break;
1453     case GeckoContentController::TapType::eSecondTap:
1454       if (mBrowserChildMessageManager) {
1455         mAPZEventState->ProcessSingleTap(point, scale, aModifiers, 2);
1456       }
1457       break;
1458     case GeckoContentController::TapType::eLongTap:
1459       if (mBrowserChildMessageManager) {
1460         RefPtr<APZEventState> eventState(mAPZEventState);
1461         eventState->ProcessLongTap(presShell, point, scale, aModifiers,
1462                                    aInputBlockId);
1463       }
1464       break;
1465     case GeckoContentController::TapType::eLongTapUp:
1466       if (mBrowserChildMessageManager) {
1467         RefPtr<APZEventState> eventState(mAPZEventState);
1468         eventState->ProcessLongTapUp(presShell, point, scale, aModifiers);
1469       }
1470       break;
1471   }
1472   return IPC_OK();
1473 }
1474 
RecvNormalPriorityHandleTap(const GeckoContentController::TapType & aType,const LayoutDevicePoint & aPoint,const Modifiers & aModifiers,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1475 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityHandleTap(
1476     const GeckoContentController::TapType& aType,
1477     const LayoutDevicePoint& aPoint, const Modifiers& aModifiers,
1478     const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId) {
1479   // IPDL doesn't hold a strong reference to protocols as they're not required
1480   // to be refcounted. This function can run script, which may trigger a nested
1481   // event loop, which may release this, so we hold a strong reference here.
1482   RefPtr<BrowserChild> kungFuDeathGrip(this);
1483   return RecvHandleTap(aType, aPoint, aModifiers, aGuid, aInputBlockId);
1484 }
1485 
NotifyAPZStateChange(const ViewID & aViewId,const layers::GeckoContentController::APZStateChange & aChange,const int & aArg)1486 bool BrowserChild::NotifyAPZStateChange(
1487     const ViewID& aViewId,
1488     const layers::GeckoContentController::APZStateChange& aChange,
1489     const int& aArg) {
1490   mAPZEventState->ProcessAPZStateChange(aViewId, aChange, aArg);
1491   if (aChange ==
1492       layers::GeckoContentController::APZStateChange::eTransformEnd) {
1493     // This is used by tests to determine when the APZ is done doing whatever
1494     // it's doing. XXX generify this as needed when writing additional tests.
1495     nsCOMPtr<nsIObserverService> observerService =
1496         mozilla::services::GetObserverService();
1497     observerService->NotifyObservers(nullptr, "APZ:TransformEnd", nullptr);
1498   }
1499   return true;
1500 }
1501 
StartScrollbarDrag(const layers::AsyncDragMetrics & aDragMetrics)1502 void BrowserChild::StartScrollbarDrag(
1503     const layers::AsyncDragMetrics& aDragMetrics) {
1504   ScrollableLayerGuid guid(mLayersId, aDragMetrics.mPresShellId,
1505                            aDragMetrics.mViewId);
1506 
1507   if (mApzcTreeManager) {
1508     mApzcTreeManager->StartScrollbarDrag(guid, aDragMetrics);
1509   }
1510 }
1511 
ZoomToRect(const uint32_t & aPresShellId,const ScrollableLayerGuid::ViewID & aViewId,const CSSRect & aRect,const uint32_t & aFlags)1512 void BrowserChild::ZoomToRect(const uint32_t& aPresShellId,
1513                               const ScrollableLayerGuid::ViewID& aViewId,
1514                               const CSSRect& aRect, const uint32_t& aFlags) {
1515   ScrollableLayerGuid guid(mLayersId, aPresShellId, aViewId);
1516 
1517   if (mApzcTreeManager) {
1518     mApzcTreeManager->ZoomToRect(guid, ZoomTarget{aRect}, aFlags);
1519   }
1520 }
1521 
RecvActivate(uint64_t aActionId)1522 mozilla::ipc::IPCResult BrowserChild::RecvActivate(uint64_t aActionId) {
1523   MOZ_ASSERT(mWebBrowser);
1524   mWebBrowser->FocusActivate(aActionId);
1525   return IPC_OK();
1526 }
1527 
RecvDeactivate(uint64_t aActionId)1528 mozilla::ipc::IPCResult BrowserChild::RecvDeactivate(uint64_t aActionId) {
1529   MOZ_ASSERT(mWebBrowser);
1530   mWebBrowser->FocusDeactivate(aActionId);
1531   return IPC_OK();
1532 }
1533 
RecvSetKeyboardIndicators(const UIStateChangeType & aShowFocusRings)1534 mozilla::ipc::IPCResult BrowserChild::RecvSetKeyboardIndicators(
1535     const UIStateChangeType& aShowFocusRings) {
1536   nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
1537   NS_ENSURE_TRUE(window, IPC_OK());
1538   window->SetKeyboardIndicators(aShowFocusRings);
1539   return IPC_OK();
1540 }
1541 
RecvStopIMEStateManagement()1542 mozilla::ipc::IPCResult BrowserChild::RecvStopIMEStateManagement() {
1543   IMEStateManager::StopIMEStateManagement();
1544   return IPC_OK();
1545 }
1546 
ProcessPendingCoalescedTouchData()1547 void BrowserChild::ProcessPendingCoalescedTouchData() {
1548   MOZ_ASSERT(StaticPrefs::dom_events_coalesce_touchmove());
1549 
1550   if (mCoalescedTouchData.IsEmpty()) {
1551     return;
1552   }
1553 
1554   if (mCoalescedTouchMoveEventFlusher) {
1555     mCoalescedTouchMoveEventFlusher->RemoveObserver();
1556   }
1557 
1558   UniquePtr<WidgetTouchEvent> touchMoveEvent =
1559       mCoalescedTouchData.TakeCoalescedEvent();
1560   Unused << RecvRealTouchEvent(*touchMoveEvent,
1561                                mCoalescedTouchData.GetScrollableLayerGuid(),
1562                                mCoalescedTouchData.GetInputBlockId(),
1563                                mCoalescedTouchData.GetApzResponse());
1564 }
1565 
ProcessPendingCoalescedMouseDataAndDispatchEvents()1566 void BrowserChild::ProcessPendingCoalescedMouseDataAndDispatchEvents() {
1567   if (!mCoalesceMouseMoveEvents || !mCoalescedMouseEventFlusher) {
1568     // We don't enable mouse coalescing or we are destroying BrowserChild.
1569     return;
1570   }
1571 
1572   // We may reentry the event loop and push more data to
1573   // mToBeDispatchedMouseData while dispatching an event.
1574 
1575   // We may have some pending coalesced data while dispatch an event and reentry
1576   // the event loop. In that case we don't have chance to consume the remainding
1577   // pending data until we get new mouse events. Get some helps from
1578   // mCoalescedMouseEventFlusher to trigger it.
1579   mCoalescedMouseEventFlusher->StartObserver();
1580 
1581   while (mToBeDispatchedMouseData.GetSize() > 0) {
1582     UniquePtr<CoalescedMouseData> data(
1583         static_cast<CoalescedMouseData*>(mToBeDispatchedMouseData.PopFront()));
1584 
1585     UniquePtr<WidgetMouseEvent> event = data->TakeCoalescedEvent();
1586     if (event) {
1587       // Dispatch the pending events. Using HandleRealMouseButtonEvent
1588       // to bypass the coalesce handling in RecvRealMouseMoveEvent. Can't use
1589       // RecvRealMouseButtonEvent because we may also put some mouse events
1590       // other than mousemove.
1591       HandleRealMouseButtonEvent(*event, data->GetScrollableLayerGuid(),
1592                                  data->GetInputBlockId());
1593     }
1594   }
1595   // mCoalescedMouseEventFlusher may be destroyed when reentrying the event
1596   // loop.
1597   if (mCoalescedMouseEventFlusher) {
1598     mCoalescedMouseEventFlusher->RemoveObserver();
1599   }
1600 }
1601 
1602 LayoutDeviceToLayoutDeviceMatrix4x4
GetChildToParentConversionMatrix() const1603 BrowserChild::GetChildToParentConversionMatrix() const {
1604   if (mChildToParentConversionMatrix) {
1605     return *mChildToParentConversionMatrix;
1606   }
1607   LayoutDevicePoint offset(GetChromeOffset());
1608   return LayoutDeviceToLayoutDeviceMatrix4x4::Translation(offset);
1609 }
1610 
GetTopLevelViewportVisibleRectInBrowserCoords() const1611 Maybe<ScreenRect> BrowserChild::GetTopLevelViewportVisibleRectInBrowserCoords()
1612     const {
1613   if (!mChildToParentConversionMatrix) {
1614     return Nothing();
1615   }
1616   return Some(mTopLevelViewportVisibleRectInBrowserCoords);
1617 }
1618 
FlushAllCoalescedMouseData()1619 void BrowserChild::FlushAllCoalescedMouseData() {
1620   MOZ_ASSERT(mCoalesceMouseMoveEvents);
1621 
1622   // Move all entries from mCoalescedMouseData to mToBeDispatchedMouseData.
1623   for (const auto& data : mCoalescedMouseData.Values()) {
1624     if (!data || data->IsEmpty()) {
1625       continue;
1626     }
1627     UniquePtr<CoalescedMouseData> dispatchData =
1628         MakeUnique<CoalescedMouseData>();
1629 
1630     dispatchData->RetrieveDataFrom(*data);
1631     mToBeDispatchedMouseData.Push(dispatchData.release());
1632   }
1633   mCoalescedMouseData.Clear();
1634 }
1635 
RecvRealMouseMoveEvent(const WidgetMouseEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1636 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseMoveEvent(
1637     const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1638     const uint64_t& aInputBlockId) {
1639   if (mCoalesceMouseMoveEvents && mCoalescedMouseEventFlusher) {
1640     CoalescedMouseData* data =
1641         mCoalescedMouseData.GetOrInsertNew(aEvent.pointerId);
1642     MOZ_ASSERT(data);
1643     if (data->CanCoalesce(aEvent, aGuid, aInputBlockId)) {
1644       data->Coalesce(aEvent, aGuid, aInputBlockId);
1645       mCoalescedMouseEventFlusher->StartObserver();
1646       return IPC_OK();
1647     }
1648     // Can't coalesce current mousemove event. Put the coalesced mousemove data
1649     // with the same pointer id to mToBeDispatchedMouseData, coalesce the
1650     // current one, and process all pending data in mToBeDispatchedMouseData.
1651     UniquePtr<CoalescedMouseData> dispatchData =
1652         MakeUnique<CoalescedMouseData>();
1653 
1654     dispatchData->RetrieveDataFrom(*data);
1655     mToBeDispatchedMouseData.Push(dispatchData.release());
1656 
1657     // Put new data to replace the old one in the hash table.
1658     CoalescedMouseData* newData =
1659         mCoalescedMouseData
1660             .InsertOrUpdate(aEvent.pointerId, MakeUnique<CoalescedMouseData>())
1661             .get();
1662     newData->Coalesce(aEvent, aGuid, aInputBlockId);
1663 
1664     // Dispatch all pending mouse events.
1665     ProcessPendingCoalescedMouseDataAndDispatchEvents();
1666     mCoalescedMouseEventFlusher->StartObserver();
1667   } else if (!RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId)) {
1668     return IPC_FAIL_NO_REASON(this);
1669   }
1670   return IPC_OK();
1671 }
1672 
RecvRealMouseMoveEventForTests(const WidgetMouseEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1673 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseMoveEventForTests(
1674     const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1675     const uint64_t& aInputBlockId) {
1676   return RecvRealMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1677 }
1678 
RecvNormalPriorityRealMouseMoveEvent(const WidgetMouseEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1679 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseMoveEvent(
1680     const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1681     const uint64_t& aInputBlockId) {
1682   return RecvRealMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1683 }
1684 
1685 mozilla::ipc::IPCResult
RecvNormalPriorityRealMouseMoveEventForTests(const WidgetMouseEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1686 BrowserChild::RecvNormalPriorityRealMouseMoveEventForTests(
1687     const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1688     const uint64_t& aInputBlockId) {
1689   return RecvRealMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1690 }
1691 
RecvSynthMouseMoveEvent(const WidgetMouseEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1692 mozilla::ipc::IPCResult BrowserChild::RecvSynthMouseMoveEvent(
1693     const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1694     const uint64_t& aInputBlockId) {
1695   if (!RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId)) {
1696     return IPC_FAIL_NO_REASON(this);
1697   }
1698   return IPC_OK();
1699 }
1700 
RecvNormalPrioritySynthMouseMoveEvent(const WidgetMouseEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1701 mozilla::ipc::IPCResult BrowserChild::RecvNormalPrioritySynthMouseMoveEvent(
1702     const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1703     const uint64_t& aInputBlockId) {
1704   return RecvSynthMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1705 }
1706 
RecvRealMouseButtonEvent(const WidgetMouseEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1707 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseButtonEvent(
1708     const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1709     const uint64_t& aInputBlockId) {
1710   if (mCoalesceMouseMoveEvents && mCoalescedMouseEventFlusher &&
1711       aEvent.mMessage != eMouseMove) {
1712     // When receiving a mouse event other than mousemove, we have to dispatch
1713     // all coalesced events before it. However, we can't dispatch all pending
1714     // coalesced events directly because we may reentry the event loop while
1715     // dispatching. To make sure we won't dispatch disorder events, we move all
1716     // coalesced mousemove events and current event to a deque to dispatch them.
1717     // When reentrying the event loop and dispatching more events, we put new
1718     // events in the end of the nsQueue and dispatch events from the beginning.
1719     FlushAllCoalescedMouseData();
1720 
1721     UniquePtr<CoalescedMouseData> dispatchData =
1722         MakeUnique<CoalescedMouseData>();
1723 
1724     dispatchData->Coalesce(aEvent, aGuid, aInputBlockId);
1725     mToBeDispatchedMouseData.Push(dispatchData.release());
1726 
1727     ProcessPendingCoalescedMouseDataAndDispatchEvents();
1728     return IPC_OK();
1729   }
1730   HandleRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1731   return IPC_OK();
1732 }
1733 
HandleRealMouseButtonEvent(const WidgetMouseEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1734 void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
1735                                               const ScrollableLayerGuid& aGuid,
1736                                               const uint64_t& aInputBlockId) {
1737   WidgetMouseEvent localEvent(aEvent);
1738   localEvent.mWidget = mPuppetWidget;
1739 
1740   // We need one InputAPZContext here to propagate |aGuid| to places in
1741   // SendSetTargetAPZCNotification() which apply the visual-to-layout transform,
1742   // and another below to propagate the |postLayerization| flag (whose value
1743   // we don't know until SendSetTargetAPZCNotification() returns) into
1744   // the event dispatch code.
1745   InputAPZContext context1(aGuid, aInputBlockId, nsEventStatus_eSentinel);
1746 
1747   // Mouse events like eMouseEnterIntoWidget, that are created in the parent
1748   // process EventStateManager code, have an input block id which they get from
1749   // the InputAPZContext in the parent process stack. However, they did not
1750   // actually go through the APZ code and so their mHandledByAPZ flag is false.
1751   // Since thos events didn't go through APZ, we don't need to send
1752   // notifications for them.
1753   RefPtr<DisplayportSetListener> postLayerization;
1754   if (aInputBlockId && localEvent.mFlags.mHandledByAPZ) {
1755     nsCOMPtr<Document> document(GetTopLevelDocument());
1756     postLayerization = APZCCallbackHelper::SendSetTargetAPZCNotification(
1757         mPuppetWidget, document, localEvent, aGuid.mLayersId, aInputBlockId);
1758   }
1759 
1760   InputAPZContext context2(aGuid, aInputBlockId, nsEventStatus_eSentinel,
1761                            postLayerization != nullptr);
1762 
1763   DispatchWidgetEventViaAPZ(localEvent);
1764 
1765   if (aInputBlockId && localEvent.mFlags.mHandledByAPZ) {
1766     mAPZEventState->ProcessMouseEvent(localEvent, aInputBlockId);
1767   }
1768 
1769   // Do this after the DispatchWidgetEventViaAPZ call above, so that if the
1770   // mouse event triggered a post-refresh AsyncDragMetrics message to be sent
1771   // to APZ (from scrollbar dragging in nsSliderFrame), then that will reach
1772   // APZ before the SetTargetAPZC message. This ensures the drag input block
1773   // gets the drag metrics before handling the input events.
1774   if (postLayerization) {
1775     postLayerization->Register();
1776   }
1777 }
1778 
RecvNormalPriorityRealMouseButtonEvent(const WidgetMouseEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1779 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseButtonEvent(
1780     const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1781     const uint64_t& aInputBlockId) {
1782   return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1783 }
1784 
RecvRealMouseEnterExitWidgetEvent(const WidgetMouseEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1785 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseEnterExitWidgetEvent(
1786     const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1787     const uint64_t& aInputBlockId) {
1788   return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1789 }
1790 
1791 mozilla::ipc::IPCResult
RecvNormalPriorityRealMouseEnterExitWidgetEvent(const WidgetMouseEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1792 BrowserChild::RecvNormalPriorityRealMouseEnterExitWidgetEvent(
1793     const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1794     const uint64_t& aInputBlockId) {
1795   return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1796 }
1797 
DispatchWidgetEventViaAPZ(WidgetGUIEvent & aEvent)1798 nsEventStatus BrowserChild::DispatchWidgetEventViaAPZ(WidgetGUIEvent& aEvent) {
1799   aEvent.ResetWaitingReplyFromRemoteProcessState();
1800   return APZCCallbackHelper::DispatchWidgetEvent(aEvent);
1801 }
1802 
DispatchCoalescedWheelEvent()1803 void BrowserChild::DispatchCoalescedWheelEvent() {
1804   UniquePtr<WidgetWheelEvent> wheelEvent =
1805       mCoalescedWheelData.TakeCoalescedEvent();
1806   MOZ_ASSERT(wheelEvent);
1807   DispatchWheelEvent(*wheelEvent, mCoalescedWheelData.GetScrollableLayerGuid(),
1808                      mCoalescedWheelData.GetInputBlockId());
1809 }
1810 
DispatchWheelEvent(const WidgetWheelEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1811 void BrowserChild::DispatchWheelEvent(const WidgetWheelEvent& aEvent,
1812                                       const ScrollableLayerGuid& aGuid,
1813                                       const uint64_t& aInputBlockId) {
1814   WidgetWheelEvent localEvent(aEvent);
1815   if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) {
1816     nsCOMPtr<Document> document(GetTopLevelDocument());
1817     RefPtr<DisplayportSetListener> postLayerization =
1818         APZCCallbackHelper::SendSetTargetAPZCNotification(
1819             mPuppetWidget, document, aEvent, aGuid.mLayersId, aInputBlockId);
1820     if (postLayerization) {
1821       postLayerization->Register();
1822     }
1823   }
1824 
1825   localEvent.mWidget = mPuppetWidget;
1826 
1827   // Stash the guid in InputAPZContext so that when the visual-to-layout
1828   // transform is applied to the event's coordinates, we use the right transform
1829   // based on the scroll frame being targeted.
1830   // The other values don't really matter.
1831   InputAPZContext context(aGuid, aInputBlockId, nsEventStatus_eSentinel);
1832 
1833   DispatchWidgetEventViaAPZ(localEvent);
1834 
1835   if (localEvent.mCanTriggerSwipe) {
1836     SendRespondStartSwipeEvent(aInputBlockId, localEvent.TriggersSwipe());
1837   }
1838 
1839   if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) {
1840     mAPZEventState->ProcessWheelEvent(localEvent, aInputBlockId);
1841   }
1842 }
1843 
RecvMouseWheelEvent(const WidgetWheelEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1844 mozilla::ipc::IPCResult BrowserChild::RecvMouseWheelEvent(
1845     const WidgetWheelEvent& aEvent, const ScrollableLayerGuid& aGuid,
1846     const uint64_t& aInputBlockId) {
1847   bool isNextWheelEvent = false;
1848   // We only coalesce the current event when
1849   // 1. It's eWheel (we don't coalesce eOperationStart and eWheelOperationEnd)
1850   // 2. It has same attributes as the coalesced wheel event which is not yet
1851   //    fired.
1852   if (aEvent.mMessage == eWheel) {
1853     GetIPCChannel()->PeekMessages(
1854         [&isNextWheelEvent](const IPC::Message& aMsg) -> bool {
1855           if (aMsg.type() == mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID) {
1856             isNextWheelEvent = true;
1857           }
1858           return false;  // Stop peeking.
1859         });
1860 
1861     if (!mCoalescedWheelData.IsEmpty() &&
1862         !mCoalescedWheelData.CanCoalesce(aEvent, aGuid, aInputBlockId)) {
1863       DispatchCoalescedWheelEvent();
1864       MOZ_ASSERT(mCoalescedWheelData.IsEmpty());
1865     }
1866     mCoalescedWheelData.Coalesce(aEvent, aGuid, aInputBlockId);
1867 
1868     MOZ_ASSERT(!mCoalescedWheelData.IsEmpty());
1869     // If the next event isn't a wheel event, make sure we dispatch.
1870     if (!isNextWheelEvent) {
1871       DispatchCoalescedWheelEvent();
1872     }
1873   } else {
1874     DispatchWheelEvent(aEvent, aGuid, aInputBlockId);
1875   }
1876 
1877   return IPC_OK();
1878 }
1879 
RecvNormalPriorityMouseWheelEvent(const WidgetWheelEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId)1880 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityMouseWheelEvent(
1881     const WidgetWheelEvent& aEvent, const ScrollableLayerGuid& aGuid,
1882     const uint64_t& aInputBlockId) {
1883   return RecvMouseWheelEvent(aEvent, aGuid, aInputBlockId);
1884 }
1885 
RecvRealTouchEvent(const WidgetTouchEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId,const nsEventStatus & aApzResponse)1886 mozilla::ipc::IPCResult BrowserChild::RecvRealTouchEvent(
1887     const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
1888     const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) {
1889   MOZ_LOG(sApzChildLog, LogLevel::Debug,
1890           ("Receiving touch event of type %d\n", aEvent.mMessage));
1891 
1892   if (StaticPrefs::dom_events_coalesce_touchmove()) {
1893     if (aEvent.mMessage == eTouchEnd || aEvent.mMessage == eTouchStart) {
1894       ProcessPendingCoalescedTouchData();
1895     }
1896 
1897     if (aEvent.mMessage != eTouchMove) {
1898       sConsecutiveTouchMoveCount = 0;
1899     }
1900   }
1901 
1902   WidgetTouchEvent localEvent(aEvent);
1903   localEvent.mWidget = mPuppetWidget;
1904 
1905   // Stash the guid in InputAPZContext so that when the visual-to-layout
1906   // transform is applied to the event's coordinates, we use the right transform
1907   // based on the scroll frame being targeted.
1908   // The other values don't really matter.
1909   InputAPZContext context(aGuid, aInputBlockId, aApzResponse);
1910 
1911   nsTArray<TouchBehaviorFlags> allowedTouchBehaviors;
1912   if (localEvent.mMessage == eTouchStart && AsyncPanZoomEnabled()) {
1913     nsCOMPtr<Document> document = GetTopLevelDocument();
1914     allowedTouchBehaviors = TouchActionHelper::GetAllowedTouchBehavior(
1915         mPuppetWidget, document, localEvent);
1916     if (!allowedTouchBehaviors.IsEmpty() && mApzcTreeManager) {
1917       mApzcTreeManager->SetAllowedTouchBehavior(aInputBlockId,
1918                                                 allowedTouchBehaviors);
1919     }
1920     RefPtr<DisplayportSetListener> postLayerization =
1921         APZCCallbackHelper::SendSetTargetAPZCNotification(
1922             mPuppetWidget, document, localEvent, aGuid.mLayersId,
1923             aInputBlockId);
1924     if (postLayerization) {
1925       postLayerization->Register();
1926     }
1927   }
1928 
1929   // Dispatch event to content (potentially a long-running operation)
1930   nsEventStatus status = DispatchWidgetEventViaAPZ(localEvent);
1931 
1932   if (!AsyncPanZoomEnabled()) {
1933     // We shouldn't have any e10s platforms that have touch events enabled
1934     // without APZ.
1935     MOZ_ASSERT(false);
1936     return IPC_OK();
1937   }
1938 
1939   mAPZEventState->ProcessTouchEvent(localEvent, aGuid, aInputBlockId,
1940                                     aApzResponse, status,
1941                                     std::move(allowedTouchBehaviors));
1942   return IPC_OK();
1943 }
1944 
RecvNormalPriorityRealTouchEvent(const WidgetTouchEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId,const nsEventStatus & aApzResponse)1945 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealTouchEvent(
1946     const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
1947     const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) {
1948   return RecvRealTouchEvent(aEvent, aGuid, aInputBlockId, aApzResponse);
1949 }
1950 
RecvRealTouchMoveEvent(const WidgetTouchEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId,const nsEventStatus & aApzResponse)1951 mozilla::ipc::IPCResult BrowserChild::RecvRealTouchMoveEvent(
1952     const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
1953     const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) {
1954   if (StaticPrefs::dom_events_coalesce_touchmove()) {
1955     ++sConsecutiveTouchMoveCount;
1956     if (mCoalescedTouchMoveEventFlusher) {
1957       MOZ_ASSERT(aEvent.mMessage == eTouchMove);
1958       if (mCoalescedTouchData.IsEmpty() ||
1959           mCoalescedTouchData.CanCoalesce(aEvent, aGuid, aInputBlockId,
1960                                           aApzResponse)) {
1961         mCoalescedTouchData.Coalesce(aEvent, aGuid, aInputBlockId,
1962                                      aApzResponse);
1963       } else {
1964         UniquePtr<WidgetTouchEvent> touchMoveEvent =
1965             mCoalescedTouchData.TakeCoalescedEvent();
1966 
1967         mCoalescedTouchData.Coalesce(aEvent, aGuid, aInputBlockId,
1968                                      aApzResponse);
1969 
1970         if (!RecvRealTouchEvent(*touchMoveEvent,
1971                                 mCoalescedTouchData.GetScrollableLayerGuid(),
1972                                 mCoalescedTouchData.GetInputBlockId(),
1973                                 mCoalescedTouchData.GetApzResponse())) {
1974           return IPC_FAIL_NO_REASON(this);
1975         }
1976       }
1977 
1978       if (sConsecutiveTouchMoveCount > 1) {
1979         mCoalescedTouchMoveEventFlusher->StartObserver();
1980       } else {
1981         // Flush the pending coalesced touch in order to avoid the first
1982         // touchmove be overridden by the second one.
1983         ProcessPendingCoalescedTouchData();
1984       }
1985       return IPC_OK();
1986     }
1987   }
1988 
1989   if (!RecvRealTouchEvent(aEvent, aGuid, aInputBlockId, aApzResponse)) {
1990     return IPC_FAIL_NO_REASON(this);
1991   }
1992   return IPC_OK();
1993 }
1994 
RecvNormalPriorityRealTouchMoveEvent(const WidgetTouchEvent & aEvent,const ScrollableLayerGuid & aGuid,const uint64_t & aInputBlockId,const nsEventStatus & aApzResponse)1995 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealTouchMoveEvent(
1996     const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
1997     const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) {
1998   return RecvRealTouchMoveEvent(aEvent, aGuid, aInputBlockId, aApzResponse);
1999 }
2000 
RecvRealDragEvent(const WidgetDragEvent & aEvent,const uint32_t & aDragAction,const uint32_t & aDropEffect,nsIPrincipal * aPrincipal,nsIContentSecurityPolicy * aCsp)2001 mozilla::ipc::IPCResult BrowserChild::RecvRealDragEvent(
2002     const WidgetDragEvent& aEvent, const uint32_t& aDragAction,
2003     const uint32_t& aDropEffect, nsIPrincipal* aPrincipal,
2004     nsIContentSecurityPolicy* aCsp) {
2005   WidgetDragEvent localEvent(aEvent);
2006   localEvent.mWidget = mPuppetWidget;
2007 
2008   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
2009   if (dragSession) {
2010     dragSession->SetDragAction(aDragAction);
2011     dragSession->SetTriggeringPrincipal(aPrincipal);
2012     dragSession->SetCsp(aCsp);
2013     RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
2014     if (initialDataTransfer) {
2015       initialDataTransfer->SetDropEffectInt(aDropEffect);
2016     }
2017   }
2018 
2019   if (aEvent.mMessage == eDrop) {
2020     bool canDrop = true;
2021     if (!dragSession || NS_FAILED(dragSession->GetCanDrop(&canDrop)) ||
2022         !canDrop) {
2023       localEvent.mMessage = eDragExit;
2024     }
2025   } else if (aEvent.mMessage == eDragOver) {
2026     nsCOMPtr<nsIDragService> dragService =
2027         do_GetService("@mozilla.org/widget/dragservice;1");
2028     if (dragService) {
2029       // This will dispatch 'drag' event at the source if the
2030       // drag transaction started in this process.
2031       dragService->FireDragEventAtSource(eDrag, aEvent.mModifiers);
2032     }
2033   }
2034 
2035   DispatchWidgetEventViaAPZ(localEvent);
2036   return IPC_OK();
2037 }
2038 
RequestEditCommands(NativeKeyBindingsType aType,const WidgetKeyboardEvent & aEvent,nsTArray<CommandInt> & aCommands)2039 void BrowserChild::RequestEditCommands(NativeKeyBindingsType aType,
2040                                        const WidgetKeyboardEvent& aEvent,
2041                                        nsTArray<CommandInt>& aCommands) {
2042   MOZ_ASSERT(aCommands.IsEmpty());
2043 
2044   if (NS_WARN_IF(aEvent.IsEditCommandsInitialized(aType))) {
2045     aCommands = aEvent.EditCommandsConstRef(aType).Clone();
2046     return;
2047   }
2048 
2049   switch (aType) {
2050     case NativeKeyBindingsType::SingleLineEditor:
2051     case NativeKeyBindingsType::MultiLineEditor:
2052     case NativeKeyBindingsType::RichTextEditor:
2053       break;
2054     default:
2055       MOZ_ASSERT_UNREACHABLE("Invalid native key bindings type");
2056   }
2057 
2058   // Don't send aEvent to the parent process directly because it'll be marked
2059   // as posted to remote process.
2060   WidgetKeyboardEvent localEvent(aEvent);
2061   SendRequestNativeKeyBindings(static_cast<uint32_t>(aType), localEvent,
2062                                &aCommands);
2063 }
2064 
RecvNativeSynthesisResponse(const uint64_t & aObserverId,const nsCString & aResponse)2065 mozilla::ipc::IPCResult BrowserChild::RecvNativeSynthesisResponse(
2066     const uint64_t& aObserverId, const nsCString& aResponse) {
2067   mozilla::widget::AutoObserverNotifier::NotifySavedObserver(aObserverId,
2068                                                              aResponse.get());
2069   return IPC_OK();
2070 }
2071 
RecvUpdateEpoch(const uint32_t & aEpoch)2072 mozilla::ipc::IPCResult BrowserChild::RecvUpdateEpoch(const uint32_t& aEpoch) {
2073   if (mSessionStoreListener) {
2074     mSessionStoreListener->SetEpoch(aEpoch);
2075   }
2076   return IPC_OK();
2077 }
2078 
RecvUpdateSHistory()2079 mozilla::ipc::IPCResult BrowserChild::RecvUpdateSHistory() {
2080   if (mSessionStoreListener) {
2081     mSessionStoreListener->UpdateSHistoryChanges();
2082   }
2083   return IPC_OK();
2084 }
2085 
2086 // In case handling repeated keys takes much time, we skip firing new ones.
SkipRepeatedKeyEvent(const WidgetKeyboardEvent & aEvent)2087 bool BrowserChild::SkipRepeatedKeyEvent(const WidgetKeyboardEvent& aEvent) {
2088   if (mRepeatedKeyEventTime.IsNull() || !aEvent.CanSkipInRemoteProcess() ||
2089       (aEvent.mMessage != eKeyDown && aEvent.mMessage != eKeyPress)) {
2090     mRepeatedKeyEventTime = TimeStamp();
2091     mSkipKeyPress = false;
2092     return false;
2093   }
2094 
2095   if ((aEvent.mMessage == eKeyDown &&
2096        (mRepeatedKeyEventTime > aEvent.mTimeStamp)) ||
2097       (mSkipKeyPress && (aEvent.mMessage == eKeyPress))) {
2098     // If we skip a keydown event, also the following keypress events should be
2099     // skipped.
2100     mSkipKeyPress |= aEvent.mMessage == eKeyDown;
2101     return true;
2102   }
2103 
2104   if (aEvent.mMessage == eKeyDown) {
2105     // If keydown wasn't skipped, nor should the possible following keypress.
2106     mRepeatedKeyEventTime = TimeStamp();
2107     mSkipKeyPress = false;
2108   }
2109   return false;
2110 }
2111 
UpdateRepeatedKeyEventEndTime(const WidgetKeyboardEvent & aEvent)2112 void BrowserChild::UpdateRepeatedKeyEventEndTime(
2113     const WidgetKeyboardEvent& aEvent) {
2114   if (aEvent.mIsRepeat &&
2115       (aEvent.mMessage == eKeyDown || aEvent.mMessage == eKeyPress)) {
2116     mRepeatedKeyEventTime = TimeStamp::Now();
2117   }
2118 }
2119 
RecvRealKeyEvent(const WidgetKeyboardEvent & aEvent)2120 mozilla::ipc::IPCResult BrowserChild::RecvRealKeyEvent(
2121     const WidgetKeyboardEvent& aEvent) {
2122   if (SkipRepeatedKeyEvent(aEvent)) {
2123     return IPC_OK();
2124   }
2125 
2126   MOZ_ASSERT(
2127       aEvent.mMessage != eKeyPress || aEvent.AreAllEditCommandsInitialized(),
2128       "eKeyPress event should have native key binding information");
2129 
2130   // If content code called preventDefault() on a keydown event, then we don't
2131   // want to process any following keypress events.
2132   if (aEvent.mMessage == eKeyPress && mIgnoreKeyPressEvent) {
2133     return IPC_OK();
2134   }
2135 
2136   WidgetKeyboardEvent localEvent(aEvent);
2137   localEvent.mWidget = mPuppetWidget;
2138   localEvent.mUniqueId = aEvent.mUniqueId;
2139   nsEventStatus status = DispatchWidgetEventViaAPZ(localEvent);
2140 
2141   // Update the end time of the possible repeated event so that we can skip
2142   // some incoming events in case event handling took long time.
2143   UpdateRepeatedKeyEventEndTime(localEvent);
2144 
2145   if (aEvent.mMessage == eKeyDown) {
2146     mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
2147   }
2148 
2149   if (localEvent.mFlags.mIsSuppressedOrDelayed) {
2150     localEvent.PreventDefault();
2151   }
2152 
2153   // If a response is desired from the content process, resend the key event.
2154   if (aEvent.WantReplyFromContentProcess()) {
2155     // If the event's default isn't prevented but the status is no default,
2156     // That means that the event was consumed by EventStateManager or something
2157     // which is not a usual event handler.  In such case, prevent its default
2158     // as a default handler.  For example, when an eKeyPress event matches
2159     // with a content accesskey, and it's executed, peventDefault() of the
2160     // event won't be called but the status is set to "no default".  Then,
2161     // the event shouldn't be handled by nsMenuBarListener in the main process.
2162     if (!localEvent.DefaultPrevented() &&
2163         status == nsEventStatus_eConsumeNoDefault) {
2164       localEvent.PreventDefault();
2165     }
2166     // This is an ugly hack, mNoRemoteProcessDispatch is set to true when the
2167     // event's PreventDefault() or StopScrollProcessForwarding() is called.
2168     // And then, it'll be checked by ParamTraits<mozilla::WidgetEvent>::Write()
2169     // whether the event is being sent to remote process unexpectedly.
2170     // However, unfortunately, it cannot check the destination.  Therefore,
2171     // we need to clear the flag explicitly here because ParamTraits should
2172     // keep checking the flag for avoiding regression.
2173     localEvent.mFlags.mNoRemoteProcessDispatch = false;
2174     SendReplyKeyEvent(localEvent);
2175   }
2176 
2177   return IPC_OK();
2178 }
2179 
RecvNormalPriorityRealKeyEvent(const WidgetKeyboardEvent & aEvent)2180 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealKeyEvent(
2181     const WidgetKeyboardEvent& aEvent) {
2182   return RecvRealKeyEvent(aEvent);
2183 }
2184 
RecvCompositionEvent(const WidgetCompositionEvent & aEvent)2185 mozilla::ipc::IPCResult BrowserChild::RecvCompositionEvent(
2186     const WidgetCompositionEvent& aEvent) {
2187   WidgetCompositionEvent localEvent(aEvent);
2188   localEvent.mWidget = mPuppetWidget;
2189   DispatchWidgetEventViaAPZ(localEvent);
2190   Unused << SendOnEventNeedingAckHandled(aEvent.mMessage);
2191   return IPC_OK();
2192 }
2193 
RecvNormalPriorityCompositionEvent(const WidgetCompositionEvent & aEvent)2194 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityCompositionEvent(
2195     const WidgetCompositionEvent& aEvent) {
2196   return RecvCompositionEvent(aEvent);
2197 }
2198 
RecvSelectionEvent(const WidgetSelectionEvent & aEvent)2199 mozilla::ipc::IPCResult BrowserChild::RecvSelectionEvent(
2200     const WidgetSelectionEvent& aEvent) {
2201   WidgetSelectionEvent localEvent(aEvent);
2202   localEvent.mWidget = mPuppetWidget;
2203   DispatchWidgetEventViaAPZ(localEvent);
2204   Unused << SendOnEventNeedingAckHandled(aEvent.mMessage);
2205   return IPC_OK();
2206 }
2207 
RecvNormalPrioritySelectionEvent(const WidgetSelectionEvent & aEvent)2208 mozilla::ipc::IPCResult BrowserChild::RecvNormalPrioritySelectionEvent(
2209     const WidgetSelectionEvent& aEvent) {
2210   return RecvSelectionEvent(aEvent);
2211 }
2212 
RecvInsertText(const nsString & aStringToInsert)2213 mozilla::ipc::IPCResult BrowserChild::RecvInsertText(
2214     const nsString& aStringToInsert) {
2215   // Use normal event path to reach focused document.
2216   WidgetContentCommandEvent localEvent(true, eContentCommandInsertText,
2217                                        mPuppetWidget);
2218   localEvent.mString = Some(aStringToInsert);
2219   DispatchWidgetEventViaAPZ(localEvent);
2220   return IPC_OK();
2221 }
2222 
RecvNormalPriorityInsertText(const nsString & aStringToInsert)2223 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityInsertText(
2224     const nsString& aStringToInsert) {
2225   return RecvInsertText(aStringToInsert);
2226 }
2227 
RecvPasteTransferable(const IPCDataTransfer & aDataTransfer,const bool & aIsPrivateData,nsIPrincipal * aRequestingPrincipal,const nsContentPolicyType & aContentPolicyType)2228 mozilla::ipc::IPCResult BrowserChild::RecvPasteTransferable(
2229     const IPCDataTransfer& aDataTransfer, const bool& aIsPrivateData,
2230     nsIPrincipal* aRequestingPrincipal,
2231     const nsContentPolicyType& aContentPolicyType) {
2232   nsresult rv;
2233   nsCOMPtr<nsITransferable> trans =
2234       do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
2235   NS_ENSURE_SUCCESS(rv, IPC_OK());
2236   trans->Init(nullptr);
2237 
2238   rv = nsContentUtils::IPCTransferableToTransferable(
2239       aDataTransfer, aIsPrivateData, aRequestingPrincipal, aContentPolicyType,
2240       trans, nullptr, this);
2241   NS_ENSURE_SUCCESS(rv, IPC_OK());
2242 
2243   nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
2244   if (NS_WARN_IF(!ourDocShell)) {
2245     return IPC_OK();
2246   }
2247 
2248   RefPtr<nsCommandParams> params = new nsCommandParams();
2249   rv = params->SetISupports("transferable", trans);
2250   NS_ENSURE_SUCCESS(rv, IPC_OK());
2251 
2252   ourDocShell->DoCommandWithParams("cmd_pasteTransferable", params);
2253   return IPC_OK();
2254 }
2255 
2256 #ifdef ACCESSIBILITY
AllocPDocAccessibleChild(PDocAccessibleChild *,const uint64_t &,const uint32_t &,const IAccessibleHolder &)2257 a11y::PDocAccessibleChild* BrowserChild::AllocPDocAccessibleChild(
2258     PDocAccessibleChild*, const uint64_t&, const uint32_t&,
2259     const IAccessibleHolder&) {
2260   MOZ_ASSERT(false, "should never call this!");
2261   return nullptr;
2262 }
2263 
DeallocPDocAccessibleChild(a11y::PDocAccessibleChild * aChild)2264 bool BrowserChild::DeallocPDocAccessibleChild(
2265     a11y::PDocAccessibleChild* aChild) {
2266   delete static_cast<mozilla::a11y::DocAccessibleChild*>(aChild);
2267   return true;
2268 }
2269 #endif
2270 
AllocPColorPickerChild(const nsString &,const nsString &)2271 PColorPickerChild* BrowserChild::AllocPColorPickerChild(const nsString&,
2272                                                         const nsString&) {
2273   MOZ_CRASH("unused");
2274   return nullptr;
2275 }
2276 
DeallocPColorPickerChild(PColorPickerChild * aColorPicker)2277 bool BrowserChild::DeallocPColorPickerChild(PColorPickerChild* aColorPicker) {
2278   nsColorPickerProxy* picker = static_cast<nsColorPickerProxy*>(aColorPicker);
2279   NS_RELEASE(picker);
2280   return true;
2281 }
2282 
AllocPFilePickerChild(const nsString &,const int16_t &)2283 PFilePickerChild* BrowserChild::AllocPFilePickerChild(const nsString&,
2284                                                       const int16_t&) {
2285   MOZ_CRASH("unused");
2286   return nullptr;
2287 }
2288 
DeallocPFilePickerChild(PFilePickerChild * actor)2289 bool BrowserChild::DeallocPFilePickerChild(PFilePickerChild* actor) {
2290   nsFilePickerProxy* filePicker = static_cast<nsFilePickerProxy*>(actor);
2291   NS_RELEASE(filePicker);
2292   return true;
2293 }
2294 
GetVsyncChild()2295 RefPtr<VsyncMainChild> BrowserChild::GetVsyncChild() {
2296   // Initializing mVsyncChild here turns on per-BrowserChild Vsync for a
2297   // given platform. Note: this only makes sense if nsWindow returns a
2298   // window-specific VsyncSource.
2299 #if defined(MOZ_WAYLAND)
2300   if (IsWaylandEnabled() && !mVsyncChild) {
2301     mVsyncChild = MakeRefPtr<VsyncMainChild>();
2302     if (!SendPVsyncConstructor(mVsyncChild)) {
2303       mVsyncChild = nullptr;
2304     }
2305   }
2306 #endif
2307   return mVsyncChild;
2308 }
2309 
RecvActivateFrameEvent(const nsString & aType,const bool & capture)2310 mozilla::ipc::IPCResult BrowserChild::RecvActivateFrameEvent(
2311     const nsString& aType, const bool& capture) {
2312   nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
2313   NS_ENSURE_TRUE(window, IPC_OK());
2314   nsCOMPtr<EventTarget> chromeHandler = window->GetChromeEventHandler();
2315   NS_ENSURE_TRUE(chromeHandler, IPC_OK());
2316   RefPtr<ContentListener> listener = new ContentListener(this);
2317   chromeHandler->AddEventListener(aType, listener, capture);
2318   return IPC_OK();
2319 }
2320 
RecvLoadRemoteScript(const nsString & aURL,const bool & aRunInGlobalScope)2321 mozilla::ipc::IPCResult BrowserChild::RecvLoadRemoteScript(
2322     const nsString& aURL, const bool& aRunInGlobalScope) {
2323   if (!InitBrowserChildMessageManager())
2324     // This can happen if we're half-destroyed.  It's not a fatal
2325     // error.
2326     return IPC_OK();
2327 
2328   JS::Rooted<JSObject*> mm(RootingCx(),
2329                            mBrowserChildMessageManager->GetOrCreateWrapper());
2330   if (!mm) {
2331     // This can happen if we're half-destroyed.  It's not a fatal error.
2332     return IPC_OK();
2333   }
2334 
2335   LoadScriptInternal(mm, aURL, !aRunInGlobalScope);
2336   return IPC_OK();
2337 }
2338 
RecvAsyncMessage(const nsString & aMessage,const ClonedMessageData & aData)2339 mozilla::ipc::IPCResult BrowserChild::RecvAsyncMessage(
2340     const nsString& aMessage, const ClonedMessageData& aData) {
2341   AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("BrowserChild::RecvAsyncMessage",
2342                                              OTHER, aMessage);
2343   MMPrinter::Print("BrowserChild::RecvAsyncMessage", aMessage, aData);
2344 
2345   if (!mBrowserChildMessageManager) {
2346     return IPC_OK();
2347   }
2348 
2349   RefPtr<nsFrameMessageManager> mm =
2350       mBrowserChildMessageManager->GetMessageManager();
2351 
2352   // We should have a message manager if the global is alive, but it
2353   // seems sometimes we don't.  Assert in aurora/nightly, but don't
2354   // crash in release builds.
2355   MOZ_DIAGNOSTIC_ASSERT(mm);
2356   if (!mm) {
2357     return IPC_OK();
2358   }
2359 
2360   JS::Rooted<JSObject*> kungFuDeathGrip(
2361       dom::RootingCx(), mBrowserChildMessageManager->GetWrapper());
2362   StructuredCloneData data;
2363   UnpackClonedMessageDataForChild(aData, data);
2364   mm->ReceiveMessage(static_cast<EventTarget*>(mBrowserChildMessageManager),
2365                      nullptr, aMessage, false, &data, nullptr, IgnoreErrors());
2366   return IPC_OK();
2367 }
2368 
RecvSwappedWithOtherRemoteLoader(const IPCTabContext & aContext)2369 mozilla::ipc::IPCResult BrowserChild::RecvSwappedWithOtherRemoteLoader(
2370     const IPCTabContext& aContext) {
2371   nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
2372   if (NS_WARN_IF(!ourDocShell)) {
2373     return IPC_OK();
2374   }
2375 
2376   nsCOMPtr<nsPIDOMWindowOuter> ourWindow = ourDocShell->GetWindow();
2377   if (NS_WARN_IF(!ourWindow)) {
2378     return IPC_OK();
2379   }
2380 
2381   RefPtr<nsDocShell> docShell = static_cast<nsDocShell*>(ourDocShell.get());
2382 
2383   nsCOMPtr<EventTarget> ourEventTarget = nsGlobalWindowOuter::Cast(ourWindow);
2384 
2385   docShell->SetInFrameSwap(true);
2386 
2387   nsContentUtils::FirePageShowEventForFrameLoaderSwap(
2388       ourDocShell, ourEventTarget, false, true);
2389   nsContentUtils::FirePageHideEventForFrameLoaderSwap(ourDocShell,
2390                                                       ourEventTarget, true);
2391 
2392   // Owner content type may have changed, so store the possibly updated context
2393   // and notify others.
2394   MaybeInvalidTabContext maybeContext(aContext);
2395   if (!maybeContext.IsValid()) {
2396     NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
2397                              "the parent process. (%s)",
2398                              maybeContext.GetInvalidReason())
2399                  .get());
2400     MOZ_CRASH("Invalid TabContext received from the parent process.");
2401   }
2402 
2403   if (!UpdateTabContextAfterSwap(maybeContext.GetTabContext())) {
2404     MOZ_CRASH("Update to TabContext after swap was denied.");
2405   }
2406 
2407   // Ignore previous value of mTriedBrowserInit since owner content has changed.
2408   mTriedBrowserInit = true;
2409 
2410   nsContentUtils::FirePageShowEventForFrameLoaderSwap(
2411       ourDocShell, ourEventTarget, true, true);
2412 
2413   docShell->SetInFrameSwap(false);
2414 
2415   // This is needed to get visibility state right in cases when we swapped a
2416   // visible tab (foreground in visible window) with a non-visible tab.
2417   if (RefPtr<Document> doc = docShell->GetDocument()) {
2418     doc->UpdateVisibilityState();
2419   }
2420 
2421   return IPC_OK();
2422 }
2423 
RecvHandleAccessKey(const WidgetKeyboardEvent & aEvent,nsTArray<uint32_t> && aCharCodes)2424 mozilla::ipc::IPCResult BrowserChild::RecvHandleAccessKey(
2425     const WidgetKeyboardEvent& aEvent, nsTArray<uint32_t>&& aCharCodes) {
2426   nsCOMPtr<Document> document(GetTopLevelDocument());
2427   RefPtr<nsPresContext> pc = document->GetPresContext();
2428   if (pc) {
2429     if (!pc->EventStateManager()->HandleAccessKey(
2430             &(const_cast<WidgetKeyboardEvent&>(aEvent)), pc, aCharCodes)) {
2431       // If no accesskey was found, inform the parent so that accesskeys on
2432       // menus can be handled.
2433       WidgetKeyboardEvent localEvent(aEvent);
2434       localEvent.mWidget = mPuppetWidget;
2435       SendAccessKeyNotHandled(localEvent);
2436     }
2437   }
2438 
2439   return IPC_OK();
2440 }
2441 
RecvPrintPreview(const PrintData & aPrintData,const MaybeDiscardedBrowsingContext & aSourceBC,PrintPreviewResolver && aCallback)2442 mozilla::ipc::IPCResult BrowserChild::RecvPrintPreview(
2443     const PrintData& aPrintData, const MaybeDiscardedBrowsingContext& aSourceBC,
2444     PrintPreviewResolver&& aCallback) {
2445 #ifdef NS_PRINTING
2446   // If we didn't succeed in passing off ownership of aCallback, then something
2447   // went wrong.
2448   auto sendCallbackError = MakeScopeExit([&] {
2449     if (aCallback) {
2450       // signal error
2451       aCallback(PrintPreviewResultInfo(0, 0, false, false, false, {}));
2452     }
2453   });
2454 
2455   if (NS_WARN_IF(aSourceBC.IsDiscarded())) {
2456     return IPC_OK();
2457   }
2458 
2459   RefPtr<nsGlobalWindowOuter> sourceWindow;
2460   if (!aSourceBC.IsNull()) {
2461     sourceWindow = nsGlobalWindowOuter::Cast(aSourceBC.get()->GetDOMWindow());
2462     if (NS_WARN_IF(!sourceWindow)) {
2463       return IPC_OK();
2464     }
2465   } else {
2466     nsCOMPtr<nsPIDOMWindowOuter> ourWindow = do_GetInterface(WebNavigation());
2467     if (NS_WARN_IF(!ourWindow)) {
2468       return IPC_OK();
2469     }
2470     sourceWindow = nsGlobalWindowOuter::Cast(ourWindow);
2471   }
2472 
2473   RefPtr<nsIPrintSettings> printSettings;
2474   nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
2475       do_GetService("@mozilla.org/gfx/printsettings-service;1");
2476   if (NS_WARN_IF(!printSettingsSvc)) {
2477     return IPC_OK();
2478   }
2479   printSettingsSvc->GetNewPrintSettings(getter_AddRefs(printSettings));
2480   if (NS_WARN_IF(!printSettings)) {
2481     return IPC_OK();
2482   }
2483   printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
2484 
2485   nsCOMPtr<nsIDocShell> docShellToCloneInto;
2486   if (!aSourceBC.IsNull()) {
2487     docShellToCloneInto = do_GetInterface(WebNavigation());
2488     if (NS_WARN_IF(!docShellToCloneInto)) {
2489       return IPC_OK();
2490     }
2491   }
2492 
2493   sourceWindow->Print(printSettings,
2494                       /* aListener = */ nullptr, docShellToCloneInto,
2495                       nsGlobalWindowOuter::IsPreview::Yes,
2496                       nsGlobalWindowOuter::IsForWindowDotPrint::No,
2497                       std::move(aCallback), IgnoreErrors());
2498 #endif
2499   return IPC_OK();
2500 }
2501 
RecvExitPrintPreview()2502 mozilla::ipc::IPCResult BrowserChild::RecvExitPrintPreview() {
2503 #ifdef NS_PRINTING
2504   nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint =
2505       do_GetInterface(ToSupports(WebNavigation()));
2506   if (NS_WARN_IF(!webBrowserPrint)) {
2507     return IPC_OK();
2508   }
2509   webBrowserPrint->ExitPrintPreview();
2510 #endif
2511   return IPC_OK();
2512 }
2513 
RecvPrint(const MaybeDiscardedBrowsingContext & aBc,const PrintData & aPrintData)2514 mozilla::ipc::IPCResult BrowserChild::RecvPrint(
2515     const MaybeDiscardedBrowsingContext& aBc, const PrintData& aPrintData) {
2516 #ifdef NS_PRINTING
2517   if (NS_WARN_IF(aBc.IsNullOrDiscarded())) {
2518     return IPC_OK();
2519   }
2520   RefPtr<nsGlobalWindowOuter> outerWindow =
2521       nsGlobalWindowOuter::Cast(aBc.get()->GetDOMWindow());
2522   if (NS_WARN_IF(!outerWindow)) {
2523     return IPC_OK();
2524   }
2525 
2526   nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
2527       do_GetService("@mozilla.org/gfx/printsettings-service;1");
2528   if (NS_WARN_IF(!printSettingsSvc)) {
2529     return IPC_OK();
2530   }
2531 
2532   nsCOMPtr<nsIPrintSettings> printSettings;
2533   nsresult rv =
2534       printSettingsSvc->GetNewPrintSettings(getter_AddRefs(printSettings));
2535   if (NS_WARN_IF(NS_FAILED(rv))) {
2536     return IPC_OK();
2537   }
2538 
2539   nsCOMPtr<nsIPrintSession> printSession =
2540       do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv);
2541   if (NS_WARN_IF(NS_FAILED(rv))) {
2542     return IPC_OK();
2543   }
2544 
2545   printSettings->SetPrintSession(printSession);
2546   printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
2547   {
2548     IgnoredErrorResult rv;
2549     outerWindow->Print(printSettings,
2550                        /* aListener = */ nullptr,
2551                        /* aWindowToCloneInto = */ nullptr,
2552                        nsGlobalWindowOuter::IsPreview::No,
2553                        nsGlobalWindowOuter::IsForWindowDotPrint::No,
2554                        /* aPrintPreviewCallback = */ nullptr, rv);
2555     if (NS_WARN_IF(rv.Failed())) {
2556       return IPC_OK();
2557     }
2558   }
2559 #endif
2560   return IPC_OK();
2561 }
2562 
RecvUpdateNativeWindowHandle(const uintptr_t & aNewHandle)2563 mozilla::ipc::IPCResult BrowserChild::RecvUpdateNativeWindowHandle(
2564     const uintptr_t& aNewHandle) {
2565 #if defined(XP_WIN) && defined(ACCESSIBILITY)
2566   mNativeWindowHandle = aNewHandle;
2567   return IPC_OK();
2568 #else
2569   return IPC_FAIL_NO_REASON(this);
2570 #endif
2571 }
2572 
RecvDestroy()2573 mozilla::ipc::IPCResult BrowserChild::RecvDestroy() {
2574   MOZ_ASSERT(mDestroyed == false);
2575   mDestroyed = true;
2576 
2577   nsTArray<PContentPermissionRequestChild*> childArray =
2578       nsContentPermissionUtils::GetContentPermissionRequestChildById(
2579           GetTabId());
2580 
2581   // Need to close undeleted ContentPermissionRequestChilds before tab is
2582   // closed.
2583   for (auto& permissionRequestChild : childArray) {
2584     auto child = static_cast<RemotePermissionRequest*>(permissionRequestChild);
2585     child->Destroy();
2586   }
2587 
2588   if (mBrowserChildMessageManager) {
2589     // Message handlers are called from the event loop, so it better be safe to
2590     // run script.
2591     MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
2592     mBrowserChildMessageManager->DispatchTrustedEvent(u"unload"_ns);
2593   }
2594 
2595   nsCOMPtr<nsIObserverService> observerService =
2596       mozilla::services::GetObserverService();
2597 
2598   observerService->RemoveObserver(this, BEFORE_FIRST_PAINT);
2599 
2600   // XXX what other code in ~BrowserChild() should we be running here?
2601   DestroyWindow();
2602 
2603   // Bounce through the event loop once to allow any delayed teardown runnables
2604   // that were just generated to have a chance to run.
2605   nsCOMPtr<nsIRunnable> deleteRunnable = new DelayedDeleteRunnable(this);
2606   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(deleteRunnable));
2607 
2608   return IPC_OK();
2609 }
2610 
RecvRenderLayers(const bool & aEnabled,const layers::LayersObserverEpoch & aEpoch)2611 mozilla::ipc::IPCResult BrowserChild::RecvRenderLayers(
2612     const bool& aEnabled, const layers::LayersObserverEpoch& aEpoch) {
2613   if (mPendingDocShellBlockers > 0) {
2614     mPendingRenderLayersReceivedMessage = true;
2615     mPendingRenderLayers = aEnabled;
2616     mPendingLayersObserverEpoch = aEpoch;
2617     return IPC_OK();
2618   }
2619 
2620   // Since requests to change the rendering state come in from both the hang
2621   // monitor channel and the PContent channel, we have an ordering problem. This
2622   // code ensures that we respect the order in which the requests were made and
2623   // ignore stale requests.
2624   if (mLayersObserverEpoch >= aEpoch) {
2625     return IPC_OK();
2626   }
2627   mLayersObserverEpoch = aEpoch;
2628 
2629   auto clearPaintWhileInterruptingJS = MakeScopeExit([&] {
2630     // We might force a paint, or we might already have painted and this is a
2631     // no-op. In either case, once we exit this scope, we need to alert the
2632     // ProcessHangMonitor that we've finished responding to what might have
2633     // been a request to force paint. This is so that the BackgroundHangMonitor
2634     // for force painting can be made to wait again.
2635     if (aEnabled) {
2636       ProcessHangMonitor::ClearPaintWhileInterruptingJS(mLayersObserverEpoch);
2637     }
2638   });
2639 
2640   if (aEnabled) {
2641     ProcessHangMonitor::MaybeStartPaintWhileInterruptingJS();
2642   }
2643 
2644   if (mCompositorOptions) {
2645     MOZ_ASSERT(mPuppetWidget);
2646     RefPtr<WebRenderLayerManager> lm =
2647         mPuppetWidget->GetWindowRenderer()->AsWebRender();
2648     if (lm) {
2649       // We send the current layer observer epoch to the compositor so that
2650       // BrowserParent knows whether a layer update notification corresponds to
2651       // the latest RecvRenderLayers request that was made.
2652       lm->SetLayersObserverEpoch(mLayersObserverEpoch);
2653     }
2654   }
2655 
2656   mRenderLayers = aEnabled;
2657 
2658   if (aEnabled && IsVisible()) {
2659     // This request is a no-op.
2660     // In this case, we still want a MozLayerTreeReady notification to fire
2661     // in the parent (so that it knows that the child has updated its epoch).
2662     // PaintWhileInterruptingJSNoOp does that.
2663     if (IPCOpen()) {
2664       Unused << SendPaintWhileInterruptingJSNoOp(mLayersObserverEpoch);
2665     }
2666     return IPC_OK();
2667   }
2668 
2669   // FIXME(emilio): Probably / maybe this shouldn't be needed? See the comment
2670   // in MakeVisible(), having the two separate states is not great.
2671   UpdateVisibility();
2672 
2673   if (!aEnabled) {
2674     return IPC_OK();
2675   }
2676 
2677   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2678   if (!docShell) {
2679     return IPC_OK();
2680   }
2681 
2682   // We don't use BrowserChildBase::GetPresShell() here because that would
2683   // create a content viewer if one doesn't exist yet. Creating a content
2684   // viewer can cause JS to run, which we want to avoid.
2685   // nsIDocShell::GetPresShell returns null if no content viewer exists yet.
2686   RefPtr<PresShell> presShell = docShell->GetPresShell();
2687   if (!presShell) {
2688     return IPC_OK();
2689   }
2690 
2691   if (nsIFrame* root = presShell->GetRootFrame()) {
2692     root->SchedulePaint();
2693   }
2694 
2695   Telemetry::AutoTimer<Telemetry::TABCHILD_PAINT_TIME> timer;
2696   // If we need to repaint, let's do that right away. No sense waiting until
2697   // we get back to the event loop again. We suppress the display port so
2698   // that we only paint what's visible. This ensures that the tab we're
2699   // switching to paints as quickly as possible.
2700   presShell->SuppressDisplayport(true);
2701   if (nsContentUtils::IsSafeToRunScript()) {
2702     WebWidget()->PaintNowIfNeeded();
2703   } else {
2704     RefPtr<nsViewManager> vm = presShell->GetViewManager();
2705     if (nsView* view = vm->GetRootView()) {
2706       presShell->PaintAndRequestComposite(view, PaintFlags::None);
2707     }
2708   }
2709   presShell->SuppressDisplayport(false);
2710   return IPC_OK();
2711 }
2712 
RecvNavigateByKey(const bool & aForward,const bool & aForDocumentNavigation)2713 mozilla::ipc::IPCResult BrowserChild::RecvNavigateByKey(
2714     const bool& aForward, const bool& aForDocumentNavigation) {
2715   nsFocusManager* fm = nsFocusManager::GetFocusManager();
2716   if (!fm) {
2717     return IPC_OK();
2718   }
2719 
2720   RefPtr<Element> result;
2721   nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
2722 
2723   // Move to the first or last document.
2724   {
2725     uint32_t type =
2726         aForward
2727             ? (aForDocumentNavigation
2728                    ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FIRSTDOC)
2729                    : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_ROOT))
2730             : (aForDocumentNavigation
2731                    ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LASTDOC)
2732                    : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LAST));
2733     uint32_t flags = nsIFocusManager::FLAG_BYKEY;
2734     if (aForward || aForDocumentNavigation) {
2735       flags |= nsIFocusManager::FLAG_NOSCROLL;
2736     }
2737     fm->MoveFocus(window, nullptr, type, flags, getter_AddRefs(result));
2738   }
2739 
2740   // No valid root element was found, so move to the first focusable element.
2741   if (!result && aForward && !aForDocumentNavigation) {
2742     fm->MoveFocus(window, nullptr, nsIFocusManager::MOVEFOCUS_FIRST,
2743                   nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
2744   }
2745 
2746   SendRequestFocus(false, CallerType::System);
2747   return IPC_OK();
2748 }
2749 
InitBrowserChildMessageManager()2750 bool BrowserChild::InitBrowserChildMessageManager() {
2751   mShouldSendWebProgressEventsToParent = true;
2752 
2753   if (!mBrowserChildMessageManager) {
2754     nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
2755     NS_ENSURE_TRUE(window, false);
2756     nsCOMPtr<EventTarget> chromeHandler = window->GetChromeEventHandler();
2757     NS_ENSURE_TRUE(chromeHandler, false);
2758 
2759     RefPtr<BrowserChildMessageManager> scope = mBrowserChildMessageManager =
2760         new BrowserChildMessageManager(this);
2761 
2762     MOZ_ALWAYS_TRUE(nsMessageManagerScriptExecutor::Init());
2763 
2764     nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
2765     if (NS_WARN_IF(!root)) {
2766       mBrowserChildMessageManager = nullptr;
2767       return false;
2768     }
2769     root->SetParentTarget(scope);
2770   }
2771 
2772   if (!mTriedBrowserInit) {
2773     mTriedBrowserInit = true;
2774   }
2775 
2776   return true;
2777 }
2778 
InitRenderingState(const TextureFactoryIdentifier & aTextureFactoryIdentifier,const layers::LayersId & aLayersId,const CompositorOptions & aCompositorOptions)2779 void BrowserChild::InitRenderingState(
2780     const TextureFactoryIdentifier& aTextureFactoryIdentifier,
2781     const layers::LayersId& aLayersId,
2782     const CompositorOptions& aCompositorOptions) {
2783   mPuppetWidget->InitIMEState();
2784 
2785   MOZ_ASSERT(aLayersId.IsValid());
2786   mTextureFactoryIdentifier = aTextureFactoryIdentifier;
2787 
2788   // Pushing layers transactions directly to a separate
2789   // compositor context.
2790   PCompositorBridgeChild* compositorChild = CompositorBridgeChild::Get();
2791   if (!compositorChild) {
2792     mLayersConnected = Some(false);
2793     NS_WARNING("failed to get CompositorBridgeChild instance");
2794     return;
2795   }
2796 
2797   mCompositorOptions = Some(aCompositorOptions);
2798 
2799   if (aLayersId.IsValid()) {
2800     StaticMutexAutoLock lock(sBrowserChildrenMutex);
2801 
2802     if (!sBrowserChildren) {
2803       sBrowserChildren = new BrowserChildMap;
2804     }
2805     MOZ_ASSERT(!sBrowserChildren->Contains(uint64_t(aLayersId)));
2806     sBrowserChildren->InsertOrUpdate(uint64_t(aLayersId), this);
2807     mLayersId = aLayersId;
2808   }
2809 
2810   // Depending on timing, we might paint too early and fall back to basic
2811   // layers. CreateRemoteLayerManager will destroy us if we manage to get a
2812   // remote layer manager though, so that's fine.
2813   MOZ_ASSERT(!mPuppetWidget->HasWindowRenderer() ||
2814              mPuppetWidget->GetWindowRenderer()->GetBackendType() ==
2815                  layers::LayersBackend::LAYERS_NONE);
2816   bool success = false;
2817   if (mLayersConnected == Some(true)) {
2818     success = CreateRemoteLayerManager(compositorChild);
2819   }
2820 
2821   if (success) {
2822     MOZ_ASSERT(mLayersConnected == Some(true));
2823     // Succeeded to create "remote" layer manager
2824     ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
2825     gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
2826     InitAPZState();
2827     RefPtr<WebRenderLayerManager> lm =
2828         mPuppetWidget->GetWindowRenderer()->AsWebRender();
2829     if (lm) {
2830       lm->SetLayersObserverEpoch(mLayersObserverEpoch);
2831     }
2832   } else {
2833     NS_WARNING("Fallback to BasicLayerManager");
2834     mLayersConnected = Some(false);
2835   }
2836 
2837   nsCOMPtr<nsIObserverService> observerService =
2838       mozilla::services::GetObserverService();
2839 
2840   if (observerService) {
2841     observerService->AddObserver(this, BEFORE_FIRST_PAINT, false);
2842   }
2843 }
2844 
CreateRemoteLayerManager(mozilla::layers::PCompositorBridgeChild * aCompositorChild)2845 bool BrowserChild::CreateRemoteLayerManager(
2846     mozilla::layers::PCompositorBridgeChild* aCompositorChild) {
2847   MOZ_ASSERT(aCompositorChild);
2848 
2849   return mPuppetWidget->CreateRemoteLayerManager(
2850       [&](WebRenderLayerManager* aLayerManager) -> bool {
2851         nsCString error;
2852         return aLayerManager->Initialize(aCompositorChild,
2853                                          wr::AsPipelineId(mLayersId),
2854                                          &mTextureFactoryIdentifier, error);
2855       });
2856 }
2857 
InitAPZState()2858 void BrowserChild::InitAPZState() {
2859   if (!mCompositorOptions->UseAPZ()) {
2860     return;
2861   }
2862   auto cbc = CompositorBridgeChild::Get();
2863 
2864   // Initialize the ApzcTreeManager. This takes multiple casts because of ugly
2865   // multiple inheritance.
2866   PAPZCTreeManagerChild* baseProtocol =
2867       cbc->SendPAPZCTreeManagerConstructor(mLayersId);
2868   APZCTreeManagerChild* derivedProtocol =
2869       static_cast<APZCTreeManagerChild*>(baseProtocol);
2870 
2871   mApzcTreeManager = RefPtr<IAPZCTreeManager>(derivedProtocol);
2872 
2873   // Initialize the GeckoContentController for this tab. We don't hold a
2874   // reference because we don't need it. The ContentProcessController will hold
2875   // a reference to the tab, and will be destroyed by the compositor or ipdl
2876   // during destruction.
2877   RefPtr<GeckoContentController> contentController =
2878       new ContentProcessController(this);
2879   APZChild* apzChild = new APZChild(contentController);
2880   cbc->SendPAPZConstructor(apzChild, mLayersId);
2881 }
2882 
RecvUpdateEffects(const EffectsInfo & aEffects)2883 IPCResult BrowserChild::RecvUpdateEffects(const EffectsInfo& aEffects) {
2884   mDidSetEffectsInfo = true;
2885 
2886   bool needInvalidate = false;
2887   if (mEffectsInfo.IsVisible() && aEffects.IsVisible() &&
2888       mEffectsInfo != aEffects) {
2889     // if we are staying visible and either the visrect or scale changed we need
2890     // to invalidate
2891     needInvalidate = true;
2892   }
2893 
2894   mEffectsInfo = aEffects;
2895   UpdateVisibility();
2896 
2897   if (needInvalidate) {
2898     nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2899     if (docShell) {
2900       // We don't use BrowserChildBase::GetPresShell() here because that would
2901       // create a content viewer if one doesn't exist yet. Creating a content
2902       // viewer can cause JS to run, which we want to avoid.
2903       // nsIDocShell::GetPresShell returns null if no content viewer exists yet.
2904       RefPtr<PresShell> presShell = docShell->GetPresShell();
2905       if (presShell) {
2906         if (nsIFrame* root = presShell->GetRootFrame()) {
2907           root->InvalidateFrame();
2908         }
2909       }
2910     }
2911   }
2912 
2913   return IPC_OK();
2914 }
2915 
IsVisible()2916 bool BrowserChild::IsVisible() {
2917   return mPuppetWidget && mPuppetWidget->IsVisible();
2918 }
2919 
UpdateVisibility()2920 void BrowserChild::UpdateVisibility() {
2921   bool shouldBeVisible = mIsTopLevel ? mRenderLayers : mEffectsInfo.IsVisible();
2922   bool isVisible = IsVisible();
2923 
2924   if (shouldBeVisible != isVisible) {
2925     if (shouldBeVisible) {
2926       MakeVisible();
2927     } else {
2928       MakeHidden();
2929     }
2930   }
2931 }
2932 
MakeVisible()2933 void BrowserChild::MakeVisible() {
2934   if (IsVisible()) {
2935     return;
2936   }
2937 
2938   if (mPuppetWidget) {
2939     mPuppetWidget->Show(true);
2940   }
2941 
2942   PresShellActivenessMaybeChanged();
2943 }
2944 
MakeHidden()2945 void BrowserChild::MakeHidden() {
2946   if (!IsVisible()) {
2947     return;
2948   }
2949 
2950   // Due to the nested event loop in ContentChild::ProvideWindowCommon,
2951   // it's possible to be told to become hidden before we're finished
2952   // setting up a layer manager. We should skip clearing cached layers
2953   // in that case, since doing so might accidentally put is into
2954   // BasicLayers mode.
2955   if (mPuppetWidget) {
2956     if (mPuppetWidget->HasWindowRenderer()) {
2957       ClearCachedResources();
2958     }
2959     mPuppetWidget->Show(false);
2960   }
2961 
2962   PresShellActivenessMaybeChanged();
2963 }
2964 
RecvPreserveLayers(bool aPreserve)2965 IPCResult BrowserChild::RecvPreserveLayers(bool aPreserve) {
2966   mIsPreservingLayers = aPreserve;
2967 
2968   PresShellActivenessMaybeChanged();
2969 
2970   return IPC_OK();
2971 }
2972 
PresShellActivenessMaybeChanged()2973 void BrowserChild::PresShellActivenessMaybeChanged() {
2974   // We don't use BrowserChildBase::GetPresShell() here because that would
2975   // create a content viewer if one doesn't exist yet. Creating a content
2976   // viewer can cause JS to run, which we want to avoid.
2977   // nsIDocShell::GetPresShell returns null if no content viewer exists yet.
2978   //
2979   // When this method is called we don't want to go through the browsing context
2980   // because we don't want to change the visibility state of the document, which
2981   // has side effects like firing events to content, unblocking media playback,
2982   // unthrottling timeouts... PresShell activeness has a lot less side effects.
2983   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2984   if (!docShell) {
2985     return;
2986   }
2987   RefPtr<PresShell> presShell = docShell->GetPresShell();
2988   if (!presShell) {
2989     return;
2990   }
2991   presShell->ActivenessMaybeChanged();
2992 }
2993 
2994 NS_IMETHODIMP
GetMessageManager(ContentFrameMessageManager ** aResult)2995 BrowserChild::GetMessageManager(ContentFrameMessageManager** aResult) {
2996   RefPtr<ContentFrameMessageManager> mm(mBrowserChildMessageManager);
2997   mm.forget(aResult);
2998   return *aResult ? NS_OK : NS_ERROR_FAILURE;
2999 }
3000 
3001 already_AddRefed<nsITopLevelNavigationDelegate>
GetTopLevelNavigationDelegate()3002 BrowserChild::GetTopLevelNavigationDelegate() {
3003   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
3004   if (nsCOMPtr<nsITopLevelNavigationDelegate> delegate = do_QueryActor(
3005           "TopLevelNavigationDelegate", docShell->GetDocument())) {
3006     return delegate.forget();
3007   }
3008   return nullptr;
3009 }
3010 
SendRequestFocus(bool aCanFocus,CallerType aCallerType)3011 void BrowserChild::SendRequestFocus(bool aCanFocus, CallerType aCallerType) {
3012   nsFocusManager* fm = nsFocusManager::GetFocusManager();
3013   if (!fm) {
3014     return;
3015   }
3016 
3017   nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
3018   if (!window) {
3019     return;
3020   }
3021 
3022   BrowsingContext* focusedBC = fm->GetFocusedBrowsingContext();
3023   if (focusedBC == window->GetBrowsingContext()) {
3024     // BrowsingContext has the focus already, do not request again.
3025     return;
3026   }
3027 
3028   PBrowserChild::SendRequestFocus(aCanFocus, aCallerType);
3029 }
3030 
3031 NS_IMETHODIMP
GetTabId(uint64_t * aId)3032 BrowserChild::GetTabId(uint64_t* aId) {
3033   *aId = GetTabId();
3034   return NS_OK;
3035 }
3036 
3037 NS_IMETHODIMP
GetChromeOuterWindowID(uint64_t * aId)3038 BrowserChild::GetChromeOuterWindowID(uint64_t* aId) {
3039   *aId = ChromeOuterWindowID();
3040   return NS_OK;
3041 }
3042 
DoSendBlockingMessage(const nsAString & aMessage,StructuredCloneData & aData,nsTArray<StructuredCloneData> * aRetVal)3043 bool BrowserChild::DoSendBlockingMessage(
3044     const nsAString& aMessage, StructuredCloneData& aData,
3045     nsTArray<StructuredCloneData>* aRetVal) {
3046   ClonedMessageData data;
3047   if (!BuildClonedMessageDataForChild(Manager(), aData, data)) {
3048     return false;
3049   }
3050   return SendSyncMessage(PromiseFlatString(aMessage), data, aRetVal);
3051 }
3052 
DoSendAsyncMessage(const nsAString & aMessage,StructuredCloneData & aData)3053 nsresult BrowserChild::DoSendAsyncMessage(const nsAString& aMessage,
3054                                           StructuredCloneData& aData) {
3055   ClonedMessageData data;
3056   if (!BuildClonedMessageDataForChild(Manager(), aData, data)) {
3057     return NS_ERROR_DOM_DATA_CLONE_ERR;
3058   }
3059   if (!SendAsyncMessage(PromiseFlatString(aMessage), data)) {
3060     return NS_ERROR_UNEXPECTED;
3061   }
3062   return NS_OK;
3063 }
3064 
3065 /* static */
GetAll()3066 nsTArray<RefPtr<BrowserChild>> BrowserChild::GetAll() {
3067   StaticMutexAutoLock lock(sBrowserChildrenMutex);
3068 
3069   if (!sBrowserChildren) {
3070     return {};
3071   }
3072 
3073   return ToTArray<nsTArray<RefPtr<BrowserChild>>>(sBrowserChildren->Values());
3074 }
3075 
GetFrom(PresShell * aPresShell)3076 BrowserChild* BrowserChild::GetFrom(PresShell* aPresShell) {
3077   Document* doc = aPresShell->GetDocument();
3078   if (!doc) {
3079     return nullptr;
3080   }
3081   nsCOMPtr<nsIDocShell> docShell(doc->GetDocShell());
3082   return GetFrom(docShell);
3083 }
3084 
GetFrom(layers::LayersId aLayersId)3085 BrowserChild* BrowserChild::GetFrom(layers::LayersId aLayersId) {
3086   StaticMutexAutoLock lock(sBrowserChildrenMutex);
3087   if (!sBrowserChildren) {
3088     return nullptr;
3089   }
3090   return sBrowserChildren->Get(uint64_t(aLayersId));
3091 }
3092 
DidComposite(mozilla::layers::TransactionId aTransactionId,const TimeStamp & aCompositeStart,const TimeStamp & aCompositeEnd)3093 void BrowserChild::DidComposite(mozilla::layers::TransactionId aTransactionId,
3094                                 const TimeStamp& aCompositeStart,
3095                                 const TimeStamp& aCompositeEnd) {
3096   MOZ_ASSERT(mPuppetWidget);
3097   RefPtr<WebRenderLayerManager> lm =
3098       mPuppetWidget->GetWindowRenderer()->AsWebRender();
3099   MOZ_ASSERT(lm);
3100 
3101   if (lm) {
3102     lm->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
3103   }
3104 }
3105 
DidRequestComposite(const TimeStamp & aCompositeReqStart,const TimeStamp & aCompositeReqEnd)3106 void BrowserChild::DidRequestComposite(const TimeStamp& aCompositeReqStart,
3107                                        const TimeStamp& aCompositeReqEnd) {
3108   nsCOMPtr<nsIDocShell> docShellComPtr = do_GetInterface(WebNavigation());
3109   if (!docShellComPtr) {
3110     return;
3111   }
3112 
3113   nsDocShell* docShell = static_cast<nsDocShell*>(docShellComPtr.get());
3114   RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
3115 
3116   if (timelines && timelines->HasConsumer(docShell)) {
3117     // Since we're assuming that it's impossible for content JS to directly
3118     // trigger a synchronous paint, we can avoid capturing a stack trace here,
3119     // which means we won't run into JS engine reentrancy issues like bug
3120     // 1310014.
3121     timelines->AddMarkerForDocShell(
3122         docShell, "CompositeForwardTransaction", aCompositeReqStart,
3123         MarkerTracingType::START, MarkerStackRequest::NO_STACK);
3124     timelines->AddMarkerForDocShell(docShell, "CompositeForwardTransaction",
3125                                     aCompositeReqEnd, MarkerTracingType::END,
3126                                     MarkerStackRequest::NO_STACK);
3127   }
3128 }
3129 
ClearCachedResources()3130 void BrowserChild::ClearCachedResources() {
3131   MOZ_ASSERT(mPuppetWidget);
3132   RefPtr<WebRenderLayerManager> lm =
3133       mPuppetWidget->GetWindowRenderer()->AsWebRender();
3134   if (lm) {
3135     lm->ClearCachedResources();
3136   }
3137 
3138   if (nsCOMPtr<Document> document = GetTopLevelDocument()) {
3139     nsPresContext* presContext = document->GetPresContext();
3140     if (presContext) {
3141       presContext->NotifyPaintStatusReset();
3142     }
3143   }
3144 }
3145 
InvalidateLayers()3146 void BrowserChild::InvalidateLayers() { MOZ_ASSERT(mPuppetWidget); }
3147 
SchedulePaint()3148 void BrowserChild::SchedulePaint() {
3149   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
3150   if (!docShell) {
3151     return;
3152   }
3153 
3154   // We don't use BrowserChildBase::GetPresShell() here because that would
3155   // create a content viewer if one doesn't exist yet. Creating a content viewer
3156   // can cause JS to run, which we want to avoid. nsIDocShell::GetPresShell
3157   // returns null if no content viewer exists yet.
3158   if (RefPtr<PresShell> presShell = docShell->GetPresShell()) {
3159     if (nsIFrame* root = presShell->GetRootFrame()) {
3160       root->SchedulePaint();
3161     }
3162   }
3163 }
3164 
ReinitRendering()3165 void BrowserChild::ReinitRendering() {
3166   MOZ_ASSERT(mLayersId.IsValid());
3167 
3168   // In some cases, like when we create a windowless browser,
3169   // RemoteLayerTreeOwner/BrowserChild is not connected to a compositor.
3170   if (mLayersConnected.isNothing() || !*mLayersConnected) {
3171     return;
3172   }
3173 
3174   // Before we establish a new PLayerTransaction, we must connect our layer tree
3175   // id, CompositorBridge, and the widget compositor all together again.
3176   // Normally this happens in BrowserParent before BrowserChild is given
3177   // rendering information.
3178   //
3179   // In this case, we will send a sync message to our BrowserParent, which in
3180   // turn will send a sync message to the Compositor of the widget owning this
3181   // tab. This guarantees the correct association is in place before our
3182   // PLayerTransaction constructor message arrives on the cross-process
3183   // compositor bridge.
3184   CompositorOptions options;
3185   SendEnsureLayersConnected(&options);
3186   mCompositorOptions = Some(options);
3187 
3188   bool success = false;
3189   RefPtr<CompositorBridgeChild> cb = CompositorBridgeChild::Get();
3190 
3191   if (cb) {
3192     success = CreateRemoteLayerManager(cb);
3193   }
3194 
3195   if (!success) {
3196     NS_WARNING("failed to recreate layer manager");
3197     return;
3198   }
3199 
3200   mLayersConnected = Some(true);
3201   ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
3202   gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
3203 
3204   InitAPZState();
3205   RefPtr<WebRenderLayerManager> lm =
3206       mPuppetWidget->GetWindowRenderer()->AsWebRender();
3207   if (lm) {
3208     lm->SetLayersObserverEpoch(mLayersObserverEpoch);
3209   }
3210 
3211   nsCOMPtr<Document> doc(GetTopLevelDocument());
3212   doc->NotifyLayerManagerRecreated();
3213 
3214   if (mRenderLayers) {
3215     SchedulePaint();
3216   }
3217 }
3218 
ReinitRenderingForDeviceReset()3219 void BrowserChild::ReinitRenderingForDeviceReset() {
3220   InvalidateLayers();
3221 
3222   RefPtr<WebRenderLayerManager> lm =
3223       mPuppetWidget->GetWindowRenderer()->AsWebRender();
3224   if (lm) {
3225     lm->DoDestroy(/* aIsSync */ true);
3226   }
3227 
3228   // Proceed with destroying and recreating the layer manager.
3229   ReinitRendering();
3230 }
3231 
3232 NS_IMETHODIMP
OnShowTooltip(int32_t aXCoords,int32_t aYCoords,const nsAString & aTipText,const nsAString & aTipDir)3233 BrowserChild::OnShowTooltip(int32_t aXCoords, int32_t aYCoords,
3234                             const nsAString& aTipText,
3235                             const nsAString& aTipDir) {
3236   nsString str(aTipText);
3237   nsString dir(aTipDir);
3238   SendShowTooltip(aXCoords, aYCoords, str, dir);
3239   return NS_OK;
3240 }
3241 
3242 NS_IMETHODIMP
OnHideTooltip()3243 BrowserChild::OnHideTooltip() {
3244   SendHideTooltip();
3245   return NS_OK;
3246 }
3247 
NotifyJankedAnimations(const nsTArray<uint64_t> & aJankedAnimations)3248 void BrowserChild::NotifyJankedAnimations(
3249     const nsTArray<uint64_t>& aJankedAnimations) {
3250   MOZ_ASSERT(mPuppetWidget);
3251   RefPtr<WebRenderLayerManager> lm =
3252       mPuppetWidget->GetWindowRenderer()->AsWebRender();
3253   if (lm) {
3254     lm->UpdatePartialPrerenderedAnimations(aJankedAnimations);
3255   }
3256 }
3257 
RecvUIResolutionChanged(const float & aDpi,const int32_t & aRounding,const double & aScale)3258 mozilla::ipc::IPCResult BrowserChild::RecvUIResolutionChanged(
3259     const float& aDpi, const int32_t& aRounding, const double& aScale) {
3260   nsCOMPtr<Document> document(GetTopLevelDocument());
3261   if (!document) {
3262     return IPC_OK();
3263   }
3264 
3265   ScreenIntSize oldScreenSize = GetInnerSize();
3266   if (aDpi > 0) {
3267     mPuppetWidget->UpdateBackingScaleCache(aDpi, aRounding, aScale);
3268   }
3269   RefPtr<nsPresContext> presContext = document->GetPresContext();
3270   if (presContext) {
3271     presContext->UIResolutionChangedSync();
3272   }
3273 
3274   ScreenIntSize screenSize = GetInnerSize();
3275   if (mHasValidInnerSize && oldScreenSize != screenSize) {
3276     ScreenIntRect screenRect = GetOuterRect();
3277 
3278     // See RecvUpdateDimensions for the order of these operations.
3279     nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
3280     baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height,
3281                                 nsIBaseWindow::eRepaint);
3282 
3283     mPuppetWidget->Resize(screenRect.x + mClientOffset.x + mChromeOffset.x,
3284                           screenRect.y + mClientOffset.y + mChromeOffset.y,
3285                           screenSize.width, screenSize.height, true);
3286   }
3287 
3288   return IPC_OK();
3289 }
3290 
RecvSafeAreaInsetsChanged(const mozilla::ScreenIntMargin & aSafeAreaInsets)3291 mozilla::ipc::IPCResult BrowserChild::RecvSafeAreaInsetsChanged(
3292     const mozilla::ScreenIntMargin& aSafeAreaInsets) {
3293   mPuppetWidget->UpdateSafeAreaInsets(aSafeAreaInsets);
3294 
3295   nsCOMPtr<nsIScreenManager> screenMgr =
3296       do_GetService("@mozilla.org/gfx/screenmanager;1");
3297   ScreenIntMargin currentSafeAreaInsets;
3298   if (screenMgr) {
3299     // aSafeAreaInsets is for current screen. But we have to calculate
3300     // safe insets for content window.
3301     int32_t x, y, cx, cy;
3302     GetDimensions(0, &x, &y, &cx, &cy);
3303     nsCOMPtr<nsIScreen> screen;
3304     screenMgr->ScreenForRect(x, y, cx, cy, getter_AddRefs(screen));
3305 
3306     if (screen) {
3307       LayoutDeviceIntRect windowRect(x + mClientOffset.x + mChromeOffset.x,
3308                                      y + mClientOffset.y + mChromeOffset.y, cx,
3309                                      cy);
3310       currentSafeAreaInsets = nsContentUtils::GetWindowSafeAreaInsets(
3311           screen, aSafeAreaInsets, windowRect);
3312     }
3313   }
3314 
3315   if (nsCOMPtr<Document> document = GetTopLevelDocument()) {
3316     nsPresContext* presContext = document->GetPresContext();
3317     if (presContext) {
3318       presContext->SetSafeAreaInsets(currentSafeAreaInsets);
3319     }
3320   }
3321 
3322   // https://github.com/w3c/csswg-drafts/issues/4670
3323   // Actually we don't set this value on sub document. This behaviour is
3324   // same as Blink that safe area insets isn't set on sub document.
3325 
3326   return IPC_OK();
3327 }
3328 
RecvAllowScriptsToClose()3329 mozilla::ipc::IPCResult BrowserChild::RecvAllowScriptsToClose() {
3330   nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
3331   if (window) {
3332     nsGlobalWindowOuter::Cast(window)->AllowScriptsToClose();
3333   }
3334   return IPC_OK();
3335 }
3336 
RecvReleaseAllPointerCapture()3337 mozilla::ipc::IPCResult BrowserChild::RecvReleaseAllPointerCapture() {
3338   PointerEventHandler::ReleaseAllPointerCapture();
3339   return IPC_OK();
3340 }
3341 
AllocPPaymentRequestChild()3342 PPaymentRequestChild* BrowserChild::AllocPPaymentRequestChild() {
3343   MOZ_CRASH(
3344       "We should never be manually allocating PPaymentRequestChild actors");
3345   return nullptr;
3346 }
3347 
DeallocPPaymentRequestChild(PPaymentRequestChild * actor)3348 bool BrowserChild::DeallocPPaymentRequestChild(PPaymentRequestChild* actor) {
3349   delete actor;
3350   return true;
3351 }
3352 
GetInnerSize()3353 ScreenIntSize BrowserChild::GetInnerSize() {
3354   LayoutDeviceIntSize innerSize =
3355       RoundedToInt(mUnscaledInnerSize * mPuppetWidget->GetDefaultScale());
3356   return ViewAs<ScreenPixel>(
3357       innerSize, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
3358 };
3359 
GetVisibleRect() const3360 Maybe<nsRect> BrowserChild::GetVisibleRect() const {
3361   if (mIsTopLevel) {
3362     // We are conservative about visible rects for top-level browsers to avoid
3363     // artifacts when resizing
3364     return Nothing();
3365   }
3366 
3367   return mDidSetEffectsInfo ? Some(mEffectsInfo.mVisibleRect) : Nothing();
3368 }
3369 
3370 Maybe<LayoutDeviceRect>
GetTopLevelViewportVisibleRectInSelfCoords() const3371 BrowserChild::GetTopLevelViewportVisibleRectInSelfCoords() const {
3372   if (mIsTopLevel) {
3373     return Nothing();
3374   }
3375 
3376   if (!mChildToParentConversionMatrix) {
3377     // We have no way to tell this remote document visible rect right now.
3378     return Nothing();
3379   }
3380 
3381   Maybe<LayoutDeviceToLayoutDeviceMatrix4x4> inverse =
3382       mChildToParentConversionMatrix->MaybeInverse();
3383   if (!inverse) {
3384     return Nothing();
3385   }
3386 
3387   // Convert the remote document visible rect to the coordinate system of the
3388   // iframe document.
3389   Maybe<LayoutDeviceRect> rect = UntransformBy(
3390       *inverse,
3391       ViewAs<LayoutDevicePixel>(
3392           mTopLevelViewportVisibleRectInBrowserCoords,
3393           PixelCastJustification::ContentProcessIsLayerInUiProcess),
3394       LayoutDeviceRect::MaxIntRect());
3395   if (!rect) {
3396     return Nothing();
3397   }
3398 
3399   return rect;
3400 }
3401 
GetOuterRect()3402 ScreenIntRect BrowserChild::GetOuterRect() {
3403   LayoutDeviceIntRect outerRect =
3404       RoundedToInt(mUnscaledOuterRect * mPuppetWidget->GetDefaultScale());
3405   return ViewAs<ScreenPixel>(
3406       outerRect, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
3407 }
3408 
PaintWhileInterruptingJS(const layers::LayersObserverEpoch & aEpoch)3409 void BrowserChild::PaintWhileInterruptingJS(
3410     const layers::LayersObserverEpoch& aEpoch) {
3411   if (!IPCOpen() || !mPuppetWidget || !mPuppetWidget->HasWindowRenderer()) {
3412     // Don't bother doing anything now. Better to wait until we receive the
3413     // message on the PContent channel.
3414     return;
3415   }
3416 
3417   MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::IsSafeToRunScript());
3418   nsAutoScriptBlocker scriptBlocker;
3419   RecvRenderLayers(true /* aEnabled */, aEpoch);
3420 }
3421 
CanCancelContentJS(nsIRemoteTab::NavigationType aNavigationType,int32_t aNavigationIndex,nsIURI * aNavigationURI,int32_t aEpoch,bool * aCanCancel)3422 nsresult BrowserChild::CanCancelContentJS(
3423     nsIRemoteTab::NavigationType aNavigationType, int32_t aNavigationIndex,
3424     nsIURI* aNavigationURI, int32_t aEpoch, bool* aCanCancel) {
3425   nsresult rv;
3426   *aCanCancel = false;
3427 
3428   if (aEpoch <= mCancelContentJSEpoch) {
3429     // The next page loaded before we got here, so we shouldn't try to cancel
3430     // the content JS.
3431     return NS_OK;
3432   }
3433 
3434   // If we have session history in the parent we've already performed
3435   // the checks following, so we can return early.
3436   if (mozilla::SessionHistoryInParent()) {
3437     *aCanCancel = true;
3438     return NS_OK;
3439   }
3440 
3441   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
3442   nsCOMPtr<nsISHistory> history;
3443   if (docShell) {
3444     history = nsDocShell::Cast(docShell)->GetSessionHistory()->LegacySHistory();
3445   }
3446 
3447   if (!history) {
3448     return NS_ERROR_FAILURE;
3449   }
3450 
3451   int32_t current;
3452   rv = history->GetIndex(&current);
3453   NS_ENSURE_SUCCESS(rv, rv);
3454 
3455   if (current == -1) {
3456     // This tab has no history! Just return.
3457     return NS_OK;
3458   }
3459 
3460   nsCOMPtr<nsISHEntry> entry;
3461   rv = history->GetEntryAtIndex(current, getter_AddRefs(entry));
3462   NS_ENSURE_SUCCESS(rv, rv);
3463 
3464   nsCOMPtr<nsIURI> currentURI = entry->GetURI();
3465   if (!currentURI->SchemeIs("http") && !currentURI->SchemeIs("https") &&
3466       !currentURI->SchemeIs("file")) {
3467     // Only cancel content JS for http(s) and file URIs. Other URIs are probably
3468     // internal and we should just let them run to completion.
3469     return NS_OK;
3470   }
3471 
3472   if (aNavigationType == nsIRemoteTab::NAVIGATE_BACK) {
3473     aNavigationIndex = current - 1;
3474   } else if (aNavigationType == nsIRemoteTab::NAVIGATE_FORWARD) {
3475     aNavigationIndex = current + 1;
3476   } else if (aNavigationType == nsIRemoteTab::NAVIGATE_URL) {
3477     if (!aNavigationURI) {
3478       return NS_ERROR_FAILURE;
3479     }
3480 
3481     if (aNavigationURI->SchemeIs("javascript")) {
3482       // "javascript:" URIs don't (necessarily) trigger navigation to a
3483       // different page, so don't allow the current page's JS to terminate.
3484       return NS_OK;
3485     }
3486 
3487     // If navigating directly to a URL (e.g. via hitting Enter in the location
3488     // bar), then we can cancel anytime the next URL is different from the
3489     // current, *excluding* the ref ("#").
3490     bool equals;
3491     rv = currentURI->EqualsExceptRef(aNavigationURI, &equals);
3492     NS_ENSURE_SUCCESS(rv, rv);
3493     *aCanCancel = !equals;
3494     return NS_OK;
3495   }
3496   // Note: aNavigationType may also be NAVIGATE_INDEX, in which case we don't
3497   // need to do anything special.
3498 
3499   int32_t delta = aNavigationIndex > current ? 1 : -1;
3500   for (int32_t i = current + delta; i != aNavigationIndex + delta; i += delta) {
3501     nsCOMPtr<nsISHEntry> nextEntry;
3502     // If `i` happens to be negative, this call will fail (which is what we
3503     // would want to happen).
3504     rv = history->GetEntryAtIndex(i, getter_AddRefs(nextEntry));
3505     NS_ENSURE_SUCCESS(rv, rv);
3506 
3507     nsCOMPtr<nsISHEntry> laterEntry = delta == 1 ? nextEntry : entry;
3508     nsCOMPtr<nsIURI> thisURI = entry->GetURI();
3509     nsCOMPtr<nsIURI> nextURI = nextEntry->GetURI();
3510 
3511     // If we changed origin and the load wasn't in a subframe, we know it was
3512     // a full document load, so we can cancel the content JS safely.
3513     if (!laterEntry->GetIsSubFrame()) {
3514       nsAutoCString thisHost;
3515       rv = thisURI->GetPrePath(thisHost);
3516       NS_ENSURE_SUCCESS(rv, rv);
3517 
3518       nsAutoCString nextHost;
3519       rv = nextURI->GetPrePath(nextHost);
3520       NS_ENSURE_SUCCESS(rv, rv);
3521 
3522       if (!thisHost.Equals(nextHost)) {
3523         *aCanCancel = true;
3524         return NS_OK;
3525       }
3526     }
3527 
3528     entry = nextEntry;
3529   }
3530 
3531   return NS_OK;
3532 }
3533 
GetHasSiblings(bool * aHasSiblings)3534 nsresult BrowserChild::GetHasSiblings(bool* aHasSiblings) {
3535   *aHasSiblings = mHasSiblings;
3536   return NS_OK;
3537 }
3538 
SetHasSiblings(bool aHasSiblings)3539 nsresult BrowserChild::SetHasSiblings(bool aHasSiblings) {
3540   mHasSiblings = aHasSiblings;
3541   return NS_OK;
3542 }
3543 
OnStateChange(nsIWebProgress * aWebProgress,nsIRequest * aRequest,uint32_t aStateFlags,nsresult aStatus)3544 NS_IMETHODIMP BrowserChild::OnStateChange(nsIWebProgress* aWebProgress,
3545                                           nsIRequest* aRequest,
3546                                           uint32_t aStateFlags,
3547                                           nsresult aStatus) {
3548   if (!IPCOpen() || !mShouldSendWebProgressEventsToParent) {
3549     return NS_OK;
3550   }
3551 
3552   // We shouldn't need to notify the parent of redirect state changes, since
3553   // with DocumentChannel that only happens when we switch to the real channel,
3554   // and that's an implementation detail that we can hide.
3555   if (aStateFlags & nsIWebProgressListener::STATE_IS_REDIRECTED_DOCUMENT) {
3556     return NS_OK;
3557   }
3558 
3559   // Our OnStateChange call must have provided the nsIDocShell which the source
3560   // comes from. We'll use this to locate the corresponding BrowsingContext in
3561   // the parent process.
3562   nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress);
3563   if (!docShell) {
3564     MOZ_ASSERT_UNREACHABLE("aWebProgress is null or not a nsIDocShell?");
3565     return NS_ERROR_UNEXPECTED;
3566   }
3567 
3568   WebProgressData webProgressData;
3569   Maybe<WebProgressStateChangeData> stateChangeData;
3570   RequestData requestData;
3571 
3572   MOZ_TRY(PrepareProgressListenerData(aWebProgress, aRequest, webProgressData,
3573                                       requestData));
3574 
3575   RefPtr<BrowsingContext> browsingContext = docShell->GetBrowsingContext();
3576   if (browsingContext->IsTopContent()) {
3577     stateChangeData.emplace();
3578 
3579     stateChangeData->isNavigating() = docShell->GetIsNavigating();
3580     stateChangeData->mayEnableCharacterEncodingMenu() =
3581         docShell->GetMayEnableCharacterEncodingMenu();
3582 
3583     RefPtr<Document> document = browsingContext->GetExtantDocument();
3584     if (document && aStateFlags & nsIWebProgressListener::STATE_STOP) {
3585       document->GetContentType(stateChangeData->contentType());
3586       document->GetCharacterSet(stateChangeData->charset());
3587       stateChangeData->documentURI() = document->GetDocumentURIObject();
3588     } else {
3589       stateChangeData->contentType().SetIsVoid(true);
3590       stateChangeData->charset().SetIsVoid(true);
3591     }
3592   }
3593 
3594   Unused << SendOnStateChange(webProgressData, requestData, aStateFlags,
3595                               aStatus, stateChangeData);
3596 
3597   return NS_OK;
3598 }
3599 
OnProgressChange(nsIWebProgress * aWebProgress,nsIRequest * aRequest,int32_t aCurSelfProgress,int32_t aMaxSelfProgress,int32_t aCurTotalProgress,int32_t aMaxTotalProgress)3600 NS_IMETHODIMP BrowserChild::OnProgressChange(nsIWebProgress* aWebProgress,
3601                                              nsIRequest* aRequest,
3602                                              int32_t aCurSelfProgress,
3603                                              int32_t aMaxSelfProgress,
3604                                              int32_t aCurTotalProgress,
3605                                              int32_t aMaxTotalProgress) {
3606   if (!IPCOpen() || !mShouldSendWebProgressEventsToParent) {
3607     return NS_OK;
3608   }
3609 
3610   // FIXME: We currently ignore ProgressChange events from out-of-process
3611   // subframes both here and in BrowserParent. We may want to change this
3612   // behaviour in the future.
3613   if (!GetBrowsingContext()->IsTopContent()) {
3614     return NS_OK;
3615   }
3616 
3617   // As we're being filtered by nsBrowserStatusFilter, we will be passed either
3618   // nullptr or 0 for all arguments other than aCurTotalProgress and
3619   // aMaxTotalProgress. Don't bother sending them.
3620   MOZ_ASSERT(!aWebProgress);
3621   MOZ_ASSERT(!aRequest);
3622   MOZ_ASSERT(aCurSelfProgress == 0);
3623   MOZ_ASSERT(aMaxSelfProgress == 0);
3624 
3625   Unused << SendOnProgressChange(aCurTotalProgress, aMaxTotalProgress);
3626 
3627   return NS_OK;
3628 }
3629 
OnLocationChange(nsIWebProgress * aWebProgress,nsIRequest * aRequest,nsIURI * aLocation,uint32_t aFlags)3630 NS_IMETHODIMP BrowserChild::OnLocationChange(nsIWebProgress* aWebProgress,
3631                                              nsIRequest* aRequest,
3632                                              nsIURI* aLocation,
3633                                              uint32_t aFlags) {
3634   if (!IPCOpen() || !mShouldSendWebProgressEventsToParent) {
3635     return NS_OK;
3636   }
3637 
3638   nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress);
3639   if (!docShell) {
3640     MOZ_ASSERT_UNREACHABLE("aWebProgress is null or not a nsIDocShell?");
3641     return NS_ERROR_UNEXPECTED;
3642   }
3643 
3644   RefPtr<BrowsingContext> browsingContext = docShell->GetBrowsingContext();
3645   RefPtr<Document> document = browsingContext->GetExtantDocument();
3646   if (!document) {
3647     return NS_OK;
3648   }
3649 
3650   WebProgressData webProgressData;
3651   RequestData requestData;
3652 
3653   MOZ_TRY(PrepareProgressListenerData(aWebProgress, aRequest, webProgressData,
3654                                       requestData));
3655 
3656   Maybe<WebProgressLocationChangeData> locationChangeData;
3657 
3658   bool canGoBack = false;
3659   bool canGoForward = false;
3660   if (!mozilla::SessionHistoryInParent()) {
3661     MOZ_TRY(WebNavigation()->GetCanGoBack(&canGoBack));
3662     MOZ_TRY(WebNavigation()->GetCanGoForward(&canGoForward));
3663   }
3664 
3665   if (browsingContext->IsTopContent()) {
3666     MOZ_ASSERT(
3667         browsingContext == GetBrowsingContext(),
3668         "Toplevel content BrowsingContext which isn't GetBrowsingContext()?");
3669 
3670     locationChangeData.emplace();
3671 
3672     document->GetContentType(locationChangeData->contentType());
3673     locationChangeData->isNavigating() = docShell->GetIsNavigating();
3674     locationChangeData->documentURI() = document->GetDocumentURIObject();
3675     document->GetTitle(locationChangeData->title());
3676     document->GetCharacterSet(locationChangeData->charset());
3677 
3678     locationChangeData->mayEnableCharacterEncodingMenu() =
3679         docShell->GetMayEnableCharacterEncodingMenu();
3680 
3681     locationChangeData->contentPrincipal() = document->NodePrincipal();
3682     locationChangeData->contentPartitionedPrincipal() =
3683         document->PartitionedPrincipal();
3684     locationChangeData->csp() = document->GetCsp();
3685     locationChangeData->referrerInfo() = document->ReferrerInfo();
3686     locationChangeData->isSyntheticDocument() = document->IsSyntheticDocument();
3687 
3688     if (nsCOMPtr<nsILoadGroup> loadGroup = document->GetDocumentLoadGroup()) {
3689       uint64_t requestContextID = 0;
3690       MOZ_TRY(loadGroup->GetRequestContextID(&requestContextID));
3691       locationChangeData->requestContextID() = Some(requestContextID);
3692     }
3693 
3694 #ifdef MOZ_CRASHREPORTER
3695     if (CrashReporter::GetEnabled()) {
3696       nsCOMPtr<nsIURI> annotationURI;
3697 
3698       nsresult rv =
3699           NS_MutateURI(aLocation).SetUserPass(""_ns).Finalize(annotationURI);
3700 
3701       if (NS_FAILED(rv)) {
3702         // Ignore failures on about: URIs.
3703         annotationURI = aLocation;
3704       }
3705 
3706       CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL,
3707                                          annotationURI->GetSpecOrDefault());
3708     }
3709 #endif
3710   }
3711 
3712   Unused << SendOnLocationChange(webProgressData, requestData, aLocation,
3713                                  aFlags, canGoBack, canGoForward,
3714                                  locationChangeData);
3715 
3716   return NS_OK;
3717 }
3718 
OnStatusChange(nsIWebProgress * aWebProgress,nsIRequest * aRequest,nsresult aStatus,const char16_t * aMessage)3719 NS_IMETHODIMP BrowserChild::OnStatusChange(nsIWebProgress* aWebProgress,
3720                                            nsIRequest* aRequest,
3721                                            nsresult aStatus,
3722                                            const char16_t* aMessage) {
3723   if (!IPCOpen() || !mShouldSendWebProgressEventsToParent) {
3724     return NS_OK;
3725   }
3726 
3727   // FIXME: We currently ignore StatusChange from out-of-process subframes both
3728   // here and in BrowserParent. We may want to change this behaviour in the
3729   // future.
3730   if (!GetBrowsingContext()->IsTopContent()) {
3731     return NS_OK;
3732   }
3733 
3734   // As we're being filtered by nsBrowserStatusFilter, we will be passed either
3735   // nullptr or NS_OK for all arguments other than aMessage. Don't bother
3736   // sending them.
3737   MOZ_ASSERT(!aWebProgress);
3738   MOZ_ASSERT(!aRequest);
3739   MOZ_ASSERT(aStatus == NS_OK);
3740 
3741   Unused << SendOnStatusChange(nsDependentString(aMessage));
3742 
3743   return NS_OK;
3744 }
3745 
OnSecurityChange(nsIWebProgress * aWebProgress,nsIRequest * aRequest,uint32_t aState)3746 NS_IMETHODIMP BrowserChild::OnSecurityChange(nsIWebProgress* aWebProgress,
3747                                              nsIRequest* aRequest,
3748                                              uint32_t aState) {
3749   // Security changes are now handled entirely in the parent process
3750   // so we don't need to worry about forwarding them (and we shouldn't
3751   // be receiving any to forward).
3752   return NS_OK;
3753 }
3754 
OnContentBlockingEvent(nsIWebProgress * aWebProgress,nsIRequest * aRequest,uint32_t aEvent)3755 NS_IMETHODIMP BrowserChild::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
3756                                                    nsIRequest* aRequest,
3757                                                    uint32_t aEvent) {
3758   // The OnContentBlockingEvent only happenes in the parent process. It should
3759   // not be seen in the content process.
3760   MOZ_DIAGNOSTIC_ASSERT(
3761       false, "OnContentBlockingEvent should not be seen in content process.");
3762   return NS_ERROR_NOT_IMPLEMENTED;
3763 }
3764 
OnProgressChange64(nsIWebProgress * aWebProgress,nsIRequest * aRequest,int64_t aCurSelfProgress,int64_t aMaxSelfProgress,int64_t aCurTotalProgress,int64_t aMaxTotalProgress)3765 NS_IMETHODIMP BrowserChild::OnProgressChange64(nsIWebProgress* aWebProgress,
3766                                                nsIRequest* aRequest,
3767                                                int64_t aCurSelfProgress,
3768                                                int64_t aMaxSelfProgress,
3769                                                int64_t aCurTotalProgress,
3770                                                int64_t aMaxTotalProgress) {
3771   // All the events we receive are filtered through an nsBrowserStatusFilter,
3772   // which accepts ProgressChange64 events, but truncates the progress values to
3773   // uint32_t and calls OnProgressChange.
3774   return NS_ERROR_NOT_IMPLEMENTED;
3775 }
3776 
OnRefreshAttempted(nsIWebProgress * aWebProgress,nsIURI * aRefreshURI,uint32_t aMillis,bool aSameURI,bool * aOut)3777 NS_IMETHODIMP BrowserChild::OnRefreshAttempted(nsIWebProgress* aWebProgress,
3778                                                nsIURI* aRefreshURI,
3779                                                uint32_t aMillis, bool aSameURI,
3780                                                bool* aOut) {
3781   NS_ENSURE_ARG_POINTER(aOut);
3782   *aOut = true;
3783 
3784   return NS_OK;
3785 }
3786 
NotifyNavigationFinished()3787 NS_IMETHODIMP BrowserChild::NotifyNavigationFinished() {
3788   Unused << SendNavigationFinished();
3789   return NS_OK;
3790 }
3791 
PrepareRequestData(nsIRequest * aRequest,RequestData & aRequestData)3792 nsresult BrowserChild::PrepareRequestData(nsIRequest* aRequest,
3793                                           RequestData& aRequestData) {
3794   nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
3795   if (!channel) {
3796     aRequestData.requestURI() = nullptr;
3797     return NS_OK;
3798   }
3799 
3800   nsresult rv = channel->GetURI(getter_AddRefs(aRequestData.requestURI()));
3801   NS_ENSURE_SUCCESS(rv, rv);
3802 
3803   rv = channel->GetOriginalURI(
3804       getter_AddRefs(aRequestData.originalRequestURI()));
3805   NS_ENSURE_SUCCESS(rv, rv);
3806 
3807   nsCOMPtr<nsIClassifiedChannel> classifiedChannel = do_QueryInterface(channel);
3808   if (classifiedChannel) {
3809     rv = classifiedChannel->GetMatchedList(aRequestData.matchedList());
3810     NS_ENSURE_SUCCESS(rv, rv);
3811   }
3812   return NS_OK;
3813 }
3814 
PrepareProgressListenerData(nsIWebProgress * aWebProgress,nsIRequest * aRequest,WebProgressData & aWebProgressData,RequestData & aRequestData)3815 nsresult BrowserChild::PrepareProgressListenerData(
3816     nsIWebProgress* aWebProgress, nsIRequest* aRequest,
3817     WebProgressData& aWebProgressData, RequestData& aRequestData) {
3818   nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress);
3819   if (!docShell) {
3820     MOZ_ASSERT_UNREACHABLE("aWebProgress is null or not a nsIDocShell?");
3821     return NS_ERROR_UNEXPECTED;
3822   }
3823 
3824   aWebProgressData.browsingContext() = docShell->GetBrowsingContext();
3825   nsresult rv = aWebProgress->GetLoadType(&aWebProgressData.loadType());
3826   NS_ENSURE_SUCCESS(rv, rv);
3827 
3828   return PrepareRequestData(aRequest, aRequestData);
3829 }
3830 
UpdateSessionStore()3831 bool BrowserChild::UpdateSessionStore() {
3832   if (!mSessionStoreListener) {
3833     return false;
3834   }
3835   RefPtr<ContentSessionStore> store = mSessionStoreListener->GetSessionStore();
3836 
3837   Maybe<nsCString> docShellCaps;
3838   if (store->IsDocCapChanged()) {
3839     docShellCaps.emplace(store->GetDocShellCaps());
3840   }
3841 
3842   Maybe<bool> privatedMode;
3843   if (store->IsPrivateChanged()) {
3844     privatedMode.emplace(store->GetPrivateModeEnabled());
3845   }
3846 
3847   Unused << SendSessionStoreUpdate(docShellCaps, privatedMode,
3848                                    store->GetAndClearSHistoryChanged(),
3849                                    mSessionStoreListener->GetEpoch());
3850   return true;
3851 }
3852 
3853 #ifdef XP_WIN
3854 RefPtr<PBrowserChild::IsWindowSupportingProtectedMediaPromise>
DoesWindowSupportProtectedMedia()3855 BrowserChild::DoesWindowSupportProtectedMedia() {
3856   MOZ_ASSERT(
3857       NS_IsMainThread(),
3858       "Protected media support check should be done on main thread only.");
3859   if (mWindowSupportsProtectedMedia) {
3860     // If we've already checked and have a cached result, resolve with that.
3861     return IsWindowSupportingProtectedMediaPromise::CreateAndResolve(
3862         mWindowSupportsProtectedMedia.value(), __func__);
3863   }
3864   RefPtr<BrowserChild> self = this;
3865   // We chain off the promise rather than passing it directly so we can cache
3866   // the result and use that for future calls.
3867   return SendIsWindowSupportingProtectedMedia(ChromeOuterWindowID())
3868       ->Then(
3869           GetCurrentSerialEventTarget(), __func__,
3870           [self](bool isSupported) {
3871             // If a result was cached while this check was inflight, ensure the
3872             // results match.
3873             MOZ_ASSERT_IF(
3874                 self->mWindowSupportsProtectedMedia,
3875                 self->mWindowSupportsProtectedMedia.value() == isSupported);
3876             // Cache the response as it will not change during the lifetime
3877             // of this object.
3878             self->mWindowSupportsProtectedMedia = Some(isSupported);
3879             return IsWindowSupportingProtectedMediaPromise::CreateAndResolve(
3880                 self->mWindowSupportsProtectedMedia.value(), __func__);
3881           },
3882           [](ResponseRejectReason reason) {
3883             return IsWindowSupportingProtectedMediaPromise::CreateAndReject(
3884                 reason, __func__);
3885           });
3886 }
3887 #endif
3888 
NotifyContentBlockingEvent(uint32_t aEvent,nsIChannel * aChannel,bool aBlocked,const nsACString & aTrackingOrigin,const nsTArray<nsCString> & aTrackingFullHashes,const Maybe<mozilla::ContentBlockingNotifier::StorageAccessPermissionGrantedReason> & aReason)3889 void BrowserChild::NotifyContentBlockingEvent(
3890     uint32_t aEvent, nsIChannel* aChannel, bool aBlocked,
3891     const nsACString& aTrackingOrigin,
3892     const nsTArray<nsCString>& aTrackingFullHashes,
3893     const Maybe<
3894         mozilla::ContentBlockingNotifier::StorageAccessPermissionGrantedReason>&
3895         aReason) {
3896   if (!IPCOpen()) {
3897     return;
3898   }
3899 
3900   RequestData requestData;
3901   if (NS_SUCCEEDED(PrepareRequestData(aChannel, requestData))) {
3902     Unused << SendNotifyContentBlockingEvent(
3903         aEvent, requestData, aBlocked, PromiseFlatCString(aTrackingOrigin),
3904         aTrackingFullHashes, aReason);
3905   }
3906 }
3907 
BrowserChildMessageManager(BrowserChild * aBrowserChild)3908 BrowserChildMessageManager::BrowserChildMessageManager(
3909     BrowserChild* aBrowserChild)
3910     : ContentFrameMessageManager(new nsFrameMessageManager(aBrowserChild)),
3911       mBrowserChild(aBrowserChild) {}
3912 
3913 BrowserChildMessageManager::~BrowserChildMessageManager() = default;
3914 
3915 NS_IMPL_CYCLE_COLLECTION_CLASS(BrowserChildMessageManager)
3916 
3917 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BrowserChildMessageManager,
3918                                                 DOMEventTargetHelper)
3919   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager);
3920   NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChild);
3921   NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
3922 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
3923 
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BrowserChildMessageManager,DOMEventTargetHelper)3924 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BrowserChildMessageManager,
3925                                                   DOMEventTargetHelper)
3926   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
3927   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChild)
3928 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
3929 
3930 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserChildMessageManager)
3931   NS_INTERFACE_MAP_ENTRY(nsIMessageSender)
3932   NS_INTERFACE_MAP_ENTRY(ContentFrameMessageManager)
3933   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
3934 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
3935 
3936 NS_IMPL_ADDREF_INHERITED(BrowserChildMessageManager, DOMEventTargetHelper)
3937 NS_IMPL_RELEASE_INHERITED(BrowserChildMessageManager, DOMEventTargetHelper)
3938 
3939 JSObject* BrowserChildMessageManager::WrapObject(
3940     JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
3941   return ContentFrameMessageManager_Binding::Wrap(aCx, this, aGivenProto);
3942 }
3943 
MarkForCC()3944 void BrowserChildMessageManager::MarkForCC() {
3945   if (mBrowserChild) {
3946     mBrowserChild->MarkScopesForCC();
3947   }
3948   EventListenerManager* elm = GetExistingListenerManager();
3949   if (elm) {
3950     elm->MarkForCC();
3951   }
3952   MessageManagerGlobal::MarkForCC();
3953 }
3954 
GetContent(ErrorResult & aError)3955 Nullable<WindowProxyHolder> BrowserChildMessageManager::GetContent(
3956     ErrorResult& aError) {
3957   nsCOMPtr<nsIDocShell> docShell = GetDocShell(aError);
3958   if (!docShell) {
3959     return nullptr;
3960   }
3961   return WindowProxyHolder(docShell->GetBrowsingContext());
3962 }
3963 
GetDocShell(ErrorResult & aError)3964 already_AddRefed<nsIDocShell> BrowserChildMessageManager::GetDocShell(
3965     ErrorResult& aError) {
3966   if (!mBrowserChild) {
3967     aError.Throw(NS_ERROR_NULL_POINTER);
3968     return nullptr;
3969   }
3970   nsCOMPtr<nsIDocShell> window =
3971       do_GetInterface(mBrowserChild->WebNavigation());
3972   return window.forget();
3973 }
3974 
3975 already_AddRefed<nsIEventTarget>
GetTabEventTarget()3976 BrowserChildMessageManager::GetTabEventTarget() {
3977   nsCOMPtr<nsIEventTarget> target = EventTargetFor(TaskCategory::Other);
3978   return target.forget();
3979 }
3980 
Dispatch(TaskCategory aCategory,already_AddRefed<nsIRunnable> && aRunnable)3981 nsresult BrowserChildMessageManager::Dispatch(
3982     TaskCategory aCategory, already_AddRefed<nsIRunnable>&& aRunnable) {
3983   return DispatcherTrait::Dispatch(aCategory, std::move(aRunnable));
3984 }
3985 
EventTargetFor(TaskCategory aCategory) const3986 nsISerialEventTarget* BrowserChildMessageManager::EventTargetFor(
3987     TaskCategory aCategory) const {
3988   return DispatcherTrait::EventTargetFor(aCategory);
3989 }
3990 
AbstractMainThreadFor(TaskCategory aCategory)3991 AbstractThread* BrowserChildMessageManager::AbstractMainThreadFor(
3992     TaskCategory aCategory) {
3993   return DispatcherTrait::AbstractMainThreadFor(aCategory);
3994 }
3995