1 | /* |
2 | * Copyright (C) 2019 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. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "EventRegion.h" |
28 | |
29 | #include "RenderStyle.h" |
30 | |
31 | namespace WebCore { |
32 | |
33 | EventRegionContext::EventRegionContext(EventRegion& eventRegion) |
34 | : m_eventRegion(eventRegion) |
35 | { |
36 | } |
37 | |
38 | void EventRegionContext::pushTransform(const AffineTransform& transform) |
39 | { |
40 | if (m_transformStack.isEmpty()) |
41 | m_transformStack.append(transform); |
42 | else |
43 | m_transformStack.append(m_transformStack.last() * transform); |
44 | } |
45 | |
46 | void EventRegionContext::popTransform() |
47 | { |
48 | m_transformStack.removeLast(); |
49 | } |
50 | |
51 | void EventRegionContext::unite(const Region& region, const RenderStyle& style) |
52 | { |
53 | if (m_transformStack.isEmpty()) |
54 | m_eventRegion.unite(region, style); |
55 | else |
56 | m_eventRegion.unite(m_transformStack.last().mapRegion(region), style); |
57 | } |
58 | |
59 | bool EventRegionContext::contains(const IntRect& rect) const |
60 | { |
61 | if (m_transformStack.isEmpty()) |
62 | return m_eventRegion.contains(rect); |
63 | |
64 | return m_eventRegion.contains(m_transformStack.last().mapRect(rect)); |
65 | } |
66 | |
67 | EventRegion::EventRegion() = default; |
68 | |
69 | bool EventRegion::operator==(const EventRegion& other) const |
70 | { |
71 | #if ENABLE(POINTER_EVENTS) |
72 | if (m_touchActionRegions != other.m_touchActionRegions) |
73 | return false; |
74 | #endif |
75 | return m_region == other.m_region; |
76 | } |
77 | |
78 | void EventRegion::unite(const Region& region, const RenderStyle& style) |
79 | { |
80 | m_region.unite(region); |
81 | |
82 | #if ENABLE(POINTER_EVENTS) |
83 | uniteTouchActions(region, style.effectiveTouchActions()); |
84 | #else |
85 | UNUSED_PARAM(style); |
86 | #endif |
87 | } |
88 | |
89 | void EventRegion::translate(const IntSize& offset) |
90 | { |
91 | m_region.translate(offset); |
92 | |
93 | #if ENABLE(POINTER_EVENTS) |
94 | for (auto& touchActionRegion : m_touchActionRegions) |
95 | touchActionRegion.translate(offset); |
96 | #endif |
97 | } |
98 | |
99 | #if ENABLE(POINTER_EVENTS) |
100 | |
101 | constexpr unsigned toIndex(TouchAction touchAction) |
102 | { |
103 | switch (touchAction) { |
104 | case TouchAction::None: |
105 | return 0; |
106 | case TouchAction::Manipulation: |
107 | return 1; |
108 | case TouchAction::PanX: |
109 | return 2; |
110 | case TouchAction::PanY: |
111 | return 3; |
112 | case TouchAction::PinchZoom: |
113 | return 4; |
114 | case TouchAction::Auto: |
115 | break; |
116 | } |
117 | ASSERT_NOT_REACHED(); |
118 | return 0; |
119 | } |
120 | |
121 | constexpr TouchAction toTouchAction(unsigned index) |
122 | { |
123 | switch (index) { |
124 | case 0: |
125 | return TouchAction::None; |
126 | case 1: |
127 | return TouchAction::Manipulation; |
128 | case 2: |
129 | return TouchAction::PanX; |
130 | case 3: |
131 | return TouchAction::PanY; |
132 | case 4: |
133 | return TouchAction::PinchZoom; |
134 | default: |
135 | break; |
136 | } |
137 | ASSERT_NOT_REACHED(); |
138 | return TouchAction::Auto; |
139 | } |
140 | |
141 | void EventRegion::uniteTouchActions(const Region& touchRegion, OptionSet<TouchAction> touchActions) |
142 | { |
143 | for (auto touchAction : touchActions) { |
144 | if (touchAction == TouchAction::Auto) |
145 | break; |
146 | auto index = toIndex(touchAction); |
147 | if (m_touchActionRegions.size() < index + 1) |
148 | m_touchActionRegions.grow(index + 1); |
149 | } |
150 | |
151 | for (unsigned i = 0; i < m_touchActionRegions.size(); ++i) { |
152 | auto regionTouchAction = toTouchAction(i); |
153 | if (touchActions.contains(regionTouchAction)) |
154 | m_touchActionRegions[i].unite(touchRegion); |
155 | else |
156 | m_touchActionRegions[i].subtract(touchRegion); |
157 | } |
158 | } |
159 | |
160 | OptionSet<TouchAction> EventRegion::touchActionsForPoint(const IntPoint& point) const |
161 | { |
162 | OptionSet<TouchAction> actions; |
163 | |
164 | for (unsigned i = 0; i < m_touchActionRegions.size(); ++i) { |
165 | if (m_touchActionRegions[i].contains(point)) { |
166 | auto action = toTouchAction(i); |
167 | actions.add(action); |
168 | if (action == TouchAction::None || action == TouchAction::Manipulation) |
169 | break; |
170 | } |
171 | } |
172 | |
173 | if (actions.isEmpty()) |
174 | return { TouchAction::Auto }; |
175 | |
176 | return actions; |
177 | } |
178 | |
179 | TextStream& operator<<(TextStream& ts, TouchAction touchAction) |
180 | { |
181 | switch (touchAction) { |
182 | case TouchAction::None: |
183 | return ts << "none" ; |
184 | case TouchAction::Manipulation: |
185 | return ts << "manipulation" ; |
186 | case TouchAction::PanX: |
187 | return ts << "pan-x" ; |
188 | case TouchAction::PanY: |
189 | return ts << "pan-y" ; |
190 | case TouchAction::PinchZoom: |
191 | return ts << "pinch-zoom" ; |
192 | case TouchAction::Auto: |
193 | return ts << "auto" ; |
194 | } |
195 | ASSERT_NOT_REACHED(); |
196 | return ts; |
197 | } |
198 | |
199 | #endif |
200 | |
201 | TextStream& operator<<(TextStream& ts, const EventRegion& eventRegion) |
202 | { |
203 | ts << eventRegion.m_region; |
204 | |
205 | #if ENABLE(POINTER_EVENTS) |
206 | if (!eventRegion.m_touchActionRegions.isEmpty()) { |
207 | TextStream::IndentScope indentScope(ts); |
208 | ts << indent << "(touch-action\n" ; |
209 | for (unsigned i = 0; i < eventRegion.m_touchActionRegions.size(); ++i) { |
210 | if (eventRegion.m_touchActionRegions[i].isEmpty()) |
211 | continue; |
212 | TextStream::IndentScope indentScope(ts); |
213 | ts << indent << "(" << toTouchAction(i); |
214 | ts << indent << eventRegion.m_touchActionRegions[i]; |
215 | ts << indent << ")\n" ; |
216 | } |
217 | ts << indent << ")\n" ; |
218 | } |
219 | #endif |
220 | |
221 | return ts; |
222 | } |
223 | |
224 | } |
225 | |