1/*
2 * Copyright (C) 2004-2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "FloatPoint.h"
29#include "IntPoint.h"
30#include "PlatformEvent.h"
31#include <wtf/WindowsExtras.h>
32
33#if PLATFORM(GTK)
34typedef struct _GdkEventScroll GdkEventScroll;
35#endif
36
37namespace WebCore {
38
39// The ScrollByPixelWheelEvent is a fine-grained event that specifies the precise number of pixels to scroll.
40// It is sent directly by touch pads on macOS, or synthesized when platforms generate line-by-line scrolling events.
41//
42// The ScrollByPageWheelEvent indicates that the wheel event should scroll an entire page.
43// In this case, WebKit built in paging behavior is used to page up and down.
44// This yields the same behavior as clicking in a scrollbar track to page up and down.
45
46enum PlatformWheelEventGranularity : uint8_t {
47 ScrollByPageWheelEvent,
48 ScrollByPixelWheelEvent,
49};
50
51#if ENABLE(ASYNC_SCROLLING)
52
53enum PlatformWheelEventPhase : uint8_t {
54 PlatformWheelEventPhaseNone = 0,
55 PlatformWheelEventPhaseBegan = 1 << 0,
56 PlatformWheelEventPhaseStationary = 1 << 1,
57 PlatformWheelEventPhaseChanged = 1 << 2,
58 PlatformWheelEventPhaseEnded = 1 << 3,
59 PlatformWheelEventPhaseCancelled = 1 << 4,
60 PlatformWheelEventPhaseMayBegin = 1 << 5,
61};
62
63#endif
64
65#if PLATFORM(WIN)
66// How many pixels should we scroll per line? Gecko uses the height of the
67// current line, which means scroll distance changes as you go through the
68// page or go to different pages. IE 7 is ~50 px/line, although the value
69// seems to vary slightly by page and zoom level. Since IE 7 has a
70// smoothing algorithm on scrolling, it can get away with slightly larger
71// scroll values without feeling jerky. Here we use 100 px per three lines
72// (the default scroll amount on Windows is three lines per wheel tick).
73const float cScrollbarPixelsPerLine = 100.0f / 3.0f;
74#endif
75
76class PlatformWheelEvent : public PlatformEvent {
77public:
78 PlatformWheelEvent()
79 : PlatformEvent(PlatformEvent::Wheel)
80 {
81 }
82
83 PlatformWheelEvent(IntPoint position, IntPoint globalPosition, float deltaX, float deltaY, float wheelTicksX, float wheelTicksY, PlatformWheelEventGranularity granularity, bool shiftKey, bool ctrlKey, bool altKey, bool metaKey)
84 : PlatformEvent(PlatformEvent::Wheel, shiftKey, ctrlKey, altKey, metaKey, { })
85 , m_position(position)
86 , m_globalPosition(globalPosition)
87 , m_deltaX(deltaX)
88 , m_deltaY(deltaY)
89 , m_wheelTicksX(wheelTicksX)
90 , m_wheelTicksY(wheelTicksY)
91 , m_granularity(granularity)
92 {
93 }
94
95 PlatformWheelEvent copySwappingDirection() const
96 {
97 PlatformWheelEvent copy = *this;
98 std::swap(copy.m_deltaX, copy.m_deltaY);
99 std::swap(copy.m_wheelTicksX, copy.m_wheelTicksY);
100 return copy;
101 }
102
103 PlatformWheelEvent copyWithDeltasAndVelocity(float deltaX, float deltaY, const FloatSize& velocity) const
104 {
105 PlatformWheelEvent copy = *this;
106 copy.m_deltaX = deltaX;
107 copy.m_deltaY = deltaY;
108 copy.m_scrollingVelocity = velocity;
109 return copy;
110 }
111
112 const IntPoint& position() const { return m_position; } // PlatformWindow coordinates.
113 const IntPoint& globalPosition() const { return m_globalPosition; } // Screen coordinates.
114
115 float deltaX() const { return m_deltaX; }
116 float deltaY() const { return m_deltaY; }
117 FloatSize delta() const { return { m_deltaX, m_deltaY}; }
118
119 float wheelTicksX() const { return m_wheelTicksX; }
120 float wheelTicksY() const { return m_wheelTicksY; }
121
122 PlatformWheelEventGranularity granularity() const { return m_granularity; }
123
124 bool directionInvertedFromDevice() const { return m_directionInvertedFromDevice; }
125
126 const FloatSize& scrollingVelocity() const { return m_scrollingVelocity; }
127
128#if PLATFORM(GTK)
129 explicit PlatformWheelEvent(GdkEventScroll*);
130#endif
131
132#if PLATFORM(COCOA)
133 bool hasPreciseScrollingDeltas() const { return m_hasPreciseScrollingDeltas; }
134 void setHasPreciseScrollingDeltas(bool hasPreciseScrollingDeltas) { m_hasPreciseScrollingDeltas = hasPreciseScrollingDeltas; }
135 unsigned scrollCount() const { return m_scrollCount; }
136 float unacceleratedScrollingDeltaX() const { return m_unacceleratedScrollingDeltaX; }
137 float unacceleratedScrollingDeltaY() const { return m_unacceleratedScrollingDeltaY; }
138#endif
139
140#if ENABLE(ASYNC_SCROLLING)
141 bool useLatchedEventElement() const;
142 bool shouldConsiderLatching() const;
143 bool shouldResetLatching() const;
144 bool isEndOfMomentumScroll() const;
145#else
146 bool useLatchedEventElement() const { return false; }
147#endif
148
149#if ENABLE(ASYNC_SCROLLING)
150 PlatformWheelEventPhase phase() const { return m_phase; }
151 PlatformWheelEventPhase momentumPhase() const { return m_momentumPhase; }
152 bool isEndOfNonMomentumScroll() const;
153 bool isTransitioningToMomentumScroll() const;
154 FloatPoint swipeVelocity() const;
155#endif
156
157#if PLATFORM(WIN)
158 PlatformWheelEvent(HWND, WPARAM, LPARAM, bool isMouseHWheel);
159 PlatformWheelEvent(HWND, const FloatSize& delta, const FloatPoint& location);
160#endif
161
162protected:
163 IntPoint m_position;
164 IntPoint m_globalPosition;
165 float m_deltaX { 0 };
166 float m_deltaY { 0 };
167 float m_wheelTicksX { 0 };
168 float m_wheelTicksY { 0 };
169 PlatformWheelEventGranularity m_granularity { ScrollByPixelWheelEvent };
170 bool m_directionInvertedFromDevice { false };
171
172 // Scrolling velocity in pixels per second.
173 FloatSize m_scrollingVelocity;
174
175#if ENABLE(ASYNC_SCROLLING)
176 PlatformWheelEventPhase m_phase { PlatformWheelEventPhaseNone };
177 PlatformWheelEventPhase m_momentumPhase { PlatformWheelEventPhaseNone };
178#endif
179#if PLATFORM(COCOA)
180 bool m_hasPreciseScrollingDeltas { false };
181 unsigned m_scrollCount { 0 };
182 float m_unacceleratedScrollingDeltaX { 0 };
183 float m_unacceleratedScrollingDeltaY { 0 };
184#endif
185};
186
187#if ENABLE(ASYNC_SCROLLING)
188
189inline bool PlatformWheelEvent::useLatchedEventElement() const
190{
191 return m_phase == PlatformWheelEventPhaseBegan
192 || m_phase == PlatformWheelEventPhaseChanged
193 || m_momentumPhase == PlatformWheelEventPhaseBegan
194 || m_momentumPhase == PlatformWheelEventPhaseChanged
195 || (m_phase == PlatformWheelEventPhaseEnded && m_momentumPhase == PlatformWheelEventPhaseNone);
196}
197
198inline bool PlatformWheelEvent::shouldConsiderLatching() const
199{
200 return m_phase == PlatformWheelEventPhaseBegan || m_phase == PlatformWheelEventPhaseMayBegin;
201}
202
203inline bool PlatformWheelEvent::shouldResetLatching() const
204{
205 return m_phase == PlatformWheelEventPhaseCancelled || m_phase == PlatformWheelEventPhaseMayBegin || isEndOfMomentumScroll();
206}
207
208inline bool PlatformWheelEvent::isEndOfMomentumScroll() const
209{
210 return m_phase == PlatformWheelEventPhaseNone && m_momentumPhase == PlatformWheelEventPhaseEnded;
211}
212
213inline bool PlatformWheelEvent::isEndOfNonMomentumScroll() const
214{
215 return m_phase == PlatformWheelEventPhaseEnded && m_momentumPhase == PlatformWheelEventPhaseNone;
216}
217
218inline bool PlatformWheelEvent::isTransitioningToMomentumScroll() const
219{
220 return m_phase == PlatformWheelEventPhaseNone && m_momentumPhase == PlatformWheelEventPhaseBegan;
221}
222
223inline FloatPoint PlatformWheelEvent::swipeVelocity() const
224{
225 // The swiping velocity is stored in the deltas of the event declaring it.
226 return isTransitioningToMomentumScroll() ? FloatPoint(m_wheelTicksX, m_wheelTicksY) : FloatPoint();
227}
228
229#endif // ENABLE(ASYNC_SCROLLING)
230
231} // namespace WebCore
232