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