Add multi-touch support for OSR (issue #1059)

This commit is contained in:
Riku Palomäki 2019-02-25 16:17:28 -05:00 committed by Marshall Greenblatt
parent 4a3a9c8c35
commit 52d535a6dc
38 changed files with 1309 additions and 72 deletions

View File

@ -445,6 +445,8 @@ static_library("libcef_static") {
"libcef/browser/origin_whitelist_impl.h",
"libcef/browser/osr/browser_platform_delegate_osr.cc",
"libcef/browser/osr/browser_platform_delegate_osr.h",
"libcef/browser/osr/motion_event_osr.cc",
"libcef/browser/osr/motion_event_osr.h",
"libcef/browser/osr/osr_accessibility_util.cc",
"libcef/browser/osr/osr_accessibility_util.h",
"libcef/browser/osr/osr_util.cc",
@ -1997,6 +1999,7 @@ if (is_mac) {
"gtk+-2.0",
"gthread-2.0",
"gtk+-unix-print-2.0",
"xi",
]
}

View File

@ -33,7 +33,7 @@
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
// $hash=f99ba0878f8b6313adc7a43ad1fa295304fa9bcb$
// $hash=15f23de47af54fa690b6c5810e3049f97ae2aabd$
//
#ifndef CEF_INCLUDE_CAPI_CEF_BROWSER_CAPI_H_
@ -617,6 +617,12 @@ typedef struct _cef_browser_host_t {
int deltaX,
int deltaY);
///
// Send a touch event to the browser for a windowless browser.
///
void(CEF_CALLBACK* send_touch_event)(struct _cef_browser_host_t* self,
const struct _cef_touch_event_t* event);
///
// Send a focus event to the browser.
///

View File

@ -638,6 +638,12 @@ class CefBrowserHost : public virtual CefBaseRefCounted {
int deltaX,
int deltaY) = 0;
///
// Send a touch event to the browser for a windowless browser.
///
/*--cef()--*/
virtual void SendTouchEvent(const CefTouchEvent& event) = 0;
///
// Send a focus event to the browser.
///

View File

@ -1696,6 +1696,74 @@ typedef struct _cef_mouse_event_t {
uint32 modifiers;
} cef_mouse_event_t;
///
// Touch points states types.
///
typedef enum {
CEF_TET_RELEASED = 0,
CEF_TET_PRESSED,
CEF_TET_MOVED,
CEF_TET_CANCELLED
} cef_touch_event_type_t;
///
// Structure representing touch event information.
///
typedef struct _cef_touch_event_t {
///
// Id of a touch point. Must be unique per touch, can be any number except -1.
// Note that a maximum of 16 concurrent touches will be tracked; touches
// beyond that will be ignored.
///
int id;
///
// X coordinate relative to the left side of the view.
///
float x;
///
// Y coordinate relative to the top side of the view.
///
float y;
///
// X radius in pixels. Set to 0 if not applicable.
///
float radius_x;
///
// Y radius in pixels. Set to 0 if not applicable.
///
float radius_y;
///
// Rotation angle in radians. Set to 0 if not applicable.
///
float rotation_angle;
///
// The normalized pressure of the pointer input in the range of [0,1].
// Set to 0 if not applicable.
///
float pressure;
///
// The state of the touch point. Touches begin with one CEF_TET_PRESSED event
// followed by zero or more CEF_TET_MOVED events and finally one
// CEF_TET_RELEASED or CEF_TET_CANCELLED event. Events not respecting this
// order will be ignored.
///
cef_touch_event_type_t type;
///
// Bit flags describing any pressed modifier keys. See
// cef_event_flags_t for values.
///
uint32 modifiers;
} cef_touch_event_t;
///
// Paint element types.
///

View File

@ -481,6 +481,25 @@ struct CefMouseEventTraits {
///
typedef CefStructBase<CefMouseEventTraits> CefMouseEvent;
struct CefTouchEventTraits {
typedef cef_touch_event_t struct_type;
static inline void init(struct_type* s) {}
static inline void clear(struct_type* s) {}
static inline void set(const struct_type* src,
struct_type* target,
bool copy) {
*target = *src;
}
};
///
// Class representing a touch event.
///
typedef CefStructBase<CefTouchEventTraits> CefTouchEvent;
struct CefPopupFeaturesTraits {
typedef cef_popup_features_t struct_type;

View File

@ -3697,3 +3697,21 @@ bool CefBrowserHostImpl::Send(IPC::Message* message) {
delete message;
return false;
}
void CefBrowserHostImpl::SendTouchEvent(const CefTouchEvent& event) {
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::SendTouchEvent, this, event));
return;
}
if (!web_contents() || !platform_delegate_)
return;
platform_delegate_->SendTouchEvent(event);
}

View File

@ -222,6 +222,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
void SendMouseWheelEvent(const CefMouseEvent& event,
int deltaX,
int deltaY) override;
void SendTouchEvent(const CefTouchEvent& event) override;
void SendFocusEvent(bool setFocus) override;
void SendCaptureLostEvent() override;
void NotifyMoveOrResizeStarted() override;

View File

@ -22,6 +22,7 @@ namespace blink {
class WebMouseEvent;
class WebMouseWheelEvent;
class WebInputEvent;
class WebTouchEvent;
} // namespace blink
namespace content {
@ -150,6 +151,9 @@ class CefBrowserPlatformDelegate {
virtual void SendMouseEvent(const blink::WebMouseEvent& event) = 0;
virtual void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event) = 0;
// Send touch events.
virtual void SendTouchEvent(const CefTouchEvent& event) = 0;
// Send focus event. The browser's WebContents may be NULL when this method is
// called.
virtual void SendFocusEvent(bool setFocus) = 0;

View File

@ -66,6 +66,11 @@ void CefBrowserPlatformDelegateBackground::SendMouseWheelEvent(
// Nothing to do here.
}
void CefBrowserPlatformDelegateBackground::SendTouchEvent(
const CefTouchEvent& event) {
// Nothing to do here.
}
void CefBrowserPlatformDelegateBackground::SendFocusEvent(bool setFocus) {
// Nothing to do here.
}

View File

@ -28,6 +28,7 @@ class CefBrowserPlatformDelegateBackground
void SendKeyEvent(const content::NativeWebKeyboardEvent& event) override;
void SendMouseEvent(const blink::WebMouseEvent& event) override;
void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event) override;
void SendTouchEvent(const CefTouchEvent& event) override;
void SendFocusEvent(bool setFocus) override;
gfx::Point GetScreenPoint(const gfx::Point& view) const override;
void ViewText(const std::string& text) override;

View File

@ -59,6 +59,9 @@ void CefBrowserPlatformDelegateNative::SendMouseWheelEvent(
host->GetWidget()->ForwardWheelEvent(event);
}
void CefBrowserPlatformDelegateNative::SendTouchEvent(
const CefTouchEvent& event) {}
bool CefBrowserPlatformDelegateNative::IsWindowless() const {
return false;
}

View File

@ -32,6 +32,7 @@ class CefBrowserPlatformDelegateNative : public CefBrowserPlatformDelegate {
void SendKeyEvent(const content::NativeWebKeyboardEvent& event) override;
void SendMouseEvent(const blink::WebMouseEvent& event) override;
void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event) override;
void SendTouchEvent(const CefTouchEvent& event) override;
bool IsWindowless() const override;
bool IsViewsHosted() const override;

View File

@ -17,6 +17,7 @@
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/render_view_host.h"
#include "ui/events/base_event_utils.h"
CefBrowserPlatformDelegateOsr::CefBrowserPlatformDelegateOsr(
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate)
@ -109,6 +110,12 @@ void CefBrowserPlatformDelegateOsr::SendMouseWheelEvent(
view->SendMouseWheelEvent(event);
}
void CefBrowserPlatformDelegateOsr::SendTouchEvent(const CefTouchEvent& event) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->SendTouchEvent(event);
}
void CefBrowserPlatformDelegateOsr::SendFocusEvent(bool setFocus) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)

View File

@ -35,6 +35,7 @@ class CefBrowserPlatformDelegateOsr
void SendKeyEvent(const content::NativeWebKeyboardEvent& event) override;
void SendMouseEvent(const blink::WebMouseEvent& event) override;
void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event) override;
void SendTouchEvent(const CefTouchEvent& event) override;
void SendFocusEvent(bool setFocus) override;
gfx::Point GetScreenPoint(const gfx::Point& view) const override;
void ViewText(const std::string& text) override;

View File

@ -0,0 +1,218 @@
// Copyright (c) 2017 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 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 "libcef/browser/osr/motion_event_osr.h"
#include <algorithm>
#include "ui/events/base_event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
CefMotionEventOSR::CefMotionEventOSR() {
std::fill(id_map_, id_map_ + blink::WebTouchEvent::kTouchesLengthCap, -1);
}
CefMotionEventOSR::~CefMotionEventOSR() {}
int CefMotionEventOSR::GetSourceDeviceId(size_t pointer_index) const {
if (IsValidIndex(pointer_index))
return pointer(pointer_index).source_device_id;
else
return -1;
}
// Returns true if the touch was valid.
bool CefMotionEventOSR::OnTouch(const CefTouchEvent& touch) {
int id = LookupId(touch.id);
bool pointer_id_is_active = id != -1;
if (touch.type == CEF_TET_PRESSED && pointer_id_is_active) {
// Ignore pressed events for already active touches.
return false;
} else if (touch.type != CEF_TET_PRESSED && !pointer_id_is_active) {
// When a window begins capturing touch events, we could have an active
// touch stream transfered to us, resulting in touch move or touch up
// events without associated touch down events. Ignore them.
return false;
}
switch (touch.type) {
case CEF_TET_PRESSED:
id = AddId(touch.id);
if (id == -1)
return false;
if (!AddTouch(touch, id))
return false;
break;
case CEF_TET_MOVED: {
// Discard if touch is stationary.
int index = FindPointerIndexOfId(id);
if (IsValidIndex(index) &&
(touch.x == GetX(index) && touch.y == GetY(index))) {
return false;
}
}
[[fallthrough]];
// No break.
case CEF_TET_RELEASED:
case CEF_TET_CANCELLED:
// Removing these touch points needs to be postponed until after the
// MotionEvent has been dispatched. This cleanup occurs in
// CleanupRemovedTouchPoints.
UpdateTouch(touch, id);
break;
}
UpdateCachedAction(touch, id);
set_unique_event_id(ui::GetNextTouchEventId());
set_flags(touch.modifiers);
set_event_time(base::TimeTicks::Now());
return true;
}
// We can't cleanup removed touch points immediately upon receipt of a
// TouchCancel or TouchRelease, as the MotionEvent needs to be able to report
// information about those touch events. Once the MotionEvent has been
// processed, we call CleanupRemovedTouchPoints to do the required
// book-keeping.
void CefMotionEventOSR::CleanupRemovedTouchPoints(const CefTouchEvent& event) {
if (event.type != CEF_TET_RELEASED && event.type != CEF_TET_CANCELLED) {
return;
}
DCHECK(GetPointerCount());
int id = LookupId(event.id);
int index_to_delete = FindPointerIndexOfId(id);
set_action_index(-1);
set_action(ui::MotionEvent::Action::NONE);
if (IsValidIndex(index_to_delete)) {
pointer(index_to_delete) = pointer(GetPointerCount() - 1);
PopPointer();
RemoveId(event.id);
}
}
// Reset unchanged touch point to StateStationary for touchmove and touchcancel.
void CefMotionEventOSR::MarkUnchangedTouchPointsAsStationary(
blink::WebTouchEvent* event,
const CefTouchEvent& cef_event) {
int id = LookupId(cef_event.id);
if (event->GetType() == blink::WebInputEvent::kTouchMove ||
event->GetType() == blink::WebInputEvent::kTouchCancel) {
for (size_t i = 0; i < event->touches_length; ++i) {
if (event->touches[i].id != id)
event->touches[i].state = blink::WebTouchPoint::kStateStationary;
}
}
}
int CefMotionEventOSR::LookupId(int id) {
if (id == -1)
return -1;
for (int i = 0; i < blink::WebTouchEvent::kTouchesLengthCap; i++) {
if (id_map_[i] == id) {
return i;
}
}
return -1;
}
int CefMotionEventOSR::AddId(int id) {
if (id == -1 || LookupId(id) >= 0)
return -1;
for (int i = 0; i < blink::WebTouchEvent::kTouchesLengthCap; i++) {
if (id_map_[i] == -1) {
id_map_[i] = id;
return i;
}
}
return -1;
}
void CefMotionEventOSR::RemoveId(int id) {
for (int i = 0; i < blink::WebTouchEvent::kTouchesLengthCap; i++) {
if (id_map_[i] == id) {
id_map_[i] = -1;
}
}
}
bool CefMotionEventOSR::AddTouch(const CefTouchEvent& touch, int id) {
if (GetPointerCount() == MotionEvent::MAX_TOUCH_POINT_COUNT)
return false;
PushPointer(GetPointerPropertiesFromTouchEvent(touch, id));
return true;
}
void CefMotionEventOSR::UpdateTouch(const CefTouchEvent& touch, int id) {
int index_to_update = FindPointerIndexOfId(id);
if (IsValidIndex(index_to_update))
pointer(index_to_update) = GetPointerPropertiesFromTouchEvent(touch, id);
}
void CefMotionEventOSR::UpdateCachedAction(const CefTouchEvent& touch, int id) {
DCHECK(GetPointerCount());
switch (touch.type) {
case CEF_TET_PRESSED:
if (GetPointerCount() == 1) {
set_action(ui::MotionEvent::Action::DOWN);
} else {
set_action(ui::MotionEvent::Action::POINTER_DOWN);
set_action_index(FindPointerIndexOfId(id));
}
break;
case CEF_TET_RELEASED:
if (GetPointerCount() == 1) {
set_action(ui::MotionEvent::Action::UP);
} else {
set_action(ui::MotionEvent::Action::POINTER_UP);
set_action_index(FindPointerIndexOfId(id));
}
break;
case CEF_TET_CANCELLED:
set_action(ui::MotionEvent::Action::CANCEL);
break;
case CEF_TET_MOVED:
set_action(ui::MotionEvent::Action::MOVE);
break;
}
}
bool CefMotionEventOSR::IsValidIndex(int index) const {
return (index >= 0) && (index < static_cast<int>(GetPointerCount()));
}
ui::PointerProperties CefMotionEventOSR::GetPointerPropertiesFromTouchEvent(
const CefTouchEvent& touch,
int id) {
ui::PointerProperties pointer_properties;
pointer_properties.x = touch.x;
pointer_properties.y = touch.y;
pointer_properties.raw_x = touch.x;
pointer_properties.raw_y = touch.y;
pointer_properties.id = id;
pointer_properties.pressure = touch.pressure;
pointer_properties.source_device_id = 0;
pointer_properties.SetAxesAndOrientation(touch.radius_x, touch.radius_y,
touch.rotation_angle);
if (!pointer_properties.touch_major) {
pointer_properties.touch_major =
2.f * ui::GestureConfiguration::GetInstance()->default_radius();
pointer_properties.touch_minor =
2.f * ui::GestureConfiguration::GetInstance()->default_radius();
pointer_properties.orientation = 0;
}
pointer_properties.tool_type = ui::MotionEvent::ToolType::FINGER;
return pointer_properties;
}

View File

@ -0,0 +1,59 @@
// Copyright (c) 2017 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 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 CEF_LIBCEF_BROWSER_OSR_MOTION_EVENT_OSR_H_
#define CEF_LIBCEF_BROWSER_OSR_MOTION_EVENT_OSR_H_
#pragma once
#include "include/cef_base.h"
#include "third_party/blink/public/platform/web_touch_event.h"
#include "ui/events/gesture_detection/motion_event_generic.h"
// Implementation of MotionEvent which takes a stream of CefTouchEvents.
// This class is based on ui::MotionEventAura.
class CefMotionEventOSR : public ui::MotionEventGeneric {
public:
CefMotionEventOSR();
~CefMotionEventOSR() override;
int GetSourceDeviceId(size_t pointer_index) const override;
// Returns true if the touch was valid.
bool OnTouch(const CefTouchEvent& touch);
// We can't cleanup removed touch points immediately upon receipt of a
// TouchCancel or TouchRelease, as the MotionEvent needs to be able to report
// information about those touch events. Once the MotionEvent has been
// processed, we call CleanupRemovedTouchPoints to do the required
// book-keeping.
void CleanupRemovedTouchPoints(const CefTouchEvent& event);
// Reset unchanged touch point to StateStationary for touchmove and
// touchcancel to make sure only send one ack per WebTouchEvent.
void MarkUnchangedTouchPointsAsStationary(blink::WebTouchEvent* event,
const CefTouchEvent& cef_event);
private:
// Chromium can't cope with touch ids >31, so let's map the incoming
// ids to a safe range.
int id_map_[blink::WebTouchEvent::kTouchesLengthCap];
int LookupId(int id);
int AddId(int id);
void RemoveId(int id);
bool AddTouch(const CefTouchEvent& touch, int id);
void UpdateTouch(const CefTouchEvent& touch, int id);
void UpdateCachedAction(const CefTouchEvent& touch, int id);
bool IsValidIndex(int index) const;
ui::PointerProperties GetPointerPropertiesFromTouchEvent(
const CefTouchEvent& touch,
int id);
DISALLOW_COPY_AND_ASSIGN(CefMotionEventOSR);
};
#endif

View File

@ -31,8 +31,11 @@
#include "content/browser/renderer_host/cursor_manager.h"
#include "content/browser/renderer_host/delegated_frame_host.h"
#include "content/browser/renderer_host/dip_util.h"
#include "content/browser/renderer_host/input/motion_event_web.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include "content/common/content_switches_internal.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_task_traits.h"
@ -43,6 +46,9 @@
#include "content/public/common/content_switches.h"
#include "media/base/video_frame.h"
#include "ui/compositor/compositor_vsync_manager.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
#include "ui/events/gesture_detection/motion_event.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/size_conversions.h"
@ -164,6 +170,23 @@ class CefDelegatedFrameHostClient : public content::DelegatedFrameHostClient {
#endif // !defined(OS_MACOSX)
ui::GestureProvider::Config CreateGestureProviderConfig() {
ui::GestureProvider::Config config = ui::GetGestureProviderConfig(
ui::GestureProviderConfigType::CURRENT_PLATFORM);
return config;
}
ui::LatencyInfo CreateLatencyInfo(const blink::WebInputEvent& event) {
ui::LatencyInfo latency_info;
// The latency number should only be added if the timestamp is valid.
base::TimeTicks time = event.TimeStamp();
if (!time.is_null()) {
latency_info.AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, time, 1);
}
return latency_info;
}
} // namespace
// Used for managing copy requests when GPU compositing is enabled. Based on
@ -326,8 +349,11 @@ CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR(
child_host_view_(NULL),
is_showing_(!render_widget_host_->is_hidden()),
is_destroyed_(false),
pinch_zoom_enabled_(content::IsPinchToZoomEnabled()),
is_scroll_offset_changed_pending_(false),
mouse_wheel_phase_handler_(this),
gesture_provider_(CreateGestureProviderConfig(), this),
forward_touch_to_popup_(false),
weak_ptr_factory_(this) {
DCHECK(render_widget_host_);
DCHECK(!render_widget_host_->GetView());
@ -398,6 +424,12 @@ CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR(
if (GetTextInputManager())
GetTextInputManager()->AddObserver(this);
if (render_widget_host_->delegate() &&
render_widget_host_->delegate()->GetInputEventRouter()) {
render_widget_host_->delegate()->GetInputEventRouter()->AddFrameSinkIdOwner(
GetFrameSinkId(), this);
}
}
CefRenderWidgetHostViewOSR::~CefRenderWidgetHostViewOSR() {
@ -854,7 +886,13 @@ content::CursorManager* CefRenderWidgetHostViewOSR::GetCursorManager() {
return cursor_manager_.get();
}
void CefRenderWidgetHostViewOSR::SetIsLoading(bool is_loading) {}
void CefRenderWidgetHostViewOSR::SetIsLoading(bool is_loading) {
if (!is_loading)
return;
// Make sure gesture detection is fresh.
gesture_provider_.ResetDetection();
forward_touch_to_popup_ = false;
}
void CefRenderWidgetHostViewOSR::RenderProcessGone(
base::TerminationStatus status,
@ -1084,6 +1122,14 @@ const viz::FrameSinkId& CefRenderWidgetHostViewOSR::GetFrameSinkId() const {
return GetDelegatedFrameHost()->frame_sink_id();
}
viz::FrameSinkId CefRenderWidgetHostViewOSR::GetRootFrameSinkId() {
#if defined(OS_MACOSX)
return browser_compositor_->GetRootFrameSinkId();
#else
return compositor_->frame_sink_id();
#endif
}
void CefRenderWidgetHostViewOSR::SetNeedsBeginFrames(bool enabled) {
SetFrameRate();
@ -1403,6 +1449,78 @@ void CefRenderWidgetHostViewOSR::SendMouseWheelEvent(
}
}
void CefRenderWidgetHostViewOSR::SendTouchEvent(const CefTouchEvent& event) {
TRACE_EVENT0("cef", "CefRenderWidgetHostViewOSR::SendTouchEvent");
if (!IsPopupWidget() && popup_host_view_) {
if (!forward_touch_to_popup_ && event.type == CEF_TET_PRESSED &&
pointer_state_.GetPointerCount() == 0) {
forward_touch_to_popup_ =
popup_host_view_->popup_position_.Contains(event.x, event.y);
}
if (forward_touch_to_popup_) {
CefTouchEvent popup_event(event);
popup_event.x -= popup_host_view_->popup_position_.x();
popup_event.y -= popup_host_view_->popup_position_.y();
popup_host_view_->SendTouchEvent(popup_event);
return;
}
}
// Update the touch event first.
if (!pointer_state_.OnTouch(event))
return;
ui::FilteredGestureProvider::TouchHandlingResult result =
gesture_provider_.OnTouchEvent(pointer_state_);
blink::WebTouchEvent touch_event = ui::CreateWebTouchEventFromMotionEvent(
pointer_state_, result.moved_beyond_slop_region, false);
pointer_state_.CleanupRemovedTouchPoints(event);
// Set unchanged touch point to StateStationary for touchmove and
// touchcancel to make sure only send one ack per WebTouchEvent.
if (!result.succeeded)
pointer_state_.MarkUnchangedTouchPointsAsStationary(&touch_event, event);
if (!render_widget_host_)
return;
ui::LatencyInfo latency_info = CreateLatencyInfo(touch_event);
if (ShouldRouteEvents()) {
render_widget_host_->delegate()->GetInputEventRouter()->RouteTouchEvent(
this, &touch_event, latency_info);
} else {
render_widget_host_->ForwardTouchEventWithLatencyInfo(touch_event,
latency_info);
}
bool touch_end = touch_event.GetType() == blink::WebInputEvent::kTouchEnd ||
touch_event.GetType() == blink::WebInputEvent::kTouchCancel;
if (touch_end && IsPopupWidget() && parent_host_view_ &&
parent_host_view_->popup_host_view_ == this) {
parent_host_view_->forward_touch_to_popup_ = false;
}
}
bool CefRenderWidgetHostViewOSR::ShouldRouteEvents() const {
if (!render_widget_host_->delegate())
return false;
// Do not route events that are currently targeted to page popups such as
// <select> element drop-downs, since these cannot contain cross-process
// frames.
if (!render_widget_host_->delegate()->IsWidgetForMainFrame(
render_widget_host_)) {
return false;
}
return !!render_widget_host_->delegate()->GetInputEventRouter();
}
void CefRenderWidgetHostViewOSR::SendFocusEvent(bool focus) {
if (!render_widget_host_)
return;
@ -1446,6 +1564,41 @@ void CefRenderWidgetHostViewOSR::OnUpdateTextInputStateCalled(
handler->OnVirtualKeyboardRequested(browser_impl_->GetBrowser(), mode);
}
void CefRenderWidgetHostViewOSR::ProcessAckedTouchEvent(
const content::TouchEventWithLatencyInfo& touch,
content::InputEventAckState ack_result) {
const bool event_consumed =
ack_result == content::INPUT_EVENT_ACK_STATE_CONSUMED;
gesture_provider_.OnTouchEventAck(touch.event.unique_touch_event_id,
event_consumed, false);
}
void CefRenderWidgetHostViewOSR::OnGestureEvent(
const ui::GestureEventData& gesture) {
if ((gesture.type() == ui::ET_GESTURE_PINCH_BEGIN ||
gesture.type() == ui::ET_GESTURE_PINCH_UPDATE ||
gesture.type() == ui::ET_GESTURE_PINCH_END) &&
!pinch_zoom_enabled_) {
return;
}
blink::WebGestureEvent web_event =
ui::CreateWebGestureEventFromGestureEventData(gesture);
// without this check, forwarding gestures does not work!
if (web_event.GetType() == blink::WebInputEvent::kUndefined)
return;
ui::LatencyInfo latency_info = CreateLatencyInfo(web_event);
if (ShouldRouteEvents()) {
render_widget_host_->delegate()->GetInputEventRouter()->RouteGestureEvent(
this, &web_event, latency_info);
} else {
render_widget_host_->ForwardGestureEventWithLatencyInfo(web_event,
latency_info);
}
}
void CefRenderWidgetHostViewOSR::UpdateFrameRate() {
frame_rate_threshold_us_ = 0;
SetFrameRate();
@ -1675,6 +1828,9 @@ void CefRenderWidgetHostViewOSR::SendBeginFrame(base::TimeTicks frame_time,
DCHECK(begin_frame_args.IsValid());
begin_frame_number_++;
if (render_widget_host_)
render_widget_host_->ProgressFlingIfNeeded(frame_time);
if (renderer_compositor_frame_sink_) {
renderer_compositor_frame_sink_->OnBeginFrame(begin_frame_args, {});
}

View File

@ -14,6 +14,8 @@
#include "include/cef_base.h"
#include "include/cef_browser.h"
#include "libcef/browser/osr/motion_event_osr.h"
#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
@ -24,6 +26,10 @@
#include "content/public/common/widget_type.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/external_begin_frame_client.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/gesture_detection/filtered_gesture_provider.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/gesture_detection/motion_event_generic.h"
#include "ui/gfx/geometry/rect.h"
#if defined(OS_LINUX)
@ -98,7 +104,8 @@ class MacHelper;
class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase,
public ui::ExternalBeginFrameClient,
public ui::CompositorDelegate,
public content::TextInputManager::Observer {
public content::TextInputManager::Observer,
public ui::GestureProviderClient {
public:
CefRenderWidgetHostViewOSR(SkColor background_color,
bool use_shared_texture,
@ -202,6 +209,7 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase,
const viz::LocalSurfaceIdAllocation& GetLocalSurfaceIdAllocation()
const override;
const viz::FrameSinkId& GetFrameSinkId() const override;
viz::FrameSinkId GetRootFrameSinkId() override;
// ui::ExternalBeginFrameClient implementation:
void OnDisplayDidFinishFrame(const viz::BeginFrameAck& ack) override;
@ -217,6 +225,11 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase,
RenderWidgetHostViewBase* updated_view,
bool did_update_state) override;
// ui::GestureProviderClient implementation.
void ProcessAckedTouchEvent(const content::TouchEventWithLatencyInfo& touch,
content::InputEventAckState ack_result) override;
void OnGestureEvent(const ui::GestureEventData& gesture) override;
bool InstallTransparency();
void SynchronizeVisualProperties();
@ -226,6 +239,8 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase,
void SendKeyEvent(const content::NativeWebKeyboardEvent& event);
void SendMouseEvent(const blink::WebMouseEvent& event);
void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event);
void SendTouchEvent(const CefTouchEvent& event);
bool ShouldRouteEvents() const;
void SendFocusEvent(bool focus);
void UpdateFrameRate();
@ -257,6 +272,8 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase,
}
void set_popup_host_view(CefRenderWidgetHostViewOSR* popup_view) {
if (popup_view != popup_host_view_)
forward_touch_to_popup_ = false;
popup_host_view_ = popup_view;
}
void set_child_host_view(CefRenderWidgetHostViewOSR* popup_view) {
@ -358,8 +375,8 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase,
std::unique_ptr<content::BrowserCompositorMac> browser_compositor_;
MacHelper* mac_helper_;
#elif defined(USE_X11)
CefWindowX11* window_;
std::unique_ptr<ui::XScopedCursor> invisible_cursor_;
CefWindowX11* window_;
std::unique_ptr<ui::XScopedCursor> invisible_cursor_;
#endif
std::unique_ptr<content::CursorManager> cursor_manager_;
@ -405,6 +422,10 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase,
base::Lock damage_rect_lock_;
std::map<uint32_t, gfx::Rect> damage_rects_;
// Whether pinch-to-zoom should be enabled and pinch events forwarded to the
// renderer.
bool pinch_zoom_enabled_;
// The last scroll offset of the view.
gfx::Vector2dF last_scroll_offset_;
bool is_scroll_offset_changed_pending_;
@ -419,6 +440,12 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase,
// EnsureSurfaceSynchronizedForLayoutTest().
uint32_t latest_capture_sequence_number_ = 0u;
// ui::GestureProviderClient implementation.
ui::FilteredGestureProvider gesture_provider_;
CefMotionEventOSR pointer_state_;
bool forward_touch_to_popup_;
base::WeakPtrFactory<CefRenderWidgetHostViewOSR> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CefRenderWidgetHostViewOSR);

View File

@ -204,6 +204,9 @@ void CefBrowserPlatformDelegateViews::SendMouseWheelEvent(
host->GetWidget()->ForwardWheelEvent(event);
}
void CefBrowserPlatformDelegateViews::SendTouchEvent(
const CefTouchEvent& event) {}
void CefBrowserPlatformDelegateViews::SendFocusEvent(bool setFocus) {
// Will result in a call to WebContents::Focus().
if (setFocus && browser_view_->root_view())

View File

@ -48,6 +48,7 @@ class CefBrowserPlatformDelegateViews
void SendKeyEvent(const content::NativeWebKeyboardEvent& event) override;
void SendMouseEvent(const blink::WebMouseEvent& event) override;
void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event) override;
void SendTouchEvent(const CefTouchEvent& event) override;
void SendFocusEvent(bool setFocus) override;
gfx::Point GetScreenPoint(const gfx::Point& view) const override;
void ViewText(const std::string& text) override;

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=9f02385389794ebb639bdd4ac1d4fca435b411ad$
// $hash=41e334182e76a4bfc65eca7cbf10e402a115ef64$
//
#include "libcef_dll/cpptoc/browser_host_cpptoc.h"
@ -724,6 +724,28 @@ browser_host_send_mouse_wheel_event(struct _cef_browser_host_t* self,
deltaY);
}
void CEF_CALLBACK
browser_host_send_touch_event(struct _cef_browser_host_t* self,
const struct _cef_touch_event_t* event) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: event; type: struct_byref_const
DCHECK(event);
if (!event)
return;
// Translate param: event; type: struct_byref_const
CefTouchEvent eventObj;
if (event)
eventObj.Set(*event, false);
// Execute
CefBrowserHostCppToC::Get(self)->SendTouchEvent(eventObj);
}
void CEF_CALLBACK
browser_host_send_focus_event(struct _cef_browser_host_t* self, int setFocus) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -1155,6 +1177,7 @@ CefBrowserHostCppToC::CefBrowserHostCppToC() {
GetStruct()->send_mouse_click_event = browser_host_send_mouse_click_event;
GetStruct()->send_mouse_move_event = browser_host_send_mouse_move_event;
GetStruct()->send_mouse_wheel_event = browser_host_send_mouse_wheel_event;
GetStruct()->send_touch_event = browser_host_send_touch_event;
GetStruct()->send_focus_event = browser_host_send_focus_event;
GetStruct()->send_capture_lost_event = browser_host_send_capture_lost_event;
GetStruct()->notify_move_or_resize_started =

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=f57448cbd63f9fdff85b1dbf22a09db3f6ecdea1$
// $hash=5b3acb2cb74ef6b6b42bade4e0515d39e4609319$
//
#include "libcef_dll/ctocpp/browser_host_ctocpp.h"
@ -622,6 +622,18 @@ void CefBrowserHostCToCpp::SendMouseWheelEvent(const CefMouseEvent& event,
_struct->send_mouse_wheel_event(_struct, &event, deltaX, deltaY);
}
NO_SANITIZE("cfi-icall")
void CefBrowserHostCToCpp::SendTouchEvent(const CefTouchEvent& event) {
cef_browser_host_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, send_touch_event))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
_struct->send_touch_event(_struct, &event);
}
NO_SANITIZE("cfi-icall")
void CefBrowserHostCToCpp::SendFocusEvent(bool setFocus) {
cef_browser_host_t* _struct = GetStruct();

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=65e39ded61217f1263d5fd3a955843078b9799d2$
// $hash=a7acce93e2b4109ddf76e4a82e0ff6d85be1451a$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_BROWSER_HOST_CTOCPP_H_
@ -96,6 +96,7 @@ class CefBrowserHostCToCpp : public CefCToCppRefCounted<CefBrowserHostCToCpp,
void SendMouseWheelEvent(const CefMouseEvent& event,
int deltaX,
int deltaY) OVERRIDE;
void SendTouchEvent(const CefTouchEvent& event) OVERRIDE;
void SendFocusEvent(bool setFocus) OVERRIDE;
void SendCaptureLostEvent() OVERRIDE;
void NotifyMoveOrResizeStarted() OVERRIDE;

View File

@ -39,7 +39,11 @@ patches = [
{
# Support component builds (GN is_component_build=true).
# https://bitbucket.org/chromiumembedded/cef/issues/1617
'name': 'component_build_1617',
#
# Export GetUnicodeCharacterFromXKeySym and XKeySymToDomKey
# to fix component builds.
# https://bitbucket.org/chromiumembedded/cef/issues/2587
'name': 'component_build',
},
{
# Revert change on Windows that removes MessageLoop::os_modal_loop().

View File

@ -0,0 +1,147 @@
diff --git content/app/content_service_manager_main_delegate.h content/app/content_service_manager_main_delegate.h
index 864f2a5a315a..78b71d523e86 100644
--- content/app/content_service_manager_main_delegate.h
+++ content/app/content_service_manager_main_delegate.h
@@ -18,7 +18,8 @@ namespace content {
class ContentMainRunnerImpl;
-class ContentServiceManagerMainDelegate : public service_manager::MainDelegate {
+class CONTENT_EXPORT ContentServiceManagerMainDelegate :
+ public service_manager::MainDelegate {
public:
explicit ContentServiceManagerMainDelegate(const ContentMainParams& params);
~ContentServiceManagerMainDelegate() override;
diff --git content/browser/renderer_host/input/mouse_wheel_phase_handler.h content/browser/renderer_host/input/mouse_wheel_phase_handler.h
index fc252b6ceffd..b0dfd847ec03 100644
--- content/browser/renderer_host/input/mouse_wheel_phase_handler.h
+++ content/browser/renderer_host/input/mouse_wheel_phase_handler.h
@@ -7,6 +7,7 @@
#include "base/timer/timer.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
+#include "content/common/content_export.h"
#include "content/public/common/input_event_ack_state.h"
#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
@@ -55,7 +56,7 @@ enum class FirstScrollUpdateAckState {
// The MouseWheelPhaseHandler is responsible for adding the proper phase to
// wheel events. Phase information is necessary for wheel scrolling since it
// shows the start and end of a scrolling sequence.
-class MouseWheelPhaseHandler {
+class CONTENT_EXPORT MouseWheelPhaseHandler {
public:
MouseWheelPhaseHandler(RenderWidgetHostViewBase* const host_view);
~MouseWheelPhaseHandler() {}
diff --git content/browser/renderer_host/input/synthetic_gesture_target_base.h content/browser/renderer_host/input/synthetic_gesture_target_base.h
index 53476354343e..fd1a7a24455b 100644
--- content/browser/renderer_host/input/synthetic_gesture_target_base.h
+++ content/browser/renderer_host/input/synthetic_gesture_target_base.h
@@ -8,6 +8,7 @@
#include "base/macros.h"
#include "base/time/time.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
+#include "content/common/content_export.h"
namespace ui {
class LatencyInfo;
@@ -24,7 +25,8 @@ namespace content {
class RenderWidgetHostImpl;
-class SyntheticGestureTargetBase : public SyntheticGestureTarget {
+class CONTENT_EXPORT SyntheticGestureTargetBase :
+ public SyntheticGestureTarget {
public:
explicit SyntheticGestureTargetBase(RenderWidgetHostImpl* host);
~SyntheticGestureTargetBase() override;
diff --git content/common/content_switches_internal.h content/common/content_switches_internal.h
index 5e67fbce7c9e..5bb9ee518dce 100644
--- content/common/content_switches_internal.h
+++ content/common/content_switches_internal.h
@@ -15,7 +15,7 @@ class CommandLine;
namespace content {
-bool IsPinchToZoomEnabled();
+CONTENT_EXPORT bool IsPinchToZoomEnabled();
V8CacheOptions GetV8CacheOptions();
diff --git third_party/blink/renderer/controller/BUILD.gn third_party/blink/renderer/controller/BUILD.gn
index 7668f3725200..665e8e579c54 100644
--- third_party/blink/renderer/controller/BUILD.gn
+++ third_party/blink/renderer/controller/BUILD.gn
@@ -25,6 +25,7 @@ component("controller") {
configs += [
"//build/config/compiler:wexit_time_destructors",
+ "//cef/libcef/features:config",
"//third_party/blink/renderer:config",
"//third_party/blink/renderer:inside_blink",
"//third_party/blink/renderer:non_test_config",
@@ -47,6 +48,8 @@ component("controller") {
"memory_usage_monitor.h",
"memory_usage_monitor_android.cc",
"memory_usage_monitor_android.h",
+ "//cef/libcef/renderer/blink_glue.cc",
+ "//cef/libcef/renderer/blink_glue.h",
]
if (is_android) {
diff --git ui/events/keycodes/BUILD.gn ui/events/keycodes/BUILD.gn
index 1e6d31cc0c92..36f3283291d9 100644
--- ui/events/keycodes/BUILD.gn
+++ ui/events/keycodes/BUILD.gn
@@ -14,6 +14,8 @@ jumbo_source_set("xkb") {
"xkb_keysym.h",
]
+ defines = [ "KEYCODES_X_IMPLEMENTATION" ]
+
deps = [
"//base",
"//ui/base:buildflags",
diff --git ui/events/keycodes/keyboard_code_conversion_xkb.h ui/events/keycodes/keyboard_code_conversion_xkb.h
index a1f9b78704fb..c7d3558251d9 100644
--- ui/events/keycodes/keyboard_code_conversion_xkb.h
+++ ui/events/keycodes/keyboard_code_conversion_xkb.h
@@ -9,6 +9,7 @@
#include "base/strings/string16.h"
#include "ui/events/keycodes/dom/dom_key.h"
+#include "ui/events/keycodes/keycodes_x_export.h"
#include "ui/events/keycodes/xkb_keysym.h"
namespace ui {
@@ -24,7 +25,7 @@ DomKey NonPrintableXKeySymToDomKey(xkb_keysym_t keysym);
// base::char16 DeadXKeySymToCombiningCharacter(xkb_keysym_t keysym);
// Return the DomKey determined by the XKB layout result (keysym, character).
-DomKey XKeySymToDomKey(xkb_keysym_t keysym, base::char16 character);
+KEYCODES_X_EXPORT DomKey XKeySymToDomKey(xkb_keysym_t keysym, base::char16 character);
} // namespace ui
diff --git ui/events/keycodes/keysym_to_unicode.h ui/events/keycodes/keysym_to_unicode.h
index a7983d179832..2bbee48e57ac 100644
--- ui/events/keycodes/keysym_to_unicode.h
+++ ui/events/keycodes/keysym_to_unicode.h
@@ -5,6 +5,8 @@
#ifndef UI_EVENTS_KEYCODES_KEYSYM_TO_UNICODE_H_
#define UI_EVENTS_KEYCODES_KEYSYM_TO_UNICODE_H_
+#include "ui/events/keycodes/keycodes_x_export.h"
+
#include <stdint.h>
namespace ui {
@@ -13,7 +15,7 @@ namespace ui {
// |keysym| doesn't represent a printable character, returns zero. We don't
// support characters outside the Basic Plane, and this function returns zero
// in that case.
-uint16_t GetUnicodeCharacterFromXKeySym(unsigned long keysym);
+KEYCODES_X_EXPORT uint16_t GetUnicodeCharacterFromXKeySym(unsigned long keysym);
} // namespace ui

View File

@ -1,56 +0,0 @@
diff --git content/app/content_service_manager_main_delegate.h content/app/content_service_manager_main_delegate.h
index 864f2a5a315a..78b71d523e86 100644
--- content/app/content_service_manager_main_delegate.h
+++ content/app/content_service_manager_main_delegate.h
@@ -18,7 +18,8 @@ namespace content {
class ContentMainRunnerImpl;
-class ContentServiceManagerMainDelegate : public service_manager::MainDelegate {
+class CONTENT_EXPORT ContentServiceManagerMainDelegate :
+ public service_manager::MainDelegate {
public:
explicit ContentServiceManagerMainDelegate(const ContentMainParams& params);
~ContentServiceManagerMainDelegate() override;
diff --git content/browser/renderer_host/input/mouse_wheel_phase_handler.h content/browser/renderer_host/input/mouse_wheel_phase_handler.h
index fc252b6ceffd..b0dfd847ec03 100644
--- content/browser/renderer_host/input/mouse_wheel_phase_handler.h
+++ content/browser/renderer_host/input/mouse_wheel_phase_handler.h
@@ -7,6 +7,7 @@
#include "base/timer/timer.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
+#include "content/common/content_export.h"
#include "content/public/common/input_event_ack_state.h"
#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
@@ -55,7 +56,7 @@ enum class FirstScrollUpdateAckState {
// The MouseWheelPhaseHandler is responsible for adding the proper phase to
// wheel events. Phase information is necessary for wheel scrolling since it
// shows the start and end of a scrolling sequence.
-class MouseWheelPhaseHandler {
+class CONTENT_EXPORT MouseWheelPhaseHandler {
public:
MouseWheelPhaseHandler(RenderWidgetHostViewBase* const host_view);
~MouseWheelPhaseHandler() {}
diff --git third_party/blink/renderer/controller/BUILD.gn third_party/blink/renderer/controller/BUILD.gn
index 7668f3725200..665e8e579c54 100644
--- third_party/blink/renderer/controller/BUILD.gn
+++ third_party/blink/renderer/controller/BUILD.gn
@@ -25,6 +25,7 @@ component("controller") {
configs += [
"//build/config/compiler:wexit_time_destructors",
+ "//cef/libcef/features:config",
"//third_party/blink/renderer:config",
"//third_party/blink/renderer:inside_blink",
"//third_party/blink/renderer:non_test_config",
@@ -47,6 +48,8 @@ component("controller") {
"memory_usage_monitor.h",
"memory_usage_monitor_android.cc",
"memory_usage_monitor_android.h",
+ "//cef/libcef/renderer/blink_glue.cc",
+ "//cef/libcef/renderer/blink_glue.h",
]
if (is_android) {

View File

@ -15,6 +15,7 @@
#define XK_3270 // for XK_3270_BackTab
#include <X11/XF86keysym.h>
#include <X11/Xcursor/Xcursor.h>
#include <X11/extensions/XInput2.h>
#include <X11/keysym.h>
#include "include/base/cef_logging.h"
@ -28,6 +29,17 @@ namespace client {
namespace {
// Major opcode of XInputExtension, or -1 if XInput 2.2 is not available.
int g_xinput_extension = -1;
// Static BrowserWindowOsrGtk::EventFilter needs to forward touch events
// to correct browser, so we maintain a vector of all windows.
std::vector<BrowserWindowOsrGtk*> g_browser_windows;
bool IsTouchAvailable() {
return g_xinput_extension != -1;
}
int GetCefStateModifiers(guint state) {
int modifiers = 0;
if (state & GDK_SHIFT_MASK)
@ -47,6 +59,20 @@ int GetCefStateModifiers(guint state) {
return modifiers;
}
int GetCefStateModifiers(XIModifierState mods, XIButtonState buttons) {
guint state = mods.effective;
if (buttons.mask_len >= 1) {
if (XIMaskIsSet(buttons.mask, 1))
state |= GDK_BUTTON1_MASK;
if (XIMaskIsSet(buttons.mask, 2))
state |= GDK_BUTTON2_MASK;
if (XIMaskIsSet(buttons.mask, 3))
state |= GDK_BUTTON3_MASK;
}
return GetCefStateModifiers(state);
}
// From ui/events/keycodes/keyboard_codes_posix.h.
enum KeyboardCode {
VKEY_BACK = 0x08,
@ -948,9 +974,12 @@ BrowserWindowOsrGtk::BrowserWindowOsrGtk(BrowserWindow::Delegate* delegate,
drag_drop_(false),
device_scale_factor_(1.0f) {
client_handler_ = new ClientHandlerOsr(this, this, startup_url);
g_browser_windows.push_back(this);
}
BrowserWindowOsrGtk::~BrowserWindowOsrGtk() {
g_browser_windows.erase(
std::find(g_browser_windows.begin(), g_browser_windows.end(), this));
ScopedGdkThreadsEnter scoped_gdk_threads;
if (drag_trigger_event_) {
@ -1387,6 +1416,11 @@ void BrowserWindowOsrGtk::Create(ClientWindowHandle parent_handle) {
// Make the GlArea visible in the parent container.
gtk_widget_show_all(parent_handle);
InitializeXinput(xdisplay_);
if (IsTouchAvailable())
RegisterTouch();
}
// static
@ -1640,6 +1674,108 @@ gint BrowserWindowOsrGtk::FocusEvent(GtkWidget* widget,
return TRUE;
}
void BrowserWindowOsrGtk::TouchEvent(CefXIDeviceEvent event) {
if (!browser_.get())
return;
XIDeviceEvent* ev = static_cast<XIDeviceEvent*>(event);
CefTouchEvent cef_event;
switch (ev->evtype) {
case XI_TouchBegin:
cef_event.type = CEF_TET_PRESSED;
break;
case XI_TouchUpdate:
cef_event.type = CEF_TET_MOVED;
break;
case XI_TouchEnd:
cef_event.type = CEF_TET_RELEASED;
break;
default:
return;
}
cef_event.id = ev->detail;
cef_event.x = ev->event_x;
cef_event.y = ev->event_y;
cef_event.radius_x = 0;
cef_event.radius_y = 0;
cef_event.rotation_angle = 0;
cef_event.pressure = 0;
cef_event.modifiers = GetCefStateModifiers(ev->mods, ev->buttons);
browser_->GetHost()->SendTouchEvent(cef_event);
}
void BrowserWindowOsrGtk::RegisterTouch() {
GdkWindow* glwindow = gtk_widget_get_window(glarea_);
::Window xwindow = GDK_WINDOW_XID(glwindow);
uint32_t bitMask = XI_TouchBeginMask | XI_TouchUpdateMask | XI_TouchEndMask;
XIEventMask mask;
mask.deviceid = XIAllMasterDevices;
mask.mask = reinterpret_cast<unsigned char*>(&bitMask);
mask.mask_len = sizeof(bitMask);
XISelectEvents(xdisplay_, xwindow, &mask, 1);
}
// static
GdkFilterReturn BrowserWindowOsrGtk::EventFilter(GdkXEvent* gdk_xevent,
GdkEvent* event,
gpointer data) {
XEvent* xevent = static_cast<XEvent*>(gdk_xevent);
if (xevent->type == GenericEvent &&
xevent->xgeneric.extension == g_xinput_extension) {
XGetEventData(xevent->xcookie.display, &xevent->xcookie);
XIDeviceEvent* ev = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
if (!ev)
return GDK_FILTER_REMOVE;
for (BrowserWindowOsrGtk* browser_window : g_browser_windows) {
GtkWidget* widget = browser_window->GetWindowHandle();
::Window xwindow = GDK_WINDOW_XID(gtk_widget_get_window(widget));
if (xwindow == ev->event) {
browser_window->TouchEvent(ev);
break;
}
}
XFreeEventData(xevent->xcookie.display, &xevent->xcookie);
// Even if we didn't find a consumer for this event, we will make sure Gdk
// doesn't attempt to process the event, since it can't parse GenericEvents
return GDK_FILTER_REMOVE;
}
return GDK_FILTER_CONTINUE;
}
// static
void BrowserWindowOsrGtk::InitializeXinput(XDisplay* xdisplay) {
static bool initialized = false;
if (initialized)
return;
initialized = true;
int firstEvent, firstError;
if (XQueryExtension(xdisplay, "XInputExtension", &g_xinput_extension,
&firstEvent, &firstError)) {
int major = 2, minor = 2;
// X Input Extension 2.2 is needed for multitouch events.
if (XIQueryVersion(xdisplay, &major, &minor) == Success) {
// Ideally we would add an event filter for each glarea_ window
// separately, but unfortunately GDK can't parse X GenericEvents
// which have the target window stored in different way compared
// to other X events. That is why we add this global event filter
// just once, and dispatch the event to correct BrowserWindowOsrGtk
// manually.
gdk_window_add_filter(nullptr, &BrowserWindowOsrGtk::EventFilter,
nullptr);
} else {
g_xinput_extension = -1;
}
}
}
bool BrowserWindowOsrGtk::IsOverPopupWidget(int x, int y) const {
const CefRect& rc = renderer_.popup_rect();
int popup_right = rc.x + rc.width;

View File

@ -20,6 +20,8 @@ namespace client {
class BrowserWindowOsrGtk : public BrowserWindow,
public ClientHandlerOsr::OsrDelegate {
public:
typedef void* CefXIDeviceEvent;
// Constructor may be called on any thread.
// |delegate| must outlive this object.
BrowserWindowOsrGtk(BrowserWindow::Delegate* delegate,
@ -114,6 +116,9 @@ class BrowserWindowOsrGtk : public BrowserWindow,
GdkEventFocus* event,
BrowserWindowOsrGtk* self);
void TouchEvent(CefXIDeviceEvent event);
void RegisterTouch();
bool IsOverPopupWidget(int x, int y) const;
int GetPopupXOffset() const;
int GetPopupYOffset() const;
@ -166,6 +171,10 @@ class BrowserWindowOsrGtk : public BrowserWindow,
guint info,
guint time,
BrowserWindowOsrGtk* self);
static GdkFilterReturn EventFilter(GdkXEvent* gdk_xevent,
GdkEvent* event,
gpointer data);
static void InitializeXinput(XDisplay* xdisplay);
XDisplay* xdisplay_;

View File

@ -33,7 +33,7 @@ CefTextInputClientOSRMac* GetInputClientFromContext(
} // namespace
@interface BrowserOpenGLView
: NSOpenGLView<NSDraggingSource, NSDraggingDestination, NSAccessibility> {
: NSOpenGLView <NSDraggingSource, NSDraggingDestination, NSAccessibility> {
@private
NSTrackingArea* tracking_area_;
client::BrowserWindowOsrMac* browser_window_;
@ -238,8 +238,8 @@ NSPoint ConvertPointFromWindowToScreen(NSWindow* window, NSPoint point) {
point = [self convertPointToBackingInternal:point];
if (!isUp) {
was_last_mouse_down_on_view_ =
![self isOverPopupWidgetX:point.x andY:point.y];
was_last_mouse_down_on_view_ = ![self isOverPopupWidgetX:point.x
andY:point.y];
} else if (was_last_mouse_down_on_view_ &&
[self isOverPopupWidgetX:point.x andY:point.y] &&
([self getPopupXOffset] || [self getPopupYOffset])) {
@ -359,6 +359,110 @@ NSPoint ConvertPointFromWindowToScreen(NSWindow* window, NSPoint point) {
[client HandleKeyEventAfterTextInputClient:keyEvent];
}
}
// Check for Caps lock and Toggle Touch Emulation
if (client::MainContext::Get()->TouchEventsEnabled())
[self toggleTouchEmulation:event];
}
// OSX does not have touch screens, so we emulate it by mapping multitouch
// events on TrackPad to Touch Events on Screen. To ensure it does not
// interfere with other Trackpad events, this mapping is only enabled if
// touch-events=enabled commandline is passed and caps lock key is on.
- (void)toggleTouchEmulation:(NSEvent*)event {
if ([event type] == NSFlagsChanged && [event keyCode] == 0x39) {
NSUInteger flags = [event modifierFlags];
BOOL touch_enabled = flags & NSAlphaShiftKeyMask ? YES : NO;
[self setAcceptsTouchEvents:touch_enabled];
}
}
- (cef_touch_event_type_t)getTouchPhase:(NSTouchPhase)phase {
cef_touch_event_type_t event_type = CEF_TET_RELEASED;
switch (phase) {
case NSTouchPhaseBegan:
event_type = CEF_TET_PRESSED;
break;
case NSTouchPhaseMoved:
event_type = CEF_TET_MOVED;
break;
case NSTouchPhaseEnded:
event_type = CEF_TET_RELEASED;
break;
case NSTouchPhaseCancelled:
event_type = CEF_TET_CANCELLED;
break;
default:
break;
}
return event_type;
}
// Translate NSTouch events to CefTouchEvents and send to browser.
- (void)sendTouchEvent:(NSEvent*)event touchPhase:(NSTouchPhase)phase {
int modifiers = [self getModifiersForEvent:event];
CefRefPtr<CefBrowser> browser = [self getBrowser];
NSSet* touches = [event touchesMatchingPhase:phase inView:self];
for (NSTouch* touch in touches) {
// Convert NSTouch to CefTouchEvent.
CefTouchEvent touch_event;
// NSTouch.identity is unique during the life of the touch
touch_event.id = touch.identity.hash;
touch_event.type = [self getTouchPhase:phase];
NSPoint scaled_pos = [touch normalizedPosition];
NSSize view_size = [self bounds].size;
// Map point on Touch Device to View coordinates.
NSPoint touch_point = NSMakePoint(scaled_pos.x * view_size.width,
scaled_pos.y * view_size.height);
NSPoint contentLocal = [self convertPoint:touch_point fromView:nil];
NSPoint point;
point.x = contentLocal.x;
point.y = [self frame].size.height - contentLocal.y; // Flip y.
// Convert to device coordinates.
point = [self convertPointToBackingInternal:point];
int device_x = point.x;
int device_y = point.y;
const float device_scale_factor = [self getDeviceScaleFactor];
// Convert to browser view coordinates.
touch_event.x = client::DeviceToLogical(device_x, device_scale_factor);
touch_event.y = client::DeviceToLogical(device_y, device_scale_factor);
touch_event.radius_x = 0;
touch_event.radius_y = 0;
touch_event.rotation_angle = 0;
touch_event.pressure = 0;
touch_event.modifiers = modifiers;
// Notify the browser of touch event.
browser->GetHost()->SendTouchEvent(touch_event);
}
}
- (void)touchesBeganWithEvent:(NSEvent*)event {
[self sendTouchEvent:event touchPhase:NSTouchPhaseBegan];
}
- (void)touchesMovedWithEvent:(NSEvent*)event {
[self sendTouchEvent:event touchPhase:NSTouchPhaseMoved];
}
- (void)touchesEndedWithEvent:(NSEvent*)event {
[self sendTouchEvent:event touchPhase:NSTouchPhaseEnded];
}
- (void)touchesCancelledWithEvent:(NSEvent*)event {
[self sendTouchEvent:event touchPhase:NSTouchPhaseCancelled];
}
- (void)keyUp:(NSEvent*)event {
@ -490,7 +594,7 @@ NSPoint ConvertPointFromWindowToScreen(NSWindow* window, NSPoint point) {
browser->GetFocusedFrame()->Paste();
}
- (void) delete:(id)sender {
- (void)delete:(id)sender {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (browser.get())
browser->GetFocusedFrame()->Delete();

View File

@ -3,6 +3,7 @@
// can be found in the LICENSE file.
#include "tests/cefclient/browser/client_browser.h"
#include "tests/cefclient/browser/main_context.h"
#include "include/cef_command_line.h"
#include "include/cef_crash_util.h"
@ -39,6 +40,14 @@ class ClientBrowserDelegate : public ClientAppBrowser::Delegate {
}
}
void OnBeforeCommandLineProcessing(
CefRefPtr<ClientAppBrowser> app,
CefRefPtr<CefCommandLine> command_line) OVERRIDE {
// Append Chromium command line parameters if touch events are enabled
if (client::MainContext::Get()->TouchEventsEnabled())
command_line->AppendSwitchWithValue("touch-events", "enabled");
}
private:
DISALLOW_COPY_AND_ASSIGN(ClientBrowserDelegate);
IMPLEMENT_REFCOUNTING(ClientBrowserDelegate);

View File

@ -44,6 +44,9 @@ class MainContext {
// Returns true if windowless (off-screen) rendering will be used.
virtual bool UseWindowlessRendering() = 0;
// Returns true if touch events are enabled.
virtual bool TouchEventsEnabled() = 0;
// Populate |settings| based on command-line arguments.
virtual void PopulateSettings(CefSettings* settings) = 0;
virtual void PopulateBrowserSettings(CefBrowserSettings* settings) = 0;

View File

@ -163,6 +163,10 @@ bool MainContextImpl::UseWindowlessRendering() {
return use_windowless_rendering_;
}
bool MainContextImpl::TouchEventsEnabled() {
return command_line_->GetSwitchValue("touch-events") == "enabled";
}
void MainContextImpl::PopulateSettings(CefSettings* settings) {
#if defined(OS_WIN) || defined(OS_LINUX)
settings->multi_threaded_message_loop =

View File

@ -29,6 +29,7 @@ class MainContextImpl : public MainContext {
cef_color_t GetBackgroundColor() OVERRIDE;
bool UseViews() OVERRIDE;
bool UseWindowlessRendering() OVERRIDE;
bool TouchEventsEnabled() OVERRIDE;
void PopulateSettings(CefSettings* settings) OVERRIDE;
void PopulateBrowserSettings(CefBrowserSettings* settings) OVERRIDE;
void PopulateOsrSettings(OsrRendererSettings* settings) OVERRIDE;
@ -70,6 +71,7 @@ class MainContextImpl : public MainContext {
bool use_windowless_rendering_;
int windowless_frame_rate_;
bool use_views_;
bool touch_events_enabled_;
scoped_ptr<RootWindowManager> root_window_manager_;

View File

@ -27,6 +27,29 @@ namespace {
const wchar_t kWndClass[] = L"Client_OsrWindow";
// Helper funtion to check if it is Windows8 or greater.
// https://msdn.microsoft.com/en-us/library/ms724833(v=vs.85).aspx
inline BOOL IsWindows_8_Or_Newer() {
OSVERSIONINFOEX osvi = {0};
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
osvi.dwMajorVersion = 6;
osvi.dwMinorVersion = 2;
DWORDLONG dwlConditionMask = 0;
VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
return ::VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION,
dwlConditionMask);
}
// Helper function to detect mouse messages coming from emulation of touch
// events. These should be ignored.
bool IsMouseEventFromTouch(UINT message) {
#define MOUSEEVENTF_FROMTOUCH 0xFF515700
return (message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST) &&
(GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) ==
MOUSEEVENTF_FROMTOUCH;
}
} // namespace
OsrWindowWin::OsrWindowWin(Delegate* delegate,
@ -256,6 +279,10 @@ void OsrWindowWin::Create(HWND parent_hwnd, const RECT& rect) {
ime_handler_.reset(new OsrImeHandlerWin(hwnd_));
// Enable Touch Events if requested
if (client::MainContext::Get()->TouchEventsEnabled())
RegisterTouchWindow(hwnd_, 0);
// Notify the window owner.
NotifyNativeWindowCreated(hwnd_);
}
@ -476,6 +503,15 @@ LRESULT CALLBACK OsrWindowWin::OsrWndProc(HWND hWnd,
// Don't erase the background.
return 0;
// If your application does not require Win7 support, please do consider
// using WM_POINTER* messages instead of WM_TOUCH. WM_POINTER are more
// intutive, complete and simpler to code.
// https://msdn.microsoft.com/en-us/library/hh454903(v=vs.85).aspx
case WM_TOUCH:
if (self->OnTouchEvent(message, wParam, lParam))
return 0;
break;
case WM_NCDESTROY:
// Clear the reference to |self|.
SetUserDataPtr(hWnd, NULL);
@ -487,6 +523,9 @@ LRESULT CALLBACK OsrWindowWin::OsrWndProc(HWND hWnd,
}
void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
if (IsMouseEventFromTouch(message))
return;
CefRefPtr<CefBrowserHost> browser_host;
if (browser_)
browser_host = browser_->GetHost();
@ -733,6 +772,63 @@ bool OsrWindowWin::OnEraseBkgnd() {
return (browser_ == NULL);
}
bool OsrWindowWin::OnTouchEvent(UINT message, WPARAM wParam, LPARAM lParam) {
// Handle touch events on Windows.
int num_points = LOWORD(wParam);
// Chromium only supports upto 16 touch points.
if (num_points < 0 || num_points > 16)
return false;
std::unique_ptr<TOUCHINPUT[]> input(new TOUCHINPUT[num_points]);
if (GetTouchInputInfo(reinterpret_cast<HTOUCHINPUT>(lParam), num_points,
input.get(), sizeof(TOUCHINPUT))) {
CefTouchEvent touch_event;
for (int i = 0; i < num_points; ++i) {
POINT point;
point.x = TOUCH_COORD_TO_PIXEL(input[i].x);
point.y = TOUCH_COORD_TO_PIXEL(input[i].y);
if (!IsWindows_8_Or_Newer()) {
// Windows 7 sends touch events for touches in the non-client area,
// whereas Windows 8 does not. In order to unify the behaviour, always
// ignore touch events in the non-client area.
LPARAM l_param_ht = MAKELPARAM(point.x, point.y);
LRESULT hittest = SendMessage(hwnd_, WM_NCHITTEST, 0, l_param_ht);
if (hittest != HTCLIENT)
return false;
}
ScreenToClient(hwnd_, &point);
touch_event.x = DeviceToLogical(point.x, device_scale_factor_);
touch_event.y = DeviceToLogical(point.y, device_scale_factor_);
// Touch point identifier stays consistent in a touch contact sequence
touch_event.id = input[i].dwID;
if (input[i].dwFlags & TOUCHEVENTF_DOWN) {
touch_event.type = CEF_TET_PRESSED;
} else if (input[i].dwFlags & TOUCHEVENTF_MOVE) {
touch_event.type = CEF_TET_MOVED;
} else if (input[i].dwFlags & TOUCHEVENTF_UP) {
touch_event.type = CEF_TET_RELEASED;
}
touch_event.radius_x = 0;
touch_event.radius_y = 0;
touch_event.rotation_angle = 0;
touch_event.pressure = 0;
touch_event.modifiers = 0;
// Notify the browser of touch event
if (browser_)
browser_->GetHost()->SendTouchEvent(touch_event);
}
CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(lParam));
return true;
}
return false;
}
bool OsrWindowWin::IsOverPopupWidget(int x, int y) const {
if (!render_handler_)
return false;

View File

@ -93,6 +93,7 @@ class OsrWindowWin
void OnKeyEvent(UINT message, WPARAM wParam, LPARAM lParam);
void OnPaint();
bool OnEraseBkgnd();
bool OnTouchEvent(UINT message, WPARAM wParam, LPARAM lParam);
void OnIMESetContext(UINT message, WPARAM wParam, LPARAM lParam);
void OnIMEStartComposition();

View File

@ -36,6 +36,7 @@
<li><a href="urlrequest">CefURLRequest</a></li>
<li><a href="xmlhttprequest">XMLHttpRequest</a></li>
<li><a href="javascript:window.print();">Print this page with &quot;javascript:window.print();&quot;</a></li>
<li><a href="https://patrickhlauke.github.io/touch">Touch Feature Tests</a> - requires "touch-events=enabled" flag (and CAPS LOCK on Mac for Trackpad simulation) </li>
</ul>
</body>
</html>

View File

@ -160,7 +160,14 @@ enum OSRTestType {
OSR_TEST_TEXT_SELECTION_CHANGE,
// clicking on text input will call OnVirtualKeyboardRequested
OSR_TEST_VIRTUAL_KEYBOARD,
// touchStart event is triggered and contains the touch point count
OSR_TEST_TOUCH_START,
// touchMove event is triggered and contains the changed touch points
OSR_TEST_TOUCH_MOVE,
// touchEnd is triggered on completion
OSR_TEST_TOUCH_END,
// touchCancel is triggered on dismissing
OSR_TEST_TOUCH_CANCEL,
// Define the range for popup tests.
OSR_TEST_POPUP_FIRST = OSR_TEST_POPUP_PAINT,
OSR_TEST_POPUP_LAST = OSR_TEST_POPUP_SCROLL_INSIDE,
@ -177,7 +184,8 @@ class OSRTestHandler : public RoutingTestHandler,
scale_factor_(scale_factor),
event_count_(0),
event_total_(1),
started_(false) {}
started_(false),
touch_state_(CEF_TET_CANCELLED) {}
// TestHandler methods
void RunTest() override {
@ -262,11 +270,58 @@ class OSRTestHandler : public RoutingTestHandler,
EXPECT_STREQ(messageStr.c_str(), "osrdrop");
DestroySucceededTestSoon();
break;
case OSR_TEST_TOUCH_START:
case OSR_TEST_TOUCH_MOVE:
case OSR_TEST_TOUCH_END:
case OSR_TEST_TOUCH_CANCEL: {
switch (touch_state_) {
case CEF_TET_CANCELLED: {
// The first message expected is touchstart.
// We expect multitouch, so touches length should be 2.
// Ignore intermediate touch start events.
if (messageStr == "osrtouchstart1")
break;
EXPECT_STREQ(messageStr.c_str(), "osrtouchstart2");
// Close Touch Start Tests.
if (test_type_ == OSR_TEST_TOUCH_START) {
DestroySucceededTestSoon();
touch_state_ = CEF_TET_RELEASED;
} else {
touch_state_ = CEF_TET_PRESSED;
}
} break;
case CEF_TET_PRESSED: {
// Touch Move include the touches that changed, should be 2.
EXPECT_STREQ(messageStr.c_str(), "osrtouchmove2");
if (test_type_ == OSR_TEST_TOUCH_MOVE) {
DestroySucceededTestSoon();
touch_state_ = CEF_TET_RELEASED;
} else {
touch_state_ = CEF_TET_MOVED;
}
} break;
case CEF_TET_MOVED: {
// There might be multiple touchmove events, ignore.
if (messageStr != "osrtouchmove2") {
if (test_type_ == OSR_TEST_TOUCH_END) {
EXPECT_STREQ(messageStr.c_str(), "osrtouchend");
DestroySucceededTestSoon();
touch_state_ = CEF_TET_RELEASED;
} else if (test_type_ == OSR_TEST_TOUCH_CANCEL) {
EXPECT_STREQ(messageStr.c_str(), "osrtouchcancel");
DestroySucceededTestSoon();
touch_state_ = CEF_TET_RELEASED;
}
}
} break;
default:
break;
}
} break;
default:
// Intentionally left blank
break;
}
callback->Success("");
return true;
}
@ -960,6 +1015,50 @@ class OSRTestHandler : public RoutingTestHandler,
1);
}
} break;
case OSR_TEST_TOUCH_START:
case OSR_TEST_TOUCH_MOVE:
case OSR_TEST_TOUCH_END:
case OSR_TEST_TOUCH_CANCEL: {
// We trigger a valid Touch workflow sequence and close the tests
// at seperate points for the 4 cases
if (StartTest()) {
const CefRect& touchdiv = GetElementBounds("touchdiv");
// click inside edit box so that text could be entered
CefTouchEvent touch_event1;
touch_event1.id = 0;
touch_event1.x = MiddleX(touchdiv) - 45;
touch_event1.y = MiddleY(touchdiv);
touch_event1.modifiers = 0;
touch_event1.type = CEF_TET_PRESSED;
CefTouchEvent touch_event2;
touch_event2.id = 1;
touch_event2.x = MiddleX(touchdiv) + 45;
touch_event2.y = MiddleY(touchdiv);
touch_event2.modifiers = 0;
touch_event2.type = CEF_TET_PRESSED;
browser->GetHost()->SendTouchEvent(touch_event1);
browser->GetHost()->SendTouchEvent(touch_event2);
// Move the Touch fingers closer
touch_event1.type = touch_event2.type = CEF_TET_MOVED;
for (size_t i = 0; i < 40; i++) {
touch_event1.x++;
touch_event2.x--;
browser->GetHost()->SendTouchEvent(touch_event1);
browser->GetHost()->SendTouchEvent(touch_event2);
}
// Now release the Touch fingers or cancel them
if (test_type_ == OSR_TEST_TOUCH_CANCEL)
touch_event1.type = touch_event2.type = CEF_TET_CANCELLED;
else
touch_event1.type = touch_event2.type = CEF_TET_RELEASED;
browser->GetHost()->SendTouchEvent(touch_event1);
browser->GetHost()->SendTouchEvent(touch_event2);
}
} break;
default:
break;
}
@ -1349,6 +1448,7 @@ class OSRTestHandler : public RoutingTestHandler,
int event_count_;
int event_total_;
bool started_;
cef_touch_event_type_t touch_state_;
TrackCallback got_update_cursor_;
TrackCallback got_navigation_focus_event_;
TrackCallback got_system_focus_event_;
@ -1441,3 +1541,11 @@ OSR_TEST(IMECancelComposition2x, OSR_TEST_IME_CANCEL_COMPOSITION, 2.0f);
OSR_TEST(TextSelectionChanged, OSR_TEST_TEXT_SELECTION_CHANGE, 1.0f);
OSR_TEST(TextSelectionChanged2x, OSR_TEST_TEXT_SELECTION_CHANGE, 2.0f);
OSR_TEST(VirtualKeyboard, OSR_TEST_VIRTUAL_KEYBOARD, 1.0f);
OSR_TEST(TouchStart, OSR_TEST_TOUCH_START, 1.0f);
OSR_TEST(TouchStart2X, OSR_TEST_TOUCH_START, 2.0f);
OSR_TEST(TouchMove, OSR_TEST_TOUCH_MOVE, 1.0f);
OSR_TEST(TouchMove2X, OSR_TEST_TOUCH_MOVE, 2.0f);
OSR_TEST(TouchEnd, OSR_TEST_TOUCH_END, 1.0f);
OSR_TEST(TouchEnd2X, OSR_TEST_TOUCH_END, 2.0f);
OSR_TEST(TouchCancel, OSR_TEST_TOUCH_CANCEL, 1.0f);
OSR_TEST(TouchCancel2X, OSR_TEST_TOUCH_CANCEL, 2.0f);

View File

@ -25,6 +25,13 @@
left: 7px;
opacity: 0.4;
}
#touchdiv {
width: 100px;
height: 50px;
background-color: red;
float: left;
margin-left: 10px;
}
</style>
<script>
function getElement(id) { return document.getElementById(id); }
@ -53,6 +60,7 @@
elems.push(getElementBounds('btnnavigate'));
elems.push(getElementBounds('dropdiv'));
elems.push(getElementBounds('dragdiv'));
elems.push(getElementBounds('touchdiv'));
if (window.testQuery)
window.testQuery({request: JSON.stringify(param)});
@ -115,6 +123,21 @@
selection.removeAllRanges();
selection.addRange(range);
}
function onTouchEvent(ev) {
var param = 'osr' + ev.type;
// For Touch start also include touch points.
if (event.type == "touchstart")
param += ev.touches.length;
// For Touch Move include the touches that changed.
if (event.type == "touchmove")
param += ev.changedTouches.length;
// Results in a call to the OnQuery method in os_rendering_unittest.cc.
if (window.testQuery)
window.testQuery({request: param});
}
</script>
<body onfocus='onEventTest(event)' onblur='onEventTest(event)' onload='load();'>
<h1 id='LI00' onclick="onEventTest(event)">
@ -146,12 +169,15 @@
<li id='LI11' onclick='selectText(event)'>SELECTED_TEXT_RANGE</li>
<li><input id='email' type='text' size=10 inputmode='email'></li>
</ol>
<div class="dropdiv" id="dropdiv" ondrop="drop(event)" ondragover="allowDrop(event)">
<span id="draghere">Drag here</span>
</div>
<div class="dropdiv">
<div id="dragdiv" draggable="true" ondragstart="drag(event)"></div>
</div>
<div id="touchdiv" ontouchstart="onTouchEvent(event)" ontouchend="onTouchEvent(event)" ontouchmove="onTouchEvent(event)" ontouchcancel="onTouchEvent(event)">
</div>
<br />
<br />
<br />