1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/lib/ui/window/pointer_data_packet_converter.h"
6#include "flutter/fml/logging.h"
7
8#include <string.h>
9
10namespace flutter {
11
12PointerDataPacketConverter::PointerDataPacketConverter() : pointer_(0) {}
13
14PointerDataPacketConverter::~PointerDataPacketConverter() = default;
15
16std::unique_ptr<PointerDataPacket> PointerDataPacketConverter::Convert(
17 std::unique_ptr<PointerDataPacket> packet) {
18 size_t kBytesPerPointerData = kPointerDataFieldCount * kBytesPerField;
19 auto buffer = packet->data();
20 size_t buffer_length = buffer.size();
21
22 std::vector<PointerData> converted_pointers;
23 // Converts each pointer data in the buffer and stores it in the
24 // converted_pointers.
25 for (size_t i = 0; i < buffer_length / kBytesPerPointerData; i++) {
26 PointerData pointer_data;
27 memcpy(&pointer_data, &buffer[i * kBytesPerPointerData],
28 sizeof(PointerData));
29 ConvertPointerData(pointer_data, converted_pointers);
30 }
31
32 // Writes converted_pointers into converted_packet.
33 auto converted_packet =
34 std::make_unique<flutter::PointerDataPacket>(converted_pointers.size());
35 size_t count = 0;
36 for (auto& converted_pointer : converted_pointers) {
37 converted_packet->SetPointerData(count++, converted_pointer);
38 }
39
40 return converted_packet;
41}
42
43void PointerDataPacketConverter::ConvertPointerData(
44 PointerData pointer_data,
45 std::vector<PointerData>& converted_pointers) {
46 if (pointer_data.signal_kind == PointerData::SignalKind::kNone) {
47 switch (pointer_data.change) {
48 case PointerData::Change::kCancel: {
49 // Android's three finger gesture will send a cancel event
50 // to a non-existing pointer. Drops the cancel if pointer
51 // is not previously added.
52 // https://github.com/flutter/flutter/issues/20517
53 auto iter = states_.find(pointer_data.device);
54 if (iter != states_.end()) {
55 PointerState state = iter->second;
56 FML_DCHECK(state.isDown);
57 UpdatePointerIdentifier(pointer_data, state, false);
58
59 if (LocationNeedsUpdate(pointer_data, state)) {
60 // Synthesizes a move event if the location does not match.
61 PointerData synthesized_move_event = pointer_data;
62 synthesized_move_event.change = PointerData::Change::kMove;
63 synthesized_move_event.synthesized = 1;
64
65 UpdateDeltaAndState(synthesized_move_event, state);
66 converted_pointers.push_back(synthesized_move_event);
67 }
68
69 state.isDown = false;
70 states_[pointer_data.device] = state;
71 converted_pointers.push_back(pointer_data);
72 }
73 break;
74 }
75 case PointerData::Change::kAdd: {
76 FML_DCHECK(states_.find(pointer_data.device) == states_.end());
77 EnsurePointerState(pointer_data);
78 converted_pointers.push_back(pointer_data);
79 break;
80 }
81 case PointerData::Change::kRemove: {
82 // Makes sure we have an existing pointer
83 auto iter = states_.find(pointer_data.device);
84 FML_DCHECK(iter != states_.end());
85 PointerState state = iter->second;
86
87 if (state.isDown) {
88 // Synthesizes cancel event if the pointer is down.
89 PointerData synthesized_cancel_event = pointer_data;
90 synthesized_cancel_event.change = PointerData::Change::kCancel;
91 synthesized_cancel_event.synthesized = 1;
92 UpdatePointerIdentifier(synthesized_cancel_event, state, false);
93
94 state.isDown = false;
95 states_[synthesized_cancel_event.device] = state;
96 converted_pointers.push_back(synthesized_cancel_event);
97 }
98
99 if (LocationNeedsUpdate(pointer_data, state)) {
100 // Synthesizes a hover event if the location does not match.
101 PointerData synthesized_hover_event = pointer_data;
102 synthesized_hover_event.change = PointerData::Change::kHover;
103 synthesized_hover_event.synthesized = 1;
104
105 UpdateDeltaAndState(synthesized_hover_event, state);
106 converted_pointers.push_back(synthesized_hover_event);
107 }
108
109 states_.erase(pointer_data.device);
110 converted_pointers.push_back(pointer_data);
111 break;
112 }
113 case PointerData::Change::kHover: {
114 auto iter = states_.find(pointer_data.device);
115 PointerState state;
116 if (iter == states_.end()) {
117 // Synthesizes add event if the pointer is not previously added.
118 PointerData synthesized_add_event = pointer_data;
119 synthesized_add_event.change = PointerData::Change::kAdd;
120 synthesized_add_event.synthesized = 1;
121 state = EnsurePointerState(synthesized_add_event);
122 converted_pointers.push_back(synthesized_add_event);
123 } else {
124 state = iter->second;
125 }
126
127 FML_DCHECK(!state.isDown);
128 if (LocationNeedsUpdate(pointer_data, state)) {
129 UpdateDeltaAndState(pointer_data, state);
130 converted_pointers.push_back(pointer_data);
131 }
132 break;
133 }
134 case PointerData::Change::kDown: {
135 auto iter = states_.find(pointer_data.device);
136 PointerState state;
137 if (iter == states_.end()) {
138 // Synthesizes a add event if the pointer is not previously added.
139 PointerData synthesized_add_event = pointer_data;
140 synthesized_add_event.change = PointerData::Change::kAdd;
141 synthesized_add_event.synthesized = 1;
142 state = EnsurePointerState(synthesized_add_event);
143 converted_pointers.push_back(synthesized_add_event);
144 } else {
145 state = iter->second;
146 }
147
148 FML_DCHECK(!state.isDown);
149 if (LocationNeedsUpdate(pointer_data, state)) {
150 // Synthesizes a hover event if the location does not match.
151 PointerData synthesized_hover_event = pointer_data;
152 synthesized_hover_event.change = PointerData::Change::kHover;
153 synthesized_hover_event.synthesized = 1;
154
155 UpdateDeltaAndState(synthesized_hover_event, state);
156 converted_pointers.push_back(synthesized_hover_event);
157 }
158
159 UpdatePointerIdentifier(pointer_data, state, true);
160 state.isDown = true;
161 states_[pointer_data.device] = state;
162 converted_pointers.push_back(pointer_data);
163 break;
164 }
165 case PointerData::Change::kMove: {
166 // Makes sure we have an existing pointer in down state
167 auto iter = states_.find(pointer_data.device);
168 FML_DCHECK(iter != states_.end());
169 PointerState state = iter->second;
170 FML_DCHECK(state.isDown);
171
172 UpdatePointerIdentifier(pointer_data, state, false);
173 UpdateDeltaAndState(pointer_data, state);
174 converted_pointers.push_back(pointer_data);
175 break;
176 }
177 case PointerData::Change::kUp: {
178 // Makes sure we have an existing pointer in down state
179 auto iter = states_.find(pointer_data.device);
180 FML_DCHECK(iter != states_.end());
181 PointerState state = iter->second;
182 FML_DCHECK(state.isDown);
183
184 UpdatePointerIdentifier(pointer_data, state, false);
185
186 if (LocationNeedsUpdate(pointer_data, state)) {
187 // Synthesizes a move event if the location does not match.
188 PointerData synthesized_move_event = pointer_data;
189 synthesized_move_event.change = PointerData::Change::kMove;
190 synthesized_move_event.synthesized = 1;
191
192 UpdateDeltaAndState(synthesized_move_event, state);
193 converted_pointers.push_back(synthesized_move_event);
194 }
195
196 state.isDown = false;
197 states_[pointer_data.device] = state;
198 converted_pointers.push_back(pointer_data);
199 break;
200 }
201 default: {
202 converted_pointers.push_back(pointer_data);
203 break;
204 }
205 }
206 } else {
207 switch (pointer_data.signal_kind) {
208 case PointerData::SignalKind::kScroll: {
209 // Makes sure we have an existing pointer
210 auto iter = states_.find(pointer_data.device);
211 FML_DCHECK(iter != states_.end());
212
213 PointerState state = iter->second;
214 if (LocationNeedsUpdate(pointer_data, state)) {
215 if (state.isDown) {
216 // Synthesizes a move event if the pointer is down.
217 PointerData synthesized_move_event = pointer_data;
218 synthesized_move_event.signal_kind = PointerData::SignalKind::kNone;
219 synthesized_move_event.change = PointerData::Change::kMove;
220 synthesized_move_event.synthesized = 1;
221
222 UpdateDeltaAndState(synthesized_move_event, state);
223 converted_pointers.push_back(synthesized_move_event);
224 } else {
225 // Synthesizes a hover event if the pointer is up.
226 PointerData synthesized_hover_event = pointer_data;
227 synthesized_hover_event.signal_kind =
228 PointerData::SignalKind::kNone;
229 synthesized_hover_event.change = PointerData::Change::kHover;
230 synthesized_hover_event.synthesized = 1;
231
232 UpdateDeltaAndState(synthesized_hover_event, state);
233 converted_pointers.push_back(synthesized_hover_event);
234 }
235 }
236
237 converted_pointers.push_back(pointer_data);
238 break;
239 }
240 default: {
241 // Ignores unknown signal kind.
242 break;
243 }
244 }
245 }
246}
247
248PointerState PointerDataPacketConverter::EnsurePointerState(
249 PointerData pointer_data) {
250 PointerState state;
251 state.pointer_identifier = 0;
252 state.isDown = false;
253 state.physical_x = pointer_data.physical_x;
254 state.physical_y = pointer_data.physical_y;
255 states_[pointer_data.device] = state;
256 return state;
257}
258
259void PointerDataPacketConverter::UpdateDeltaAndState(PointerData& pointer_data,
260 PointerState& state) {
261 pointer_data.physical_delta_x = pointer_data.physical_x - state.physical_x;
262 pointer_data.physical_delta_y = pointer_data.physical_y - state.physical_y;
263 state.physical_x = pointer_data.physical_x;
264 state.physical_y = pointer_data.physical_y;
265 states_[pointer_data.device] = state;
266}
267
268bool PointerDataPacketConverter::LocationNeedsUpdate(
269 const PointerData pointer_data,
270 const PointerState state) {
271 return state.physical_x != pointer_data.physical_x ||
272 state.physical_y != pointer_data.physical_y;
273}
274
275void PointerDataPacketConverter::UpdatePointerIdentifier(
276 PointerData& pointer_data,
277 PointerState& state,
278 bool start_new_pointer) {
279 if (start_new_pointer) {
280 state.pointer_identifier = ++pointer_;
281 states_[pointer_data.device] = state;
282 }
283 pointer_data.pointer_identifier = state.pointer_identifier;
284}
285
286} // namespace flutter
287