blob: 272f6a4a1befc163ec06a1699075de14b53347c4 [file] [log] [blame]
// Copyright 2015 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 <stdint.h>
#include "base/callback.h"
#include "content/browser/renderer_host/input/synthetic_touchpad_pinch_gesture.h"
namespace content {
namespace {
float Lerp(float start, float end, float progress) {
return start + progress * (end - start);
}
} // namespace
SyntheticTouchpadPinchGesture::SyntheticTouchpadPinchGesture(
const SyntheticPinchGestureParams& params)
: params_(params),
gesture_source_type_(SyntheticGestureParams::DEFAULT_INPUT),
state_(SETUP),
current_scale_(1.0f) {
DCHECK_GT(params_.scale_factor, 0.0f);
}
SyntheticTouchpadPinchGesture::~SyntheticTouchpadPinchGesture() {}
SyntheticGesture::Result SyntheticTouchpadPinchGesture::ForwardInputEvents(
const base::TimeTicks& timestamp,
SyntheticGestureTarget* target) {
if (state_ == SETUP) {
gesture_source_type_ = params_.gesture_source_type;
if (gesture_source_type_ == SyntheticGestureParams::DEFAULT_INPUT)
gesture_source_type_ = target->GetDefaultSyntheticGestureSourceType();
state_ = STARTED;
start_time_ = timestamp;
}
DCHECK_NE(gesture_source_type_, SyntheticGestureParams::DEFAULT_INPUT);
if (gesture_source_type_ == SyntheticGestureParams::MOUSE_INPUT) {
ForwardGestureEvents(timestamp, target);
} else {
// Touch input should be using SyntheticTouchscreenPinchGesture.
return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
}
return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED
: SyntheticGesture::GESTURE_RUNNING;
}
void SyntheticTouchpadPinchGesture::WaitForTargetAck(
base::OnceClosure callback,
SyntheticGestureTarget* target) const {
target->WaitForTargetAck(params_.GetGestureType(), gesture_source_type_,
std::move(callback));
}
void SyntheticTouchpadPinchGesture::ForwardGestureEvents(
const base::TimeTicks& timestamp,
SyntheticGestureTarget* target) {
switch (state_) {
case STARTED:
// Check for an early finish.
if (params_.scale_factor == 1.0f) {
state_ = DONE;
break;
}
CalculateEndTime(target);
// Send the start event.
target->DispatchInputEventToPlatform(
SyntheticWebGestureEventBuilder::Build(
blink::WebGestureEvent::kGesturePinchBegin,
blink::WebGestureDevice::kTouchpad));
state_ = IN_PROGRESS;
break;
case IN_PROGRESS: {
base::TimeTicks event_timestamp = ClampTimestamp(timestamp);
float target_scale = CalculateTargetScale(event_timestamp);
float incremental_scale = target_scale / current_scale_;
current_scale_ = target_scale;
// Send the incremental scale event.
target->DispatchInputEventToPlatform(
SyntheticWebGestureEventBuilder::BuildPinchUpdate(
incremental_scale, params_.anchor.x(), params_.anchor.y(),
0 /* modifierFlags */, blink::WebGestureDevice::kTouchpad));
if (HasReachedTarget(event_timestamp)) {
target->DispatchInputEventToPlatform(
SyntheticWebGestureEventBuilder::Build(
blink::WebGestureEvent::kGesturePinchEnd,
blink::WebGestureDevice::kTouchpad));
state_ = DONE;
}
break;
}
case SETUP:
NOTREACHED() << "State SETUP invalid for synthetic pinch.";
break;
case DONE:
NOTREACHED() << "State DONE invalid for synthetic pinch.";
break;
}
}
float SyntheticTouchpadPinchGesture::CalculateTargetScale(
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 params_.scale_factor;
float progress = (timestamp - start_time_).InSecondsF() /
(stop_time_ - start_time_).InSecondsF();
return Lerp(1.0f, params_.scale_factor, progress);
}
// Calculate an end time based on the amount of scaling to be done and the
// |relative_pointer_speed_in_pixels_s|. Because we don't have an actual pixel
// delta, we assume that a pinch of 200 pixels is needed to double the screen
// size and generate a stop time based on that.
// TODO(ericrk): We should not calculate duration from
// |relative_pointer_speed_in_pixels_s|, but should instead get a duration from
// a SyntheticTouchpadPinchGestureParams type. crbug.com/534976
void SyntheticTouchpadPinchGesture::CalculateEndTime(
SyntheticGestureTarget* target) {
const int kPixelsNeededToDoubleOrHalve = 200;
float scale_factor = params_.scale_factor;
if (scale_factor < 1.0f) {
// If we are scaling down, calculate the time based on the inverse so that
// halving or doubling the scale takes the same amount of time.
scale_factor = 1.0f / scale_factor;
}
float scale_factor_delta =
(scale_factor - 1.0f) * kPixelsNeededToDoubleOrHalve;
int64_t total_duration_in_us =
static_cast<int64_t>(1e6 * (static_cast<double>(scale_factor_delta) /
params_.relative_pointer_speed_in_pixels_s));
DCHECK_GT(total_duration_in_us, 0);
stop_time_ =
start_time_ + base::TimeDelta::FromMicroseconds(total_duration_in_us);
}
base::TimeTicks SyntheticTouchpadPinchGesture::ClampTimestamp(
const base::TimeTicks& timestamp) const {
return std::min(timestamp, stop_time_);
}
bool SyntheticTouchpadPinchGesture::HasReachedTarget(
const base::TimeTicks& timestamp) const {
return timestamp >= stop_time_;
}
} // namespace content