Enable pinch-zoom telemetry on Mac
This change adds a SyntheticGestureTargetMac which is able to interpret the touches sent from telemetry's pinch simulator and convert these into trackpad zoom gestures. BUG= CQ_EXTRA_TRYBOTS=tryserver.chromium.perf:linux_perf_bisect;tryserver.chromium.perf:mac_10_10_perf_bisect;tryserver.chromium.perf:win_perf_bisect;tryserver.chromium.perf:android_nexus5_perf_bisect Review URL: https://codereview.chromium.org/1349813002 Cr-Commit-Position: refs/heads/master@{#350316}
This commit is contained in:
content
browser
renderer_host
input
synthetic_gesture_controller_unittest.ccsynthetic_gesture_target_mac.hsynthetic_gesture_target_mac.mmsynthetic_pinch_gesture.ccsynthetic_pinch_gesture.hsynthetic_touchpad_pinch_gesture.ccsynthetic_touchpad_pinch_gesture.hsynthetic_touchscreen_pinch_gesture.ccsynthetic_touchscreen_pinch_gesture.h
render_widget_host_view_mac.hrender_widget_host_view_mac.mmtools
@ -13,6 +13,8 @@
|
||||
#include "content/browser/renderer_host/input/synthetic_smooth_move_gesture.h"
|
||||
#include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
|
||||
#include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
|
||||
#include "content/browser/renderer_host/input/synthetic_touchpad_pinch_gesture.h"
|
||||
#include "content/browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_delegate.h"
|
||||
#include "content/common/input/synthetic_pinch_gesture_params.h"
|
||||
#include "content/common/input/synthetic_smooth_drag_gesture_params.h"
|
||||
@ -218,7 +220,8 @@ class MockDragMouseTarget : public MockMoveGestureTarget {
|
||||
gfx::PointF start_, last_mouse_point_;
|
||||
};
|
||||
|
||||
class MockSyntheticPinchTouchTarget : public MockSyntheticGestureTarget {
|
||||
class MockSyntheticTouchscreenPinchTouchTarget
|
||||
: public MockSyntheticGestureTarget {
|
||||
public:
|
||||
enum ZoomDirection {
|
||||
ZOOM_DIRECTION_UNKNOWN,
|
||||
@ -226,12 +229,12 @@ class MockSyntheticPinchTouchTarget : public MockSyntheticGestureTarget {
|
||||
ZOOM_OUT
|
||||
};
|
||||
|
||||
MockSyntheticPinchTouchTarget()
|
||||
MockSyntheticTouchscreenPinchTouchTarget()
|
||||
: initial_pointer_distance_(0),
|
||||
last_pointer_distance_(0),
|
||||
zoom_direction_(ZOOM_DIRECTION_UNKNOWN),
|
||||
started_(false) {}
|
||||
~MockSyntheticPinchTouchTarget() override {}
|
||||
~MockSyntheticTouchscreenPinchTouchTarget() override {}
|
||||
|
||||
void DispatchInputEventToPlatform(const WebInputEvent& event) override {
|
||||
ASSERT_TRUE(WebInputEvent::isTouchEventType(event.type));
|
||||
@ -271,6 +274,11 @@ class MockSyntheticPinchTouchTarget : public MockSyntheticGestureTarget {
|
||||
}
|
||||
}
|
||||
|
||||
SyntheticGestureParams::GestureSourceType
|
||||
GetDefaultSyntheticGestureSourceType() const override {
|
||||
return SyntheticGestureParams::TOUCH_INPUT;
|
||||
}
|
||||
|
||||
ZoomDirection zoom_direction() const { return zoom_direction_; }
|
||||
|
||||
float ComputeScaleFactor() const {
|
||||
@ -305,6 +313,67 @@ class MockSyntheticPinchTouchTarget : public MockSyntheticGestureTarget {
|
||||
bool started_;
|
||||
};
|
||||
|
||||
class MockSyntheticTouchpadPinchTouchTarget
|
||||
: public MockSyntheticGestureTarget {
|
||||
public:
|
||||
enum ZoomDirection { ZOOM_DIRECTION_UNKNOWN, ZOOM_IN, ZOOM_OUT };
|
||||
|
||||
MockSyntheticTouchpadPinchTouchTarget()
|
||||
: zoom_direction_(ZOOM_DIRECTION_UNKNOWN),
|
||||
started_(false),
|
||||
ended_(false),
|
||||
scale_factor_(1.0f) {}
|
||||
~MockSyntheticTouchpadPinchTouchTarget() override {}
|
||||
|
||||
void DispatchInputEventToPlatform(const WebInputEvent& event) override {
|
||||
EXPECT_TRUE(WebInputEvent::isGestureEventType(event.type));
|
||||
const blink::WebGestureEvent& gesture_event =
|
||||
static_cast<const blink::WebGestureEvent&>(event);
|
||||
|
||||
if (gesture_event.type == WebInputEvent::GesturePinchBegin) {
|
||||
EXPECT_FALSE(started_);
|
||||
EXPECT_FALSE(ended_);
|
||||
started_ = true;
|
||||
} else if (gesture_event.type == WebInputEvent::GesturePinchEnd) {
|
||||
EXPECT_TRUE(started_);
|
||||
EXPECT_FALSE(ended_);
|
||||
ended_ = true;
|
||||
} else {
|
||||
EXPECT_EQ(WebInputEvent::GesturePinchUpdate, gesture_event.type);
|
||||
EXPECT_TRUE(started_);
|
||||
EXPECT_FALSE(ended_);
|
||||
const float scale = gesture_event.data.pinchUpdate.scale;
|
||||
if (scale != 1.0f) {
|
||||
if (zoom_direction_ == ZOOM_DIRECTION_UNKNOWN) {
|
||||
zoom_direction_ = scale > 1.0f ? ZOOM_IN : ZOOM_OUT;
|
||||
} else if (zoom_direction_ == ZOOM_IN) {
|
||||
EXPECT_GT(scale, 1.0f);
|
||||
} else {
|
||||
EXPECT_EQ(ZOOM_OUT, zoom_direction_);
|
||||
EXPECT_LT(scale, 1.0f);
|
||||
}
|
||||
|
||||
scale_factor_ *= scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SyntheticGestureParams::GestureSourceType
|
||||
GetDefaultSyntheticGestureSourceType() const override {
|
||||
return SyntheticGestureParams::MOUSE_INPUT;
|
||||
}
|
||||
|
||||
ZoomDirection zoom_direction() const { return zoom_direction_; }
|
||||
|
||||
float scale_factor() const { return scale_factor_; }
|
||||
|
||||
private:
|
||||
ZoomDirection zoom_direction_;
|
||||
bool started_;
|
||||
bool ended_;
|
||||
float scale_factor_;
|
||||
};
|
||||
|
||||
class MockSyntheticTapGestureTarget : public MockSyntheticGestureTarget {
|
||||
public:
|
||||
MockSyntheticTapGestureTarget() : state_(NOT_STARTED) {}
|
||||
@ -1100,8 +1169,143 @@ TEST_F(SyntheticGestureControllerTest,
|
||||
gesture->ForwardInputEvents(timestamp, target_);
|
||||
}
|
||||
|
||||
TEST_F(SyntheticGestureControllerTest, PinchGestureTouchZoomIn) {
|
||||
CreateControllerAndTarget<MockSyntheticPinchTouchTarget>();
|
||||
TEST_F(SyntheticGestureControllerTest,
|
||||
TouchscreenTouchpadPinchGestureTouchZoomIn) {
|
||||
CreateControllerAndTarget<MockSyntheticTouchscreenPinchTouchTarget>();
|
||||
|
||||
SyntheticPinchGestureParams params;
|
||||
params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
|
||||
params.scale_factor = 2.3f;
|
||||
params.anchor.SetPoint(54, 89);
|
||||
|
||||
scoped_ptr<SyntheticTouchscreenPinchGesture> gesture(
|
||||
new SyntheticTouchscreenPinchGesture(params));
|
||||
QueueSyntheticGesture(gesture.Pass());
|
||||
FlushInputUntilComplete();
|
||||
|
||||
MockSyntheticTouchscreenPinchTouchTarget* pinch_target =
|
||||
static_cast<MockSyntheticTouchscreenPinchTouchTarget*>(target_);
|
||||
EXPECT_EQ(1, num_success_);
|
||||
EXPECT_EQ(0, num_failure_);
|
||||
EXPECT_EQ(pinch_target->zoom_direction(),
|
||||
MockSyntheticTouchscreenPinchTouchTarget::ZOOM_IN);
|
||||
EXPECT_FLOAT_EQ(params.scale_factor, pinch_target->ComputeScaleFactor());
|
||||
}
|
||||
|
||||
TEST_F(SyntheticGestureControllerTest,
|
||||
TouchscreenTouchpadPinchGestureTouchZoomOut) {
|
||||
CreateControllerAndTarget<MockSyntheticTouchscreenPinchTouchTarget>();
|
||||
|
||||
SyntheticPinchGestureParams params;
|
||||
params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
|
||||
params.scale_factor = 0.4f;
|
||||
params.anchor.SetPoint(-12, 93);
|
||||
|
||||
scoped_ptr<SyntheticTouchscreenPinchGesture> gesture(
|
||||
new SyntheticTouchscreenPinchGesture(params));
|
||||
QueueSyntheticGesture(gesture.Pass());
|
||||
FlushInputUntilComplete();
|
||||
|
||||
MockSyntheticTouchscreenPinchTouchTarget* pinch_target =
|
||||
static_cast<MockSyntheticTouchscreenPinchTouchTarget*>(target_);
|
||||
EXPECT_EQ(1, num_success_);
|
||||
EXPECT_EQ(0, num_failure_);
|
||||
EXPECT_EQ(pinch_target->zoom_direction(),
|
||||
MockSyntheticTouchscreenPinchTouchTarget::ZOOM_OUT);
|
||||
EXPECT_FLOAT_EQ(params.scale_factor, pinch_target->ComputeScaleFactor());
|
||||
}
|
||||
|
||||
TEST_F(SyntheticGestureControllerTest,
|
||||
TouchscreenTouchpadPinchGestureTouchNoScaling) {
|
||||
CreateControllerAndTarget<MockSyntheticTouchscreenPinchTouchTarget>();
|
||||
|
||||
SyntheticPinchGestureParams params;
|
||||
params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
|
||||
params.scale_factor = 1.0f;
|
||||
|
||||
scoped_ptr<SyntheticTouchscreenPinchGesture> gesture(
|
||||
new SyntheticTouchscreenPinchGesture(params));
|
||||
QueueSyntheticGesture(gesture.Pass());
|
||||
FlushInputUntilComplete();
|
||||
|
||||
MockSyntheticTouchscreenPinchTouchTarget* pinch_target =
|
||||
static_cast<MockSyntheticTouchscreenPinchTouchTarget*>(target_);
|
||||
EXPECT_EQ(1, num_success_);
|
||||
EXPECT_EQ(0, num_failure_);
|
||||
EXPECT_EQ(pinch_target->zoom_direction(),
|
||||
MockSyntheticTouchscreenPinchTouchTarget::ZOOM_DIRECTION_UNKNOWN);
|
||||
EXPECT_EQ(params.scale_factor, pinch_target->ComputeScaleFactor());
|
||||
}
|
||||
|
||||
TEST_F(SyntheticGestureControllerTest, TouchpadPinchGestureTouchZoomIn) {
|
||||
CreateControllerAndTarget<MockSyntheticTouchpadPinchTouchTarget>();
|
||||
|
||||
SyntheticPinchGestureParams params;
|
||||
params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT;
|
||||
params.scale_factor = 2.3f;
|
||||
params.anchor.SetPoint(54, 89);
|
||||
|
||||
scoped_ptr<SyntheticTouchpadPinchGesture> gesture(
|
||||
new SyntheticTouchpadPinchGesture(params));
|
||||
QueueSyntheticGesture(gesture.Pass());
|
||||
FlushInputUntilComplete();
|
||||
|
||||
MockSyntheticTouchpadPinchTouchTarget* pinch_target =
|
||||
static_cast<MockSyntheticTouchpadPinchTouchTarget*>(target_);
|
||||
EXPECT_EQ(1, num_success_);
|
||||
EXPECT_EQ(0, num_failure_);
|
||||
EXPECT_EQ(pinch_target->zoom_direction(),
|
||||
MockSyntheticTouchpadPinchTouchTarget::ZOOM_IN);
|
||||
EXPECT_FLOAT_EQ(params.scale_factor, pinch_target->scale_factor());
|
||||
}
|
||||
|
||||
TEST_F(SyntheticGestureControllerTest, TouchpadPinchGestureTouchZoomOut) {
|
||||
CreateControllerAndTarget<MockSyntheticTouchpadPinchTouchTarget>();
|
||||
|
||||
SyntheticPinchGestureParams params;
|
||||
params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT;
|
||||
params.scale_factor = 0.4f;
|
||||
params.anchor.SetPoint(-12, 93);
|
||||
|
||||
scoped_ptr<SyntheticTouchpadPinchGesture> gesture(
|
||||
new SyntheticTouchpadPinchGesture(params));
|
||||
QueueSyntheticGesture(gesture.Pass());
|
||||
FlushInputUntilComplete();
|
||||
|
||||
MockSyntheticTouchpadPinchTouchTarget* pinch_target =
|
||||
static_cast<MockSyntheticTouchpadPinchTouchTarget*>(target_);
|
||||
EXPECT_EQ(1, num_success_);
|
||||
EXPECT_EQ(0, num_failure_);
|
||||
EXPECT_EQ(pinch_target->zoom_direction(),
|
||||
MockSyntheticTouchpadPinchTouchTarget::ZOOM_OUT);
|
||||
EXPECT_FLOAT_EQ(params.scale_factor, pinch_target->scale_factor());
|
||||
}
|
||||
|
||||
TEST_F(SyntheticGestureControllerTest, TouchpadPinchGestureTouchNoScaling) {
|
||||
CreateControllerAndTarget<MockSyntheticTouchpadPinchTouchTarget>();
|
||||
|
||||
SyntheticPinchGestureParams params;
|
||||
params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT;
|
||||
params.scale_factor = 1.0f;
|
||||
|
||||
scoped_ptr<SyntheticTouchpadPinchGesture> gesture(
|
||||
new SyntheticTouchpadPinchGesture(params));
|
||||
QueueSyntheticGesture(gesture.Pass());
|
||||
FlushInputUntilComplete();
|
||||
|
||||
MockSyntheticTouchpadPinchTouchTarget* pinch_target =
|
||||
static_cast<MockSyntheticTouchpadPinchTouchTarget*>(target_);
|
||||
EXPECT_EQ(1, num_success_);
|
||||
EXPECT_EQ(0, num_failure_);
|
||||
EXPECT_EQ(pinch_target->zoom_direction(),
|
||||
MockSyntheticTouchpadPinchTouchTarget::ZOOM_DIRECTION_UNKNOWN);
|
||||
EXPECT_EQ(params.scale_factor, pinch_target->scale_factor());
|
||||
}
|
||||
|
||||
// Ensure that if SyntheticPinchGesture is instantiated with TOUCH_INPUT it
|
||||
// correctly creates a touchscreen gesture.
|
||||
TEST_F(SyntheticGestureControllerTest, PinchGestureExplicitTouch) {
|
||||
CreateControllerAndTarget<MockSyntheticTouchscreenPinchTouchTarget>();
|
||||
|
||||
SyntheticPinchGestureParams params;
|
||||
params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
|
||||
@ -1112,54 +1316,62 @@ TEST_F(SyntheticGestureControllerTest, PinchGestureTouchZoomIn) {
|
||||
QueueSyntheticGesture(gesture.Pass());
|
||||
FlushInputUntilComplete();
|
||||
|
||||
MockSyntheticPinchTouchTarget* pinch_target =
|
||||
static_cast<MockSyntheticPinchTouchTarget*>(target_);
|
||||
EXPECT_EQ(1, num_success_);
|
||||
EXPECT_EQ(0, num_failure_);
|
||||
EXPECT_EQ(pinch_target->zoom_direction(),
|
||||
MockSyntheticPinchTouchTarget::ZOOM_IN);
|
||||
EXPECT_FLOAT_EQ(params.scale_factor, pinch_target->ComputeScaleFactor());
|
||||
// Gesture target will fail expectations if the wrong underlying
|
||||
// SyntheticPinch*Gesture was instantiated.
|
||||
}
|
||||
|
||||
TEST_F(SyntheticGestureControllerTest, PinchGestureTouchZoomOut) {
|
||||
CreateControllerAndTarget<MockSyntheticPinchTouchTarget>();
|
||||
// Ensure that if SyntheticPinchGesture is instantiated with MOUSE_INPUT it
|
||||
// correctly creates a touchpad gesture.
|
||||
TEST_F(SyntheticGestureControllerTest, PinchGestureExplicitMouse) {
|
||||
CreateControllerAndTarget<MockSyntheticTouchpadPinchTouchTarget>();
|
||||
|
||||
SyntheticPinchGestureParams params;
|
||||
params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
|
||||
params.scale_factor = 0.4f;
|
||||
params.anchor.SetPoint(-12, 93);
|
||||
params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT;
|
||||
params.scale_factor = 2.3f;
|
||||
params.anchor.SetPoint(54, 89);
|
||||
|
||||
scoped_ptr<SyntheticPinchGesture> gesture(new SyntheticPinchGesture(params));
|
||||
QueueSyntheticGesture(gesture.Pass());
|
||||
FlushInputUntilComplete();
|
||||
|
||||
MockSyntheticPinchTouchTarget* pinch_target =
|
||||
static_cast<MockSyntheticPinchTouchTarget*>(target_);
|
||||
EXPECT_EQ(1, num_success_);
|
||||
EXPECT_EQ(0, num_failure_);
|
||||
EXPECT_EQ(pinch_target->zoom_direction(),
|
||||
MockSyntheticPinchTouchTarget::ZOOM_OUT);
|
||||
EXPECT_FLOAT_EQ(params.scale_factor, pinch_target->ComputeScaleFactor());
|
||||
// Gesture target will fail expectations if the wrong underlying
|
||||
// SyntheticPinch*Gesture was instantiated.
|
||||
}
|
||||
|
||||
TEST_F(SyntheticGestureControllerTest, PinchGestureTouchNoScaling) {
|
||||
CreateControllerAndTarget<MockSyntheticPinchTouchTarget>();
|
||||
// Ensure that if SyntheticPinchGesture is instantiated with DEFAULT_INPUT it
|
||||
// correctly creates a touchscreen gesture for a touchscreen controller.
|
||||
TEST_F(SyntheticGestureControllerTest, PinchGestureDefaultTouch) {
|
||||
CreateControllerAndTarget<MockSyntheticTouchscreenPinchTouchTarget>();
|
||||
|
||||
SyntheticPinchGestureParams params;
|
||||
params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
|
||||
params.scale_factor = 1.0f;
|
||||
params.gesture_source_type = SyntheticGestureParams::DEFAULT_INPUT;
|
||||
params.scale_factor = 2.3f;
|
||||
params.anchor.SetPoint(54, 89);
|
||||
|
||||
scoped_ptr<SyntheticPinchGesture> gesture(new SyntheticPinchGesture(params));
|
||||
QueueSyntheticGesture(gesture.Pass());
|
||||
FlushInputUntilComplete();
|
||||
|
||||
MockSyntheticPinchTouchTarget* pinch_target =
|
||||
static_cast<MockSyntheticPinchTouchTarget*>(target_);
|
||||
EXPECT_EQ(1, num_success_);
|
||||
EXPECT_EQ(0, num_failure_);
|
||||
EXPECT_EQ(pinch_target->zoom_direction(),
|
||||
MockSyntheticPinchTouchTarget::ZOOM_DIRECTION_UNKNOWN);
|
||||
EXPECT_EQ(params.scale_factor, pinch_target->ComputeScaleFactor());
|
||||
// Gesture target will fail expectations if the wrong underlying
|
||||
// SyntheticPinch*Gesture was instantiated.
|
||||
}
|
||||
|
||||
// Ensure that if SyntheticPinchGesture is instantiated with DEFAULT_INPUT it
|
||||
// correctly creates a touchpad gesture for a touchpad controller.
|
||||
TEST_F(SyntheticGestureControllerTest, PinchGestureDefaultMouse) {
|
||||
CreateControllerAndTarget<MockSyntheticTouchpadPinchTouchTarget>();
|
||||
|
||||
SyntheticPinchGestureParams params;
|
||||
params.gesture_source_type = SyntheticGestureParams::DEFAULT_INPUT;
|
||||
params.scale_factor = 2.3f;
|
||||
params.anchor.SetPoint(54, 89);
|
||||
|
||||
scoped_ptr<SyntheticPinchGesture> gesture(new SyntheticPinchGesture(params));
|
||||
QueueSyntheticGesture(gesture.Pass());
|
||||
FlushInputUntilComplete();
|
||||
|
||||
// Gesture target will fail expectations if the wrong underlying
|
||||
// SyntheticPinch*Gesture was instantiated.
|
||||
}
|
||||
|
||||
TEST_F(SyntheticGestureControllerTest, TapGestureTouch) {
|
||||
|
@ -0,0 +1,31 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_GESTURE_TARGET_MAC_H_
|
||||
#define CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_GESTURE_TARGET_MAC_H_
|
||||
|
||||
#include "content/browser/renderer_host/input/synthetic_gesture_target_base.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_view_mac.h"
|
||||
#include "content/common/input/synthetic_gesture_params.h"
|
||||
|
||||
namespace content {
|
||||
|
||||
// SyntheticGestureTarget implementation for mac
|
||||
class SyntheticGestureTargetMac : public SyntheticGestureTargetBase {
|
||||
public:
|
||||
SyntheticGestureTargetMac(RenderWidgetHostImpl* host,
|
||||
RenderWidgetHostViewCocoa* cocoa_view);
|
||||
|
||||
// SyntheticGestureTarget:
|
||||
void DispatchInputEventToPlatform(const blink::WebInputEvent& event) override;
|
||||
|
||||
private:
|
||||
RenderWidgetHostViewCocoa* cocoa_view_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SyntheticGestureTargetMac);
|
||||
};
|
||||
|
||||
} // namespace content
|
||||
|
||||
#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_GESTURE_TARGET_MAC_H_
|
@ -0,0 +1,122 @@
|
||||
// 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 "content/browser/renderer_host/input/synthetic_gesture_target_mac.h"
|
||||
|
||||
#include "base/mac/scoped_nsautorelease_pool.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_impl.h"
|
||||
|
||||
// Unlike some event APIs, Apple does not provide a way to programmatically
|
||||
// build a zoom event. To work around this, we leverage ObjectiveC's flexible
|
||||
// typing and build up an object with the right interface to provide a zoom
|
||||
// event.
|
||||
@interface SyntheticPinchEvent : NSObject
|
||||
|
||||
// Populated based on desired zoom level.
|
||||
@property CGFloat magnification;
|
||||
@property NSPoint locationInWindow;
|
||||
@property NSEventType type;
|
||||
|
||||
// Filled with default values.
|
||||
@property(readonly) CGFloat deltaX;
|
||||
@property(readonly) CGFloat deltaY;
|
||||
@property(readonly) NSEventModifierFlags modifierFlags;
|
||||
@property(readonly) NSTimeInterval timestamp;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SyntheticPinchEvent
|
||||
|
||||
@synthesize magnification = magnification_;
|
||||
@synthesize locationInWindow = locationInWindow_;
|
||||
@synthesize type = type_;
|
||||
@synthesize deltaX = deltaX_;
|
||||
@synthesize deltaY = deltaY_;
|
||||
@synthesize modifierFlags = modifierFlags_;
|
||||
@synthesize timestamp = timestamp_;
|
||||
|
||||
- (id)initWithMagnification:(float)magnification
|
||||
locationInWindow:(NSPoint)location {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
type_ = NSEventTypeMagnify;
|
||||
magnification_ = magnification;
|
||||
locationInWindow_ = location;
|
||||
|
||||
deltaX_ = 0;
|
||||
deltaY_ = 0;
|
||||
modifierFlags_ = 0;
|
||||
|
||||
// Default timestamp to current time.
|
||||
timestamp_ = [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)eventWithMagnification:(float)magnification
|
||||
locationInWindow:(NSPoint)location {
|
||||
SyntheticPinchEvent* event =
|
||||
[[SyntheticPinchEvent alloc] initWithMagnification:magnification
|
||||
locationInWindow:location];
|
||||
return [event autorelease];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
using blink::WebInputEvent;
|
||||
using blink::WebGestureEvent;
|
||||
|
||||
namespace content {
|
||||
|
||||
SyntheticGestureTargetMac::SyntheticGestureTargetMac(
|
||||
RenderWidgetHostImpl* host,
|
||||
RenderWidgetHostViewCocoa* cocoa_view)
|
||||
: SyntheticGestureTargetBase(host), cocoa_view_(cocoa_view) {}
|
||||
|
||||
void SyntheticGestureTargetMac::DispatchInputEventToPlatform(
|
||||
const WebInputEvent& event) {
|
||||
if (WebInputEvent::isGestureEventType(event.type)) {
|
||||
// Create an autorelease pool so that we clean up any synthetic events we
|
||||
// generate.
|
||||
base::mac::ScopedNSAutoreleasePool pool;
|
||||
|
||||
const WebGestureEvent* gesture_event =
|
||||
static_cast<const WebGestureEvent*>(&event);
|
||||
|
||||
switch (event.type) {
|
||||
case WebInputEvent::GesturePinchBegin: {
|
||||
id event = [SyntheticPinchEvent
|
||||
eventWithMagnification:0.0f
|
||||
locationInWindow:NSMakePoint(gesture_event->x,
|
||||
gesture_event->y)];
|
||||
[cocoa_view_ beginGestureWithEvent:event];
|
||||
return;
|
||||
}
|
||||
case WebInputEvent::GesturePinchEnd: {
|
||||
id event = [SyntheticPinchEvent
|
||||
eventWithMagnification:0.0f
|
||||
locationInWindow:NSMakePoint(gesture_event->x,
|
||||
gesture_event->y)];
|
||||
[cocoa_view_ endGestureWithEvent:event];
|
||||
return;
|
||||
}
|
||||
case WebInputEvent::GesturePinchUpdate: {
|
||||
id event = [SyntheticPinchEvent
|
||||
eventWithMagnification:gesture_event->data.pinchUpdate.scale - 1.0f
|
||||
locationInWindow:NSMakePoint(gesture_event->x,
|
||||
gesture_event->y)];
|
||||
[cocoa_view_ magnifyWithEvent:event];
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// This event wasn't handled yet, forward to the base class.
|
||||
SyntheticGestureTargetBase::DispatchInputEventToPlatform(event);
|
||||
}
|
||||
|
||||
} // namespace content
|
@ -1,165 +1,39 @@
|
||||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// 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 "content/browser/renderer_host/input/synthetic_pinch_gesture.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "ui/events/latency_info.h"
|
||||
#include "content/browser/renderer_host/input/synthetic_touchpad_pinch_gesture.h"
|
||||
#include "content/browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.h"
|
||||
|
||||
namespace content {
|
||||
|
||||
SyntheticPinchGesture::SyntheticPinchGesture(
|
||||
const SyntheticPinchGestureParams& params)
|
||||
: params_(params),
|
||||
start_y_0_(0.0f),
|
||||
start_y_1_(0.0f),
|
||||
max_pointer_delta_0_(0.0f),
|
||||
gesture_source_type_(SyntheticGestureParams::DEFAULT_INPUT),
|
||||
state_(SETUP) {
|
||||
DCHECK_GT(params_.scale_factor, 0.0f);
|
||||
}
|
||||
|
||||
: params_(params) {}
|
||||
SyntheticPinchGesture::~SyntheticPinchGesture() {}
|
||||
|
||||
SyntheticGesture::Result SyntheticPinchGesture::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::TOUCH_INPUT)
|
||||
ForwardTouchInputEvents(timestamp, target);
|
||||
else
|
||||
return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
|
||||
|
||||
return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED
|
||||
: SyntheticGesture::GESTURE_RUNNING;
|
||||
}
|
||||
|
||||
void SyntheticPinchGesture::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.";
|
||||
case DONE:
|
||||
NOTREACHED() << "State DONE invalid for synthetic pinch.";
|
||||
}
|
||||
}
|
||||
|
||||
void SyntheticPinchGesture::PressTouchPoints(SyntheticGestureTarget* target,
|
||||
const base::TimeTicks& timestamp) {
|
||||
touch_event_.PressPoint(params_.anchor.x(), start_y_0_);
|
||||
touch_event_.PressPoint(params_.anchor.x(), start_y_1_);
|
||||
ForwardTouchEvent(target, timestamp);
|
||||
}
|
||||
|
||||
void SyntheticPinchGesture::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;
|
||||
|
||||
touch_event_.MovePoint(0, params_.anchor.x(), current_y_0);
|
||||
touch_event_.MovePoint(1, params_.anchor.x(), current_y_1);
|
||||
ForwardTouchEvent(target, timestamp);
|
||||
}
|
||||
|
||||
void SyntheticPinchGesture::ReleaseTouchPoints(
|
||||
SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
|
||||
touch_event_.ReleasePoint(0);
|
||||
touch_event_.ReleasePoint(1);
|
||||
ForwardTouchEvent(target, timestamp);
|
||||
}
|
||||
|
||||
void SyntheticPinchGesture::ForwardTouchEvent(
|
||||
SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
|
||||
touch_event_.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
|
||||
target->DispatchInputEventToPlatform(touch_event_);
|
||||
}
|
||||
|
||||
void SyntheticPinchGesture::SetupCoordinatesAndStopTime(
|
||||
const base::TimeTicks& timestamp,
|
||||
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;
|
||||
if (params_.scale_factor > 1.0f) { // zooming in
|
||||
initial_distance_to_anchor = target->GetMinScalingSpanInDips() / 2.0f;
|
||||
final_distance_to_anchor =
|
||||
(initial_distance_to_anchor + target->GetTouchSlopInDips()) *
|
||||
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) +
|
||||
target->GetTouchSlopInDips();
|
||||
if (!lazy_gesture_) {
|
||||
SyntheticGestureParams::GestureSourceType source_type =
|
||||
params_.gesture_source_type;
|
||||
if (source_type == SyntheticGestureParams::DEFAULT_INPUT) {
|
||||
source_type = target->GetDefaultSyntheticGestureSourceType();
|
||||
}
|
||||
|
||||
DCHECK_NE(SyntheticGestureParams::DEFAULT_INPUT, source_type);
|
||||
if (source_type == SyntheticGestureParams::TOUCH_INPUT) {
|
||||
lazy_gesture_.reset(new SyntheticTouchscreenPinchGesture(params_));
|
||||
} else {
|
||||
DCHECK_EQ(SyntheticGestureParams::MOUSE_INPUT, source_type);
|
||||
lazy_gesture_.reset(new SyntheticTouchpadPinchGesture(params_));
|
||||
}
|
||||
}
|
||||
|
||||
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 total_duration_in_us = static_cast<int64>(
|
||||
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::TimeDelta::FromMicroseconds(total_duration_in_us);
|
||||
}
|
||||
|
||||
float SyntheticPinchGesture::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 SyntheticPinchGesture::ClampTimestamp(
|
||||
const base::TimeTicks& timestamp) const {
|
||||
return std::min(timestamp, stop_time_);
|
||||
}
|
||||
|
||||
bool SyntheticPinchGesture::HasReachedTarget(const base::TimeTicks& timestamp)
|
||||
const {
|
||||
return timestamp >= stop_time_;
|
||||
return lazy_gesture_->ForwardInputEvents(timestamp, target);
|
||||
}
|
||||
|
||||
} // namespace content
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// 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.
|
||||
|
||||
@ -10,11 +10,13 @@
|
||||
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
|
||||
#include "content/common/content_export.h"
|
||||
#include "content/common/input/synthetic_pinch_gesture_params.h"
|
||||
#include "content/common/input/synthetic_web_input_event_builders.h"
|
||||
#include "third_party/WebKit/public/web/WebInputEvent.h"
|
||||
|
||||
namespace content {
|
||||
|
||||
// SyntheticPinchGesture is a thin wrapper around either
|
||||
// SyntheticTouchscreenPinchGesture or SyntheticTouchpadPinchGesture, depending
|
||||
// on the SyntheticGestureParam's |input_type| and the default input type of the
|
||||
// target.
|
||||
class CONTENT_EXPORT SyntheticPinchGesture : public SyntheticGesture {
|
||||
public:
|
||||
explicit SyntheticPinchGesture(const SyntheticPinchGestureParams& params);
|
||||
@ -25,42 +27,9 @@ class CONTENT_EXPORT SyntheticPinchGesture : public SyntheticGesture {
|
||||
SyntheticGestureTarget* target) override;
|
||||
|
||||
private:
|
||||
enum GestureState {
|
||||
SETUP,
|
||||
STARTED,
|
||||
MOVING,
|
||||
DONE
|
||||
};
|
||||
|
||||
void ForwardTouchInputEvents(const base::TimeTicks& timestamp,
|
||||
SyntheticGestureTarget* target);
|
||||
|
||||
void UpdateTouchPoints(const base::TimeTicks& timestamp);
|
||||
void PressTouchPoints(SyntheticGestureTarget* target,
|
||||
const base::TimeTicks& timestamp);
|
||||
void MoveTouchPoints(SyntheticGestureTarget* target, float delta,
|
||||
const base::TimeTicks& timestamp);
|
||||
void ReleaseTouchPoints(SyntheticGestureTarget* target,
|
||||
const base::TimeTicks& timestamp);
|
||||
void ForwardTouchEvent(SyntheticGestureTarget* target,
|
||||
const base::TimeTicks& timestamp);
|
||||
|
||||
void SetupCoordinatesAndStopTime(SyntheticGestureTarget* target);
|
||||
float GetDeltaForPointer0AtTime(const base::TimeTicks& timestamp) const;
|
||||
base::TimeTicks ClampTimestamp(const base::TimeTicks& timestamp) const;
|
||||
bool HasReachedTarget(const base::TimeTicks& timestamp) const;
|
||||
|
||||
SyntheticPinchGestureParams params_;
|
||||
float start_y_0_;
|
||||
float start_y_1_;
|
||||
float max_pointer_delta_0_;
|
||||
SyntheticGestureParams::GestureSourceType gesture_source_type_;
|
||||
GestureState state_;
|
||||
SyntheticWebTouchEvent touch_event_;
|
||||
base::TimeTicks start_time_;
|
||||
base::TimeTicks stop_time_;
|
||||
scoped_ptr<SyntheticGesture> lazy_gesture_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(SyntheticPinchGesture);
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,150 @@
|
||||
// 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 "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::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::GesturePinchBegin,
|
||||
blink::WebGestureDeviceTouchpad));
|
||||
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::WebGestureDeviceTouchpad));
|
||||
|
||||
if (HasReachedTarget(event_timestamp)) {
|
||||
target->DispatchInputEventToPlatform(
|
||||
SyntheticWebGestureEventBuilder::Build(
|
||||
blink::WebGestureEvent::GesturePinchEnd,
|
||||
blink::WebGestureDeviceTouchpad));
|
||||
state_ = DONE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SETUP:
|
||||
NOTREACHED() << "State SETUP invalid for synthetic pinch.";
|
||||
case DONE:
|
||||
NOTREACHED() << "State DONE invalid for synthetic pinch.";
|
||||
}
|
||||
}
|
||||
|
||||
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 total_duration_in_us =
|
||||
static_cast<int64>(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
|
@ -0,0 +1,54 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_TOUCHPAD_PINCH_GESTURE_H_
|
||||
#define CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_TOUCHPAD_PINCH_GESTURE_H_
|
||||
|
||||
#include "base/time/time.h"
|
||||
#include "content/browser/renderer_host/input/synthetic_gesture.h"
|
||||
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
|
||||
#include "content/common/content_export.h"
|
||||
#include "content/common/input/synthetic_pinch_gesture_params.h"
|
||||
#include "content/common/input/synthetic_web_input_event_builders.h"
|
||||
#include "third_party/WebKit/public/web/WebInputEvent.h"
|
||||
|
||||
namespace content {
|
||||
|
||||
class CONTENT_EXPORT SyntheticTouchpadPinchGesture : public SyntheticGesture {
|
||||
public:
|
||||
explicit SyntheticTouchpadPinchGesture(
|
||||
const SyntheticPinchGestureParams& params);
|
||||
~SyntheticTouchpadPinchGesture() override;
|
||||
|
||||
SyntheticGesture::Result ForwardInputEvents(
|
||||
const base::TimeTicks& timestamp,
|
||||
SyntheticGestureTarget* target) override;
|
||||
|
||||
private:
|
||||
enum GestureState { SETUP, STARTED, IN_PROGRESS, DONE };
|
||||
|
||||
void ForwardGestureEvents(const base::TimeTicks& timestamp,
|
||||
SyntheticGestureTarget* target);
|
||||
|
||||
void UpdateTouchPoints(const base::TimeTicks& timestamp);
|
||||
|
||||
void CalculateEndTime(SyntheticGestureTarget* target);
|
||||
float CalculateTargetScale(const base::TimeTicks& timestamp) const;
|
||||
base::TimeTicks ClampTimestamp(const base::TimeTicks& timestamp) const;
|
||||
bool HasReachedTarget(const base::TimeTicks& timestamp) const;
|
||||
|
||||
SyntheticPinchGestureParams params_;
|
||||
SyntheticGestureParams::GestureSourceType gesture_source_type_;
|
||||
GestureState state_;
|
||||
base::TimeTicks start_time_;
|
||||
base::TimeTicks stop_time_;
|
||||
float current_scale_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(SyntheticTouchpadPinchGesture);
|
||||
};
|
||||
|
||||
} // namespace content
|
||||
|
||||
#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_TOUCHPAD_PINCH_GESTURE_H_
|
@ -0,0 +1,172 @@
|
||||
// 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 <cmath>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "ui/events/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_(SyntheticGestureParams::DEFAULT_INPUT),
|
||||
state_(SETUP) {
|
||||
DCHECK_GT(params_.scale_factor, 0.0f);
|
||||
}
|
||||
|
||||
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_ == 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::TOUCH_INPUT) {
|
||||
ForwardTouchInputEvents(timestamp, target);
|
||||
} else {
|
||||
return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED
|
||||
: SyntheticGesture::GESTURE_RUNNING;
|
||||
}
|
||||
|
||||
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.";
|
||||
case DONE:
|
||||
NOTREACHED() << "State DONE invalid for synthetic pinch.";
|
||||
}
|
||||
}
|
||||
|
||||
void SyntheticTouchscreenPinchGesture::PressTouchPoints(
|
||||
SyntheticGestureTarget* target,
|
||||
const base::TimeTicks& timestamp) {
|
||||
touch_event_.PressPoint(params_.anchor.x(), start_y_0_);
|
||||
touch_event_.PressPoint(params_.anchor.x(), start_y_1_);
|
||||
ForwardTouchEvent(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;
|
||||
|
||||
touch_event_.MovePoint(0, params_.anchor.x(), current_y_0);
|
||||
touch_event_.MovePoint(1, params_.anchor.x(), current_y_1);
|
||||
ForwardTouchEvent(target, timestamp);
|
||||
}
|
||||
|
||||
void SyntheticTouchscreenPinchGesture::ReleaseTouchPoints(
|
||||
SyntheticGestureTarget* target,
|
||||
const base::TimeTicks& timestamp) {
|
||||
touch_event_.ReleasePoint(0);
|
||||
touch_event_.ReleasePoint(1);
|
||||
ForwardTouchEvent(target, timestamp);
|
||||
}
|
||||
|
||||
void SyntheticTouchscreenPinchGesture::ForwardTouchEvent(
|
||||
SyntheticGestureTarget* target,
|
||||
const base::TimeTicks& timestamp) {
|
||||
touch_event_.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
|
||||
target->DispatchInputEventToPlatform(touch_event_);
|
||||
}
|
||||
|
||||
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;
|
||||
if (params_.scale_factor > 1.0f) { // zooming in
|
||||
initial_distance_to_anchor = target->GetMinScalingSpanInDips() / 2.0f;
|
||||
final_distance_to_anchor =
|
||||
(initial_distance_to_anchor + target->GetTouchSlopInDips()) *
|
||||
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) +
|
||||
target->GetTouchSlopInDips();
|
||||
}
|
||||
|
||||
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 total_duration_in_us = static_cast<int64>(
|
||||
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::TimeDelta::FromMicroseconds(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
|
@ -0,0 +1,67 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_TOUCHSCREEN_PINCH_GESTURE_H_
|
||||
#define CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_TOUCHSCREEN_PINCH_GESTURE_H_
|
||||
|
||||
#include "base/time/time.h"
|
||||
#include "content/browser/renderer_host/input/synthetic_gesture.h"
|
||||
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
|
||||
#include "content/common/content_export.h"
|
||||
#include "content/common/input/synthetic_pinch_gesture_params.h"
|
||||
#include "content/common/input/synthetic_web_input_event_builders.h"
|
||||
#include "third_party/WebKit/public/web/WebInputEvent.h"
|
||||
|
||||
namespace content {
|
||||
|
||||
class CONTENT_EXPORT SyntheticTouchscreenPinchGesture
|
||||
: public SyntheticGesture {
|
||||
public:
|
||||
explicit SyntheticTouchscreenPinchGesture(
|
||||
const SyntheticPinchGestureParams& params);
|
||||
~SyntheticTouchscreenPinchGesture() override;
|
||||
|
||||
SyntheticGesture::Result ForwardInputEvents(
|
||||
const base::TimeTicks& timestamp,
|
||||
SyntheticGestureTarget* target) override;
|
||||
|
||||
private:
|
||||
enum GestureState { SETUP, STARTED, MOVING, DONE };
|
||||
|
||||
void ForwardTouchInputEvents(const base::TimeTicks& timestamp,
|
||||
SyntheticGestureTarget* target);
|
||||
|
||||
void UpdateTouchPoints(const base::TimeTicks& timestamp);
|
||||
void PressTouchPoints(SyntheticGestureTarget* target,
|
||||
const base::TimeTicks& timestamp);
|
||||
void MoveTouchPoints(SyntheticGestureTarget* target,
|
||||
float delta,
|
||||
const base::TimeTicks& timestamp);
|
||||
void ReleaseTouchPoints(SyntheticGestureTarget* target,
|
||||
const base::TimeTicks& timestamp);
|
||||
void ForwardTouchEvent(SyntheticGestureTarget* target,
|
||||
const base::TimeTicks& timestamp);
|
||||
|
||||
void SetupCoordinatesAndStopTime(SyntheticGestureTarget* target);
|
||||
float GetDeltaForPointer0AtTime(const base::TimeTicks& timestamp) const;
|
||||
base::TimeTicks ClampTimestamp(const base::TimeTicks& timestamp) const;
|
||||
bool HasReachedTarget(const base::TimeTicks& timestamp) const;
|
||||
|
||||
SyntheticPinchGestureParams params_;
|
||||
float start_y_0_;
|
||||
float start_y_1_;
|
||||
float max_pointer_delta_0_;
|
||||
SyntheticGestureParams::GestureSourceType gesture_source_type_;
|
||||
GestureState state_;
|
||||
SyntheticWebTouchEvent touch_event_;
|
||||
base::TimeTicks start_time_;
|
||||
base::TimeTicks stop_time_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(SyntheticTouchscreenPinchGesture);
|
||||
};
|
||||
|
||||
} // namespace content
|
||||
|
||||
#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_SYNTHETIC_TOUCHSCREEN_PINCH_GESTURE_H_
|
@ -342,6 +342,8 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
|
||||
void WheelEventAck(const blink::WebMouseWheelEvent& event,
|
||||
InputEventAckState ack_result) override;
|
||||
|
||||
scoped_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget() override;
|
||||
|
||||
uint32_t GetSurfaceIdNamespace() override;
|
||||
uint32_t SurfaceIdNamespaceAtPoint(const gfx::Point& point,
|
||||
gfx::Point* transformed_point) override;
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "content/browser/renderer_host/render_widget_helper.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_delegate.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
|
||||
#import "content/browser/renderer_host/input/synthetic_gesture_target_mac.h"
|
||||
#import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h"
|
||||
#import "content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h"
|
||||
#include "content/browser/renderer_host/render_widget_resize_helper_mac.h"
|
||||
@ -1638,6 +1639,14 @@ void RenderWidgetHostViewMac::WheelEventAck(
|
||||
[cocoa_view_ processedWheelEvent:event consumed:consumed];
|
||||
}
|
||||
|
||||
scoped_ptr<SyntheticGestureTarget>
|
||||
RenderWidgetHostViewMac::CreateSyntheticGestureTarget() {
|
||||
RenderWidgetHostImpl* host =
|
||||
RenderWidgetHostImpl::From(GetRenderWidgetHost());
|
||||
return scoped_ptr<SyntheticGestureTarget>(
|
||||
new SyntheticGestureTargetMac(host, cocoa_view_));
|
||||
}
|
||||
|
||||
uint32_t RenderWidgetHostViewMac::GetSurfaceIdNamespace() {
|
||||
DCHECK(delegated_frame_host_);
|
||||
return delegated_frame_host_->GetSurfaceIdNamespace();
|
||||
|
@ -1199,8 +1199,14 @@
|
||||
'browser/renderer_host/input/synthetic_gesture_target_aura.h',
|
||||
'browser/renderer_host/input/synthetic_gesture_target_base.cc',
|
||||
'browser/renderer_host/input/synthetic_gesture_target_base.h',
|
||||
'browser/renderer_host/input/synthetic_gesture_target_mac.mm',
|
||||
'browser/renderer_host/input/synthetic_gesture_target_mac.h',
|
||||
'browser/renderer_host/input/synthetic_pinch_gesture.cc',
|
||||
'browser/renderer_host/input/synthetic_pinch_gesture.h',
|
||||
'browser/renderer_host/input/synthetic_touchpad_pinch_gesture.cc',
|
||||
'browser/renderer_host/input/synthetic_touchpad_pinch_gesture.h',
|
||||
'browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.cc',
|
||||
'browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.h',
|
||||
'browser/renderer_host/input/synthetic_smooth_drag_gesture.cc',
|
||||
'browser/renderer_host/input/synthetic_smooth_drag_gesture.h',
|
||||
'browser/renderer_host/input/synthetic_smooth_move_gesture.cc',
|
||||
|
@ -250,7 +250,7 @@ class SmoothnessFlingSimpleMobilePages(perf_benchmark.PerfBenchmark):
|
||||
return 'smoothness.fling.simple_mobile_sites'
|
||||
|
||||
|
||||
@benchmark.Enabled('android', 'chromeos')
|
||||
@benchmark.Enabled('android', 'chromeos', 'mac')
|
||||
class SmoothnessToughPinchZoomCases(perf_benchmark.PerfBenchmark):
|
||||
"""Measures rendering statistics for pinch-zooming into the tough pinch zoom
|
||||
cases.
|
||||
|
@ -43,15 +43,6 @@ class PinchAction(page_action.PageAction):
|
||||
'This version of the browser doesn\'t support the new JS interface '
|
||||
'for pinch gestures.')
|
||||
|
||||
if (self._synthetic_gesture_source ==
|
||||
'chrome.gpuBenchmarking.MOUSE_INPUT'):
|
||||
raise page_action.PageActionNotSupported(
|
||||
'Pinch page action does not support mouse input')
|
||||
|
||||
if not page_action.IsGestureSourceTypeSupported(tab, 'touch'):
|
||||
raise page_action.PageActionNotSupported(
|
||||
'Touch input not supported for this browser')
|
||||
|
||||
done_callback = 'function() { window.__pinchActionDone = true; }'
|
||||
tab.ExecuteJavaScript("""
|
||||
window.__pinchActionDone = false;
|
||||
|
Reference in New Issue
Block a user