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 #ifndef mozilla_layers_APZCCallbackHelper_h
7 #define mozilla_layers_APZCCallbackHelper_h
8 
9 #include "FrameMetrics.h"
10 #include "InputData.h"
11 #include "mozilla/EventForwards.h"
12 #include "mozilla/Function.h"
13 #include "mozilla/layers/APZUtils.h"
14 #include "nsIDOMWindowUtils.h"
15 
16 class nsIContent;
17 class nsIDocument;
18 class nsIPresShell;
19 class nsIScrollableFrame;
20 class nsIWidget;
21 template<class T> struct already_AddRefed;
22 template<class T> class nsCOMPtr;
23 
24 namespace mozilla {
25 namespace layers {
26 
27 typedef function<void(uint64_t, const nsTArray<TouchBehaviorFlags>&)>
28         SetAllowedTouchBehaviorCallback;
29 
30 /* This class contains some helper methods that facilitate implementing the
31    GeckoContentController callback interface required by the AsyncPanZoomController.
32    Since different platforms need to implement this interface in similar-but-
33    not-quite-the-same ways, this utility class provides some helpful methods
34    to hold code that can be shared across the different platform implementations.
35  */
36 class APZCCallbackHelper
37 {
38     typedef mozilla::layers::FrameMetrics FrameMetrics;
39     typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
40 
41 public:
42     /* Applies the scroll and zoom parameters from the given FrameMetrics object
43        to the root frame for the given metrics' scrollId. If tiled thebes layers
44        are enabled, this will align the displayport to tile boundaries. Setting
45        the scroll position can cause some small adjustments to be made to the
46        actual scroll position. aMetrics' display port and scroll position will
47        be updated with any modifications made. */
48     static void UpdateRootFrame(FrameMetrics& aMetrics);
49 
50     /* Applies the scroll parameters from the given FrameMetrics object to the
51        subframe corresponding to given metrics' scrollId. If tiled thebes
52        layers are enabled, this will align the displayport to tile boundaries.
53        Setting the scroll position can cause some small adjustments to be made
54        to the actual scroll position. aMetrics' display port and scroll position
55        will be updated with any modifications made. */
56     static void UpdateSubFrame(FrameMetrics& aMetrics);
57 
58     /* Get the presShellId and view ID for the given content element.
59      * If the view ID does not exist, one is created.
60      * The pres shell ID should generally already exist; if it doesn't for some
61      * reason, false is returned. */
62     static bool GetOrCreateScrollIdentifiers(nsIContent* aContent,
63                                              uint32_t* aPresShellIdOut,
64                                              FrameMetrics::ViewID* aViewIdOut);
65 
66     /* Initialize a zero-margin displayport on the root document element of the
67        given presShell. */
68     static void InitializeRootDisplayport(nsIPresShell* aPresShell);
69 
70     /* Get the pres context associated with the document enclosing |aContent|. */
71     static nsPresContext* GetPresContextForContent(nsIContent* aContent);
72 
73     /* Get the pres shell associated with the root content document enclosing |aContent|. */
74     static nsIPresShell* GetRootContentDocumentPresShellForContent(nsIContent* aContent);
75 
76     /* Apply an "input transform" to the given |aInput| and return the transformed value.
77        The input transform applied is the one for the content element corresponding to
78        |aGuid|; this is populated in a previous call to UpdateCallbackTransform. See that
79        method's documentations for details.
80        This method additionally adjusts |aInput| by inversely scaling by the provided
81        pres shell resolution, to cancel out a compositor-side transform (added in
82        bug 1076241) that APZ doesn't unapply. */
83     static CSSPoint ApplyCallbackTransform(const CSSPoint& aInput,
84                                            const ScrollableLayerGuid& aGuid);
85 
86     /* Same as above, but operates on LayoutDeviceIntPoint.
87        Requires an additonal |aScale| parameter to convert between CSS and
88        LayoutDevice space. */
89     static mozilla::LayoutDeviceIntPoint
90     ApplyCallbackTransform(const LayoutDeviceIntPoint& aPoint,
91                            const ScrollableLayerGuid& aGuid,
92                            const CSSToLayoutDeviceScale& aScale);
93 
94     /* Convenience function for applying a callback transform to all refpoints
95      * in the input event. */
96     static void ApplyCallbackTransform(WidgetEvent& aEvent,
97                                        const ScrollableLayerGuid& aGuid,
98                                        const CSSToLayoutDeviceScale& aScale);
99 
100     /* Dispatch a widget event via the widget stored in the event, if any.
101      * In a child process, allows the TabParent event-capture mechanism to
102      * intercept the event. */
103     static nsEventStatus DispatchWidgetEvent(WidgetGUIEvent& aEvent);
104 
105     /* Synthesize a mouse event with the given parameters, and dispatch it
106      * via the given widget. */
107     static nsEventStatus DispatchSynthesizedMouseEvent(EventMessage aMsg,
108                                                        uint64_t aTime,
109                                                        const LayoutDevicePoint& aRefPoint,
110                                                        Modifiers aModifiers,
111                                                        int32_t aClickCount,
112                                                        nsIWidget* aWidget);
113 
114     /* Dispatch a mouse event with the given parameters.
115      * Return whether or not any listeners have called preventDefault on the event. */
116     static bool DispatchMouseEvent(const nsCOMPtr<nsIPresShell>& aPresShell,
117                                    const nsString& aType,
118                                    const CSSPoint& aPoint,
119                                    int32_t aButton,
120                                    int32_t aClickCount,
121                                    int32_t aModifiers,
122                                    bool aIgnoreRootScrollFrame,
123                                    unsigned short aInputSourceArg);
124 
125     /* Fire a single-tap event at the given point. The event is dispatched
126      * via the given widget. */
127     static void FireSingleTapEvent(const LayoutDevicePoint& aPoint,
128                                    Modifiers aModifiers,
129                                    int32_t aClickCount,
130                                    nsIWidget* aWidget);
131 
132     /* Perform hit-testing on the touch points of |aEvent| to determine
133      * which scrollable frames they target. If any of these frames don't have
134      * a displayport, set one.
135      *
136      * If any displayports need to be set, the actual notification to APZ is
137      * sent to the compositor, which will then post a message back to APZ's
138      * controller thread. Otherwise, the provided widget's SetConfirmedTargetAPZC
139      * method is invoked immediately.
140      */
141     static void SendSetTargetAPZCNotification(nsIWidget* aWidget,
142                                               nsIDocument* aDocument,
143                                               const WidgetGUIEvent& aEvent,
144                                               const ScrollableLayerGuid& aGuid,
145                                               uint64_t aInputBlockId);
146 
147     /* Figure out the allowed touch behaviors of each touch point in |aEvent|
148      * and send that information to the provided callback. */
149     static void SendSetAllowedTouchBehaviorNotification(nsIWidget* aWidget,
150                                                         nsIDocument* aDocument,
151                                                         const WidgetTouchEvent& aEvent,
152                                                         uint64_t aInputBlockId,
153                                                         const SetAllowedTouchBehaviorCallback& aCallback);
154 
155     /* Notify content of a mouse scroll testing event. */
156     static void NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent);
157 
158     /* Notify content that the repaint flush is complete. */
159     static void NotifyFlushComplete(nsIPresShell* aShell);
160 
161     /* Temporarily ignore the Displayport for better paint performance. If at
162      * all possible, pass in a presShell if you have one at the call site, we
163      * use it to trigger a repaint once suppression is disabled. Without that
164      * the displayport may get left at the suppressed size for an extended
165      * period of time and result in unnecessary checkerboarding (see bug
166      * 1255054). */
167     static void SuppressDisplayport(const bool& aEnabled,
168                                     const nsCOMPtr<nsIPresShell>& aShell);
169 
170     /* Whether or not displayport suppression should be turned on. Note that
171      * this only affects the return value of |IsDisplayportSuppressed()|, and
172      * doesn't change the value of the internal counter. As with
173      * SuppressDisplayport, this function should be passed a presShell to trigger
174      * a repaint if suppression is being turned off.
175      */
176     static void RespectDisplayPortSuppression(bool aEnabled,
177                                               const nsCOMPtr<nsIPresShell>& aShell);
178 
179     /* Whether or not the displayport is currently suppressed. */
180     static bool IsDisplayportSuppressed();
181 
182     static void
183     AdjustDisplayPortForScrollDelta(mozilla::layers::FrameMetrics& aFrameMetrics,
184                                     const CSSPoint& aActualScrollOffset);
185 
186     /*
187      * Check if the scrollable frame is currently in the middle of an async
188      * or smooth scroll. We want to discard certain scroll input if this is
189      * true to prevent clobbering higher priority origins.
190      */
191     static bool
192     IsScrollInProgress(nsIScrollableFrame* aFrame);
193 
194     /* Notify content of the progress of a pinch gesture that APZ won't do
195      * zooming for (because the apz.allow_zooming pref is false). This function
196      * will dispatch appropriate WidgetSimpleGestureEvent events to gecko.
197      */
198     static void NotifyPinchGesture(PinchGestureInput::PinchGestureType aType,
199                                    LayoutDeviceCoord aSpanChange,
200                                    Modifiers aModifiers,
201                                    nsIWidget* aWidget);
202 private:
203   static uint64_t sLastTargetAPZCNotificationInputBlock;
204 };
205 
206 } // namespace layers
207 } // namespace mozilla
208 
209 #endif /* mozilla_layers_APZCCallbackHelper_h */
210