no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / ipc / BrowserChild.cpp
blob830ad8579a39d262a1fd2c86479f2ddc77c01ae2
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 (StaticPrefs::browser_sessionstore_platform_collection_AtStartup()) {
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::AnnotateCrashReport(CrashReporter::Annotation::URL, spec);
818 return IPC_OK();
821 mozilla::ipc::IPCResult BrowserChild::RecvCreateAboutBlankDocumentViewer(
822 nsIPrincipal* aPrincipal, nsIPrincipal* aPartitionedPrincipal) {
823 if (aPrincipal->GetIsExpandedPrincipal() ||
824 aPartitionedPrincipal->GetIsExpandedPrincipal()) {
825 return IPC_FAIL(this, "Cannot create document with an expanded principal");
827 if (aPrincipal->IsSystemPrincipal() ||
828 aPartitionedPrincipal->IsSystemPrincipal()) {
829 MOZ_ASSERT_UNREACHABLE(
830 "Cannot use CreateAboutBlankDocumentViewer to create system principal "
831 "document in content");
832 return IPC_OK();
835 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
836 if (!docShell) {
837 MOZ_ASSERT_UNREACHABLE("WebNavigation does not have a docshell");
838 return IPC_OK();
841 nsCOMPtr<nsIURI> currentURI;
842 MOZ_ALWAYS_SUCCEEDS(
843 WebNavigation()->GetCurrentURI(getter_AddRefs(currentURI)));
844 if (!currentURI || !NS_IsAboutBlank(currentURI)) {
845 NS_WARNING("Can't create a ContentViewer unless on about:blank");
846 return IPC_OK();
849 docShell->CreateAboutBlankDocumentViewer(aPrincipal, aPartitionedPrincipal,
850 nullptr);
851 return IPC_OK();
854 mozilla::ipc::IPCResult BrowserChild::RecvResumeLoad(
855 const uint64_t& aPendingSwitchID, const ParentShowInfo& aInfo) {
856 if (!mDidLoadURLInit) {
857 mDidLoadURLInit = true;
858 if (!InitBrowserChildMessageManager()) {
859 return IPC_FAIL_NO_REASON(this);
862 ApplyParentShowInfo(aInfo);
865 nsresult rv = WebNavigation()->ResumeRedirectedLoad(aPendingSwitchID, -1);
866 if (NS_FAILED(rv)) {
867 NS_WARNING("WebNavigation()->ResumeRedirectedLoad failed");
870 return IPC_OK();
873 nsresult BrowserChild::CloneDocumentTreeIntoSelf(
874 const MaybeDiscarded<BrowsingContext>& aSourceBC,
875 const embedding::PrintData& aPrintData) {
876 #ifdef NS_PRINTING
877 if (NS_WARN_IF(aSourceBC.IsNullOrDiscarded())) {
878 return NS_ERROR_FAILURE;
880 nsCOMPtr<Document> sourceDocument = aSourceBC.get()->GetDocument();
881 if (NS_WARN_IF(!sourceDocument)) {
882 return NS_ERROR_FAILURE;
885 nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
886 if (NS_WARN_IF(!ourDocShell)) {
887 return NS_ERROR_FAILURE;
890 nsCOMPtr<nsIDocumentViewer> viewer;
891 ourDocShell->GetDocViewer(getter_AddRefs(viewer));
892 if (NS_WARN_IF(!viewer)) {
893 return NS_ERROR_FAILURE;
896 nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
897 do_GetService("@mozilla.org/gfx/printsettings-service;1");
898 if (NS_WARN_IF(!printSettingsSvc)) {
899 return NS_ERROR_FAILURE;
902 nsCOMPtr<nsIPrintSettings> printSettings;
903 nsresult rv =
904 printSettingsSvc->CreateNewPrintSettings(getter_AddRefs(printSettings));
905 if (NS_WARN_IF(NS_FAILED(rv))) {
906 return rv;
909 printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
911 RefPtr<Document> clone;
913 AutoPrintEventDispatcher dispatcher(*sourceDocument);
914 nsAutoScriptBlocker scriptBlocker;
915 bool hasInProcessCallbacks = false;
916 clone = sourceDocument->CreateStaticClone(
917 ourDocShell, viewer, printSettings, &hasInProcessCallbacks);
918 if (NS_WARN_IF(!clone)) {
919 return NS_ERROR_FAILURE;
923 rv = UpdateRemotePrintSettings(aPrintData);
924 if (NS_FAILED(rv)) {
925 return rv;
928 #endif
929 return NS_OK;
932 mozilla::ipc::IPCResult BrowserChild::RecvCloneDocumentTreeIntoSelf(
933 const MaybeDiscarded<BrowsingContext>& aSourceBC,
934 const embedding::PrintData& aPrintData,
935 CloneDocumentTreeIntoSelfResolver&& aResolve) {
936 nsresult rv = NS_OK;
938 #ifdef NS_PRINTING
939 rv = CloneDocumentTreeIntoSelf(aSourceBC, aPrintData);
940 #endif
942 aResolve(NS_SUCCEEDED(rv));
943 return IPC_OK();
946 nsresult BrowserChild::UpdateRemotePrintSettings(
947 const embedding::PrintData& aPrintData) {
948 #ifdef NS_PRINTING
949 nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
950 if (NS_WARN_IF(!ourDocShell)) {
951 return NS_ERROR_FAILURE;
954 RefPtr<Document> doc = ourDocShell->GetExtantDocument();
955 if (NS_WARN_IF(!doc) || NS_WARN_IF(!doc->IsStaticDocument())) {
956 return NS_ERROR_FAILURE;
959 RefPtr<BrowsingContext> bc = ourDocShell->GetBrowsingContext();
960 if (NS_WARN_IF(!bc)) {
961 return NS_ERROR_FAILURE;
964 nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
965 do_GetService("@mozilla.org/gfx/printsettings-service;1");
966 if (NS_WARN_IF(!printSettingsSvc)) {
967 return NS_ERROR_FAILURE;
970 nsCOMPtr<nsIPrintSettings> printSettings;
971 nsresult rv =
972 printSettingsSvc->CreateNewPrintSettings(getter_AddRefs(printSettings));
973 if (NS_WARN_IF(NS_FAILED(rv))) {
974 return rv;
977 printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
979 bc->PreOrderWalk([&](BrowsingContext* aBc) {
980 if (nsCOMPtr<nsIDocShell> inProcess = aBc->GetDocShell()) {
981 nsCOMPtr<nsIDocumentViewer> viewer;
982 inProcess->GetDocViewer(getter_AddRefs(viewer));
983 if (NS_WARN_IF(!viewer)) {
984 return BrowsingContext::WalkFlag::Skip;
986 // The CanRunScript analysis is not smart enough to see across
987 // the std::function PreOrderWalk uses, so we cheat a bit here, but it is
988 // fine because PreOrderWalk does deal with arbitrary script changing the
989 // BC tree, and our code above is simple enough and keeps strong refs to
990 // everything.
991 ([&]() MOZ_CAN_RUN_SCRIPT_BOUNDARY {
992 RefPtr<RemotePrintJobChild> printJob =
993 static_cast<RemotePrintJobChild*>(
994 aPrintData.remotePrintJob().AsChild());
995 viewer->SetPrintSettingsForSubdocument(printSettings, printJob);
996 }());
997 } else if (RefPtr<BrowserBridgeChild> remoteChild =
998 BrowserBridgeChild::GetFrom(aBc->GetEmbedderElement())) {
999 Unused << remoteChild->SendUpdateRemotePrintSettings(aPrintData);
1000 return BrowsingContext::WalkFlag::Skip;
1002 return BrowsingContext::WalkFlag::Next;
1004 #endif
1006 return NS_OK;
1009 mozilla::ipc::IPCResult BrowserChild::RecvUpdateRemotePrintSettings(
1010 const embedding::PrintData& aPrintData) {
1011 #ifdef NS_PRINTING
1012 UpdateRemotePrintSettings(aPrintData);
1013 #endif
1015 return IPC_OK();
1018 void BrowserChild::DoFakeShow(const ParentShowInfo& aParentShowInfo) {
1019 OwnerShowInfo ownerInfo{ScreenIntSize(), ScrollbarPreference::Auto,
1020 nsSizeMode_Normal};
1021 RecvShow(aParentShowInfo, ownerInfo);
1022 mDidFakeShow = true;
1025 void BrowserChild::ApplyParentShowInfo(const ParentShowInfo& aInfo) {
1026 // Even if we already set real show info, the dpi / rounding & scale may still
1027 // be invalid (if BrowserParent wasn't able to get widget it would just send
1028 // 0). So better to always set up-to-date values here.
1029 if (aInfo.dpi() > 0) {
1030 mPuppetWidget->UpdateBackingScaleCache(aInfo.dpi(), aInfo.widgetRounding(),
1031 aInfo.defaultScale());
1034 if (mDidSetRealShowInfo) {
1035 return;
1038 if (!aInfo.fakeShowInfo()) {
1039 // Once we've got one ShowInfo from parent, no need to update the values
1040 // anymore.
1041 mDidSetRealShowInfo = true;
1044 mIsTransparent = aInfo.isTransparent();
1047 mozilla::ipc::IPCResult BrowserChild::RecvShow(
1048 const ParentShowInfo& aParentInfo, const OwnerShowInfo& aOwnerInfo) {
1049 bool res = true;
1051 mPuppetWidget->SetSizeMode(aOwnerInfo.sizeMode());
1052 if (!mDidFakeShow) {
1053 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
1054 if (!baseWindow) {
1055 NS_ERROR("WebNavigation() doesn't QI to nsIBaseWindow");
1056 return IPC_FAIL_NO_REASON(this);
1059 baseWindow->SetVisibility(true);
1060 res = InitBrowserChildMessageManager();
1063 ApplyParentShowInfo(aParentInfo);
1065 if (!mIsTopLevel) {
1066 RecvScrollbarPreferenceChanged(aOwnerInfo.scrollbarPreference());
1069 if (!res) {
1070 return IPC_FAIL_NO_REASON(this);
1073 UpdateVisibility();
1075 return IPC_OK();
1078 mozilla::ipc::IPCResult BrowserChild::RecvInitRendering(
1079 const TextureFactoryIdentifier& aTextureFactoryIdentifier,
1080 const layers::LayersId& aLayersId,
1081 const CompositorOptions& aCompositorOptions, const bool& aLayersConnected) {
1082 mLayersConnected = Some(aLayersConnected);
1083 mLayersConnectRequested = Some(aLayersConnected);
1084 InitRenderingState(aTextureFactoryIdentifier, aLayersId, aCompositorOptions);
1085 return IPC_OK();
1088 mozilla::ipc::IPCResult BrowserChild::RecvScrollbarPreferenceChanged(
1089 ScrollbarPreference aPreference) {
1090 MOZ_ASSERT(!mIsTopLevel,
1091 "Scrollbar visibility should be derived from chrome flags for "
1092 "top-level windows");
1093 if (nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation())) {
1094 nsDocShell::Cast(docShell)->SetScrollbarPreference(aPreference);
1096 return IPC_OK();
1099 mozilla::ipc::IPCResult BrowserChild::RecvCompositorOptionsChanged(
1100 const CompositorOptions& aNewOptions) {
1101 MOZ_ASSERT(mCompositorOptions);
1103 // The only compositor option we currently support changing is APZ
1104 // enablement. Even that is only partially supported for now:
1105 // * Going from APZ to non-APZ is fine - we just flip the stored flag.
1106 // Note that we keep the actors (mApzcTreeManager, and the APZChild
1107 // created in InitAPZState()) around (read on for why).
1108 // * Going from non-APZ to APZ is only supported if we were using
1109 // APZ initially (at InitRendering() time) and we are transitioning
1110 // back. In this case, we just reuse the actors which we kept around.
1111 // Fully supporting a non-APZ to APZ transition (i.e. even in cases
1112 // where we initialized as non-APZ) would require setting up the actors
1113 // here. (In that case, we would also have the options of destroying
1114 // the actors in the APZ --> non-APZ case, and always re-creating them
1115 // during a non-APZ --> APZ transition).
1116 mCompositorOptions->SetUseAPZ(aNewOptions.UseAPZ());
1117 return IPC_OK();
1120 mozilla::ipc::IPCResult BrowserChild::RecvUpdateDimensions(
1121 const DimensionInfo& aDimensionInfo) {
1122 if (mLayersConnected.isNothing()) {
1123 return IPC_OK();
1126 mUnscaledOuterRect = aDimensionInfo.rect();
1127 mClientOffset = aDimensionInfo.clientOffset();
1128 mChromeOffset = aDimensionInfo.chromeOffset();
1129 MOZ_ASSERT_IF(!IsTopLevel(), mChromeOffset == LayoutDeviceIntPoint());
1131 SetUnscaledInnerSize(aDimensionInfo.size());
1132 if (!mHasValidInnerSize && aDimensionInfo.size().width != 0 &&
1133 aDimensionInfo.size().height != 0) {
1134 mHasValidInnerSize = true;
1137 ScreenIntSize screenSize = GetInnerSize();
1138 ScreenIntRect screenRect = GetOuterRect();
1140 // Make sure to set the size on the document viewer first. The
1141 // MobileViewportManager needs the content viewer size to be updated before
1142 // the reflow, otherwise it gets a stale size when it computes a new CSS
1143 // viewport.
1144 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
1145 baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height,
1146 nsIBaseWindow::eRepaint);
1148 mPuppetWidget->Resize(screenRect.x + mClientOffset.x + mChromeOffset.x,
1149 screenRect.y + mClientOffset.y + mChromeOffset.y,
1150 screenSize.width, screenSize.height, true);
1152 RecvSafeAreaInsetsChanged(mPuppetWidget->GetSafeAreaInsets());
1154 return IPC_OK();
1157 mozilla::ipc::IPCResult BrowserChild::RecvSizeModeChanged(
1158 const nsSizeMode& aSizeMode) {
1159 mPuppetWidget->SetSizeMode(aSizeMode);
1160 if (!mPuppetWidget->IsVisible()) {
1161 return IPC_OK();
1163 nsCOMPtr<Document> document(GetTopLevelDocument());
1164 if (!document) {
1165 return IPC_OK();
1167 nsPresContext* presContext = document->GetPresContext();
1168 if (presContext) {
1169 presContext->SizeModeChanged(aSizeMode);
1171 return IPC_OK();
1174 mozilla::ipc::IPCResult BrowserChild::RecvChildToParentMatrix(
1175 const Maybe<gfx::Matrix4x4>& aMatrix,
1176 const ScreenRect& aTopLevelViewportVisibleRectInBrowserCoords) {
1177 mChildToParentConversionMatrix =
1178 LayoutDeviceToLayoutDeviceMatrix4x4::FromUnknownMatrix(aMatrix);
1179 mTopLevelViewportVisibleRectInBrowserCoords =
1180 aTopLevelViewportVisibleRectInBrowserCoords;
1182 if (mContentTransformPromise) {
1183 mContentTransformPromise->MaybeResolveWithUndefined();
1184 mContentTransformPromise = nullptr;
1187 // Trigger an intersection observation update since ancestor viewports
1188 // changed.
1189 if (RefPtr<Document> toplevelDoc = GetTopLevelDocument()) {
1190 if (nsPresContext* pc = toplevelDoc->GetPresContext()) {
1191 pc->RefreshDriver()->EnsureIntersectionObservationsUpdateHappens();
1195 return IPC_OK();
1198 mozilla::ipc::IPCResult BrowserChild::RecvUpdateRemoteStyle(
1199 const StyleImageRendering& aImageRendering) {
1200 BrowsingContext* context = GetBrowsingContext();
1201 if (!context) {
1202 return IPC_OK();
1205 Document* document = context->GetDocument();
1206 if (!document) {
1207 return IPC_OK();
1210 if (document->IsImageDocument()) {
1211 document->AsImageDocument()->UpdateRemoteStyle(aImageRendering);
1214 return IPC_OK();
1217 mozilla::ipc::IPCResult BrowserChild::RecvDynamicToolbarMaxHeightChanged(
1218 const ScreenIntCoord& aHeight) {
1219 #if defined(MOZ_WIDGET_ANDROID)
1220 mDynamicToolbarMaxHeight = aHeight;
1222 RefPtr<Document> document = GetTopLevelDocument();
1223 if (!document) {
1224 return IPC_OK();
1227 if (RefPtr<nsPresContext> presContext = document->GetPresContext()) {
1228 presContext->SetDynamicToolbarMaxHeight(aHeight);
1230 #endif
1231 return IPC_OK();
1234 mozilla::ipc::IPCResult BrowserChild::RecvDynamicToolbarOffsetChanged(
1235 const ScreenIntCoord& aOffset) {
1236 #if defined(MOZ_WIDGET_ANDROID)
1237 RefPtr<Document> document = GetTopLevelDocument();
1238 if (!document) {
1239 return IPC_OK();
1242 if (nsPresContext* presContext = document->GetPresContext()) {
1243 presContext->UpdateDynamicToolbarOffset(aOffset);
1245 #endif
1246 return IPC_OK();
1249 mozilla::ipc::IPCResult BrowserChild::RecvSuppressDisplayport(
1250 const bool& aEnabled) {
1251 if (RefPtr<PresShell> presShell = GetTopLevelPresShell()) {
1252 presShell->SuppressDisplayport(aEnabled);
1254 return IPC_OK();
1257 void BrowserChild::HandleDoubleTap(const CSSPoint& aPoint,
1258 const Modifiers& aModifiers,
1259 const ScrollableLayerGuid& aGuid,
1260 const DoubleTapToZoomMetrics& aMetrics) {
1261 MOZ_LOG(
1262 sApzChildLog, LogLevel::Debug,
1263 ("Handling double tap at %s with %p %p\n", ToString(aPoint).c_str(),
1264 mBrowserChildMessageManager ? mBrowserChildMessageManager->GetWrapper()
1265 : nullptr,
1266 mBrowserChildMessageManager.get()));
1268 if (!mBrowserChildMessageManager) {
1269 return;
1272 // Note: there is nothing to do with the modifiers here, as we are not
1273 // synthesizing any sort of mouse event.
1274 RefPtr<Document> document = GetTopLevelDocument();
1275 ZoomTarget zoomTarget = CalculateRectToZoomTo(document, aPoint, aMetrics);
1276 // The double-tap can be dispatched by any scroll frame (so |aGuid| could be
1277 // the guid of any scroll frame), but the zoom-to-rect operation must be
1278 // performed by the root content scroll frame, so query its identifiers
1279 // for the SendZoomToRect() call rather than using the ones from |aGuid|.
1280 uint32_t presShellId;
1281 ViewID viewId;
1282 if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(
1283 document->GetDocumentElement(), &presShellId, &viewId) &&
1284 mApzcTreeManager) {
1285 ScrollableLayerGuid guid(mLayersId, presShellId, viewId);
1287 mApzcTreeManager->ZoomToRect(guid, zoomTarget,
1288 ZoomToRectBehavior::DEFAULT_BEHAVIOR);
1292 mozilla::ipc::IPCResult BrowserChild::RecvHandleTap(
1293 const GeckoContentController::TapType& aType,
1294 const LayoutDevicePoint& aPoint, const Modifiers& aModifiers,
1295 const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId,
1296 const Maybe<DoubleTapToZoomMetrics>& aDoubleTapToZoomMetrics) {
1297 // IPDL doesn't hold a strong reference to protocols as they're not required
1298 // to be refcounted. This function can run script, which may trigger a nested
1299 // event loop, which may release this, so we hold a strong reference here.
1300 RefPtr<BrowserChild> kungFuDeathGrip(this);
1301 RefPtr<PresShell> presShell = GetTopLevelPresShell();
1302 if (!presShell || !presShell->GetPresContext() || !mAPZEventState) {
1303 return IPC_OK();
1305 CSSToLayoutDeviceScale scale(
1306 presShell->GetPresContext()->CSSToDevPixelScale());
1307 CSSPoint point = aPoint / scale;
1309 // Stash the guid in InputAPZContext so that when the visual-to-layout
1310 // transform is applied to the event's coordinates, we use the right transform
1311 // based on the scroll frame being targeted.
1312 // The other values don't really matter.
1313 InputAPZContext context(aGuid, aInputBlockId, nsEventStatus_eSentinel);
1315 switch (aType) {
1316 case GeckoContentController::TapType::eSingleTap:
1317 if (mBrowserChildMessageManager) {
1318 RefPtr<APZEventState> eventState(mAPZEventState);
1319 eventState->ProcessSingleTap(point, scale, aModifiers, 1,
1320 aInputBlockId);
1322 break;
1323 case GeckoContentController::TapType::eDoubleTap:
1324 HandleDoubleTap(point, aModifiers, aGuid, *aDoubleTapToZoomMetrics);
1325 break;
1326 case GeckoContentController::TapType::eSecondTap:
1327 if (mBrowserChildMessageManager) {
1328 RefPtr<APZEventState> eventState(mAPZEventState);
1329 eventState->ProcessSingleTap(point, scale, aModifiers, 2,
1330 aInputBlockId);
1332 break;
1333 case GeckoContentController::TapType::eLongTap:
1334 if (mBrowserChildMessageManager) {
1335 RefPtr<APZEventState> eventState(mAPZEventState);
1336 eventState->ProcessLongTap(presShell, point, scale, aModifiers,
1337 aInputBlockId);
1339 break;
1340 case GeckoContentController::TapType::eLongTapUp:
1341 if (mBrowserChildMessageManager) {
1342 RefPtr<APZEventState> eventState(mAPZEventState);
1343 eventState->ProcessLongTapUp(presShell, point, scale, aModifiers);
1345 break;
1347 return IPC_OK();
1350 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityHandleTap(
1351 const GeckoContentController::TapType& aType,
1352 const LayoutDevicePoint& aPoint, const Modifiers& aModifiers,
1353 const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId,
1354 const Maybe<DoubleTapToZoomMetrics>& aDoubleTapToZoomMetrics) {
1355 // IPDL doesn't hold a strong reference to protocols as they're not required
1356 // to be refcounted. This function can run script, which may trigger a nested
1357 // event loop, which may release this, so we hold a strong reference here.
1358 RefPtr<BrowserChild> kungFuDeathGrip(this);
1359 return RecvHandleTap(aType, aPoint, aModifiers, aGuid, aInputBlockId,
1360 aDoubleTapToZoomMetrics);
1363 void BrowserChild::NotifyAPZStateChange(
1364 const ViewID& aViewId,
1365 const layers::GeckoContentController::APZStateChange& aChange,
1366 const int& aArg, Maybe<uint64_t> aInputBlockId) {
1367 if (mAPZEventState) {
1368 mAPZEventState->ProcessAPZStateChange(aViewId, aChange, aArg,
1369 aInputBlockId);
1371 nsCOMPtr<nsIObserverService> observerService =
1372 mozilla::services::GetObserverService();
1373 if (aChange ==
1374 layers::GeckoContentController::APZStateChange::eTransformEnd) {
1375 // This is used by tests to determine when the APZ is done doing whatever
1376 // it's doing. XXX generify this as needed when writing additional tests.
1377 observerService->NotifyObservers(nullptr, "APZ:TransformEnd", nullptr);
1378 observerService->NotifyObservers(nullptr, "PanZoom:StateChange",
1379 u"NOTHING");
1380 } else if (aChange ==
1381 layers::GeckoContentController::APZStateChange::eTransformBegin) {
1382 observerService->NotifyObservers(nullptr, "PanZoom:StateChange",
1383 u"PANNING");
1387 void BrowserChild::StartScrollbarDrag(
1388 const layers::AsyncDragMetrics& aDragMetrics) {
1389 ScrollableLayerGuid guid(mLayersId, aDragMetrics.mPresShellId,
1390 aDragMetrics.mViewId);
1392 if (mApzcTreeManager) {
1393 mApzcTreeManager->StartScrollbarDrag(guid, aDragMetrics);
1397 void BrowserChild::ZoomToRect(const uint32_t& aPresShellId,
1398 const ScrollableLayerGuid::ViewID& aViewId,
1399 const CSSRect& aRect, const uint32_t& aFlags) {
1400 ScrollableLayerGuid guid(mLayersId, aPresShellId, aViewId);
1402 if (mApzcTreeManager) {
1403 mApzcTreeManager->ZoomToRect(guid, ZoomTarget{aRect}, aFlags);
1407 mozilla::ipc::IPCResult BrowserChild::RecvActivate(uint64_t aActionId) {
1408 MOZ_ASSERT(mWebBrowser);
1409 mWebBrowser->FocusActivate(aActionId);
1410 return IPC_OK();
1413 mozilla::ipc::IPCResult BrowserChild::RecvDeactivate(uint64_t aActionId) {
1414 MOZ_ASSERT(mWebBrowser);
1415 mWebBrowser->FocusDeactivate(aActionId);
1416 return IPC_OK();
1419 mozilla::ipc::IPCResult BrowserChild::RecvStopIMEStateManagement() {
1420 IMEStateManager::StopIMEStateManagement();
1421 return IPC_OK();
1424 void BrowserChild::ProcessPendingCoalescedTouchData() {
1425 MOZ_ASSERT(StaticPrefs::dom_events_coalesce_touchmove());
1427 if (mCoalescedTouchData.IsEmpty()) {
1428 return;
1431 if (mCoalescedTouchMoveEventFlusher) {
1432 mCoalescedTouchMoveEventFlusher->RemoveObserver();
1435 UniquePtr<WidgetTouchEvent> touchMoveEvent =
1436 mCoalescedTouchData.TakeCoalescedEvent();
1437 Unused << RecvRealTouchEvent(*touchMoveEvent,
1438 mCoalescedTouchData.GetScrollableLayerGuid(),
1439 mCoalescedTouchData.GetInputBlockId(),
1440 mCoalescedTouchData.GetApzResponse());
1443 void BrowserChild::ProcessPendingCoalescedMouseDataAndDispatchEvents() {
1444 if (!mCoalesceMouseMoveEvents || !mCoalescedMouseEventFlusher) {
1445 // We don't enable mouse coalescing or we are destroying BrowserChild.
1446 return;
1449 // We may reentry the event loop and push more data to
1450 // mToBeDispatchedMouseData while dispatching an event.
1452 // We may have some pending coalesced data while dispatch an event and reentry
1453 // the event loop. In that case we don't have chance to consume the remainding
1454 // pending data until we get new mouse events. Get some helps from
1455 // mCoalescedMouseEventFlusher to trigger it.
1456 mCoalescedMouseEventFlusher->StartObserver();
1458 while (mToBeDispatchedMouseData.GetSize() > 0) {
1459 UniquePtr<CoalescedMouseData> data(
1460 static_cast<CoalescedMouseData*>(mToBeDispatchedMouseData.PopFront()));
1462 UniquePtr<WidgetMouseEvent> event = data->TakeCoalescedEvent();
1463 if (event) {
1464 // Dispatch the pending events. Using HandleRealMouseButtonEvent
1465 // to bypass the coalesce handling in RecvRealMouseMoveEvent. Can't use
1466 // RecvRealMouseButtonEvent because we may also put some mouse events
1467 // other than mousemove.
1468 HandleRealMouseButtonEvent(*event, data->GetScrollableLayerGuid(),
1469 data->GetInputBlockId());
1472 // mCoalescedMouseEventFlusher may be destroyed when reentrying the event
1473 // loop.
1474 if (mCoalescedMouseEventFlusher) {
1475 mCoalescedMouseEventFlusher->RemoveObserver();
1479 LayoutDeviceToLayoutDeviceMatrix4x4
1480 BrowserChild::GetChildToParentConversionMatrix() const {
1481 if (mChildToParentConversionMatrix) {
1482 return *mChildToParentConversionMatrix;
1484 LayoutDevicePoint offset(GetChromeOffset());
1485 return LayoutDeviceToLayoutDeviceMatrix4x4::Translation(offset);
1488 Maybe<ScreenRect> BrowserChild::GetTopLevelViewportVisibleRectInBrowserCoords()
1489 const {
1490 if (!mChildToParentConversionMatrix) {
1491 return Nothing();
1493 return Some(mTopLevelViewportVisibleRectInBrowserCoords);
1496 void BrowserChild::FlushAllCoalescedMouseData() {
1497 MOZ_ASSERT(mCoalesceMouseMoveEvents);
1499 // Move all entries from mCoalescedMouseData to mToBeDispatchedMouseData.
1500 for (const auto& data : mCoalescedMouseData.Values()) {
1501 if (!data || data->IsEmpty()) {
1502 continue;
1504 UniquePtr<CoalescedMouseData> dispatchData =
1505 MakeUnique<CoalescedMouseData>();
1507 dispatchData->RetrieveDataFrom(*data);
1508 mToBeDispatchedMouseData.Push(dispatchData.release());
1510 mCoalescedMouseData.Clear();
1513 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseMoveEvent(
1514 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1515 const uint64_t& aInputBlockId) {
1516 if (mCoalesceMouseMoveEvents && mCoalescedMouseEventFlusher) {
1517 CoalescedMouseData* data =
1518 mCoalescedMouseData.GetOrInsertNew(aEvent.pointerId);
1519 MOZ_ASSERT(data);
1520 if (data->CanCoalesce(aEvent, aGuid, aInputBlockId)) {
1521 data->Coalesce(aEvent, aGuid, aInputBlockId);
1522 mCoalescedMouseEventFlusher->StartObserver();
1523 return IPC_OK();
1525 // Can't coalesce current mousemove event. Put the coalesced mousemove data
1526 // with the same pointer id to mToBeDispatchedMouseData, coalesce the
1527 // current one, and process all pending data in mToBeDispatchedMouseData.
1528 UniquePtr<CoalescedMouseData> dispatchData =
1529 MakeUnique<CoalescedMouseData>();
1531 dispatchData->RetrieveDataFrom(*data);
1532 mToBeDispatchedMouseData.Push(dispatchData.release());
1534 // Put new data to replace the old one in the hash table.
1535 CoalescedMouseData* newData =
1536 mCoalescedMouseData
1537 .InsertOrUpdate(aEvent.pointerId, MakeUnique<CoalescedMouseData>())
1538 .get();
1539 newData->Coalesce(aEvent, aGuid, aInputBlockId);
1541 // Dispatch all pending mouse events.
1542 ProcessPendingCoalescedMouseDataAndDispatchEvents();
1543 mCoalescedMouseEventFlusher->StartObserver();
1544 } else if (!RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId)) {
1545 return IPC_FAIL_NO_REASON(this);
1547 return IPC_OK();
1550 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseMoveEventForTests(
1551 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1552 const uint64_t& aInputBlockId) {
1553 return RecvRealMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1556 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseMoveEvent(
1557 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1558 const uint64_t& aInputBlockId) {
1559 return RecvRealMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1562 mozilla::ipc::IPCResult
1563 BrowserChild::RecvNormalPriorityRealMouseMoveEventForTests(
1564 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1565 const uint64_t& aInputBlockId) {
1566 return RecvRealMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1569 mozilla::ipc::IPCResult BrowserChild::RecvSynthMouseMoveEvent(
1570 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1571 const uint64_t& aInputBlockId) {
1572 if (!RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId)) {
1573 return IPC_FAIL_NO_REASON(this);
1575 return IPC_OK();
1578 mozilla::ipc::IPCResult BrowserChild::RecvNormalPrioritySynthMouseMoveEvent(
1579 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1580 const uint64_t& aInputBlockId) {
1581 return RecvSynthMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1584 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseButtonEvent(
1585 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1586 const uint64_t& aInputBlockId) {
1587 if (mCoalesceMouseMoveEvents && mCoalescedMouseEventFlusher &&
1588 aEvent.mMessage != eMouseMove) {
1589 // When receiving a mouse event other than mousemove, we have to dispatch
1590 // all coalesced events before it. However, we can't dispatch all pending
1591 // coalesced events directly because we may reentry the event loop while
1592 // dispatching. To make sure we won't dispatch disorder events, we move all
1593 // coalesced mousemove events and current event to a deque to dispatch them.
1594 // When reentrying the event loop and dispatching more events, we put new
1595 // events in the end of the nsQueue and dispatch events from the beginning.
1596 FlushAllCoalescedMouseData();
1598 UniquePtr<CoalescedMouseData> dispatchData =
1599 MakeUnique<CoalescedMouseData>();
1601 dispatchData->Coalesce(aEvent, aGuid, aInputBlockId);
1602 mToBeDispatchedMouseData.Push(dispatchData.release());
1604 ProcessPendingCoalescedMouseDataAndDispatchEvents();
1605 return IPC_OK();
1607 HandleRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1608 return IPC_OK();
1611 void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
1612 const ScrollableLayerGuid& aGuid,
1613 const uint64_t& aInputBlockId) {
1614 WidgetMouseEvent localEvent(aEvent);
1615 localEvent.mWidget = mPuppetWidget;
1617 // We need one InputAPZContext here to propagate |aGuid| to places in
1618 // SendSetTargetAPZCNotification() which apply the visual-to-layout transform,
1619 // and another below to propagate the |postLayerization| flag (whose value
1620 // we don't know until SendSetTargetAPZCNotification() returns) into
1621 // the event dispatch code.
1622 InputAPZContext context1(aGuid, aInputBlockId, nsEventStatus_eSentinel);
1624 // Mouse events like eMouseEnterIntoWidget, that are created in the parent
1625 // process EventStateManager code, have an input block id which they get from
1626 // the InputAPZContext in the parent process stack. However, they did not
1627 // actually go through the APZ code and so their mHandledByAPZ flag is false.
1628 // Since thos events didn't go through APZ, we don't need to send
1629 // notifications for them.
1630 RefPtr<DisplayportSetListener> postLayerization;
1631 if (aInputBlockId && localEvent.mFlags.mHandledByAPZ) {
1632 nsCOMPtr<Document> document(GetTopLevelDocument());
1633 postLayerization = APZCCallbackHelper::SendSetTargetAPZCNotification(
1634 mPuppetWidget, document, localEvent, aGuid.mLayersId, aInputBlockId);
1637 InputAPZContext context2(aGuid, aInputBlockId, nsEventStatus_eSentinel,
1638 postLayerization != nullptr);
1640 DispatchWidgetEventViaAPZ(localEvent);
1642 if (aInputBlockId && localEvent.mFlags.mHandledByAPZ && mAPZEventState) {
1643 mAPZEventState->ProcessMouseEvent(localEvent, aInputBlockId);
1646 // Do this after the DispatchWidgetEventViaAPZ call above, so that if the
1647 // mouse event triggered a post-refresh AsyncDragMetrics message to be sent
1648 // to APZ (from scrollbar dragging in nsSliderFrame), then that will reach
1649 // APZ before the SetTargetAPZC message. This ensures the drag input block
1650 // gets the drag metrics before handling the input events.
1651 if (postLayerization) {
1652 postLayerization->Register();
1656 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseButtonEvent(
1657 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1658 const uint64_t& aInputBlockId) {
1659 return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1662 mozilla::ipc::IPCResult BrowserChild::RecvRealMouseEnterExitWidgetEvent(
1663 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1664 const uint64_t& aInputBlockId) {
1665 return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1668 mozilla::ipc::IPCResult
1669 BrowserChild::RecvNormalPriorityRealMouseEnterExitWidgetEvent(
1670 const WidgetMouseEvent& aEvent, const ScrollableLayerGuid& aGuid,
1671 const uint64_t& aInputBlockId) {
1672 return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1675 nsEventStatus BrowserChild::DispatchWidgetEventViaAPZ(WidgetGUIEvent& aEvent) {
1676 aEvent.ResetWaitingReplyFromRemoteProcessState();
1677 return APZCCallbackHelper::DispatchWidgetEvent(aEvent);
1680 void BrowserChild::DispatchCoalescedWheelEvent() {
1681 UniquePtr<WidgetWheelEvent> wheelEvent =
1682 mCoalescedWheelData.TakeCoalescedEvent();
1683 MOZ_ASSERT(wheelEvent);
1684 DispatchWheelEvent(*wheelEvent, mCoalescedWheelData.GetScrollableLayerGuid(),
1685 mCoalescedWheelData.GetInputBlockId());
1688 void BrowserChild::DispatchWheelEvent(const WidgetWheelEvent& aEvent,
1689 const ScrollableLayerGuid& aGuid,
1690 const uint64_t& aInputBlockId) {
1691 WidgetWheelEvent localEvent(aEvent);
1692 if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) {
1693 nsCOMPtr<Document> document(GetTopLevelDocument());
1694 RefPtr<DisplayportSetListener> postLayerization =
1695 APZCCallbackHelper::SendSetTargetAPZCNotification(
1696 mPuppetWidget, document, aEvent, aGuid.mLayersId, aInputBlockId);
1697 if (postLayerization) {
1698 postLayerization->Register();
1702 localEvent.mWidget = mPuppetWidget;
1704 // Stash the guid in InputAPZContext so that when the visual-to-layout
1705 // transform is applied to the event's coordinates, we use the right transform
1706 // based on the scroll frame being targeted.
1707 // The other values don't really matter.
1708 InputAPZContext context(aGuid, aInputBlockId, nsEventStatus_eSentinel);
1710 DispatchWidgetEventViaAPZ(localEvent);
1712 if (localEvent.mCanTriggerSwipe) {
1713 SendRespondStartSwipeEvent(aInputBlockId, localEvent.TriggersSwipe());
1716 if (aInputBlockId && aEvent.mFlags.mHandledByAPZ && mAPZEventState) {
1717 mAPZEventState->ProcessWheelEvent(localEvent, aInputBlockId);
1721 mozilla::ipc::IPCResult BrowserChild::RecvMouseWheelEvent(
1722 const WidgetWheelEvent& aEvent, const ScrollableLayerGuid& aGuid,
1723 const uint64_t& aInputBlockId) {
1724 bool isNextWheelEvent = false;
1725 // We only coalesce the current event when
1726 // 1. It's eWheel (we don't coalesce eOperationStart and eWheelOperationEnd)
1727 // 2. It has same attributes as the coalesced wheel event which is not yet
1728 // fired.
1729 if (aEvent.mMessage == eWheel) {
1730 GetIPCChannel()->PeekMessages(
1731 [&isNextWheelEvent](const IPC::Message& aMsg) -> bool {
1732 if (aMsg.type() == mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID) {
1733 isNextWheelEvent = true;
1735 return false; // Stop peeking.
1738 if (!mCoalescedWheelData.IsEmpty() &&
1739 !mCoalescedWheelData.CanCoalesce(aEvent, aGuid, aInputBlockId)) {
1740 DispatchCoalescedWheelEvent();
1741 MOZ_ASSERT(mCoalescedWheelData.IsEmpty());
1743 mCoalescedWheelData.Coalesce(aEvent, aGuid, aInputBlockId);
1745 MOZ_ASSERT(!mCoalescedWheelData.IsEmpty());
1746 // If the next event isn't a wheel event, make sure we dispatch.
1747 if (!isNextWheelEvent) {
1748 DispatchCoalescedWheelEvent();
1750 } else {
1751 DispatchWheelEvent(aEvent, aGuid, aInputBlockId);
1754 return IPC_OK();
1757 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityMouseWheelEvent(
1758 const WidgetWheelEvent& aEvent, const ScrollableLayerGuid& aGuid,
1759 const uint64_t& aInputBlockId) {
1760 return RecvMouseWheelEvent(aEvent, aGuid, aInputBlockId);
1763 mozilla::ipc::IPCResult BrowserChild::RecvRealTouchEvent(
1764 const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
1765 const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) {
1766 MOZ_LOG(sApzChildLog, LogLevel::Debug,
1767 ("Receiving touch event of type %d\n", aEvent.mMessage));
1769 if (StaticPrefs::dom_events_coalesce_touchmove()) {
1770 if (aEvent.mMessage == eTouchEnd || aEvent.mMessage == eTouchStart) {
1771 ProcessPendingCoalescedTouchData();
1774 if (aEvent.mMessage != eTouchMove) {
1775 sConsecutiveTouchMoveCount = 0;
1779 WidgetTouchEvent localEvent(aEvent);
1780 localEvent.mWidget = mPuppetWidget;
1782 // Stash the guid in InputAPZContext so that when the visual-to-layout
1783 // transform is applied to the event's coordinates, we use the right transform
1784 // based on the scroll frame being targeted.
1785 // The other values don't really matter.
1786 InputAPZContext context(aGuid, aInputBlockId, aApzResponse);
1788 nsTArray<TouchBehaviorFlags> allowedTouchBehaviors;
1789 if (localEvent.mMessage == eTouchStart && AsyncPanZoomEnabled()) {
1790 nsCOMPtr<Document> document = GetTopLevelDocument();
1791 allowedTouchBehaviors = TouchActionHelper::GetAllowedTouchBehavior(
1792 mPuppetWidget, document, localEvent);
1793 if (!allowedTouchBehaviors.IsEmpty() && mApzcTreeManager) {
1794 mApzcTreeManager->SetAllowedTouchBehavior(aInputBlockId,
1795 allowedTouchBehaviors);
1797 RefPtr<DisplayportSetListener> postLayerization =
1798 APZCCallbackHelper::SendSetTargetAPZCNotification(
1799 mPuppetWidget, document, localEvent, aGuid.mLayersId,
1800 aInputBlockId);
1801 if (postLayerization) {
1802 postLayerization->Register();
1806 // Dispatch event to content (potentially a long-running operation)
1807 nsEventStatus status = DispatchWidgetEventViaAPZ(localEvent);
1809 if (!AsyncPanZoomEnabled()) {
1810 // We shouldn't have any e10s platforms that have touch events enabled
1811 // without APZ.
1812 MOZ_ASSERT(false);
1813 return IPC_OK();
1816 if (mAPZEventState) {
1817 mAPZEventState->ProcessTouchEvent(localEvent, aGuid, aInputBlockId,
1818 aApzResponse, status,
1819 std::move(allowedTouchBehaviors));
1821 return IPC_OK();
1824 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealTouchEvent(
1825 const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
1826 const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) {
1827 return RecvRealTouchEvent(aEvent, aGuid, aInputBlockId, aApzResponse);
1830 mozilla::ipc::IPCResult BrowserChild::RecvRealTouchMoveEvent(
1831 const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
1832 const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) {
1833 if (StaticPrefs::dom_events_coalesce_touchmove()) {
1834 ++sConsecutiveTouchMoveCount;
1835 if (mCoalescedTouchMoveEventFlusher) {
1836 MOZ_ASSERT(aEvent.mMessage == eTouchMove);
1837 if (mCoalescedTouchData.IsEmpty() ||
1838 mCoalescedTouchData.CanCoalesce(aEvent, aGuid, aInputBlockId,
1839 aApzResponse)) {
1840 mCoalescedTouchData.Coalesce(aEvent, aGuid, aInputBlockId,
1841 aApzResponse);
1842 } else {
1843 UniquePtr<WidgetTouchEvent> touchMoveEvent =
1844 mCoalescedTouchData.TakeCoalescedEvent();
1846 mCoalescedTouchData.Coalesce(aEvent, aGuid, aInputBlockId,
1847 aApzResponse);
1849 if (!RecvRealTouchEvent(*touchMoveEvent,
1850 mCoalescedTouchData.GetScrollableLayerGuid(),
1851 mCoalescedTouchData.GetInputBlockId(),
1852 mCoalescedTouchData.GetApzResponse())) {
1853 return IPC_FAIL_NO_REASON(this);
1857 if (sConsecutiveTouchMoveCount > 1) {
1858 mCoalescedTouchMoveEventFlusher->StartObserver();
1859 } else {
1860 // Flush the pending coalesced touch in order to avoid the first
1861 // touchmove be overridden by the second one.
1862 ProcessPendingCoalescedTouchData();
1864 return IPC_OK();
1868 if (!RecvRealTouchEvent(aEvent, aGuid, aInputBlockId, aApzResponse)) {
1869 return IPC_FAIL_NO_REASON(this);
1871 return IPC_OK();
1874 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealTouchMoveEvent(
1875 const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
1876 const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) {
1877 return RecvRealTouchMoveEvent(aEvent, aGuid, aInputBlockId, aApzResponse);
1880 mozilla::ipc::IPCResult BrowserChild::RecvRealDragEvent(
1881 const WidgetDragEvent& aEvent, const uint32_t& aDragAction,
1882 const uint32_t& aDropEffect, nsIPrincipal* aPrincipal,
1883 nsIContentSecurityPolicy* aCsp) {
1884 WidgetDragEvent localEvent(aEvent);
1885 localEvent.mWidget = mPuppetWidget;
1887 nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
1888 if (dragSession) {
1889 dragSession->SetDragAction(aDragAction);
1890 dragSession->SetTriggeringPrincipal(aPrincipal);
1891 dragSession->SetCsp(aCsp);
1892 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
1893 if (initialDataTransfer) {
1894 initialDataTransfer->SetDropEffectInt(aDropEffect);
1898 if (aEvent.mMessage == eDrop) {
1899 bool canDrop = true;
1900 if (!dragSession || NS_FAILED(dragSession->GetCanDrop(&canDrop)) ||
1901 !canDrop) {
1902 localEvent.mMessage = eDragExit;
1904 } else if (aEvent.mMessage == eDragOver) {
1905 nsCOMPtr<nsIDragService> dragService =
1906 do_GetService("@mozilla.org/widget/dragservice;1");
1907 if (dragService) {
1908 // This will dispatch 'drag' event at the source if the
1909 // drag transaction started in this process.
1910 dragService->FireDragEventAtSource(eDrag, aEvent.mModifiers);
1914 DispatchWidgetEventViaAPZ(localEvent);
1915 return IPC_OK();
1918 void BrowserChild::RequestEditCommands(NativeKeyBindingsType aType,
1919 const WidgetKeyboardEvent& aEvent,
1920 nsTArray<CommandInt>& aCommands) {
1921 MOZ_ASSERT(aCommands.IsEmpty());
1923 if (NS_WARN_IF(aEvent.IsEditCommandsInitialized(aType))) {
1924 aCommands = aEvent.EditCommandsConstRef(aType).Clone();
1925 return;
1928 switch (aType) {
1929 case NativeKeyBindingsType::SingleLineEditor:
1930 case NativeKeyBindingsType::MultiLineEditor:
1931 case NativeKeyBindingsType::RichTextEditor:
1932 break;
1933 default:
1934 MOZ_ASSERT_UNREACHABLE("Invalid native key bindings type");
1937 // Don't send aEvent to the parent process directly because it'll be marked
1938 // as posted to remote process.
1939 WidgetKeyboardEvent localEvent(aEvent);
1940 SendRequestNativeKeyBindings(static_cast<uint32_t>(aType), localEvent,
1941 &aCommands);
1944 mozilla::ipc::IPCResult BrowserChild::RecvNativeSynthesisResponse(
1945 const uint64_t& aObserverId, const nsCString& aResponse) {
1946 mozilla::widget::AutoObserverNotifier::NotifySavedObserver(aObserverId,
1947 aResponse.get());
1948 return IPC_OK();
1951 mozilla::ipc::IPCResult BrowserChild::RecvUpdateSHistory() {
1952 if (mSessionStoreChild) {
1953 mSessionStoreChild->UpdateSHistoryChanges();
1955 return IPC_OK();
1958 // In case handling repeated keys takes much time, we skip firing new ones.
1959 bool BrowserChild::SkipRepeatedKeyEvent(const WidgetKeyboardEvent& aEvent) {
1960 if (mRepeatedKeyEventTime.IsNull() || !aEvent.CanSkipInRemoteProcess() ||
1961 (aEvent.mMessage != eKeyDown && aEvent.mMessage != eKeyPress)) {
1962 mRepeatedKeyEventTime = TimeStamp();
1963 mSkipKeyPress = false;
1964 return false;
1967 if ((aEvent.mMessage == eKeyDown &&
1968 (mRepeatedKeyEventTime > aEvent.mTimeStamp)) ||
1969 (mSkipKeyPress && (aEvent.mMessage == eKeyPress))) {
1970 // If we skip a keydown event, also the following keypress events should be
1971 // skipped.
1972 mSkipKeyPress |= aEvent.mMessage == eKeyDown;
1973 return true;
1976 if (aEvent.mMessage == eKeyDown) {
1977 // If keydown wasn't skipped, nor should the possible following keypress.
1978 mRepeatedKeyEventTime = TimeStamp();
1979 mSkipKeyPress = false;
1981 return false;
1984 void BrowserChild::UpdateRepeatedKeyEventEndTime(
1985 const WidgetKeyboardEvent& aEvent) {
1986 if (aEvent.mIsRepeat &&
1987 (aEvent.mMessage == eKeyDown || aEvent.mMessage == eKeyPress)) {
1988 mRepeatedKeyEventTime = TimeStamp::Now();
1992 mozilla::ipc::IPCResult BrowserChild::RecvRealKeyEvent(
1993 const WidgetKeyboardEvent& aEvent, const nsID& aUUID) {
1994 MOZ_ASSERT_IF(aEvent.mMessage == eKeyPress,
1995 aEvent.AreAllEditCommandsInitialized());
1997 // If content code called preventDefault() on a keydown event, then we don't
1998 // want to process any following keypress events.
1999 const bool isPrecedingKeyDownEventConsumed =
2000 aEvent.mMessage == eKeyPress && mIgnoreKeyPressEvent;
2002 WidgetKeyboardEvent localEvent(aEvent);
2003 localEvent.mWidget = mPuppetWidget;
2004 localEvent.mUniqueId = aEvent.mUniqueId;
2006 if (!SkipRepeatedKeyEvent(aEvent) && !isPrecedingKeyDownEventConsumed) {
2007 nsEventStatus status = DispatchWidgetEventViaAPZ(localEvent);
2009 // Update the end time of the possible repeated event so that we can skip
2010 // some incoming events in case event handling took long time.
2011 UpdateRepeatedKeyEventEndTime(localEvent);
2013 if (aEvent.mMessage == eKeyDown) {
2014 mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
2017 if (localEvent.mFlags.mIsSuppressedOrDelayed) {
2018 localEvent.PreventDefault();
2021 // If the event's default isn't prevented but the status is no default,
2022 // That means that the event was consumed by EventStateManager or something
2023 // which is not a usual event handler. In such case, prevent its default
2024 // as a default handler. For example, when an eKeyPress event matches
2025 // with a content accesskey, and it's executed, preventDefault() of the
2026 // event won't be called but the status is set to "no default". Then,
2027 // the event shouldn't be handled by nsMenuBarListener in the main process.
2028 if (!localEvent.DefaultPrevented() &&
2029 status == nsEventStatus_eConsumeNoDefault) {
2030 localEvent.PreventDefault();
2033 MOZ_DIAGNOSTIC_ASSERT(!localEvent.PropagationStopped());
2035 // The keyboard event which we ignore should not be handled in the main
2036 // process for shortcut key handling. For notifying if we skipped it, we can
2037 // use "stop propagation" flag here because it must be cleared by
2038 // `EventTargetChainItem` if we've dispatched it.
2039 else {
2040 localEvent.StopPropagation();
2043 // If we don't need to send a rely for the given keyboard event, we do nothing
2044 // anymore here.
2045 if (!aEvent.WantReplyFromContentProcess()) {
2046 return IPC_OK();
2049 // This is an ugly hack, mNoRemoteProcessDispatch is set to true when the
2050 // event's PreventDefault() or StopScrollProcessForwarding() is called.
2051 // And then, it'll be checked by ParamTraits<mozilla::WidgetEvent>::Write()
2052 // whether the event is being sent to remote process unexpectedly.
2053 // However, unfortunately, it cannot check the destination. Therefore,
2054 // we need to clear the flag explicitly here because ParamTraits should
2055 // keep checking the flag for avoiding regression.
2056 localEvent.mFlags.mNoRemoteProcessDispatch = false;
2057 SendReplyKeyEvent(localEvent, aUUID);
2059 return IPC_OK();
2062 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealKeyEvent(
2063 const WidgetKeyboardEvent& aEvent, const nsID& aUUID) {
2064 return RecvRealKeyEvent(aEvent, aUUID);
2067 mozilla::ipc::IPCResult BrowserChild::RecvCompositionEvent(
2068 const WidgetCompositionEvent& aEvent) {
2069 WidgetCompositionEvent localEvent(aEvent);
2070 localEvent.mWidget = mPuppetWidget;
2071 DispatchWidgetEventViaAPZ(localEvent);
2072 Unused << SendOnEventNeedingAckHandled(aEvent.mMessage,
2073 localEvent.mCompositionId);
2074 return IPC_OK();
2077 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityCompositionEvent(
2078 const WidgetCompositionEvent& aEvent) {
2079 return RecvCompositionEvent(aEvent);
2082 mozilla::ipc::IPCResult BrowserChild::RecvSelectionEvent(
2083 const WidgetSelectionEvent& aEvent) {
2084 WidgetSelectionEvent localEvent(aEvent);
2085 localEvent.mWidget = mPuppetWidget;
2086 DispatchWidgetEventViaAPZ(localEvent);
2087 Unused << SendOnEventNeedingAckHandled(aEvent.mMessage, 0u);
2088 return IPC_OK();
2091 mozilla::ipc::IPCResult BrowserChild::RecvNormalPrioritySelectionEvent(
2092 const WidgetSelectionEvent& aEvent) {
2093 return RecvSelectionEvent(aEvent);
2096 mozilla::ipc::IPCResult BrowserChild::RecvInsertText(
2097 const nsAString& aStringToInsert) {
2098 // Use normal event path to reach focused document.
2099 WidgetContentCommandEvent localEvent(true, eContentCommandInsertText,
2100 mPuppetWidget);
2101 localEvent.mString = Some(nsString(aStringToInsert));
2102 DispatchWidgetEventViaAPZ(localEvent);
2103 return IPC_OK();
2106 mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityInsertText(
2107 const nsAString& aStringToInsert) {
2108 return RecvInsertText(aStringToInsert);
2111 mozilla::ipc::IPCResult BrowserChild::RecvPasteTransferable(
2112 const IPCTransferable& aTransferable) {
2113 nsresult rv;
2114 nsCOMPtr<nsITransferable> trans =
2115 do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
2116 NS_ENSURE_SUCCESS(rv, IPC_OK());
2117 trans->Init(nullptr);
2119 rv = nsContentUtils::IPCTransferableToTransferable(
2120 aTransferable, true /* aAddDataFlavor */, trans,
2121 false /* aFilterUnknownFlavors */);
2122 NS_ENSURE_SUCCESS(rv, IPC_OK());
2124 nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
2125 if (NS_WARN_IF(!ourDocShell)) {
2126 return IPC_OK();
2129 RefPtr<nsCommandParams> params = new nsCommandParams();
2130 rv = params->SetISupports("transferable", trans);
2131 NS_ENSURE_SUCCESS(rv, IPC_OK());
2133 ourDocShell->DoCommandWithParams("cmd_pasteTransferable", params);
2134 return IPC_OK();
2137 #ifdef ACCESSIBILITY
2138 a11y::PDocAccessibleChild* BrowserChild::AllocPDocAccessibleChild(
2139 PDocAccessibleChild*, const uint64_t&,
2140 const MaybeDiscardedBrowsingContext&) {
2141 MOZ_ASSERT(false, "should never call this!");
2142 return nullptr;
2145 bool BrowserChild::DeallocPDocAccessibleChild(
2146 a11y::PDocAccessibleChild* aChild) {
2147 delete static_cast<mozilla::a11y::DocAccessibleChild*>(aChild);
2148 return true;
2150 #endif
2152 RefPtr<VsyncMainChild> BrowserChild::GetVsyncChild() {
2153 // Initializing mVsyncChild here turns on per-BrowserChild Vsync for a
2154 // given platform. Note: this only makes sense if nsWindow returns a
2155 // window-specific VsyncSource.
2156 #if defined(MOZ_WAYLAND)
2157 if (IsWaylandEnabled() && !mVsyncChild) {
2158 mVsyncChild = MakeRefPtr<VsyncMainChild>();
2159 if (!SendPVsyncConstructor(mVsyncChild)) {
2160 mVsyncChild = nullptr;
2163 #endif
2164 return mVsyncChild;
2167 mozilla::ipc::IPCResult BrowserChild::RecvLoadRemoteScript(
2168 const nsAString& aURL, const bool& aRunInGlobalScope) {
2169 if (!InitBrowserChildMessageManager())
2170 // This can happen if we're half-destroyed. It's not a fatal
2171 // error.
2172 return IPC_OK();
2174 JS::Rooted<JSObject*> mm(RootingCx(),
2175 mBrowserChildMessageManager->GetOrCreateWrapper());
2176 if (!mm) {
2177 // This can happen if we're half-destroyed. It's not a fatal error.
2178 return IPC_OK();
2181 LoadScriptInternal(mm, aURL, !aRunInGlobalScope);
2182 return IPC_OK();
2185 mozilla::ipc::IPCResult BrowserChild::RecvAsyncMessage(
2186 const nsAString& aMessage, const ClonedMessageData& aData) {
2187 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("BrowserChild::RecvAsyncMessage",
2188 OTHER, aMessage);
2189 MMPrinter::Print("BrowserChild::RecvAsyncMessage", aMessage, aData);
2191 if (!mBrowserChildMessageManager) {
2192 return IPC_OK();
2195 RefPtr<nsFrameMessageManager> mm =
2196 mBrowserChildMessageManager->GetMessageManager();
2198 // We should have a message manager if the global is alive, but it
2199 // seems sometimes we don't. Assert in aurora/nightly, but don't
2200 // crash in release builds.
2201 MOZ_DIAGNOSTIC_ASSERT(mm);
2202 if (!mm) {
2203 return IPC_OK();
2206 JS::Rooted<JSObject*> kungFuDeathGrip(
2207 dom::RootingCx(), mBrowserChildMessageManager->GetWrapper());
2208 StructuredCloneData data;
2209 UnpackClonedMessageData(aData, data);
2210 mm->ReceiveMessage(static_cast<EventTarget*>(mBrowserChildMessageManager),
2211 nullptr, aMessage, false, &data, nullptr, IgnoreErrors());
2212 return IPC_OK();
2215 mozilla::ipc::IPCResult BrowserChild::RecvSwappedWithOtherRemoteLoader(
2216 const IPCTabContext& aContext) {
2217 nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
2218 if (NS_WARN_IF(!ourDocShell)) {
2219 return IPC_OK();
2222 nsCOMPtr<nsPIDOMWindowOuter> ourWindow = ourDocShell->GetWindow();
2223 if (NS_WARN_IF(!ourWindow)) {
2224 return IPC_OK();
2227 RefPtr<nsDocShell> docShell = static_cast<nsDocShell*>(ourDocShell.get());
2229 nsCOMPtr<EventTarget> ourEventTarget = nsGlobalWindowOuter::Cast(ourWindow);
2231 docShell->SetInFrameSwap(true);
2233 nsContentUtils::FirePageShowEventForFrameLoaderSwap(
2234 ourDocShell, ourEventTarget, false, true);
2235 nsContentUtils::FirePageHideEventForFrameLoaderSwap(ourDocShell,
2236 ourEventTarget, true);
2238 // Owner content type may have changed, so store the possibly updated context
2239 // and notify others.
2240 MaybeInvalidTabContext maybeContext(aContext);
2241 if (!maybeContext.IsValid()) {
2242 NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
2243 "the parent process. (%s)",
2244 maybeContext.GetInvalidReason())
2245 .get());
2246 MOZ_CRASH("Invalid TabContext received from the parent process.");
2249 if (!UpdateTabContextAfterSwap(maybeContext.GetTabContext())) {
2250 MOZ_CRASH("Update to TabContext after swap was denied.");
2253 // Ignore previous value of mTriedBrowserInit since owner content has changed.
2254 mTriedBrowserInit = true;
2256 nsContentUtils::FirePageShowEventForFrameLoaderSwap(
2257 ourDocShell, ourEventTarget, true, true);
2259 docShell->SetInFrameSwap(false);
2261 // This is needed to get visibility state right in cases when we swapped a
2262 // visible tab (foreground in visible window) with a non-visible tab.
2263 if (RefPtr<Document> doc = docShell->GetDocument()) {
2264 doc->UpdateVisibilityState();
2267 return IPC_OK();
2270 mozilla::ipc::IPCResult BrowserChild::RecvHandleAccessKey(
2271 const WidgetKeyboardEvent& aEvent, nsTArray<uint32_t>&& aCharCodes) {
2272 nsCOMPtr<Document> document(GetTopLevelDocument());
2273 RefPtr<nsPresContext> pc = document->GetPresContext();
2274 if (pc) {
2275 if (!pc->EventStateManager()->HandleAccessKey(
2276 &(const_cast<WidgetKeyboardEvent&>(aEvent)), pc, aCharCodes)) {
2277 // If no accesskey was found, inform the parent so that accesskeys on
2278 // menus can be handled.
2279 WidgetKeyboardEvent localEvent(aEvent);
2280 localEvent.mWidget = mPuppetWidget;
2281 SendAccessKeyNotHandled(localEvent);
2285 return IPC_OK();
2288 mozilla::ipc::IPCResult BrowserChild::RecvPrintPreview(
2289 const PrintData& aPrintData, const MaybeDiscardedBrowsingContext& aSourceBC,
2290 PrintPreviewResolver&& aCallback) {
2291 #ifdef NS_PRINTING
2292 // If we didn't succeed in passing off ownership of aCallback, then something
2293 // went wrong.
2294 auto sendCallbackError = MakeScopeExit([&] {
2295 if (aCallback) {
2296 // signal error
2297 aCallback(PrintPreviewResultInfo(0, 0, false, false, false, {}, {}, {}));
2301 if (NS_WARN_IF(aSourceBC.IsDiscarded())) {
2302 return IPC_OK();
2305 RefPtr<nsGlobalWindowOuter> sourceWindow;
2306 if (!aSourceBC.IsNull()) {
2307 sourceWindow = nsGlobalWindowOuter::Cast(aSourceBC.get()->GetDOMWindow());
2308 if (NS_WARN_IF(!sourceWindow)) {
2309 return IPC_OK();
2311 } else {
2312 nsCOMPtr<nsPIDOMWindowOuter> ourWindow = do_GetInterface(WebNavigation());
2313 if (NS_WARN_IF(!ourWindow)) {
2314 return IPC_OK();
2316 sourceWindow = nsGlobalWindowOuter::Cast(ourWindow);
2319 RefPtr<nsIPrintSettings> printSettings;
2320 nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
2321 do_GetService("@mozilla.org/gfx/printsettings-service;1");
2322 if (NS_WARN_IF(!printSettingsSvc)) {
2323 return IPC_OK();
2325 printSettingsSvc->CreateNewPrintSettings(getter_AddRefs(printSettings));
2326 if (NS_WARN_IF(!printSettings)) {
2327 return IPC_OK();
2329 printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
2331 nsCOMPtr<nsIDocShell> docShellToCloneInto;
2332 if (!aSourceBC.IsNull()) {
2333 docShellToCloneInto = do_GetInterface(WebNavigation());
2334 if (NS_WARN_IF(!docShellToCloneInto)) {
2335 return IPC_OK();
2339 sourceWindow->Print(printSettings,
2340 /* aRemotePrintJob = */ nullptr,
2341 /* aListener = */ nullptr, docShellToCloneInto,
2342 nsGlobalWindowOuter::IsPreview::Yes,
2343 nsGlobalWindowOuter::IsForWindowDotPrint::No,
2344 std::move(aCallback), IgnoreErrors());
2345 #endif
2346 return IPC_OK();
2349 mozilla::ipc::IPCResult BrowserChild::RecvExitPrintPreview() {
2350 #ifdef NS_PRINTING
2351 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint =
2352 do_GetInterface(ToSupports(WebNavigation()));
2353 if (NS_WARN_IF(!webBrowserPrint)) {
2354 return IPC_OK();
2356 webBrowserPrint->ExitPrintPreview();
2357 #endif
2358 return IPC_OK();
2361 mozilla::ipc::IPCResult BrowserChild::RecvPrint(
2362 const MaybeDiscardedBrowsingContext& aBc, const PrintData& aPrintData) {
2363 #ifdef NS_PRINTING
2364 if (NS_WARN_IF(aBc.IsNullOrDiscarded())) {
2365 return IPC_OK();
2367 RefPtr<nsGlobalWindowOuter> outerWindow =
2368 nsGlobalWindowOuter::Cast(aBc.get()->GetDOMWindow());
2369 if (NS_WARN_IF(!outerWindow)) {
2370 return IPC_OK();
2373 nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
2374 do_GetService("@mozilla.org/gfx/printsettings-service;1");
2375 if (NS_WARN_IF(!printSettingsSvc)) {
2376 return IPC_OK();
2379 nsCOMPtr<nsIPrintSettings> printSettings;
2380 nsresult rv =
2381 printSettingsSvc->CreateNewPrintSettings(getter_AddRefs(printSettings));
2382 if (NS_WARN_IF(NS_FAILED(rv))) {
2383 return IPC_OK();
2386 printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
2388 IgnoredErrorResult rv;
2389 RefPtr printJob = static_cast<RemotePrintJobChild*>(
2390 aPrintData.remotePrintJob().AsChild());
2391 outerWindow->Print(printSettings, printJob,
2392 /* aListener = */ nullptr,
2393 /* aWindowToCloneInto = */ nullptr,
2394 nsGlobalWindowOuter::IsPreview::No,
2395 nsGlobalWindowOuter::IsForWindowDotPrint::No,
2396 /* aPrintPreviewCallback = */ nullptr, rv);
2397 if (NS_WARN_IF(rv.Failed())) {
2398 return IPC_OK();
2401 #endif
2402 return IPC_OK();
2405 mozilla::ipc::IPCResult BrowserChild::RecvUpdateNativeWindowHandle(
2406 const uintptr_t& aNewHandle) {
2407 #if defined(XP_WIN) && defined(ACCESSIBILITY)
2408 mNativeWindowHandle = aNewHandle;
2409 return IPC_OK();
2410 #else
2411 return IPC_FAIL_NO_REASON(this);
2412 #endif
2415 mozilla::ipc::IPCResult BrowserChild::RecvDestroy() {
2416 MOZ_ASSERT(!mDestroyed);
2417 mDestroyed = true;
2419 nsTArray<PContentPermissionRequestChild*> childArray =
2420 nsContentPermissionUtils::GetContentPermissionRequestChildById(
2421 GetTabId());
2423 // Need to close undeleted ContentPermissionRequestChilds before tab is
2424 // closed.
2425 for (auto& permissionRequestChild : childArray) {
2426 auto* child = static_cast<RemotePermissionRequest*>(permissionRequestChild);
2427 child->Destroy();
2430 if (mBrowserChildMessageManager) {
2431 // Message handlers are called from the event loop, so it better be safe to
2432 // run script.
2433 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
2434 mBrowserChildMessageManager->DispatchTrustedEvent(u"unload"_ns);
2437 nsCOMPtr<nsIObserverService> observerService =
2438 mozilla::services::GetObserverService();
2440 observerService->RemoveObserver(this, BEFORE_FIRST_PAINT);
2442 // XXX what other code in ~BrowserChild() should we be running here?
2443 DestroyWindow();
2445 // Bounce through the event loop once to allow any delayed teardown runnables
2446 // that were just generated to have a chance to run.
2447 nsCOMPtr<nsIRunnable> deleteRunnable = new DelayedDeleteRunnable(this);
2448 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(deleteRunnable));
2450 return IPC_OK();
2453 mozilla::ipc::IPCResult BrowserChild::RecvRenderLayers(const bool& aEnabled) {
2454 auto clearPaintWhileInterruptingJS = MakeScopeExit([&] {
2455 // We might force a paint, or we might already have painted and this is a
2456 // no-op. In either case, once we exit this scope, we need to alert the
2457 // ProcessHangMonitor that we've finished responding to what might have
2458 // been a request to force paint. This is so that the BackgroundHangMonitor
2459 // for force painting can be made to wait again.
2460 if (aEnabled) {
2461 ProcessHangMonitor::ClearPaintWhileInterruptingJS();
2465 if (aEnabled) {
2466 ProcessHangMonitor::MaybeStartPaintWhileInterruptingJS();
2469 mRenderLayers = aEnabled;
2470 const bool wasVisible = IsVisible();
2472 UpdateVisibility();
2474 // If we just became visible, try to trigger a paint as soon as possible.
2475 const bool becameVisible = !wasVisible && IsVisible();
2476 if (!becameVisible) {
2477 return IPC_OK();
2480 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2481 if (!docShell) {
2482 return IPC_OK();
2485 // We don't use BrowserChildBase::GetPresShell() here because that would
2486 // create a content viewer if one doesn't exist yet. Creating a content
2487 // viewer can cause JS to run, which we want to avoid.
2488 // nsIDocShell::GetPresShell returns null if no content viewer exists yet.
2489 RefPtr<PresShell> presShell = docShell->GetPresShell();
2490 if (!presShell) {
2491 return IPC_OK();
2494 if (nsIFrame* root = presShell->GetRootFrame()) {
2495 root->SchedulePaint();
2498 Telemetry::AutoTimer<Telemetry::TABCHILD_PAINT_TIME> timer;
2499 // If we need to repaint, let's do that right away. No sense waiting until
2500 // we get back to the event loop again. We suppress the display port so
2501 // that we only paint what's visible. This ensures that the tab we're
2502 // switching to paints as quickly as possible.
2503 presShell->SuppressDisplayport(true);
2504 if (nsContentUtils::IsSafeToRunScript()) {
2505 WebWidget()->PaintNowIfNeeded();
2506 } else {
2507 RefPtr<nsViewManager> vm = presShell->GetViewManager();
2508 if (nsView* view = vm->GetRootView()) {
2509 presShell->PaintAndRequestComposite(view, PaintFlags::None);
2512 presShell->SuppressDisplayport(false);
2513 return IPC_OK();
2516 mozilla::ipc::IPCResult BrowserChild::RecvNavigateByKey(
2517 const bool& aForward, const bool& aForDocumentNavigation) {
2518 nsFocusManager* fm = nsFocusManager::GetFocusManager();
2519 if (!fm) {
2520 return IPC_OK();
2523 RefPtr<Element> result;
2524 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
2526 // Move to the first or last document.
2528 uint32_t type =
2529 aForward
2530 ? (aForDocumentNavigation
2531 ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FIRSTDOC)
2532 : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_ROOT))
2533 : (aForDocumentNavigation
2534 ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LASTDOC)
2535 : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LAST));
2536 uint32_t flags = nsIFocusManager::FLAG_BYKEY;
2537 if (aForward || aForDocumentNavigation) {
2538 flags |= nsIFocusManager::FLAG_NOSCROLL;
2540 fm->MoveFocus(window, nullptr, type, flags, getter_AddRefs(result));
2543 // No valid root element was found, so move to the first focusable element.
2544 if (!result && aForward && !aForDocumentNavigation) {
2545 fm->MoveFocus(window, nullptr, nsIFocusManager::MOVEFOCUS_FIRST,
2546 nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
2549 SendRequestFocus(false, CallerType::System);
2550 return IPC_OK();
2553 bool BrowserChild::InitBrowserChildMessageManager() {
2554 mShouldSendWebProgressEventsToParent = true;
2556 if (!mBrowserChildMessageManager) {
2557 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
2558 NS_ENSURE_TRUE(window, false);
2559 nsCOMPtr<EventTarget> chromeHandler = window->GetChromeEventHandler();
2560 NS_ENSURE_TRUE(chromeHandler, false);
2562 RefPtr<BrowserChildMessageManager> scope = mBrowserChildMessageManager =
2563 new BrowserChildMessageManager(this);
2565 MOZ_ALWAYS_TRUE(nsMessageManagerScriptExecutor::Init());
2567 nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
2568 if (NS_WARN_IF(!root)) {
2569 mBrowserChildMessageManager = nullptr;
2570 return false;
2572 root->SetParentTarget(scope);
2575 if (!mTriedBrowserInit) {
2576 mTriedBrowserInit = true;
2579 return true;
2582 void BrowserChild::InitRenderingState(
2583 const TextureFactoryIdentifier& aTextureFactoryIdentifier,
2584 const layers::LayersId& aLayersId,
2585 const CompositorOptions& aCompositorOptions) {
2586 mPuppetWidget->InitIMEState();
2588 MOZ_ASSERT(aLayersId.IsValid());
2589 mTextureFactoryIdentifier = aTextureFactoryIdentifier;
2591 // Pushing layers transactions directly to a separate
2592 // compositor context.
2593 PCompositorBridgeChild* compositorChild = CompositorBridgeChild::Get();
2594 if (!compositorChild) {
2595 mLayersConnected = Some(false);
2596 NS_WARNING("failed to get CompositorBridgeChild instance");
2597 return;
2600 mCompositorOptions = Some(aCompositorOptions);
2602 if (aLayersId.IsValid()) {
2603 StaticMutexAutoLock lock(sBrowserChildrenMutex);
2605 if (!sBrowserChildren) {
2606 sBrowserChildren = new BrowserChildMap;
2608 MOZ_ASSERT(!sBrowserChildren->Contains(uint64_t(aLayersId)));
2609 sBrowserChildren->InsertOrUpdate(uint64_t(aLayersId), this);
2610 mLayersId = aLayersId;
2613 // Depending on timing, we might paint too early and fall back to basic
2614 // layers. CreateRemoteLayerManager will destroy us if we manage to get a
2615 // remote layer manager though, so that's fine.
2616 MOZ_ASSERT(!mPuppetWidget->HasWindowRenderer() ||
2617 mPuppetWidget->GetWindowRenderer()->GetBackendType() ==
2618 layers::LayersBackend::LAYERS_NONE);
2619 bool success = false;
2620 if (mLayersConnected == Some(true)) {
2621 success = CreateRemoteLayerManager(compositorChild);
2624 if (success) {
2625 MOZ_ASSERT(mLayersConnected == Some(true));
2626 // Succeeded to create "remote" layer manager
2627 ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
2628 gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
2629 InitAPZState();
2630 } else {
2631 NS_WARNING("Fallback to FallbackRenderer");
2632 mLayersConnected = Some(false);
2635 nsCOMPtr<nsIObserverService> observerService =
2636 mozilla::services::GetObserverService();
2638 if (observerService) {
2639 observerService->AddObserver(this, BEFORE_FIRST_PAINT, false);
2643 bool BrowserChild::CreateRemoteLayerManager(
2644 mozilla::layers::PCompositorBridgeChild* aCompositorChild) {
2645 MOZ_ASSERT(aCompositorChild);
2647 return mPuppetWidget->CreateRemoteLayerManager(
2648 [&](WebRenderLayerManager* aLayerManager) -> bool {
2649 nsCString error;
2650 return aLayerManager->Initialize(aCompositorChild,
2651 wr::AsPipelineId(mLayersId),
2652 &mTextureFactoryIdentifier, error);
2656 void BrowserChild::InitAPZState() {
2657 if (!mCompositorOptions->UseAPZ()) {
2658 return;
2660 auto* cbc = CompositorBridgeChild::Get();
2662 // Initialize the ApzcTreeManager. This takes multiple casts because of ugly
2663 // multiple inheritance.
2664 PAPZCTreeManagerChild* baseProtocol =
2665 cbc->SendPAPZCTreeManagerConstructor(mLayersId);
2666 if (!baseProtocol) {
2667 MOZ_ASSERT(false,
2668 "Allocating a TreeManager should not fail with APZ enabled");
2669 return;
2671 APZCTreeManagerChild* derivedProtocol =
2672 static_cast<APZCTreeManagerChild*>(baseProtocol);
2674 mApzcTreeManager = RefPtr<IAPZCTreeManager>(derivedProtocol);
2676 // Initialize the GeckoContentController for this tab. We don't hold a
2677 // reference because we don't need it. The ContentProcessController will hold
2678 // a reference to the tab, and will be destroyed by the compositor or ipdl
2679 // during destruction.
2680 RefPtr<GeckoContentController> contentController =
2681 new ContentProcessController(this);
2682 APZChild* apzChild = new APZChild(contentController);
2683 cbc->SendPAPZConstructor(apzChild, mLayersId);
2686 IPCResult BrowserChild::RecvUpdateEffects(const EffectsInfo& aEffects) {
2687 bool needInvalidate = false;
2688 if (mEffectsInfo.IsVisible() && aEffects.IsVisible() &&
2689 mEffectsInfo != aEffects) {
2690 // If we are staying visible and either the visrect or scale changed we need
2691 // to invalidate
2692 needInvalidate = true;
2695 mEffectsInfo = aEffects;
2696 UpdateVisibility();
2698 if (needInvalidate) {
2699 if (nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation())) {
2700 // We don't use BrowserChildBase::GetPresShell() here because that would
2701 // create a content viewer if one doesn't exist yet. Creating a content
2702 // viewer can cause JS to run, which we want to avoid.
2703 // nsIDocShell::GetPresShell returns null if no content viewer exists yet.
2704 if (RefPtr<PresShell> presShell = docShell->GetPresShell()) {
2705 if (nsIFrame* root = presShell->GetRootFrame()) {
2706 root->InvalidateFrame();
2712 return IPC_OK();
2715 bool BrowserChild::IsVisible() {
2716 return mPuppetWidget && mPuppetWidget->IsVisible();
2719 void BrowserChild::UpdateVisibility() {
2720 const bool shouldBeVisible = [&] {
2721 // If we're known to be visibility: hidden / display: none, just return
2722 // false here, we're pretty sure we don't want to be considered visible
2723 // here.
2724 if (mBrowsingContext && mBrowsingContext->IsUnderHiddenEmbedderElement()) {
2725 return false;
2727 // For OOP iframes, include viewport visibility. For top-level <browser>
2728 // elements we don't use this, because the front-end relies on using
2729 // `mRenderLayers` when invisible for tab warming purposes.
2731 // An alternative, maybe more consistent approach would be to add an opt-in
2732 // into this behavior for top-level tabs managed by the tab-switcher
2733 // instead...
2734 if (!mIsTopLevel && !mEffectsInfo.IsVisible()) {
2735 return false;
2737 // If we're explicitly told not to render layers, we're also invisible.
2738 if (!mRenderLayers) {
2739 return false;
2741 return true;
2742 }();
2744 const bool isVisible = IsVisible();
2745 if (shouldBeVisible == isVisible) {
2746 return;
2748 if (shouldBeVisible) {
2749 MakeVisible();
2750 } else {
2751 MakeHidden();
2755 void BrowserChild::MakeVisible() {
2756 if (IsVisible()) {
2757 return;
2760 if (mPuppetWidget) {
2761 mPuppetWidget->Show(true);
2764 PresShellActivenessMaybeChanged();
2767 void BrowserChild::MakeHidden() {
2768 if (!IsVisible()) {
2769 return;
2772 // Due to the nested event loop in ContentChild::ProvideWindowCommon,
2773 // it's possible to be told to become hidden before we're finished
2774 // setting up a layer manager. We should skip clearing cached layers
2775 // in that case, since doing so might accidentally put is into
2776 // BasicLayers mode.
2777 if (mPuppetWidget) {
2778 if (mPuppetWidget->HasWindowRenderer()) {
2779 ClearCachedResources();
2781 mPuppetWidget->Show(false);
2784 PresShellActivenessMaybeChanged();
2787 IPCResult BrowserChild::RecvPreserveLayers(bool aPreserve) {
2788 mIsPreservingLayers = aPreserve;
2790 PresShellActivenessMaybeChanged();
2792 return IPC_OK();
2795 void BrowserChild::PresShellActivenessMaybeChanged() {
2796 // We don't use BrowserChildBase::GetPresShell() here because that would
2797 // create a content viewer if one doesn't exist yet. Creating a content
2798 // viewer can cause JS to run, which we want to avoid.
2799 // nsIDocShell::GetPresShell returns null if no content viewer exists yet.
2801 // When this method is called we don't want to go through the browsing context
2802 // because we don't want to change the visibility state of the document, which
2803 // has side effects like firing events to content, unblocking media playback,
2804 // unthrottling timeouts... PresShell activeness has a lot less side effects.
2805 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2806 if (!docShell) {
2807 return;
2809 RefPtr<PresShell> presShell = docShell->GetPresShell();
2810 if (!presShell) {
2811 return;
2813 presShell->ActivenessMaybeChanged();
2816 NS_IMETHODIMP
2817 BrowserChild::GetMessageManager(ContentFrameMessageManager** aResult) {
2818 RefPtr<ContentFrameMessageManager> mm(mBrowserChildMessageManager);
2819 mm.forget(aResult);
2820 return *aResult ? NS_OK : NS_ERROR_FAILURE;
2823 void BrowserChild::SendRequestFocus(bool aCanFocus, CallerType aCallerType) {
2824 nsFocusManager* fm = nsFocusManager::GetFocusManager();
2825 if (!fm) {
2826 return;
2829 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
2830 if (!window) {
2831 return;
2834 BrowsingContext* focusedBC = fm->GetFocusedBrowsingContext();
2835 if (focusedBC == window->GetBrowsingContext()) {
2836 // BrowsingContext has the focus already, do not request again.
2837 return;
2840 PBrowserChild::SendRequestFocus(aCanFocus, aCallerType);
2843 NS_IMETHODIMP
2844 BrowserChild::GetTabId(uint64_t* aId) {
2845 *aId = GetTabId();
2846 return NS_OK;
2849 NS_IMETHODIMP
2850 BrowserChild::GetChromeOuterWindowID(uint64_t* aId) {
2851 *aId = ChromeOuterWindowID();
2852 return NS_OK;
2855 bool BrowserChild::DoSendBlockingMessage(
2856 const nsAString& aMessage, StructuredCloneData& aData,
2857 nsTArray<StructuredCloneData>* aRetVal) {
2858 ClonedMessageData data;
2859 if (!BuildClonedMessageData(aData, data)) {
2860 return false;
2862 return SendSyncMessage(PromiseFlatString(aMessage), data, aRetVal);
2865 nsresult BrowserChild::DoSendAsyncMessage(const nsAString& aMessage,
2866 StructuredCloneData& aData) {
2867 ClonedMessageData data;
2868 if (!BuildClonedMessageData(aData, data)) {
2869 return NS_ERROR_DOM_DATA_CLONE_ERR;
2871 if (!SendAsyncMessage(PromiseFlatString(aMessage), data)) {
2872 return NS_ERROR_UNEXPECTED;
2874 return NS_OK;
2877 /* static */
2878 nsTArray<RefPtr<BrowserChild>> BrowserChild::GetAll() {
2879 StaticMutexAutoLock lock(sBrowserChildrenMutex);
2881 if (!sBrowserChildren) {
2882 return {};
2885 return ToTArray<nsTArray<RefPtr<BrowserChild>>>(sBrowserChildren->Values());
2888 BrowserChild* BrowserChild::GetFrom(PresShell* aPresShell) {
2889 Document* doc = aPresShell->GetDocument();
2890 if (!doc) {
2891 return nullptr;
2893 nsCOMPtr<nsIDocShell> docShell(doc->GetDocShell());
2894 return GetFrom(docShell);
2897 BrowserChild* BrowserChild::GetFrom(layers::LayersId aLayersId) {
2898 StaticMutexAutoLock lock(sBrowserChildrenMutex);
2899 if (!sBrowserChildren) {
2900 return nullptr;
2902 return sBrowserChildren->Get(uint64_t(aLayersId));
2905 void BrowserChild::DidComposite(mozilla::layers::TransactionId aTransactionId,
2906 const TimeStamp& aCompositeStart,
2907 const TimeStamp& aCompositeEnd) {
2908 MOZ_ASSERT(mPuppetWidget);
2909 RefPtr<WebRenderLayerManager> lm =
2910 mPuppetWidget->GetWindowRenderer()->AsWebRender();
2911 MOZ_ASSERT(lm);
2913 if (lm) {
2914 lm->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
2918 void BrowserChild::ClearCachedResources() {
2919 MOZ_ASSERT(mPuppetWidget);
2920 RefPtr<WebRenderLayerManager> lm =
2921 mPuppetWidget->GetWindowRenderer()->AsWebRender();
2922 if (lm) {
2923 lm->ClearCachedResources();
2926 if (nsCOMPtr<Document> document = GetTopLevelDocument()) {
2927 nsPresContext* presContext = document->GetPresContext();
2928 if (presContext) {
2929 presContext->NotifyPaintStatusReset();
2934 void BrowserChild::SchedulePaint() {
2935 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2936 if (!docShell) {
2937 return;
2940 // We don't use BrowserChildBase::GetPresShell() here because that would
2941 // create a content viewer if one doesn't exist yet. Creating a content viewer
2942 // can cause JS to run, which we want to avoid. nsIDocShell::GetPresShell
2943 // returns null if no content viewer exists yet.
2944 if (RefPtr<PresShell> presShell = docShell->GetPresShell()) {
2945 if (nsIFrame* root = presShell->GetRootFrame()) {
2946 root->SchedulePaint();
2951 void BrowserChild::ReinitRendering() {
2952 MOZ_ASSERT(mLayersId.IsValid());
2954 // In some cases, like when we create a windowless browser,
2955 // RemoteLayerTreeOwner/BrowserChild is not connected to a compositor.
2956 if (mLayersConnectRequested.isNothing() ||
2957 mLayersConnectRequested == Some(false)) {
2958 return;
2961 // Before we establish a new PLayerTransaction, we must connect our layer tree
2962 // id, CompositorBridge, and the widget compositor all together again.
2963 // Normally this happens in BrowserParent before BrowserChild is given
2964 // rendering information.
2966 // In this case, we will send a sync message to our BrowserParent, which in
2967 // turn will send a sync message to the Compositor of the widget owning this
2968 // tab. This guarantees the correct association is in place before our
2969 // PLayerTransaction constructor message arrives on the cross-process
2970 // compositor bridge.
2971 CompositorOptions options;
2972 SendEnsureLayersConnected(&options);
2973 mCompositorOptions = Some(options);
2975 bool success = false;
2976 RefPtr<CompositorBridgeChild> cb = CompositorBridgeChild::Get();
2978 if (cb) {
2979 success = CreateRemoteLayerManager(cb);
2982 if (!success) {
2983 NS_WARNING("failed to recreate layer manager");
2984 return;
2987 mLayersConnected = Some(true);
2988 ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
2989 gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
2991 InitAPZState();
2992 if (nsCOMPtr<Document> doc = GetTopLevelDocument()) {
2993 doc->NotifyLayerManagerRecreated();
2996 if (mRenderLayers) {
2997 SchedulePaint();
3001 void BrowserChild::ReinitRenderingForDeviceReset() {
3002 RefPtr<WebRenderLayerManager> lm =
3003 mPuppetWidget->GetWindowRenderer()->AsWebRender();
3004 if (lm) {
3005 lm->DoDestroy(/* aIsSync */ true);
3008 // Proceed with destroying and recreating the layer manager.
3009 ReinitRendering();
3012 NS_IMETHODIMP
3013 BrowserChild::OnShowTooltip(int32_t aXCoords, int32_t aYCoords,
3014 const nsAString& aTipText,
3015 const nsAString& aTipDir) {
3016 nsString str(aTipText);
3017 nsString dir(aTipDir);
3018 SendShowTooltip(aXCoords, aYCoords, str, dir);
3019 return NS_OK;
3022 NS_IMETHODIMP
3023 BrowserChild::OnHideTooltip() {
3024 SendHideTooltip();
3025 return NS_OK;
3028 void BrowserChild::NotifyJankedAnimations(
3029 const nsTArray<uint64_t>& aJankedAnimations) {
3030 MOZ_ASSERT(mPuppetWidget);
3031 RefPtr<WebRenderLayerManager> lm =
3032 mPuppetWidget->GetWindowRenderer()->AsWebRender();
3033 if (lm) {
3034 lm->UpdatePartialPrerenderedAnimations(aJankedAnimations);
3038 mozilla::ipc::IPCResult BrowserChild::RecvUIResolutionChanged(
3039 const float& aDpi, const int32_t& aRounding, const double& aScale) {
3040 ScreenIntSize oldScreenSize = GetInnerSize();
3041 if (aDpi > 0) {
3042 mPuppetWidget->UpdateBackingScaleCache(aDpi, aRounding, aScale);
3045 ScreenIntSize screenSize = GetInnerSize();
3046 if (mHasValidInnerSize && oldScreenSize != screenSize) {
3047 ScreenIntRect screenRect = GetOuterRect();
3049 // See RecvUpdateDimensions for the order of these operations.
3050 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
3051 baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height,
3052 nsIBaseWindow::eRepaint);
3054 mPuppetWidget->Resize(screenRect.x + mClientOffset.x + mChromeOffset.x,
3055 screenRect.y + mClientOffset.y + mChromeOffset.y,
3056 screenSize.width, screenSize.height, true);
3059 nsCOMPtr<Document> document(GetTopLevelDocument());
3060 RefPtr<nsPresContext> presContext =
3061 document ? document->GetPresContext() : nullptr;
3062 if (presContext) {
3063 presContext->UIResolutionChangedSync();
3066 return IPC_OK();
3069 mozilla::ipc::IPCResult BrowserChild::RecvSafeAreaInsetsChanged(
3070 const mozilla::ScreenIntMargin& aSafeAreaInsets) {
3071 mPuppetWidget->UpdateSafeAreaInsets(aSafeAreaInsets);
3073 nsCOMPtr<nsIScreenManager> screenMgr =
3074 do_GetService("@mozilla.org/gfx/screenmanager;1");
3075 ScreenIntMargin currentSafeAreaInsets;
3076 if (screenMgr) {
3077 // aSafeAreaInsets is for current screen. But we have to calculate
3078 // safe insets for content window.
3079 int32_t x, y, cx, cy;
3080 GetDimensions(DimensionKind::Outer, &x, &y, &cx, &cy);
3081 nsCOMPtr<nsIScreen> screen;
3082 screenMgr->ScreenForRect(x, y, cx, cy, getter_AddRefs(screen));
3084 if (screen) {
3085 LayoutDeviceIntRect windowRect(x + mClientOffset.x + mChromeOffset.x,
3086 y + mClientOffset.y + mChromeOffset.y, cx,
3087 cy);
3088 currentSafeAreaInsets = nsContentUtils::GetWindowSafeAreaInsets(
3089 screen, aSafeAreaInsets, windowRect);
3093 if (nsCOMPtr<Document> document = GetTopLevelDocument()) {
3094 nsPresContext* presContext = document->GetPresContext();
3095 if (presContext) {
3096 presContext->SetSafeAreaInsets(currentSafeAreaInsets);
3100 // https://github.com/w3c/csswg-drafts/issues/4670
3101 // Actually we don't set this value on sub document. This behaviour is
3102 // same as Blink that safe area insets isn't set on sub document.
3104 return IPC_OK();
3107 mozilla::ipc::IPCResult BrowserChild::RecvAllowScriptsToClose() {
3108 nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
3109 if (window) {
3110 nsGlobalWindowOuter::Cast(window)->AllowScriptsToClose();
3112 return IPC_OK();
3115 mozilla::ipc::IPCResult BrowserChild::RecvReleaseAllPointerCapture() {
3116 PointerEventHandler::ReleaseAllPointerCapture();
3117 return IPC_OK();
3120 PPaymentRequestChild* BrowserChild::AllocPPaymentRequestChild() {
3121 MOZ_CRASH(
3122 "We should never be manually allocating PPaymentRequestChild actors");
3123 return nullptr;
3126 bool BrowserChild::DeallocPPaymentRequestChild(PPaymentRequestChild* actor) {
3127 delete actor;
3128 return true;
3131 ScreenIntSize BrowserChild::GetInnerSize() {
3132 LayoutDeviceIntSize innerSize =
3133 RoundedToInt(mUnscaledInnerSize * mPuppetWidget->GetDefaultScale());
3134 return ViewAs<ScreenPixel>(
3135 innerSize, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
3138 Maybe<nsRect> BrowserChild::GetVisibleRect() const {
3139 if (mIsTopLevel) {
3140 // We are conservative about visible rects for top-level browsers to avoid
3141 // artifacts when resizing
3142 return Nothing();
3144 return mEffectsInfo.mVisibleRect;
3147 Maybe<LayoutDeviceRect>
3148 BrowserChild::GetTopLevelViewportVisibleRectInSelfCoords() const {
3149 if (mIsTopLevel) {
3150 return Nothing();
3153 if (!mChildToParentConversionMatrix) {
3154 // We have no way to tell this remote document visible rect right now.
3155 return Nothing();
3158 Maybe<LayoutDeviceToLayoutDeviceMatrix4x4> inverse =
3159 mChildToParentConversionMatrix->MaybeInverse();
3160 if (!inverse) {
3161 return Nothing();
3164 // Convert the remote document visible rect to the coordinate system of the
3165 // iframe document.
3166 Maybe<LayoutDeviceRect> rect = UntransformBy(
3167 *inverse,
3168 ViewAs<LayoutDevicePixel>(
3169 mTopLevelViewportVisibleRectInBrowserCoords,
3170 PixelCastJustification::ContentProcessIsLayerInUiProcess),
3171 LayoutDeviceRect::MaxIntRect());
3172 if (!rect) {
3173 return Nothing();
3176 return rect;
3179 ScreenIntRect BrowserChild::GetOuterRect() {
3180 LayoutDeviceIntRect outerRect =
3181 RoundedToInt(mUnscaledOuterRect * mPuppetWidget->GetDefaultScale());
3182 return ViewAs<ScreenPixel>(
3183 outerRect, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
3186 void BrowserChild::PaintWhileInterruptingJS() {
3187 if (!IPCOpen() || !mPuppetWidget || !mPuppetWidget->HasWindowRenderer()) {
3188 // Don't bother doing anything now. Better to wait until we receive the
3189 // message on the PContent channel.
3190 return;
3193 MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::IsSafeToRunScript());
3194 nsAutoScriptBlocker scriptBlocker;
3195 RecvRenderLayers(/* aEnabled = */ true);
3198 void BrowserChild::UnloadLayersWhileInterruptingJS() {
3199 if (!IPCOpen() || !mPuppetWidget || !mPuppetWidget->HasWindowRenderer()) {
3200 // Don't bother doing anything now. Better to wait until we receive the
3201 // message on the PContent channel.
3202 return;
3205 MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::IsSafeToRunScript());
3206 nsAutoScriptBlocker scriptBlocker;
3207 RecvRenderLayers(/* aEnabled = */ false);
3210 nsresult BrowserChild::CanCancelContentJS(
3211 nsIRemoteTab::NavigationType aNavigationType, int32_t aNavigationIndex,
3212 nsIURI* aNavigationURI, int32_t aEpoch, bool* aCanCancel) {
3213 nsresult rv;
3214 *aCanCancel = false;
3216 if (aEpoch <= mCancelContentJSEpoch) {
3217 // The next page loaded before we got here, so we shouldn't try to cancel
3218 // the content JS.
3219 return NS_OK;
3222 // If we have session history in the parent we've already performed
3223 // the checks following, so we can return early.
3224 if (mozilla::SessionHistoryInParent()) {
3225 *aCanCancel = true;
3226 return NS_OK;
3229 nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
3230 nsCOMPtr<nsISHistory> history;
3231 if (docShell) {
3232 history = nsDocShell::Cast(docShell)->GetSessionHistory()->LegacySHistory();
3235 if (!history) {
3236 return NS_ERROR_FAILURE;
3239 int32_t current;
3240 rv = history->GetIndex(&current);
3241 NS_ENSURE_SUCCESS(rv, rv);
3243 if (current == -1) {
3244 // This tab has no history! Just return.
3245 return NS_OK;
3248 nsCOMPtr<nsISHEntry> entry;
3249 rv = history->GetEntryAtIndex(current, getter_AddRefs(entry));
3250 NS_ENSURE_SUCCESS(rv, rv);
3252 nsCOMPtr<nsIURI> currentURI = entry->GetURI();
3253 if (!currentURI->SchemeIs("http") && !currentURI->SchemeIs("https") &&
3254 !currentURI->SchemeIs("file")) {
3255 // Only cancel content JS for http(s) and file URIs. Other URIs are probably
3256 // internal and we should just let them run to completion.
3257 return NS_OK;
3260 if (aNavigationType == nsIRemoteTab::NAVIGATE_BACK) {
3261 aNavigationIndex = current - 1;
3262 } else if (aNavigationType == nsIRemoteTab::NAVIGATE_FORWARD) {
3263 aNavigationIndex = current + 1;
3264 } else if (aNavigationType == nsIRemoteTab::NAVIGATE_URL) {
3265 if (!aNavigationURI) {
3266 return NS_ERROR_FAILURE;
3269 if (aNavigationURI->SchemeIs("javascript")) {
3270 // "javascript:" URIs don't (necessarily) trigger navigation to a
3271 // different page, so don't allow the current page's JS to terminate.
3272 return NS_OK;
3275 // If navigating directly to a URL (e.g. via hitting Enter in the location
3276 // bar), then we can cancel anytime the next URL is different from the
3277 // current, *excluding* the ref ("#").
3278 bool equals;
3279 rv = currentURI->EqualsExceptRef(aNavigationURI, &equals);
3280 NS_ENSURE_SUCCESS(rv, rv);
3281 *aCanCancel = !equals;
3282 return NS_OK;
3284 // Note: aNavigationType may also be NAVIGATE_INDEX, in which case we don't
3285 // need to do anything special.
3287 int32_t delta = aNavigationIndex > current ? 1 : -1;
3288 for (int32_t i = current + delta; i != aNavigationIndex + delta; i += delta) {
3289 nsCOMPtr<nsISHEntry> nextEntry;
3290 // If `i` happens to be negative, this call will fail (which is what we
3291 // would want to happen).
3292 rv = history->GetEntryAtIndex(i, getter_AddRefs(nextEntry));
3293 NS_ENSURE_SUCCESS(rv, rv);
3295 nsCOMPtr<nsISHEntry> laterEntry = delta == 1 ? nextEntry : entry;
3296 nsCOMPtr<nsIURI> thisURI = entry->GetURI();
3297 nsCOMPtr<nsIURI> nextURI = nextEntry->GetURI();
3299 // If we changed origin and the load wasn't in a subframe, we know it was
3300 // a full document load, so we can cancel the content JS safely.
3301 if (!laterEntry->GetIsSubFrame()) {
3302 nsAutoCString thisHost;
3303 rv = thisURI->GetPrePath(thisHost);
3304 NS_ENSURE_SUCCESS(rv, rv);
3306 nsAutoCString nextHost;
3307 rv = nextURI->GetPrePath(nextHost);
3308 NS_ENSURE_SUCCESS(rv, rv);
3310 if (!thisHost.Equals(nextHost)) {
3311 *aCanCancel = true;
3312 return NS_OK;
3316 entry = nextEntry;
3319 return NS_OK;
3322 NS_IMETHODIMP BrowserChild::OnStateChange(nsIWebProgress* aWebProgress,
3323 nsIRequest* aRequest,
3324 uint32_t aStateFlags,
3325 nsresult aStatus) {
3326 if (!IPCOpen() || !mShouldSendWebProgressEventsToParent) {
3327 return NS_OK;
3330 // We shouldn't need to notify the parent of redirect state changes, since
3331 // with DocumentChannel that only happens when we switch to the real channel,
3332 // and that's an implementation detail that we can hide.
3333 if (aStateFlags & nsIWebProgressListener::STATE_IS_REDIRECTED_DOCUMENT) {
3334 return NS_OK;
3337 // Our OnStateChange call must have provided the nsIDocShell which the source
3338 // comes from. We'll use this to locate the corresponding BrowsingContext in
3339 // the parent process.
3340 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress);
3341 if (!docShell) {
3342 MOZ_ASSERT_UNREACHABLE("aWebProgress is null or not a nsIDocShell?");
3343 return NS_ERROR_UNEXPECTED;
3346 WebProgressData webProgressData;
3347 Maybe<WebProgressStateChangeData> stateChangeData;
3348 RequestData requestData;
3350 MOZ_TRY(PrepareProgressListenerData(aWebProgress, aRequest, webProgressData,
3351 requestData));
3353 RefPtr<BrowsingContext> browsingContext = docShell->GetBrowsingContext();
3354 if (browsingContext->IsTopContent()) {
3355 stateChangeData.emplace();
3357 stateChangeData->isNavigating() = docShell->GetIsNavigating();
3358 stateChangeData->mayEnableCharacterEncodingMenu() =
3359 docShell->GetMayEnableCharacterEncodingMenu();
3361 RefPtr<Document> document = browsingContext->GetExtantDocument();
3362 if (document && aStateFlags & nsIWebProgressListener::STATE_STOP) {
3363 document->GetContentType(stateChangeData->contentType());
3364 document->GetCharacterSet(stateChangeData->charset());
3365 stateChangeData->documentURI() = document->GetDocumentURIObject();
3366 } else {
3367 stateChangeData->contentType().SetIsVoid(true);
3368 stateChangeData->charset().SetIsVoid(true);
3372 Unused << SendOnStateChange(webProgressData, requestData, aStateFlags,
3373 aStatus, stateChangeData);
3375 return NS_OK;
3378 NS_IMETHODIMP BrowserChild::OnProgressChange(nsIWebProgress* aWebProgress,
3379 nsIRequest* aRequest,
3380 int32_t aCurSelfProgress,
3381 int32_t aMaxSelfProgress,
3382 int32_t aCurTotalProgress,
3383 int32_t aMaxTotalProgress) {
3384 if (!IPCOpen() || !mShouldSendWebProgressEventsToParent) {
3385 return NS_OK;
3388 // FIXME: We currently ignore ProgressChange events from out-of-process
3389 // subframes both here and in BrowserParent. We may want to change this
3390 // behaviour in the future.
3391 if (!GetBrowsingContext()->IsTopContent()) {
3392 return NS_OK;
3395 // As we're being filtered by nsBrowserStatusFilter, we will be passed either
3396 // nullptr or 0 for all arguments other than aCurTotalProgress and
3397 // aMaxTotalProgress. Don't bother sending them.
3398 MOZ_ASSERT(!aWebProgress);
3399 MOZ_ASSERT(!aRequest);
3400 MOZ_ASSERT(aCurSelfProgress == 0);
3401 MOZ_ASSERT(aMaxSelfProgress == 0);
3403 Unused << SendOnProgressChange(aCurTotalProgress, aMaxTotalProgress);
3405 return NS_OK;
3408 NS_IMETHODIMP BrowserChild::OnLocationChange(nsIWebProgress* aWebProgress,
3409 nsIRequest* aRequest,
3410 nsIURI* aLocation,
3411 uint32_t aFlags) {
3412 if (!IPCOpen() || !mShouldSendWebProgressEventsToParent) {
3413 return NS_OK;
3416 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress);
3417 if (!docShell) {
3418 MOZ_ASSERT_UNREACHABLE("aWebProgress is null or not a nsIDocShell?");
3419 return NS_ERROR_UNEXPECTED;
3422 RefPtr<BrowsingContext> browsingContext = docShell->GetBrowsingContext();
3423 RefPtr<Document> document = browsingContext->GetExtantDocument();
3424 if (!document) {
3425 return NS_OK;
3428 WebProgressData webProgressData;
3429 RequestData requestData;
3431 MOZ_TRY(PrepareProgressListenerData(aWebProgress, aRequest, webProgressData,
3432 requestData));
3434 Maybe<WebProgressLocationChangeData> locationChangeData;
3436 bool canGoBack = false;
3437 bool canGoForward = false;
3438 if (!mozilla::SessionHistoryInParent()) {
3439 MOZ_TRY(WebNavigation()->GetCanGoBack(&canGoBack));
3440 MOZ_TRY(WebNavigation()->GetCanGoForward(&canGoForward));
3443 if (browsingContext->IsTopContent()) {
3444 MOZ_ASSERT(
3445 browsingContext == GetBrowsingContext(),
3446 "Toplevel content BrowsingContext which isn't GetBrowsingContext()?");
3448 locationChangeData.emplace();
3450 document->GetContentType(locationChangeData->contentType());
3451 locationChangeData->isNavigating() = docShell->GetIsNavigating();
3452 locationChangeData->documentURI() = document->GetDocumentURIObject();
3453 document->GetTitle(locationChangeData->title());
3454 document->GetCharacterSet(locationChangeData->charset());
3456 locationChangeData->mayEnableCharacterEncodingMenu() =
3457 docShell->GetMayEnableCharacterEncodingMenu();
3459 locationChangeData->contentPrincipal() = document->NodePrincipal();
3460 locationChangeData->contentPartitionedPrincipal() =
3461 document->PartitionedPrincipal();
3462 locationChangeData->csp() = document->GetCsp();
3463 locationChangeData->referrerInfo() = document->ReferrerInfo();
3464 locationChangeData->isSyntheticDocument() = document->IsSyntheticDocument();
3466 if (nsCOMPtr<nsILoadGroup> loadGroup = document->GetDocumentLoadGroup()) {
3467 uint64_t requestContextID = 0;
3468 MOZ_TRY(loadGroup->GetRequestContextID(&requestContextID));
3469 locationChangeData->requestContextID() = Some(requestContextID);
3472 #ifdef MOZ_CRASHREPORTER
3473 if (CrashReporter::GetEnabled()) {
3474 nsCOMPtr<nsIURI> annotationURI;
3476 nsresult rv =
3477 NS_MutateURI(aLocation).SetUserPass(""_ns).Finalize(annotationURI);
3479 if (NS_FAILED(rv)) {
3480 // Ignore failures on about: URIs.
3481 annotationURI = aLocation;
3484 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL,
3485 annotationURI->GetSpecOrDefault());
3487 #endif
3490 Unused << SendOnLocationChange(webProgressData, requestData, aLocation,
3491 aFlags, canGoBack, canGoForward,
3492 locationChangeData);
3494 return NS_OK;
3497 NS_IMETHODIMP BrowserChild::OnStatusChange(nsIWebProgress* aWebProgress,
3498 nsIRequest* aRequest,
3499 nsresult aStatus,
3500 const char16_t* aMessage) {
3501 if (!IPCOpen() || !mShouldSendWebProgressEventsToParent) {
3502 return NS_OK;
3505 // FIXME: We currently ignore StatusChange from out-of-process subframes both
3506 // here and in BrowserParent. We may want to change this behaviour in the
3507 // future.
3508 if (!GetBrowsingContext()->IsTopContent()) {
3509 return NS_OK;
3512 // As we're being filtered by nsBrowserStatusFilter, we will be passed either
3513 // nullptr or NS_OK for all arguments other than aMessage. Don't bother
3514 // sending them.
3515 MOZ_ASSERT(!aWebProgress);
3516 MOZ_ASSERT(!aRequest);
3517 MOZ_ASSERT(aStatus == NS_OK);
3519 Unused << SendOnStatusChange(nsDependentString(aMessage));
3521 return NS_OK;
3524 NS_IMETHODIMP BrowserChild::OnSecurityChange(nsIWebProgress* aWebProgress,
3525 nsIRequest* aRequest,
3526 uint32_t aState) {
3527 // Security changes are now handled entirely in the parent process
3528 // so we don't need to worry about forwarding them (and we shouldn't
3529 // be receiving any to forward).
3530 return NS_OK;
3533 NS_IMETHODIMP BrowserChild::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
3534 nsIRequest* aRequest,
3535 uint32_t aEvent) {
3536 // The OnContentBlockingEvent only happenes in the parent process. It should
3537 // not be seen in the content process.
3538 MOZ_DIAGNOSTIC_ASSERT(
3539 false, "OnContentBlockingEvent should not be seen in content process.");
3540 return NS_ERROR_NOT_IMPLEMENTED;
3543 NS_IMETHODIMP BrowserChild::OnProgressChange64(nsIWebProgress* aWebProgress,
3544 nsIRequest* aRequest,
3545 int64_t aCurSelfProgress,
3546 int64_t aMaxSelfProgress,
3547 int64_t aCurTotalProgress,
3548 int64_t aMaxTotalProgress) {
3549 // All the events we receive are filtered through an nsBrowserStatusFilter,
3550 // which accepts ProgressChange64 events, but truncates the progress values to
3551 // uint32_t and calls OnProgressChange.
3552 return NS_ERROR_NOT_IMPLEMENTED;
3555 NS_IMETHODIMP BrowserChild::OnRefreshAttempted(nsIWebProgress* aWebProgress,
3556 nsIURI* aRefreshURI,
3557 uint32_t aMillis, bool aSameURI,
3558 bool* aOut) {
3559 NS_ENSURE_ARG_POINTER(aOut);
3560 *aOut = true;
3562 return NS_OK;
3565 NS_IMETHODIMP BrowserChild::NotifyNavigationFinished() {
3566 Unused << SendNavigationFinished();
3567 return NS_OK;
3570 nsresult BrowserChild::PrepareRequestData(nsIRequest* aRequest,
3571 RequestData& aRequestData) {
3572 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
3573 if (!channel) {
3574 aRequestData.requestURI() = nullptr;
3575 return NS_OK;
3578 nsresult rv = channel->GetURI(getter_AddRefs(aRequestData.requestURI()));
3579 NS_ENSURE_SUCCESS(rv, rv);
3581 rv = channel->GetOriginalURI(
3582 getter_AddRefs(aRequestData.originalRequestURI()));
3583 NS_ENSURE_SUCCESS(rv, rv);
3585 nsCOMPtr<nsIClassifiedChannel> classifiedChannel = do_QueryInterface(channel);
3586 if (classifiedChannel) {
3587 rv = classifiedChannel->GetMatchedList(aRequestData.matchedList());
3588 NS_ENSURE_SUCCESS(rv, rv);
3590 return NS_OK;
3593 nsresult BrowserChild::PrepareProgressListenerData(
3594 nsIWebProgress* aWebProgress, nsIRequest* aRequest,
3595 WebProgressData& aWebProgressData, RequestData& aRequestData) {
3596 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aWebProgress);
3597 if (!docShell) {
3598 MOZ_ASSERT_UNREACHABLE("aWebProgress is null or not a nsIDocShell?");
3599 return NS_ERROR_UNEXPECTED;
3602 aWebProgressData.browsingContext() = docShell->GetBrowsingContext();
3603 nsresult rv = aWebProgress->GetLoadType(&aWebProgressData.loadType());
3604 NS_ENSURE_SUCCESS(rv, rv);
3606 return PrepareRequestData(aRequest, aRequestData);
3609 void BrowserChild::UpdateSessionStore() {
3610 if (mSessionStoreChild) {
3611 mSessionStoreChild->UpdateSessionStore();
3615 #ifdef XP_WIN
3616 RefPtr<PBrowserChild::IsWindowSupportingProtectedMediaPromise>
3617 BrowserChild::DoesWindowSupportProtectedMedia() {
3618 MOZ_ASSERT(
3619 NS_IsMainThread(),
3620 "Protected media support check should be done on main thread only.");
3621 if (mWindowSupportsProtectedMedia) {
3622 // If we've already checked and have a cached result, resolve with that.
3623 return IsWindowSupportingProtectedMediaPromise::CreateAndResolve(
3624 mWindowSupportsProtectedMedia.value(), __func__);
3626 RefPtr<BrowserChild> self = this;
3627 // We chain off the promise rather than passing it directly so we can cache
3628 // the result and use that for future calls.
3629 return SendIsWindowSupportingProtectedMedia(ChromeOuterWindowID())
3630 ->Then(
3631 GetCurrentSerialEventTarget(), __func__,
3632 [self](bool isSupported) {
3633 // If a result was cached while this check was inflight, ensure the
3634 // results match.
3635 MOZ_ASSERT_IF(
3636 self->mWindowSupportsProtectedMedia,
3637 self->mWindowSupportsProtectedMedia.value() == isSupported);
3638 // Cache the response as it will not change during the lifetime
3639 // of this object.
3640 self->mWindowSupportsProtectedMedia = Some(isSupported);
3641 return IsWindowSupportingProtectedMediaPromise::CreateAndResolve(
3642 self->mWindowSupportsProtectedMedia.value(), __func__);
3644 [](ResponseRejectReason reason) {
3645 return IsWindowSupportingProtectedMediaPromise::CreateAndReject(
3646 reason, __func__);
3649 #endif
3651 void BrowserChild::NotifyContentBlockingEvent(
3652 uint32_t aEvent, nsIChannel* aChannel, bool aBlocked,
3653 const nsACString& aTrackingOrigin,
3654 const nsTArray<nsCString>& aTrackingFullHashes,
3655 const Maybe<
3656 mozilla::ContentBlockingNotifier::StorageAccessPermissionGrantedReason>&
3657 aReason,
3658 const Maybe<ContentBlockingNotifier::CanvasFingerprinter>&
3659 aCanvasFingerprinter,
3660 const Maybe<bool> aCanvasFingerprinterKnownText) {
3661 if (!IPCOpen()) {
3662 return;
3665 RequestData requestData;
3666 if (NS_SUCCEEDED(PrepareRequestData(aChannel, requestData))) {
3667 Unused << SendNotifyContentBlockingEvent(
3668 aEvent, requestData, aBlocked, PromiseFlatCString(aTrackingOrigin),
3669 aTrackingFullHashes, aReason, aCanvasFingerprinter,
3670 aCanvasFingerprinterKnownText);
3674 NS_IMETHODIMP
3675 BrowserChild::ContentTransformsReceived(JSContext* aCx,
3676 dom::Promise** aPromise) {
3677 auto* globalObject = xpc::CurrentNativeGlobal(aCx);
3678 ErrorResult rv;
3679 if (mChildToParentConversionMatrix) {
3680 // Already received content transforms
3681 RefPtr<Promise> promise =
3682 Promise::CreateResolvedWithUndefined(globalObject, rv);
3683 promise.forget(aPromise);
3684 return rv.StealNSResult();
3687 if (!mContentTransformPromise) {
3688 mContentTransformPromise = Promise::Create(globalObject, rv);
3691 MOZ_ASSERT(globalObject == mContentTransformPromise->GetGlobalObject());
3692 NS_IF_ADDREF(*aPromise = mContentTransformPromise);
3693 return rv.StealNSResult();
3696 BrowserChildMessageManager::BrowserChildMessageManager(
3697 BrowserChild* aBrowserChild)
3698 : ContentFrameMessageManager(new nsFrameMessageManager(aBrowserChild)),
3699 mBrowserChild(aBrowserChild) {}
3701 BrowserChildMessageManager::~BrowserChildMessageManager() = default;
3703 NS_IMPL_CYCLE_COLLECTION_CLASS(BrowserChildMessageManager)
3705 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BrowserChildMessageManager,
3706 DOMEventTargetHelper)
3707 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager);
3708 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChild);
3709 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
3710 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
3712 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BrowserChildMessageManager,
3713 DOMEventTargetHelper)
3714 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
3715 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChild)
3716 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
3718 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserChildMessageManager)
3719 NS_INTERFACE_MAP_ENTRY(nsIMessageSender)
3720 NS_INTERFACE_MAP_ENTRY_CONCRETE(ContentFrameMessageManager)
3721 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
3722 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
3724 NS_IMPL_ADDREF_INHERITED(BrowserChildMessageManager, DOMEventTargetHelper)
3725 NS_IMPL_RELEASE_INHERITED(BrowserChildMessageManager, DOMEventTargetHelper)
3727 JSObject* BrowserChildMessageManager::WrapObject(
3728 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
3729 return ContentFrameMessageManager_Binding::Wrap(aCx, this, aGivenProto);
3732 void BrowserChildMessageManager::MarkForCC() {
3733 if (mBrowserChild) {
3734 mBrowserChild->MarkScopesForCC();
3736 EventListenerManager* elm = GetExistingListenerManager();
3737 if (elm) {
3738 elm->MarkForCC();
3740 MessageManagerGlobal::MarkForCC();
3743 Nullable<WindowProxyHolder> BrowserChildMessageManager::GetContent(
3744 ErrorResult& aError) {
3745 nsCOMPtr<nsIDocShell> docShell = GetDocShell(aError);
3746 if (!docShell) {
3747 return nullptr;
3749 return WindowProxyHolder(docShell->GetBrowsingContext());
3752 already_AddRefed<nsIDocShell> BrowserChildMessageManager::GetDocShell(
3753 ErrorResult& aError) {
3754 if (!mBrowserChild) {
3755 aError.Throw(NS_ERROR_NULL_POINTER);
3756 return nullptr;
3758 nsCOMPtr<nsIDocShell> window =
3759 do_GetInterface(mBrowserChild->WebNavigation());
3760 return window.forget();
3763 already_AddRefed<nsIEventTarget>
3764 BrowserChildMessageManager::GetTabEventTarget() {
3765 return do_AddRef(GetMainThreadSerialEventTarget());
3768 nsresult BrowserChildMessageManager::Dispatch(
3769 already_AddRefed<nsIRunnable>&& aRunnable) const {
3770 return SchedulerGroup::Dispatch(std::move(aRunnable));