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