Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(137)

Unified Diff: ui/touch_selection/touch_selection_controller.cc

Issue 903143003: wip: Touch Text Selection Prototypes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@selection_granularity_on_unified
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/touch_selection/touch_selection_controller.cc
diff --git a/ui/touch_selection/touch_selection_controller.cc b/ui/touch_selection/touch_selection_controller.cc
index ec720b4280865ebdf66a4c1e49b4c73fa7b5324e..dbc7e5e47152df6b323f339c79ca4fa5ba3fb0a9 100644
--- a/ui/touch_selection/touch_selection_controller.cc
+++ b/ui/touch_selection/touch_selection_controller.cc
@@ -39,11 +39,208 @@ TouchHandleOrientation ToTouchHandleOrientation(SelectionBound::Type type) {
} // namespace
+class GranularityStrategy {
+ public:
+ virtual ~GranularityStrategy() {};
+ virtual void OnSelectionBoundsUpdated(const SelectionBound& start,
+ const SelectionBound& end) {};
+ virtual void OnHandleDragBegin(const gfx::PointF& position,
+ base::TimeTicks event_time,
+ TouchSelectionController* controller) {};
+ virtual TextSelectionGranularity OnHandleDragUpdate(
+ const gfx::PointF& position,
+ const gfx::PointF& line_position,
+ base::TimeTicks event_time,
+ bool end_handle_dragged) { return ui::CHARACTER_GRANULARITY; };
+ protected:
+ GranularityStrategy() {};
+};
+
+class DefaultGranularityStrategy : public GranularityStrategy {
+ public:
+ DefaultGranularityStrategy() {};
+ ~DefaultGranularityStrategy() override {};
+};
+
+class DirectionGranularityStrategy : public GranularityStrategy {
+ public:
+ DirectionGranularityStrategy() : granularity_(ui::CHARACTER_GRANULARITY) {};
+
+ ~DirectionGranularityStrategy() override {};
+
+ void OnSelectionBoundsUpdated(const SelectionBound& start,
+ const SelectionBound& end) override {
+// LOG(ERROR) << "Bounds updated: "
+// << "start.y/2=" << (start.edge_bottom_rounded().y() + start.edge_top_rounded().y()) /2
+// << ", start.x=" << start.edge_bottom_rounded().x()
+// << ", end.y/2=" << (end.edge_bottom_rounded().y() + end.edge_top_rounded().y()) / 2
+// << ", end.x=" << end.edge_bottom_rounded().x();
+
+ if (granularity_ == ui::WORD_GRANULARITY) {
+ granularity_threshold_start_ = start;
+ granularity_threshold_end_ = end;
+ }
+ };
+
+ void OnHandleDragBegin(const gfx::PointF& position,
+ base::TimeTicks event_time,
+ TouchSelectionController* controller) override {
+ // TODO(mfomitchev):
+ // Ideally we want word boundaries communicated in CompositorFrameMetadata
+ // (see RenderWidgetHostViewAura::OnSwapCompositorFrame)
+ granularity_threshold_start_ = controller->start();
+ granularity_threshold_end_ = controller->end();
+ farthest_dragging_handle_position_ = position;
+ granularity_ = ui::WORD_GRANULARITY;
+ };
+
+ // TODO(mfomitchev): perhaps this should depend on character size?
+ // tap_slop_ is too big, uses max_touch_move_in_pixels_for_click. Perhaps
+ // we should use span_slop? See GestureConfiguration
+ const int kHandleDragSlop = 7;
+ TextSelectionGranularity OnHandleDragUpdate(
+ const gfx::PointF& position,
+ const gfx::PointF& line_position,
+ base::TimeTicks event_time,
+ bool end_handle_dragged) override {
+ if (end_handle_dragged) {
+ if (line_position.y() > granularity_threshold_end_.edge_bottom().y()) {
+ LOG(ERROR) << "Moved down a line - adjusting max_dragging_handle_position_";
+ farthest_dragging_handle_position_ = position;
+ if (granularity_ == ui::CHARACTER_GRANULARITY) {
+ LOG(ERROR) << "Moved down a line, switching to WORD_GRANULARITY";
+ granularity_ = ui::WORD_GRANULARITY;
+ }
+ } else if (line_position.y() < granularity_threshold_end_.edge_top().y()) {
+ LOG(ERROR) << "Moved up a line - adjusting max_dragging_handle_position_";
+ farthest_dragging_handle_position_ = position;
+ if (granularity_ == ui::CHARACTER_GRANULARITY) {
+ granularity_ = ui::WORD_GRANULARITY;
+ LOG(ERROR) << "Moved up a line - switching to WORD_GRANULARITY";
+ }
+ } else if (position.x() > farthest_dragging_handle_position_.x()) {
+ LOG(ERROR) << "Incrementing max_dragging_handle_position_";
+ farthest_dragging_handle_position_ = position;
+ if (granularity_ == ui::CHARACTER_GRANULARITY &&
+ position.x() > granularity_threshold_end_.edge_bottom().x()) {
+ granularity_ = ui::WORD_GRANULARITY;
+ LOG(ERROR) << "Moved right of granularity_threshold_end_,"
+ << " switching to WORD_GRANULARITY";
+ }
+ } else if (position.x() + kHandleDragSlop <
+ farthest_dragging_handle_position_.x()) {
+ if (granularity_ == ui::WORD_GRANULARITY) {
+ granularity_ = ui::CHARACTER_GRANULARITY;
+ LOG(ERROR) << "Moved left of max_dragging_handle_position_,"
+ << " switching to CHARACTER_GRANULARITY";
+ }
+ }
+ } else { //!end_handle_dragged
+ if (line_position.y() < granularity_threshold_start_.edge_top().y() ||
+ line_position.y() > granularity_threshold_start_.edge_bottom().y()) {
+ // Line change
+ farthest_dragging_handle_position_ = position;
+ granularity_ = ui::WORD_GRANULARITY;
+ } else if (position.x() < farthest_dragging_handle_position_.x()) {
+ farthest_dragging_handle_position_ = position;
+ if (position.x() < granularity_threshold_start_.edge_bottom().x())
+ granularity_ = ui::WORD_GRANULARITY;
+ } else if (position.x() - kHandleDragSlop >
+ farthest_dragging_handle_position_.x()) {
+ granularity_ = ui::CHARACTER_GRANULARITY;
+ }
+ }
+ return granularity_;
+ }
+
+ private:
+ TextSelectionGranularity granularity_;
+ SelectionBound granularity_threshold_start_;
+ SelectionBound granularity_threshold_end_;
+ // If we go left of this by more than slop - switch to CHAR granularity
+ // For right handle - farthest down/right
+ // For left handle - farthest up/left
+ gfx::PointF farthest_dragging_handle_position_;
+
+ DISALLOW_COPY_AND_ASSIGN(DirectionGranularityStrategy);
+};
+
+class VelocityGranularityStrategy : public GranularityStrategy {
+ public:
+ VelocityGranularityStrategy() :
+ granularity_(ui::CHARACTER_GRANULARITY),
+ avg_velocity_(0.f),
+ filterTimeConstant_(kFilterTimeConstant),
+ velocityGranularityThreshold_(kVelocityGranularityThreshold) {};
+
+ ~VelocityGranularityStrategy() override {};
+
+ const float kFilterTimeConstant = 0.3f; // half decay @ 300ms
+ const float kVelocityGranularityThreshold = 80.f;
+
+ void SetStrategyParameters(int halfDecayMs, int threshold) {
+ filterTimeConstant_ = halfDecayMs / 1000.f;
+ velocityGranularityThreshold_ = threshold;
+ }
+
+ void OnHandleDragBegin(const gfx::PointF& position,
+ base::TimeTicks event_time,
+ TouchSelectionController* controller) override {
+ last_dragging_handle_position_ = position;
+ avg_velocity_ = 0;
+ last_event_time_ = event_time;
+ granularity_ = ui::WORD_GRANULARITY;
+ };
+
+ TextSelectionGranularity OnHandleDragUpdate(
+ const gfx::PointF& position,
+ const gfx::PointF& line_position,
+ base::TimeTicks event_time,
+ bool end_handle_dragged) override {
+ float dist = (position - last_dragging_handle_position_).Length();
+ float dt = static_cast<float>((event_time - last_event_time_).InSecondsF());
+ float current_velocity = dist / dt;
+
+ if (avg_velocity_ == 0) {
+ avg_velocity_ = current_velocity;
+ } else {
+ float alpha = dt / (filterTimeConstant_ + dt);
+ avg_velocity_ += (current_velocity - avg_velocity_) * alpha;
+ }
+
+ if (avg_velocity_ > velocityGranularityThreshold_)
+ granularity_ = ui::WORD_GRANULARITY;
+ else
+ granularity_ = ui::CHARACTER_GRANULARITY;
+
+ LOG(ERROR) << "avg_velocity=" << avg_velocity_
+ << ", current_velocity=" << current_velocity;
+
+ last_dragging_handle_position_ = position;
+ last_event_time_ = event_time;
+
+ return granularity_;
+ };
+
+ private:
+ TextSelectionGranularity granularity_;
+ gfx::PointF last_dragging_handle_position_;
+ base::TimeTicks last_event_time_;
+ float avg_velocity_;
+
+ float filterTimeConstant_;
+ float velocityGranularityThreshold_;
+
+
+ DISALLOW_COPY_AND_ASSIGN(VelocityGranularityStrategy);
+};
+
TouchSelectionController::TouchSelectionController(
TouchSelectionControllerClient* client,
base::TimeDelta tap_timeout,
float tap_slop,
- bool show_on_tap_for_empty_editable)
+ bool show_on_tap_for_empty_editable,
+ TextSelectionGranularityStrategy selection_granularity_strategy)
: client_(client),
tap_timeout_(tap_timeout),
tap_slop_(tap_slop),
@@ -57,19 +254,43 @@ TouchSelectionController::TouchSelectionController(
activate_selection_automatically_(false),
selection_empty_(false),
selection_editable_(false),
- temporarily_hidden_(false) {
+ temporarily_hidden_(false),
+ selection_granularity_strategy_(selection_granularity_strategy) {
DCHECK(client_);
+ switch (selection_granularity_strategy) {
+ case GRANULARITY_STRATEGY_DEFAULT:
+ granularity_strategy_.reset(new DefaultGranularityStrategy());
+ break;
+ case GRANULARITY_STRATEGY_DIRECTION:
+ granularity_strategy_.reset(new DirectionGranularityStrategy());
+ break;
+ case GRANULARITY_STRATEGY_VELOCITY:
+ granularity_strategy_.reset(new VelocityGranularityStrategy());
+ break;
+ }
}
TouchSelectionController::~TouchSelectionController() {
}
+void TouchSelectionController::SetVelocityStrategyParameters(int halfDecayMs,
+ int threshold) {
+ if (selection_granularity_strategy_ != GRANULARITY_STRATEGY_VELOCITY)
+ return;
+
+ VelocityGranularityStrategy* velocityStrategy =
+ static_cast<VelocityGranularityStrategy*>(granularity_strategy_.get());
+ velocityStrategy->SetStrategyParameters(halfDecayMs, threshold);
+}
+
void TouchSelectionController::OnSelectionBoundsUpdated(
const SelectionBound& start,
const SelectionBound& end) {
if (start == start_ && end_ == end)
return;
+ granularity_strategy_->OnSelectionBoundsUpdated(start, end);
+
start_ = start;
end_ = end;
start_orientation_ = ToTouchHandleOrientation(start_.type());
@@ -235,7 +456,8 @@ void TouchSelectionController::TryActivateSelection() {
}
}
-void TouchSelectionController::OnHandleDragBegin(const TouchHandle& handle) {
+void TouchSelectionController::OnHandleDragBegin(const TouchHandle& handle,
+ base::TimeTicks event_time) {
if (&handle == insertion_handle_.get()) {
client_->OnSelectionEvent(INSERTION_DRAG_STARTED, handle.position());
return;
@@ -245,30 +467,49 @@ void TouchSelectionController::OnHandleDragBegin(const TouchHandle& handle) {
if (&handle == start_selection_handle_.get()) {
base = end_selection_handle_->position() + GetEndLineOffset();
extent = start_selection_handle_->position() + GetStartLineOffset();
+ // TODO: HACK
+ client_->SelectBetweenCoordinates(base, start_.edge_bottom_rounded() + GetStartLineOffset());
} else {
base = start_selection_handle_->position() + GetStartLineOffset();
extent = end_selection_handle_->position() + GetEndLineOffset();
+ // TODO: HACK
+ client_->SelectBetweenCoordinates(base, end_.edge_bottom_rounded() + GetEndLineOffset());
}
+ granularity_strategy_->OnHandleDragBegin(handle.position(), event_time, this);
+
// When moving the handle we want to move only the extent point. Before doing
// so we must make sure that the base point is set correctly.
- client_->SelectBetweenCoordinates(base, extent);
+ // TODO: HACK - swallow the update
+ //client_->SelectBetweenCoordinates(base, extent);
+ //OnHandleDragUpdate(handle, handle.position());
client_->OnSelectionEvent(SELECTION_DRAG_STARTED, handle.position());
}
void TouchSelectionController::OnHandleDragUpdate(const TouchHandle& handle,
- const gfx::PointF& position) {
+ const gfx::PointF& position,
+ base::TimeTicks event_time) {
+ // TODO: figure out RTL
+ // TODO: start/end can switch! Handle!
+ bool end_handle_dragged = &handle == end_selection_handle_.get();
// As the position corresponds to the bottom left point of the selection
// bound, offset it by half the corresponding line height.
- gfx::Vector2dF line_offset = &handle == start_selection_handle_.get()
- ? GetStartLineOffset()
- : GetEndLineOffset();
+ gfx::Vector2dF line_offset = end_handle_dragged
+ ? GetEndLineOffset()
+ : GetStartLineOffset();
+
gfx::PointF line_position = position + line_offset;
+
if (&handle == insertion_handle_.get()) {
client_->MoveCaret(line_position);
} else {
- client_->MoveRangeSelectionExtent(line_position, ui::CHARACTER_GRANULARITY);
+ TextSelectionGranularity granularity =
+ granularity_strategy_->OnHandleDragUpdate(position,
+ line_position,
+ event_time,
+ end_handle_dragged);
+ client_->MoveRangeSelectionExtent(line_position, granularity);
}
}
« no previous file with comments | « ui/touch_selection/touch_selection_controller.h ('k') | ui/touch_selection/touch_selection_controller_aura.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698