[go: up one dir, main page]

blob: f997628aba9414ea36725c8421f5e9e9b4cac7ca [file] [log] [blame]
// Copyright 2013 The Chromium 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 "content/browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.h"
#include <stdint.h>
#include <cmath>
#include "base/check_op.h"
#include "base/notreached.h"
#include "ui/latency/latency_info.h"
namespace content {
SyntheticTouchscreenPinchGesture::SyntheticTouchscreenPinchGesture(
const SyntheticPinchGestureParams& params)
: params_(params),
start_y_0_(0.0f),
start_y_1_(0.0f),
max_pointer_delta_0_(0.0f),
gesture_source_type_(content::mojom::GestureSourceType::kDefaultInput),
state_(SETUP) {
DCHECK_GT(params_.scale_factor, 0.0f);
if (params_.gesture_source_type !=
content::mojom::GestureSourceType::kTouchInput) {
DCHECK_EQ(params_.gesture_source_type,
content::mojom::GestureSourceType::kDefaultInput);
params_.gesture_source_type =
content::mojom::GestureSourceType::kTouchInput;
}
}
SyntheticTouchscreenPinchGesture::~SyntheticTouchscreenPinchGesture() {}
SyntheticGesture::Result SyntheticTouchscreenPinchGesture::ForwardInputEvents(
const base::TimeTicks& timestamp,
SyntheticGestureTarget* target) {
if (state_ == SETUP) {
gesture_source_type_ = params_.gesture_source_type;
if (gesture_source_type_ ==
content::mojom::GestureSourceType::kDefaultInput)
gesture_source_type_ = target->GetDefaultSyntheticGestureSourceType();
state_ = STARTED;
start_time_ = timestamp;
}
DCHECK_NE(gesture_source_type_,
content::mojom::GestureSourceType::kDefaultInput);
if (!synthetic_pointer_driver_)
synthetic_pointer_driver_ = SyntheticPointerDriver::Create(
gesture_source_type_, params_.from_devtools_debugger);
if (gesture_source_type_ == content::mojom::GestureSourceType::kTouchInput) {
ForwardTouchInputEvents(timestamp, target);
} else {
return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
}
return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED
: SyntheticGesture::GESTURE_RUNNING;
}
void SyntheticTouchscreenPinchGesture::WaitForTargetAck(
base::OnceClosure callback,
SyntheticGestureTarget* target) const {
target->WaitForTargetAck(params_.GetGestureType(), gesture_source_type_,
std::move(callback));
}
void SyntheticTouchscreenPinchGesture::ForwardTouchInputEvents(
const base::TimeTicks& timestamp,
SyntheticGestureTarget* target) {
switch (state_) {
case STARTED:
// Check for an early finish.
if (params_.scale_factor == 1.0f) {
state_ = DONE;
break;
}
SetupCoordinatesAndStopTime(target);
PressTouchPoints(target, timestamp);
state_ = MOVING;
break;
case MOVING: {
base::TimeTicks event_timestamp = ClampTimestamp(timestamp);
float delta = GetDeltaForPointer0AtTime(event_timestamp);
MoveTouchPoints(target, delta, event_timestamp);
if (HasReachedTarget(event_timestamp)) {
ReleaseTouchPoints(target, event_timestamp);
state_ = DONE;
}
} break;
case SETUP:
NOTREACHED() << "State SETUP invalid for synthetic pinch.";
break;
case DONE:
NOTREACHED() << "State DONE invalid for synthetic pinch.";
break;
}
}
void SyntheticTouchscreenPinchGesture::PressTouchPoints(
SyntheticGestureTarget* target,
const base::TimeTicks& timestamp) {
synthetic_pointer_driver_->Press(params_.anchor.x(), start_y_0_, 0);
synthetic_pointer_driver_->Press(params_.anchor.x(), start_y_1_, 1);
synthetic_pointer_driver_->DispatchEvent(target, timestamp);
}
void SyntheticTouchscreenPinchGesture::MoveTouchPoints(
SyntheticGestureTarget* target,
float delta,
const base::TimeTicks& timestamp) {
// The two pointers move in opposite directions.
float current_y_0 = start_y_0_ + delta;
float current_y_1 = start_y_1_ - delta;
synthetic_pointer_driver_->Move(params_.anchor.x(), current_y_0, 0);
synthetic_pointer_driver_->Move(params_.anchor.x(), current_y_1, 1);
synthetic_pointer_driver_->DispatchEvent(target, timestamp);
}
void SyntheticTouchscreenPinchGesture::ReleaseTouchPoints(
SyntheticGestureTarget* target,
const base::TimeTicks& timestamp) {
synthetic_pointer_driver_->Release(0);
synthetic_pointer_driver_->Release(1);
synthetic_pointer_driver_->DispatchEvent(target, timestamp);
}
void SyntheticTouchscreenPinchGesture::SetupCoordinatesAndStopTime(
SyntheticGestureTarget* target) {
// To achieve the specified scaling factor, the ratio of the final to the
// initial span (distance between the pointers) has to be equal to the scaling
// factor. Since we're moving both pointers at the same speed, each pointer's
// distance to the anchor is half the span.
float initial_distance_to_anchor, final_distance_to_anchor;
const float single_point_slop = target->GetSpanSlopInDips() / 2.0f;
if (params_.scale_factor > 1.0f) { // zooming in
initial_distance_to_anchor = target->GetMinScalingSpanInDips() / 2.0f;
final_distance_to_anchor =
(initial_distance_to_anchor + single_point_slop) * params_.scale_factor;
} else { // zooming out
final_distance_to_anchor = target->GetMinScalingSpanInDips() / 2.0f;
initial_distance_to_anchor =
(final_distance_to_anchor / params_.scale_factor) + single_point_slop;
}
start_y_0_ = params_.anchor.y() - initial_distance_to_anchor;
start_y_1_ = params_.anchor.y() + initial_distance_to_anchor;
max_pointer_delta_0_ = initial_distance_to_anchor - final_distance_to_anchor;
int64_t total_duration_in_us = static_cast<int64_t>(
1e6 * (static_cast<double>(std::abs(2 * max_pointer_delta_0_)) /
params_.relative_pointer_speed_in_pixels_s));
DCHECK_GT(total_duration_in_us, 0);
stop_time_ = start_time_ + base::Microseconds(total_duration_in_us);
}
float SyntheticTouchscreenPinchGesture::GetDeltaForPointer0AtTime(
const base::TimeTicks& timestamp) const {
// Make sure the final delta is correct. Using the computation below can lead
// to issues with floating point precision.
if (HasReachedTarget(timestamp))
return max_pointer_delta_0_;
float total_abs_delta = params_.relative_pointer_speed_in_pixels_s *
(timestamp - start_time_).InSecondsF();
float abs_delta_pointer_0 = total_abs_delta / 2.0f;
return (params_.scale_factor > 1.0f) ? -abs_delta_pointer_0
: abs_delta_pointer_0;
}
base::TimeTicks SyntheticTouchscreenPinchGesture::ClampTimestamp(
const base::TimeTicks& timestamp) const {
return std::min(timestamp, stop_time_);
}
bool SyntheticTouchscreenPinchGesture::HasReachedTarget(
const base::TimeTicks& timestamp) const {
return timestamp >= stop_time_;
}
} // namespace content