Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/ipc/TabChild.cpp
Line
Count
Source (jump to first uncovered line)
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 "TabChild.h"
10
11
#include "gfxPrefs.h"
12
#ifdef ACCESSIBILITY
13
#include "mozilla/a11y/DocAccessibleChild.h"
14
#endif
15
#include "Layers.h"
16
#include "ContentChild.h"
17
#include "TabParent.h"
18
#include "js/JSON.h"
19
#include "mozilla/Preferences.h"
20
#include "mozilla/BrowserElementParent.h"
21
#include "mozilla/ClearOnShutdown.h"
22
#include "mozilla/EventListenerManager.h"
23
#include "mozilla/dom/DataTransfer.h"
24
#include "mozilla/dom/Event.h"
25
#include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
26
#include "mozilla/dom/MessageManagerBinding.h"
27
#include "mozilla/dom/MouseEventBinding.h"
28
#include "mozilla/dom/PaymentRequestChild.h"
29
#include "mozilla/IMEStateManager.h"
30
#include "mozilla/ipc/URIUtils.h"
31
#include "mozilla/layers/APZChild.h"
32
#include "mozilla/layers/APZCCallbackHelper.h"
33
#include "mozilla/layers/APZCTreeManagerChild.h"
34
#include "mozilla/layers/APZEventState.h"
35
#include "mozilla/layers/ContentProcessController.h"
36
#include "mozilla/layers/CompositorBridgeChild.h"
37
#include "mozilla/layers/DoubleTapToZoom.h"
38
#include "mozilla/layers/IAPZCTreeManager.h"
39
#include "mozilla/layers/ImageBridgeChild.h"
40
#include "mozilla/layers/InputAPZContext.h"
41
#include "mozilla/layers/LayerTransactionChild.h"
42
#include "mozilla/layers/ShadowLayers.h"
43
#include "mozilla/layers/WebRenderLayerManager.h"
44
#include "mozilla/layout/RenderFrameChild.h"
45
#include "mozilla/layout/RenderFrameParent.h"
46
#include "mozilla/plugins/PPluginWidgetChild.h"
47
#include "mozilla/recordreplay/ParentIPC.h"
48
#include "mozilla/LookAndFeel.h"
49
#include "mozilla/MouseEvents.h"
50
#include "mozilla/Move.h"
51
#include "mozilla/PresShell.h"
52
#include "mozilla/ProcessHangMonitor.h"
53
#include "mozilla/ScopeExit.h"
54
#include "mozilla/Services.h"
55
#include "mozilla/StaticPtr.h"
56
#include "mozilla/TextEvents.h"
57
#include "mozilla/TouchEvents.h"
58
#include "mozilla/Unused.h"
59
#include "nsContentUtils.h"
60
#include "nsCSSFrameConstructor.h"
61
#include "nsDocShell.h"
62
#include "nsEmbedCID.h"
63
#include "nsGlobalWindow.h"
64
#include <algorithm>
65
#include "nsExceptionHandler.h"
66
#include "nsFilePickerProxy.h"
67
#include "mozilla/dom/Element.h"
68
#include "nsGlobalWindow.h"
69
#include "nsIBaseWindow.h"
70
#include "nsIBrowserDOMWindow.h"
71
#include "nsIDocumentInlines.h"
72
#include "nsIDocShellTreeOwner.h"
73
#include "nsIDOMChromeWindow.h"
74
#include "nsIDOMWindow.h"
75
#include "nsIDOMWindowUtils.h"
76
#include "nsFocusManager.h"
77
#include "EventStateManager.h"
78
#include "nsIDocShell.h"
79
#include "nsIFrame.h"
80
#include "nsIURI.h"
81
#include "nsIURIFixup.h"
82
#include "nsCDefaultURIFixup.h"
83
#include "nsIWebBrowser.h"
84
#include "nsIWebProgress.h"
85
#include "nsIXULRuntime.h"
86
#include "nsPIDOMWindow.h"
87
#include "nsPIWindowRoot.h"
88
#include "nsPointerHashKeys.h"
89
#include "nsLayoutUtils.h"
90
#include "nsPrintfCString.h"
91
#include "nsTHashtable.h"
92
#include "nsThreadManager.h"
93
#include "nsThreadUtils.h"
94
#include "nsViewManager.h"
95
#include "nsWeakReference.h"
96
#include "nsWindowWatcher.h"
97
#include "PermissionMessageUtils.h"
98
#include "PuppetWidget.h"
99
#include "StructuredCloneData.h"
100
#include "nsViewportInfo.h"
101
#include "nsILoadContext.h"
102
#include "ipc/nsGUIEventIPC.h"
103
#include "mozilla/gfx/Matrix.h"
104
#include "UnitTransforms.h"
105
#include "ClientLayerManager.h"
106
#include "LayersLogging.h"
107
#include "nsColorPickerProxy.h"
108
#include "nsContentPermissionHelper.h"
109
#include "nsNetUtil.h"
110
#include "nsIPermissionManager.h"
111
#include "nsIURILoader.h"
112
#include "nsIScriptError.h"
113
#include "mozilla/EventForwards.h"
114
#include "nsDeviceContext.h"
115
#include "nsSandboxFlags.h"
116
#include "FrameLayerBuilder.h"
117
#include "VRManagerChild.h"
118
#include "nsCommandParams.h"
119
#include "nsISHistory.h"
120
#include "nsQueryObject.h"
121
#include "nsIHttpChannel.h"
122
#include "mozilla/dom/DocGroup.h"
123
#include "nsString.h"
124
#include "nsISupportsPrimitives.h"
125
#include "mozilla/Telemetry.h"
126
#include "nsDocShellLoadInfo.h"
127
#include "nsWebBrowser.h"
128
129
#ifdef XP_WIN
130
#include "mozilla/plugins/PluginWidgetChild.h"
131
#endif
132
133
#ifdef NS_PRINTING
134
#include "nsIPrintSession.h"
135
#include "nsIPrintSettings.h"
136
#include "nsIPrintSettingsService.h"
137
#include "nsIWebBrowserPrint.h"
138
#endif
139
140
#define BROWSER_ELEMENT_CHILD_SCRIPT \
141
0
    NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js")
142
143
#define TABC_LOG(...)
144
// #define TABC_LOG(...) printf_stderr("TABC: " __VA_ARGS__)
145
146
using namespace mozilla;
147
using namespace mozilla::dom;
148
using namespace mozilla::dom::ipc;
149
using namespace mozilla::ipc;
150
using namespace mozilla::layers;
151
using namespace mozilla::layout;
152
using namespace mozilla::docshell;
153
using namespace mozilla::widget;
154
using namespace mozilla::jsipc;
155
using mozilla::layers::GeckoContentController;
156
157
NS_IMPL_ISUPPORTS(ContentListener, nsIDOMEventListener)
158
159
static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
160
161
nsTHashtable<nsPtrHashKey<TabChild>>* TabChild::sVisibleTabs;
162
163
typedef nsDataHashtable<nsUint64HashKey, TabChild*> TabChildMap;
164
static TabChildMap* sTabChildren;
165
StaticMutex sTabChildrenMutex;
166
167
TabChildBase::TabChildBase()
168
  : mTabChildMessageManager(nullptr)
169
0
{
170
0
}
171
172
TabChildBase::~TabChildBase()
173
0
{
174
0
  mAnonymousGlobalScopes.Clear();
175
0
}
176
177
NS_IMPL_CYCLE_COLLECTION_CLASS(TabChildBase)
178
179
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TabChildBase)
180
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChildMessageManager)
181
0
  tmp->nsMessageManagerScriptExecutor::Unlink();
182
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebBrowserChrome)
183
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
184
185
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TabChildBase)
186
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChildMessageManager)
187
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebBrowserChrome)
188
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
189
190
0
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TabChildBase)
191
0
  tmp->nsMessageManagerScriptExecutor::Trace(aCallbacks, aClosure);
192
0
NS_IMPL_CYCLE_COLLECTION_TRACE_END
193
194
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TabChildBase)
195
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
196
0
NS_INTERFACE_MAP_END
197
198
NS_IMPL_CYCLE_COLLECTING_ADDREF(TabChildBase)
199
NS_IMPL_CYCLE_COLLECTING_RELEASE(TabChildBase)
200
201
already_AddRefed<nsIDocument>
202
TabChildBase::GetDocument() const
203
0
{
204
0
  nsCOMPtr<nsIDocument> doc;
205
0
  WebNavigation()->GetDocument(getter_AddRefs(doc));
206
0
  return doc.forget();
207
0
}
208
209
already_AddRefed<nsIPresShell>
210
TabChildBase::GetPresShell() const
211
0
{
212
0
  nsCOMPtr<nsIPresShell> result;
213
0
  if (nsCOMPtr<nsIDocument> doc = GetDocument()) {
214
0
    result = doc->GetShell();
215
0
  }
216
0
  return result.forget();
217
0
}
218
219
void
220
TabChildBase::DispatchMessageManagerMessage(const nsAString& aMessageName,
221
                                            const nsAString& aJSONData)
222
0
{
223
0
    AutoSafeJSContext cx;
224
0
    JS::Rooted<JS::Value> json(cx, JS::NullValue());
225
0
    dom::ipc::StructuredCloneData data;
226
0
    if (JS_ParseJSON(cx,
227
0
                      static_cast<const char16_t*>(aJSONData.BeginReading()),
228
0
                      aJSONData.Length(),
229
0
                      &json)) {
230
0
        ErrorResult rv;
231
0
        data.Write(cx, json, rv);
232
0
        if (NS_WARN_IF(rv.Failed())) {
233
0
            rv.SuppressException();
234
0
            return;
235
0
        }
236
0
    }
237
0
238
0
    RefPtr<TabChildMessageManager> kungFuDeathGrip(mTabChildMessageManager);
239
0
    RefPtr<nsFrameMessageManager> mm = kungFuDeathGrip->GetMessageManager();
240
0
    mm->ReceiveMessage(static_cast<EventTarget*>(kungFuDeathGrip), nullptr,
241
0
                       aMessageName, false, &data, nullptr, nullptr, nullptr,
242
0
                       IgnoreErrors());
243
0
}
244
245
bool
246
TabChildBase::UpdateFrameHandler(const FrameMetrics& aFrameMetrics)
247
0
{
248
0
  MOZ_ASSERT(aFrameMetrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID);
249
0
250
0
  if (aFrameMetrics.IsRootContent()) {
251
0
    if (nsCOMPtr<nsIPresShell> shell = GetPresShell()) {
252
0
      // Guard against stale updates (updates meant for a pres shell which
253
0
      // has since been torn down and destroyed).
254
0
      if (aFrameMetrics.GetPresShellId() == shell->GetPresShellId()) {
255
0
        ProcessUpdateFrame(aFrameMetrics);
256
0
        return true;
257
0
      }
258
0
    }
259
0
  } else {
260
0
    // aFrameMetrics.mIsRoot is false, so we are trying to update a subframe.
261
0
    // This requires special handling.
262
0
    FrameMetrics newSubFrameMetrics(aFrameMetrics);
263
0
    APZCCallbackHelper::UpdateSubFrame(newSubFrameMetrics);
264
0
    return true;
265
0
  }
266
0
  return true;
267
0
}
268
269
void
270
TabChildBase::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
271
0
{
272
0
    if (!mTabChildMessageManager) {
273
0
        return;
274
0
    }
275
0
276
0
    FrameMetrics newMetrics = aFrameMetrics;
277
0
    APZCCallbackHelper::UpdateRootFrame(newMetrics);
278
0
}
279
280
NS_IMETHODIMP
281
ContentListener::HandleEvent(Event* aEvent)
282
0
{
283
0
  RemoteDOMEvent remoteEvent;
284
0
  remoteEvent.mEvent = aEvent;
285
0
  NS_ENSURE_STATE(remoteEvent.mEvent);
286
0
  mTabChild->SendEvent(remoteEvent);
287
0
  return NS_OK;
288
0
}
289
290
class TabChild::DelayedDeleteRunnable final
291
  : public Runnable
292
  , public nsIRunnablePriority
293
{
294
    RefPtr<TabChild> mTabChild;
295
296
    // In order to ensure that this runnable runs after everything that could
297
    // possibly touch this tab, we send it through the event queue twice. The
298
    // first time it runs at normal priority and the second time it runs at
299
    // input priority. This ensures that it runs after all events that were in
300
    // either queue at the time it was first dispatched. mReadyToDelete starts
301
    // out false (when it runs at normal priority) and is then set to true.
302
    bool mReadyToDelete = false;
303
304
public:
305
    explicit DelayedDeleteRunnable(TabChild* aTabChild)
306
      : Runnable("TabChild::DelayedDeleteRunnable")
307
      , mTabChild(aTabChild)
308
0
    {
309
0
        MOZ_ASSERT(NS_IsMainThread());
310
0
        MOZ_ASSERT(aTabChild);
311
0
    }
312
313
    NS_DECL_ISUPPORTS_INHERITED
314
315
private:
316
    ~DelayedDeleteRunnable()
317
0
    {
318
0
        MOZ_ASSERT(NS_IsMainThread());
319
0
        MOZ_ASSERT(!mTabChild);
320
0
    }
321
322
    NS_IMETHOD GetPriority(uint32_t* aPriority) override
323
0
    {
324
0
      *aPriority = mReadyToDelete
325
0
                 ? nsIRunnablePriority::PRIORITY_INPUT
326
0
                 : nsIRunnablePriority::PRIORITY_NORMAL;
327
0
      return NS_OK;
328
0
    }
329
330
    NS_IMETHOD
331
    Run() override
332
0
    {
333
0
        MOZ_ASSERT(NS_IsMainThread());
334
0
        MOZ_ASSERT(mTabChild);
335
0
336
0
        if (!mReadyToDelete) {
337
0
          // This time run this runnable at input priority.
338
0
          mReadyToDelete = true;
339
0
          MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(this));
340
0
          return NS_OK;
341
0
        }
342
0
343
0
        // Check in case ActorDestroy was called after RecvDestroy message.
344
0
        // Middleman processes with their own recording child process avoid
345
0
        // sending a delete message, so that the parent process does not
346
0
        // receive two deletes for the same actor.
347
0
        if (mTabChild->IPCOpen() && !recordreplay::parent::IsMiddlemanWithRecordingChild()) {
348
0
          Unused << PBrowserChild::Send__delete__(mTabChild);
349
0
        }
350
0
351
0
        mTabChild = nullptr;
352
0
        return NS_OK;
353
0
    }
354
};
355
356
NS_IMPL_ISUPPORTS_INHERITED(TabChild::DelayedDeleteRunnable,
357
                            Runnable,
358
                            nsIRunnablePriority)
359
360
namespace {
361
std::map<TabId, RefPtr<TabChild>>&
362
NestedTabChildMap()
363
0
{
364
0
  MOZ_ASSERT(NS_IsMainThread());
365
0
  static std::map<TabId, RefPtr<TabChild>> sNestedTabChildMap;
366
0
  return sNestedTabChildMap;
367
0
}
368
} // namespace
369
370
already_AddRefed<TabChild>
371
TabChild::FindTabChild(const TabId& aTabId)
372
0
{
373
0
  auto iter = NestedTabChildMap().find(aTabId);
374
0
  if (iter == NestedTabChildMap().end()) {
375
0
    return nullptr;
376
0
  }
377
0
  RefPtr<TabChild> tabChild = iter->second;
378
0
  return tabChild.forget();
379
0
}
380
381
/*static*/ already_AddRefed<TabChild>
382
TabChild::Create(nsIContentChild* aManager,
383
                 const TabId& aTabId,
384
                 const TabId& aSameTabGroupAs,
385
                 const TabContext &aContext,
386
                 uint32_t aChromeFlags)
387
0
{
388
0
  RefPtr<TabChild> groupChild = FindTabChild(aSameTabGroupAs);
389
0
  dom::TabGroup* group = groupChild ? groupChild->TabGroup() : nullptr;
390
0
  RefPtr<TabChild> iframe = new TabChild(aManager, aTabId, group,
391
0
                                         aContext, aChromeFlags);
392
0
  return iframe.forget();
393
0
}
394
395
TabChild::TabChild(nsIContentChild* aManager,
396
                   const TabId& aTabId,
397
                   dom::TabGroup* aTabGroup,
398
                   const TabContext& aContext,
399
                   uint32_t aChromeFlags)
400
  : TabContext(aContext)
401
  , mTabGroup(aTabGroup)
402
  , mRemoteFrame(nullptr)
403
  , mManager(aManager)
404
  , mChromeFlags(aChromeFlags)
405
  , mMaxTouchPoints(0)
406
  , mLayersId{0}
407
  , mBeforeUnloadListeners(0)
408
  , mDidFakeShow(false)
409
  , mNotified(false)
410
  , mTriedBrowserInit(false)
411
  , mOrientation(hal::eScreenOrientation_PortraitPrimary)
412
  , mIgnoreKeyPressEvent(false)
413
  , mHasValidInnerSize(false)
414
  , mDestroyed(false)
415
  , mUniqueId(aTabId)
416
  , mHasSiblings(false)
417
  , mIsTransparent(false)
418
  , mIPCOpen(false)
419
  , mParentIsActive(false)
420
  , mDidSetRealShowInfo(false)
421
  , mDidLoadURLInit(false)
422
  , mAwaitingLA(false)
423
  , mSkipKeyPress(false)
424
  , mLayersObserverEpoch{1}
425
#if defined(XP_WIN) && defined(ACCESSIBILITY)
426
  , mNativeWindowHandle(0)
427
#endif
428
#if defined(ACCESSIBILITY)
429
  , mTopLevelDocAccessibleChild(nullptr)
430
#endif
431
  , mPendingDocShellIsActive(false)
432
  , mPendingDocShellReceivedMessage(false)
433
  , mPendingRenderLayers(false)
434
  , mPendingRenderLayersReceivedMessage(false)
435
  , mPendingLayersObserverEpoch{0}
436
  , mPendingDocShellBlockers(0)
437
  , mWidgetNativeData(0)
438
0
{
439
0
  mozilla::HoldJSObjects(this);
440
0
441
0
  nsWeakPtr weakPtrThis(do_GetWeakReference(static_cast<nsITabChild*>(this)));  // for capture by the lambda
442
0
  mSetAllowedTouchBehaviorCallback = [weakPtrThis](uint64_t aInputBlockId,
443
0
                                                   const nsTArray<TouchBehaviorFlags>& aFlags)
444
0
  {
445
0
    if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(weakPtrThis)) {
446
0
      static_cast<TabChild*>(tabChild.get())->SetAllowedTouchBehavior(aInputBlockId, aFlags);
447
0
    }
448
0
  };
449
0
450
0
  // preloaded TabChild should not be added to child map
451
0
  if (mUniqueId) {
452
0
    MOZ_ASSERT(NestedTabChildMap().find(mUniqueId) == NestedTabChildMap().end());
453
0
    NestedTabChildMap()[mUniqueId] = this;
454
0
  }
455
0
  mCoalesceMouseMoveEvents =
456
0
    Preferences::GetBool("dom.event.coalesce_mouse_move");
457
0
  if (mCoalesceMouseMoveEvents) {
458
0
    mCoalescedMouseEventFlusher = new CoalescedMouseMoveFlusher(this);
459
0
  }
460
0
}
461
462
const CompositorOptions&
463
TabChild::GetCompositorOptions() const
464
0
{
465
0
  // If you're calling this before mCompositorOptions is set, well.. don't.
466
0
  MOZ_ASSERT(mCompositorOptions);
467
0
  return mCompositorOptions.ref();
468
0
}
469
470
bool
471
TabChild::AsyncPanZoomEnabled() const
472
0
{
473
0
  // This might get called by the TouchEvent::PrefEnabled code before we have
474
0
  // mCompositorOptions populated (bug 1370089). In that case we just assume
475
0
  // APZ is enabled because we're in a content process (because TabChild) and
476
0
  // APZ is probably going to be enabled here since e10s is enabled.
477
0
  return mCompositorOptions ? mCompositorOptions->UseAPZ() : true;
478
0
}
479
480
NS_IMETHODIMP
481
TabChild::Observe(nsISupports *aSubject,
482
                  const char *aTopic,
483
                  const char16_t *aData)
484
0
{
485
0
  if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) {
486
0
    if (AsyncPanZoomEnabled()) {
487
0
      nsCOMPtr<nsIDocument> subject(do_QueryInterface(aSubject));
488
0
      nsCOMPtr<nsIDocument> doc(GetDocument());
489
0
490
0
      if (SameCOMIdentity(subject, doc)) {
491
0
        nsCOMPtr<nsIPresShell> shell(doc->GetShell());
492
0
        if (shell) {
493
0
          shell->SetIsFirstPaint(true);
494
0
        }
495
0
496
0
        APZCCallbackHelper::InitializeRootDisplayport(shell);
497
0
      }
498
0
    }
499
0
  }
500
0
501
0
  return NS_OK;
502
0
}
503
504
void
505
TabChild::ContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
506
                                    uint64_t aInputBlockId,
507
                                    bool aPreventDefault) const
508
0
{
509
0
  if (mApzcTreeManager) {
510
0
    mApzcTreeManager->ContentReceivedInputBlock(aInputBlockId, aPreventDefault);
511
0
  }
512
0
}
513
514
void
515
TabChild::SetTargetAPZC(uint64_t aInputBlockId,
516
                        const nsTArray<ScrollableLayerGuid>& aTargets) const
517
0
{
518
0
  if (mApzcTreeManager) {
519
0
    mApzcTreeManager->SetTargetAPZC(aInputBlockId, aTargets);
520
0
  }
521
0
}
522
523
void
524
TabChild::SetAllowedTouchBehavior(uint64_t aInputBlockId,
525
                                  const nsTArray<TouchBehaviorFlags>& aTargets) const
526
0
{
527
0
  if (mApzcTreeManager) {
528
0
    mApzcTreeManager->SetAllowedTouchBehavior(aInputBlockId, aTargets);
529
0
  }
530
0
}
531
532
bool
533
TabChild::DoUpdateZoomConstraints(const uint32_t& aPresShellId,
534
                                  const ViewID& aViewId,
535
                                  const Maybe<ZoomConstraints>& aConstraints)
536
0
{
537
0
  if (!mApzcTreeManager || mDestroyed) {
538
0
    return false;
539
0
  }
540
0
541
0
  ScrollableLayerGuid guid = ScrollableLayerGuid(mLayersId, aPresShellId, aViewId);
542
0
543
0
  mApzcTreeManager->UpdateZoomConstraints(guid, aConstraints);
544
0
  return true;
545
0
}
546
547
nsresult
548
TabChild::Init()
549
0
{
550
0
  if (!mTabGroup) {
551
0
    mTabGroup = TabGroup::GetFromActor(this);
552
0
  }
553
0
554
0
  // Directly create our web browser object and store it, so we can start
555
0
  // eliminating QIs.
556
0
  mWebBrowser = new nsWebBrowser();
557
0
  nsIWebBrowser* webBrowser = mWebBrowser;
558
0
559
0
  webBrowser->SetContainerWindow(this);
560
0
  webBrowser->SetOriginAttributes(OriginAttributesRef());
561
0
  mWebNav = do_QueryInterface(webBrowser);
562
0
  NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
563
0
564
0
  nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(WebNavigation()));
565
0
  docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
566
0
567
0
  nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
568
0
  if (!baseWindow) {
569
0
    NS_ERROR("mWebNav doesn't QI to nsIBaseWindow");
570
0
    return NS_ERROR_FAILURE;
571
0
  }
572
0
573
0
  nsCOMPtr<nsIWidget> widget = nsIWidget::CreatePuppetWidget(this);
574
0
  mPuppetWidget = static_cast<PuppetWidget*>(widget.get());
575
0
  if (!mPuppetWidget) {
576
0
    NS_ERROR("couldn't create fake widget");
577
0
    return NS_ERROR_FAILURE;
578
0
  }
579
0
  mPuppetWidget->InfallibleCreate(
580
0
    nullptr, 0,              // no parents
581
0
    LayoutDeviceIntRect(0, 0, 0, 0),
582
0
    nullptr                  // HandleWidgetEvent
583
0
  );
584
0
585
0
  baseWindow->InitWindow(0, mPuppetWidget, 0, 0, 0, 0);
586
0
  baseWindow->Create();
587
0
588
0
  // Set the tab context attributes then pass to docShell
589
0
  NotifyTabContextUpdated(false);
590
0
591
0
  // IPC uses a WebBrowser object for which DNS prefetching is turned off
592
0
  // by default. But here we really want it, so enable it explicitly
593
0
  mWebBrowser->SetAllowDNSPrefetch(true);
594
0
595
0
  nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
596
0
  MOZ_ASSERT(docShell);
597
0
598
0
  docShell->SetAffectPrivateSessionLifetime(
599
0
      mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME);
600
0
  nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(WebNavigation());
601
0
  MOZ_ASSERT(loadContext);
602
0
  loadContext->SetPrivateBrowsing(OriginAttributesRef().mPrivateBrowsingId > 0);
603
0
  loadContext->SetRemoteTabs(
604
0
      mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
605
0
606
0
  // Few lines before, baseWindow->Create() will end up creating a new
607
0
  // window root in nsGlobalWindow::SetDocShell.
608
0
  // Then this chrome event handler, will be inherited to inner windows.
609
0
  // We want to also set it to the docshell so that inner windows
610
0
  // and any code that has access to the docshell
611
0
  // can all listen to the same chrome event handler.
612
0
  // XXX: ideally, we would set a chrome event handler earlier,
613
0
  // and all windows, even the root one, will use the docshell one.
614
0
  nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
615
0
  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
616
0
  nsCOMPtr<EventTarget> chromeHandler = window->GetChromeEventHandler();
617
0
  docShell->SetChromeEventHandler(chromeHandler);
618
0
619
0
  if (window->GetCurrentInnerWindow()) {
620
0
    window->SetKeyboardIndicators(ShowAccelerators(), ShowFocusRings());
621
0
  } else {
622
0
    // Skip ShouldShowFocusRing check if no inner window is available
623
0
    window->SetInitialKeyboardIndicators(ShowAccelerators(), ShowFocusRings());
624
0
  }
625
0
626
0
  nsContentUtils::SetScrollbarsVisibility(window->GetDocShell(),
627
0
    !!(mChromeFlags & nsIWebBrowserChrome::CHROME_SCROLLBARS));
628
0
629
0
  nsWeakPtr weakPtrThis = do_GetWeakReference(static_cast<nsITabChild*>(this));  // for capture by the lambda
630
0
  ContentReceivedInputBlockCallback callback(
631
0
      [weakPtrThis](const ScrollableLayerGuid& aGuid,
632
0
                    uint64_t aInputBlockId,
633
0
                    bool aPreventDefault)
634
0
      {
635
0
        if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(weakPtrThis)) {
636
0
          static_cast<TabChild*>(tabChild.get())->ContentReceivedInputBlock(aGuid, aInputBlockId, aPreventDefault);
637
0
        }
638
0
      });
639
0
  mAPZEventState = new APZEventState(mPuppetWidget, std::move(callback));
640
0
641
0
  mIPCOpen = true;
642
0
643
0
  // Recording/replaying processes use their own compositor.
644
0
  if (recordreplay::IsRecordingOrReplaying()) {
645
0
    mPuppetWidget->CreateCompositor();
646
0
  }
647
0
648
0
  return NS_OK;
649
0
}
650
651
void
652
TabChild::NotifyTabContextUpdated(bool aIsPreallocated)
653
0
{
654
0
  nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
655
0
  MOZ_ASSERT(docShell);
656
0
657
0
  if (!docShell) {
658
0
    return;
659
0
  }
660
0
661
0
  UpdateFrameType();
662
0
663
0
  if (aIsPreallocated)  {
664
0
    nsDocShell::Cast(docShell)->SetOriginAttributes(OriginAttributesRef());
665
0
  }
666
0
667
0
  // Set SANDBOXED_AUXILIARY_NAVIGATION flag if this is a receiver page.
668
0
  if (!PresentationURL().IsEmpty()) {
669
0
    docShell->SetSandboxFlags(SANDBOXED_AUXILIARY_NAVIGATION);
670
0
  }
671
0
}
672
673
void
674
TabChild::UpdateFrameType()
675
0
{
676
0
  nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
677
0
  MOZ_ASSERT(docShell);
678
0
679
0
  // TODO: Bug 1252794 - remove frameType from nsIDocShell.idl
680
0
  docShell->SetFrameType(IsMozBrowserElement() ? nsIDocShell::FRAME_TYPE_BROWSER :
681
0
                           nsIDocShell::FRAME_TYPE_REGULAR);
682
0
}
683
684
NS_IMPL_CYCLE_COLLECTION_CLASS(TabChild)
685
686
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TabChild, TabChildBase)
687
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebNav)
688
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
689
690
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TabChild, TabChildBase)
691
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebNav)
692
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
693
694
0
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(TabChild, TabChildBase)
695
0
NS_IMPL_CYCLE_COLLECTION_TRACE_END
696
697
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TabChild)
698
0
  NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
699
0
  NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
700
0
  NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
701
0
  NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus)
702
0
  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
703
0
  NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
704
0
  NS_INTERFACE_MAP_ENTRY(nsITabChild)
705
0
  NS_INTERFACE_MAP_ENTRY(nsIObserver)
706
0
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
707
0
  NS_INTERFACE_MAP_ENTRY(nsITooltipListener)
708
0
NS_INTERFACE_MAP_END_INHERITING(TabChildBase)
709
710
NS_IMPL_ADDREF_INHERITED(TabChild, TabChildBase);
711
NS_IMPL_RELEASE_INHERITED(TabChild, TabChildBase);
712
713
NS_IMETHODIMP
714
TabChild::SetStatus(uint32_t aStatusType, const char16_t* aStatus)
715
0
{
716
0
  return SetStatusWithContext(aStatusType,
717
0
      aStatus ? static_cast<const nsString &>(nsDependentString(aStatus))
718
0
              : EmptyString(),
719
0
      nullptr);
720
0
}
721
722
NS_IMETHODIMP
723
TabChild::GetWebBrowser(nsIWebBrowser** aWebBrowser)
724
0
{
725
0
  NS_WARNING("TabChild::GetWebBrowser not supported in TabChild");
726
0
727
0
  return NS_ERROR_NOT_IMPLEMENTED;
728
0
}
729
730
NS_IMETHODIMP
731
TabChild::SetWebBrowser(nsIWebBrowser* aWebBrowser)
732
0
{
733
0
  NS_WARNING("TabChild::SetWebBrowser not supported in TabChild");
734
0
735
0
  return NS_ERROR_NOT_IMPLEMENTED;
736
0
}
737
738
NS_IMETHODIMP
739
TabChild::GetChromeFlags(uint32_t* aChromeFlags)
740
0
{
741
0
  *aChromeFlags = mChromeFlags;
742
0
  return NS_OK;
743
0
}
744
745
NS_IMETHODIMP
746
TabChild::SetChromeFlags(uint32_t aChromeFlags)
747
0
{
748
0
  NS_WARNING("trying to SetChromeFlags from content process?");
749
0
750
0
  return NS_ERROR_NOT_IMPLEMENTED;
751
0
}
752
753
NS_IMETHODIMP
754
TabChild::DestroyBrowserWindow()
755
0
{
756
0
  NS_WARNING("TabChild::DestroyBrowserWindow not supported in TabChild");
757
0
758
0
  return NS_ERROR_NOT_IMPLEMENTED;
759
0
}
760
761
NS_IMETHODIMP
762
TabChild::RemoteSizeShellTo(int32_t aWidth, int32_t aHeight,
763
                            int32_t aShellItemWidth, int32_t aShellItemHeight)
764
0
{
765
0
  nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
766
0
  nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(ourDocShell));
767
0
  NS_ENSURE_STATE(docShellAsWin);
768
0
769
0
  int32_t width, height;
770
0
  docShellAsWin->GetSize(&width, &height);
771
0
772
0
  uint32_t flags = 0;
773
0
  if (width == aWidth) {
774
0
    flags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX;
775
0
  }
776
0
777
0
  if (height == aHeight) {
778
0
    flags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY;
779
0
  }
780
0
781
0
  bool sent = SendSizeShellTo(flags, aWidth, aHeight, aShellItemWidth, aShellItemHeight);
782
0
783
0
  return sent ? NS_OK : NS_ERROR_FAILURE;
784
0
}
785
786
NS_IMETHODIMP
787
TabChild::RemoteDropLinks(uint32_t aLinksCount,
788
                          nsIDroppedLinkItem** aLinks)
789
0
{
790
0
  nsTArray<nsString> linksArray;
791
0
  nsresult rv = NS_OK;
792
0
  for (uint32_t i = 0; i < aLinksCount; i++) {
793
0
    nsString tmp;
794
0
    rv = aLinks[i]->GetUrl(tmp);
795
0
    if (NS_FAILED(rv)) {
796
0
      return rv;
797
0
    }
798
0
    linksArray.AppendElement(tmp);
799
0
800
0
    rv = aLinks[i]->GetName(tmp);
801
0
    if (NS_FAILED(rv)) {
802
0
      return rv;
803
0
    }
804
0
    linksArray.AppendElement(tmp);
805
0
806
0
    rv = aLinks[i]->GetType(tmp);
807
0
    if (NS_FAILED(rv)) {
808
0
      return rv;
809
0
    }
810
0
    linksArray.AppendElement(tmp);
811
0
  }
812
0
  bool sent = SendDropLinks(linksArray);
813
0
814
0
  return sent ? NS_OK : NS_ERROR_FAILURE;
815
0
}
816
817
NS_IMETHODIMP
818
TabChild::SizeBrowserTo(int32_t aWidth, int32_t aHeight)
819
0
{
820
0
  NS_WARNING("TabChild::SizeBrowserTo not supported in TabChild");
821
0
822
0
  return NS_ERROR_NOT_IMPLEMENTED;
823
0
}
824
825
NS_IMETHODIMP
826
TabChild::ShowAsModal()
827
0
{
828
0
  NS_WARNING("TabChild::ShowAsModal not supported in TabChild");
829
0
830
0
  return NS_ERROR_NOT_IMPLEMENTED;
831
0
}
832
833
NS_IMETHODIMP
834
TabChild::IsWindowModal(bool* aRetVal)
835
0
{
836
0
  *aRetVal = false;
837
0
  return NS_OK;
838
0
}
839
840
NS_IMETHODIMP
841
TabChild::ExitModalEventLoop(nsresult aStatus)
842
0
{
843
0
  NS_WARNING("TabChild::ExitModalEventLoop not supported in TabChild");
844
0
845
0
  return NS_ERROR_NOT_IMPLEMENTED;
846
0
}
847
848
NS_IMETHODIMP
849
TabChild::SetStatusWithContext(uint32_t aStatusType,
850
                               const nsAString& aStatusText,
851
                               nsISupports* aStatusContext)
852
0
{
853
0
  // We can only send the status after the ipc machinery is set up,
854
0
  // mRemoteFrame is a good indicator.
855
0
  if (mRemoteFrame)
856
0
    SendSetStatus(aStatusType, nsString(aStatusText));
857
0
  return NS_OK;
858
0
}
859
860
NS_IMETHODIMP
861
TabChild::SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY,
862
                        int32_t aCx, int32_t aCy)
863
0
{
864
0
  // The parent is in charge of the dimension changes. If JS code wants to
865
0
  // change the dimensions (moveTo, screenX, etc.) we send a message to the
866
0
  // parent about the new requested dimension, the parent does the resize/move
867
0
  // then send a message to the child to update itself. For APIs like screenX
868
0
  // this function is called with the current value for the non-changed values.
869
0
  // In a series of calls like window.screenX = 10; window.screenY = 10; for
870
0
  // the second call, since screenX is not yet updated we might accidentally
871
0
  // reset back screenX to it's old value. To avoid this if a parameter did not
872
0
  // change we want the parent to ignore its value.
873
0
  int32_t x, y, cx, cy;
874
0
  GetDimensions(aFlags, &x, &y, &cx, &cy);
875
0
876
0
  if (x == aX) {
877
0
    aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_X;
878
0
  }
879
0
880
0
  if (y == aY) {
881
0
    aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_Y;
882
0
  }
883
0
884
0
  if (cx == aCx) {
885
0
    aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX;
886
0
  }
887
0
888
0
  if (cy == aCy) {
889
0
    aFlags |= nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY;
890
0
  }
891
0
892
0
  Unused << SendSetDimensions(aFlags, aX, aY, aCx, aCy);
893
0
894
0
  return NS_OK;
895
0
}
896
897
NS_IMETHODIMP
898
TabChild::GetDimensions(uint32_t aFlags, int32_t* aX,
899
                             int32_t* aY, int32_t* aCx, int32_t* aCy)
900
0
{
901
0
  ScreenIntRect rect = GetOuterRect();
902
0
  if (aX) {
903
0
    *aX = rect.x;
904
0
  }
905
0
  if (aY) {
906
0
    *aY = rect.y;
907
0
  }
908
0
  if (aCx) {
909
0
    *aCx = rect.width;
910
0
  }
911
0
  if (aCy) {
912
0
    *aCy = rect.height;
913
0
  }
914
0
915
0
  return NS_OK;
916
0
}
917
918
NS_IMETHODIMP
919
TabChild::SetFocus()
920
0
{
921
0
  return NS_ERROR_NOT_IMPLEMENTED;
922
0
}
923
924
NS_IMETHODIMP
925
TabChild::GetVisibility(bool* aVisibility)
926
0
{
927
0
  *aVisibility = true;
928
0
  return NS_OK;
929
0
}
930
931
NS_IMETHODIMP
932
TabChild::SetVisibility(bool aVisibility)
933
0
{
934
0
  // should the platform support this? Bug 666365
935
0
  return NS_OK;
936
0
}
937
938
NS_IMETHODIMP
939
TabChild::GetTitle(nsAString& aTitle)
940
0
{
941
0
  NS_WARNING("TabChild::GetTitle not supported in TabChild");
942
0
943
0
  return NS_ERROR_NOT_IMPLEMENTED;
944
0
}
945
946
NS_IMETHODIMP
947
TabChild::SetTitle(const nsAString& aTitle)
948
0
{
949
0
  // JavaScript sends the "DOMTitleChanged" event to the parent
950
0
  // via the message manager.
951
0
  return NS_OK;
952
0
}
953
954
NS_IMETHODIMP
955
TabChild::GetSiteWindow(void** aSiteWindow)
956
0
{
957
0
  NS_WARNING("TabChild::GetSiteWindow not supported in TabChild");
958
0
959
0
  return NS_ERROR_NOT_IMPLEMENTED;
960
0
}
961
962
NS_IMETHODIMP
963
TabChild::Blur()
964
0
{
965
0
  return NS_ERROR_NOT_IMPLEMENTED;
966
0
}
967
968
NS_IMETHODIMP
969
TabChild::FocusNextElement(bool aForDocumentNavigation)
970
0
{
971
0
  SendMoveFocus(true, aForDocumentNavigation);
972
0
  return NS_OK;
973
0
}
974
975
NS_IMETHODIMP
976
TabChild::FocusPrevElement(bool aForDocumentNavigation)
977
0
{
978
0
  SendMoveFocus(false, aForDocumentNavigation);
979
0
  return NS_OK;
980
0
}
981
982
NS_IMETHODIMP
983
TabChild::GetInterface(const nsIID & aIID, void **aSink)
984
0
{
985
0
    if (aIID.Equals(NS_GET_IID(nsIWebBrowserChrome3))) {
986
0
      NS_IF_ADDREF(((nsISupports *) (*aSink = mWebBrowserChrome)));
987
0
      return NS_OK;
988
0
    }
989
0
990
0
    // XXXbz should we restrict the set of interfaces we hand out here?
991
0
    // See bug 537429
992
0
    return QueryInterface(aIID, aSink);
993
0
}
994
995
NS_IMETHODIMP
996
TabChild::ProvideWindow(mozIDOMWindowProxy* aParent,
997
                        uint32_t aChromeFlags,
998
                        bool aCalledFromJS,
999
                        bool aPositionSpecified, bool aSizeSpecified,
1000
                        nsIURI* aURI, const nsAString& aName,
1001
                        const nsACString& aFeatures, bool aForceNoOpener,
1002
                        nsDocShellLoadInfo* aLoadInfo, bool* aWindowIsNew,
1003
                        mozIDOMWindowProxy** aReturn)
1004
0
{
1005
0
    *aReturn = nullptr;
1006
0
1007
0
    // If aParent is inside an <iframe mozbrowser> and this isn't a request to
1008
0
    // open a modal-type window, we're going to create a new <iframe mozbrowser>
1009
0
    // and return its window here.
1010
0
    nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
1011
0
    bool iframeMoz = (docshell && docshell->GetIsInMozBrowser() &&
1012
0
                      !(aChromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
1013
0
                                        nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
1014
0
                                        nsIWebBrowserChrome::CHROME_OPENAS_CHROME)));
1015
0
1016
0
    if (!iframeMoz) {
1017
0
      int32_t openLocation =
1018
0
        nsWindowWatcher::GetWindowOpenLocation(nsPIDOMWindowOuter::From(aParent),
1019
0
                                               aChromeFlags, aCalledFromJS,
1020
0
                                               aPositionSpecified, aSizeSpecified);
1021
0
1022
0
      // If it turns out we're opening in the current browser, just hand over the
1023
0
      // current browser's docshell.
1024
0
      if (openLocation == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
1025
0
        nsCOMPtr<nsIWebBrowser> browser = do_GetInterface(WebNavigation());
1026
0
        *aWindowIsNew = false;
1027
0
        return browser->GetContentDOMWindow(aReturn);
1028
0
      }
1029
0
    }
1030
0
1031
0
    // Note that ProvideWindowCommon may return NS_ERROR_ABORT if the
1032
0
    // open window call was canceled.  It's important that we pass this error
1033
0
    // code back to our caller.
1034
0
    ContentChild* cc = ContentChild::GetSingleton();
1035
0
    return cc->ProvideWindowCommon(this,
1036
0
                                   aParent,
1037
0
                                   iframeMoz,
1038
0
                                   aChromeFlags,
1039
0
                                   aCalledFromJS,
1040
0
                                   aPositionSpecified,
1041
0
                                   aSizeSpecified,
1042
0
                                   aURI,
1043
0
                                   aName,
1044
0
                                   aFeatures,
1045
0
                                   aForceNoOpener,
1046
0
                                   aLoadInfo,
1047
0
                                   aWindowIsNew,
1048
0
                                   aReturn);
1049
0
}
1050
1051
void
1052
TabChild::DestroyWindow()
1053
0
{
1054
0
    if (mCoalescedMouseEventFlusher) {
1055
0
      mCoalescedMouseEventFlusher->RemoveObserver();
1056
0
      mCoalescedMouseEventFlusher = nullptr;
1057
0
    }
1058
0
1059
0
    // In case we don't have chance to process all entries, clean all data in
1060
0
    // the queue.
1061
0
    while (mToBeDispatchedMouseData.GetSize() > 0) {
1062
0
      UniquePtr<CoalescedMouseData> data(
1063
0
        static_cast<CoalescedMouseData*>(mToBeDispatchedMouseData.PopFront()));
1064
0
      data.reset();
1065
0
    }
1066
0
1067
0
    nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
1068
0
    if (baseWindow)
1069
0
        baseWindow->Destroy();
1070
0
1071
0
    // NB: the order of mPuppetWidget->Destroy() and mRemoteFrame->Destroy()
1072
0
    // is important: we want to kill off remote layers before their
1073
0
    // frames
1074
0
    if (mPuppetWidget) {
1075
0
        mPuppetWidget->Destroy();
1076
0
    }
1077
0
1078
0
    if (mRemoteFrame) {
1079
0
        mRemoteFrame->Destroy();
1080
0
        mRemoteFrame = nullptr;
1081
0
    }
1082
0
1083
0
1084
0
    if (mLayersId.IsValid()) {
1085
0
      StaticMutexAutoLock lock(sTabChildrenMutex);
1086
0
1087
0
      MOZ_ASSERT(sTabChildren);
1088
0
      sTabChildren->Remove(uint64_t(mLayersId));
1089
0
      if (!sTabChildren->Count()) {
1090
0
        delete sTabChildren;
1091
0
        sTabChildren = nullptr;
1092
0
      }
1093
0
      mLayersId = layers::LayersId{0};
1094
0
    }
1095
0
}
1096
1097
void
1098
TabChild::ActorDestroy(ActorDestroyReason why)
1099
0
{
1100
0
  mIPCOpen = false;
1101
0
1102
0
  DestroyWindow();
1103
0
1104
0
  if (mTabChildMessageManager) {
1105
0
    // We should have a message manager if the global is alive, but it
1106
0
    // seems sometimes we don't.  Assert in aurora/nightly, but don't
1107
0
    // crash in release builds.
1108
0
    MOZ_DIAGNOSTIC_ASSERT(mTabChildMessageManager->GetMessageManager());
1109
0
    if (mTabChildMessageManager->GetMessageManager()) {
1110
0
      // The messageManager relays messages via the TabChild which
1111
0
      // no longer exists.
1112
0
      mTabChildMessageManager->DisconnectMessageManager();
1113
0
    }
1114
0
  }
1115
0
1116
0
  CompositorBridgeChild* compositorChild = CompositorBridgeChild::Get();
1117
0
  if (compositorChild) {
1118
0
    compositorChild->CancelNotifyAfterRemotePaint(this);
1119
0
  }
1120
0
1121
0
  if (GetTabId() != 0) {
1122
0
    NestedTabChildMap().erase(GetTabId());
1123
0
  }
1124
0
}
1125
1126
TabChild::~TabChild()
1127
0
{
1128
0
  if (sVisibleTabs) {
1129
0
    sVisibleTabs->RemoveEntry(this);
1130
0
    if (sVisibleTabs->IsEmpty()) {
1131
0
      delete sVisibleTabs;
1132
0
      sVisibleTabs = nullptr;
1133
0
    }
1134
0
  }
1135
0
1136
0
  DestroyWindow();
1137
0
1138
0
  nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(WebNavigation());
1139
0
  if (webBrowser) {
1140
0
    webBrowser->SetContainerWindow(nullptr);
1141
0
  }
1142
0
1143
0
  mozilla::DropJSObjects(this);
1144
0
}
1145
1146
mozilla::ipc::IPCResult
1147
TabChild::RecvLoadURL(const nsCString& aURI,
1148
                      const ShowInfo& aInfo)
1149
0
{
1150
0
  if (!mDidLoadURLInit) {
1151
0
    mDidLoadURLInit = true;
1152
0
    if (!InitTabChildMessageManager()) {
1153
0
      return IPC_FAIL_NO_REASON(this);
1154
0
    }
1155
0
1156
0
    ApplyShowInfo(aInfo);
1157
0
  }
1158
0
1159
0
  nsresult rv =
1160
0
    WebNavigation()->LoadURI(NS_ConvertUTF8toUTF16(aURI),
1161
0
                             nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
1162
0
                             nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL,
1163
0
                             nullptr, nullptr, nullptr, nsContentUtils::GetSystemPrincipal());
1164
0
  if (NS_FAILED(rv)) {
1165
0
      NS_WARNING("WebNavigation()->LoadURI failed. Eating exception, what else can I do?");
1166
0
  }
1167
0
1168
0
  CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL, aURI);
1169
0
1170
0
  return IPC_OK();
1171
0
}
1172
1173
void
1174
TabChild::DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
1175
                     const layers::LayersId& aLayersId,
1176
                     const CompositorOptions& aCompositorOptions,
1177
                     PRenderFrameChild* aRenderFrame, const ShowInfo& aShowInfo)
1178
0
{
1179
0
  mLayersConnected = aRenderFrame ? Some(true) : Some(false);
1180
0
  InitRenderingState(aTextureFactoryIdentifier, aLayersId, aCompositorOptions, aRenderFrame);
1181
0
  RecvShow(ScreenIntSize(0, 0), aShowInfo, mParentIsActive, nsSizeMode_Normal);
1182
0
  mDidFakeShow = true;
1183
0
}
1184
1185
void
1186
TabChild::ApplyShowInfo(const ShowInfo& aInfo)
1187
0
{
1188
0
  // Even if we already set real show info, the dpi / rounding & scale may still
1189
0
  // be invalid (if TabParent wasn't able to get widget it would just send 0).
1190
0
  // So better to always set up-to-date values here.
1191
0
  if (aInfo.dpi() > 0) {
1192
0
    mPuppetWidget->UpdateBackingScaleCache(aInfo.dpi(),
1193
0
                                           aInfo.widgetRounding(),
1194
0
                                           aInfo.defaultScale());
1195
0
  }
1196
0
1197
0
  if (mDidSetRealShowInfo) {
1198
0
    return;
1199
0
  }
1200
0
1201
0
  if (!aInfo.fakeShowInfo()) {
1202
0
    // Once we've got one ShowInfo from parent, no need to update the values
1203
0
    // anymore.
1204
0
    mDidSetRealShowInfo = true;
1205
0
  }
1206
0
1207
0
  nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
1208
0
  if (docShell) {
1209
0
    nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(docShell);
1210
0
    if (IsMozBrowser()) {
1211
0
      // B2G allows window.name to be set by changing the name attribute on the
1212
0
      // <iframe mozbrowser> element. window.open calls cause this attribute to
1213
0
      // be set to the correct value. A normal <xul:browser> element has no such
1214
0
      // attribute. The data we get here comes from reading the attribute, so we
1215
0
      // shouldn't trust it for <xul:browser> elements.
1216
0
      item->SetName(aInfo.name());
1217
0
    }
1218
0
    docShell->SetFullscreenAllowed(aInfo.fullscreenAllowed());
1219
0
    if (aInfo.isPrivate()) {
1220
0
      nsCOMPtr<nsILoadContext> context = do_GetInterface(docShell);
1221
0
      // No need to re-set private browsing mode.
1222
0
      if (!context->UsePrivateBrowsing()) {
1223
0
        if (docShell->GetHasLoadedNonBlankURI()) {
1224
0
          nsContentUtils::ReportToConsoleNonLocalized(
1225
0
            NS_LITERAL_STRING("We should not switch to Private Browsing after loading a document."),
1226
0
            nsIScriptError::warningFlag,
1227
0
            NS_LITERAL_CSTRING("mozprivatebrowsing"),
1228
0
            nullptr);
1229
0
        } else {
1230
0
          OriginAttributes attrs(nsDocShell::Cast(docShell)->GetOriginAttributes());
1231
0
          attrs.SyncAttributesWithPrivateBrowsing(true);
1232
0
          nsDocShell::Cast(docShell)->SetOriginAttributes(attrs);
1233
0
        }
1234
0
      }
1235
0
    }
1236
0
  }
1237
0
  mIsTransparent = aInfo.isTransparent();
1238
0
}
1239
1240
mozilla::ipc::IPCResult
1241
TabChild::RecvShow(const ScreenIntSize& aSize,
1242
                   const ShowInfo& aInfo,
1243
                   const bool& aParentIsActive,
1244
                   const nsSizeMode& aSizeMode)
1245
0
{
1246
0
  bool res = true;
1247
0
1248
0
  mPuppetWidget->SetSizeMode(aSizeMode);
1249
0
  if (!mDidFakeShow) {
1250
0
    nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
1251
0
    if (!baseWindow) {
1252
0
        NS_ERROR("WebNavigation() doesn't QI to nsIBaseWindow");
1253
0
        return IPC_FAIL_NO_REASON(this);
1254
0
    }
1255
0
1256
0
    baseWindow->SetVisibility(true);
1257
0
    res = InitTabChildMessageManager();
1258
0
  }
1259
0
1260
0
  ApplyShowInfo(aInfo);
1261
0
  RecvParentActivated(aParentIsActive);
1262
0
1263
0
  if (!res) {
1264
0
    return IPC_FAIL_NO_REASON(this);
1265
0
  }
1266
0
1267
0
  // We have now done enough initialization for the record/replay system to
1268
0
  // create checkpoints. Try to create the initial checkpoint now, in case this
1269
0
  // process never paints later on (the usual place where checkpoints occur).
1270
0
  if (recordreplay::IsRecordingOrReplaying()) {
1271
0
    recordreplay::child::MaybeCreateInitialCheckpoint();
1272
0
  }
1273
0
1274
0
  return IPC_OK();
1275
0
}
1276
1277
mozilla::ipc::IPCResult
1278
TabChild::RecvInitRendering(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
1279
                            const layers::LayersId& aLayersId,
1280
                            const CompositorOptions& aCompositorOptions,
1281
                            const bool& aLayersConnected,
1282
                            PRenderFrameChild* aRenderFrame)
1283
0
{
1284
0
  MOZ_ASSERT((!mDidFakeShow && aRenderFrame) || (mDidFakeShow && !aRenderFrame));
1285
0
1286
0
  mLayersConnected = Some(aLayersConnected);
1287
0
  InitRenderingState(aTextureFactoryIdentifier, aLayersId, aCompositorOptions, aRenderFrame);
1288
0
  return IPC_OK();
1289
0
}
1290
1291
mozilla::ipc::IPCResult
1292
TabChild::RecvUpdateDimensions(const DimensionInfo& aDimensionInfo)
1293
0
{
1294
0
    // When recording/replaying we need to make sure the dimensions are up to
1295
0
    // date on the compositor used in this process.
1296
0
    if (!mRemoteFrame && !recordreplay::IsRecordingOrReplaying()) {
1297
0
        return IPC_OK();
1298
0
    }
1299
0
1300
0
    mUnscaledOuterRect = aDimensionInfo.rect();
1301
0
    mClientOffset = aDimensionInfo.clientOffset();
1302
0
    mChromeOffset = aDimensionInfo.chromeOffset();
1303
0
1304
0
    mOrientation = aDimensionInfo.orientation();
1305
0
    SetUnscaledInnerSize(aDimensionInfo.size());
1306
0
    if (!mHasValidInnerSize &&
1307
0
        aDimensionInfo.size().width != 0 &&
1308
0
        aDimensionInfo.size().height != 0) {
1309
0
      mHasValidInnerSize = true;
1310
0
    }
1311
0
1312
0
    ScreenIntSize screenSize = GetInnerSize();
1313
0
    ScreenIntRect screenRect = GetOuterRect();
1314
0
1315
0
    // Set the size on the document viewer before we update the widget and
1316
0
    // trigger a reflow. Otherwise the MobileViewportManager reads the stale
1317
0
    // size from the content viewer when it computes a new CSS viewport.
1318
0
    nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
1319
0
    baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height,
1320
0
                                nsIBaseWindow::eRepaint);
1321
0
1322
0
    mPuppetWidget->Resize(screenRect.x + mClientOffset.x + mChromeOffset.x,
1323
0
                          screenRect.y + mClientOffset.y + mChromeOffset.y,
1324
0
                          screenSize.width, screenSize.height, true);
1325
0
1326
0
    return IPC_OK();
1327
0
}
1328
1329
mozilla::ipc::IPCResult
1330
TabChild::RecvSizeModeChanged(const nsSizeMode& aSizeMode)
1331
0
{
1332
0
  mPuppetWidget->SetSizeMode(aSizeMode);
1333
0
  if (!mPuppetWidget->IsVisible()) {
1334
0
    return IPC_OK();
1335
0
  }
1336
0
  nsCOMPtr<nsIDocument> document(GetDocument());
1337
0
  nsPresContext* presContext = document->GetPresContext();
1338
0
  if (presContext) {
1339
0
    presContext->SizeModeChanged(aSizeMode);
1340
0
  }
1341
0
  return IPC_OK();
1342
0
}
1343
1344
bool
1345
TabChild::UpdateFrame(const FrameMetrics& aFrameMetrics)
1346
0
{
1347
0
  return TabChildBase::UpdateFrameHandler(aFrameMetrics);
1348
0
}
1349
1350
mozilla::ipc::IPCResult
1351
TabChild::RecvSuppressDisplayport(const bool& aEnabled)
1352
0
{
1353
0
  if (nsCOMPtr<nsIPresShell> shell = GetPresShell()) {
1354
0
    shell->SuppressDisplayport(aEnabled);
1355
0
  }
1356
0
  return IPC_OK();
1357
0
}
1358
1359
void
1360
TabChild::HandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers,
1361
                          const ScrollableLayerGuid& aGuid)
1362
0
{
1363
0
  TABC_LOG("Handling double tap at %s with %p %p\n",
1364
0
    Stringify(aPoint).c_str(),
1365
0
    mTabChildMessageManager ? mTabChildMessageManager->GetWrapper() : nullptr,
1366
0
    mTabChildMessageManager.get());
1367
0
1368
0
  if (!mTabChildMessageManager) {
1369
0
    return;
1370
0
  }
1371
0
1372
0
  // Note: there is nothing to do with the modifiers here, as we are not
1373
0
  // synthesizing any sort of mouse event.
1374
0
  nsCOMPtr<nsIDocument> document = GetDocument();
1375
0
  CSSRect zoomToRect = CalculateRectToZoomTo(document, aPoint);
1376
0
  // The double-tap can be dispatched by any scroll frame (so |aGuid| could be
1377
0
  // the guid of any scroll frame), but the zoom-to-rect operation must be
1378
0
  // performed by the root content scroll frame, so query its identifiers
1379
0
  // for the SendZoomToRect() call rather than using the ones from |aGuid|.
1380
0
  uint32_t presShellId;
1381
0
  ViewID viewId;
1382
0
  if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(
1383
0
      document->GetDocumentElement(), &presShellId, &viewId) && mApzcTreeManager) {
1384
0
    ScrollableLayerGuid guid(mLayersId, presShellId, viewId);
1385
0
1386
0
    mApzcTreeManager->ZoomToRect(guid, zoomToRect, DEFAULT_BEHAVIOR);
1387
0
  }
1388
0
}
1389
1390
mozilla::ipc::IPCResult
1391
TabChild::RecvHandleTap(const GeckoContentController::TapType& aType,
1392
                        const LayoutDevicePoint& aPoint,
1393
                        const Modifiers& aModifiers,
1394
                        const ScrollableLayerGuid& aGuid,
1395
                        const uint64_t& aInputBlockId)
1396
0
{
1397
0
  nsCOMPtr<nsIPresShell> presShell = GetPresShell();
1398
0
  if (!presShell) {
1399
0
    return IPC_OK();
1400
0
  }
1401
0
  if (!presShell->GetPresContext()) {
1402
0
    return IPC_OK();
1403
0
  }
1404
0
  CSSToLayoutDeviceScale scale(presShell->GetPresContext()->CSSToDevPixelScale());
1405
0
  CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint / scale, aGuid);
1406
0
1407
0
  switch (aType) {
1408
0
  case GeckoContentController::TapType::eSingleTap:
1409
0
    if (mTabChildMessageManager) {
1410
0
      mAPZEventState->ProcessSingleTap(point, scale, aModifiers, aGuid, 1);
1411
0
    }
1412
0
    break;
1413
0
  case GeckoContentController::TapType::eDoubleTap:
1414
0
    HandleDoubleTap(point, aModifiers, aGuid);
1415
0
    break;
1416
0
  case GeckoContentController::TapType::eSecondTap:
1417
0
    if (mTabChildMessageManager) {
1418
0
      mAPZEventState->ProcessSingleTap(point, scale, aModifiers, aGuid, 2);
1419
0
    }
1420
0
    break;
1421
0
  case GeckoContentController::TapType::eLongTap:
1422
0
    if (mTabChildMessageManager) {
1423
0
      mAPZEventState->ProcessLongTap(presShell, point, scale, aModifiers, aGuid,
1424
0
          aInputBlockId);
1425
0
    }
1426
0
    break;
1427
0
  case GeckoContentController::TapType::eLongTapUp:
1428
0
    if (mTabChildMessageManager) {
1429
0
      mAPZEventState->ProcessLongTapUp(presShell, point, scale, aModifiers);
1430
0
    }
1431
0
    break;
1432
0
  }
1433
0
  return IPC_OK();
1434
0
}
1435
1436
mozilla::ipc::IPCResult
1437
TabChild::RecvNormalPriorityHandleTap(
1438
  const GeckoContentController::TapType& aType,
1439
  const LayoutDevicePoint& aPoint,
1440
  const Modifiers& aModifiers,
1441
  const ScrollableLayerGuid& aGuid,
1442
  const uint64_t& aInputBlockId)
1443
0
{
1444
0
  return RecvHandleTap(aType, aPoint, aModifiers, aGuid, aInputBlockId);
1445
0
}
1446
1447
bool
1448
TabChild::NotifyAPZStateChange(const ViewID& aViewId,
1449
                               const layers::GeckoContentController::APZStateChange& aChange,
1450
                               const int& aArg)
1451
0
{
1452
0
  mAPZEventState->ProcessAPZStateChange(aViewId, aChange, aArg);
1453
0
  if (aChange == layers::GeckoContentController::APZStateChange::eTransformEnd) {
1454
0
    // This is used by tests to determine when the APZ is done doing whatever
1455
0
    // it's doing. XXX generify this as needed when writing additional tests.
1456
0
    nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
1457
0
    observerService->NotifyObservers(nullptr, "APZ:TransformEnd", nullptr);
1458
0
  }
1459
0
  return true;
1460
0
}
1461
1462
void
1463
TabChild::StartScrollbarDrag(const layers::AsyncDragMetrics& aDragMetrics)
1464
0
{
1465
0
  ScrollableLayerGuid guid(mLayersId, aDragMetrics.mPresShellId,
1466
0
                           aDragMetrics.mViewId);
1467
0
1468
0
  if (mApzcTreeManager) {
1469
0
    mApzcTreeManager->StartScrollbarDrag(guid, aDragMetrics);
1470
0
  }
1471
0
}
1472
1473
void
1474
TabChild::ZoomToRect(const uint32_t& aPresShellId,
1475
                     const FrameMetrics::ViewID& aViewId,
1476
                     const CSSRect& aRect,
1477
                     const uint32_t& aFlags)
1478
0
{
1479
0
  ScrollableLayerGuid guid(mLayersId, aPresShellId, aViewId);
1480
0
1481
0
  if (mApzcTreeManager) {
1482
0
    mApzcTreeManager->ZoomToRect(guid, aRect, aFlags);
1483
0
  }
1484
0
}
1485
1486
mozilla::ipc::IPCResult
1487
TabChild::RecvActivate()
1488
0
{
1489
0
  MOZ_ASSERT(mWebBrowser);
1490
0
  // Ensure that the PresShell exists, otherwise focusing
1491
0
  // is definitely not going to work. GetPresShell should
1492
0
  // create a PresShell if one doesn't exist yet.
1493
0
  nsCOMPtr<nsIPresShell> presShell = GetPresShell();
1494
0
  MOZ_ASSERT(presShell);
1495
0
1496
0
  mWebBrowser->FocusActivate();
1497
0
  return IPC_OK();
1498
0
}
1499
1500
mozilla::ipc::IPCResult
1501
TabChild::RecvDeactivate()
1502
0
{
1503
0
  MOZ_ASSERT(mWebBrowser);
1504
0
  mWebBrowser->FocusDeactivate();
1505
0
  return IPC_OK();
1506
0
}
1507
1508
mozilla::ipc::IPCResult
1509
TabChild::RecvParentActivated(const bool& aActivated)
1510
0
{
1511
0
  mParentIsActive = aActivated;
1512
0
1513
0
  nsFocusManager* fm = nsFocusManager::GetFocusManager();
1514
0
  NS_ENSURE_TRUE(fm, IPC_OK());
1515
0
1516
0
  nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
1517
0
  fm->ParentActivated(window, aActivated);
1518
0
  return IPC_OK();
1519
0
}
1520
1521
mozilla::ipc::IPCResult
1522
TabChild::RecvSetKeyboardIndicators(const UIStateChangeType& aShowAccelerators,
1523
                                    const UIStateChangeType& aShowFocusRings)
1524
0
{
1525
0
  nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
1526
0
  NS_ENSURE_TRUE(window, IPC_OK());
1527
0
1528
0
  window->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
1529
0
  return IPC_OK();
1530
0
}
1531
1532
mozilla::ipc::IPCResult
1533
TabChild::RecvStopIMEStateManagement()
1534
0
{
1535
0
  IMEStateManager::StopIMEStateManagement();
1536
0
  return IPC_OK();
1537
0
}
1538
1539
mozilla::ipc::IPCResult
1540
TabChild::RecvMouseEvent(const nsString& aType,
1541
                         const float&    aX,
1542
                         const float&    aY,
1543
                         const int32_t&  aButton,
1544
                         const int32_t&  aClickCount,
1545
                         const int32_t&  aModifiers,
1546
                         const bool&     aIgnoreRootScrollFrame)
1547
0
{
1548
0
  APZCCallbackHelper::DispatchMouseEvent(GetPresShell(), aType,
1549
0
                                         CSSPoint(aX, aY), aButton, aClickCount,
1550
0
                                         aModifiers, aIgnoreRootScrollFrame,
1551
0
                                         MouseEvent_Binding::MOZ_SOURCE_UNKNOWN,
1552
0
                                         0 /* Use the default value here. */);
1553
0
  return IPC_OK();
1554
0
}
1555
1556
void
1557
TabChild::ProcessPendingCoalescedMouseDataAndDispatchEvents()
1558
0
{
1559
0
  if (!mCoalesceMouseMoveEvents || !mCoalescedMouseEventFlusher) {
1560
0
    // We don't enable mouse coalescing or we are destroying TabChild.
1561
0
    return;
1562
0
  }
1563
0
1564
0
  // We may reentry the event loop and push more data to
1565
0
  // mToBeDispatchedMouseData while dispatching an event.
1566
0
1567
0
  // We may have some pending coalesced data while dispatch an event and reentry
1568
0
  // the event loop. In that case we don't have chance to consume the remainding
1569
0
  // pending data until we get new mouse events. Get some helps from
1570
0
  // mCoalescedMouseEventFlusher to trigger it.
1571
0
  mCoalescedMouseEventFlusher->StartObserver();
1572
0
1573
0
  while (mToBeDispatchedMouseData.GetSize() > 0) {
1574
0
    UniquePtr<CoalescedMouseData> data(
1575
0
      static_cast<CoalescedMouseData*>(mToBeDispatchedMouseData.PopFront()));
1576
0
1577
0
    UniquePtr<WidgetMouseEvent> event = data->TakeCoalescedEvent();
1578
0
    if (event) {
1579
0
      // Dispatch the pending events. Using HandleRealMouseButtonEvent
1580
0
      // to bypass the coalesce handling in RecvRealMouseMoveEvent. Can't use
1581
0
      // RecvRealMouseButtonEvent because we may also put some mouse events
1582
0
      // other than mousemove.
1583
0
      HandleRealMouseButtonEvent(*event,
1584
0
                                 data->GetScrollableLayerGuid(),
1585
0
                                 data->GetInputBlockId());
1586
0
    }
1587
0
  }
1588
0
  // mCoalescedMouseEventFlusher may be destroyed when reentrying the event
1589
0
  // loop.
1590
0
  if (mCoalescedMouseEventFlusher) {
1591
0
    mCoalescedMouseEventFlusher->RemoveObserver();
1592
0
  }
1593
0
}
1594
1595
void
1596
TabChild::FlushAllCoalescedMouseData()
1597
0
{
1598
0
  MOZ_ASSERT(mCoalesceMouseMoveEvents);
1599
0
1600
0
  // Move all entries from mCoalescedMouseData to mToBeDispatchedMouseData.
1601
0
  for (auto iter = mCoalescedMouseData.Iter(); !iter.Done(); iter.Next()) {
1602
0
    CoalescedMouseData* data = iter.UserData();
1603
0
    if (!data || data->IsEmpty()) {
1604
0
      continue;
1605
0
    }
1606
0
    UniquePtr<CoalescedMouseData> dispatchData =
1607
0
      MakeUnique<CoalescedMouseData>();
1608
0
1609
0
    dispatchData->RetrieveDataFrom(*data);
1610
0
    mToBeDispatchedMouseData.Push(dispatchData.release());
1611
0
  }
1612
0
  mCoalescedMouseData.Clear();
1613
0
}
1614
1615
mozilla::ipc::IPCResult
1616
TabChild::RecvRealMouseMoveEvent(const WidgetMouseEvent& aEvent,
1617
                                 const ScrollableLayerGuid& aGuid,
1618
                                 const uint64_t& aInputBlockId)
1619
0
{
1620
0
  if (mCoalesceMouseMoveEvents && mCoalescedMouseEventFlusher) {
1621
0
    CoalescedMouseData* data = nullptr;
1622
0
    mCoalescedMouseData.Get(aEvent.pointerId, &data);
1623
0
    if (!data) {
1624
0
      data = new CoalescedMouseData();
1625
0
      mCoalescedMouseData.Put(aEvent.pointerId, data);
1626
0
    }
1627
0
    if (data->CanCoalesce(aEvent, aGuid, aInputBlockId)) {
1628
0
      data->Coalesce(aEvent, aGuid, aInputBlockId);
1629
0
      mCoalescedMouseEventFlusher->StartObserver();
1630
0
      return IPC_OK();
1631
0
    }
1632
0
    // Can't coalesce current mousemove event. Put the coalesced mousemove data
1633
0
    // with the same pointer id to mToBeDispatchedMouseData, coalesce the
1634
0
    // current one, and process all pending data in mToBeDispatchedMouseData.
1635
0
    MOZ_ASSERT(data);
1636
0
    UniquePtr<CoalescedMouseData> dispatchData =
1637
0
      MakeUnique<CoalescedMouseData>();
1638
0
1639
0
    dispatchData->RetrieveDataFrom(*data);
1640
0
    mToBeDispatchedMouseData.Push(dispatchData.release());
1641
0
1642
0
    // Put new data to replace the old one in the hash table.
1643
0
    CoalescedMouseData* newData = new CoalescedMouseData();
1644
0
    mCoalescedMouseData.Put(aEvent.pointerId, newData);
1645
0
    newData->Coalesce(aEvent, aGuid, aInputBlockId);
1646
0
1647
0
    // Dispatch all pending mouse events.
1648
0
    ProcessPendingCoalescedMouseDataAndDispatchEvents();
1649
0
    mCoalescedMouseEventFlusher->StartObserver();
1650
0
  } else if (!RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId)) {
1651
0
    return IPC_FAIL_NO_REASON(this);
1652
0
  }
1653
0
  return IPC_OK();
1654
0
}
1655
1656
mozilla::ipc::IPCResult
1657
TabChild::RecvNormalPriorityRealMouseMoveEvent(const WidgetMouseEvent& aEvent,
1658
                                               const ScrollableLayerGuid& aGuid,
1659
                                               const uint64_t& aInputBlockId)
1660
0
{
1661
0
  return RecvRealMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1662
0
}
1663
1664
mozilla::ipc::IPCResult
1665
TabChild::RecvSynthMouseMoveEvent(const WidgetMouseEvent& aEvent,
1666
                                  const ScrollableLayerGuid& aGuid,
1667
                                  const uint64_t& aInputBlockId)
1668
0
{
1669
0
  if (!RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId)) {
1670
0
    return IPC_FAIL_NO_REASON(this);
1671
0
  }
1672
0
  return IPC_OK();
1673
0
}
1674
1675
mozilla::ipc::IPCResult
1676
TabChild::RecvNormalPrioritySynthMouseMoveEvent(const WidgetMouseEvent& aEvent,
1677
                                                const ScrollableLayerGuid& aGuid,
1678
                                                const uint64_t& aInputBlockId)
1679
0
{
1680
0
  return RecvSynthMouseMoveEvent(aEvent, aGuid, aInputBlockId);
1681
0
}
1682
1683
mozilla::ipc::IPCResult
1684
TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
1685
                                   const ScrollableLayerGuid& aGuid,
1686
                                   const uint64_t& aInputBlockId)
1687
0
{
1688
0
  if (mCoalesceMouseMoveEvents && mCoalescedMouseEventFlusher &&
1689
0
      aEvent.mMessage != eMouseMove) {
1690
0
    // When receiving a mouse event other than mousemove, we have to dispatch
1691
0
    // all coalesced events before it. However, we can't dispatch all pending
1692
0
    // coalesced events directly because we may reentry the event loop while
1693
0
    // dispatching. To make sure we won't dispatch disorder events, we move all
1694
0
    // coalesced mousemove events and current event to a deque to dispatch them.
1695
0
    // When reentrying the event loop and dispatching more events, we put new
1696
0
    // events in the end of the nsQueue and dispatch events from the beginning.
1697
0
    FlushAllCoalescedMouseData();
1698
0
1699
0
    UniquePtr<CoalescedMouseData> dispatchData =
1700
0
      MakeUnique<CoalescedMouseData>();
1701
0
1702
0
    dispatchData->Coalesce(aEvent, aGuid, aInputBlockId);
1703
0
    mToBeDispatchedMouseData.Push(dispatchData.release());
1704
0
1705
0
    ProcessPendingCoalescedMouseDataAndDispatchEvents();
1706
0
    return IPC_OK();
1707
0
  }
1708
0
  HandleRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1709
0
  return IPC_OK();
1710
0
}
1711
1712
void
1713
TabChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
1714
                                     const ScrollableLayerGuid& aGuid,
1715
                                     const uint64_t& aInputBlockId)
1716
0
{
1717
0
  // Mouse events like eMouseEnterIntoWidget, that are created in the parent
1718
0
  // process EventStateManager code, have an input block id which they get from
1719
0
  // the InputAPZContext in the parent process stack. However, they did not
1720
0
  // actually go through the APZ code and so their mHandledByAPZ flag is false.
1721
0
  // Since thos events didn't go through APZ, we don't need to send
1722
0
  // notifications for them.
1723
0
  UniquePtr<DisplayportSetListener> postLayerization;
1724
0
  if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) {
1725
0
    nsCOMPtr<nsIDocument> document(GetDocument());
1726
0
    postLayerization = APZCCallbackHelper::SendSetTargetAPZCNotification(
1727
0
        mPuppetWidget, document, aEvent, aGuid, aInputBlockId);
1728
0
  }
1729
0
1730
0
  InputAPZContext context(aGuid, aInputBlockId, nsEventStatus_eIgnore, postLayerization != nullptr);
1731
0
1732
0
  WidgetMouseEvent localEvent(aEvent);
1733
0
  localEvent.mWidget = mPuppetWidget;
1734
0
  APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
1735
0
      mPuppetWidget->GetDefaultScale());
1736
0
  DispatchWidgetEventViaAPZ(localEvent);
1737
0
1738
0
  if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) {
1739
0
    mAPZEventState->ProcessMouseEvent(aEvent, aGuid, aInputBlockId);
1740
0
  }
1741
0
1742
0
  // Do this after the DispatchWidgetEventViaAPZ call above, so that if the
1743
0
  // mouse event triggered a post-refresh AsyncDragMetrics message to be sent
1744
0
  // to APZ (from scrollbar dragging in nsSliderFrame), then that will reach
1745
0
  // APZ before the SetTargetAPZC message. This ensures the drag input block
1746
0
  // gets the drag metrics before handling the input events.
1747
0
  if (postLayerization && postLayerization->Register()) {
1748
0
    Unused << postLayerization.release();
1749
0
  }
1750
0
}
1751
1752
mozilla::ipc::IPCResult
1753
TabChild::RecvNormalPriorityRealMouseButtonEvent(
1754
  const WidgetMouseEvent& aEvent,
1755
  const ScrollableLayerGuid& aGuid,
1756
  const uint64_t& aInputBlockId)
1757
0
{
1758
0
  return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
1759
0
}
1760
1761
// In case handling repeated mouse wheel takes much time, we skip firing current
1762
// wheel event if it may be coalesced to the next one.
1763
bool
1764
TabChild::MaybeCoalesceWheelEvent(const WidgetWheelEvent& aEvent,
1765
                                  const ScrollableLayerGuid& aGuid,
1766
                                  const uint64_t& aInputBlockId,
1767
                                  bool* aIsNextWheelEvent)
1768
0
{
1769
0
  MOZ_ASSERT(aIsNextWheelEvent);
1770
0
  if (aEvent.mMessage == eWheel) {
1771
0
    GetIPCChannel()->PeekMessages(
1772
0
        [aIsNextWheelEvent](const IPC::Message& aMsg) -> bool {
1773
0
          if (aMsg.type() == mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID) {
1774
0
            *aIsNextWheelEvent = true;
1775
0
          }
1776
0
          return false; // Stop peeking.
1777
0
        });
1778
0
    // We only coalesce the current event when
1779
0
    // 1. It's eWheel (we don't coalesce eOperationStart and eWheelOperationEnd)
1780
0
    // 2. It's not the first wheel event.
1781
0
    // 3. It's not the last wheel event.
1782
0
    // 4. It's dispatched before the last wheel event was processed +
1783
0
    //    the processing time of the last event.
1784
0
    //    This way pages spending lots of time in wheel listeners get wheel
1785
0
    //    events coalesced more aggressively.
1786
0
    // 5. It has same attributes as the coalesced wheel event which is not yet
1787
0
    //    fired.
1788
0
    if (!mLastWheelProcessedTimeFromParent.IsNull() &&
1789
0
        *aIsNextWheelEvent &&
1790
0
        aEvent.mTimeStamp < (mLastWheelProcessedTimeFromParent +
1791
0
                             mLastWheelProcessingDuration) &&
1792
0
        (mCoalescedWheelData.IsEmpty() ||
1793
0
         mCoalescedWheelData.CanCoalesce(aEvent, aGuid, aInputBlockId))) {
1794
0
      mCoalescedWheelData.Coalesce(aEvent, aGuid, aInputBlockId);
1795
0
      return true;
1796
0
    }
1797
0
  }
1798
0
  return false;
1799
0
}
1800
1801
nsEventStatus
1802
TabChild::DispatchWidgetEventViaAPZ(WidgetGUIEvent& aEvent)
1803
0
{
1804
0
  aEvent.ResetWaitingReplyFromRemoteProcessState();
1805
0
  return APZCCallbackHelper::DispatchWidgetEvent(aEvent);
1806
0
}
1807
1808
void
1809
TabChild::MaybeDispatchCoalescedWheelEvent()
1810
0
{
1811
0
  if (mCoalescedWheelData.IsEmpty()) {
1812
0
    return;
1813
0
  }
1814
0
  UniquePtr<WidgetWheelEvent> wheelEvent =
1815
0
    mCoalescedWheelData.TakeCoalescedEvent();
1816
0
  MOZ_ASSERT(wheelEvent);
1817
0
  DispatchWheelEvent(*wheelEvent,
1818
0
                     mCoalescedWheelData.GetScrollableLayerGuid(),
1819
0
                     mCoalescedWheelData.GetInputBlockId());
1820
0
}
1821
1822
void
1823
TabChild::DispatchWheelEvent(const WidgetWheelEvent& aEvent,
1824
                                  const ScrollableLayerGuid& aGuid,
1825
                                  const uint64_t& aInputBlockId)
1826
0
{
1827
0
  WidgetWheelEvent localEvent(aEvent);
1828
0
  if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) {
1829
0
    nsCOMPtr<nsIDocument> document(GetDocument());
1830
0
    UniquePtr<DisplayportSetListener> postLayerization =
1831
0
        APZCCallbackHelper::SendSetTargetAPZCNotification(
1832
0
            mPuppetWidget, document, aEvent, aGuid, aInputBlockId);
1833
0
    if (postLayerization && postLayerization->Register()) {
1834
0
      Unused << postLayerization.release();
1835
0
    }
1836
0
  }
1837
0
1838
0
  localEvent.mWidget = mPuppetWidget;
1839
0
  APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
1840
0
                                             mPuppetWidget->GetDefaultScale());
1841
0
  DispatchWidgetEventViaAPZ(localEvent);
1842
0
1843
0
  if (localEvent.mCanTriggerSwipe) {
1844
0
    SendRespondStartSwipeEvent(aInputBlockId, localEvent.TriggersSwipe());
1845
0
  }
1846
0
1847
0
  if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) {
1848
0
    mAPZEventState->ProcessWheelEvent(localEvent, aGuid, aInputBlockId);
1849
0
  }
1850
0
}
1851
1852
mozilla::ipc::IPCResult
1853
TabChild::RecvMouseWheelEvent(const WidgetWheelEvent& aEvent,
1854
                              const ScrollableLayerGuid& aGuid,
1855
                              const uint64_t& aInputBlockId)
1856
0
{
1857
0
  bool isNextWheelEvent = false;
1858
0
  if (MaybeCoalesceWheelEvent(aEvent, aGuid, aInputBlockId,
1859
0
                              &isNextWheelEvent)) {
1860
0
    return IPC_OK();
1861
0
  }
1862
0
  if (isNextWheelEvent) {
1863
0
    // Update mLastWheelProcessedTimeFromParent so that we can compare the end
1864
0
    // time of the current event with the dispatched time of the next event.
1865
0
    mLastWheelProcessedTimeFromParent = aEvent.mTimeStamp;
1866
0
    mozilla::TimeStamp beforeDispatchingTime = TimeStamp::Now();
1867
0
    MaybeDispatchCoalescedWheelEvent();
1868
0
    DispatchWheelEvent(aEvent, aGuid, aInputBlockId);
1869
0
    mLastWheelProcessingDuration = (TimeStamp::Now() - beforeDispatchingTime);
1870
0
    mLastWheelProcessedTimeFromParent += mLastWheelProcessingDuration;
1871
0
  } else {
1872
0
    // This is the last wheel event. Set mLastWheelProcessedTimeFromParent to
1873
0
    // null moment to avoid coalesce the next incoming wheel event.
1874
0
    mLastWheelProcessedTimeFromParent = TimeStamp();
1875
0
    MaybeDispatchCoalescedWheelEvent();
1876
0
    DispatchWheelEvent(aEvent, aGuid, aInputBlockId);
1877
0
  }
1878
0
  return IPC_OK();
1879
0
}
1880
1881
mozilla::ipc::IPCResult
1882
TabChild::RecvNormalPriorityMouseWheelEvent(const WidgetWheelEvent& aEvent,
1883
                                            const ScrollableLayerGuid& aGuid,
1884
                                            const uint64_t& aInputBlockId)
1885
0
{
1886
0
  return RecvMouseWheelEvent(aEvent, aGuid, aInputBlockId);
1887
0
}
1888
1889
mozilla::ipc::IPCResult
1890
TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
1891
                             const ScrollableLayerGuid& aGuid,
1892
                             const uint64_t& aInputBlockId,
1893
                             const nsEventStatus& aApzResponse)
1894
0
{
1895
0
  TABC_LOG("Receiving touch event of type %d\n", aEvent.mMessage);
1896
0
1897
0
  WidgetTouchEvent localEvent(aEvent);
1898
0
  localEvent.mWidget = mPuppetWidget;
1899
0
1900
0
  APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
1901
0
                                             mPuppetWidget->GetDefaultScale());
1902
0
1903
0
  if (localEvent.mMessage == eTouchStart && AsyncPanZoomEnabled()) {
1904
0
    nsCOMPtr<nsIDocument> document = GetDocument();
1905
0
    if (gfxPrefs::TouchActionEnabled()) {
1906
0
      APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(
1907
0
        mPuppetWidget, document, localEvent, aInputBlockId,
1908
0
        mSetAllowedTouchBehaviorCallback);
1909
0
    }
1910
0
    UniquePtr<DisplayportSetListener> postLayerization =
1911
0
        APZCCallbackHelper::SendSetTargetAPZCNotification(
1912
0
            mPuppetWidget, document, localEvent, aGuid, aInputBlockId);
1913
0
    if (postLayerization && postLayerization->Register()) {
1914
0
      Unused << postLayerization.release();
1915
0
    }
1916
0
  }
1917
0
1918
0
  // Dispatch event to content (potentially a long-running operation)
1919
0
  nsEventStatus status = DispatchWidgetEventViaAPZ(localEvent);
1920
0
1921
0
  if (!AsyncPanZoomEnabled()) {
1922
0
    // We shouldn't have any e10s platforms that have touch events enabled
1923
0
    // without APZ.
1924
0
    MOZ_ASSERT(false);
1925
0
    return IPC_OK();
1926
0
  }
1927
0
1928
0
  mAPZEventState->ProcessTouchEvent(localEvent, aGuid, aInputBlockId,
1929
0
                                    aApzResponse, status);
1930
0
  return IPC_OK();
1931
0
}
1932
1933
mozilla::ipc::IPCResult
1934
TabChild::RecvNormalPriorityRealTouchEvent(const WidgetTouchEvent& aEvent,
1935
                                           const ScrollableLayerGuid& aGuid,
1936
                                           const uint64_t& aInputBlockId,
1937
                                           const nsEventStatus& aApzResponse)
1938
0
{
1939
0
  return RecvRealTouchEvent(aEvent, aGuid, aInputBlockId, aApzResponse);
1940
0
}
1941
1942
mozilla::ipc::IPCResult
1943
TabChild::RecvRealTouchMoveEvent(const WidgetTouchEvent& aEvent,
1944
                                 const ScrollableLayerGuid& aGuid,
1945
                                 const uint64_t& aInputBlockId,
1946
                                 const nsEventStatus& aApzResponse)
1947
0
{
1948
0
  if (!RecvRealTouchEvent(aEvent, aGuid, aInputBlockId, aApzResponse)) {
1949
0
    return IPC_FAIL_NO_REASON(this);
1950
0
  }
1951
0
  return IPC_OK();
1952
0
}
1953
1954
mozilla::ipc::IPCResult
1955
TabChild::RecvNormalPriorityRealTouchMoveEvent(
1956
  const WidgetTouchEvent& aEvent,
1957
  const ScrollableLayerGuid& aGuid,
1958
  const uint64_t& aInputBlockId,
1959
  const nsEventStatus& aApzResponse)
1960
0
{
1961
0
  return RecvRealTouchMoveEvent(aEvent, aGuid, aInputBlockId, aApzResponse);
1962
0
}
1963
1964
mozilla::ipc::IPCResult
1965
TabChild::RecvRealDragEvent(const WidgetDragEvent& aEvent,
1966
                            const uint32_t& aDragAction,
1967
                            const uint32_t& aDropEffect,
1968
                            const nsCString& aPrincipalURISpec)
1969
0
{
1970
0
  WidgetDragEvent localEvent(aEvent);
1971
0
  localEvent.mWidget = mPuppetWidget;
1972
0
1973
0
  nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
1974
0
  if (dragSession) {
1975
0
    dragSession->SetDragAction(aDragAction);
1976
0
    dragSession->SetTriggeringPrincipalURISpec(aPrincipalURISpec);
1977
0
    RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
1978
0
    if (initialDataTransfer) {
1979
0
      initialDataTransfer->SetDropEffectInt(aDropEffect);
1980
0
    }
1981
0
  }
1982
0
1983
0
  if (aEvent.mMessage == eDrop) {
1984
0
    bool canDrop = true;
1985
0
    if (!dragSession || NS_FAILED(dragSession->GetCanDrop(&canDrop)) ||
1986
0
        !canDrop) {
1987
0
      localEvent.mMessage = eDragExit;
1988
0
    }
1989
0
  } else if (aEvent.mMessage == eDragOver) {
1990
0
    nsCOMPtr<nsIDragService> dragService =
1991
0
      do_GetService("@mozilla.org/widget/dragservice;1");
1992
0
    if (dragService) {
1993
0
      // This will dispatch 'drag' event at the source if the
1994
0
      // drag transaction started in this process.
1995
0
      dragService->FireDragEventAtSource(eDrag, aEvent.mModifiers);
1996
0
    }
1997
0
  }
1998
0
1999
0
  DispatchWidgetEventViaAPZ(localEvent);
2000
0
  return IPC_OK();
2001
0
}
2002
2003
mozilla::ipc::IPCResult
2004
TabChild::RecvPluginEvent(const WidgetPluginEvent& aEvent)
2005
0
{
2006
0
  WidgetPluginEvent localEvent(aEvent);
2007
0
  localEvent.mWidget = mPuppetWidget;
2008
0
  nsEventStatus status = DispatchWidgetEventViaAPZ(localEvent);
2009
0
  if (status != nsEventStatus_eConsumeNoDefault) {
2010
0
    // If not consumed, we should call default action
2011
0
    SendDefaultProcOfPluginEvent(aEvent);
2012
0
  }
2013
0
  return IPC_OK();
2014
0
}
2015
2016
void
2017
TabChild::RequestEditCommands(nsIWidget::NativeKeyBindingsType aType,
2018
                              const WidgetKeyboardEvent& aEvent,
2019
                              nsTArray<CommandInt>& aCommands)
2020
0
{
2021
0
  MOZ_ASSERT(aCommands.IsEmpty());
2022
0
2023
0
  if (NS_WARN_IF(aEvent.IsEditCommandsInitialized(aType))) {
2024
0
    aCommands = aEvent.EditCommandsConstRef(aType);
2025
0
    return;
2026
0
  }
2027
0
2028
0
  switch (aType) {
2029
0
    case nsIWidget::NativeKeyBindingsForSingleLineEditor:
2030
0
    case nsIWidget::NativeKeyBindingsForMultiLineEditor:
2031
0
    case nsIWidget::NativeKeyBindingsForRichTextEditor:
2032
0
      break;
2033
0
    default:
2034
0
      MOZ_ASSERT_UNREACHABLE("Invalid native key bindings type");
2035
0
  }
2036
0
2037
0
  // Don't send aEvent to the parent process directly because it'll be marked
2038
0
  // as posted to remote process.
2039
0
  WidgetKeyboardEvent localEvent(aEvent);
2040
0
  SendRequestNativeKeyBindings(aType, localEvent, &aCommands);
2041
0
}
2042
2043
mozilla::ipc::IPCResult
2044
TabChild::RecvNativeSynthesisResponse(const uint64_t& aObserverId,
2045
                                      const nsCString& aResponse)
2046
0
{
2047
0
  mozilla::widget::AutoObserverNotifier::NotifySavedObserver(aObserverId,
2048
0
                                                             aResponse.get());
2049
0
  return IPC_OK();
2050
0
}
2051
2052
// In case handling repeated keys takes much time, we skip firing new ones.
2053
bool
2054
TabChild::SkipRepeatedKeyEvent(const WidgetKeyboardEvent& aEvent)
2055
0
{
2056
0
  if (mRepeatedKeyEventTime.IsNull() ||
2057
0
      !aEvent.CanSkipInRemoteProcess() ||
2058
0
      (aEvent.mMessage != eKeyDown && aEvent.mMessage != eKeyPress)) {
2059
0
    mRepeatedKeyEventTime = TimeStamp();
2060
0
    mSkipKeyPress = false;
2061
0
    return false;
2062
0
  }
2063
0
2064
0
  if ((aEvent.mMessage == eKeyDown &&
2065
0
       (mRepeatedKeyEventTime > aEvent.mTimeStamp)) ||
2066
0
      (mSkipKeyPress && (aEvent.mMessage == eKeyPress))) {
2067
0
    // If we skip a keydown event, also the following keypress events should be
2068
0
    // skipped.
2069
0
    mSkipKeyPress |= aEvent.mMessage == eKeyDown;
2070
0
    return true;
2071
0
  }
2072
0
2073
0
  if (aEvent.mMessage == eKeyDown) {
2074
0
    // If keydown wasn't skipped, nor should the possible following keypress.
2075
0
    mRepeatedKeyEventTime = TimeStamp();
2076
0
    mSkipKeyPress = false;
2077
0
  }
2078
0
  return false;
2079
0
}
2080
2081
void
2082
TabChild::UpdateRepeatedKeyEventEndTime(const WidgetKeyboardEvent& aEvent)
2083
0
{
2084
0
  if (aEvent.mIsRepeat &&
2085
0
      (aEvent.mMessage == eKeyDown || aEvent.mMessage == eKeyPress)) {
2086
0
    mRepeatedKeyEventTime = TimeStamp::Now();
2087
0
  }
2088
0
}
2089
2090
mozilla::ipc::IPCResult
2091
TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& aEvent)
2092
0
{
2093
0
  if (SkipRepeatedKeyEvent(aEvent)) {
2094
0
    return IPC_OK();
2095
0
  }
2096
0
2097
0
  MOZ_ASSERT(aEvent.mMessage != eKeyPress ||
2098
0
             aEvent.AreAllEditCommandsInitialized(),
2099
0
    "eKeyPress event should have native key binding information");
2100
0
2101
0
  // If content code called preventDefault() on a keydown event, then we don't
2102
0
  // want to process any following keypress events.
2103
0
  if (aEvent.mMessage == eKeyPress && mIgnoreKeyPressEvent) {
2104
0
    return IPC_OK();
2105
0
  }
2106
0
2107
0
  WidgetKeyboardEvent localEvent(aEvent);
2108
0
  localEvent.mWidget = mPuppetWidget;
2109
0
  localEvent.mUniqueId = aEvent.mUniqueId;
2110
0
  nsEventStatus status = DispatchWidgetEventViaAPZ(localEvent);
2111
0
2112
0
  // Update the end time of the possible repeated event so that we can skip
2113
0
  // some incoming events in case event handling took long time.
2114
0
  UpdateRepeatedKeyEventEndTime(localEvent);
2115
0
2116
0
  if (aEvent.mMessage == eKeyDown) {
2117
0
    mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
2118
0
  }
2119
0
2120
0
  if (localEvent.mFlags.mIsSuppressedOrDelayed) {
2121
0
    localEvent.PreventDefault();
2122
0
  }
2123
0
2124
0
  // If a response is desired from the content process, resend the key event.
2125
0
  if (aEvent.WantReplyFromContentProcess()) {
2126
0
    // If the event's default isn't prevented but the status is no default,
2127
0
    // That means that the event was consumed by EventStateManager or something
2128
0
    // which is not a usual event handler.  In such case, prevent its default
2129
0
    // as a default handler.  For example, when an eKeyPress event matches
2130
0
    // with a content accesskey, and it's executed, peventDefault() of the
2131
0
    // event won't be called but the status is set to "no default".  Then,
2132
0
    // the event shouldn't be handled by nsMenuBarListener in the main process.
2133
0
    if (!localEvent.DefaultPrevented() &&
2134
0
        status == nsEventStatus_eConsumeNoDefault) {
2135
0
      localEvent.PreventDefault();
2136
0
    }
2137
0
    // This is an ugly hack, mNoRemoteProcessDispatch is set to true when the
2138
0
    // event's PreventDefault() or StopScrollProcessForwarding() is called.
2139
0
    // And then, it'll be checked by ParamTraits<mozilla::WidgetEvent>::Write()
2140
0
    // whether the event is being sent to remote process unexpectedly.
2141
0
    // However, unfortunately, it cannot check the destination.  Therefore,
2142
0
    // we need to clear the flag explicitly here because ParamTraits should
2143
0
    // keep checking the flag for avoiding regression.
2144
0
    localEvent.mFlags.mNoRemoteProcessDispatch = false;
2145
0
    SendReplyKeyEvent(localEvent);
2146
0
  }
2147
0
2148
0
  return IPC_OK();
2149
0
}
2150
2151
mozilla::ipc::IPCResult
2152
TabChild::RecvNormalPriorityRealKeyEvent(const WidgetKeyboardEvent& aEvent)
2153
0
{
2154
0
  return RecvRealKeyEvent(aEvent);
2155
0
}
2156
2157
mozilla::ipc::IPCResult
2158
TabChild::RecvCompositionEvent(const WidgetCompositionEvent& aEvent)
2159
0
{
2160
0
  WidgetCompositionEvent localEvent(aEvent);
2161
0
  localEvent.mWidget = mPuppetWidget;
2162
0
  DispatchWidgetEventViaAPZ(localEvent);
2163
0
  Unused << SendOnEventNeedingAckHandled(aEvent.mMessage);
2164
0
  return IPC_OK();
2165
0
}
2166
2167
mozilla::ipc::IPCResult
2168
TabChild::RecvNormalPriorityCompositionEvent(
2169
            const WidgetCompositionEvent& aEvent)
2170
0
{
2171
0
  return RecvCompositionEvent(aEvent);
2172
0
}
2173
2174
mozilla::ipc::IPCResult
2175
TabChild::RecvSelectionEvent(const WidgetSelectionEvent& aEvent)
2176
0
{
2177
0
  WidgetSelectionEvent localEvent(aEvent);
2178
0
  localEvent.mWidget = mPuppetWidget;
2179
0
  DispatchWidgetEventViaAPZ(localEvent);
2180
0
  Unused << SendOnEventNeedingAckHandled(aEvent.mMessage);
2181
0
  return IPC_OK();
2182
0
}
2183
2184
mozilla::ipc::IPCResult
2185
TabChild::RecvNormalPrioritySelectionEvent(const WidgetSelectionEvent& aEvent)
2186
0
{
2187
0
  return RecvSelectionEvent(aEvent);
2188
0
}
2189
2190
mozilla::ipc::IPCResult
2191
TabChild::RecvPasteTransferable(const IPCDataTransfer& aDataTransfer,
2192
                                const bool& aIsPrivateData,
2193
                                const IPC::Principal& aRequestingPrincipal,
2194
                                const uint32_t& aContentPolicyType)
2195
0
{
2196
0
  nsresult rv;
2197
0
  nsCOMPtr<nsITransferable> trans =
2198
0
    do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
2199
0
  NS_ENSURE_SUCCESS(rv, IPC_OK());
2200
0
  trans->Init(nullptr);
2201
0
2202
0
  rv = nsContentUtils::IPCTransferableToTransferable(aDataTransfer,
2203
0
                                                     aIsPrivateData,
2204
0
                                                     aRequestingPrincipal,
2205
0
                                                     aContentPolicyType,
2206
0
                                                     trans, nullptr, this);
2207
0
  NS_ENSURE_SUCCESS(rv, IPC_OK());
2208
0
2209
0
  nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
2210
0
  if (NS_WARN_IF(!ourDocShell)) {
2211
0
    return IPC_OK();
2212
0
  }
2213
0
2214
0
  RefPtr<nsCommandParams> params = new nsCommandParams();
2215
0
  rv = params->SetISupports("transferable", trans);
2216
0
  NS_ENSURE_SUCCESS(rv, IPC_OK());
2217
0
2218
0
  ourDocShell->DoCommandWithParams("cmd_pasteTransferable", params);
2219
0
  return IPC_OK();
2220
0
}
2221
2222
2223
a11y::PDocAccessibleChild*
2224
TabChild::AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&,
2225
                                   const uint32_t&, const IAccessibleHolder&)
2226
0
{
2227
0
  MOZ_ASSERT(false, "should never call this!");
2228
0
  return nullptr;
2229
0
}
2230
2231
bool
2232
TabChild::DeallocPDocAccessibleChild(a11y::PDocAccessibleChild* aChild)
2233
0
{
2234
0
#ifdef ACCESSIBILITY
2235
0
  delete static_cast<mozilla::a11y::DocAccessibleChild*>(aChild);
2236
0
#endif
2237
0
  return true;
2238
0
}
2239
2240
PColorPickerChild*
2241
TabChild::AllocPColorPickerChild(const nsString&, const nsString&)
2242
0
{
2243
0
  MOZ_CRASH("unused");
2244
0
  return nullptr;
2245
0
}
2246
2247
bool
2248
TabChild::DeallocPColorPickerChild(PColorPickerChild* aColorPicker)
2249
0
{
2250
0
  nsColorPickerProxy* picker = static_cast<nsColorPickerProxy*>(aColorPicker);
2251
0
  NS_RELEASE(picker);
2252
0
  return true;
2253
0
}
2254
2255
PFilePickerChild*
2256
TabChild::AllocPFilePickerChild(const nsString&, const int16_t&)
2257
0
{
2258
0
  MOZ_CRASH("unused");
2259
0
  return nullptr;
2260
0
}
2261
2262
bool
2263
TabChild::DeallocPFilePickerChild(PFilePickerChild* actor)
2264
0
{
2265
0
  nsFilePickerProxy* filePicker = static_cast<nsFilePickerProxy*>(actor);
2266
0
  NS_RELEASE(filePicker);
2267
0
  return true;
2268
0
}
2269
2270
auto
2271
TabChild::AllocPIndexedDBPermissionRequestChild(const Principal& aPrincipal)
2272
  -> PIndexedDBPermissionRequestChild*
2273
0
{
2274
0
  MOZ_CRASH("PIndexedDBPermissionRequestChild actors should always be created "
2275
0
            "manually!");
2276
0
}
2277
2278
bool
2279
TabChild::DeallocPIndexedDBPermissionRequestChild(
2280
                                       PIndexedDBPermissionRequestChild* aActor)
2281
0
{
2282
0
  MOZ_ASSERT(aActor);
2283
0
  delete aActor;
2284
0
  return true;
2285
0
}
2286
2287
mozilla::ipc::IPCResult
2288
TabChild::RecvActivateFrameEvent(const nsString& aType, const bool& capture)
2289
0
{
2290
0
  nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
2291
0
  NS_ENSURE_TRUE(window, IPC_OK());
2292
0
  nsCOMPtr<EventTarget> chromeHandler = window->GetChromeEventHandler();
2293
0
  NS_ENSURE_TRUE(chromeHandler, IPC_OK());
2294
0
  RefPtr<ContentListener> listener = new ContentListener(this);
2295
0
  chromeHandler->AddEventListener(aType, listener, capture);
2296
0
  return IPC_OK();
2297
0
}
2298
2299
// Return whether a remote script should be loaded in middleman processes in
2300
// addition to any child recording process they have.
2301
static bool
2302
LoadScriptInMiddleman(const nsString& aURL)
2303
0
{
2304
0
  return // Middleman processes run devtools server side scripts.
2305
0
         (StringBeginsWith(aURL, NS_LITERAL_STRING("resource://devtools/")) &&
2306
0
          recordreplay::parent::DebuggerRunsInMiddleman())
2307
0
         // This script includes event listeners needed to propagate document
2308
0
         // title changes.
2309
0
      || aURL.EqualsLiteral("chrome://global/content/browser-child.js")
2310
0
         // This script is needed to respond to session store requests from the
2311
0
         // UI process.
2312
0
      || aURL.EqualsLiteral("chrome://browser/content/content-sessionStore.js");
2313
0
}
2314
2315
mozilla::ipc::IPCResult
2316
TabChild::RecvLoadRemoteScript(const nsString& aURL, const bool& aRunInGlobalScope)
2317
0
{
2318
0
  if (!InitTabChildMessageManager())
2319
0
    // This can happen if we're half-destroyed.  It's not a fatal
2320
0
    // error.
2321
0
    return IPC_OK();
2322
0
2323
0
  JS::Rooted<JSObject*> mm(RootingCx(), mTabChildMessageManager->GetOrCreateWrapper());
2324
0
  if (!mm) {
2325
0
    // This can happen if we're half-destroyed.  It's not a fatal error.
2326
0
    return IPC_OK();
2327
0
  }
2328
0
2329
0
  // Make sure we only load whitelisted scripts in middleman processes.
2330
0
  if (recordreplay::IsMiddleman() && !LoadScriptInMiddleman(aURL)) {
2331
0
    return IPC_OK();
2332
0
  }
2333
0
2334
0
  LoadScriptInternal(mm, aURL, !aRunInGlobalScope);
2335
0
  return IPC_OK();
2336
0
}
2337
2338
mozilla::ipc::IPCResult
2339
TabChild::RecvAsyncMessage(const nsString& aMessage,
2340
                           InfallibleTArray<CpowEntry>&& aCpows,
2341
                           const IPC::Principal& aPrincipal,
2342
                           const ClonedMessageData& aData)
2343
0
{
2344
0
  AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
2345
0
    "TabChild::RecvAsyncMessage", OTHER, aMessage);
2346
0
2347
0
  CrossProcessCpowHolder cpows(Manager(), aCpows);
2348
0
  if (!mTabChildMessageManager) {
2349
0
    return IPC_OK();
2350
0
  }
2351
0
2352
0
  RefPtr<nsFrameMessageManager> mm = mTabChildMessageManager->GetMessageManager();
2353
0
2354
0
  // We should have a message manager if the global is alive, but it
2355
0
  // seems sometimes we don't.  Assert in aurora/nightly, but don't
2356
0
  // crash in release builds.
2357
0
  MOZ_DIAGNOSTIC_ASSERT(mm);
2358
0
  if (!mm) {
2359
0
    return IPC_OK();
2360
0
  }
2361
0
2362
0
  JS::Rooted<JSObject*> kungFuDeathGrip(dom::RootingCx(), mTabChildMessageManager->GetWrapper());
2363
0
  StructuredCloneData data;
2364
0
  UnpackClonedMessageDataForChild(aData, data);
2365
0
  mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildMessageManager), nullptr,
2366
0
                     aMessage, false, &data, &cpows, aPrincipal, nullptr,
2367
0
                     IgnoreErrors());
2368
0
  return IPC_OK();
2369
0
}
2370
2371
mozilla::ipc::IPCResult
2372
TabChild::RecvSwappedWithOtherRemoteLoader(const IPCTabContext& aContext)
2373
0
{
2374
0
  nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
2375
0
  if (NS_WARN_IF(!ourDocShell)) {
2376
0
    return IPC_OK();
2377
0
  }
2378
0
2379
0
  nsCOMPtr<nsPIDOMWindowOuter> ourWindow = ourDocShell->GetWindow();
2380
0
  if (NS_WARN_IF(!ourWindow)) {
2381
0
    return IPC_OK();
2382
0
  }
2383
0
2384
0
  RefPtr<nsDocShell> docShell = static_cast<nsDocShell*>(ourDocShell.get());
2385
0
2386
0
  nsCOMPtr<EventTarget> ourEventTarget = nsGlobalWindowOuter::Cast(ourWindow);
2387
0
2388
0
  docShell->SetInFrameSwap(true);
2389
0
2390
0
  nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, false, true);
2391
0
  nsContentUtils::FirePageHideEvent(ourDocShell, ourEventTarget, true);
2392
0
2393
0
  // Owner content type may have changed, so store the possibly updated context
2394
0
  // and notify others.
2395
0
  MaybeInvalidTabContext maybeContext(aContext);
2396
0
  if (!maybeContext.IsValid()) {
2397
0
    NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
2398
0
                             "the parent process. (%s)",
2399
0
                             maybeContext.GetInvalidReason()).get());
2400
0
    MOZ_CRASH("Invalid TabContext received from the parent process.");
2401
0
  }
2402
0
2403
0
  if (!UpdateTabContextAfterSwap(maybeContext.GetTabContext())) {
2404
0
    MOZ_CRASH("Update to TabContext after swap was denied.");
2405
0
  }
2406
0
2407
0
  // Since mIsMozBrowserElement may change in UpdateTabContextAfterSwap, so we
2408
0
  // call UpdateFrameType here to make sure the frameType on the docshell is
2409
0
  // correct.
2410
0
  UpdateFrameType();
2411
0
2412
0
  // Ignore previous value of mTriedBrowserInit since owner content has changed.
2413
0
  mTriedBrowserInit = true;
2414
0
  // Initialize the child side of the browser element machinery, if appropriate.
2415
0
  if (IsMozBrowser()) {
2416
0
    RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
2417
0
  }
2418
0
2419
0
  nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, true, true);
2420
0
2421
0
  docShell->SetInFrameSwap(false);
2422
0
2423
0
  return IPC_OK();
2424
0
}
2425
2426
mozilla::ipc::IPCResult
2427
TabChild::RecvHandleAccessKey(const WidgetKeyboardEvent& aEvent,
2428
                              nsTArray<uint32_t>&& aCharCodes)
2429
0
{
2430
0
  nsCOMPtr<nsIDocument> document(GetDocument());
2431
0
  RefPtr<nsPresContext> pc = document->GetPresContext();
2432
0
  if (pc) {
2433
0
    if (!pc->EventStateManager()->
2434
0
               HandleAccessKey(&(const_cast<WidgetKeyboardEvent&>(aEvent)),
2435
0
                               pc, aCharCodes)) {
2436
0
      // If no accesskey was found, inform the parent so that accesskeys on
2437
0
      // menus can be handled.
2438
0
      WidgetKeyboardEvent localEvent(aEvent);
2439
0
      localEvent.mWidget = mPuppetWidget;
2440
0
      SendAccessKeyNotHandled(localEvent);
2441
0
    }
2442
0
  }
2443
0
2444
0
  return IPC_OK();
2445
0
}
2446
2447
mozilla::ipc::IPCResult
2448
TabChild::RecvSetUseGlobalHistory(const bool& aUse)
2449
0
{
2450
0
  nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2451
0
  MOZ_ASSERT(docShell);
2452
0
2453
0
  nsresult rv = docShell->SetUseGlobalHistory(aUse);
2454
0
  if (NS_FAILED(rv)) {
2455
0
    NS_WARNING("Failed to set UseGlobalHistory on TabChild docShell");
2456
0
  }
2457
0
2458
0
  return IPC_OK();
2459
0
}
2460
2461
mozilla::ipc::IPCResult
2462
TabChild::RecvPrint(const uint64_t& aOuterWindowID, const PrintData& aPrintData)
2463
0
{
2464
0
#ifdef NS_PRINTING
2465
0
  nsGlobalWindowOuter* outerWindow =
2466
0
    nsGlobalWindowOuter::GetOuterWindowWithId(aOuterWindowID);
2467
0
  if (NS_WARN_IF(!outerWindow)) {
2468
0
    return IPC_OK();
2469
0
  }
2470
0
2471
0
  nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint =
2472
0
    do_GetInterface(outerWindow->AsOuter());
2473
0
  if (NS_WARN_IF(!webBrowserPrint)) {
2474
0
    return IPC_OK();
2475
0
  }
2476
0
2477
0
  nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
2478
0
    do_GetService("@mozilla.org/gfx/printsettings-service;1");
2479
0
  if (NS_WARN_IF(!printSettingsSvc)) {
2480
0
    return IPC_OK();
2481
0
  }
2482
0
2483
0
  nsCOMPtr<nsIPrintSettings> printSettings;
2484
0
  nsresult rv =
2485
0
    printSettingsSvc->GetNewPrintSettings(getter_AddRefs(printSettings));
2486
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
2487
0
    return IPC_OK();
2488
0
  }
2489
0
2490
0
  nsCOMPtr<nsIPrintSession>  printSession =
2491
0
    do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv);
2492
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
2493
0
    return IPC_OK();
2494
0
  }
2495
0
2496
0
  printSettings->SetPrintSession(printSession);
2497
0
  printSettingsSvc->DeserializeToPrintSettings(aPrintData, printSettings);
2498
0
  rv = webBrowserPrint->Print(printSettings, nullptr);
2499
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
2500
0
    return IPC_OK();
2501
0
  }
2502
0
2503
0
#endif
2504
0
  return IPC_OK();
2505
0
}
2506
2507
mozilla::ipc::IPCResult
2508
TabChild::RecvUpdateNativeWindowHandle(const uintptr_t& aNewHandle)
2509
0
{
2510
#if defined(XP_WIN) && defined(ACCESSIBILITY)
2511
  mNativeWindowHandle = aNewHandle;
2512
  return IPC_OK();
2513
#else
2514
0
  return IPC_FAIL_NO_REASON(this);
2515
0
#endif
2516
0
}
2517
2518
mozilla::ipc::IPCResult
2519
TabChild::RecvDestroy()
2520
0
{
2521
0
  MOZ_ASSERT(mDestroyed == false);
2522
0
  mDestroyed = true;
2523
0
2524
0
  nsTArray<PContentPermissionRequestChild*> childArray =
2525
0
      nsContentPermissionUtils::GetContentPermissionRequestChildById(GetTabId());
2526
0
2527
0
  // Need to close undeleted ContentPermissionRequestChilds before tab is closed.
2528
0
  for (auto& permissionRequestChild : childArray) {
2529
0
      auto child = static_cast<RemotePermissionRequest*>(permissionRequestChild);
2530
0
      child->Destroy();
2531
0
  }
2532
0
2533
0
  if (mTabChildMessageManager) {
2534
0
    // Message handlers are called from the event loop, so it better be safe to
2535
0
    // run script.
2536
0
    MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
2537
0
    mTabChildMessageManager->DispatchTrustedEvent(NS_LITERAL_STRING("unload"));
2538
0
  }
2539
0
2540
0
  nsCOMPtr<nsIObserverService> observerService =
2541
0
    mozilla::services::GetObserverService();
2542
0
2543
0
  observerService->RemoveObserver(this, BEFORE_FIRST_PAINT);
2544
0
2545
0
  // XXX what other code in ~TabChild() should we be running here?
2546
0
  DestroyWindow();
2547
0
2548
0
  // Bounce through the event loop once to allow any delayed teardown runnables
2549
0
  // that were just generated to have a chance to run.
2550
0
  nsCOMPtr<nsIRunnable> deleteRunnable = new DelayedDeleteRunnable(this);
2551
0
  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(deleteRunnable));
2552
0
2553
0
  return IPC_OK();
2554
0
}
2555
2556
void
2557
TabChild::AddPendingDocShellBlocker()
2558
0
{
2559
0
  mPendingDocShellBlockers++;
2560
0
}
2561
2562
void
2563
TabChild::RemovePendingDocShellBlocker()
2564
0
{
2565
0
  mPendingDocShellBlockers--;
2566
0
  if (!mPendingDocShellBlockers && mPendingDocShellReceivedMessage) {
2567
0
    mPendingDocShellReceivedMessage = false;
2568
0
    InternalSetDocShellIsActive(mPendingDocShellIsActive);
2569
0
  }
2570
0
  if (!mPendingDocShellBlockers && mPendingRenderLayersReceivedMessage) {
2571
0
    mPendingRenderLayersReceivedMessage = false;
2572
0
    RecvRenderLayers(mPendingRenderLayers,
2573
0
                     false /* aForceRepaint */,
2574
0
                     mPendingLayersObserverEpoch);
2575
0
  }
2576
0
}
2577
2578
void
2579
TabChild::InternalSetDocShellIsActive(bool aIsActive)
2580
0
{
2581
0
  nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2582
0
2583
0
  if (docShell) {
2584
0
    docShell->SetIsActive(aIsActive);
2585
0
  }
2586
0
}
2587
2588
mozilla::ipc::IPCResult
2589
TabChild::RecvSetDocShellIsActive(const bool& aIsActive)
2590
0
{
2591
0
  // If we're currently waiting for window opening to complete, we need to hold
2592
0
  // off on setting the docshell active. We queue up the values we're receiving
2593
0
  // in the mWindowOpenDocShellActiveStatus.
2594
0
  if (mPendingDocShellBlockers > 0) {
2595
0
    mPendingDocShellReceivedMessage = true;
2596
0
    mPendingDocShellIsActive = aIsActive;
2597
0
    return IPC_OK();
2598
0
  }
2599
0
2600
0
  InternalSetDocShellIsActive(aIsActive);
2601
0
  return IPC_OK();
2602
0
}
2603
2604
mozilla::ipc::IPCResult
2605
TabChild::RecvRenderLayers(const bool& aEnabled, const bool& aForceRepaint, const layers::LayersObserverEpoch& aEpoch)
2606
0
{
2607
0
  if (mPendingDocShellBlockers > 0) {
2608
0
    mPendingRenderLayersReceivedMessage = true;
2609
0
    mPendingRenderLayers = aEnabled;
2610
0
    mPendingLayersObserverEpoch = aEpoch;
2611
0
    return IPC_OK();
2612
0
  }
2613
0
2614
0
  // Since requests to change the rendering state come in from both the hang
2615
0
  // monitor channel and the PContent channel, we have an ordering problem. This
2616
0
  // code ensures that we respect the order in which the requests were made and
2617
0
  // ignore stale requests.
2618
0
  if (mLayersObserverEpoch >= aEpoch) {
2619
0
    return IPC_OK();
2620
0
  }
2621
0
  mLayersObserverEpoch = aEpoch;
2622
0
2623
0
  auto clearPaintWhileInterruptingJS = MakeScopeExit([&] {
2624
0
    // We might force a paint, or we might already have painted and this is a
2625
0
    // no-op. In either case, once we exit this scope, we need to alert the
2626
0
    // ProcessHangMonitor that we've finished responding to what might have
2627
0
    // been a request to force paint. This is so that the BackgroundHangMonitor
2628
0
    // for force painting can be made to wait again.
2629
0
    if (aEnabled) {
2630
0
      ProcessHangMonitor::ClearPaintWhileInterruptingJS(mLayersObserverEpoch);
2631
0
    }
2632
0
  });
2633
0
2634
0
  if (aEnabled) {
2635
0
    ProcessHangMonitor::MaybeStartPaintWhileInterruptingJS();
2636
0
  }
2637
0
2638
0
  if (mCompositorOptions) {
2639
0
    MOZ_ASSERT(mPuppetWidget);
2640
0
    RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
2641
0
    MOZ_ASSERT(lm);
2642
0
2643
0
    // We send the current layer observer epoch to the compositor so that
2644
0
    // TabParent knows whether a layer update notification corresponds to the
2645
0
    // latest RecvRenderLayers request that was made.
2646
0
    lm->SetLayersObserverEpoch(mLayersObserverEpoch);
2647
0
  }
2648
0
2649
0
  if (aEnabled) {
2650
0
    if (!aForceRepaint && IsVisible()) {
2651
0
      // This request is a no-op. In this case, we still want a MozLayerTreeReady
2652
0
      // notification to fire in the parent (so that it knows that the child has
2653
0
      // updated its epoch). PaintWhileInterruptingJSNoOp does that.
2654
0
      if (IPCOpen()) {
2655
0
        Unused << SendPaintWhileInterruptingJSNoOp(mLayersObserverEpoch);
2656
0
        return IPC_OK();
2657
0
      }
2658
0
    }
2659
0
2660
0
    if (!sVisibleTabs) {
2661
0
      sVisibleTabs = new nsTHashtable<nsPtrHashKey<TabChild>>();
2662
0
    }
2663
0
    sVisibleTabs->PutEntry(this);
2664
0
2665
0
    MakeVisible();
2666
0
2667
0
    nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2668
0
    if (!docShell) {
2669
0
      return IPC_OK();
2670
0
    }
2671
0
2672
0
    // We don't use TabChildBase::GetPresShell() here because that would create
2673
0
    // a content viewer if one doesn't exist yet. Creating a content viewer can
2674
0
    // cause JS to run, which we want to avoid. nsIDocShell::GetPresShell
2675
0
    // returns null if no content viewer exists yet.
2676
0
    if (nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell()) {
2677
0
      presShell->SetIsActive(true);
2678
0
2679
0
      if (nsIFrame* root = presShell->GetRootFrame()) {
2680
0
        FrameLayerBuilder::InvalidateAllLayersForFrame(
2681
0
          nsLayoutUtils::GetDisplayRootFrame(root));
2682
0
        root->SchedulePaint();
2683
0
      }
2684
0
2685
0
      Telemetry::AutoTimer<Telemetry::TABCHILD_PAINT_TIME> timer;
2686
0
      // If we need to repaint, let's do that right away. No sense waiting until
2687
0
      // we get back to the event loop again. We suppress the display port so that
2688
0
      // we only paint what's visible. This ensures that the tab we're switching
2689
0
      // to paints as quickly as possible.
2690
0
      presShell->SuppressDisplayport(true);
2691
0
      if (nsContentUtils::IsSafeToRunScript()) {
2692
0
        WebWidget()->PaintNowIfNeeded();
2693
0
      } else {
2694
0
        RefPtr<nsViewManager> vm = presShell->GetViewManager();
2695
0
        if (nsView* view = vm->GetRootView()) {
2696
0
          presShell->Paint(view, view->GetBounds(),
2697
0
                           nsIPresShell::PAINT_LAYERS);
2698
0
        }
2699
0
      }
2700
0
      presShell->SuppressDisplayport(false);
2701
0
    }
2702
0
  } else {
2703
0
    if (sVisibleTabs) {
2704
0
      sVisibleTabs->RemoveEntry(this);
2705
0
      // We don't delete sVisibleTabs here when it's empty since that
2706
0
      // could cause a lot of churn. Instead, we wait until ~TabChild.
2707
0
    }
2708
0
2709
0
    MakeHidden();
2710
0
  }
2711
0
2712
0
  return IPC_OK();
2713
0
}
2714
2715
mozilla::ipc::IPCResult
2716
TabChild::RecvNavigateByKey(const bool& aForward, const bool& aForDocumentNavigation)
2717
0
{
2718
0
  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2719
0
  if (fm) {
2720
0
    RefPtr<Element> result;
2721
0
    nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
2722
0
2723
0
    // Move to the first or last document.
2724
0
    uint32_t type = aForward ?
2725
0
      (aForDocumentNavigation ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FIRSTDOC) :
2726
0
                                static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_ROOT)) :
2727
0
      (aForDocumentNavigation ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LASTDOC) :
2728
0
                                static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_LAST));
2729
0
    fm->MoveFocus(window, nullptr, type,
2730
0
                  nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
2731
0
2732
0
    // No valid root element was found, so move to the first focusable element.
2733
0
    if (!result && aForward && !aForDocumentNavigation) {
2734
0
      fm->MoveFocus(window, nullptr, nsIFocusManager::MOVEFOCUS_FIRST,
2735
0
                  nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
2736
0
    }
2737
0
2738
0
    SendRequestFocus(false);
2739
0
  }
2740
0
2741
0
  return IPC_OK();
2742
0
}
2743
2744
mozilla::ipc::IPCResult
2745
TabChild::RecvHandledWindowedPluginKeyEvent(
2746
            const NativeEventData& aKeyEventData,
2747
            const bool& aIsConsumed)
2748
0
{
2749
0
  if (NS_WARN_IF(!mPuppetWidget)) {
2750
0
    return IPC_OK();
2751
0
  }
2752
0
  mPuppetWidget->HandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
2753
0
  return IPC_OK();
2754
0
}
2755
2756
PRenderFrameChild*
2757
TabChild::AllocPRenderFrameChild()
2758
0
{
2759
0
    return new RenderFrameChild();
2760
0
}
2761
2762
bool
2763
TabChild::DeallocPRenderFrameChild(PRenderFrameChild* aFrame)
2764
0
{
2765
0
    delete aFrame;
2766
0
    return true;
2767
0
}
2768
2769
bool
2770
TabChild::InitTabChildMessageManager()
2771
0
{
2772
0
  if (!mTabChildMessageManager) {
2773
0
    nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
2774
0
    NS_ENSURE_TRUE(window, false);
2775
0
    nsCOMPtr<EventTarget> chromeHandler = window->GetChromeEventHandler();
2776
0
    NS_ENSURE_TRUE(chromeHandler, false);
2777
0
2778
0
    RefPtr<TabChildMessageManager> scope = mTabChildMessageManager = new TabChildMessageManager(this);
2779
0
2780
0
    MOZ_ALWAYS_TRUE(nsMessageManagerScriptExecutor::Init());
2781
0
2782
0
    nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
2783
0
    if (NS_WARN_IF(!root)) {
2784
0
        mTabChildMessageManager = nullptr;
2785
0
        return false;
2786
0
    }
2787
0
    root->SetParentTarget(scope);
2788
0
  }
2789
0
2790
0
  if (!mTriedBrowserInit) {
2791
0
    mTriedBrowserInit = true;
2792
0
    // Initialize the child side of the browser element machinery,
2793
0
    // if appropriate.
2794
0
    if (IsMozBrowser()) {
2795
0
      RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
2796
0
    }
2797
0
  }
2798
0
2799
0
  return true;
2800
0
}
2801
2802
void
2803
TabChild::InitRenderingState(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
2804
                             const layers::LayersId& aLayersId,
2805
                             const CompositorOptions& aCompositorOptions,
2806
                             PRenderFrameChild* aRenderFrame)
2807
0
{
2808
0
    mPuppetWidget->InitIMEState();
2809
0
2810
0
    if (!aRenderFrame) {
2811
0
      mLayersConnected = Some(false);
2812
0
      NS_WARNING("failed to construct RenderFrame");
2813
0
      return;
2814
0
    }
2815
0
2816
0
    MOZ_ASSERT(aLayersId.IsValid());
2817
0
    mTextureFactoryIdentifier = aTextureFactoryIdentifier;
2818
0
2819
0
    // Pushing layers transactions directly to a separate
2820
0
    // compositor context.
2821
0
    PCompositorBridgeChild* compositorChild = CompositorBridgeChild::Get();
2822
0
    if (!compositorChild) {
2823
0
      mLayersConnected = Some(false);
2824
0
      NS_WARNING("failed to get CompositorBridgeChild instance");
2825
0
      return;
2826
0
    }
2827
0
2828
0
    mCompositorOptions = Some(aCompositorOptions);
2829
0
2830
0
    mRemoteFrame = static_cast<RenderFrameChild*>(aRenderFrame);
2831
0
    if (aLayersId.IsValid()) {
2832
0
      StaticMutexAutoLock lock(sTabChildrenMutex);
2833
0
2834
0
      if (!sTabChildren) {
2835
0
        sTabChildren = new TabChildMap;
2836
0
      }
2837
0
      MOZ_ASSERT(!sTabChildren->Get(uint64_t(aLayersId)));
2838
0
      sTabChildren->Put(uint64_t(aLayersId), this);
2839
0
      mLayersId = aLayersId;
2840
0
    }
2841
0
2842
0
    MOZ_ASSERT(!mPuppetWidget->HasLayerManager());
2843
0
    bool success = false;
2844
0
    if (mLayersConnected == Some(true)) {
2845
0
      success = CreateRemoteLayerManager(compositorChild);
2846
0
    }
2847
0
2848
0
    if (success) {
2849
0
      MOZ_ASSERT(mLayersConnected == Some(true));
2850
0
      // Succeeded to create "remote" layer manager
2851
0
      ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
2852
0
      gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
2853
0
      InitAPZState();
2854
0
      RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
2855
0
      MOZ_ASSERT(lm);
2856
0
      lm->SetLayersObserverEpoch(mLayersObserverEpoch);
2857
0
    } else {
2858
0
      NS_WARNING("Fallback to BasicLayerManager");
2859
0
      mLayersConnected = Some(false);
2860
0
    }
2861
0
2862
0
    nsCOMPtr<nsIObserverService> observerService =
2863
0
        mozilla::services::GetObserverService();
2864
0
2865
0
    if (observerService) {
2866
0
        observerService->AddObserver(this,
2867
0
                                     BEFORE_FIRST_PAINT,
2868
0
                                     false);
2869
0
    }
2870
0
}
2871
2872
bool
2873
TabChild::CreateRemoteLayerManager(mozilla::layers::PCompositorBridgeChild* aCompositorChild)
2874
0
{
2875
0
  MOZ_ASSERT(aCompositorChild);
2876
0
2877
0
  bool success = false;
2878
0
  if (mCompositorOptions->UseWebRender()) {
2879
0
    success = mPuppetWidget->CreateRemoteLayerManager([&] (LayerManager* aLayerManager) -> bool {
2880
0
      MOZ_ASSERT(aLayerManager->AsWebRenderLayerManager());
2881
0
      return aLayerManager->AsWebRenderLayerManager()->Initialize(aCompositorChild,
2882
0
                                                                  wr::AsPipelineId(mLayersId),
2883
0
                                                                  &mTextureFactoryIdentifier);
2884
0
    });
2885
0
  } else {
2886
0
    nsTArray<LayersBackend> ignored;
2887
0
    PLayerTransactionChild* shadowManager = aCompositorChild->SendPLayerTransactionConstructor(ignored, GetLayersId());
2888
0
    if (shadowManager &&
2889
0
        shadowManager->SendGetTextureFactoryIdentifier(&mTextureFactoryIdentifier) &&
2890
0
        mTextureFactoryIdentifier.mParentBackend != LayersBackend::LAYERS_NONE)
2891
0
    {
2892
0
      success = true;
2893
0
    }
2894
0
    if (!success) {
2895
0
      // Since no LayerManager is associated with the tab's widget, we will never
2896
0
      // have an opportunity to destroy the PLayerTransaction on the next device
2897
0
      // or compositor reset. Therefore, we make sure to forcefully close it here.
2898
0
      // Failure to do so will cause the next layer tree to fail to attach due
2899
0
      // since the compositor requires the old layer tree to be disassociated.
2900
0
      if (shadowManager) {
2901
0
        static_cast<LayerTransactionChild*>(shadowManager)->Destroy();
2902
0
        shadowManager = nullptr;
2903
0
      }
2904
0
      NS_WARNING("failed to allocate layer transaction");
2905
0
    } else {
2906
0
      success = mPuppetWidget->CreateRemoteLayerManager([&] (LayerManager* aLayerManager) -> bool {
2907
0
        ShadowLayerForwarder* lf = aLayerManager->AsShadowForwarder();
2908
0
        lf->SetShadowManager(shadowManager);
2909
0
        lf->IdentifyTextureHost(mTextureFactoryIdentifier);
2910
0
        return true;
2911
0
      });
2912
0
    }
2913
0
  }
2914
0
  return success;
2915
0
}
2916
2917
void
2918
TabChild::InitAPZState()
2919
0
{
2920
0
  if (!mCompositorOptions->UseAPZ()) {
2921
0
    return;
2922
0
  }
2923
0
  auto cbc = CompositorBridgeChild::Get();
2924
0
2925
0
  // Initialize the ApzcTreeManager. This takes multiple casts because of ugly multiple inheritance.
2926
0
  PAPZCTreeManagerChild* baseProtocol = cbc->SendPAPZCTreeManagerConstructor(mLayersId);
2927
0
  APZCTreeManagerChild* derivedProtocol = static_cast<APZCTreeManagerChild*>(baseProtocol);
2928
0
2929
0
  mApzcTreeManager = RefPtr<IAPZCTreeManager>(derivedProtocol);
2930
0
2931
0
  // Initialize the GeckoContentController for this tab. We don't hold a reference because we don't need it.
2932
0
  // The ContentProcessController will hold a reference to the tab, and will be destroyed by the compositor or ipdl
2933
0
  // during destruction.
2934
0
  RefPtr<GeckoContentController> contentController = new ContentProcessController(this);
2935
0
  APZChild* apzChild = new APZChild(contentController);
2936
0
  cbc->SetEventTargetForActor(
2937
0
    apzChild, TabGroup()->EventTargetFor(TaskCategory::Other));
2938
0
  MOZ_ASSERT(apzChild->GetActorEventTarget());
2939
0
  cbc->SendPAPZConstructor(apzChild, mLayersId);
2940
0
}
2941
2942
void
2943
TabChild::NotifyPainted()
2944
0
{
2945
0
    if (!mNotified) {
2946
0
        // Recording/replaying processes have a compositor but not a remote frame.
2947
0
        if (!recordreplay::IsRecordingOrReplaying()) {
2948
0
            mRemoteFrame->SendNotifyCompositorTransaction();
2949
0
        }
2950
0
        mNotified = true;
2951
0
    }
2952
0
}
2953
2954
void
2955
TabChild::MakeVisible()
2956
0
{
2957
0
  if (IsVisible()) {
2958
0
    return;
2959
0
  }
2960
0
2961
0
  if (mPuppetWidget) {
2962
0
    mPuppetWidget->Show(true);
2963
0
  }
2964
0
}
2965
2966
void
2967
TabChild::MakeHidden()
2968
0
{
2969
0
  if (!IsVisible()) {
2970
0
    return;
2971
0
  }
2972
0
2973
0
  // Due to the nested event loop in ContentChild::ProvideWindowCommon,
2974
0
  // it's possible to be told to become hidden before we're finished
2975
0
  // setting up a layer manager. We should skip clearing cached layers
2976
0
  // in that case, since doing so might accidentally put is into
2977
0
  // BasicLayers mode.
2978
0
  if (mPuppetWidget && mPuppetWidget->HasLayerManager()) {
2979
0
    ClearCachedResources();
2980
0
  }
2981
0
2982
0
  nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
2983
0
  if (docShell) {
2984
0
    // Hide all plugins in this tab. We don't use TabChildBase::GetPresShell()
2985
0
    // here because that would create a content viewer if one doesn't exist yet.
2986
0
    // Creating a content viewer can cause JS to run, which we want to avoid.
2987
0
    // nsIDocShell::GetPresShell returns null if no content viewer exists yet.
2988
0
    if (nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell()) {
2989
0
      if (nsPresContext* presContext = presShell->GetPresContext()) {
2990
0
        nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
2991
0
        nsIFrame* rootFrame = presShell->GetRootFrame();
2992
0
        rootPresContext->ComputePluginGeometryUpdates(rootFrame, nullptr, nullptr);
2993
0
        rootPresContext->ApplyPluginGeometryUpdates();
2994
0
      }
2995
0
      presShell->SetIsActive(false);
2996
0
    }
2997
0
  }
2998
0
2999
0
  if (mPuppetWidget) {
3000
0
    mPuppetWidget->Show(false);
3001
0
  }
3002
0
}
3003
3004
bool
3005
TabChild::IsVisible()
3006
0
{
3007
0
  return mPuppetWidget && mPuppetWidget->IsVisible();
3008
0
}
3009
3010
NS_IMETHODIMP
3011
TabChild::GetMessageManager(ContentFrameMessageManager** aResult)
3012
0
{
3013
0
  RefPtr<ContentFrameMessageManager> mm(mTabChildMessageManager);
3014
0
  mm.forget(aResult);
3015
0
  return *aResult ? NS_OK : NS_ERROR_FAILURE;
3016
0
}
3017
3018
NS_IMETHODIMP
3019
TabChild::GetWebBrowserChrome(nsIWebBrowserChrome3** aWebBrowserChrome)
3020
0
{
3021
0
  NS_IF_ADDREF(*aWebBrowserChrome = mWebBrowserChrome);
3022
0
  return NS_OK;
3023
0
}
3024
3025
NS_IMETHODIMP
3026
TabChild::SetWebBrowserChrome(nsIWebBrowserChrome3* aWebBrowserChrome)
3027
0
{
3028
0
  mWebBrowserChrome = aWebBrowserChrome;
3029
0
  return NS_OK;
3030
0
}
3031
3032
void
3033
TabChild::SendRequestFocus(bool aCanFocus)
3034
0
{
3035
0
  PBrowserChild::SendRequestFocus(aCanFocus);
3036
0
}
3037
3038
void
3039
TabChild::EnableDisableCommands(const nsAString& aAction,
3040
                                nsTArray<nsCString>& aEnabledCommands,
3041
                                nsTArray<nsCString>& aDisabledCommands)
3042
0
{
3043
0
  PBrowserChild::SendEnableDisableCommands(PromiseFlatString(aAction),
3044
0
                                           aEnabledCommands, aDisabledCommands);
3045
0
}
3046
3047
NS_IMETHODIMP
3048
TabChild::GetTabId(uint64_t* aId)
3049
0
{
3050
0
  *aId = GetTabId();
3051
0
  return NS_OK;
3052
0
}
3053
3054
void
3055
TabChild::SetTabId(const TabId& aTabId)
3056
0
{
3057
0
  MOZ_ASSERT(mUniqueId == 0);
3058
0
3059
0
  mUniqueId = aTabId;
3060
0
  NestedTabChildMap()[mUniqueId] = this;
3061
0
}
3062
3063
bool
3064
TabChild::DoSendBlockingMessage(JSContext* aCx,
3065
                                const nsAString& aMessage,
3066
                                StructuredCloneData& aData,
3067
                                JS::Handle<JSObject *> aCpows,
3068
                                nsIPrincipal* aPrincipal,
3069
                                nsTArray<StructuredCloneData>* aRetVal,
3070
                                bool aIsSync)
3071
0
{
3072
0
  ClonedMessageData data;
3073
0
  if (!BuildClonedMessageDataForChild(Manager(), aData, data)) {
3074
0
    return false;
3075
0
  }
3076
0
  InfallibleTArray<CpowEntry> cpows;
3077
0
  if (aCpows) {
3078
0
    jsipc::CPOWManager* mgr = Manager()->GetCPOWManager();
3079
0
    if (!mgr || !mgr->Wrap(aCx, aCpows, &cpows)) {
3080
0
      return false;
3081
0
    }
3082
0
  }
3083
0
  if (aIsSync) {
3084
0
    return SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
3085
0
                           Principal(aPrincipal), aRetVal);
3086
0
  }
3087
0
3088
0
  return SendRpcMessage(PromiseFlatString(aMessage), data, cpows,
3089
0
                        Principal(aPrincipal), aRetVal);
3090
0
}
3091
3092
nsresult
3093
TabChild::DoSendAsyncMessage(JSContext* aCx,
3094
                             const nsAString& aMessage,
3095
                             StructuredCloneData& aData,
3096
                             JS::Handle<JSObject *> aCpows,
3097
                             nsIPrincipal* aPrincipal)
3098
0
{
3099
0
  ClonedMessageData data;
3100
0
  if (!BuildClonedMessageDataForChild(Manager(), aData, data)) {
3101
0
    return NS_ERROR_DOM_DATA_CLONE_ERR;
3102
0
  }
3103
0
  InfallibleTArray<CpowEntry> cpows;
3104
0
  if (aCpows) {
3105
0
    jsipc::CPOWManager* mgr = Manager()->GetCPOWManager();
3106
0
    if (!mgr || !mgr->Wrap(aCx, aCpows, &cpows)) {
3107
0
      return NS_ERROR_UNEXPECTED;
3108
0
    }
3109
0
  }
3110
0
  if (!SendAsyncMessage(PromiseFlatString(aMessage), cpows,
3111
0
                        Principal(aPrincipal), data)) {
3112
0
    return NS_ERROR_UNEXPECTED;
3113
0
  }
3114
0
  return NS_OK;
3115
0
}
3116
3117
/* static */ nsTArray<RefPtr<TabChild>>
3118
TabChild::GetAll()
3119
0
{
3120
0
  StaticMutexAutoLock lock(sTabChildrenMutex);
3121
0
3122
0
  nsTArray<RefPtr<TabChild>> list;
3123
0
  if (!sTabChildren) {
3124
0
    return list;
3125
0
  }
3126
0
3127
0
  for (auto iter = sTabChildren->Iter(); !iter.Done(); iter.Next()) {
3128
0
    list.AppendElement(iter.Data());
3129
0
  }
3130
0
3131
0
  return list;
3132
0
}
3133
3134
TabChild*
3135
TabChild::GetFrom(nsIPresShell* aPresShell)
3136
0
{
3137
0
  nsIDocument* doc = aPresShell->GetDocument();
3138
0
  if (!doc) {
3139
0
      return nullptr;
3140
0
  }
3141
0
  nsCOMPtr<nsIDocShell> docShell(doc->GetDocShell());
3142
0
  return GetFrom(docShell);
3143
0
}
3144
3145
TabChild*
3146
TabChild::GetFrom(layers::LayersId aLayersId)
3147
0
{
3148
0
  StaticMutexAutoLock lock(sTabChildrenMutex);
3149
0
  if (!sTabChildren) {
3150
0
    return nullptr;
3151
0
  }
3152
0
  return sTabChildren->Get(uint64_t(aLayersId));
3153
0
}
3154
3155
void
3156
TabChild::DidComposite(mozilla::layers::TransactionId aTransactionId,
3157
                       const TimeStamp& aCompositeStart,
3158
                       const TimeStamp& aCompositeEnd)
3159
0
{
3160
0
  MOZ_ASSERT(mPuppetWidget);
3161
0
  RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
3162
0
  MOZ_ASSERT(lm);
3163
0
3164
0
  lm->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
3165
0
}
3166
3167
void
3168
TabChild::DidRequestComposite(const TimeStamp& aCompositeReqStart,
3169
                              const TimeStamp& aCompositeReqEnd)
3170
0
{
3171
0
  nsCOMPtr<nsIDocShell> docShellComPtr = do_GetInterface(WebNavigation());
3172
0
  if (!docShellComPtr) {
3173
0
    return;
3174
0
  }
3175
0
3176
0
  nsDocShell* docShell = static_cast<nsDocShell*>(docShellComPtr.get());
3177
0
  RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
3178
0
3179
0
  if (timelines && timelines->HasConsumer(docShell)) {
3180
0
    // Since we're assuming that it's impossible for content JS to directly
3181
0
    // trigger a synchronous paint, we can avoid capturing a stack trace here,
3182
0
    // which means we won't run into JS engine reentrancy issues like bug
3183
0
    // 1310014.
3184
0
    timelines->AddMarkerForDocShell(docShell,
3185
0
      "CompositeForwardTransaction", aCompositeReqStart,
3186
0
      MarkerTracingType::START, MarkerStackRequest::NO_STACK);
3187
0
    timelines->AddMarkerForDocShell(docShell,
3188
0
      "CompositeForwardTransaction", aCompositeReqEnd,
3189
0
      MarkerTracingType::END, MarkerStackRequest::NO_STACK);
3190
0
  }
3191
0
}
3192
3193
void
3194
TabChild::ClearCachedResources()
3195
0
{
3196
0
  MOZ_ASSERT(mPuppetWidget);
3197
0
  RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
3198
0
  MOZ_ASSERT(lm);
3199
0
3200
0
  lm->ClearCachedResources();
3201
0
}
3202
3203
void
3204
TabChild::InvalidateLayers()
3205
0
{
3206
0
  MOZ_ASSERT(mPuppetWidget);
3207
0
  RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
3208
0
  MOZ_ASSERT(lm);
3209
0
3210
0
  FrameLayerBuilder::InvalidateAllLayers(lm);
3211
0
}
3212
3213
void
3214
TabChild::ReinitRendering()
3215
0
{
3216
0
  MOZ_ASSERT(mLayersId.IsValid());
3217
0
3218
0
  // Before we establish a new PLayerTransaction, we must connect our layer tree
3219
0
  // id, CompositorBridge, and the widget compositor all together again.
3220
0
  // Normally this happens in TabParent before TabChild is given rendering
3221
0
  // information.
3222
0
  //
3223
0
  // In this case, we will send a sync message to our TabParent, which in turn
3224
0
  // will send a sync message to the Compositor of the widget owning this tab.
3225
0
  // This guarantees the correct association is in place before our
3226
0
  // PLayerTransaction constructor message arrives on the cross-process
3227
0
  // compositor bridge.
3228
0
  CompositorOptions options;
3229
0
  SendEnsureLayersConnected(&options);
3230
0
  mCompositorOptions = Some(options);
3231
0
3232
0
  bool success = false;
3233
0
  RefPtr<CompositorBridgeChild> cb = CompositorBridgeChild::Get();
3234
0
3235
0
  if (cb) {
3236
0
    success = CreateRemoteLayerManager(cb);
3237
0
  }
3238
0
3239
0
  if (!success) {
3240
0
    NS_WARNING("failed to recreate layer manager");
3241
0
    return;
3242
0
  }
3243
0
3244
0
  mLayersConnected = Some(true);
3245
0
  ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
3246
0
  gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
3247
0
3248
0
  InitAPZState();
3249
0
  RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
3250
0
  MOZ_ASSERT(lm);
3251
0
  lm->SetLayersObserverEpoch(mLayersObserverEpoch);
3252
0
3253
0
  nsCOMPtr<nsIDocument> doc(GetDocument());
3254
0
  doc->NotifyLayerManagerRecreated();
3255
0
}
3256
3257
void
3258
TabChild::ReinitRenderingForDeviceReset()
3259
0
{
3260
0
  InvalidateLayers();
3261
0
3262
0
  RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
3263
0
  if (WebRenderLayerManager* wlm = lm->AsWebRenderLayerManager()) {
3264
0
    wlm->DoDestroy(/* aIsSync */ true);
3265
0
  } else if (ClientLayerManager* clm = lm->AsClientLayerManager()) {
3266
0
    if (ShadowLayerForwarder* fwd = clm->AsShadowForwarder()) {
3267
0
      // Force the LayerTransactionChild to synchronously shutdown. It is
3268
0
      // okay to do this early, we'll simply stop sending messages. This
3269
0
      // step is necessary since otherwise the compositor will think we
3270
0
      // are trying to attach two layer trees to the same ID.
3271
0
      fwd->SynchronouslyShutdown();
3272
0
    }
3273
0
  } else {
3274
0
    if (mLayersConnected.isNothing()) {
3275
0
      return;
3276
0
    }
3277
0
  }
3278
0
3279
0
  // Proceed with destroying and recreating the layer manager.
3280
0
  ReinitRendering();
3281
0
}
3282
3283
NS_IMETHODIMP
3284
TabChild::OnShowTooltip(int32_t aXCoords, int32_t aYCoords, const char16_t *aTipText,
3285
                        const char16_t *aTipDir)
3286
0
{
3287
0
    nsString str(aTipText);
3288
0
    nsString dir(aTipDir);
3289
0
    SendShowTooltip(aXCoords, aYCoords, str, dir);
3290
0
    return NS_OK;
3291
0
}
3292
3293
NS_IMETHODIMP
3294
TabChild::OnHideTooltip()
3295
0
{
3296
0
    SendHideTooltip();
3297
0
    return NS_OK;
3298
0
}
3299
3300
mozilla::ipc::IPCResult
3301
TabChild::RecvRequestNotifyAfterRemotePaint()
3302
0
{
3303
0
  // Get the CompositorBridgeChild instance for this content thread.
3304
0
  CompositorBridgeChild* compositor = CompositorBridgeChild::Get();
3305
0
3306
0
  // Tell the CompositorBridgeChild that, when it gets a RemotePaintIsReady
3307
0
  // message that it should forward it us so that we can bounce it to our
3308
0
  // RenderFrameParent.
3309
0
  compositor->RequestNotifyAfterRemotePaint(this);
3310
0
  return IPC_OK();
3311
0
}
3312
3313
mozilla::ipc::IPCResult
3314
TabChild::RecvUIResolutionChanged(const float& aDpi,
3315
                                  const int32_t& aRounding,
3316
                                  const double& aScale)
3317
0
{
3318
0
  ScreenIntSize oldScreenSize = GetInnerSize();
3319
0
  if (aDpi > 0) {
3320
0
    mPuppetWidget->UpdateBackingScaleCache(aDpi, aRounding, aScale);
3321
0
  }
3322
0
  nsCOMPtr<nsIDocument> document(GetDocument());
3323
0
  RefPtr<nsPresContext> presContext = document->GetPresContext();
3324
0
  if (presContext) {
3325
0
    presContext->UIResolutionChangedSync();
3326
0
  }
3327
0
3328
0
  ScreenIntSize screenSize = GetInnerSize();
3329
0
  if (mHasValidInnerSize && oldScreenSize != screenSize) {
3330
0
    ScreenIntRect screenRect = GetOuterRect();
3331
0
    mPuppetWidget->Resize(screenRect.x + mClientOffset.x + mChromeOffset.x,
3332
0
                          screenRect.y + mClientOffset.y + mChromeOffset.y,
3333
0
                          screenSize.width, screenSize.height, true);
3334
0
3335
0
    nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
3336
0
    baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height,
3337
0
                                nsIBaseWindow::eRepaint);
3338
0
  }
3339
0
3340
0
  return IPC_OK();
3341
0
}
3342
3343
mozilla::ipc::IPCResult
3344
TabChild::RecvThemeChanged(nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache)
3345
0
{
3346
0
  LookAndFeel::SetIntCache(aLookAndFeelIntCache);
3347
0
  nsCOMPtr<nsIDocument> document(GetDocument());
3348
0
  RefPtr<nsPresContext> presContext = document->GetPresContext();
3349
0
  if (presContext) {
3350
0
    presContext->ThemeChanged();
3351
0
  }
3352
0
  return IPC_OK();
3353
0
}
3354
3355
mozilla::ipc::IPCResult
3356
TabChild::RecvAwaitLargeAlloc()
3357
0
{
3358
0
  mAwaitingLA = true;
3359
0
  return IPC_OK();
3360
0
}
3361
3362
bool
3363
TabChild::IsAwaitingLargeAlloc()
3364
0
{
3365
0
  return mAwaitingLA;
3366
0
}
3367
3368
bool
3369
TabChild::StopAwaitingLargeAlloc()
3370
0
{
3371
0
  bool awaiting = mAwaitingLA;
3372
0
  mAwaitingLA = false;
3373
0
  return awaiting;
3374
0
}
3375
3376
mozilla::ipc::IPCResult
3377
TabChild::RecvSetWindowName(const nsString& aName)
3378
0
{
3379
0
  nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(WebNavigation());
3380
0
  if (item) {
3381
0
    item->SetName(aName);
3382
0
  }
3383
0
  return IPC_OK();
3384
0
}
3385
3386
mozilla::ipc::IPCResult
3387
TabChild::RecvAllowScriptsToClose()
3388
0
{
3389
0
  nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
3390
0
  if (window) {
3391
0
    nsGlobalWindowOuter::Cast(window)->AllowScriptsToClose();
3392
0
  }
3393
0
  return IPC_OK();
3394
0
}
3395
3396
mozilla::ipc::IPCResult
3397
TabChild::RecvSetOriginAttributes(const OriginAttributes& aOriginAttributes)
3398
0
{
3399
0
  nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
3400
0
  nsDocShell::Cast(docShell)->SetOriginAttributes(aOriginAttributes);
3401
0
3402
0
  return IPC_OK();
3403
0
}
3404
3405
mozilla::ipc::IPCResult
3406
TabChild::RecvSetWidgetNativeData(const WindowsHandle& aWidgetNativeData)
3407
0
{
3408
0
  mWidgetNativeData = aWidgetNativeData;
3409
0
  return IPC_OK();
3410
0
}
3411
3412
mozilla::plugins::PPluginWidgetChild*
3413
TabChild::AllocPPluginWidgetChild()
3414
0
{
3415
#ifdef XP_WIN
3416
  return new mozilla::plugins::PluginWidgetChild();
3417
#else
3418
0
  MOZ_ASSERT_UNREACHABLE("AllocPPluginWidgetChild only supports Windows");
3419
0
  return nullptr;
3420
0
#endif
3421
0
}
3422
3423
bool
3424
TabChild::DeallocPPluginWidgetChild(mozilla::plugins::PPluginWidgetChild* aActor)
3425
0
{
3426
0
  delete aActor;
3427
0
  return true;
3428
0
}
3429
3430
#ifdef XP_WIN
3431
nsresult
3432
TabChild::CreatePluginWidget(nsIWidget* aParent, nsIWidget** aOut)
3433
{
3434
  *aOut = nullptr;
3435
  mozilla::plugins::PluginWidgetChild* child =
3436
    static_cast<mozilla::plugins::PluginWidgetChild*>(SendPPluginWidgetConstructor());
3437
  if (!child) {
3438
    NS_ERROR("couldn't create PluginWidgetChild");
3439
    return NS_ERROR_UNEXPECTED;
3440
  }
3441
  nsCOMPtr<nsIWidget> pluginWidget = nsIWidget::CreatePluginProxyWidget(this, child);
3442
  if (!pluginWidget) {
3443
    NS_ERROR("couldn't create PluginWidgetProxy");
3444
    return NS_ERROR_UNEXPECTED;
3445
  }
3446
3447
  nsWidgetInitData initData;
3448
  initData.mWindowType = eWindowType_plugin_ipc_content;
3449
  initData.mUnicode = false;
3450
  initData.clipChildren = true;
3451
  initData.clipSiblings = true;
3452
  nsresult rv = pluginWidget->Create(aParent, nullptr,
3453
                                     LayoutDeviceIntRect(0, 0, 0, 0),
3454
                                     &initData);
3455
  if (NS_FAILED(rv)) {
3456
    NS_WARNING("Creating native plugin widget on the chrome side failed.");
3457
  }
3458
  pluginWidget.forget(aOut);
3459
  return rv;
3460
}
3461
#endif // XP_WIN
3462
3463
PPaymentRequestChild*
3464
TabChild::AllocPPaymentRequestChild()
3465
0
{
3466
0
  MOZ_CRASH("We should never be manually allocating PPaymentRequestChild actors");
3467
0
  return nullptr;
3468
0
}
3469
3470
bool
3471
TabChild::DeallocPPaymentRequestChild(PPaymentRequestChild* actor)
3472
0
{
3473
0
  delete actor;
3474
0
  return true;
3475
0
}
3476
3477
ScreenIntSize
3478
TabChild::GetInnerSize()
3479
0
{
3480
0
  LayoutDeviceIntSize innerSize =
3481
0
    RoundedToInt(mUnscaledInnerSize * mPuppetWidget->GetDefaultScale());
3482
0
  return ViewAs<ScreenPixel>(innerSize, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
3483
0
};
3484
3485
ScreenIntRect
3486
TabChild::GetOuterRect()
3487
0
{
3488
0
  LayoutDeviceIntRect outerRect =
3489
0
    RoundedToInt(mUnscaledOuterRect * mPuppetWidget->GetDefaultScale());
3490
0
  return ViewAs<ScreenPixel>(outerRect, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
3491
0
}
3492
3493
void
3494
TabChild::PaintWhileInterruptingJS(const layers::LayersObserverEpoch& aEpoch,
3495
                                   bool aForceRepaint)
3496
0
{
3497
0
  if (!IPCOpen() || !mPuppetWidget || !mPuppetWidget->HasLayerManager()) {
3498
0
    // Don't bother doing anything now. Better to wait until we receive the
3499
0
    // message on the PContent channel.
3500
0
    return;
3501
0
  }
3502
0
3503
0
  nsAutoScriptBlocker scriptBlocker;
3504
0
  RecvRenderLayers(true /* aEnabled */, aForceRepaint, aEpoch);
3505
0
}
3506
3507
void
3508
TabChild::BeforeUnloadAdded()
3509
0
{
3510
0
  // Don't bother notifying the parent if we don't have an IPC link open.
3511
0
  if (mBeforeUnloadListeners == 0 && IPCOpen()) {
3512
0
    SendSetHasBeforeUnload(true);
3513
0
  }
3514
0
3515
0
  mBeforeUnloadListeners++;
3516
0
  MOZ_ASSERT(mBeforeUnloadListeners >= 0);
3517
0
}
3518
3519
void
3520
TabChild::BeforeUnloadRemoved()
3521
0
{
3522
0
  mBeforeUnloadListeners--;
3523
0
  MOZ_ASSERT(mBeforeUnloadListeners >= 0);
3524
0
3525
0
  // Don't bother notifying the parent if we don't have an IPC link open.
3526
0
  if (mBeforeUnloadListeners == 0 && IPCOpen()) {
3527
0
    SendSetHasBeforeUnload(false);
3528
0
  }
3529
0
}
3530
3531
mozilla::dom::TabGroup*
3532
TabChild::TabGroup()
3533
0
{
3534
0
  return mTabGroup;
3535
0
}
3536
3537
nsresult
3538
TabChild::GetHasSiblings(bool* aHasSiblings)
3539
0
{
3540
0
  *aHasSiblings = mHasSiblings;
3541
0
  return NS_OK;
3542
0
}
3543
3544
nsresult
3545
TabChild::SetHasSiblings(bool aHasSiblings)
3546
0
{
3547
0
  mHasSiblings = aHasSiblings;
3548
0
  return NS_OK;
3549
0
}
3550
3551
TabChildMessageManager::TabChildMessageManager(TabChild* aTabChild)
3552
: ContentFrameMessageManager(new nsFrameMessageManager(aTabChild)),
3553
  mTabChild(aTabChild)
3554
0
{
3555
0
}
3556
3557
TabChildMessageManager::~TabChildMessageManager()
3558
0
{
3559
0
}
3560
3561
NS_IMPL_CYCLE_COLLECTION_CLASS(TabChildMessageManager)
3562
3563
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TabChildMessageManager,
3564
0
                                                DOMEventTargetHelper)
3565
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager);
3566
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChild);
3567
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
3568
3569
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TabChildMessageManager,
3570
0
                                                  DOMEventTargetHelper)
3571
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
3572
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChild)
3573
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
3574
3575
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TabChildMessageManager)
3576
0
  NS_INTERFACE_MAP_ENTRY(nsIMessageSender)
3577
0
  NS_INTERFACE_MAP_ENTRY(ContentFrameMessageManager)
3578
0
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
3579
0
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
3580
3581
NS_IMPL_ADDREF_INHERITED(TabChildMessageManager, DOMEventTargetHelper)
3582
NS_IMPL_RELEASE_INHERITED(TabChildMessageManager, DOMEventTargetHelper)
3583
3584
JSObject*
3585
TabChildMessageManager::WrapObject(JSContext* aCx,
3586
                                   JS::Handle<JSObject*> aGivenProto)
3587
0
{
3588
0
  return ContentFrameMessageManager_Binding::Wrap(aCx, this, aGivenProto);
3589
0
}
3590
3591
void
3592
TabChildMessageManager::MarkForCC()
3593
0
{
3594
0
  if (mTabChild) {
3595
0
    mTabChild->MarkScopesForCC();
3596
0
  }
3597
0
  EventListenerManager* elm = GetExistingListenerManager();
3598
0
  if (elm) {
3599
0
    elm->MarkForCC();
3600
0
  }
3601
0
  MessageManagerGlobal::MarkForCC();
3602
0
}
3603
3604
already_AddRefed<nsPIDOMWindowOuter>
3605
TabChildMessageManager::GetContent(ErrorResult& aError)
3606
0
{
3607
0
  if (!mTabChild) {
3608
0
    aError.Throw(NS_ERROR_NULL_POINTER);
3609
0
    return nullptr;
3610
0
  }
3611
0
  nsCOMPtr<nsPIDOMWindowOuter> window =
3612
0
    do_GetInterface(mTabChild->WebNavigation());
3613
0
  return window.forget();
3614
0
}
3615
3616
already_AddRefed<nsIDocShell>
3617
TabChildMessageManager::GetDocShell(ErrorResult& aError)
3618
0
{
3619
0
  if (!mTabChild) {
3620
0
    aError.Throw(NS_ERROR_NULL_POINTER);
3621
0
    return nullptr;
3622
0
  }
3623
0
  nsCOMPtr<nsIDocShell> window = do_GetInterface(mTabChild->WebNavigation());
3624
0
  return window.forget();
3625
0
}
3626
3627
already_AddRefed<nsIEventTarget>
3628
TabChildMessageManager::GetTabEventTarget()
3629
0
{
3630
0
  nsCOMPtr<nsIEventTarget> target = EventTargetFor(TaskCategory::Other);
3631
0
  return target.forget();
3632
0
}
3633
3634
uint64_t
3635
TabChildMessageManager::ChromeOuterWindowID()
3636
0
{
3637
0
  if (!mTabChild) {
3638
0
    return 0;
3639
0
  }
3640
0
  return mTabChild->ChromeOuterWindowID();
3641
0
}
3642
3643
nsresult
3644
TabChildMessageManager::Dispatch(TaskCategory aCategory,
3645
                         already_AddRefed<nsIRunnable>&& aRunnable)
3646
0
{
3647
0
  if (mTabChild && mTabChild->TabGroup()) {
3648
0
    return mTabChild->TabGroup()->Dispatch(aCategory, std::move(aRunnable));
3649
0
  }
3650
0
  return DispatcherTrait::Dispatch(aCategory, std::move(aRunnable));
3651
0
}
3652
3653
nsISerialEventTarget*
3654
TabChildMessageManager::EventTargetFor(TaskCategory aCategory) const
3655
0
{
3656
0
  if (mTabChild && mTabChild->TabGroup()) {
3657
0
    return mTabChild->TabGroup()->EventTargetFor(aCategory);
3658
0
  }
3659
0
  return DispatcherTrait::EventTargetFor(aCategory);
3660
0
}
3661
3662
AbstractThread*
3663
TabChildMessageManager::AbstractMainThreadFor(TaskCategory aCategory)
3664
0
{
3665
0
  if (mTabChild && mTabChild->TabGroup()) {
3666
0
    return mTabChild->TabGroup()->AbstractMainThreadFor(aCategory);
3667
0
  }
3668
0
  return DispatcherTrait::AbstractMainThreadFor(aCategory);
3669
0
}