Skip to content

Commit

Permalink
Port of Android platform gesture detection code to C++
Browse files Browse the repository at this point in the history
This is a direct C++ port of all Java classes utilized by the current
ContentViewGestureHandler, including forks of Android C++ classes used in
gesture detection. This includes the following:

* ZoomManager - Forked from Chromium.
* SnapScrollingController - Forked from Chromium.
* GestureDetector - Forked from Chromium class originally from Android.
* ScaleGestureDetector - Forked from Android.
* VelocityTracker - Forked from Android.
* VelocityTrackerState - Forked from Android.
* BitSet32 - Forked from Android.

A MotionEvent class is introduced to abstract touch event API differences
between Chromium and Android, allowing other platforms to hook into the
detection pipeline without loss of generality.

Note that this patch is additive only, and does not affect gesture detection
for current platforms.  Wiring for Android and Aura will land in separate
patches. (see https://codereview.chromium.org/128613003/)

BUG=332418
NOTRY=true

Review URL: https://codereview.chromium.org/171773012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@253489 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
jdduke@chromium.org committed Feb 26, 2014
1 parent 8a67750 commit d759e8a
Show file tree
Hide file tree
Showing 28 changed files with 5,360 additions and 0 deletions.
80 changes: 80 additions & 0 deletions ui/events/events.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,54 @@
}],
],
},
{
'target_name': 'gesture_detection',
'type': '<(component)',
'dependencies': [
'<(DEPTH)/base/base.gyp:base',
'<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'../gfx/gfx.gyp:gfx',
'../gfx/gfx.gyp:gfx_geometry',
'events_base',
],
'defines': [
'GESTURE_DETECTION_IMPLEMENTATION',
],
'sources': [
'gesture_detection/bitset_32.h',
'gesture_detection/gesture_detection_export.h',
'gesture_detection/gesture_detector.cc',
'gesture_detection/gesture_detector.h',
'gesture_detection/gesture_event_params.cc',
'gesture_detection/gesture_event_params.h',
'gesture_detection/gesture_config_helper.h',
'gesture_detection/gesture_config_helper_aura.cc',
'gesture_detection/gesture_config_helper_android.cc',
'gesture_detection/gesture_provider.cc',
'gesture_detection/gesture_provider.h',
'gesture_detection/motion_event.h',
'gesture_detection/scale_gesture_detector.cc',
'gesture_detection/scale_gesture_detector.h',
'gesture_detection/snap_scroll_controller.cc',
'gesture_detection/snap_scroll_controller.h',
'gesture_detection/velocity_tracker_state.cc',
'gesture_detection/velocity_tracker_state.h',
'gesture_detection/velocity_tracker.cc',
'gesture_detection/velocity_tracker.h',
],
'conditions': [
['use_aura==1', {
'dependencies': [
'events'
],
}],
['use_aura!=1 and OS!="android"', {
'sources': [
'gesture_detection/gesture_config_helper.cc',
],
}],
],
},
{
'target_name': 'events_test_support',
'type': 'static_library',
Expand Down Expand Up @@ -210,13 +258,19 @@
'events',
'events_base',
'events_test_support',
'gesture_detection'
],
'sources': [
'cocoa/cocoa_event_utils_unittest.mm',
'event_dispatcher_unittest.cc',
'event_processor_unittest.cc',
'event_unittest.cc',
'gestures/velocity_calculator_unittest.cc',
'gesture_detection/bitset_32_unittest.cc',
'gesture_detection/gesture_provider_unittest.cc',
'gesture_detection/mock_motion_event.h',
'gesture_detection/mock_motion_event.cc',
'gesture_detection/velocity_tracker_unittest.cc',
'keycodes/dom4/keycode_converter_unittest.cc',
'latency_info_unittest.cc',
'ozone/evdev/key_event_converter_evdev_unittest.cc',
Expand All @@ -229,7 +283,33 @@
'<(DEPTH)/base/allocator/allocator.gyp:allocator',
],
}],
['OS == "android" and gtest_target_type == "shared_library"', {
'dependencies': [
'../../testing/android/native_test.gyp:native_test_native_code',
],
}],
],
},
],
'conditions': [
# Special target to wrap a gtest_target_type==shared_library
# ui_unittests into an android apk for execution.
# See base.gyp for TODO(jrg)s about this strategy.
['OS == "android" and gtest_target_type == "shared_library"', {
'targets': [
{
'target_name': 'events_unittests_apk',
'type': 'none',
'dependencies': [
'events_unittests',
],
'variables': {
'test_suite_name': 'events_unittests',
'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)events_unittests<(SHARED_LIB_SUFFIX)',
},
'includes': [ '../../build/apk_test.gypi' ],
},
],
}],
],
}
2 changes: 2 additions & 0 deletions ui/events/gesture_detection/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
jdduke@chromium.org
tdresser@chromium.org
128 changes: 128 additions & 0 deletions ui/events/gesture_detection/bitset_32.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright 2014 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 UI_EVENTS_GESTURE_DETECTION_BITSET_32_H_
#define UI_EVENTS_GESTURE_DETECTION_BITSET_32_H_

#include "base/basictypes.h"

namespace ui {

// Port of BitSet32 from Android
// * platform/system/core/include/utils/BitSet.h
// * Change-Id: I9bbf41f9d2d4a2593b0e6d7d8be7e283f985bade
// * Please update the Change-Id as upstream Android changes are pulled.
struct BitSet32 {
uint32_t value;

inline BitSet32() : value(0) {}
explicit inline BitSet32(uint32_t value) : value(value) {}

// Gets the value associated with a particular bit index.
static inline uint32_t value_for_bit(uint32_t n) { return 0x80000000 >> n; }

// Clears the bit set.
inline void clear() { value = 0; }

// Returns the number of marked bits in the set.
inline uint32_t count() const { return popcnt(value); }

// Returns true if the bit set does not contain any marked bits.
inline bool is_empty() const { return !value; }

// Returns true if the bit set does not contain any unmarked bits.
inline bool is_full() const { return value == 0xffffffff; }

// Returns true if the specified bit is marked.
inline bool has_bit(uint32_t n) const {
return (value & value_for_bit(n)) != 0;
}

// Marks the specified bit.
inline void mark_bit(uint32_t n) { value |= value_for_bit(n); }

// Clears the specified bit.
inline void clear_bit(uint32_t n) { value &= ~value_for_bit(n); }

// Finds the first marked bit in the set.
// Result is undefined if all bits are unmarked.
inline uint32_t first_marked_bit() const { return clz(value); }

// Finds the first unmarked bit in the set.
// Result is undefined if all bits are marked.
inline uint32_t first_unmarked_bit() const { return clz(~value); }

// Finds the last marked bit in the set.
// Result is undefined if all bits are unmarked.
inline uint32_t last_marked_bit() const { return 31 - ctz(value); }

// Finds the first marked bit in the set and clears it. Returns the bit
// index.
// Result is undefined if all bits are unmarked.
inline uint32_t clear_first_marked_bit() {
uint32_t n = first_marked_bit();
clear_bit(n);
return n;
}

// Finds the first unmarked bit in the set and marks it. Returns the bit
// index.
// Result is undefined if all bits are marked.
inline uint32_t mark_first_unmarked_bit() {
uint32_t n = first_unmarked_bit();
mark_bit(n);
return n;
}

// Finds the last marked bit in the set and clears it. Returns the bit index.
// Result is undefined if all bits are unmarked.
inline uint32_t clear_last_marked_bit() {
uint32_t n = last_marked_bit();
clear_bit(n);
return n;
}

// Gets the inde of the specified bit in the set, which is the number of
// marked bits that appear before the specified bit.
inline uint32_t get_index_of_bit(uint32_t n) const {
return popcnt(value & ~(0xffffffffUL >> n));
}

inline bool operator==(const BitSet32& other) const {
return value == other.value;
}
inline bool operator!=(const BitSet32& other) const {
return value != other.value;
}

private:
#if defined(COMPILER_GCC) || defined(__clang__)
static inline uint32_t popcnt(uint32_t v) { return __builtin_popcount(v); }
static inline uint32_t clz(uint32_t v) { return __builtin_clz(v); }
static inline uint32_t ctz(uint32_t v) { return __builtin_ctz(v); }
#else
// http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
static inline uint32_t popcnt(uint32_t v) {
v = v - ((v >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
return (((v + (v >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
// TODO(jdduke): Use intrinsics (BitScan{Forward,Reverse}) with MSVC.
static inline uint32_t clz(uint32_t v) {
v |= (v >> 1);
v |= (v >> 2);
v |= (v >> 4);
v |= (v >> 8);
v |= (v >> 16);
return 32 - popcnt(v);
}
static inline uint32_t ctz(uint32_t v) {
return popcnt((v & static_cast<uint32_t>(-static_cast<int>(v))) - 1);
}
#endif
};

} // namespace ui

#endif // UI_EVENTS_GESTURE_DETECTION_BITSET_32_H_
100 changes: 100 additions & 0 deletions ui/events/gesture_detection/bitset_32_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright 2014 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 "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/gesture_detection/bitset_32.h"

namespace ui {

class BitSet32Test : public testing::Test {};

TEST_F(BitSet32Test, Basic) {
BitSet32 bits;

// Test the empty set.
EXPECT_EQ(0U, bits.count());
EXPECT_TRUE(bits.is_empty());
EXPECT_FALSE(bits.is_full());
EXPECT_FALSE(bits.has_bit(0));
EXPECT_FALSE(bits.has_bit(31));

// Mark the first bit.
bits.mark_bit(0);
EXPECT_EQ(1U, bits.count());
EXPECT_FALSE(bits.is_empty());
EXPECT_FALSE(bits.is_full());
EXPECT_TRUE(bits.has_bit(0));
EXPECT_FALSE(bits.has_bit(31));
EXPECT_EQ(0U, bits.first_marked_bit());
EXPECT_EQ(0U, bits.last_marked_bit());
EXPECT_EQ(1U, bits.first_unmarked_bit());

// Mark the last bit.
bits.mark_bit(31);
EXPECT_EQ(2U, bits.count());
EXPECT_FALSE(bits.is_empty());
EXPECT_FALSE(bits.is_full());
EXPECT_TRUE(bits.has_bit(0));
EXPECT_TRUE(bits.has_bit(31));
EXPECT_FALSE(bits.has_bit(15));
EXPECT_EQ(0U, bits.first_marked_bit());
EXPECT_EQ(31U, bits.last_marked_bit());
EXPECT_EQ(1U, bits.first_unmarked_bit());
EXPECT_EQ(0U, bits.get_index_of_bit(0));
EXPECT_EQ(1U, bits.get_index_of_bit(1));
EXPECT_EQ(1U, bits.get_index_of_bit(2));
EXPECT_EQ(1U, bits.get_index_of_bit(31));

// Clear the first bit.
bits.clear_first_marked_bit();
EXPECT_EQ(1U, bits.count());
EXPECT_FALSE(bits.is_empty());
EXPECT_FALSE(bits.is_full());
EXPECT_FALSE(bits.has_bit(0));
EXPECT_TRUE(bits.has_bit(31));
EXPECT_EQ(31U, bits.first_marked_bit());
EXPECT_EQ(31U, bits.last_marked_bit());
EXPECT_EQ(0U, bits.first_unmarked_bit());
EXPECT_EQ(0U, bits.get_index_of_bit(0));
EXPECT_EQ(0U, bits.get_index_of_bit(1));
EXPECT_EQ(0U, bits.get_index_of_bit(31));

// Clear the last bit (the set should be empty).
bits.clear_last_marked_bit();
EXPECT_EQ(0U, bits.count());
EXPECT_TRUE(bits.is_empty());
EXPECT_FALSE(bits.is_full());
EXPECT_FALSE(bits.has_bit(0));
EXPECT_FALSE(bits.has_bit(31));
EXPECT_EQ(0U, bits.get_index_of_bit(0));
EXPECT_EQ(0U, bits.get_index_of_bit(31));
EXPECT_EQ(BitSet32(), bits);

// Mark the first unmarked bit (bit 0).
bits.mark_first_unmarked_bit();
EXPECT_EQ(1U, bits.count());
EXPECT_FALSE(bits.is_empty());
EXPECT_FALSE(bits.is_full());
EXPECT_TRUE(bits.has_bit(0));
EXPECT_EQ(0U, bits.first_marked_bit());
EXPECT_EQ(0U, bits.last_marked_bit());
EXPECT_EQ(1U, bits.first_unmarked_bit());

// Mark the next unmarked bit (bit 1).
bits.mark_first_unmarked_bit();
EXPECT_EQ(2U, bits.count());
EXPECT_FALSE(bits.is_empty());
EXPECT_FALSE(bits.is_full());
EXPECT_TRUE(bits.has_bit(0));
EXPECT_TRUE(bits.has_bit(1));
EXPECT_EQ(0U, bits.first_marked_bit());
EXPECT_EQ(1U, bits.last_marked_bit());
EXPECT_EQ(2U, bits.first_unmarked_bit());
EXPECT_EQ(0U, bits.get_index_of_bit(0));
EXPECT_EQ(1U, bits.get_index_of_bit(1));
EXPECT_EQ(2U, bits.get_index_of_bit(2));
}

} // namespace ui
25 changes: 25 additions & 0 deletions ui/events/gesture_detection/gesture_config_helper.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2014 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 "ui/events/gesture_detection/gesture_config_helper.h"

namespace ui {

GestureDetector::Config DefaultGestureDetectorConfig() {
return GestureDetector::Config();
}

ScaleGestureDetector::Config DefaultScaleGestureDetectorConfig() {
return ScaleGestureDetector::Config();
}

SnapScrollController::Config DefaultSnapScrollControllerConfig() {
return SnapScrollController::Config();
}

GestureProvider::Config DefaultGestureProviderConfig() {
return GestureProvider::Config();
}

} // namespace ui
30 changes: 30 additions & 0 deletions ui/events/gesture_detection/gesture_config_helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2014 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 UI_EVENTS_GESTURE_DETECTION_GESTURE_CONFIG_HELPER_H_
#define UI_EVENTS_GESTURE_DETECTION_GESTURE_CONFIG_HELPER_H_

#include "ui/events/gesture_detection/gesture_detection_export.h"
#include "ui/events/gesture_detection/gesture_detector.h"
#include "ui/events/gesture_detection/gesture_provider.h"
#include "ui/events/gesture_detection/scale_gesture_detector.h"
#include "ui/events/gesture_detection/snap_scroll_controller.h"

namespace ui {

GESTURE_DETECTION_EXPORT GestureDetector::Config
DefaultGestureDetectorConfig();

GESTURE_DETECTION_EXPORT ScaleGestureDetector::Config
DefaultScaleGestureDetectorConfig();

GESTURE_DETECTION_EXPORT SnapScrollController::Config
DefaultSnapScrollControllerConfig();

GESTURE_DETECTION_EXPORT GestureProvider::Config
DefaultGestureProviderConfig();

} // namespace ui

#endif // UI_EVENTS_GESTURE_DETECTION_GESTURE_CONFIG_HELPER_H_
Loading

0 comments on commit d759e8a

Please sign in to comment.