Backed out changeset 1d9301697aa0 (bug 1887752) for causing failures on browser_all_f...
[gecko.git] / dom / ipc / BrowserChild.cpp
blob3d1f399edb4feb0793c214917464be2599739e6e
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/. */
7 #include "BrowserChild.h"
9 #ifdef ACCESSIBILITY
10 # include "mozilla/a11y/DocAccessibleChild.h"
11 #endif
12 #include <utility>
14 #include "BrowserParent.h"
15 #include "ContentChild.h"
16 #include "EventStateManager.h"
17 #include "MMPrinter.h"
18 #include "PuppetWidget.h"
19 #include "StructuredCloneData.h"
20 #include "UnitTransforms.h"
21 #include "Units.h"
22 #include "VRManagerChild.h"
23 #include "mozilla/Assertions.h"
24 #include "mozilla/BasePrincipal.h"
25 #include "mozilla/EventForwards.h"
26 #include "mozilla/EventListenerManager.h"
27 #include "mozilla/HoldDropJSObjects.h"
28 #include "mozilla/IMEStateManager.h"
29 #include "mozilla/LookAndFeel.h"
30 #include "mozilla/MouseEvents.h"
31 #include "mozilla/NativeKeyBindingsType.h"
32 #include "mozilla/NullPrincipal.h"
33 #include "mozilla/PresShell.h"
34 #include "mozilla/ProcessHangMonitor.h"
35 #include "mozilla/ProfilerLabels.h"
36 #include "mozilla/SchedulerGroup.h"
37 #include "mozilla/ScopeExit.h"
38 #include "mozilla/Services.h"
39 #include "mozilla/StaticPrefs_dom.h"
40 #include "mozilla/TextEvents.h"
41 #include "mozilla/ToString.h"
42 #include "mozilla/Unused.h"
43 #include "mozilla/dom/AutoPrintEventDispatcher.h"
44 #include "mozilla/dom/BrowserBridgeChild.h"
45 #include "mozilla/dom/DataTransfer.h"
46 #include "mozilla/dom/Element.h"
47 #include "mozilla/dom/Event.h"
48 #include "mozilla/dom/JSWindowActorChild.h"
49 #include "mozilla/dom/ImageDocument.h"
50 #include "mozilla/dom/LoadURIOptionsBinding.h"
51 #include "mozilla/dom/MessageManagerBinding.h"
52 #include "mozilla/dom/MouseEventBinding.h"
53 #include "mozilla/dom/Nullable.h"
54 #include "mozilla/dom/PaymentRequestChild.h"
55 #include "mozilla/dom/PBrowser.h"
56 #include "mozilla/dom/PointerEventHandler.h"
57 #include "mozilla/dom/SessionStoreUtils.h"
58 #include "mozilla/dom/SessionStoreChild.h"
59 #include "mozilla/dom/UserActivation.h"
60 #include "mozilla/dom/WindowGlobalChild.h"
61 #include "mozilla/dom/WindowProxyHolder.h"
62 #include "mozilla/gfx/CrossProcessPaint.h"
63 #include "mozilla/gfx/Matrix.h"
64 #include "mozilla/ipc/BackgroundChild.h"
65 #include "mozilla/ipc/BackgroundUtils.h"
66 #include "mozilla/ipc/PBackgroundChild.h"
67 #include "mozilla/layers/APZCCallbackHelper.h"
68 #include "mozilla/layers/TouchActionHelper.h"
69 #include "mozilla/layers/APZCTreeManagerChild.h"
70 #include "mozilla/layers/APZChild.h"
71 #include "mozilla/layers/APZEventState.h"
72 #include "mozilla/layers/CompositorBridgeChild.h"
73 #include "mozilla/layers/ContentProcessController.h"
74 #include "mozilla/layers/DoubleTapToZoom.h"
75 #include "mozilla/layers/IAPZCTreeManager.h"
76 #include "mozilla/layers/ImageBridgeChild.h"
77 #include "mozilla/layers/InputAPZContext.h"
78 #include "mozilla/layers/WebRenderLayerManager.h"
79 #include "nsBrowserStatusFilter.h"
80 #include "nsCommandParams.h"
81 #include "nsContentPermissionHelper.h"
82 #include "nsContentUtils.h"
83 #include "nsDeviceContext.h"
84 #include "nsDocShell.h"
85 #include "nsDocShellLoadState.h"
86 #include "nsExceptionHandler.h"
87 #include "nsFilePickerProxy.h"
88 #include "nsFocusManager.h"
89 #include "nsGlobalWindowOuter.h"
90 #include "nsIBaseWindow.h"
91 #include "nsIBrowserDOMWindow.h"
92 #include "nsIClassifiedChannel.h"
93 #include "nsIDocShell.h"
94 #include "nsIFrame.h"
95 #include "nsILoadContext.h"
96 #include "nsISHEntry.h"
97 #include "nsISHistory.h"
98 #include "nsIScreenManager.h"
99 #include "nsIScriptError.h"
100 #include "nsIURI.h"
101 #include "nsIURIMutator.h"
102 #include "nsIWeakReferenceUtils.h"
103 #include "nsIWebBrowser.h"
104 #include "nsIWebProgress.h"
105 #include "nsLayoutUtils.h"
106 #include "nsNetUtil.h"
107 #include "nsIOpenWindowInfo.h"
108 #include "nsPIDOMWindow.h"
109 #include "nsPIWindowRoot.h"
110 #include "nsPrintfCString.h"
111 #include "nsRefreshDriver.h"
112 #include "nsThreadManager.h"
113 #include "nsThreadUtils.h"
114 #include "nsViewManager.h"
115 #include "nsWebBrowser.h"
116 #include "nsWindowWatcher.h"
117 #include "nsIXULRuntime.h"
119 #ifdef MOZ_WAYLAND
120 # include "nsAppRunner.h"
121 #endif
123 #ifdef NS_PRINTING
124 # include "mozilla/layout/RemotePrintJobChild.h"
125 # include "nsIPrintSettings.h"
126 # include "nsIPrintSettingsService.h"
127 # include "nsIWebBrowserPrint.h"
128 #endif
130 static mozilla::LazyLogModule sApzChildLog("apz.child");
132 using namespace mozilla;
133 using namespace mozilla::dom;
134 using namespace mozilla::dom::ipc;
135 using namespace mozilla::ipc;
136 using namespace mozilla::layers;
137 using namespace mozilla::layout;
138 using namespace mozilla::widget;
139 using mozilla::layers::GeckoContentController;
141 static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
143 static uint32_t sConsecutiveTouchMoveCount = 0;
145 using BrowserChildMap = nsTHashMap<nsUint64HashKey, BrowserChild*>;
146 static BrowserChildMap* sBrowserChildren;
147 StaticMutex sBrowserChildrenMutex;
149 already_AddRefed<Document> BrowserChild::GetTopLevelDocument() const {
150 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
151 nsCOMPtr<Document> doc = docShell ? docShell->GetExtantDocument() : nullptr;
152 return doc.forget();
155 PresShell* BrowserChild::GetTopLevelPresShell() const {
156 if (RefPtr<Document> doc = GetTopLevelDocument()) {
157 return doc->GetPresShell();
159 return nullptr;
162 bool BrowserChild::UpdateFrame(const RepaintRequest& aRequest) {
163 MOZ_ASSERT(aRequest.GetScrollId() != ScrollableLayerGuid::NULL_SCROLL_ID);
165 if (aRequest.IsRootContent()) {
166 if (PresShell* presShell = GetTopLevelPresShell()) {
167 // Guard against stale updates (updates meant for a pres shell which
168 // has since been torn down and destroyed).
169 if (aRequest.GetPresShellId() == presShell->GetPresShellId()) {
170 APZCCallbackHelper::UpdateRootFrame(aRequest);
171 return true;
174 } else {
175 // aRequest.mIsRoot is false, so we are trying to update a subframe.
176 // This requires special handling.
177 APZCCallbackHelper::UpdateSubFrame(aRequest);
178 return true;
180 return true;
183 class BrowserChild::DelayedDeleteRunnable final : public Runnable,
184 public nsIRunnablePriority {
185 RefPtr<BrowserChild> mBrowserChild;
187 // In order to try that this runnable runs after everything that could
188 // possibly touch this tab, we send it through the event queue twice.
189 bool mReadyToDelete = false;
191 public:
192 explicit DelayedDeleteRunnable(BrowserChild* aBrowserChild)
193 : Runnable("BrowserChild::DelayedDeleteRunnable"),
194 mBrowserChild(aBrowserChild) {
195 MOZ_ASSERT(NS_IsMainThread());
196 MOZ_ASSERT(aBrowserChild);
199 NS_DECL_ISUPPORTS_INHERITED
201 private:
202 ~DelayedDeleteRunnable() {
203 MOZ_ASSERT(NS_IsMainThread());
204 MOZ_ASSERT(!mBrowserChild);
207 NS_IMETHOD GetPriority(uint32_t* aPriority) override {
208 *aPriority = nsIRunnablePriority::PRIORITY_NORMAL;
209 return NS_OK;
212 NS_IMETHOD
213 Run() override {
214 MOZ_ASSERT(NS_IsMainThread());
215 MOZ_ASSERT(mBrowserChild);
217 if (!mReadyToDelete) {
218 // This time run this runnable at input priority.
219 mReadyToDelete = true;
220 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(this));
221 return NS_OK;
224 // Check in case ActorDestroy was called after RecvDestroy message.
225 if (mBrowserChild->IPCOpen()) {
226 Unused << PBrowserChild::Send__delete__(mBrowserChild);
229 mBrowserChild = nullptr;
230 return NS_OK;
234 NS_IMPL_ISUPPORTS_INHERITED(BrowserChild::DelayedDeleteRunnable, Runnable,
235 nsIRunnablePriority)
237 namespace {
238 std::map<TabId, RefPtr<BrowserChild>>& NestedBrowserChildMap() {
239 MOZ_ASSERT(NS_IsMainThread());
240 static std::map<TabId, RefPtr<BrowserChild>> sNestedBrowserChildMap;
241 return sNestedBrowserChildMap;
243 } // namespace
245 already_AddRefed<BrowserChild> BrowserChild::FindBrowserChild(
246 const TabId& aTabId) {
247 auto iter = NestedBrowserChildMap().find(aTabId);
248 if (iter == NestedBrowserChildMap().end()) {
249 return nullptr;
251 RefPtr<BrowserChild> browserChild = iter->second;
252 return browserChild.forget();
255 /*static*/
256 already_AddRefed<BrowserChild> BrowserChild::Create(
257 ContentChild* aManager, const TabId& aTabId, const TabContext& aContext,
258 BrowsingContext* aBrowsingContext, uint32_t aChromeFlags,
259 bool aIsTopLevel) {
260 RefPtr<BrowserChild> iframe = new BrowserChild(
261 aManager, aTabId, aContext, aBrowsingContext, aChromeFlags, aIsTopLevel);
262 return iframe.forget();
265 BrowserChild::BrowserChild(ContentChild* aManager, const TabId& aTabId,
266 const TabContext& aContext,
267 BrowsingContext* aBrowsingContext,
268 uint32_t aChromeFlags, bool aIsTopLevel)
269 : TabContext(aContext),
270 mBrowserChildMessageManager(nullptr),
271 mManager(aManager),
272 mBrowsingContext(aBrowsingContext),
273 mChromeFlags(aChromeFlags),
274 mMaxTouchPoints(0),
275 mLayersId{0},
276 mEffectsInfo{EffectsInfo::FullyHidden()},
277 mDynamicToolbarMaxHeight(0),
278 mUniqueId(aTabId),
279 mDidFakeShow(false),
280 mTriedBrowserInit(false),
281 mIgnoreKeyPressEvent(false),
282 mHasValidInnerSize(false),
283 mDestroyed(false),
284 mIsTopLevel(aIsTopLevel),
285 mIsTransparent(false),
286 mIPCOpen(false),
287 mDidSetRealShowInfo(false),
288 mDidLoadURLInit(false),
289 mSkipKeyPress(false),
290 mShouldSendWebProgressEventsToParent(false),
291 mRenderLayers(true),
292 mIsPreservingLayers(false),
293 #if defined(XP_WIN) && defined(ACCESSIBILITY)
294 mNativeWindowHandle(0),
295 #endif
296 mCancelContentJSEpoch(0) {
297 mozilla::HoldJSObjects(this);
299 // preloaded BrowserChild should not be added to child map
300 if (mUniqueId) {
301 MOZ_ASSERT(NestedBrowserChildMap().find(mUniqueId) ==
302 NestedBrowserChildMap().end());
303 NestedBrowserChildMap()[mUniqueId] = this;
305 mCoalesceMouseMoveEvents = StaticPrefs::dom_events_coalesce_mousemove();
306 if (mCoalesceMouseMoveEvents) {
307 mCoalescedMouseEventFlusher = new CoalescedMouseMoveFlusher(this);
310 if (StaticPrefs::dom_events_coalesce_touchmove()) {
311 mCoalescedTouchMoveEventFlusher = new CoalescedTouchMoveFlusher(this);
315 const CompositorOptions& BrowserChild::GetCompositorOptions() const {
316 // If you're calling this before mCompositorOptions is set, well.. don't.
317 MOZ_ASSERT(mCompositorOptions);
318 return mCompositorOptions.ref();
321 bool BrowserChild::AsyncPanZoomEnabled() const {
322 // This might get called by the TouchEvent::PrefEnabled code before we have
323 // mCompositorOptions populated (bug 1370089). In that case we just assume
324 // APZ is enabled because we're in a content process (because BrowserChild)
325 // and APZ is probably going to be enabled here since e10s is enabled.
326 return mCompositorOptions ? mCompositorOptions->UseAPZ() : true;
329 NS_IMETHODIMP
330 BrowserChild::Observe(nsISupports* aSubject, const char* aTopic,
331 const char16_t* aData) {
332 if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) {
333 if (AsyncPanZoomEnabled()) {
334 nsCOMPtr<Document> subject(do_QueryInterface(aSubject));
335 nsCOMPtr<Document> doc(GetTopLevelDocument());
337 if (subject == doc) {
338 RefPtr<PresShell> presShell = doc->GetPresShell();
339 if (presShell) {
340 presShell->SetIsFirstPaint(true);
343 APZCCallbackHelper::InitializeRootDisplayport(presShell);
348 return NS_OK;
351 void BrowserChild::ContentReceivedInputBlock(uint64_t aInputBlockId,
352 bool aPreventDefault) const {
353 if (mApzcTreeManager) {
354 mApzcTreeManager->ContentReceivedInputBlock(aInputBlockId, aPreventDefault);
358 void BrowserChild::SetTargetAPZC(
359 uint64_t aInputBlockId,
360 const nsTArray<ScrollableLayerGuid>& aTargets) const {
361 if (mApzcTreeManager) {
362 mApzcTreeManager->SetTargetAPZC(aInputBlockId, aTargets);
366 bool BrowserChild::DoUpdateZoomConstraints(
367 const uint32_t& aPresShellId, const ViewID& aViewId,
368 const Maybe<ZoomConstraints>& aConstraints) {
369 if (!mApzcTreeManager || mDestroyed) {
370 return false;
373 ScrollableLayerGuid guid =
374 ScrollableLayerGuid(mLayersId, aPresShellId, aViewId);
376 mApzcTreeManager->UpdateZoomConstraints(guid, aConstraints);
377 return true;
380 nsresult BrowserChild::Init(mozIDOMWindowProxy* aParent,
381 WindowGlobalChild* aInitialWindowChild) {
382 MOZ_ASSERT_IF(aInitialWindowChild,
383 aInitialWindowChild->BrowsingContext() == mBrowsingContext);
385 nsCOMPtr<nsIWidget> widget = nsIWidget::CreatePuppetWidget(this);
386 mPuppetWidget = static_cast<PuppetWidget*>(widget.get());
387 if (!mPuppetWidget) {
388 NS_ERROR("couldn't create fake widget");
389 return NS_ERROR_FAILURE;
391 mPuppetWidget->InfallibleCreate(nullptr,
392 nullptr, // no parents
393 LayoutDeviceIntRect(0, 0, 0, 0),
394 nullptr); // HandleWidgetEvent
396 mWebBrowser = nsWebBrowser::Create(this, mPuppetWidget, mBrowsingContext,
397 aInitialWindowChild);
398 nsIWebBrowser* webBrowser = mWebBrowser;
400 mWebNav = do_QueryInterface(webBrowser);
401 NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
403 // IPC uses a WebBrowser object for which DNS prefetching is turned off
404 // by default. But here we really want it, so enable it explicitly
405 mWebBrowser->SetAllowDNSPrefetch(true);
407 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
408 MOZ_ASSERT(docShell);
410 mStatusFilter = new nsBrowserStatusFilter();
412 nsresult rv =
413 mStatusFilter->AddProgressListener(this, nsIWebProgress::NOTIFY_ALL);
414 NS_ENSURE_SUCCESS(rv, rv);
417 nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(docShell);
418 rv = webProgress->AddProgressListener(mStatusFilter,
419 nsIWebProgress::NOTIFY_ALL);
420 NS_ENSURE_SUCCESS(rv, rv);
423 #ifdef DEBUG
424 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(WebNavigation());
425 MOZ_ASSERT(loadContext);
426 MOZ_ASSERT(loadContext->UseRemoteTabs() ==
427 !!(mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW));
428 MOZ_ASSERT(loadContext->UseRemoteSubframes() ==
429 !!(mChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW));
430 #endif // defined(DEBUG)
432 // Few lines before, baseWindow->Create() will end up creating a new
433 // window root in nsGlobalWindowOuter::SetDocShell.
434 // Then this chrome event handler, will be inherited to inner windows.
435 // We want to also set it to the docshell so that inner windows
436 // and any code that has access to the docshell
437 // can all listen to the same chrome event handler.
438 // XXX: ideally, we would set a chrome event handler earlier,
439 // and all windows, even the root one, will use the docshell one.
440 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
441 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
442 nsCOMPtr<EventTarget> chromeHandler = window->GetChromeEventHandler();
443 docShell->SetChromeEventHandler(chromeHandler);
445 // Window scrollbar flags only affect top level remote frames, not fission
446 // frames.
447 if (mIsTopLevel) {
448 nsContentUtils::SetScrollbarsVisibility(
449 docShell, !!(mChromeFlags & nsIWebBrowserChrome::CHROME_SCROLLBARS));
452 nsWeakPtr weakPtrThis = do_GetWeakReference(
453 static_cast<nsIBrowserChild*>(this)); // for capture by the lambda
454 ContentReceivedInputBlockCallback callback(
455 [weakPtrThis](uint64_t aInputBlockId, bool aPreventDefault) {
456 if (nsCOMPtr<nsIBrowserChild> browserChild =
457 do_QueryReferent(weakPtrThis)) {
458 static_cast<BrowserChild*>(browserChild.get())
459 ->ContentReceivedInputBlock(aInputBlockId, aPreventDefault);
462 mAPZEventState = new APZEventState(mPuppetWidget, std::move(callback));
464 mIPCOpen = true;
466 if (SessionStorePlatformCollection()) {
467 mSessionStoreChild = SessionStoreChild::GetOrCreate(mBrowsingContext);
470 // We've all set up, make sure our visibility state is consistent. This is
471 // important for OOP iframes, which start off as hidden.
472 UpdateVisibility();
474 return NS_OK;
477 NS_IMPL_CYCLE_COLLECTION_CLASS(BrowserChild)
479 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowserChild)
480 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChildMessageManager)
481 tmp->nsMessageManagerScriptExecutor::Unlink();
482 NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusFilter)
483 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebNav)
484 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
485 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStoreChild)
486 NS_IMPL_CYCLE_COLLECTION_UNLINK(mContentTransformPromise)
487 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
488 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
490 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowserChild)
491 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChildMessageManager)
492 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusFilter)
493 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebNav)
494 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
495 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStoreChild)
496 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContentTransformPromise)
497 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
499 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(BrowserChild)
500 tmp->nsMessageManagerScriptExecutor::Trace(aCallbacks, aClosure);
501 NS_IMPL_CYCLE_COLLECTION_TRACE_END
503 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserChild)
504 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
505 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus)
506 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
507 NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
508 NS_INTERFACE_MAP_ENTRY(nsIBrowserChild)
509 NS_INTERFACE_MAP_ENTRY(nsIObserver)
510 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
511 NS_INTERFACE_MAP_ENTRY(nsITooltipListener)
512 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
513 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener2)
514 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIBrowserChild)
515 NS_INTERFACE_MAP_END
517 NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowserChild)
518 NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowserChild)
520 NS_IMETHODIMP
521 BrowserChild::GetChromeFlags(uint32_t* aChromeFlags) {
522 *aChromeFlags = mChromeFlags;
523 return NS_OK;
526 NS_IMETHODIMP
527 BrowserChild::SetChromeFlags(uint32_t aChromeFlags) {
528 NS_WARNING("trying to SetChromeFlags from content process?");
530 return NS_ERROR_NOT_IMPLEMENTED;
533 NS_IMETHODIMP
534 BrowserChild::RemoteDropLinks(
535 const nsTArray<RefPtr<nsIDroppedLinkItem>>& aLinks) {
536 nsTArray<nsString> linksArray;
537 nsresult rv = NS_OK;
538 for (nsIDroppedLinkItem* link : aLinks) {
539 nsString tmp;
540 rv = link->GetUrl(tmp);
541 if (NS_FAILED(rv)) {
542 return rv;
544 linksArray.AppendElement(tmp);
546 rv = link->GetName(tmp);
547 if (NS_FAILED(rv)) {
548 return rv;
550 linksArray.AppendElement(tmp);
552 rv = link->GetType(tmp);
553 if (NS_FAILED(rv)) {
554 return rv;
556 linksArray.AppendElement(tmp);
558 bool sent = SendDropLinks(linksArray);
560 return sent ? NS_OK : NS_ERROR_FAILURE;
563 NS_IMETHODIMP
564 BrowserChild::ShowAsModal() {
565 NS_WARNING("BrowserChild::ShowAsModal not supported in BrowserChild");
567 return NS_ERROR_NOT_IMPLEMENTED;
570 NS_IMETHODIMP
571 BrowserChild::IsWindowModal(bool* aRetVal) {
572 *aRetVal = false;
573 return NS_OK;
576 NS_IMETHODIMP
577 BrowserChild::SetLinkStatus(const nsAString& aStatusText) {
578 // We can only send the status after the ipc machinery is set up
579 if (IPCOpen()) {
580 SendSetLinkStatus(aStatusText);
582 return NS_OK;
585 NS_IMETHODIMP
586 BrowserChild::SetDimensions(DimensionRequest&& aRequest) {
587 // The parent is in charge of the dimension changes. If JS code wants to
588 // change the dimensions (moveTo, screenX, etc.) we send a message to the
589 // parent about the new requested dimension, the parent does the resize/move
590 // then send a message to the child to update itself. For APIs like screenX
591 // this function is called with only the changed values. In a series of calls
592 // like window.screenX = 10; window.screenY = 10; for the second call, since
593 // screenX is not yet updated we might accidentally reset back screenX to it's
594 // old value. To avoid this, if a parameter did not change, we want the parent
595 // to handle the unchanged values.
597 double scale = mPuppetWidget ? mPuppetWidget->GetDefaultScale().scale : 1.0;
598 SendSetDimensions(aRequest, scale);
599 return NS_OK;
602 NS_IMETHODIMP
603 BrowserChild::GetDimensions(DimensionKind aDimensionKind, int32_t* aX,
604 int32_t* aY, int32_t* aCx, int32_t* aCy) {
605 ScreenIntRect rect = GetOuterRect();
606 if (aDimensionKind == DimensionKind::Inner) {
607 if (aX || aY) {
608 return NS_ERROR_NOT_IMPLEMENTED;
610 rect.SizeTo(GetInnerSize());
612 if (aX) {
613 *aX = rect.x;
615 if (aY) {
616 *aY = rect.y;
618 if (aCx) {
619 *aCx = rect.width;
621 if (aCy) {
622 *aCy = rect.height;
624 return NS_OK;
627 NS_IMETHODIMP
628 BrowserChild::Blur() { return NS_ERROR_NOT_IMPLEMENTED; }
630 NS_IMETHODIMP
631 BrowserChild::FocusNextElement(bool aForDocumentNavigation) {
632 SendMoveFocus(true, aForDocumentNavigation);
633 return NS_OK;
636 NS_IMETHODIMP
637 BrowserChild::FocusPrevElement(bool aForDocumentNavigation) {
638 SendMoveFocus(false, aForDocumentNavigation);
639 return NS_OK;
642 NS_IMETHODIMP
643 BrowserChild::GetInterface(const nsIID& aIID, void** aSink) {
644 // XXXbz should we restrict the set of interfaces we hand out here?
645 // See bug 537429
646 return QueryInterface(aIID, aSink);
649 NS_IMETHODIMP
650 BrowserChild::ProvideWindow(nsIOpenWindowInfo* aOpenWindowInfo,
651 uint32_t aChromeFlags, bool aCalledFromJS,
652 nsIURI* aURI, const nsAString& aName,
653 const nsACString& aFeatures,
654 const UserActivation::Modifiers& aModifiers,
655 bool aForceNoOpener, bool aForceNoReferrer,
656 bool aIsPopupRequested,
657 nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
658 BrowsingContext** aReturn) {
659 *aReturn = nullptr;
661 RefPtr<BrowsingContext> parent = aOpenWindowInfo->GetParent();
663 int32_t openLocation = nsWindowWatcher::GetWindowOpenLocation(
664 parent->GetDOMWindow(), aChromeFlags, aModifiers, aCalledFromJS,
665 aOpenWindowInfo->GetIsForPrinting());
667 // If it turns out we're opening in the current browser, just hand over the
668 // current browser's docshell.
669 if (openLocation == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
670 nsCOMPtr<nsIWebBrowser> browser = do_GetInterface(WebNavigation());
671 *aWindowIsNew = false;
673 nsCOMPtr<mozIDOMWindowProxy> win;
674 MOZ_TRY(browser->GetContentDOMWindow(getter_AddRefs(win)));
676 RefPtr<BrowsingContext> bc(
677 nsPIDOMWindowOuter::From(win)->GetBrowsingContext());
678 bc.forget(aReturn);
679 return NS_OK;
682 // Note that ProvideWindowCommon may return NS_ERROR_ABORT if the
683 // open window call was canceled. It's important that we pass this error
684 // code back to our caller.
685 ContentChild* cc = ContentChild::GetSingleton();
686 return cc->ProvideWindowCommon(
687 WrapNotNull(this), aOpenWindowInfo, aChromeFlags, aCalledFromJS, aURI,
688 aName, aFeatures, aModifiers, aForceNoOpener, aForceNoReferrer,
689 aIsPopupRequested, aLoadState, aWindowIsNew, aReturn);
692 void BrowserChild::DestroyWindow() {
693 mBrowsingContext = nullptr;
695 if (mStatusFilter) {
696 if (nsCOMPtr<nsIWebProgress> webProgress =
697 do_QueryInterface(WebNavigation())) {
698 webProgress->RemoveProgressListener(mStatusFilter);
701 mStatusFilter->RemoveProgressListener(this);
702 mStatusFilter = nullptr;
705 if (mCoalescedMouseEventFlusher) {
706 mCoalescedMouseEventFlusher->RemoveObserver();
707 mCoalescedMouseEventFlusher = nullptr;
710 if (mCoalescedTouchMoveEventFlusher) {
711 mCoalescedTouchMoveEventFlusher->RemoveObserver();
712 mCoalescedTouchMoveEventFlusher = nullptr;
715 if (mSessionStoreChild) {
716 mSessionStoreChild->Stop();
717 mSessionStoreChild = nullptr;
720 // In case we don't have chance to process all entries, clean all data in
721 // the queue.
722 while (mToBeDispatchedMouseData.GetSize() > 0) {
723 UniquePtr<CoalescedMouseData> data(
724 static_cast<CoalescedMouseData*>(mToBeDispatchedMouseData.PopFront()));
725 data.reset();
728 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
729 if (baseWindow) baseWindow->Destroy();
731 if (mPuppetWidget) {
732 mPuppetWidget->Destroy();
735 mLayersConnected = Nothing();
737 if (mLayersId.IsValid()) {
738 StaticMutexAutoLock lock(sBrowserChildrenMutex);
740 MOZ_ASSERT(sBrowserChildren);
741 sBrowserChildren->Remove(uint64_t(mLayersId));
742 if (!sBrowserChildren->Count()) {
743 delete sBrowserChildren;
744 sBrowserChildren = nullptr;
746 mLayersId = layers::LayersId{0};
749 if (mAPZEventState) {
750 mAPZEventState->Destroy();
751 mAPZEventState = nullptr;
755 void BrowserChild::ActorDestroy(ActorDestroyReason why) {
756 mIPCOpen = false;
758 DestroyWindow();
760 if (mBrowserChildMessageManager) {
761 // We should have a message manager if the global is alive, but it
762 // seems sometimes we don't. Assert in aurora/nightly, but don't
763 // crash in release builds.
764 MOZ_DIAGNOSTIC_ASSERT(mBrowserChildMessageManager->GetMessageManager());
765 if (mBrowserChildMessageManager->GetMessageManager()) {
766 // The messageManager relays messages via the BrowserChild which
767 // no longer exists.
768 mBrowserChildMessageManager->DisconnectMessageManager();
772 if (GetTabId() != 0) {
773 NestedBrowserChildMap().erase(GetTabId());
777 BrowserChild::~BrowserChild() {
778 mAnonymousGlobalScopes.Clear();
780 DestroyWindow();
782 nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(WebNavigation());
783 if (webBrowser) {
784 webBrowser->SetContainerWindow(nullptr);
787 mozilla::DropJSObjects(this);
790 mozilla::ipc::IPCResult BrowserChild::RecvWillChangeProcess() {
791 if (mWebBrowser) {
792 mWebBrowser->SetWillChangeProcess();
794 return IPC_OK();
797 mozilla::ipc::IPCResult BrowserChild::RecvLoadURL(
798 nsDocShellLoadState* aLoadState, const ParentShowInfo& aInfo) {
799 if (!mDidLoadURLInit) {
800 mDidLoadURLInit = true;
801 if (!InitBrowserChildMessageManager()) {
802 return IPC_FAIL_NO_REASON(this);
805 ApplyParentShowInfo(aInfo);
807 nsAutoCString spec;
808 aLoadState->URI()->GetSpec(spec);
810 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
811 if (!docShell) {
812 NS_WARNING("WebNavigation does not have a docshell");
813 return IPC_OK();
815 docShell->LoadURI(aLoadState, true);
817 CrashReporter::RecordAnnotationNSCString(CrashReporter::Annotation::URL,
818 spec);
819 return IPC_OK();
822 mozilla::ipc::IPCResult BrowserChild::RecvCreateAboutBlankDocumentViewer(
823 nsIPrincipal* aPrincipal, nsIPrincipal* aPartitionedPrincipal) {
824 if (aPrincipal->GetIsExpandedPrincipal() ||
825 aPartitionedPrincipal->GetIsExpandedPrincipal()) {
826 return IPC_FAIL(this, "Cannot create document with an expanded principal");
828 if (aPrincipal->IsSystemPrincipal() ||
829 aPartitionedPrincipal->IsSystemPrincipal()) {
830 MOZ_ASSERT_UNREACHABLE(
831 "Cannot use CreateAboutBlankDocumentViewer to create system principal "
832 "document in content");
833 return IPC_OK();
836 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
837 if (!docShell) {
838 MOZ_ASSERT_UNREACHABLE("WebNavigation does not have a docshell");
839 return IPC_OK();
842 nsCOMPtr<nsIURI> currentURI;
843 MOZ_ALWAYS_SUCCEEDS(
844 WebNavigation()->GetCurrentURI(getter_AddRefs(currentURI)));
845 if (!currentURI || !NS_IsAboutBlank(currentURI)) {
846 NS_WARNING("Can't create a ContentViewer unless on about:blank");
847 return IPC_OK();
850 docShell->CreateAboutBlankDocumentViewer(aPrincipal, aPartitionedPrincipal,
851 nullptr);
852 return IPC_OK();
855 mozilla::ipc::IPCResult BrowserChild::RecvResumeLoad(
856 const uint64_t& aPendingSwitchID, const ParentShowInfo& aInfo) {
857 if (!mDidLoadURLInit) {
858 mDidLoadURLInit = true;
859 if (!InitBrowserChildMessageManager()) {
860 return IPC_FAIL_NO_REASON(this);
863 ApplyParentShowInfo(aInfo);
866 nsresult rv = WebNavigation()->ResumeRedirectedLoad(aPendingSwitchID, -1);
867 if (NS_FAILED(rv)) {
868 NS_WARNING("WebNavigation()->ResumeRedirectedLoad failed");
871 return IPC_OK();
874 nsresult BrowserChild::CloneDocumentTreeIntoSelf(
875 const MaybeDiscarded<BrowsingContext>& aSourceBC,
876 const embedding::PrintData& aPrintData) {
877 #ifdef NS_PRINTING
878 if (NS_WARN_IF(aSourceBC.IsNullOrDiscarded())) {
879 return NS_ERROR_FAILURE;
881 nsCOMPtr<Document> sourceDocument = aSourceBC.get()->GetDocument();
882 if (NS_WARN_IF(!sourceDocument)) {
883 return NS_ERROR_FAILURE;
886 nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
887 if (NS_WARN_IF(!ourDocShell)) {
888 return NS_ERROR_FAILURE;
891 nsCOMPtr<nsIDocumentViewer> viewer;
892 ourDocShell->GetDocViewer(getter_AddRefs(viewer));
893 if (NS_WARN_IF(!viewer)) {
894 return NS_ERROR_FAILURE;
897 nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
898 do_GetService("@mozilla.org/gfx/printsettings-service;1");
899 if (NS_WARN_IF(!printSettingsSvc)) {
900 return NS_ERROR_FAILURE;
903 nsCOMPtr<nsIPrintSettings> printSettings;
904 nsresult rv =
905 printSettingsSvc->CreateNewPrintSettings(getter_AddRefs(printSettings));
906 if (NS_WARN_IF(NS_FAILED(rv))) {
907 return rv;
910 printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
912 RefPtr<Document> clone;
914 AutoPrintEventDispatcher dispatcher(*sourceDocument);
915 nsAutoScriptBlocker scriptBlocker;
916 bool hasInProcessCallbacks = false;
917 clone = sourceDocument->CreateStaticClone(
918 ourDocShell, viewer, printSettings, &hasInProcessCallbacks);
919 if (NS_WARN_IF(!clone)) {
920 return NS_ERROR_FAILURE;
924 rv = UpdateRemotePrintSettings(aPrintData);
925 if (NS_FAILED(rv)) {
926 return rv;
929 #endif
930 return NS_OK;
933 mozilla::ipc::IPCResult BrowserChild::RecvCloneDocumentTreeIntoSelf(
934 const MaybeDiscarded<BrowsingContext>& aSourceBC,
935 const embedding::PrintData& aPrintData,
936 CloneDocumentTreeIntoSelfResolver&& aResolve) {
937 nsresult rv = NS_OK;
939 #ifdef NS_PRINTING
940 rv = CloneDocumentTreeIntoSelf(aSourceBC, aPrintData);
941 #endif
943 aResolve(NS_SUCCEEDED(rv));
944 return IPC_OK();
947 nsresult BrowserChild::UpdateRemotePrintSettings(
948 const embedding::PrintData& aPrintData) {
949 #ifdef NS_PRINTING
950 nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
951 if (NS_WARN_IF(!ourDocShell)) {
952 return NS_ERROR_FAILURE;
955 RefPtr<Document> doc = ourDocShell->GetExtantDocument();
956 if (NS_WARN_IF(!doc) || NS_WARN_IF(!doc->IsStaticDocument())) {
957 return NS_ERROR_FAILURE;
960 RefPtr<BrowsingContext> bc = ourDocShell->GetBrowsingContext();
961 if (NS_WARN_IF(!bc)) {
962 return NS_ERROR_FAILURE;
965 nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
966 do_GetService("@mozilla.org/gfx/printsettings-service;1");
967 if (NS_WARN_IF(!printSettingsSvc)) {
968 return NS_ERROR_FAILURE;
971 nsCOMPtr<nsIPrintSettings> printSettings;
972 nsresult rv =
973 printSettingsSvc->CreateNewPrintSettings(getter_AddRefs(printSettings));
974 if (NS_WARN_IF(NS_FAILED(rv))) {
975 return rv;
978 printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
980 bc->PreOrderWalk([&](BrowsingContext* aBc) {
981 if (nsCOMPtr<nsIDocShell> inProcess = aBc->GetDocShell()) {
982 nsCOMPtr<nsIDocumentViewer> viewer;
983 inProcess->GetDocViewer(getter_AddRefs(viewer));
984 if (NS_WARN_IF(!viewer)) {
985 return BrowsingContext::WalkFlag::Skip;
987 // The CanRunScript analysis is not smart enough to see across
988 // the std::function PreOrderWalk uses, so we cheat a bit here, but it is
989 // fine because PreOrderWalk does deal with arbitrary script changing the
990 // BC tree, and our code above is simple enough and keeps strong refs to
991 // everything.
992 ([&]() MOZ_CAN_RUN_SCRIPT_BOUNDARY {
993 RefPtr<RemotePrintJobChild> printJob =
994 static_cast<RemotePrintJobChild*>(
995 aPrintData.remotePrintJob().AsChild());
996 viewer->SetPrintSettingsForSubdocument(printSettings, printJob);
997 }());
998 } else if (RefPtr<BrowserBridgeChild> remoteChild =
999 BrowserBridgeChild::GetFrom(aBc->GetEmbedderElement())) {
1000 Unused << remoteChild->SendUpdateRemotePrintSettings(aPrintData);
1001 return BrowsingContext::WalkFlag::Skip;
1003 return BrowsingContext::WalkFlag::Next;
1005 #endif
1007 return NS_OK;
1010 mozilla::ipc::IPCResult BrowserChild::RecvUpdateRemotePrintSettings(
1011 const embedding::PrintData& aPrintData) {
1012 #ifdef NS_PRINTING
1013 UpdateRemotePrintSettings(aPrintData);
1014 #endif
1016 return IPC_OK();
1019 void BrowserChild::DoFakeShow(const ParentShowInfo& aParentShowInfo) {
1020 OwnerShowInfo ownerInfo{ScreenIntSize(), ScrollbarPreference::Auto,
1021 nsSizeMode_Normal};
1022 RecvShow(aParentShowInfo, ownerInfo);
1023 mDidFakeShow = true;
1026 void BrowserChild::ApplyParentShowInfo(const ParentShowInfo& aInfo) {
1027 // Even if we already set real show info, the dpi / rounding & scale may still
1028 // be invalid (if BrowserParent wasn't able to get widget it would just send
1029 // 0). So better to always set up-to-date values here.
1030 if (aInfo.dpi() > 0) {
1031 mPuppetWidget->UpdateBackingScaleCache(aInfo.dpi(), aInfo.widgetRounding(),
1032 aInfo.defaultScale());
1035 if (mDidSetRealShowInfo) {
1036 return;
1039 if (!aInfo.fakeShowInfo()) {
1040 // Once we've got one ShowInfo from parent, no need to update the values
1041 // anymore.
1042 mDidSetRealShowInfo = true;
1045 mIsTransparent = aInfo.isTransparent();
1048 mozilla::ipc::IPCResult BrowserChild::RecvShow(
1049 const ParentShowInfo& aParentInfo, const OwnerShowInfo& aOwnerInfo) {
1050 bool res = true;
1052 mPuppetWidget->SetSizeMode(aOwnerInfo.sizeMode());
1053 if (!mDidFakeShow) {
1054 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
1055 if (!baseWindow) {
1056 NS_ERROR("WebNavigation() doesn't QI to nsIBaseWindow");
1057 return IPC_FAIL_NO_REASON(this);
1060 baseWindow->SetVisibility(true);
1061 res = InitBrowserChildMessageManager();
1064 ApplyParentShowInfo(aParentInfo);
1066 if (!mIsTopLevel) {
1067 RecvScrollbarPreferenceChanged(aOwnerInfo.scrollbarPreference());
1070 if (!res) {
1071 return IPC_FAIL_NO_REASON(this);
1074 UpdateVisibility();
1076 return IPC_OK();
1079 mozilla::ipc::IPCResult BrowserChild::RecvInitRendering(
1080 const TextureFactoryIdentifier& aTextureFactoryIdentifier,
1081 const layers::LayersId& aLayersId,
1082 const CompositorOptions& aCompositorOptions, const bool& aLayersConnected) {
1083 mLayersConnected = Some(aLayersConnected);
1084 mLayersConnectRequested = Some(aLayersConnected);
1085 InitRenderingState(aTextureFactoryIdentifier, aLayersId, aCompositorOptions);
1086 return IPC_OK();
1089 mozilla::ipc::IPCResult BrowserChild::RecvScrollbarPreferenceChanged(
1090 ScrollbarPreference aPreference) {
1091 MOZ_ASSERT(!mIsTopLevel,
1092 "Scrollbar visibility should be derived from chrome flags for "
1093 "top-level windows");
1094 if (nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation())) {
1095 nsDocShell::Cast(docShell)->SetScrollbarPreference(aPreference);
1097 return IPC_OK();
1100 mozilla::ipc::IPCResult BrowserChild::RecvCompositorOptionsChanged(
1101 const CompositorOptions& aNewOptions) {
1102 MOZ_ASSERT(mCompositorOptions);
1104 // The only compositor option we currently support changing is APZ
1105 // enablement. Even that is only partially supported for now:
1106 // * Going from APZ to non-APZ is fine - we just flip the stored flag.
1107 // Note that we keep the actors (mApzcTreeManager, and the APZChild
1108 // created in InitAPZState()) around (read on for why).
1109 // * Going from non-APZ to APZ is only supported if we were using
1110 // APZ initially (at InitRendering() time) and we are transitioning
1111 // back. In this case, we just reuse the actors which we kept around.
1112 // Fully supporting a non-APZ to APZ transition (i.e. even in cases
1113 // where we initialized as non-APZ) would require setting up the actors
1114 // here. (In that case, we would also have the options of destroying
1115 // the actors in the APZ --> non-APZ case, and always re-creating them
1116 // during a non-APZ --> APZ transition).
1117 mCompositorOptions->SetUseAPZ(aNewOptions.UseAPZ());
1118 return IPC_OK();
1121 mozilla::ipc::IPCResult BrowserChild::RecvUpdateDimensions(
1122 const DimensionInfo& aDimensionInfo) {
1123 if (mLayersConnected.isNothing()) {
1124 return IPC_OK();
1127 mUnscaledOuterRect = aDimensionInfo.rect();
1128 mClientOffset = aDimensionInfo.clientOffset();
1129 mChromeOffset = aDimensionInfo.chromeOffset();
1130 MOZ_ASSERT_IF(!IsTopLevel(), mChromeOffset == LayoutDeviceIntPoint());
1132 SetUnscaledInnerSize(aDimensionInfo.size());
1133 if (!mHasValidInnerSize && aDimensionInfo.size().width != 0 &&
1134 aDimensionInfo.size().height != 0) {
1135 mHasValidInnerSize = true;
1138 ScreenIntSize screenSize = GetInnerSize();
1139 ScreenIntRect screenRect = GetOuterRect();
1141 // Make sure to set the size on the document viewer first. The
1142 // MobileViewportManager needs the content viewer size to be updated before
1143 // the reflow, otherwise it gets a stale size when it computes a new CSS
1144 // viewport.
1145 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
1146 baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height,
1147 nsIBaseWindow::eRepaint);
1149 mPuppetWidget->Resize(screenRect.x + mClientOffset.x + mChromeOffset.x,
1150 screenRect.y + mClientOffset.y + mChromeOffset.y,
1151 screenSize.width, screenSize.height, true);
1153 RecvSafeAreaInsetsChanged(mPuppetWidget->GetSafeAreaInsets());
1155 return IPC_OK();
1158 mozilla::ipc::IPCResult BrowserChild::RecvSizeModeChanged(
1159 const nsSizeMode& aSizeMode) {
1160 mPuppetWidget->SetSizeMode(aSizeMode);
1161 if (!mPuppetWidget->IsVisible()) {
1162 return IPC_OK();
1164 nsCOMPtr<Document> document(GetTopLevelDocument());
1165 if (!document) {
1166 return IPC_OK();
1168 nsPresContext* presContext = document->GetPresContext();
1169 if (presContext) {
1170 presContext->SizeModeChanged(aSizeMode);
1172 return IPC_OK();
1175 mozilla::ipc::IPCResult BrowserChild::RecvChildToParentMatrix(
1176 const Maybe<gfx::Matrix4x4>& aMatrix,
1177 const ScreenRect& aTopLevelViewportVisibleRectInBrowserCoords) {
1178 mChildToParentConversionMatrix =
1179 LayoutDeviceToLayoutDeviceMatrix4x4::FromUnknownMatrix(aMatrix);
1180 mTopLevelViewportVisibleRectInBrowserCoords =
1181 aTopLevelViewportVisibleRectInBrowserCoords;
1183 if (mContentTransformPromise) {
1184 mContentTransformPromise->MaybeResolveWithUndefined();
1185 mContentTransformPromise = nullptr;
1188 // Trigger an intersection observation update since ancestor viewports
1189 // changed.
1190 if (RefPtr<Document> toplevelDoc = GetTopLevelDocument()) {
1191 if (nsPresContext* pc = toplevelDoc->GetPresContext()) {
1192 pc->RefreshDriver()->EnsureIntersectionObservationsUpdateHappens();
1196 return IPC_OK();
1199 mozilla::ipc::IPCResult BrowserChild::RecvUpdateRemoteStyle(
1200 const StyleImageRendering& aImageRendering) {
1201 BrowsingContext* context = GetBrowsingContext();
1202 if (!context) {
1203 return IPC_OK();
1206 Document* document = context->GetDocument();
1207 if (!document) {
1208 return IPC_OK();
1211 if (document->IsImageDocument()) {
1212 document->AsImageDocument()->UpdateRemoteStyle(aImageRendering);
1215 return IPC_OK();
1218 mozilla::ipc::IPCResult BrowserChild::RecvDynamicToolbarMaxHeightChanged(
1219 const ScreenIntCoord& aHeight) {
1220 #if defined(MOZ_WIDGET_ANDROID)
1221 mDynamicToolbarMaxHeight = aHeight;
1223 RefPtr<Document> document = GetTopLevelDocument();
1224 if (!document) {
1225 return IPC_OK();
1228 if (RefPtr<nsPresContext> presContext = document->GetPresContext()) {
1229 presContext->SetDynamicToolbarMaxHeight(aHeight);
1231 #endif
1232 return IPC_OK();
1235 mozilla::ipc::IPCResult BrowserChild::RecvDynamicToolbarOffsetChanged(
1236 const ScreenIntCoord& aOffset) {
1237 #if defined(MOZ_WIDGET_ANDROID)
1238 RefPtr<Document> document = GetTopLevelDocument();
1239 if (!document) {
1240 return IPC_OK();
1243 if (nsPresContext* presContext = document->GetPresContext()) {
1244 presContext->UpdateDynamicToolbarOffset(aOffset);
1246 #endif
1247 return IPC_OK();
1250 mozilla::ipc::IPCResult BrowserChild::RecvSuppressDisplayport(
1251 const bool& aEnabled) {
1252 if (RefPtr<PresShell> presShell = GetTopLevelPresShell()) {
1253 presShell->SuppressDisplayport(aEnabled);
1255 return IPC_OK();
1258 void BrowserChild::HandleDoubleTap(const CSSPoint& aPoint,
1259 const Modifiers& aModifiers,
1260 const ScrollableLayerGuid& aGuid,
1261 const DoubleTapToZoomMetrics& aMetrics) {
1262 MOZ_LOG(
1263 sApzChildLog, LogLevel::Debug,
1264 ("Handling double tap at %s with %p %p\n", ToString(aPoint).c_str(),
1265 mBrowserChildMessageManager ? mBrowserChildMessageManager->GetWrapper()
1266 : nullptr,
1267 mBrowserChildMessageManager.get()));
1269 if (!mBrowserChildMessageManager) {
1270 return;
1273 // Note: there is nothing to do with the modifiers here, as we are not
1274 // synthesizing any sort of mouse event.
1275 RefPtr<Document> document = GetTopLevelDocument();
1276 ZoomTarget zoomTarget = CalculateRectToZoomTo(document, aPoint, aMetrics);
1277 // The double-tap can be dispatched by any scroll frame (so |aGuid| could be
1278 // the guid of any scroll frame), but the zoom-to-rect operation must be
1279 // performed by the root content scroll frame, so query its identifiers
1280 // for the SendZoomToRect() call rather than using the ones from |aGuid|.
1281 uint32_t presShellId;
1282 ViewID viewId;
1283 if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(
1284 document->GetDocumentElement(), &presShellId, &viewId) &&
1285 mApzcTreeManager) {
1286 ScrollableLayerGuid guid(mLayersId, presShellId, viewId);
1288 mApzcTreeManager->ZoomToRect(guid, zoomTarget,
1289 ZoomToRectBehavior::DEFAULT_BEHAVIOR);
1293 mozilla::ipc::IPCResult BrowserChild::RecvHandleTap(
1294 const GeckoContentController::TapType& aType,
1295 const LayoutDevicePoint& aPoint, const Modifiers& aModifiers,
1296 const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId,
1297 const Maybe<DoubleTapToZoomMetrics>& aDoubleTapToZoomMetrics) {
1298 // IPDL doesn't hold a strong reference to protocols as they're not required
1299 // to be refcounted. This function can run script, which may trigger a nested
1300 // event loop, which may release this, so we hold a strong reference here.
1301 RefPtr<BrowserChild> kungFuDeathGrip(this);
1302 RefPtr<PresShell> presShell = GetTopLevelPresShell();
1303 if (!presShell || !presShell->GetPresContext() || !mAPZEventState) {
1304 return IPC_OK();
1306 CSSToLayoutDeviceScale scale(
1307 presShell->GetPresContext()->CSSToDevPixelScale());
1308 CSSPoint point = aPoint / scale;
1310 // Stash the guid in InputAPZContext so that when the visual-to-layout
1311 // transform is applied to the event's coordinates, we use the right transform
1312 // based on the scroll frame being targeted.
1313 // The other values don't really matter.
1314 InputAPZContext context(aGuid, aInputBlockId, nsEventStatus_eSentinel);
1316 switch (aType) {
1317 case GeckoContentController::TapType::eSingleTap:
1318 if (mBrowserChildMessageManager) {
1319 RefPtr<APZEventState> eventState(mAPZEventState);
1320 eventState->ProcessSingleTap(point, scale, aModifiers, 1,
1321 aInputBlockId);
1323 break;
1324 case GeckoContentController::TapType::eDoubleTap:
1325 HandleDoubleTap(point, aModifiers, aGuid, *aDoubleTapToZoomMetrics);
1326 break;
1327 case GeckoContentController::TapType::eSecondTap:
1328 if (mBrowserChildMessageManager) {
1329 RefPtr<APZEventState> eventState(mAPZEventState);
1330 eventState->ProcessSingleTap(point, scale, aModifiers, 2,
1331 aInputBlockId);
1333 break;
1334 case GeckoContentController::TapType::eLongTap:
1335 if (mBrowserChildMessageManager) {
1336 RefPtr<APZEventState> eventState(mAPZEventState);
1337 eventState->ProcessLongTap(presShell, point, scale, aModifiers,
1338 aInputBlockId);
1340 break;
1341 case GeckoContentController::TapType::eLongTapUp:
1342 if (mBrowserChildMessageManager) {
1343 RefPtr<APZEventState> eventState(mAPZEventState);
1344 eventState->ProcessLongTapUp(presShell, point, scale, aModifiers);
1346 break;
1348 return IPC_OK();
1351 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityHandleTap(
1352 const GeckoContentController::TapType& aType,
1353 const LayoutDevicePoint& aPoint, const Modifiers& aModifiers,
1354 const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId,
1355 const Maybe<DoubleTapToZoomMetrics>& aDoubleTapToZoomMetrics) {
1356 // IPDL doesn't hold a strong reference to protocols as they're not required
1357 // to be refcounted. This function can run script, which may trigger a nested
1358 // event loop, which may release this, so we hold a strong reference here.
1359 RefPtr<BrowserChild> kungFuDeathGrip(this);
1360 return RecvHandleTap(aType, aPoint, aModifiers, aGuid, aInputBlockId,
1361 aDoubleTapToZoomMetrics);
1364 void BrowserChild::NotifyAPZStateChange(
1365 const ViewID& aViewId,
1366 const layers::GeckoContentController::APZStateChange& aChange,
1367 const int& aArg, Maybe<uint64_t> aInputBlockId) {
1368 if (mAPZEventState) {
1369 mAPZEventState->ProcessAPZStateChange(aViewId, aChange, aArg,
1370 aInputBlockId);
1372 nsCOMPtr<nsIObserverService> observerService =
1373 mozilla::services::GetObserverService();
1374 if (aChange ==
1375 layers::GeckoContentController::APZStateChange::eTransformEnd) {
1376 // This is used by tests to determine when the APZ is done doing whatever
1377 // it's doing. XXX generify this as needed when writing additional tests.
1378 observerService->NotifyObservers(nullptr, "APZ:TransformEnd", nullptr);
1379 observerService->NotifyObservers(nullptr, "PanZoom:StateChange",
1380 u"NOTHING");
1381 } else if (aChange ==
1382 layers::GeckoContentController::APZStateChange::eTransformBegin) {
1383 observerService->NotifyObservers(nullptr, "PanZoom:StateChange",
1384 u"PANNING");
1388 void BrowserChild::StartScrollbarDrag(
1389 const layers::AsyncDragMetrics& aDragMetrics) {
1390 ScrollableLayerGuid guid(mLayersId, aDragMetrics.mPresShellId,
1391 aDragMetrics.mViewId);
1393 if (mApzcTreeManager) {
1394 mApzcTreeManager->StartScrollbarDrag(guid, aDragMetrics);
1398 void BrowserChild::ZoomToRect(const uint32_t& aPresShellId,
1399 const ScrollableLayerGuid::ViewID& aViewId,
1400 const CSSRect& aRect, const uint32_t& aFlags) {
1401 ScrollableLayerGuid guid(mLayersId, aPresShellId, aViewId);
1403 if (mApzcTreeManager) {
1404 mApzcTreeManager->ZoomToRect(guid, ZoomTarget{aRect}, aFlags);
1408 mozilla::ipc::IPCResult BrowserChild::RecvActivate(uint64_t aActionId) {
1409 MOZ_ASSERT(mWebBrowser);
1410 mWebBrowser->FocusActivate(aActionId);
1411 return IPC_OK();
1414 mozilla::ipc::IPCResult BrowserChild::RecvDeactivate(uint64_t aActionId) {
1415 MOZ_ASSERT(mWebBrowser);
1416 mWebBrowser->FocusDeactivate(aActionId);
1417 return IPC_OK();
1420 mozilla::ipc::IPCResult BrowserChild::RecvStopIMEStateManagement() {
1421 IMEStateManager::StopIMEStateManagement();
1422 return IPC_OK();
1425 void BrowserChild::ProcessPendingCoalescedTouchData() {
1426 MOZ_ASSERT(StaticPrefs::dom_events_coalesce_touchmove());
1428 if (mCoalescedTouchData.IsEmpty()) {
1429 return;
1432 if (mCoalescedTouchMoveEventFlusher) {
1433 mCoalescedTouchMoveEventFlusher->RemoveObserver();
1436 UniquePtr<WidgetTouchEvent> touchMoveEvent =
1437 mCoalescedTouchData.TakeCoalescedEvent();
1438 Unused << RecvRealTouchEvent(*touchMoveEvent,
1439 mCoalescedTouchData.GetScrollableLayerGuid(),
1440 mCoalescedTouchData.GetInputBlockId(),
1441 mCoalescedTouchData.GetApzResponse());
1444 void BrowserChild::ProcessPendingCoalescedMouseDataAndDispatchEvents() {
1445 if (!mCoalesceMouseMoveEvents || !mCoalescedMouseEventFlusher) {
1446 // We don't enable mouse coalescing or we are destroying BrowserChild.
1447 return;
1450 // We may reentry the event loop and push more data to
1451 // mToBeDispatchedMouseData while dispatching an event.
1453 // We may have some pending coalesced data while dispatch an event and reentry
1454 // the event loop. In that case we don't have chance to consume the remainding
1455 // pending data until we get new mouse events. Get some helps from
1456 // mCoalescedMouseEventFlusher to trigger it.
1457 mCoalescedMouseEventFlusher->StartObserver();
1459 while (mToBeDispatchedMouseData.GetSize() > 0) {
1460 UniquePtr<CoalescedMouseData> data(
1461 static_cast<CoalescedMouseData*>(mToBeDispatchedMouseData.PopFront()));
1463 UniquePtr<WidgetMouseEvent> event = data->TakeCoalescedEvent();
1464 if (event) {
1465 // Dispatch the pending events. Using HandleRealMouseButtonEvent
1466 // to bypass the coalesce handling in RecvRealMouseMoveEvent. Can't use
1467 // RecvRealMouseButtonEvent because we may also put some mouse events
1468 // other than mousemove.
1469 HandleRealMouseButtonEvent(*event, data->GetScrollableLayerGuid(),
1470 data->GetInputBlockId());
1473 // mCoalescedMouseEventFlusher may be destroyed when reentrying the event
1474 // loop.
1475 if (mCoalescedMouseEventFlusher) {
1476 mCoalescedMouseEventFlusher->RemoveObserver();
1480 LayoutDeviceToLayoutDeviceMatrix4x4
1481 BrowserChild::GetChildToParentConversionMatrix() const {
1482 if (mChildToParentConversionMatrix) {
1483 return *mChildToParentConversionMatrix;
1485 LayoutDevicePoint offset(GetChromeOffset());
1486 return LayoutDeviceToLayoutDeviceMatrix4x4::Translation(offset);
1489 Maybe<ScreenRect> BrowserChild::GetTopLevelViewportVisibleRectInBrowserCoords()
1490 const {
1491 if (!mChildToParentConversionMatrix) {
1492 return Nothing();
1494 return Some(mTopLevelViewportVisibleRectInBrowserCoords);
1497 void BrowserChild::FlushAllCoalescedMouseData() {
1498 MOZ_ASSERT(mCoalesceMouseMoveEvents);
1500 // Move all entries from mCoalescedMouseData to mToBeDispatchedMouseData.
1501 for (const auto& data : mCoalescedMouseData.Values()) {
1502 if (!data || data->IsEmpty()) {
1503 continue;
1505 UniquePtr<CoalescedMouseData> dispatchData =
1506 MakeUnique<CoalescedMouseData>();
1508 dispatchData->RetrieveDataFrom(*data);
1509 mToBeDispatchedMouseData.Push(dispatchData.release());
1511 mCoalescedMouseData.Clear();
1514 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseMoveEvent(
1515 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1516 const uint64_t& aInputBlockId) {
1517 if (mCoalesceMouseMoveEvents && mCoalescedMouseEventFlusher) {
1518 CoalescedMouseData* data =
1519 mCoalescedMouseData.GetOrInsertNew(aEvent.pointerId);
1520 MOZ_ASSERT(data);
1521 if (data->CanCoalesce(aEvent, aGuid, aInputBlockId)) {
1522 data->Coalesce(aEvent, aGuid, aInputBlockId);
1523 mCoalescedMouseEventFlusher->StartObserver();
1524 return IPC_OK();
1526 // Can't coalesce current mousemove event. Put the coalesced mousemove data
1527 // with the same pointer id to mToBeDispatchedMouseData, coalesce the
1528 // current one, and process all pending data in mToBeDispatchedMouseData.
1529 UniquePtr<CoalescedMouseData> dispatchData =
1530 MakeUnique<CoalescedMouseData>();
1532 dispatchData->RetrieveDataFrom(*data);
1533 mToBeDispatchedMouseData.Push(dispatchData.release());
1535 // Put new data to replace the old one in the hash table.
1536 CoalescedMouseData* newData =
1537 mCoalescedMouseData
1538 .InsertOrUpdate(aEvent.pointerId, MakeUnique<CoalescedMouseData>())
1539 .get();
1540 newData->Coalesce(aEvent, aGuid, aInputBlockId);
1542 // Dispatch all pending mouse events.
1543 ProcessPendingCoalescedMouseDataAndDispatchEvents();
1544 mCoalescedMouseEventFlusher->StartObserver();
1545 } else if (!RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId)) {
1546 return IPC_FAIL_NO_REASON(this);
1548 return IPC_OK();
1551 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseMoveEventForTests(
1552 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1553 const uint64_t& aInputBlockId) {
1554 return RecvRealMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1557 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseMoveEvent(
1558 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1559 const uint64_t& aInputBlockId) {
1560 return RecvRealMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1563 mozilla::ipc::IPCResult
1564 BrowserChild::RecvNormalPriorityRealMouseMoveEventForTests(
1565 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1566 const uint64_t& aInputBlockId) {
1567 return RecvRealMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1570 mozilla::ipc::IPCResult BrowserChild::RecvSynthMouseMoveEvent(
1571 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1572 const uint64_t& aInputBlockId) {
1573 if (!RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId)) {
1574 return IPC_FAIL_NO_REASON(this);
1576 return IPC_OK();
1579 mozilla::ipc::IPCResult BrowserChild::RecvNormalPrioritySynthMouseMoveEvent(
1580 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1581 const uint64_t& aInputBlockId) {
1582 return RecvSynthMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1585 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseButtonEvent(
1586 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1587 const uint64_t& aInputBlockId) {
1588 if (mCoalesceMouseMoveEvents && mCoalescedMouseEventFlusher &&
1589 aEvent.mMessage != eMouseMove) {
1590 // When receiving a mouse event other than mousemove, we have to dispatch
1591 // all coalesced events before it. However, we can't dispatch all pending
1592 // coalesced events directly because we may reentry the event loop while
1593 // dispatching. To make sure we won't dispatch disorder events, we move all
1594 // coalesced mousemove events and current event to a deque to dispatch them.
1595 // When reentrying the event loop and dispatching more events, we put new
1596 // events in the end of the nsQueue and dispatch events from the beginning.
1597 FlushAllCoalescedMouseData();
1599 UniquePtr<CoalescedMouseData> dispatchData =
1600 MakeUnique<CoalescedMouseData>();
1602 dispatchData->Coalesce(aEvent, aGuid, aInputBlockId);
1603 mToBeDispatchedMouseData.Push(dispatchData.release());
1605 ProcessPendingCoalescedMouseDataAndDispatchEvents();
1606 return IPC_OK();
1608 HandleRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1609 return IPC_OK();
1612 void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
1613 const ScrollableLayerGuid& aGuid,
1614 const uint64_t& aInputBlockId) {
1615 WidgetMouseEvent localEvent(aEvent);
1616 localEvent.mWidget = mPuppetWidget;
1618 // We need one InputAPZContext here to propagate |aGuid| to places in
1619 // SendSetTargetAPZCNotification() which apply the visual-to-layout transform,
1620 // and another below to propagate the |postLayerization| flag (whose value
1621 // we don't know until SendSetTargetAPZCNotification() returns) into
1622 // the event dispatch code.
1623 InputAPZContext context1(aGuid, aInputBlockId, nsEventStatus_eSentinel);
1625 // Mouse events like eMouseEnterIntoWidget, that are created in the parent
1626 // process EventStateManager code, have an input block id which they get from
1627 // the InputAPZContext in the parent process stack. However, they did not
1628 // actually go through the APZ code and so their mHandledByAPZ flag is false.
1629 // Since thos events didn't go through APZ, we don't need to send
1630 // notifications for them.
1631 RefPtr<DisplayportSetListener> postLayerization;
1632 if (aInputBlockId && localEvent.mFlags.mHandledByAPZ) {
1633 nsCOMPtr<Document> document(GetTopLevelDocument());
1634 postLayerization = APZCCallbackHelper::SendSetTargetAPZCNotification(
1635 mPuppetWidget, document, localEvent, aGuid.mLayersId, aInputBlockId);
1638 InputAPZContext context2(aGuid, aInputBlockId, nsEventStatus_eSentinel,
1639 postLayerization != nullptr);
1641 DispatchWidgetEventViaAPZ(localEvent);
1643 if (aInputBlockId && localEvent.mFlags.mHandledByAPZ && mAPZEventState) {
1644 mAPZEventState->ProcessMouseEvent(localEvent, aInputBlockId);
1647 // Do this after the DispatchWidgetEventViaAPZ call above, so that if the
1648 // mouse event triggered a post-refresh AsyncDragMetrics message to be sent
1649 // to APZ (from scrollbar dragging in nsSliderFrame), then that will reach
1650 // APZ before the SetTargetAPZC message. This ensures the drag input block
1651 // gets the drag metrics before handling the input events.
1652 if (postLayerization) {
1653 postLayerization->Register();
1657 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseButtonEvent(
1658 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1659 const uint64_t& aInputBlockId) {
1660 return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1663 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseEnterExitWidgetEvent(
1664 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1665 const uint64_t& aInputBlockId) {
1666 return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1669 mozilla::ipc::IPCResult
1670 BrowserChild::RecvNormalPriorityRealMouseEnterExitWidgetEvent(
1671 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1672 const uint64_t& aInputBlockId) {
1673 return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1676 nsEventStatus BrowserChild::DispatchWidgetEventViaAPZ(WidgetGUIEvent& aEvent) {
1677 aEvent.ResetWaitingReplyFromRemoteProcessState();
1678 return APZCCallbackHelper::DispatchWidgetEvent(aEvent);
1681 void BrowserChild::DispatchCoalescedWheelEvent() {
1682 UniquePtr<WidgetWheelEvent> wheelEvent =
1683 mCoalescedWheelData.TakeCoalescedEvent();
1684 MOZ_ASSERT(wheelEvent);
1685 DispatchWheelEvent(*wheelEvent, mCoalescedWheelData.GetScrollableLayerGuid(),
1686 mCoalescedWheelData.GetInputBlockId());
1689 void BrowserChild::DispatchWheelEvent(const WidgetWheelEvent& aEvent,
1690 const ScrollableLayerGuid& aGuid,
1691 const uint64_t& aInputBlockId) {
1692 WidgetWheelEvent localEvent(aEvent);
1693 if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) {
1694 nsCOMPtr<Document> document(GetTopLevelDocument());
1695 RefPtr<DisplayportSetListener> postLayerization =
1696 APZCCallbackHelper::SendSetTargetAPZCNotification(
1697 mPuppetWidget, document, aEvent, aGuid.mLayersId, aInputBlockId);
1698 if (postLayerization) {
1699 postLayerization->Register();
1703 localEvent.mWidget = mPuppetWidget;
1705 // Stash the guid in InputAPZContext so that when the visual-to-layout
1706 // transform is applied to the event's coordinates, we use the right transform
1707 // based on the scroll frame being targeted.
1708 // The other values don't really matter.
1709 InputAPZContext context(aGuid, aInputBlockId, nsEventStatus_eSentinel);
1711 DispatchWidgetEventViaAPZ(localEvent);
1713 if (localEvent.mCanTriggerSwipe) {
1714 SendRespondStartSwipeEvent(aInputBlockId, localEvent.TriggersSwipe());
1717 if (aInputBlockId && aEvent.mFlags.mHandledByAPZ && mAPZEventState) {
1718 mAPZEventState->ProcessWheelEvent(localEvent, aInputBlockId);
1722 mozilla::ipc::IPCResult BrowserChild::RecvMouseWheelEvent(
1723 const WidgetWheelEvent& aEvent, const ScrollableLayerGuid& aGuid,
1724 const uint64_t& aInputBlockId) {
1725 bool isNextWheelEvent = false;
1726 // We only coalesce the current event when
1727 // 1. It's eWheel (we don't coalesce eOperationStart and eWheelOperationEnd)
1728 // 2. It has same attributes as the coalesced wheel event which is not yet
1729 // fired.
1730 if (aEvent.mMessage == eWheel) {
1731 GetIPCChannel()->PeekMessages(
1732 [&isNextWheelEvent](const IPC::Message& aMsg) -> bool {
1733 if (aMsg.type() == mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID) {
1734 isNextWheelEvent = true;
1736 return false; // Stop peeking.
1739 if (!mCoalescedWheelData.IsEmpty() &&
1740 !mCoalescedWheelData.CanCoalesce(aEvent, aGuid, aInputBlockId)) {
1741 DispatchCoalescedWheelEvent();
1742 MOZ_ASSERT(mCoalescedWheelData.IsEmpty());
1744 mCoalescedWheelData.Coalesce(aEvent, aGuid, aInputBlockId);
1746 MOZ_ASSERT(!mCoalescedWheelData.IsEmpty());
1747 // If the next event isn't a wheel event, make sure we dispatch.
1748 if (!isNextWheelEvent) {
1749 DispatchCoalescedWheelEvent();
1751 } else {
1752 DispatchWheelEvent(aEvent, aGuid, aInputBlockId);
1755 return IPC_OK();
1758 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityMouseWheelEvent(
1759 const WidgetWheelEvent& aEvent, const ScrollableLayerGuid& aGuid,
1760 const uint64_t& aInputBlockId) {
1761 return RecvMouseWheelEvent(aEvent, aGuid, aInputBlockId);
1764 mozilla::ipc::IPCResult BrowserChild::RecvRealTouchEvent(
1765 const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
1766 const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) {
1767 MOZ_LOG(sApzChildLog, LogLevel::Debug,
1768 ("Receiving touch event of type %d\n", aEvent.mMessage));
1770 if (StaticPrefs::dom_events_coalesce_touchmove()) {
1771 if (aEvent.mMessage == eTouchEnd || aEvent.mMessage == eTouchStart) {
1772 ProcessPendingCoalescedTouchData();
1775 if (aEvent.mMessage != eTouchMove) {
1776 sConsecutiveTouchMoveCount = 0;
1780 WidgetTouchEvent localEvent(aEvent);
1781 localEvent.mWidget = mPuppetWidget;
1783 // Stash the guid in InputAPZContext so that when the visual-to-layout
1784 // transform is applied to the event's coordinates, we use the right transform
1785 // based on the scroll frame being targeted.
1786 // The other values don't really matter.
1787 InputAPZContext context(aGuid, aInputBlockId, aApzResponse);
1789 nsTArray<TouchBehaviorFlags> allowedTouchBehaviors;
1790 if (localEvent.mMessage == eTouchStart && AsyncPanZoomEnabled()) {
1791 nsCOMPtr<Document> document = GetTopLevelDocument();
1792 allowedTouchBehaviors = TouchActionHelper::GetAllowedTouchBehavior(
1793 mPuppetWidget, document, localEvent);
1794 if (!allowedTouchBehaviors.IsEmpty() && mApzcTreeManager) {
1795 mApzcTreeManager->SetAllowedTouchBehavior(aInputBlockId,
1796 allowedTouchBehaviors);
1798 RefPtr<DisplayportSetListener> postLayerization =
1799 APZCCallbackHelper::SendSetTargetAPZCNotification(
1800 mPuppetWidget, document, localEvent, aGuid.mLayersId,
1801 aInputBlockId);
1802 if (postLayerization) {
1803 postLayerization->Register();
1807 // Dispatch event to content (potentially a long-running operation)
1808 nsEventStatus status = DispatchWidgetEventViaAPZ(localEvent);
1810 if (!AsyncPanZoomEnabled()) {
1811 // We shouldn't have any e10s platforms that have touch events enabled
1812 // without APZ.
1813 MOZ_ASSERT(false);
1814 return IPC_OK();
1817 if (mAPZEventState) {
1818 mAPZEventState->ProcessTouchEvent(localEvent, aGuid, aInputBlockId,
1819 aApzResponse, status,
1820 std::move(allowedTouchBehaviors));
1822 return IPC_OK();
1825 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealTouchEvent(
1826 const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
1827 const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) {
1828 return RecvRealTouchEvent(aEvent, aGuid, aInputBlockId, aApzResponse);
1831 mozilla::ipc::IPCResult BrowserChild::RecvRealTouchMoveEvent(
1832 const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
1833 const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) {
1834 if (StaticPrefs::dom_events_coalesce_touchmove()) {
1835 ++sConsecutiveTouchMoveCount;
1836 if (mCoalescedTouchMoveEventFlusher) {
1837 MOZ_ASSERT(aEvent.mMessage == eTouchMove);
1838 if (mCoalescedTouchData.IsEmpty() ||
1839 mCoalescedTouchData.CanCoalesce(aEvent, aGuid, aInputBlockId,
1840 aApzResponse)) {
1841 mCoalescedTouchData.Coalesce(aEvent, aGuid, aInputBlockId,
1842 aApzResponse);
1843 } else {
1844 UniquePtr<WidgetTouchEvent> touchMoveEvent =
1845 mCoalescedTouchData.TakeCoalescedEvent();
1847 mCoalescedTouchData.Coalesce(aEvent, aGuid, aInputBlockId,
1848 aApzResponse);
1850 if (!RecvRealTouchEvent(*touchMoveEvent,
1851 mCoalescedTouchData.GetScrollableLayerGuid(),
1852 mCoalescedTouchData.GetInputBlockId(),
1853 mCoalescedTouchData.GetApzResponse())) {
1854 return IPC_FAIL_NO_REASON(this);
1858 if (sConsecutiveTouchMoveCount > 1) {
1859 mCoalescedTouchMoveEventFlusher->StartObserver();
1860 } else {
1861 // Flush the pending coalesced touch in order to avoid the first
1862 // touchmove be overridden by the second one.
1863 ProcessPendingCoalescedTouchData();
1865 return IPC_OK();
1869 if (!RecvRealTouchEvent(aEvent, aGuid, aInputBlockId, aApzResponse)) {
1870 return IPC_FAIL_NO_REASON(this);
1872 return IPC_OK();
1875 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealTouchMoveEvent(
1876 const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
1877 const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) {
1878 return RecvRealTouchMoveEvent(aEvent, aGuid, aInputBlockId, aApzResponse);
1881 mozilla::ipc::IPCResult BrowserChild::RecvRealDragEvent(
1882 const WidgetDragEvent& aEvent, const uint32_t& aDragAction,
1883 const uint32_t& aDropEffect, nsIPrincipal* aPrincipal,
1884 nsIContentSecurityPolicy* aCsp) {
1885 WidgetDragEvent localEvent(aEvent);
1886 localEvent.mWidget = mPuppetWidget;
1888 nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
1889 if (dragSession) {
1890 dragSession->SetDragAction(aDragAction);
1891 dragSession->SetTriggeringPrincipal(aPrincipal);
1892 dragSession->SetCsp(aCsp);
1893 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
1894 if (initialDataTransfer) {
1895 initialDataTransfer->SetDropEffectInt(aDropEffect);
1899 if (aEvent.mMessage == eDrop) {
1900 bool canDrop = true;
1901 if (!dragSession || NS_FAILED(dragSession->GetCanDrop(&canDrop)) ||
1902 !canDrop) {
1903 localEvent.mMessage = eDragExit;
1905 } else if (aEvent.mMessage == eDragOver) {
1906 nsCOMPtr<nsIDragService> dragService =
1907 do_GetService("@mozilla.org/widget/dragservice;1");
1908 if (dragService) {
1909 // This will dispatch 'drag' event at the source if the
1910 // drag transaction started in this process.
1911 dragService->FireDragEventAtSource(eDrag, aEvent.mModifiers);
1915 DispatchWidgetEventViaAPZ(localEvent);
1916 return IPC_OK();
1919 void BrowserChild::RequestEditCommands(NativeKeyBindingsType aType,
1920 const WidgetKeyboardEvent& aEvent,
1921 nsTArray<CommandInt>& aCommands) {
1922 MOZ_ASSERT(aCommands.IsEmpty());
1924 if (NS_WARN_IF(aEvent.IsEditCommandsInitialized(aType))) {
1925 aCommands = aEvent.EditCommandsConstRef(aType).Clone();
1926 return;
1929 switch (aType) {
1930 case NativeKeyBindingsType::SingleLineEditor:
1931 case NativeKeyBindingsType::MultiLineEditor:
1932 case NativeKeyBindingsType::RichTextEditor:
1933 break;
1934 default:
1935 MOZ_ASSERT_UNREACHABLE("Invalid native key bindings type");
1938 // Don't send aEvent to the parent process directly because it'll be marked
1939 // as posted to remote process.
1940 WidgetKeyboardEvent localEvent(aEvent);
1941 SendRequestNativeKeyBindings(static_cast<uint32_t>(aType), localEvent,
1942 &aCommands);
1945 mozilla::ipc::IPCResult BrowserChild::RecvNativeSynthesisResponse(
1946 const uint64_t& aObserverId, const nsCString& aResponse) {
1947 mozilla::widget::AutoObserverNotifier::NotifySavedObserver(aObserverId,
1948 aResponse.get());
1949 return IPC_OK();
1952 mozilla::ipc::IPCResult BrowserChild::RecvUpdateSHistory() {
1953 if (mSessionStoreChild) {
1954 mSessionStoreChild->UpdateSHistoryChanges();
1956 return IPC_OK();
1959 // In case handling repeated keys takes much time, we skip firing new ones.
1960 bool BrowserChild::SkipRepeatedKeyEvent(const WidgetKeyboardEvent& aEvent) {
1961 if (mRepeatedKeyEventTime.IsNull() || !aEvent.CanSkipInRemoteProcess() ||
1962 (aEvent.mMessage != eKeyDown && aEvent.mMessage != eKeyPress)) {
1963 mRepeatedKeyEventTime = TimeStamp();
1964 mSkipKeyPress = false;
1965 return false;
1968 if ((aEvent.mMessage == eKeyDown &&
1969 (mRepeatedKeyEventTime > aEvent.mTimeStamp)) ||
1970 (mSkipKeyPress && (aEvent.mMessage == eKeyPress))) {
1971 // If we skip a keydown event, also the following keypress events should be
1972 // skipped.
1973 mSkipKeyPress |= aEvent.mMessage == eKeyDown;
1974 return true;
1977 if (aEvent.mMessage == eKeyDown) {
1978 // If keydown wasn't skipped, nor should the possible following keypress.
1979 mRepeatedKeyEventTime = TimeStamp();
1980 mSkipKeyPress = false;
1982 return false;
1985 void BrowserChild::UpdateRepeatedKeyEventEndTime(
1986 const WidgetKeyboardEvent& aEvent) {
1987 if (aEvent.mIsRepeat &&
1988 (aEvent.mMessage == eKeyDown || aEvent.mMessage == eKeyPress)) {
1989 mRepeatedKeyEventTime = TimeStamp::Now();
1993 mozilla::ipc::IPCResult BrowserChild::RecvRealKeyEvent(
1994 const WidgetKeyboardEvent& aEvent, const nsID& aUUID) {
1995 MOZ_ASSERT_IF(aEvent.mMessage == eKeyPress,
1996 aEvent.AreAllEditCommandsInitialized());
1998 // If content code called preventDefault() on a keydown event, then we don't
1999 // want to process any following keypress events.
2000 const bool isPrecedingKeyDownEventConsumed =
2001 aEvent.mMessage == eKeyPress && mIgnoreKeyPressEvent;
2003 WidgetKeyboardEvent localEvent(aEvent);
2004 localEvent.mWidget = mPuppetWidget;
2005 localEvent.mUniqueId = aEvent.mUniqueId;
2007 if (!SkipRepeatedKeyEvent(aEvent) && !isPrecedingKeyDownEventConsumed) {
2008 nsEventStatus status = DispatchWidgetEventViaAPZ(localEvent);
2010 // Update the end time of the possible repeated event so that we can skip
2011 // some incoming events in case event handling took long time.
2012 UpdateRepeatedKeyEventEndTime(localEvent);
2014 if (aEvent.mMessage == eKeyDown) {
2015 mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
2018 if (localEvent.mFlags.mIsSuppressedOrDelayed) {
2019 localEvent.PreventDefault();
2022 // If the event's default isn't prevented but the status is no default,
2023 // That means that the event was consumed by EventStateManager or something
2024 // which is not a usual event handler. In such case, prevent its default
2025 // as a default handler. For example, when an eKeyPress event matches
2026 // with a content accesskey, and it's executed, preventDefault() of the
2027 // event won't be called but the status is set to "no default". Then,
2028 // the event shouldn't be handled by nsMenuBarListener in the main process.
2029 if (!localEvent.DefaultPrevented() &&
2030 status == nsEventStatus_eConsumeNoDefault) {
2031 localEvent.PreventDefault();
2034 MOZ_DIAGNOSTIC_ASSERT(!localEvent.PropagationStopped());
2036 // The keyboard event which we ignore should not be handled in the main
2037 // process for shortcut key handling. For notifying if we skipped it, we can
2038 // use "stop propagation" flag here because it must be cleared by
2039 // `EventTargetChainItem` if we've dispatched it.
2040 else {
2041 localEvent.StopPropagation();
2044 // If we don't need to send a rely for the given keyboard event, we do nothing
2045 // anymore here.
2046 if (!aEvent.WantReplyFromContentProcess()) {
2047 return IPC_OK();
2050 // This is an ugly hack, mNoRemoteProcessDispatch is set to true when the
2051 // event's PreventDefault() or StopScrollProcessForwarding() is called.
2052 // And then, it'll be checked by ParamTraits<mozilla::WidgetEvent>::Write()
2053 // whether the event is being sent to remote process unexpectedly.
2054 // However, unfortunately, it cannot check the destination. Therefore,
2055 // we need to clear the flag explicitly here because ParamTraits should
2056 // keep checking the flag for avoiding regression.
2057 localEvent.mFlags.mNoRemoteProcessDispatch = false;
2058 SendReplyKeyEvent(localEvent, aUUID);
2060 return IPC_OK();
2063 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealKeyEvent(
2064 const WidgetKeyboardEvent& aEvent, const nsID& aUUID) {
2065 return RecvRealKeyEvent(aEvent, aUUID);
2068 mozilla::ipc::IPCResult BrowserChild::RecvCompositionEvent(
2069 const WidgetCompositionEvent& aEvent) {
2070 WidgetCompositionEvent localEvent(aEvent);
2071 localEvent.mWidget = mPuppetWidget;
2072 DispatchWidgetEventViaAPZ(localEvent);
2073 Unused << SendOnEventNeedingAckHandled(aEvent.mMessage,
2074 localEvent.mCompositionId);
2075 return IPC_OK();
2078 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityCompositionEvent(
2079 const WidgetCompositionEvent& aEvent) {
2080 return RecvCompositionEvent(aEvent);
2083 mozilla::ipc::IPCResult BrowserChild::RecvSelectionEvent(
2084 const WidgetSelectionEvent& aEvent) {
2085 WidgetSelectionEvent localEvent(aEvent);
2086 localEvent.mWidget = mPuppetWidget;
2087 DispatchWidgetEventViaAPZ(localEvent);
2088 Unused << SendOnEventNeedingAckHandled(aEvent.mMessage, 0u);
2089 return IPC_OK();
2092 mozilla::ipc::IPCResult BrowserChild::RecvNormalPrioritySelectionEvent(
2093 const WidgetSelectionEvent& aEvent) {
2094 return RecvSelectionEvent(aEvent);
2097 mozilla::ipc::IPCResult BrowserChild::RecvInsertText(
2098 const nsAString& aStringToInsert) {
2099 // Use normal event path to reach focused document.
2100 WidgetContentCommandEvent localEvent(true, eContentCommandInsertText,
2101 mPuppetWidget);
2102 localEvent.mString = Some(nsString(aStringToInsert));
2103 DispatchWidgetEventViaAPZ(localEvent);
2104 return IPC_OK();
2107 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityInsertText(
2108 const nsAString& aStringToInsert) {
2109 return RecvInsertText(aStringToInsert);
2112 mozilla::ipc::IPCResult BrowserChild::RecvPasteTransferable(
2113 const IPCTransferable& aTransferable) {
2114 nsresult rv;
2115 nsCOMPtr<nsITransferable> trans =
2116 do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
2117 NS_ENSURE_SUCCESS(rv, IPC_OK());
2118 trans->Init(nullptr);
2120 rv = nsContentUtils::IPCTransferableToTransferable(
2121 aTransferable, true /* aAddDataFlavor */, trans,
2122 false /* aFilterUnknownFlavors */);
2123 NS_ENSURE_SUCCESS(rv, IPC_OK());
2125 nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
2126 if (NS_WARN_IF(!ourDocShell)) {
2127 return IPC_OK();
2130 RefPtr<nsCommandParams> params = new nsCommandParams();
2131 rv = params->SetISupports("transferable", trans);
2132 NS_ENSURE_SUCCESS(rv, IPC_OK());
2134 ourDocShell->DoCommandWithParams("cmd_pasteTransferable", params);
2135 return IPC_OK();
2138 #ifdef ACCESSIBILITY
2139 a11y::PDocAccessibleChild* BrowserChild::AllocPDocAccessibleChild(
2140 PDocAccessibleChild*, const uint64_t&,
2141 const MaybeDiscardedBrowsingContext&) {
2142 MOZ_ASSERT(false, "should never call this!");
2143 return nullptr;
2146 bool BrowserChild::DeallocPDocAccessibleChild(
2147 a11y::PDocAccessibleChild* aChild) {
2148 delete static_cast<mozilla::a11y::DocAccessibleChild*>(aChild);
2149 return true;
2151 #endif
2153 RefPtr<VsyncMainChild> BrowserChild::GetVsyncChild() {
2154 // Initializing mVsyncChild here turns on per-BrowserChild Vsync for a
2155 // given platform. Note: this only makes sense if nsWindow returns a
2156 // window-specific VsyncSource.
2157 #if defined(MOZ_WAYLAND)
2158 if (IsWaylandEnabled() && !mVsyncChild) {
2159 mVsyncChild = MakeRefPtr<VsyncMainChild>();
2160 if (!SendPVsyncConstructor(mVsyncChild)) {
2161 mVsyncChild = nullptr;
2164 #endif
2165 return mVsyncChild;
2168 mozilla::ipc::IPCResult BrowserChild::RecvLoadRemoteScript(
2169 const nsAString& aURL, const bool& aRunInGlobalScope) {
2170 if (!InitBrowserChildMessageManager())
2171 // This can happen if we're half-destroyed. It's not a fatal
2172 // error.
2173 return IPC_OK();
2175 JS::Rooted<JSObject*> mm(RootingCx(),
2176 mBrowserChildMessageManager->GetOrCreateWrapper());
2177 if (!mm) {
2178 // This can happen if we're half-destroyed. It's not a fatal error.
2179 return IPC_OK();
2182 LoadScriptInternal(mm, aURL, !aRunInGlobalScope);
2183 return IPC_OK();
2186 mozilla::ipc::IPCResult BrowserChild::RecvAsyncMessage(
2187 const nsAString& aMessage, const ClonedMessageData& aData) {
2188 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("BrowserChild::RecvAsyncMessage",
2189 OTHER, aMessage);
2190 MMPrinter::Print("BrowserChild::RecvAsyncMessage", aMessage, aData);
2192 if (!mBrowserChildMessageManager) {
2193 return IPC_OK();
2196 RefPtr<nsFrameMessageManager> mm =
2197 mBrowserChildMessageManager->GetMessageManager();
2199 // We should have a message manager if the global is alive, but it
2200 // seems sometimes we don't. Assert in aurora/nightly, but don't
2201 // crash in release builds.
2202 MOZ_DIAGNOSTIC_ASSERT(mm);
2203 if (!mm) {
2204 return IPC_OK();
2207 JS::Rooted<JSObject*> kungFuDeathGrip(
2208 dom::RootingCx(), mBrowserChildMessageManager->GetWrapper());
2209 StructuredCloneData data;
2210 UnpackClonedMessageData(aData, data);
2211 mm->ReceiveMessage(static_cast<EventTarget*>(mBrowserChildMessageManager),
2212 nullptr, aMessage, false, &data, nullptr, IgnoreErrors());
2213 return IPC_OK();
2216 mozilla::ipc::IPCResult BrowserChild::RecvSwappedWithOtherRemoteLoader(
2217 const IPCTabContext& aContext) {
2218 nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
2219 if (NS_WARN_IF(!ourDocShell)) {
2220 return IPC_OK();
2223 nsCOMPtr<nsPIDOMWindowOuter> ourWindow = ourDocShell->GetWindow();
2224 if (NS_WARN_IF(!ourWindow)) {
2225 return IPC_OK();
2228 RefPtr<nsDocShell> docShell = static_cast<nsDocShell*>(ourDocShell.get());
2230 nsCOMPtr<EventTarget> ourEventTarget = nsGlobalWindowOuter::Cast(ourWindow);
2232 docShell->SetInFrameSwap(true);
2234 nsContentUtils::FirePageShowEventForFrameLoaderSwap(
2235 ourDocShell, ourEventTarget, false, true);
2236 nsContentUtils::FirePageHideEventForFrameLoaderSwap(ourDocShell,
2237 ourEventTarget, true);
2239 // Owner content type may have changed, so store the possibly updated context
2240 // and notify others.
2241 MaybeInvalidTabContext maybeContext(aContext);
2242 if (!maybeContext.IsValid()) {
2243 NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
2244 "the parent process. (%s)",
2245 maybeContext.GetInvalidReason())
2246 .get());
2247 MOZ_CRASH("Invalid TabContext received from the parent process.");
2250 if (!UpdateTabContextAfterSwap(maybeContext.GetTabContext())) {
2251 MOZ_CRASH("Update to TabContext after swap was denied.");
2254 // Ignore previous value of mTriedBrowserInit since owner content has changed.
2255 mTriedBrowserInit = true;
2257 nsContentUtils::FirePageShowEventForFrameLoaderSwap(
2258 ourDocShell, ourEventTarget, true, true);
2260 docShell->SetInFrameSwap(false);
2262 // This is needed to get visibility state right in cases when we swapped a
2263 // visible tab (foreground in visible window) with a non-visible tab.
2264 if (RefPtr<Document> doc = docShell->GetDocument()) {
2265 doc->UpdateVisibilityState();
2268 return IPC_OK();
2271 mozilla::ipc::IPCResult BrowserChild::RecvHandleAccessKey(
2272 const WidgetKeyboardEvent& aEvent, nsTArray<uint32_t>&& aCharCodes) {
2273 nsCOMPtr<Document> document(GetTopLevelDocument());
2274 RefPtr<nsPresContext> pc = document->GetPresContext();
2275 if (pc) {
2276 if (!pc->EventStateManager()->HandleAccessKey(
2277 &(const_cast<WidgetKeyboardEvent&>(aEvent)), pc, aCharCodes)) {
2278 // If no accesskey was found, inform the parent so that accesskeys on
2279 // menus can be handled.
2280 WidgetKeyboardEvent localEvent(aEvent);
2281 localEvent.mWidget = mPuppetWidget;
2282 SendAccessKeyNotHandled(localEvent);
2286 return IPC_OK();
2289 mozilla::ipc::IPCResult BrowserChild::RecvPrintPreview(
2290 const PrintData& aPrintData, const MaybeDiscardedBrowsingContext& aSourceBC,
2291 PrintPreviewResolver&& aCallback) {
2292 #ifdef NS_PRINTING
2293 // If we didn't succeed in passing off ownership of aCallback, then something
2294 // went wrong.
2295 auto sendCallbackError = MakeScopeExit([&] {
2296 if (aCallback) {
2297 // signal error
2298 aCallback(PrintPreviewResultInfo(0, 0, false, false, false, {}, {}, {}));
2302 if (NS_WARN_IF(aSourceBC.IsDiscarded())) {
2303 return IPC_OK();
2306 RefPtr<nsGlobalWindowOuter> sourceWindow;
2307 if (!aSourceBC.IsNull()) {
2308 sourceWindow = nsGlobalWindowOuter::Cast(aSourceBC.get()->GetDOMWindow());
2309 if (NS_WARN_IF(!sourceWindow)) {
2310 return IPC_OK();
2312 } else {
2313 nsCOMPtr<nsPIDOMWindowOuter> ourWindow = do_GetInterface(WebNavigation());
2314 if (NS_WARN_IF(!ourWindow)) {
2315 return IPC_OK();
2317 sourceWindow = nsGlobalWindowOuter::Cast(ourWindow);
2320 RefPtr<nsIPrintSettings> printSettings;
2321 nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
2322 do_GetService("@mozilla.org/gfx/printsettings-service;1");
2323 if (NS_WARN_IF(!printSettingsSvc)) {
2324 return IPC_OK();
2326 printSettingsSvc->CreateNewPrintSettings(getter_AddRefs(printSettings));
2327 if (NS_WARN_IF(!printSettings)) {
2328 return IPC_OK();
2330 printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
2332 nsCOMPtr<nsIDocShell> docShellToCloneInto;
2333 if (!aSourceBC.IsNull()) {
2334 docShellToCloneInto = do_GetInterface(WebNavigation());
2335 if (NS_WARN_IF(!docShellToCloneInto)) {
2336 return IPC_OK();
2340 sourceWindow->Print(printSettings,
2341 /* aRemotePrintJob = */ nullptr,
2342 /* aListener = */ nullptr, docShellToCloneInto,
2343 nsGlobalWindowOuter::IsPreview::Yes,
2344 nsGlobalWindowOuter::IsForWindowDotPrint::No,
2345 std::move(aCallback), nullptr, IgnoreErrors());
2346 #endif
2347 return IPC_OK();
2350 mozilla::ipc::IPCResult BrowserChild::RecvExitPrintPreview() {
2351 #ifdef NS_PRINTING
2352 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint =
2353 do_GetInterface(ToSupports(WebNavigation()));
2354 if (NS_WARN_IF(!webBrowserPrint)) {
2355 return IPC_OK();
2357 webBrowserPrint->ExitPrintPreview();
2358 #endif
2359 return IPC_OK();
2362 mozilla::ipc::IPCResult BrowserChild::CommonPrint(
2363 const MaybeDiscardedBrowsingContext& aBc, const PrintData& aPrintData,
2364 RefPtr<BrowsingContext>* aCachedBrowsingContext) {
2365 #ifdef NS_PRINTING
2366 if (NS_WARN_IF(aBc.IsNullOrDiscarded())) {
2367 return IPC_OK();
2369 RefPtr<nsGlobalWindowOuter> outerWindow =
2370 nsGlobalWindowOuter::Cast(aBc.get()->GetDOMWindow());
2371 if (NS_WARN_IF(!outerWindow)) {
2372 return IPC_OK();
2375 nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
2376 do_GetService("@mozilla.org/gfx/printsettings-service;1");
2377 if (NS_WARN_IF(!printSettingsSvc)) {
2378 return IPC_OK();
2381 nsCOMPtr<nsIPrintSettings> printSettings;
2382 nsresult rv =
2383 printSettingsSvc->CreateNewPrintSettings(getter_AddRefs(printSettings));
2384 if (NS_WARN_IF(NS_FAILED(rv))) {
2385 return IPC_OK();
2388 printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
2390 IgnoredErrorResult rv;
2391 RefPtr printJob = static_cast<RemotePrintJobChild*>(
2392 aPrintData.remotePrintJob().AsChild());
2393 outerWindow->Print(
2394 printSettings, printJob,
2395 /* aListener = */ nullptr,
2396 /* aWindowToCloneInto = */ nullptr, nsGlobalWindowOuter::IsPreview::No,
2397 nsGlobalWindowOuter::IsForWindowDotPrint::No,
2398 /* aPrintPreviewCallback = */ nullptr, aCachedBrowsingContext, rv);
2399 if (NS_WARN_IF(rv.Failed())) {
2400 return IPC_OK();
2403 #endif
2404 return IPC_OK();
2407 mozilla::ipc::IPCResult BrowserChild::RecvPrint(
2408 const MaybeDiscardedBrowsingContext& aBc, const PrintData& aPrintData,
2409 bool aReturnStaticClone, PrintResolver&& aResolve) {
2410 #ifdef NS_PRINTING
2411 RefPtr<BrowsingContext> browsingContext;
2412 auto result = CommonPrint(aBc, aPrintData,
2413 aReturnStaticClone ? &browsingContext : nullptr);
2414 aResolve(browsingContext);
2415 return result;
2416 #else
2417 aResolve(nullptr);
2418 return IPC_OK();
2419 #endif
2422 mozilla::ipc::IPCResult BrowserChild::RecvPrintClonedPage(
2423 const MaybeDiscardedBrowsingContext& aBc, const PrintData& aPrintData,
2424 const MaybeDiscardedBrowsingContext& aClonedBc) {
2425 #ifdef NS_PRINTING
2426 if (aClonedBc.IsNullOrDiscarded()) {
2427 return IPC_OK();
2429 RefPtr<BrowsingContext> clonedBc = aClonedBc.get();
2430 return CommonPrint(aBc, aPrintData, &clonedBc);
2431 #else
2432 return IPC_OK();
2433 #endif
2436 mozilla::ipc::IPCResult BrowserChild::RecvDestroyPrintClone(
2437 const MaybeDiscardedBrowsingContext& aCachedPage) {
2438 #ifdef NS_PRINTING
2439 if (aCachedPage) {
2440 RefPtr<nsPIDOMWindowOuter> window = aCachedPage->GetDOMWindow();
2441 if (NS_WARN_IF(!window)) {
2442 return IPC_OK();
2444 window->Close();
2446 #endif
2447 return IPC_OK();
2450 mozilla::ipc::IPCResult BrowserChild::RecvUpdateNativeWindowHandle(
2451 const uintptr_t& aNewHandle) {
2452 #if defined(XP_WIN) && defined(ACCESSIBILITY)
2453 mNativeWindowHandle = aNewHandle;
2454 return IPC_OK();
2455 #else
2456 return IPC_FAIL_NO_REASON(this);
2457 #endif
2460 mozilla::ipc::IPCResult BrowserChild::RecvDestroy() {
2461 MOZ_ASSERT(!mDestroyed);
2462 mDestroyed = true;
2464 nsTArray<PContentPermissionRequestChild*> childArray =
2465 nsContentPermissionUtils::GetContentPermissionRequestChildById(
2466 GetTabId());
2468 // Need to close undeleted ContentPermissionRequestChilds before tab is
2469 // closed.
2470 for (auto& permissionRequestChild : childArray) {
2471 auto* child = static_cast<RemotePermissionRequest*>(permissionRequestChild);
2472 child->Destroy();
2475 if (mBrowserChildMessageManager) {
2476 // Message handlers are called from the event loop, so it better be safe to
2477 // run script.
2478 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
2479 mBrowserChildMessageManager->DispatchTrustedEvent(u"unload"_ns);
2482 nsCOMPtr<nsIObserverService> observerService =
2483 mozilla::services::GetObserverService();
2485 observerService->RemoveObserver(this, BEFORE_FIRST_PAINT);
2487 // XXX what other code in ~BrowserChild() should we be running here?
2488 DestroyWindow();
2490 // Bounce through the event loop once to allow any delayed teardown runnables
2491 // that were just generated to have a chance to run.
2492 nsCOMPtr<nsIRunnable> deleteRunnable = new DelayedDeleteRunnable(this);
2493 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(deleteRunnable));
2495 return IPC_OK();
2498 mozilla::ipc::IPCResult BrowserChild::RecvRenderLayers(const bool& aEnabled) {
2499 auto clearPaintWhileInterruptingJS = MakeScopeExit([&] {
2500 // We might force a paint, or we might already have painted and this is a
2501 // no-op. In either case, once we exit this scope, we need to alert the
2502 // ProcessHangMonitor that we've finished responding to what might have
2503 // been a request to force paint. This is so that the BackgroundHangMonitor
2504 // for force painting can be made to wait again.
2505 if (aEnabled) {
2506 ProcessHangMonitor::ClearPaintWhileInterruptingJS();
2510 if (aEnabled) {
2511 ProcessHangMonitor::MaybeStartPaintWhileInterruptingJS();
2514 mRenderLayers = aEnabled;
2515 const bool wasVisible = IsVisible();
2517 UpdateVisibility();
2519 // If we just became visible, try to trigger a paint as soon as possible.
2520 const bool becameVisible = !wasVisible && IsVisible();
2521 if (!becameVisible) {
2522 return IPC_OK();
2525 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2526 if (!docShell) {
2527 return IPC_OK();
2530 // We don't use BrowserChildBase::GetPresShell() here because that would
2531 // create a content viewer if one doesn't exist yet. Creating a content
2532 // viewer can cause JS to run, which we want to avoid.
2533 // nsIDocShell::GetPresShell returns null if no content viewer exists yet.
2534 RefPtr<PresShell> presShell = docShell->GetPresShell();
2535 if (!presShell) {
2536 return IPC_OK();
2539 if (nsIFrame* root = presShell->GetRootFrame()) {
2540 root->SchedulePaint();
2543 Telemetry::AutoTimer<Telemetry::TABCHILD_PAINT_TIME> timer;
2544 // If we need to repaint, let's do that right away. No sense waiting until
2545 // we get back to the event loop again. We suppress the display port so
2546 // that we only paint what's visible. This ensures that the tab we're
2547 // switching to paints as quickly as possible.
2548 presShell->SuppressDisplayport(true);
2549 if (nsContentUtils::IsSafeToRunScript()) {
2550 WebWidget()->PaintNowIfNeeded();
2551 } else {
2552 RefPtr<nsViewManager> vm = presShell->GetViewManager();
2553 if (nsView* view = vm->GetRootView()) {
2554 presShell->PaintAndRequestComposite(view, PaintFlags::None);
2557 presShell->SuppressDisplayport(false);
2558 return IPC_OK();
2561 mozilla::ipc::IPCResult BrowserChild::RecvNavigateByKey(
2562 const bool& aForward, const bool& aForDocumentNavigation) {
2563 nsFocusManager* fm = nsFocusManager::GetFocusManager();
2564 if (!fm) {
2565 return IPC_OK();
2568 RefPtr<Element> result;
2569 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
2571 // Move to the first or last document.
2573 uint32_t type =
2574 aForward
2575 ? (aForDocumentNavigation
2576 ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FIRSTDOC)
2577 : StaticPrefs::dom_disable_tab_focus_to_root_element()
2578 ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FIRST)
2579 : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_ROOT))
2580 : (aForDocumentNavigation
2581 ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LASTDOC)
2582 : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LAST));
2583 uint32_t flags = nsIFocusManager::FLAG_BYKEY;
2584 if (aForward || aForDocumentNavigation) {
2585 flags |= nsIFocusManager::FLAG_NOSCROLL;
2587 fm->MoveFocus(window, nullptr, type, flags, getter_AddRefs(result));
2590 // No valid root element was found, so move to the first focusable element.
2591 if (!result && aForward && !aForDocumentNavigation) {
2592 fm->MoveFocus(window, nullptr, nsIFocusManager::MOVEFOCUS_FIRST,
2593 nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
2596 SendRequestFocus(false, CallerType::System);
2597 return IPC_OK();
2600 bool BrowserChild::InitBrowserChildMessageManager() {
2601 mShouldSendWebProgressEventsToParent = true;
2603 if (!mBrowserChildMessageManager) {
2604 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
2605 NS_ENSURE_TRUE(window, false);
2606 nsCOMPtr<EventTarget> chromeHandler = window->GetChromeEventHandler();
2607 NS_ENSURE_TRUE(chromeHandler, false);
2609 RefPtr<BrowserChildMessageManager> scope = mBrowserChildMessageManager =
2610 new BrowserChildMessageManager(this);
2612 MOZ_ALWAYS_TRUE(nsMessageManagerScriptExecutor::Init());
2614 nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
2615 if (NS_WARN_IF(!root)) {
2616 mBrowserChildMessageManager = nullptr;
2617 return false;
2619 root->SetParentTarget(scope);
2622 if (!mTriedBrowserInit) {
2623 mTriedBrowserInit = true;
2626 return true;
2629 void BrowserChild::InitRenderingState(
2630 const TextureFactoryIdentifier& aTextureFactoryIdentifier,
2631 const layers::LayersId& aLayersId,
2632 const CompositorOptions& aCompositorOptions) {
2633 mPuppetWidget->InitIMEState();
2635 MOZ_ASSERT(aLayersId.IsValid());
2636 mTextureFactoryIdentifier = aTextureFactoryIdentifier;
2638 // Pushing layers transactions directly to a separate
2639 // compositor context.
2640 PCompositorBridgeChild* compositorChild = CompositorBridgeChild::Get();
2641 if (!compositorChild) {
2642 mLayersConnected = Some(false);
2643 NS_WARNING("failed to get CompositorBridgeChild instance");
2644 return;
2647 mCompositorOptions = Some(aCompositorOptions);
2649 if (aLayersId.IsValid()) {
2650 StaticMutexAutoLock lock(sBrowserChildrenMutex);
2652 if (!sBrowserChildren) {
2653 sBrowserChildren = new BrowserChildMap;
2655 MOZ_ASSERT(!sBrowserChildren->Contains(uint64_t(aLayersId)));
2656 sBrowserChildren->InsertOrUpdate(uint64_t(aLayersId), this);
2657 mLayersId = aLayersId;
2660 // Depending on timing, we might paint too early and fall back to basic
2661 // layers. CreateRemoteLayerManager will destroy us if we manage to get a
2662 // remote layer manager though, so that's fine.
2663 MOZ_ASSERT(!mPuppetWidget->HasWindowRenderer() ||
2664 mPuppetWidget->GetWindowRenderer()->GetBackendType() ==
2665 layers::LayersBackend::LAYERS_NONE);
2666 bool success = false;
2667 if (mLayersConnected == Some(true)) {
2668 success = CreateRemoteLayerManager(compositorChild);
2671 if (success) {
2672 MOZ_ASSERT(mLayersConnected == Some(true));
2673 // Succeeded to create "remote" layer manager
2674 ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
2675 gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
2676 InitAPZState();
2677 } else {
2678 NS_WARNING("Fallback to FallbackRenderer");
2679 mLayersConnected = Some(false);
2682 nsCOMPtr<nsIObserverService> observerService =
2683 mozilla::services::GetObserverService();
2685 if (observerService) {
2686 observerService->AddObserver(this, BEFORE_FIRST_PAINT, false);
2690 bool BrowserChild::CreateRemoteLayerManager(
2691 mozilla::layers::PCompositorBridgeChild* aCompositorChild) {
2692 MOZ_ASSERT(aCompositorChild);
2694 return mPuppetWidget->CreateRemoteLayerManager(
2695 [&](WebRenderLayerManager* aLayerManager) -> bool {
2696 nsCString error;
2697 return aLayerManager->Initialize(aCompositorChild,
2698 wr::AsPipelineId(mLayersId),
2699 &mTextureFactoryIdentifier, error);
2703 void BrowserChild::InitAPZState() {
2704 if (!mCompositorOptions->UseAPZ()) {
2705 return;
2707 auto* cbc = CompositorBridgeChild::Get();
2709 // Initialize the ApzcTreeManager. This takes multiple casts because of ugly
2710 // multiple inheritance.
2711 PAPZCTreeManagerChild* baseProtocol =
2712 cbc->SendPAPZCTreeManagerConstructor(mLayersId);
2713 if (!baseProtocol) {
2714 MOZ_ASSERT(false,
2715 "Allocating a TreeManager should not fail with APZ enabled");
2716 return;
2718 APZCTreeManagerChild* derivedProtocol =
2719 static_cast<APZCTreeManagerChild*>(baseProtocol);
2721 mApzcTreeManager = RefPtr<IAPZCTreeManager>(derivedProtocol);
2723 // Initialize the GeckoContentController for this tab. We don't hold a
2724 // reference because we don't need it. The ContentProcessController will hold
2725 // a reference to the tab, and will be destroyed by the compositor or ipdl
2726 // during destruction.
2727 RefPtr<GeckoContentController> contentController =
2728 new ContentProcessController(this);
2729 APZChild* apzChild = new APZChild(contentController);
2730 cbc->SendPAPZConstructor(apzChild, mLayersId);
2733 IPCResult BrowserChild::RecvUpdateEffects(const EffectsInfo& aEffects) {
2734 bool needInvalidate = false;
2735 if (mEffectsInfo.IsVisible() && aEffects.IsVisible() &&
2736 mEffectsInfo != aEffects) {
2737 // If we are staying visible and either the visrect or scale changed we need
2738 // to invalidate
2739 needInvalidate = true;
2742 mEffectsInfo = aEffects;
2743 UpdateVisibility();
2745 if (needInvalidate) {
2746 if (nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation())) {
2747 // We don't use BrowserChildBase::GetPresShell() here because that would
2748 // create a content viewer if one doesn't exist yet. Creating a content
2749 // viewer can cause JS to run, which we want to avoid.
2750 // nsIDocShell::GetPresShell returns null if no content viewer exists yet.
2751 if (RefPtr<PresShell> presShell = docShell->GetPresShell()) {
2752 if (nsIFrame* root = presShell->GetRootFrame()) {
2753 root->InvalidateFrame();
2759 return IPC_OK();
2762 bool BrowserChild::IsVisible() {
2763 return mPuppetWidget && mPuppetWidget->IsVisible();
2766 void BrowserChild::UpdateVisibility() {
2767 const bool shouldBeVisible = [&] {
2768 // If we're known to be visibility: hidden / display: none, just return
2769 // false here, we're pretty sure we don't want to be considered visible
2770 // here.
2771 if (mBrowsingContext && mBrowsingContext->IsUnderHiddenEmbedderElement()) {
2772 return false;
2774 // For OOP iframes, include viewport visibility. For top-level <browser>
2775 // elements we don't use this, because the front-end relies on using
2776 // `mRenderLayers` when invisible for tab warming purposes.
2778 // An alternative, maybe more consistent approach would be to add an opt-in
2779 // into this behavior for top-level tabs managed by the tab-switcher
2780 // instead...
2781 if (!mIsTopLevel && !mEffectsInfo.IsVisible()) {
2782 return false;
2784 // If we're explicitly told not to render layers, we're also invisible.
2785 if (!mRenderLayers) {
2786 return false;
2788 return true;
2789 }();
2791 const bool isVisible = IsVisible();
2792 if (shouldBeVisible == isVisible) {
2793 return;
2795 if (shouldBeVisible) {
2796 MakeVisible();
2797 } else {
2798 MakeHidden();
2802 void BrowserChild::MakeVisible() {
2803 if (IsVisible()) {
2804 return;
2807 if (mPuppetWidget) {
2808 mPuppetWidget->Show(true);
2811 PresShellActivenessMaybeChanged();
2814 void BrowserChild::MakeHidden() {
2815 if (!IsVisible()) {
2816 return;
2819 // Due to the nested event loop in ContentChild::ProvideWindowCommon,
2820 // it's possible to be told to become hidden before we're finished
2821 // setting up a layer manager. We should skip clearing cached layers
2822 // in that case, since doing so might accidentally put is into
2823 // BasicLayers mode.
2824 if (mPuppetWidget) {
2825 if (mPuppetWidget->HasWindowRenderer()) {
2826 ClearCachedResources();
2828 mPuppetWidget->Show(false);
2831 PresShellActivenessMaybeChanged();
2834 IPCResult BrowserChild::RecvPreserveLayers(bool aPreserve) {
2835 mIsPreservingLayers = aPreserve;
2837 PresShellActivenessMaybeChanged();
2839 return IPC_OK();
2842 void BrowserChild::PresShellActivenessMaybeChanged() {
2843 // We don't use BrowserChildBase::GetPresShell() here because that would
2844 // create a content viewer if one doesn't exist yet. Creating a content
2845 // viewer can cause JS to run, which we want to avoid.
2846 // nsIDocShell::GetPresShell returns null if no content viewer exists yet.
2848 // When this method is called we don't want to go through the browsing context
2849 // because we don't want to change the visibility state of the document, which
2850 // has side effects like firing events to content, unblocking media playback,
2851 // unthrottling timeouts... PresShell activeness has a lot less side effects.
2852 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2853 if (!docShell) {
2854 return;
2856 RefPtr<PresShell> presShell = docShell->GetPresShell();
2857 if (!presShell) {
2858 return;
2860 presShell->ActivenessMaybeChanged();
2863 NS_IMETHODIMP
2864 BrowserChild::GetMessageManager(ContentFrameMessageManager** aResult) {
2865 RefPtr<ContentFrameMessageManager> mm(mBrowserChildMessageManager);
2866 mm.forget(aResult);
2867 return *aResult ? NS_OK : NS_ERROR_FAILURE;
2870 void BrowserChild::SendRequestFocus(bool aCanFocus, CallerType aCallerType) {
2871 nsFocusManager* fm = nsFocusManager::GetFocusManager();
2872 if (!fm) {
2873 return;
2876 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
2877 if (!window) {
2878 return;
2881 BrowsingContext* focusedBC = fm->GetFocusedBrowsingContext();
2882 if (focusedBC == window->GetBrowsingContext()) {
2883 // BrowsingContext has the focus already, do not request again.
2884 return;
2887 PBrowserChild::SendRequestFocus(aCanFocus, aCallerType);
2890 NS_IMETHODIMP
2891 BrowserChild::GetTabId(uint64_t* aId) {
2892 *aId = GetTabId();
2893 return NS_OK;
2896 NS_IMETHODIMP
2897 BrowserChild::GetChromeOuterWindowID(uint64_t* aId) {
2898 *aId = ChromeOuterWindowID();
2899 return NS_OK;
2902 bool BrowserChild::DoSendBlockingMessage(
2903 const nsAString& aMessage, StructuredCloneData& aData,
2904 nsTArray<StructuredCloneData>* aRetVal) {
2905 ClonedMessageData data;
2906 if (!BuildClonedMessageData(aData, data)) {
2907 return false;
2909 return SendSyncMessage(PromiseFlatString(aMessage), data, aRetVal);
2912 nsresult BrowserChild::DoSendAsyncMessage(const nsAString& aMessage,
2913 StructuredCloneData& aData) {
2914 ClonedMessageData data;
2915 if (!BuildClonedMessageData(aData, data)) {
2916 return NS_ERROR_DOM_DATA_CLONE_ERR;
2918 if (!SendAsyncMessage(PromiseFlatString(aMessage), data)) {
2919 return NS_ERROR_UNEXPECTED;
2921 return NS_OK;
2924 /* static */
2925 nsTArray<RefPtr<BrowserChild>> BrowserChild::GetAll() {
2926 StaticMutexAutoLock lock(sBrowserChildrenMutex);
2928 if (!sBrowserChildren) {
2929 return {};
2932 return ToTArray<nsTArray<RefPtr<BrowserChild>>>(sBrowserChildren->Values());
2935 BrowserChild* BrowserChild::GetFrom(PresShell* aPresShell) {
2936 Document* doc = aPresShell->GetDocument();
2937 if (!doc) {
2938 return nullptr;
2940 nsCOMPtr<nsIDocShell> docShell(doc->GetDocShell());
2941 return GetFrom(docShell);
2944 BrowserChild* BrowserChild::GetFrom(layers::LayersId aLayersId) {
2945 StaticMutexAutoLock lock(sBrowserChildrenMutex);
2946 if (!sBrowserChildren) {
2947 return nullptr;
2949 return sBrowserChildren->Get(uint64_t(aLayersId));
2952 void BrowserChild::DidComposite(mozilla::layers::TransactionId aTransactionId,
2953 const TimeStamp& aCompositeStart,
2954 const TimeStamp& aCompositeEnd) {
2955 MOZ_ASSERT(mPuppetWidget);
2956 RefPtr<WebRenderLayerManager> lm =
2957 mPuppetWidget->GetWindowRenderer()->AsWebRender();
2958 MOZ_ASSERT(lm);
2960 if (lm) {
2961 lm->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
2965 void BrowserChild::ClearCachedResources() {
2966 MOZ_ASSERT(mPuppetWidget);
2967 RefPtr<WebRenderLayerManager> lm =
2968 mPuppetWidget->GetWindowRenderer()->AsWebRender();
2969 if (lm) {
2970 lm->ClearCachedResources();
2973 if (nsCOMPtr<Document> document = GetTopLevelDocument()) {
2974 nsPresContext* presContext = document->GetPresContext();
2975 if (presContext) {
2976 presContext->NotifyPaintStatusReset();
2981 void BrowserChild::SchedulePaint() {
2982 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2983 if (!docShell) {
2984 return;
2987 // We don't use BrowserChildBase::GetPresShell() here because that would
2988 // create a content viewer if one doesn't exist yet. Creating a content viewer
2989 // can cause JS to run, which we want to avoid. nsIDocShell::GetPresShell
2990 // returns null if no content viewer exists yet.
2991 if (RefPtr<PresShell> presShell = docShell->GetPresShell()) {
2992 if (nsIFrame* root = presShell->GetRootFrame()) {
2993 root->SchedulePaint();
2998 void BrowserChild::ReinitRendering() {
2999 MOZ_ASSERT(mLayersId.IsValid());
3001 // In some cases, like when we create a windowless browser,
3002 // RemoteLayerTreeOwner/BrowserChild is not connected to a compositor.
3003 if (mLayersConnectRequested.isNothing() ||
3004 mLayersConnectRequested == Some(false)) {
3005 return;
3008 // Before we establish a new PLayerTransaction, we must connect our layer tree
3009 // id, CompositorBridge, and the widget compositor all together again.
3010 // Normally this happens in BrowserParent before BrowserChild is given
3011 // rendering information.
3013 // In this case, we will send a sync message to our BrowserParent, which in
3014 // turn will send a sync message to the Compositor of the widget owning this
3015 // tab. This guarantees the correct association is in place before our
3016 // PLayerTransaction constructor message arrives on the cross-process
3017 // compositor bridge.
3018 CompositorOptions options;
3019 SendEnsureLayersConnected(&options);
3020 mCompositorOptions = Some(options);
3022 bool success = false;
3023 RefPtr<CompositorBridgeChild> cb = CompositorBridgeChild::Get();
3025 if (cb) {
3026 success = CreateRemoteLayerManager(cb);
3029 if (!success) {
3030 NS_WARNING("failed to recreate layer manager");
3031 return;
3034 mLayersConnected = Some(true);
3035 ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
3036 gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
3038 InitAPZState();
3039 if (nsCOMPtr<Document> doc = GetTopLevelDocument()) {
3040 doc->NotifyLayerManagerRecreated();
3043 if (mRenderLayers) {
3044 SchedulePaint();
3048 void BrowserChild::ReinitRenderingForDeviceReset() {
3049 RefPtr<WebRenderLayerManager> lm =
3050 mPuppetWidget->GetWindowRenderer()->AsWebRender();
3051 if (lm) {
3052 lm->DoDestroy(/* aIsSync */ true);
3055 // Proceed with destroying and recreating the layer manager.
3056 ReinitRendering();
3059 NS_IMETHODIMP
3060 BrowserChild::OnShowTooltip(int32_t aXCoords, int32_t aYCoords,
3061 const nsAString& aTipText,
3062 const nsAString& aTipDir) {
3063 nsString str(aTipText);
3064 nsString dir(aTipDir);
3065 SendShowTooltip(aXCoords, aYCoords, str, dir);
3066 return NS_OK;
3069 NS_IMETHODIMP
3070 BrowserChild::OnHideTooltip() {
3071 SendHideTooltip();
3072 return NS_OK;
3075 void BrowserChild::NotifyJankedAnimations(
3076 const nsTArray<uint64_t>& aJankedAnimations) {
3077 MOZ_ASSERT(mPuppetWidget);
3078 RefPtr<WebRenderLayerManager> lm =
3079 mPuppetWidget->GetWindowRenderer()->AsWebRender();
3080 if (lm) {
3081 lm->UpdatePartialPrerenderedAnimations(aJankedAnimations);
3085 mozilla::ipc::IPCResult BrowserChild::RecvUIResolutionChanged(
3086 const float& aDpi, const int32_t& aRounding, const double& aScale) {
3087 ScreenIntSize oldScreenSize = GetInnerSize();
3088 if (aDpi > 0) {
3089 mPuppetWidget->UpdateBackingScaleCache(aDpi, aRounding, aScale);
3092 ScreenIntSize screenSize = GetInnerSize();
3093 if (mHasValidInnerSize && oldScreenSize != screenSize) {
3094 ScreenIntRect screenRect = GetOuterRect();
3096 // See RecvUpdateDimensions for the order of these operations.
3097 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
3098 baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height,
3099 nsIBaseWindow::eRepaint);
3101 mPuppetWidget->Resize(screenRect.x + mClientOffset.x + mChromeOffset.x,
3102 screenRect.y + mClientOffset.y + mChromeOffset.y,
3103 screenSize.width, screenSize.height, true);
3106 nsCOMPtr<Document> document(GetTopLevelDocument());
3107 RefPtr<nsPresContext> presContext =
3108 document ? document->GetPresContext() : nullptr;
3109 if (presContext) {
3110 presContext->UIResolutionChangedSync();
3113 return IPC_OK();
3116 mozilla::ipc::IPCResult BrowserChild::RecvSafeAreaInsetsChanged(
3117 const mozilla::ScreenIntMargin& aSafeAreaInsets) {
3118 mPuppetWidget->UpdateSafeAreaInsets(aSafeAreaInsets);
3120 nsCOMPtr<nsIScreenManager> screenMgr =
3121 do_GetService("@mozilla.org/gfx/screenmanager;1");
3122 ScreenIntMargin currentSafeAreaInsets;
3123 if (screenMgr) {
3124 // aSafeAreaInsets is for current screen. But we have to calculate
3125 // safe insets for content window.
3126 int32_t x, y, cx, cy;
3127 GetDimensions(DimensionKind::Outer, &x, &y, &cx, &cy);
3128 nsCOMPtr<nsIScreen> screen;
3129 screenMgr->ScreenForRect(x, y, cx, cy, getter_AddRefs(screen));
3131 if (screen) {
3132 LayoutDeviceIntRect windowRect(x + mClientOffset.x + mChromeOffset.x,
3133 y + mClientOffset.y + mChromeOffset.y, cx,
3134 cy);
3135 currentSafeAreaInsets = nsContentUtils::GetWindowSafeAreaInsets(
3136 screen, aSafeAreaInsets, windowRect);
3140 if (nsCOMPtr<Document> document = GetTopLevelDocument()) {
3141 nsPresContext* presContext = document->GetPresContext();
3142 if (presContext) {
3143 presContext->SetSafeAreaInsets(currentSafeAreaInsets);
3147 // https://github.com/w3c/csswg-drafts/issues/4670
3148 // Actually we don't set this value on sub document. This behaviour is
3149 // same as Blink that safe area insets isn't set on sub document.
3151 return IPC_OK();
3154 mozilla::ipc::IPCResult BrowserChild::RecvAllowScriptsToClose() {
3155 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
3156 if (window) {
3157 nsGlobalWindowOuter::Cast(window)->AllowScriptsToClose();
3159 return IPC_OK();
3162 mozilla::ipc::IPCResult BrowserChild::RecvReleaseAllPointerCapture() {
3163 PointerEventHandler::ReleaseAllPointerCapture();
3164 return IPC_OK();
3167 PPaymentRequestChild* BrowserChild::AllocPPaymentRequestChild() {
3168 MOZ_CRASH(
3169 "We should never be manually allocating PPaymentRequestChild actors");
3170 return nullptr;
3173 bool BrowserChild::DeallocPPaymentRequestChild(PPaymentRequestChild* actor) {
3174 delete actor;
3175 return true;
3178 ScreenIntSize BrowserChild::GetInnerSize() {
3179 LayoutDeviceIntSize innerSize =
3180 RoundedToInt(mUnscaledInnerSize * mPuppetWidget->GetDefaultScale());
3181 return ViewAs<ScreenPixel>(
3182 innerSize, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
3185 Maybe<nsRect> BrowserChild::GetVisibleRect() const {
3186 if (mIsTopLevel) {
3187 // We are conservative about visible rects for top-level browsers to avoid
3188 // artifacts when resizing
3189 return Nothing();
3191 return mEffectsInfo.mVisibleRect;
3194 Maybe<LayoutDeviceRect>
3195 BrowserChild::GetTopLevelViewportVisibleRectInSelfCoords() const {
3196 if (mIsTopLevel) {
3197 return Nothing();
3200 if (!mChildToParentConversionMatrix) {
3201 // We have no way to tell this remote document visible rect right now.
3202 return Nothing();
3205 Maybe<LayoutDeviceToLayoutDeviceMatrix4x4> inverse =
3206 mChildToParentConversionMatrix->MaybeInverse();
3207 if (!inverse) {
3208 return Nothing();
3211 // Convert the remote document visible rect to the coordinate system of the
3212 // iframe document.
3213 Maybe<LayoutDeviceRect> rect = UntransformBy(
3214 *inverse,
3215 ViewAs<LayoutDevicePixel>(
3216 mTopLevelViewportVisibleRectInBrowserCoords,
3217 PixelCastJustification::ContentProcessIsLayerInUiProcess),
3218 LayoutDeviceRect::MaxIntRect());
3219 if (!rect) {
3220 return Nothing();
3223 return rect;
3226 ScreenIntRect BrowserChild::GetOuterRect() {
3227 LayoutDeviceIntRect outerRect =
3228 RoundedToInt(mUnscaledOuterRect * mPuppetWidget->GetDefaultScale());
3229 return ViewAs<ScreenPixel>(
3230 outerRect, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
3233 void BrowserChild::PaintWhileInterruptingJS() {
3234 if (!IPCOpen() || !mPuppetWidget || !mPuppetWidget->HasWindowRenderer()) {
3235 // Don't bother doing anything now. Better to wait until we receive the
3236 // message on the PContent channel.
3237 return;
3240 MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::IsSafeToRunScript());
3241 nsAutoScriptBlocker scriptBlocker;
3242 RecvRenderLayers(/* aEnabled = */ true);
3245 void BrowserChild::UnloadLayersWhileInterruptingJS() {
3246 if (!IPCOpen() || !mPuppetWidget || !mPuppetWidget->HasWindowRenderer()) {
3247 // Don't bother doing anything now. Better to wait until we receive the
3248 // message on the PContent channel.
3249 return;
3252 MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::IsSafeToRunScript());
3253 nsAutoScriptBlocker scriptBlocker;
3254 RecvRenderLayers(/* aEnabled = */ false);
3257 nsresult BrowserChild::CanCancelContentJS(
3258 nsIRemoteTab::NavigationType aNavigationType, int32_t aNavigationIndex,
3259 nsIURI* aNavigationURI, int32_t aEpoch, bool* aCanCancel) {
3260 nsresult rv;
3261 *aCanCancel = false;
3263 if (aEpoch <= mCancelContentJSEpoch) {
3264 // The next page loaded before we got here, so we shouldn't try to cancel
3265 // the content JS.
3266 return NS_OK;
3269 // If we have session history in the parent we've already performed
3270 // the checks following, so we can return early.
3271 if (mozilla::SessionHistoryInParent()) {
3272 *aCanCancel = true;
3273 return NS_OK;
3276 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
3277 nsCOMPtr<nsISHistory> history;
3278 if (docShell) {
3279 history = nsDocShell::Cast(docShell)->GetSessionHistory()->LegacySHistory();
3282 if (!history) {
3283 return NS_ERROR_FAILURE;
3286 int32_t current;
3287 rv = history->GetIndex(&current);
3288 NS_ENSURE_SUCCESS(rv, rv);
3290 if (current == -1) {
3291 // This tab has no history! Just return.
3292 return NS_OK;
3295 nsCOMPtr<nsISHEntry> entry;
3296 rv = history->GetEntryAtIndex(current, getter_AddRefs(entry));
3297 NS_ENSURE_SUCCESS(rv, rv);
3299 nsCOMPtr<nsIURI> currentURI = entry->GetURI();
3300 if (!currentURI->SchemeIs("http") && !currentURI->SchemeIs("https") &&
3301 !currentURI->SchemeIs("file")) {
3302 // Only cancel content JS for http(s) and file URIs. Other URIs are probably
3303 // internal and we should just let them run to completion.
3304 return NS_OK;
3307 if (aNavigationType == nsIRemoteTab::NAVIGATE_BACK) {
3308 aNavigationIndex = current - 1;
3309 } else if (aNavigationType == nsIRemoteTab::NAVIGATE_FORWARD) {
3310 aNavigationIndex = current + 1;
3311 } else if (aNavigationType == nsIRemoteTab::NAVIGATE_URL) {
3312 if (!aNavigationURI) {
3313 return NS_ERROR_FAILURE;
3316 if (aNavigationURI->SchemeIs("javascript")) {
3317 // "javascript:" URIs don't (necessarily) trigger navigation to a
3318 // different page, so don't allow the current page's JS to terminate.
3319 return NS_OK;
3322 // If navigating directly to a URL (e.g. via hitting Enter in the location
3323 // bar), then we can cancel anytime the next URL is different from the
3324 // current, *excluding* the ref ("#").
3325 bool equals;
3326 rv = currentURI->EqualsExceptRef(aNavigationURI, &equals);
3327 NS_ENSURE_SUCCESS(rv, rv);
3328 *aCanCancel = !equals;
3329 return NS_OK;
3331 // Note: aNavigationType may also be NAVIGATE_INDEX, in which case we don't
3332 // need to do anything special.
3334 int32_t delta = aNavigationIndex > current ? 1 : -1;
3335 for (int32_t i = current + delta; i != aNavigationIndex + delta; i += delta) {
3336 nsCOMPtr<nsISHEntry> nextEntry;
3337 // If `i` happens to be negative, this call will fail (which is what we
3338 // would want to happen).
3339 rv = history->GetEntryAtIndex(i, getter_AddRefs(nextEntry));
3340 NS_ENSURE_SUCCESS(rv, rv);
3342 nsCOMPtr<nsISHEntry> laterEntry = delta == 1 ? nextEntry : entry;
3343 nsCOMPtr<nsIURI> thisURI = entry->GetURI();
3344 nsCOMPtr<nsIURI> nextURI = nextEntry->GetURI();
3346 // If we changed origin and the load wasn't in a subframe, we know it was
3347 // a full document load, so we can cancel the content JS safely.
3348 if (!laterEntry->GetIsSubFrame()) {
3349 nsAutoCString thisHost;
3350 rv = thisURI->GetPrePath(thisHost);
3351 NS_ENSURE_SUCCESS(rv, rv);
3353 nsAutoCString nextHost;
3354 rv = nextURI->GetPrePath(nextHost);
3355 NS_ENSURE_SUCCESS(rv, rv);
3357 if (!thisHost.Equals(nextHost)) {
3358 *aCanCancel = true;
3359 return NS_OK;
3363 entry = nextEntry;
3366 return NS_OK;
3369 NS_IMETHODIMP BrowserChild::OnStateChange(nsIWebProgress* aWebProgress,
3370 nsIRequest* aRequest,
3371 uint32_t aStateFlags,
3372 nsresult aStatus) {
3373 if (!IPCOpen() || !mShouldSendWebProgressEventsToParent) {
3374 return NS_OK;
3377 // We shouldn't need to notify the parent of redirect state changes, since
3378 // with DocumentChannel that only happens when we switch to the real channel,
3379 // and that's an implementation detail that we can hide.
3380 if (aStateFlags & nsIWebProgressListener::STATE_IS_REDIRECTED_DOCUMENT) {
3381 return NS_OK;
3384 // Our OnStateChange call must have provided the nsIDocShell which the source
3385 // comes from. We'll use this to locate the corresponding BrowsingContext in
3386 // the parent process.
3387 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress);
3388 if (!docShell) {
3389 MOZ_ASSERT_UNREACHABLE("aWebProgress is null or not a nsIDocShell?");
3390 return NS_ERROR_UNEXPECTED;
3393 WebProgressData webProgressData;
3394 Maybe<WebProgressStateChangeData> stateChangeData;
3395 RequestData requestData;
3397 MOZ_TRY(PrepareProgressListenerData(aWebProgress, aRequest, webProgressData,
3398 requestData));
3400 RefPtr<BrowsingContext> browsingContext = docShell->GetBrowsingContext();
3401 if (browsingContext->IsTopContent()) {
3402 stateChangeData.emplace();
3404 stateChangeData->isNavigating() = docShell->GetIsNavigating();
3405 stateChangeData->mayEnableCharacterEncodingMenu() =
3406 docShell->GetMayEnableCharacterEncodingMenu();
3408 RefPtr<Document> document = browsingContext->GetExtantDocument();
3409 if (document && aStateFlags & nsIWebProgressListener::STATE_STOP) {
3410 document->GetContentType(stateChangeData->contentType());
3411 document->GetCharacterSet(stateChangeData->charset());
3412 stateChangeData->documentURI() = document->GetDocumentURIObject();
3413 } else {
3414 stateChangeData->contentType().SetIsVoid(true);
3415 stateChangeData->charset().SetIsVoid(true);
3419 Unused << SendOnStateChange(webProgressData, requestData, aStateFlags,
3420 aStatus, stateChangeData);
3422 return NS_OK;
3425 NS_IMETHODIMP BrowserChild::OnProgressChange(nsIWebProgress* aWebProgress,
3426 nsIRequest* aRequest,
3427 int32_t aCurSelfProgress,
3428 int32_t aMaxSelfProgress,
3429 int32_t aCurTotalProgress,
3430 int32_t aMaxTotalProgress) {
3431 if (!IPCOpen() || !mShouldSendWebProgressEventsToParent) {
3432 return NS_OK;
3435 // FIXME: We currently ignore ProgressChange events from out-of-process
3436 // subframes both here and in BrowserParent. We may want to change this
3437 // behaviour in the future.
3438 if (!GetBrowsingContext()->IsTopContent()) {
3439 return NS_OK;
3442 // As we're being filtered by nsBrowserStatusFilter, we will be passed either
3443 // nullptr or 0 for all arguments other than aCurTotalProgress and
3444 // aMaxTotalProgress. Don't bother sending them.
3445 MOZ_ASSERT(!aWebProgress);
3446 MOZ_ASSERT(!aRequest);
3447 MOZ_ASSERT(aCurSelfProgress == 0);
3448 MOZ_ASSERT(aMaxSelfProgress == 0);
3450 Unused << SendOnProgressChange(aCurTotalProgress, aMaxTotalProgress);
3452 return NS_OK;
3455 NS_IMETHODIMP BrowserChild::OnLocationChange(nsIWebProgress* aWebProgress,
3456 nsIRequest* aRequest,
3457 nsIURI* aLocation,
3458 uint32_t aFlags) {
3459 if (!IPCOpen() || !mShouldSendWebProgressEventsToParent) {
3460 return NS_OK;
3463 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress);
3464 if (!docShell) {
3465 MOZ_ASSERT_UNREACHABLE("aWebProgress is null or not a nsIDocShell?");
3466 return NS_ERROR_UNEXPECTED;
3469 RefPtr<BrowsingContext> browsingContext = docShell->GetBrowsingContext();
3470 RefPtr<Document> document = browsingContext->GetExtantDocument();
3471 if (!document) {
3472 return NS_OK;
3475 WebProgressData webProgressData;
3476 RequestData requestData;
3478 MOZ_TRY(PrepareProgressListenerData(aWebProgress, aRequest, webProgressData,
3479 requestData));
3481 Maybe<WebProgressLocationChangeData> locationChangeData;
3483 bool canGoBack = false;
3484 bool canGoForward = false;
3485 if (!mozilla::SessionHistoryInParent()) {
3486 MOZ_TRY(WebNavigation()->GetCanGoBack(&canGoBack));
3487 MOZ_TRY(WebNavigation()->GetCanGoForward(&canGoForward));
3490 if (browsingContext->IsTopContent()) {
3491 MOZ_ASSERT(
3492 browsingContext == GetBrowsingContext(),
3493 "Toplevel content BrowsingContext which isn't GetBrowsingContext()?");
3495 locationChangeData.emplace();
3497 document->GetContentType(locationChangeData->contentType());
3498 locationChangeData->isNavigating() = docShell->GetIsNavigating();
3499 locationChangeData->documentURI() = document->GetDocumentURIObject();
3500 document->GetTitle(locationChangeData->title());
3501 document->GetCharacterSet(locationChangeData->charset());
3503 locationChangeData->mayEnableCharacterEncodingMenu() =
3504 docShell->GetMayEnableCharacterEncodingMenu();
3506 locationChangeData->contentPrincipal() = document->NodePrincipal();
3507 locationChangeData->contentPartitionedPrincipal() =
3508 document->PartitionedPrincipal();
3509 locationChangeData->csp() = document->GetCsp();
3510 locationChangeData->referrerInfo() = document->ReferrerInfo();
3511 locationChangeData->isSyntheticDocument() = document->IsSyntheticDocument();
3513 if (nsCOMPtr<nsILoadGroup> loadGroup = document->GetDocumentLoadGroup()) {
3514 uint64_t requestContextID = 0;
3515 MOZ_TRY(loadGroup->GetRequestContextID(&requestContextID));
3516 locationChangeData->requestContextID() = Some(requestContextID);
3519 #ifdef MOZ_CRASHREPORTER
3520 if (CrashReporter::GetEnabled()) {
3521 nsCOMPtr<nsIURI> annotationURI;
3523 nsresult rv =
3524 NS_MutateURI(aLocation).SetUserPass(""_ns).Finalize(annotationURI);
3526 if (NS_FAILED(rv)) {
3527 // Ignore failures on about: URIs.
3528 annotationURI = aLocation;
3531 CrashReporter::RecordAnnotationNSCString(
3532 CrashReporter::Annotation::URL, annotationURI->GetSpecOrDefault());
3534 #endif
3537 Unused << SendOnLocationChange(webProgressData, requestData, aLocation,
3538 aFlags, canGoBack, canGoForward,
3539 locationChangeData);
3541 return NS_OK;
3544 NS_IMETHODIMP BrowserChild::OnStatusChange(nsIWebProgress* aWebProgress,
3545 nsIRequest* aRequest,
3546 nsresult aStatus,
3547 const char16_t* aMessage) {
3548 if (!IPCOpen() || !mShouldSendWebProgressEventsToParent) {
3549 return NS_OK;
3552 // FIXME: We currently ignore StatusChange from out-of-process subframes both
3553 // here and in BrowserParent. We may want to change this behaviour in the
3554 // future.
3555 if (!GetBrowsingContext()->IsTopContent()) {
3556 return NS_OK;
3559 // As we're being filtered by nsBrowserStatusFilter, we will be passed either
3560 // nullptr or NS_OK for all arguments other than aMessage. Don't bother
3561 // sending them.
3562 MOZ_ASSERT(!aWebProgress);
3563 MOZ_ASSERT(!aRequest);
3564 MOZ_ASSERT(aStatus == NS_OK);
3566 Unused << SendOnStatusChange(nsDependentString(aMessage));
3568 return NS_OK;
3571 NS_IMETHODIMP BrowserChild::OnSecurityChange(nsIWebProgress* aWebProgress,
3572 nsIRequest* aRequest,
3573 uint32_t aState) {
3574 // Security changes are now handled entirely in the parent process
3575 // so we don't need to worry about forwarding them (and we shouldn't
3576 // be receiving any to forward).
3577 return NS_OK;
3580 NS_IMETHODIMP BrowserChild::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
3581 nsIRequest* aRequest,
3582 uint32_t aEvent) {
3583 // The OnContentBlockingEvent only happenes in the parent process. It should
3584 // not be seen in the content process.
3585 MOZ_DIAGNOSTIC_ASSERT(
3586 false, "OnContentBlockingEvent should not be seen in content process.");
3587 return NS_ERROR_NOT_IMPLEMENTED;
3590 NS_IMETHODIMP BrowserChild::OnProgressChange64(nsIWebProgress* aWebProgress,
3591 nsIRequest* aRequest,
3592 int64_t aCurSelfProgress,
3593 int64_t aMaxSelfProgress,
3594 int64_t aCurTotalProgress,
3595 int64_t aMaxTotalProgress) {
3596 // All the events we receive are filtered through an nsBrowserStatusFilter,
3597 // which accepts ProgressChange64 events, but truncates the progress values to
3598 // uint32_t and calls OnProgressChange.
3599 return NS_ERROR_NOT_IMPLEMENTED;
3602 NS_IMETHODIMP BrowserChild::OnRefreshAttempted(nsIWebProgress* aWebProgress,
3603 nsIURI* aRefreshURI,
3604 uint32_t aMillis, bool aSameURI,
3605 bool* aOut) {
3606 NS_ENSURE_ARG_POINTER(aOut);
3607 *aOut = true;
3609 return NS_OK;
3612 NS_IMETHODIMP BrowserChild::NotifyNavigationFinished() {
3613 Unused << SendNavigationFinished();
3614 return NS_OK;
3617 nsresult BrowserChild::PrepareRequestData(nsIRequest* aRequest,
3618 RequestData& aRequestData) {
3619 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
3620 if (!channel) {
3621 aRequestData.requestURI() = nullptr;
3622 return NS_OK;
3625 nsresult rv = channel->GetURI(getter_AddRefs(aRequestData.requestURI()));
3626 NS_ENSURE_SUCCESS(rv, rv);
3628 rv = channel->GetOriginalURI(
3629 getter_AddRefs(aRequestData.originalRequestURI()));
3630 NS_ENSURE_SUCCESS(rv, rv);
3632 nsCOMPtr<nsIClassifiedChannel> classifiedChannel = do_QueryInterface(channel);
3633 if (classifiedChannel) {
3634 rv = classifiedChannel->GetMatchedList(aRequestData.matchedList());
3635 NS_ENSURE_SUCCESS(rv, rv);
3637 return NS_OK;
3640 nsresult BrowserChild::PrepareProgressListenerData(
3641 nsIWebProgress* aWebProgress, nsIRequest* aRequest,
3642 WebProgressData& aWebProgressData, RequestData& aRequestData) {
3643 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress);
3644 if (!docShell) {
3645 MOZ_ASSERT_UNREACHABLE("aWebProgress is null or not a nsIDocShell?");
3646 return NS_ERROR_UNEXPECTED;
3649 aWebProgressData.browsingContext() = docShell->GetBrowsingContext();
3650 nsresult rv = aWebProgress->GetLoadType(&aWebProgressData.loadType());
3651 NS_ENSURE_SUCCESS(rv, rv);
3653 return PrepareRequestData(aRequest, aRequestData);
3656 void BrowserChild::UpdateSessionStore() {
3657 if (mSessionStoreChild) {
3658 mSessionStoreChild->UpdateSessionStore();
3662 #ifdef XP_WIN
3663 RefPtr<PBrowserChild::IsWindowSupportingProtectedMediaPromise>
3664 BrowserChild::DoesWindowSupportProtectedMedia() {
3665 MOZ_ASSERT(
3666 NS_IsMainThread(),
3667 "Protected media support check should be done on main thread only.");
3668 if (mWindowSupportsProtectedMedia) {
3669 // If we've already checked and have a cached result, resolve with that.
3670 return IsWindowSupportingProtectedMediaPromise::CreateAndResolve(
3671 mWindowSupportsProtectedMedia.value(), __func__);
3673 RefPtr<BrowserChild> self = this;
3674 // We chain off the promise rather than passing it directly so we can cache
3675 // the result and use that for future calls.
3676 return SendIsWindowSupportingProtectedMedia(ChromeOuterWindowID())
3677 ->Then(
3678 GetCurrentSerialEventTarget(), __func__,
3679 [self](bool isSupported) {
3680 // If a result was cached while this check was inflight, ensure the
3681 // results match.
3682 MOZ_ASSERT_IF(
3683 self->mWindowSupportsProtectedMedia,
3684 self->mWindowSupportsProtectedMedia.value() == isSupported);
3685 // Cache the response as it will not change during the lifetime
3686 // of this object.
3687 self->mWindowSupportsProtectedMedia = Some(isSupported);
3688 return IsWindowSupportingProtectedMediaPromise::CreateAndResolve(
3689 self->mWindowSupportsProtectedMedia.value(), __func__);
3691 [](ResponseRejectReason reason) {
3692 return IsWindowSupportingProtectedMediaPromise::CreateAndReject(
3693 reason, __func__);
3696 #endif
3698 void BrowserChild::NotifyContentBlockingEvent(
3699 uint32_t aEvent, nsIChannel* aChannel, bool aBlocked,
3700 const nsACString& aTrackingOrigin,
3701 const nsTArray<nsCString>& aTrackingFullHashes,
3702 const Maybe<
3703 mozilla::ContentBlockingNotifier::StorageAccessPermissionGrantedReason>&
3704 aReason,
3705 const Maybe<ContentBlockingNotifier::CanvasFingerprinter>&
3706 aCanvasFingerprinter,
3707 const Maybe<bool> aCanvasFingerprinterKnownText) {
3708 if (!IPCOpen()) {
3709 return;
3712 RequestData requestData;
3713 if (NS_SUCCEEDED(PrepareRequestData(aChannel, requestData))) {
3714 Unused << SendNotifyContentBlockingEvent(
3715 aEvent, requestData, aBlocked, PromiseFlatCString(aTrackingOrigin),
3716 aTrackingFullHashes, aReason, aCanvasFingerprinter,
3717 aCanvasFingerprinterKnownText);
3721 NS_IMETHODIMP
3722 BrowserChild::ContentTransformsReceived(JSContext* aCx,
3723 dom::Promise** aPromise) {
3724 auto* globalObject = xpc::CurrentNativeGlobal(aCx);
3725 ErrorResult rv;
3726 if (mChildToParentConversionMatrix) {
3727 // Already received content transforms
3728 RefPtr<Promise> promise =
3729 Promise::CreateResolvedWithUndefined(globalObject, rv);
3730 promise.forget(aPromise);
3731 return rv.StealNSResult();
3734 if (!mContentTransformPromise) {
3735 mContentTransformPromise = Promise::Create(globalObject, rv);
3738 MOZ_ASSERT(globalObject == mContentTransformPromise->GetGlobalObject());
3739 NS_IF_ADDREF(*aPromise = mContentTransformPromise);
3740 return rv.StealNSResult();
3743 BrowserChildMessageManager::BrowserChildMessageManager(
3744 BrowserChild* aBrowserChild)
3745 : ContentFrameMessageManager(new nsFrameMessageManager(aBrowserChild)),
3746 mBrowserChild(aBrowserChild) {}
3748 BrowserChildMessageManager::~BrowserChildMessageManager() = default;
3750 NS_IMPL_CYCLE_COLLECTION_CLASS(BrowserChildMessageManager)
3752 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BrowserChildMessageManager,
3753 DOMEventTargetHelper)
3754 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager);
3755 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChild);
3756 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
3757 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
3759 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BrowserChildMessageManager,
3760 DOMEventTargetHelper)
3761 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
3762 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChild)
3763 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
3765 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserChildMessageManager)
3766 NS_INTERFACE_MAP_ENTRY(nsIMessageSender)
3767 NS_INTERFACE_MAP_ENTRY_CONCRETE(ContentFrameMessageManager)
3768 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
3769 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
3771 NS_IMPL_ADDREF_INHERITED(BrowserChildMessageManager, DOMEventTargetHelper)
3772 NS_IMPL_RELEASE_INHERITED(BrowserChildMessageManager, DOMEventTargetHelper)
3774 JSObject* BrowserChildMessageManager::WrapObject(
3775 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
3776 return ContentFrameMessageManager_Binding::Wrap(aCx, this, aGivenProto);
3779 void BrowserChildMessageManager::MarkForCC() {
3780 if (mBrowserChild) {
3781 mBrowserChild->MarkScopesForCC();
3783 EventListenerManager* elm = GetExistingListenerManager();
3784 if (elm) {
3785 elm->MarkForCC();
3787 MessageManagerGlobal::MarkForCC();
3790 Nullable<WindowProxyHolder> BrowserChildMessageManager::GetContent(
3791 ErrorResult& aError) {
3792 nsCOMPtr<nsIDocShell> docShell = GetDocShell(aError);
3793 if (!docShell) {
3794 return nullptr;
3796 return WindowProxyHolder(docShell->GetBrowsingContext());
3799 already_AddRefed<nsIDocShell> BrowserChildMessageManager::GetDocShell(
3800 ErrorResult& aError) {
3801 if (!mBrowserChild) {
3802 aError.Throw(NS_ERROR_NULL_POINTER);
3803 return nullptr;
3805 nsCOMPtr<nsIDocShell> window =
3806 do_GetInterface(mBrowserChild->WebNavigation());
3807 return window.forget();
3810 already_AddRefed<nsIEventTarget>
3811 BrowserChildMessageManager::GetTabEventTarget() {
3812 return do_AddRef(GetMainThreadSerialEventTarget());
3815 nsresult BrowserChildMessageManager::Dispatch(
3816 already_AddRefed<nsIRunnable>&& aRunnable) const {
3817 return SchedulerGroup::Dispatch(std::move(aRunnable));