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