Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/apz/util/ChromeProcessController.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 "ChromeProcessController.h"
8
9
#include "MainThreadUtils.h"    // for NS_IsMainThread()
10
#include "base/message_loop.h"  // for MessageLoop
11
#include "mozilla/dom/Element.h"
12
#include "mozilla/layers/CompositorBridgeParent.h"
13
#include "mozilla/layers/APZCCallbackHelper.h"
14
#include "mozilla/layers/APZEventState.h"
15
#include "mozilla/layers/APZThreadUtils.h"
16
#include "mozilla/layers/IAPZCTreeManager.h"
17
#include "mozilla/layers/DoubleTapToZoom.h"
18
#include "nsIDocument.h"
19
#include "nsIInterfaceRequestorUtils.h"
20
#include "nsIPresShell.h"
21
#include "nsLayoutUtils.h"
22
#include "nsView.h"
23
24
using namespace mozilla;
25
using namespace mozilla::layers;
26
using namespace mozilla::widget;
27
28
ChromeProcessController::ChromeProcessController(nsIWidget* aWidget,
29
                                                 APZEventState* aAPZEventState,
30
                                                 IAPZCTreeManager* aAPZCTreeManager)
31
  : mWidget(aWidget)
32
  , mAPZEventState(aAPZEventState)
33
  , mAPZCTreeManager(aAPZCTreeManager)
34
  , mUILoop(MessageLoop::current())
35
0
{
36
0
  // Otherwise we're initializing mUILoop incorrectly.
37
0
  MOZ_ASSERT(NS_IsMainThread());
38
0
  MOZ_ASSERT(aAPZEventState);
39
0
  MOZ_ASSERT(aAPZCTreeManager);
40
0
41
0
  mUILoop->PostTask(
42
0
    NewRunnableMethod("layers::ChromeProcessController::InitializeRoot",
43
0
                      this,
44
0
                      &ChromeProcessController::InitializeRoot));
45
0
}
46
47
0
ChromeProcessController::~ChromeProcessController() {}
48
49
void
50
ChromeProcessController::InitializeRoot()
51
0
{
52
0
  APZCCallbackHelper::InitializeRootDisplayport(GetPresShell());
53
0
}
54
55
void
56
ChromeProcessController::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
57
0
{
58
0
  MOZ_ASSERT(IsRepaintThread());
59
0
60
0
  FrameMetrics metrics = aFrameMetrics;
61
0
  if (metrics.IsRootContent()) {
62
0
    APZCCallbackHelper::UpdateRootFrame(metrics);
63
0
  } else {
64
0
    APZCCallbackHelper::UpdateSubFrame(metrics);
65
0
  }
66
0
}
67
68
void
69
ChromeProcessController::PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs)
70
0
{
71
0
  MessageLoop::current()->PostDelayedTask(std::move(aTask), aDelayMs);
72
0
}
73
74
bool
75
ChromeProcessController::IsRepaintThread()
76
0
{
77
0
  return NS_IsMainThread();
78
0
}
79
80
void
81
ChromeProcessController::DispatchToRepaintThread(already_AddRefed<Runnable> aTask)
82
0
{
83
0
  NS_DispatchToMainThread(std::move(aTask));
84
0
}
85
86
void
87
ChromeProcessController::Destroy()
88
0
{
89
0
  if (MessageLoop::current() != mUILoop) {
90
0
    mUILoop->PostTask(
91
0
      NewRunnableMethod("layers::ChromeProcessController::Destroy",
92
0
                        this,
93
0
                        &ChromeProcessController::Destroy));
94
0
    return;
95
0
  }
96
0
97
0
  MOZ_ASSERT(MessageLoop::current() == mUILoop);
98
0
  mWidget = nullptr;
99
0
  mAPZEventState = nullptr;
100
0
}
101
102
nsIPresShell*
103
ChromeProcessController::GetPresShell() const
104
0
{
105
0
  if (!mWidget) {
106
0
    return nullptr;
107
0
  }
108
0
  if (nsView* view = nsView::GetViewFor(mWidget)) {
109
0
    return view->GetPresShell();
110
0
  }
111
0
  return nullptr;
112
0
}
113
114
nsIDocument*
115
ChromeProcessController::GetRootDocument() const
116
0
{
117
0
  if (nsIPresShell* presShell = GetPresShell()) {
118
0
    return presShell->GetDocument();
119
0
  }
120
0
  return nullptr;
121
0
}
122
123
nsIDocument*
124
ChromeProcessController::GetRootContentDocument(const FrameMetrics::ViewID& aScrollId) const
125
0
{
126
0
  nsIContent* content = nsLayoutUtils::FindContentFor(aScrollId);
127
0
  if (!content) {
128
0
    return nullptr;
129
0
  }
130
0
  nsIPresShell* presShell = APZCCallbackHelper::GetRootContentDocumentPresShellForContent(content);
131
0
  if (presShell) {
132
0
    return presShell->GetDocument();
133
0
  }
134
0
  return nullptr;
135
0
}
136
137
void
138
ChromeProcessController::HandleDoubleTap(const mozilla::CSSPoint& aPoint,
139
                                         Modifiers aModifiers,
140
                                         const ScrollableLayerGuid& aGuid)
141
0
{
142
0
  MOZ_ASSERT(MessageLoop::current() == mUILoop);
143
0
144
0
  nsCOMPtr<nsIDocument> document = GetRootContentDocument(aGuid.mScrollId);
145
0
  if (!document.get()) {
146
0
    return;
147
0
  }
148
0
149
0
  // CalculateRectToZoomTo performs a hit test on the frame associated with the
150
0
  // Root Content Document. Unfortunately that frame does not know about the
151
0
  // resolution of the document and so we must remove it before calculating
152
0
  // the zoomToRect.
153
0
  nsIPresShell* presShell = document->GetShell();
154
0
  const float resolution = presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f;
155
0
  CSSPoint point(aPoint.x / resolution, aPoint.y / resolution);
156
0
  CSSRect zoomToRect = CalculateRectToZoomTo(document, point);
157
0
158
0
  uint32_t presShellId;
159
0
  FrameMetrics::ViewID viewId;
160
0
  if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(
161
0
      document->GetDocumentElement(), &presShellId, &viewId)) {
162
0
    APZThreadUtils::RunOnControllerThread(
163
0
      NewRunnableMethod<ScrollableLayerGuid, CSSRect, uint32_t>(
164
0
        "IAPZCTreeManager::ZoomToRect",
165
0
        mAPZCTreeManager,
166
0
        &IAPZCTreeManager::ZoomToRect,
167
0
        ScrollableLayerGuid(aGuid.mLayersId, presShellId, viewId),
168
0
        zoomToRect,
169
0
        ZoomToRectBehavior::DEFAULT_BEHAVIOR));
170
0
  }
171
0
}
172
173
void
174
ChromeProcessController::HandleTap(TapType aType,
175
                                   const mozilla::LayoutDevicePoint& aPoint,
176
                                   Modifiers aModifiers,
177
                                   const ScrollableLayerGuid& aGuid,
178
                                   uint64_t aInputBlockId)
179
0
{
180
0
  if (MessageLoop::current() != mUILoop) {
181
0
    mUILoop->PostTask(
182
0
      NewRunnableMethod<TapType,
183
0
                        mozilla::LayoutDevicePoint,
184
0
                        Modifiers,
185
0
                        ScrollableLayerGuid,
186
0
                        uint64_t>("layers::ChromeProcessController::HandleTap",
187
0
                                  this,
188
0
                                  &ChromeProcessController::HandleTap,
189
0
                                  aType,
190
0
                                  aPoint,
191
0
                                  aModifiers,
192
0
                                  aGuid,
193
0
                                  aInputBlockId));
194
0
    return;
195
0
  }
196
0
197
0
  if (!mAPZEventState) {
198
0
    return;
199
0
  }
200
0
201
0
  nsCOMPtr<nsIPresShell> presShell = GetPresShell();
202
0
  if (!presShell) {
203
0
    return;
204
0
  }
205
0
  if (!presShell->GetPresContext()) {
206
0
    return;
207
0
  }
208
0
  CSSToLayoutDeviceScale scale(presShell->GetPresContext()->CSSToDevPixelScale());
209
0
  CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint / scale, aGuid);
210
0
211
0
  switch (aType) {
212
0
  case TapType::eSingleTap:
213
0
    mAPZEventState->ProcessSingleTap(point, scale, aModifiers, aGuid, 1);
214
0
    break;
215
0
  case TapType::eDoubleTap:
216
0
    HandleDoubleTap(point, aModifiers, aGuid);
217
0
    break;
218
0
  case TapType::eSecondTap:
219
0
    mAPZEventState->ProcessSingleTap(point, scale, aModifiers, aGuid, 2);
220
0
    break;
221
0
  case TapType::eLongTap:
222
0
    mAPZEventState->ProcessLongTap(presShell, point, scale, aModifiers, aGuid,
223
0
        aInputBlockId);
224
0
    break;
225
0
  case TapType::eLongTapUp:
226
0
    mAPZEventState->ProcessLongTapUp(presShell, point, scale, aModifiers);
227
0
    break;
228
0
  }
229
0
}
230
231
void
232
ChromeProcessController::NotifyPinchGesture(PinchGestureInput::PinchGestureType aType,
233
                                            const ScrollableLayerGuid& aGuid,
234
                                            LayoutDeviceCoord aSpanChange,
235
                                            Modifiers aModifiers)
236
0
{
237
0
  if (MessageLoop::current() != mUILoop) {
238
0
    mUILoop->PostTask(NewRunnableMethod<PinchGestureInput::PinchGestureType,
239
0
                                        ScrollableLayerGuid,
240
0
                                        LayoutDeviceCoord,
241
0
                                        Modifiers>(
242
0
      "layers::ChromeProcessController::NotifyPinchGesture",
243
0
      this,
244
0
      &ChromeProcessController::NotifyPinchGesture,
245
0
      aType,
246
0
      aGuid,
247
0
      aSpanChange,
248
0
      aModifiers));
249
0
    return;
250
0
  }
251
0
252
0
  if (mWidget) {
253
0
    APZCCallbackHelper::NotifyPinchGesture(aType, aSpanChange, aModifiers, mWidget.get());
254
0
  }
255
0
}
256
257
void
258
ChromeProcessController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
259
                                              APZStateChange aChange,
260
                                              int aArg)
261
0
{
262
0
  if (MessageLoop::current() != mUILoop) {
263
0
    mUILoop->PostTask(
264
0
      NewRunnableMethod<ScrollableLayerGuid, APZStateChange, int>(
265
0
        "layers::ChromeProcessController::NotifyAPZStateChange",
266
0
        this,
267
0
        &ChromeProcessController::NotifyAPZStateChange,
268
0
        aGuid,
269
0
        aChange,
270
0
        aArg));
271
0
    return;
272
0
  }
273
0
274
0
  if (!mAPZEventState) {
275
0
    return;
276
0
  }
277
0
278
0
  mAPZEventState->ProcessAPZStateChange(aGuid.mScrollId, aChange, aArg);
279
0
}
280
281
void
282
ChromeProcessController::NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent)
283
0
{
284
0
  if (MessageLoop::current() != mUILoop) {
285
0
    mUILoop->PostTask(NewRunnableMethod<FrameMetrics::ViewID, nsString>(
286
0
      "layers::ChromeProcessController::NotifyMozMouseScrollEvent",
287
0
      this,
288
0
      &ChromeProcessController::NotifyMozMouseScrollEvent,
289
0
      aScrollId,
290
0
      aEvent));
291
0
    return;
292
0
  }
293
0
294
0
  APZCCallbackHelper::NotifyMozMouseScrollEvent(aScrollId, aEvent);
295
0
}
296
297
void
298
ChromeProcessController::NotifyFlushComplete()
299
0
{
300
0
  MOZ_ASSERT(IsRepaintThread());
301
0
302
0
  APZCCallbackHelper::NotifyFlushComplete(GetPresShell());
303
0
}
304
305
void
306
ChromeProcessController::NotifyAsyncScrollbarDragRejected(const FrameMetrics::ViewID& aScrollId)
307
0
{
308
0
  if (MessageLoop::current() != mUILoop) {
309
0
    mUILoop->PostTask(NewRunnableMethod<FrameMetrics::ViewID>(
310
0
      "layers::ChromeProcessController::NotifyAsyncScrollbarDragRejected",
311
0
      this,
312
0
      &ChromeProcessController::NotifyAsyncScrollbarDragRejected,
313
0
      aScrollId));
314
0
    return;
315
0
  }
316
0
317
0
  APZCCallbackHelper::NotifyAsyncScrollbarDragRejected(aScrollId);
318
0
}
319
320
void
321
ChromeProcessController::NotifyAsyncAutoscrollRejected(const FrameMetrics::ViewID& aScrollId)
322
0
{
323
0
  if (MessageLoop::current() != mUILoop) {
324
0
    mUILoop->PostTask(NewRunnableMethod<FrameMetrics::ViewID>(
325
0
      "layers::ChromeProcessController::NotifyAsyncAutoscrollRejected",
326
0
      this,
327
0
      &ChromeProcessController::NotifyAsyncAutoscrollRejected,
328
0
      aScrollId));
329
0
    return;
330
0
  }
331
0
332
0
  APZCCallbackHelper::NotifyAsyncAutoscrollRejected(aScrollId);
333
0
}
334
335
void
336
ChromeProcessController::CancelAutoscroll(const ScrollableLayerGuid& aGuid)
337
0
{
338
0
  if (MessageLoop::current() != mUILoop) {
339
0
    mUILoop->PostTask(NewRunnableMethod<ScrollableLayerGuid>(
340
0
      "layers::ChromeProcessController::CancelAutoscroll",
341
0
      this,
342
0
      &ChromeProcessController::CancelAutoscroll,
343
0
      aGuid));
344
0
    return;
345
0
  }
346
0
347
0
  APZCCallbackHelper::CancelAutoscroll(aGuid.mScrollId);
348
0
}