blob: 1465cc1e3c4960951effff0793e14aa6b9ae9cc7 [file] [log] [blame]
// 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.
#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>);
TRACE_FLOW_END("input", "dispatch_event_to_client", event.trace_flow_id());
} // namespace pointer_utility
} // namespace embedder