| // Copyright 2022 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_EMBEDDER_POINTER_UTILITY_H_ |
| #define SRC_EMBEDDER_POINTER_UTILITY_H_ |
| |
| #include <fuchsia/ui/pointer/cpp/fidl.h> |
| #include <lib/syslog/global.h> |
| #include <lib/trace/event.h> |
| |
| #include <array> |
| |
| #include "src/embedder/logging.h" |
| |
| namespace embedder { |
| |
| namespace fup = fuchsia::ui::pointer; |
| |
| // Functions shared by TouchDelegate and MouseDelegate |
| namespace pointer_utility { |
| |
| /// This is intended to be run immediately after a FlutterPointerEvent |
| /// is initialized on the stack. It will clear all of the fields |
| /// that may be garbage values, and it will set the struct_size field |
| /// so that consumers can interpret it correctly. |
| inline void ResetFlutterPointerEvent(FlutterPointerEvent& ptr) { |
| memset(&ptr, 0, sizeof(FlutterPointerEvent)); |
| ptr.struct_size = sizeof(FlutterPointerEvent); |
| } |
| |
| /// Converts the time value sent from Scenic via the TouchEvent or MouseEvent |
| /// that is in nanosecond units to microseconds. |
| inline size_t ConvertEventTimeToMicroseconds(const zx_time_t& time) { return time / 1000; } |
| |
| /// Clamps x, and y, based on the min/max values listed in the ViewParameters |
| /// Prints a log if any clamping occurred. |
| inline std::array<float, 2> ClampToViewSpace(const float x, const float y, |
| const fup::ViewParameters& p) { |
| const float min_x = p.view.min[0]; |
| const float min_y = p.view.min[1]; |
| const float max_x = p.view.max[0]; |
| const float max_y = p.view.max[1]; |
| if (min_x <= x && x < max_x && min_y <= y && y < max_y) { |
| return {x, y}; // No clamping to perform. |
| } |
| // View boundary is [min_x, max_x) x [min_y, max_y). Note that min is |
| // inclusive, but max is exclusive - so we subtract epsilon. |
| const float max_x_inclusive = std::nextafter(max_x, min_x); |
| const float max_y_inclusive = std::nextafter(max_y, min_y); |
| const float& clamped_x = std::clamp(x, min_x, max_x_inclusive); |
| const float& clamped_y = std::clamp(y, min_y, max_y_inclusive); |
| FX_LOGF(INFO, kLogTag, "Clamped (%f, %f) to (%f, %f).", x, y, clamped_x, clamped_y); |
| return {clamped_x, clamped_y}; |
| } |
| |
| inline std::array<float, 2> ViewportToViewCoordinates( |
| std::array<float, 2> viewport_coordinates, |
| const std::array<float, 9>& viewport_to_view_transform) { |
| // The transform matrix is a FIDL array with matrix data in column-major |
| // order. For a matrix with data [a b c d e f g h i], and with the viewport |
| // coordinates expressed as homogeneous coordinates, the logical view |
| // coordinates are obtained with the following formula: |
| // |a d g| |x| |x'| |
| // |b e h| * |y| = |y'| |
| // |c f i| |1| |w'| |
| // which we then normalize based on the w component: |
| // if z' not zero: (x'/w', y'/w') |
| // else (x', y') |
| const auto& M = viewport_to_view_transform; |
| const float x = viewport_coordinates[0]; |
| const float y = viewport_coordinates[1]; |
| const float xp = M[0] * x + M[3] * y + M[6]; |
| const float yp = M[1] * x + M[4] * y + M[7]; |
| const float wp = M[2] * x + M[5] * y + M[8]; |
| if (wp != 0) { |
| return {xp / wp, yp / wp}; |
| } else { |
| return {xp, yp}; |
| } |
| } |
| |
| /// Writes a trace flow end event. |
| /// Only intended to be used for TouchEvent and MouseEvent types |
| /// see static assertion |
| template <typename EventT> |
| void IssueInputTraceEvent(const EventT& event) { |
| static_assert(std::is_same_v<EventT, fup::TouchEvent> || std::is_same_v<EventT, fup::MouseEvent>); |
| FX_DCHECK(event.has_trace_flow_id()); |
| TRACE_FLOW_END("input", "dispatch_event_to_client", event.trace_flow_id()); |
| } |
| |
| } // namespace pointer_utility |
| } // namespace embedder |
| |
| #endif // SRC_EMBEDDER_POINTER_UTILITY_H_ |