blob: a4fcd346a2b96c45ea6ac687e7026993d5255d31 [file] [log] [blame]
// Copyright 2016 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 THIRD_PARTY_BLINK_PUBLIC_COMMON_INPUT_WEB_GESTURE_EVENT_H_
#define THIRD_PARTY_BLINK_PUBLIC_COMMON_INPUT_WEB_GESTURE_EVENT_H_
#include <memory>
#include "base/check.h"
#include "base/notreached.h"
#include "cc/paint/element_id.h"
#include "third_party/blink/public/common/input/web_gesture_device.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/input/web_pointer_properties.h"
#include "third_party/blink/public/mojom/input/gesture_event.mojom-shared.h"
#include "ui/events/types/scroll_types.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/size_f.h"
namespace blink {
// WebGestureEvent ---------------------------------------------------------
class BLINK_COMMON_EXPORT WebGestureEvent : public WebInputEvent {
public:
using InertialPhaseState = mojom::InertialPhaseState;
bool is_source_touch_event_set_blocking = false;
// The pointer type for the first touch point in the gesture.
WebPointerProperties::PointerType primary_pointer_type =
WebPointerProperties::PointerType::kUnknown;
// If the WebGestureEvent has source_device ==
// mojom::GestureDevice::kTouchscreen, this field contains the unique
// identifier for the touch event that released this event at
// TouchDispositionGestureFilter. If the WebGestureEvents was not released
// through a touch event (e.g. timer-released gesture events or gesture events
// with source_device != mojom::GestureDevice::kTouchscreen), the field
// contains 0. See crbug.com/618738.
uint32_t unique_touch_event_id = 0;
union {
// Tap information must be set for GestureTap, GestureTapUnconfirmed,
// and GestureDoubleTap events.
struct {
int tap_count;
float width;
float height;
// |needs_wheel_event| for touchpad GestureDoubleTap has the same
// semantics as |needs_wheel_event| for touchpad pinch described below.
bool needs_wheel_event;
} tap;
struct {
float width;
float height;
} tap_down;
struct {
float width;
float height;
} show_press;
// This is used for both GestureLongPress and GestureLongTap.
struct {
float width;
float height;
} long_press;
struct {
float first_finger_width;
float first_finger_height;
} two_finger_tap;
struct {
// If set, used to target a scrollable area directly instead of performing
// a hit-test. Should be used for gestures queued up internally within
// the renderer process. This is an ElementIdType instead of ElementId
// due to the fact that ElementId has a non-trivial constructor that
// can't easily participate in this union of structs. Note that while
// this is used in scroll unification to perform a main thread hit test,
// in which case |main_thread_hit_tested| is true, it is also used in
// other cases like scroll events reinjected for scrollbar scrolling.
cc::ElementIdType scrollable_area_element_id;
// Initial motion that triggered the scroll.
float delta_x_hint;
float delta_y_hint;
// number of pointers down.
int pointer_count;
// Default initialized to kScrollByPrecisePixel.
ui::ScrollGranularity delta_hint_units;
// The state of inertial phase scrolling. OSX has unique phases for normal
// and momentum scroll events. Should always be kUnknownMomentumPhase for
// touch based input as it generates GestureFlingStart instead.
InertialPhaseState inertial_phase;
// If true, this event will skip hit testing to find a scroll
// target and instead just scroll the viewport.
bool target_viewport;
// True if this event is generated from a wheel event with synthetic
// phase.
bool synthetic;
// If true, this event has been hit tested by the main thread and the
// result is stored in scrollable_area_element_id. Used only in scroll
// unification when the event is sent back the the compositor for a
// second time after the main thread hit test is complete.
bool main_thread_hit_tested;
// If true, this event will be used for cursor control instead of
// scrolling. the entire scroll sequence will be used for cursor control.
bool cursor_control;
} scroll_begin;
struct {
float delta_x;
float delta_y;
float velocity_x;
float velocity_y;
InertialPhaseState inertial_phase;
// Default initialized to kScrollByPrecisePixel.
ui::ScrollGranularity delta_units;
} scroll_update;
struct {
// The original delta units the ScrollBegin and ScrollUpdates
// were sent as.
ui::ScrollGranularity delta_units;
// The state of inertial phase scrolling. OSX has unique phases for normal
// and momentum scroll events. Should always be kUnknownMomentumPhase for
// touch based input as it generates GestureFlingStart instead.
InertialPhaseState inertial_phase;
// True if this event is generated from a wheel event with synthetic
// phase.
bool synthetic;
// True if this event is generated by the fling controller. The GSE
// generated at the end of a fling should not get pushed to the
// debouncing_deferral_queue_. This attribute is not mojofied and will not
// get transferred across since it is only used on the browser.
bool generated_by_fling_controller;
} scroll_end;
struct {
float velocity_x;
float velocity_y;
// If true, this event will skip hit testing to find a scroll
// target and instead just scroll the viewport.
bool target_viewport;
} fling_start;
struct {
bool target_viewport;
// If set to true, don't treat fling_cancel
// as a part of fling boost events sequence.
bool prevent_boosting;
} fling_cancel;
// Note that for the pinch event types, |needs_wheel_event| and
// |zoom_disabled| are browser side implementation details for touchpad
// pinch zoom. From the renderer's perspective, both are always false.
// TODO(mcnee): Remove these implementation details once the browser has its
// own representation of a touchpad pinch event. See
// https://crbug.com/563730
struct {
// |needs_wheel_event| is used to indicate the phase of handling a
// touchpad pinch. When the event is created it is set to true, so that
// the InputRouter knows to offer the event to the renderer as a wheel
// event. Once the wheel event is acknowledged, |needs_wheel_event| is set
// to false and the event is resent. When the InputRouter receives it the
// second time, it knows to send the real gesture event to the renderer.
bool needs_wheel_event;
// If true, this event will not cause a change in page scale, but will
// still be offered as a wheel event to any handlers.
bool zoom_disabled;
float scale;
} pinch_update;
struct {
bool needs_wheel_event;
} pinch_begin;
struct {
bool needs_wheel_event;
} pinch_end;
} data;
private:
// Widget coordinate, which is relative to the bound of current RenderWidget
// (e.g. a plugin or OOPIF inside a RenderView). Similar to viewport
// coordinates but without DevTools emulation transform or overscroll applied.
gfx::PointF position_in_widget_;
// Screen coordinate
gfx::PointF position_in_screen_;
mojom::GestureDevice source_device_ = mojom::GestureDevice::kUninitialized;
public:
WebGestureEvent(
Type type,
int modifiers,
base::TimeTicks time_stamp,
mojom::GestureDevice device = mojom::GestureDevice::kUninitialized)
: WebInputEvent(type, modifiers, time_stamp), source_device_(device) {
memset(&data, 0, sizeof(data));
}
WebGestureEvent() { memset(&data, 0, sizeof(data)); }
const gfx::PointF& PositionInWidget() const { return position_in_widget_; }
const gfx::PointF& PositionInScreen() const { return position_in_screen_; }
std::unique_ptr<WebInputEvent> Clone() const override;
bool CanCoalesce(const WebInputEvent& event) const override;
void Coalesce(const WebInputEvent& event) override;
base::Optional<ui::ScrollInputType> GetScrollInputType() const override;
void SetPositionInWidget(const gfx::PointF& point) {
position_in_widget_ = point;
}
void SetPositionInScreen(const gfx::PointF& point) {
position_in_screen_ = point;
}
mojom::GestureDevice SourceDevice() const { return source_device_; }
void SetSourceDevice(mojom::GestureDevice device) { source_device_ = device; }
float DeltaXInRootFrame() const;
float DeltaYInRootFrame() const;
ui::ScrollGranularity DeltaUnits() const;
gfx::PointF PositionInRootFrame() const;
InertialPhaseState InertialPhase() const;
bool Synthetic() const;
float VelocityX() const;
float VelocityY() const;
gfx::SizeF TapAreaInRootFrame() const;
int TapCount() const;
void ApplyTouchAdjustment(const gfx::PointF& root_frame_coords);
// Sets any scaled values to be their computed values and sets |frame_scale_|
// back to 1 and |frame_translate_| X and Y coordinates back to 0.
void FlattenTransform();
bool IsScrollEvent() const {
switch (type_) {
case Type::kGestureScrollBegin:
case Type::kGestureScrollEnd:
case Type::kGestureScrollUpdate:
case Type::kGestureFlingStart:
case Type::kGestureFlingCancel:
case Type::kGesturePinchBegin:
case Type::kGesturePinchEnd:
case Type::kGesturePinchUpdate:
return true;
case Type::kGestureTap:
case Type::kGestureTapUnconfirmed:
case Type::kGestureTapDown:
case Type::kGestureShowPress:
case Type::kGestureTapCancel:
case Type::kGestureTwoFingerTap:
case Type::kGestureLongPress:
case Type::kGestureLongTap:
return false;
default:
NOTREACHED();
return false;
}
}
bool IsTargetViewport() const {
switch (type_) {
case Type::kGestureScrollBegin:
return data.scroll_begin.target_viewport;
case Type::kGestureFlingStart:
return data.fling_start.target_viewport;
case Type::kGestureFlingCancel:
return data.fling_cancel.target_viewport;
default:
return false;
}
}
bool IsTouchpadZoomEvent() const {
// Touchpad GestureDoubleTap also causes a page scale change like a touchpad
// pinch gesture.
return source_device_ == mojom::GestureDevice::kTouchpad &&
(WebInputEvent::IsPinchGestureEventType(type_) ||
type_ == Type::kGestureDoubleTap);
}
bool NeedsWheelEvent() const {
DCHECK(IsTouchpadZoomEvent());
switch (type_) {
case Type::kGesturePinchBegin:
return data.pinch_begin.needs_wheel_event;
case Type::kGesturePinchUpdate:
return data.pinch_update.needs_wheel_event;
case Type::kGesturePinchEnd:
return data.pinch_end.needs_wheel_event;
case Type::kGestureDoubleTap:
return data.tap.needs_wheel_event;
default:
NOTREACHED();
return false;
}
}
void SetNeedsWheelEvent(bool needs_wheel_event) {
DCHECK(!needs_wheel_event || IsTouchpadZoomEvent());
switch (type_) {
case Type::kGesturePinchBegin:
data.pinch_begin.needs_wheel_event = needs_wheel_event;
break;
case Type::kGesturePinchUpdate:
data.pinch_update.needs_wheel_event = needs_wheel_event;
break;
case Type::kGesturePinchEnd:
data.pinch_end.needs_wheel_event = needs_wheel_event;
break;
case Type::kGestureDoubleTap:
data.tap.needs_wheel_event = needs_wheel_event;
break;
default:
break;
}
}
// Coalesce the |new_event| with |last_event| and optionally
// |second_last_event|. Scroll and pinch are two separate gestures so they
// would need separate events that is why this method returns a pair.
static std::pair<std::unique_ptr<WebGestureEvent>,
std::unique_ptr<WebGestureEvent>>
CoalesceScrollAndPinch(const WebGestureEvent* second_last_event,
const WebGestureEvent& last_event,
const WebGestureEvent& new_event);
// Whether |event_in_queue| is a touchscreen GesturePinchUpdate or
// GestureScrollUpdate and has the same modifiers/source as the new
// scroll/pinch event. Compatible touchscreen scroll and pinch event pairs
// can be logically coalesced.
static bool IsCompatibleScrollorPinch(const WebGestureEvent& new_event,
const WebGestureEvent& event_in_queue);
// Generate a scroll gesture event (begin, update, or end), based on the
// parameters passed in. Populates the data field of the created
// WebGestureEvent based on the type.
static std::unique_ptr<blink::WebGestureEvent> GenerateInjectedScrollGesture(
WebInputEvent::Type type,
base::TimeTicks timestamp,
WebGestureDevice device,
gfx::PointF position_in_widget,
gfx::Vector2dF scroll_delta,
ui::ScrollGranularity granularity);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_INPUT_WEB_GESTURE_EVENT_H_