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

Side by Side Diff: ui/views/touchui/touch_selection_controller_impl.cc

Issue 700563002: Implementing directional text selection handles (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@new_assets_text
Patch Set: Created 6 years, 1 month 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/touchui/touch_selection_controller_impl.h" 5 #include "ui/views/touchui/touch_selection_controller_impl.h"
6 6
7 #include "base/time/time.h" 7 #include "base/time/time.h"
8 #include "ui/aura/client/cursor_client.h" 8 #include "ui/aura/client/cursor_client.h"
9 #include "ui/aura/env.h" 9 #include "ui/aura/env.h"
10 #include "ui/aura/window.h" 10 #include "ui/aura/window.h"
11 #include "ui/base/resource/resource_bundle.h" 11 #include "ui/base/resource/resource_bundle.h"
12 #include "ui/gfx/canvas.h" 12 #include "ui/gfx/canvas.h"
13 #include "ui/gfx/image/image.h" 13 #include "ui/gfx/image/image.h"
14 #include "ui/gfx/path.h" 14 #include "ui/gfx/path.h"
15 #include "ui/gfx/rect.h" 15 #include "ui/gfx/rect.h"
16 #include "ui/gfx/screen.h" 16 #include "ui/gfx/screen.h"
17 #include "ui/gfx/size.h" 17 #include "ui/gfx/size.h"
18 #include "ui/resources/grit/ui_resources.h" 18 #include "ui/resources/grit/ui_resources.h"
19 #include "ui/strings/grit/ui_strings.h" 19 #include "ui/strings/grit/ui_strings.h"
20 #include "ui/views/widget/widget.h" 20 #include "ui/views/widget/widget.h"
21 #include "ui/wm/core/coordinate_conversion.h"
21 #include "ui/wm/core/masked_window_targeter.h" 22 #include "ui/wm/core/masked_window_targeter.h"
22 23
23 namespace { 24 namespace {
24 25
25 // Constants defining the visual attributes of selection handles 26 // Constants defining the visual attributes of selection handles
26 const int kSelectionHandleLineWidth = 1; 27
28 // Controls the width of the cursor line associated with the selection handle.
29 const int kSelectionHandleLineWidth = 2;
30
27 const SkColor kSelectionHandleLineColor = 31 const SkColor kSelectionHandleLineColor =
28 SkColorSetRGB(0x42, 0x81, 0xf4); 32 SkColorSetRGB(0x42, 0x81, 0xf4);
29 33
30 // When a handle is dragged, the drag position reported to the client view is 34 // Padding around the selection handle defining the area that will be included
31 // offset vertically to represent the cursor position. This constant specifies 35 // in the touch target to make dragging the handle easier (see pic below).
32 // the offset in pixels above the "O" (see pic below). This is required because
33 // say if this is zero, that means the drag position we report is the point
34 // right above the "O" or the bottom most point of the cursor "|". In that case,
35 // a vertical movement of even one pixel will make the handle jump to the line
36 // below it. So when the user just starts dragging, the handle will jump to the
37 // next line if the user makes any vertical movement. It is correct but
38 // looks/feels weird. So we have this non-zero offset to prevent this jumping.
39 //
40 // Editing handle widget showing the difference between the position of the
41 // ET_GESTURE_SCROLL_UPDATE event and the drag position reported to the client:
42 // _____ 36 // _____
43 // | |<-|---- Drag position reported to client 37 // | | |
44 // _ | O | 38 // _ | O |
45 // Vertical Padding __| | <-|---- ET_GESTURE_SCROLL_UPDATE position 39 // Vertical Padding __| | |<--- Editing handle widget
46 // |_ |_____|<--- Editing handle widget 40 // |_ |_____|
47 // 41 //
48 // | | 42 // | |
49 // T 43 // T
50 // Horizontal Padding 44 // Horizontal Padding
51 // 45 //
52 const int kSelectionHandleVerticalDragOffset = 5;
53
54 // Padding around the selection handle defining the area that will be included
55 // in the touch target to make dragging the handle easier (see pic above).
56 const int kSelectionHandleHorizPadding = 10; 46 const int kSelectionHandleHorizPadding = 10;
57 const int kSelectionHandleVertPadding = 20; 47 const int kSelectionHandleVertPadding = 20;
58 48
59 const int kContextMenuTimoutMs = 200; 49 const int kContextMenuTimoutMs = 200;
60 50
61 const int kSelectionHandleQuickFadeDurationMs = 50; 51 const int kSelectionHandleQuickFadeDurationMs = 50;
62 52
63 // Minimum height for selection handle bar. If the bar height is going to be 53 // Minimum height for selection handle bar. If the bar height is going to be
64 // less than this value, handle will not be shown. 54 // less than this value, handle will not be shown.
65 const int kSelectionHandleBarMinHeight = 5; 55 const int kSelectionHandleBarMinHeight = 5;
66 // Maximum amount that selection handle bar can stick out of client view's 56 // Maximum amount that selection handle bar can stick out of client view's
67 // boundaries. 57 // boundaries.
68 const int kSelectionHandleBarBottomAllowance = 3; 58 const int kSelectionHandleBarBottomAllowance = 3;
69 59
70 // Creates a widget to host SelectionHandleView. 60 // Creates a widget to host SelectionHandleView.
71 views::Widget* CreateTouchSelectionPopupWidget( 61 views::Widget* CreateTouchSelectionPopupWidget(
72 gfx::NativeView context, 62 gfx::NativeView context,
73 views::WidgetDelegate* widget_delegate) { 63 views::WidgetDelegate* widget_delegate) {
74 views::Widget* widget = new views::Widget; 64 views::Widget* widget = new views::Widget;
75 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); 65 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
76 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 66 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
77 params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE; 67 params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
78 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 68 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
79 params.parent = context; 69 params.parent = context;
80 params.delegate = widget_delegate; 70 params.delegate = widget_delegate;
81 widget->Init(params); 71 widget->Init(params);
82 return widget; 72 return widget;
83 } 73 }
84 74
mohsen 2014/11/07 16:52:27 The only difference between following 3 functions
mfomitchev 2014/11/10 04:04:12 I kind of like not having to pass id. And not havi
85 gfx::Image* GetHandleImage() { 75 gfx::Image* GetCenterHandleImage() {
86 static gfx::Image* handle_image = NULL; 76 static gfx::Image* handle_image = nullptr;
87 if (!handle_image) { 77 if (!handle_image) {
88 handle_image = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( 78 handle_image = &ui::ResourceBundle::GetSharedInstance().GetImageNamed(
89 IDR_TEXT_SELECTION_HANDLE); 79 IDR_TEXT_SELECTION_HANDLE_CENTER);
90 } 80 }
91 return handle_image; 81 return handle_image;
92 } 82 }
93 83
94 gfx::Size GetHandleImageSize() { 84 gfx::Image* GetLeftHandleImage() {
95 return GetHandleImage()->Size(); 85 static gfx::Image* handle_image = nullptr;
86 if (!handle_image) {
87 handle_image = &ui::ResourceBundle::GetSharedInstance().GetImageNamed(
88 IDR_TEXT_SELECTION_HANDLE_LEFT);
89 }
90 return handle_image;
96 } 91 }
97 92
98 // Cannot use gfx::UnionRect since it does not work for empty rects. 93 gfx::Image* GetRightHandleImage() {
99 gfx::Rect Union(const gfx::Rect& r1, const gfx::Rect& r2) { 94 static gfx::Image* handle_image = nullptr;
100 int rx = std::min(r1.x(), r2.x()); 95 if (!handle_image) {
101 int ry = std::min(r1.y(), r2.y()); 96 handle_image = &ui::ResourceBundle::GetSharedInstance().GetImageNamed(
102 int rr = std::max(r1.right(), r2.right()); 97 IDR_TEXT_SELECTION_HANDLE_RIGHT);
103 int rb = std::max(r1.bottom(), r2.bottom()); 98 }
104 99 return handle_image;
105 return gfx::Rect(rx, ry, rr - rx, rb - ry);
106 } 100 }
107 101
108 // Convenience methods to convert a |rect| from screen to the |client|'s 102 // Return the appropriate handle image based on the bound's type
103 gfx::Image* GetHandleImage(const ui::SelectionBound& bound) {
mohsen 2014/11/07 16:52:27 GetHandleImage(ui::SelectionBound::Type bound_type
mfomitchev 2014/11/10 04:04:12 Done.
104 switch(bound.type) {
105 case ui::SelectionBound::LEFT:
106 return GetLeftHandleImage();
107 case ui::SelectionBound::CENTER:
108 return GetCenterHandleImage();
109 case ui::SelectionBound::RIGHT:
110 return GetRightHandleImage();
111 default:
112 NOTREACHED() << "Invalid touch handle bound type.";
113 return nullptr;
114 };
115 }
116
117 enum Alignment {ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT};
mohsen 2014/11/07 16:52:27 Can't we just use SelectionBound::Type enum?
mfomitchev 2014/11/10 04:04:12 Not sure what are you suggesting - have GetCursorA
mohsen 2014/11/10 22:25:59 You have codes like this: Alignment alignment =
mfomitchev 2014/11/10 23:07:29 GetCursorAlignment is used twice, so doing this wo
mohsen 2014/11/13 22:59:56 What I was suggesting was to remove Alignment enum
mfomitchev 2014/11/13 23:49:51 Yup, that's how I understood it. Whether the align
118
119 // Determine the cursor line alignment to the handle image based on the bound
120 // type. Depends on the visual shapes of the handle image assets.
121 Alignment GetCursorAlignment(ui::SelectionBound::Type bound_type) {
122 switch (bound_type) {
123 case ui::SelectionBound::LEFT:
124 return ALIGN_RIGHT;
125 case ui::SelectionBound::RIGHT:
126 return ALIGN_LEFT;
127 case ui::SelectionBound::CENTER:
128 return ALIGN_CENTER;
129 default:
130 NOTREACHED() << "Undefined bound type for cursor alignment.";
131 return ALIGN_LEFT;
132 };
133 }
134
135 // Calculates the bounds of the widget containing the selection handle based
136 // on the SelectionBound's type and location
137 gfx::Rect GetSelectionWidgetBounds(const ui::SelectionBound& bound) {
138 Alignment cursor_alignment = GetCursorAlignment(bound.type);
139 gfx::Size image_size = GetHandleImage(bound)->Size();
140 int widget_width = image_size.width() + 2 * kSelectionHandleHorizPadding;
141 int widget_height = bound.GetHeight() + image_size.height() +
142 kSelectionHandleVertPadding;
143 int widget_left = 0;
144 switch (cursor_alignment) {
145 case ALIGN_LEFT:
146 widget_left = bound.edge_top.x() - kSelectionHandleHorizPadding;
147 break;
148 case ALIGN_RIGHT:
149 widget_left = bound.edge_top.x() - image_size.width() -
150 kSelectionHandleHorizPadding;
151 break;
152 case ALIGN_CENTER:
153 widget_left = bound.edge_top.x() - widget_width / 2;
154 break;
155 };
156 return gfx::Rect(
157 widget_left, bound.edge_top.y(), widget_width, widget_height);
158 }
159
160 gfx::Size GetMaxHandleImageSize() {
161 static gfx::Size* max_size = nullptr;
mohsen 2014/11/07 16:52:27 Is this caching to prevent image load every time o
mfomitchev 2014/11/10 04:04:12 Done.
162 if (!max_size) {
163 gfx::Rect center_rect = gfx::Rect(GetCenterHandleImage()->Size());
164 gfx::Rect left_rect = gfx::Rect(GetLeftHandleImage()->Size());
165 gfx::Rect right_rect = gfx::Rect(GetRightHandleImage()->Size());
166 gfx::Rect union_rect = center_rect;
167 union_rect.Union(left_rect);
168 union_rect.Union(right_rect);
169 max_size = new gfx::Size(union_rect.size());
170 }
171 return *max_size;
172 }
173
174 // Convenience methods to convert a |bound| from screen to the |client|'s
109 // coordinate system and vice versa. 175 // coordinate system and vice versa.
110 // Note that this is not quite correct because it does not take into account 176 // Note that this is not quite correct because it does not take into account
111 // transforms such as rotation and scaling. This should be in TouchEditable. 177 // transforms such as rotation and scaling. This should be in TouchEditable.
112 // TODO(varunjain): Fix this. 178 // TODO(varunjain): Fix this.
113 gfx::Rect ConvertFromScreen(ui::TouchEditable* client, const gfx::Rect& rect) { 179 ui::SelectionBound ConvertFromScreen(ui::TouchEditable* client,
114 gfx::Point origin = rect.origin(); 180 const ui::SelectionBound& bound) {
115 client->ConvertPointFromScreen(&origin); 181 ui::SelectionBound result = bound;
116 return gfx::Rect(origin, rect.size()); 182 gfx::Point edge_bottom = bound.edge_bottom;
183 gfx::Point edge_top = bound.edge_top;
184 client->ConvertPointFromScreen(&edge_bottom);
185 client->ConvertPointFromScreen(&edge_top);
186 result.edge_bottom = edge_bottom;
187 result.edge_top = edge_top;
188 return result;
117 } 189 }
118 gfx::Rect ConvertToScreen(ui::TouchEditable* client, const gfx::Rect& rect) { 190
119 gfx::Point origin = rect.origin(); 191 ui::SelectionBound ConvertToScreen(ui::TouchEditable* client,
120 client->ConvertPointToScreen(&origin); 192 const ui::SelectionBound& bound) {
121 return gfx::Rect(origin, rect.size()); 193 ui::SelectionBound result = bound;
194 gfx::Point edge_bottom = bound.edge_bottom;
195 gfx::Point edge_top = bound.edge_top;
196 client->ConvertPointToScreen(&edge_bottom);
197 client->ConvertPointToScreen(&edge_top);
198 result.edge_bottom = edge_bottom;
199 result.edge_top = edge_top;
200 return result;
201 }
202
203 gfx::Rect BoundToRect(const ui::SelectionBound& bound) {
204 return gfx::Rect(bound.edge_top,
205 gfx::Size(0, bound.edge_bottom.y() - bound.edge_top.y()));
mohsen 2014/11/07 16:52:27 gfx::BoundingRect()
mfomitchev 2014/11/10 04:04:12 Done
122 } 206 }
123 207
124 } // namespace 208 } // namespace
125 209
126 namespace views { 210 namespace views {
127 211
128 typedef TouchSelectionControllerImpl::EditingHandleView EditingHandleView; 212 typedef TouchSelectionControllerImpl::EditingHandleView EditingHandleView;
129 213
130 class TouchHandleWindowTargeter : public wm::MaskedWindowTargeter { 214 class TouchHandleWindowTargeter : public wm::MaskedWindowTargeter {
131 public: 215 public:
(...skipping 11 matching lines...) Expand all
143 DISALLOW_COPY_AND_ASSIGN(TouchHandleWindowTargeter); 227 DISALLOW_COPY_AND_ASSIGN(TouchHandleWindowTargeter);
144 }; 228 };
145 229
146 // A View that displays the text selection handle. 230 // A View that displays the text selection handle.
147 class TouchSelectionControllerImpl::EditingHandleView 231 class TouchSelectionControllerImpl::EditingHandleView
148 : public views::WidgetDelegateView { 232 : public views::WidgetDelegateView {
149 public: 233 public:
150 EditingHandleView(TouchSelectionControllerImpl* controller, 234 EditingHandleView(TouchSelectionControllerImpl* controller,
151 gfx::NativeView context) 235 gfx::NativeView context)
152 : controller_(controller), 236 : controller_(controller),
153 drag_offset_(0), 237 image_(GetCenterHandleImage()),
mohsen 2014/11/07 16:52:27 Can't we initialize image_ with nullptr?
mfomitchev 2014/11/10 04:04:12 I had that initially, but I feel better not having
154 draw_invisible_(false) { 238 draw_invisible_(false) {
155 widget_.reset(CreateTouchSelectionPopupWidget(context, this)); 239 widget_.reset(CreateTouchSelectionPopupWidget(context, this));
156 widget_->SetContentsView(this); 240 widget_->SetContentsView(this);
157 241
158 aura::Window* window = widget_->GetNativeWindow(); 242 aura::Window* window = widget_->GetNativeWindow();
159 window->SetEventTargeter(scoped_ptr<ui::EventTargeter>( 243 window->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
160 new TouchHandleWindowTargeter(window, this))); 244 new TouchHandleWindowTargeter(window, this)));
161 245
162 // We are owned by the TouchSelectionController. 246 // We are owned by the TouchSelectionController.
163 set_owned_by_client(); 247 set_owned_by_client();
164 } 248 }
165 249
166 ~EditingHandleView() override { SetWidgetVisible(false, false); } 250 ~EditingHandleView() override { SetWidgetVisible(false, false); }
167 251
252 const gfx::Image* image() const { return image_; }
253
254 const ui::SelectionBound& selection_bound() { return selection_bound_; }
mohsen 2014/11/07 16:52:27 Apparently it is not used anywhere. So, you can re
mfomitchev 2014/11/10 04:04:12 Done.
255
168 // Overridden from views::WidgetDelegateView: 256 // Overridden from views::WidgetDelegateView:
169 bool WidgetHasHitTestMask() const override { return true; } 257 bool WidgetHasHitTestMask() const override { return true; }
170 258
171 void GetWidgetHitTestMask(gfx::Path* mask) const override { 259 void GetWidgetHitTestMask(gfx::Path* mask) const override {
172 gfx::Size image_size = GetHandleImageSize(); 260 gfx::Size image_size = image_->Size();
173 mask->addRect(SkIntToScalar(0), SkIntToScalar(selection_rect_.height()), 261 mask->addRect(
262 SkIntToScalar(0),
263 SkIntToScalar(selection_bound_.GetHeight()),
174 SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding, 264 SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding,
175 SkIntToScalar(selection_rect_.height() + image_size.height() + 265 SkIntToScalar(selection_bound_.GetHeight() + image_size.height() +
176 kSelectionHandleVertPadding)); 266 kSelectionHandleVertPadding));
177 } 267 }
178 268
179 void DeleteDelegate() override { 269 void DeleteDelegate() override {
180 // We are owned and deleted by TouchSelectionController. 270 // We are owned and deleted by TouchSelectionController.
181 } 271 }
182 272
183 // Overridden from views::View: 273 // Overridden from views::View:
184 void OnPaint(gfx::Canvas* canvas) override { 274 void OnPaint(gfx::Canvas* canvas) override {
185 if (draw_invisible_) 275 if (draw_invisible_)
186 return; 276 return;
187 gfx::Size image_size = GetHandleImageSize();
188 int cursor_pos_x = image_size.width() / 2 - kSelectionHandleLineWidth +
189 kSelectionHandleHorizPadding;
190 277
278 Alignment cursor_alignment = GetCursorAlignment(selection_bound_.type);
279 int cursor_x = 0;
280 switch (cursor_alignment) {
281 case ALIGN_RIGHT:
282 cursor_x = selection_bound_.edge_top.x() - kSelectionHandleLineWidth;
283 break;
284 case ALIGN_LEFT:
285 cursor_x = selection_bound_.edge_top.x();
286 break;
287 case ALIGN_CENTER:
288 cursor_x =
289 selection_bound_.edge_top.x() - kSelectionHandleLineWidth / 2;
290 break;
291 };
191 // Draw the cursor line. 292 // Draw the cursor line.
192 canvas->FillRect( 293 canvas->FillRect(gfx::Rect(cursor_x,
193 gfx::Rect(cursor_pos_x, 0, 294 0,
194 2 * kSelectionHandleLineWidth + 1, selection_rect_.height()), 295 kSelectionHandleLineWidth,
195 kSelectionHandleLineColor); 296 selection_bound_.GetHeight()),
196 297 kSelectionHandleLineColor);
197 // Draw the handle image. 298 // Draw the handle image.
198 canvas->DrawImageInt(*GetHandleImage()->ToImageSkia(), 299 canvas->DrawImageInt(*image_->ToImageSkia(),
199 kSelectionHandleHorizPadding, selection_rect_.height()); 300 kSelectionHandleHorizPadding, selection_bound_.GetHeight());
200 } 301 }
201 302
202 void OnGestureEvent(ui::GestureEvent* event) override { 303 void OnGestureEvent(ui::GestureEvent* event) override {
203 event->SetHandled(); 304 event->SetHandled();
204 switch (event->type()) { 305 switch (event->type()) {
205 case ui::ET_GESTURE_SCROLL_BEGIN: 306 case ui::ET_GESTURE_SCROLL_BEGIN: {
206 widget_->SetCapture(this); 307 widget_->SetCapture(this);
207 controller_->SetDraggingHandle(this); 308 controller_->SetDraggingHandle(this);
208 drag_offset_ = event->y() - selection_rect_.height() + 309 gfx::Point selection_bound_center(selection_bound_.edge_top.x(),
mohsen 2014/11/07 16:52:27 Height of selection bound might change during drag
mfomitchev 2014/11/10 04:04:12 That's a great point. I have tried a couple of thi
209 kSelectionHandleVerticalDragOffset; 310 selection_bound_.GetHeight() / 2);
311 drag_offset_ = selection_bound_center - event->location();
210 break; 312 break;
313 }
211 case ui::ET_GESTURE_SCROLL_UPDATE: { 314 case ui::ET_GESTURE_SCROLL_UPDATE: {
212 gfx::Point drag_pos(event->location().x(), 315 controller_->SelectionHandleDragged(event->location() + drag_offset_);
213 event->location().y() - drag_offset_);
214 controller_->SelectionHandleDragged(drag_pos);
215 break; 316 break;
216 } 317 }
217 case ui::ET_GESTURE_SCROLL_END: 318 case ui::ET_GESTURE_SCROLL_END:
218 case ui::ET_SCROLL_FLING_START: 319 case ui::ET_SCROLL_FLING_START:
219 widget_->ReleaseCapture(); 320 widget_->ReleaseCapture();
220 controller_->SetDraggingHandle(NULL); 321 controller_->SetDraggingHandle(nullptr);
221 break; 322 break;
222 default: 323 default:
223 break; 324 break;
224 } 325 }
225 } 326 }
226 327
227 gfx::Size GetPreferredSize() const override { 328 gfx::Size GetPreferredSize() const override {
228 gfx::Size image_size = GetHandleImageSize(); 329 gfx::Size image_size = image_->Size();
229 return gfx::Size(image_size.width() + 2 * kSelectionHandleHorizPadding, 330 return gfx::Size(image_size.width() + 2 * kSelectionHandleHorizPadding,
230 image_size.height() + selection_rect_.height() + 331 image_size.height() + selection_bound_.GetHeight() +
231 kSelectionHandleVertPadding); 332 kSelectionHandleVertPadding);
232 } 333 }
233 334
234 bool IsWidgetVisible() const { 335 bool IsWidgetVisible() const {
235 return widget_->IsVisible(); 336 return widget_->IsVisible();
236 } 337 }
237 338
238 void SetWidgetVisible(bool visible, bool quick) { 339 void SetWidgetVisible(bool visible, bool quick) {
239 if (widget_->IsVisible() == visible) 340 if (widget_->IsVisible() == visible)
240 return; 341 return;
241 widget_->SetVisibilityAnimationDuration( 342 widget_->SetVisibilityAnimationDuration(
242 base::TimeDelta::FromMilliseconds( 343 base::TimeDelta::FromMilliseconds(
243 quick ? kSelectionHandleQuickFadeDurationMs : 0)); 344 quick ? kSelectionHandleQuickFadeDurationMs : 0));
244 if (visible) 345 if (visible)
245 widget_->Show(); 346 widget_->Show();
246 else 347 else
247 widget_->Hide(); 348 widget_->Hide();
248 } 349 }
249 350
250 void SetSelectionRectInScreen(const gfx::Rect& rect) { 351 void SetBoundInScreen(const ui::SelectionBound& bound) {
251 gfx::Size image_size = GetHandleImageSize(); 352 if (bound.type != selection_bound_.type) {
252 selection_rect_ = rect; 353 image_ = GetHandleImage(bound);
253 gfx::Rect widget_bounds( 354 // TODO(mfomitchev): Ideally we should update drag_offset_ as well: as the
254 rect.x() - image_size.width() / 2 - kSelectionHandleHorizPadding, 355 // bound type changes, the position of the line cursor in the handle view
255 rect.y(), 356 // changes as well. We don't do this, because it would cause a "flicker"
256 image_size.width() + 2 * kSelectionHandleHorizPadding, 357 // effect every time the handle orientation changes as the user is
257 rect.height() + image_size.height() + kSelectionHandleVertPadding); 358 // dragging the handle. So instead the issue we have is that the position
258 widget_->SetBounds(widget_bounds); 359 // of the handle relative to your finger changes slightly every time the
259 } 360 // handle changes its orientation.
260 361 // This should be possible to fix once crbug.com/399721 is resolved.
mohsen 2014/11/07 16:52:27 How is it possible to fix after crbug.com/399721?
mfomitchev 2014/11/10 04:04:12 Got rid of this comment, since the offset no longe
261 gfx::Point GetScreenPosition() { 362 SchedulePaint();
262 return widget_->GetClientAreaBoundsInScreen().origin(); 363 }
364 widget_->SetBounds(GetSelectionWidgetBounds(bound));
365 selection_bound_ = bound;
366 aura::Window* window = widget_->GetNativeView();
367 wm::ConvertPointFromScreen(window, &selection_bound_.edge_top);
368 wm::ConvertPointFromScreen(window, &selection_bound_.edge_bottom);
263 } 369 }
264 370
265 void SetDrawInvisible(bool draw_invisible) { 371 void SetDrawInvisible(bool draw_invisible) {
266 if (draw_invisible_ == draw_invisible) 372 if (draw_invisible_ == draw_invisible)
267 return; 373 return;
268 draw_invisible_ = draw_invisible; 374 draw_invisible_ = draw_invisible;
269 SchedulePaint(); 375 SchedulePaint();
270 } 376 }
271 377
272 const gfx::Rect& selection_rect() const { return selection_rect_; }
273
274 private: 378 private:
275 scoped_ptr<Widget> widget_; 379 scoped_ptr<Widget> widget_;
276 TouchSelectionControllerImpl* controller_; 380 TouchSelectionControllerImpl* controller_;
277 gfx::Rect selection_rect_;
278 381
279 // Vertical offset between the scroll event position and the drag position 382 // In local coordinates
280 // reported to the client view (see the ASCII figure at the top of the file 383 ui::SelectionBound selection_bound_;
281 // and its description for more details). 384 gfx::Image* image_;
282 int drag_offset_; 385
386 // Distance from the touch-drag point to the middle of the handle's cursor
387 // line.
388 gfx::Vector2d drag_offset_;
283 389
284 // If set to true, the handle will not draw anything, hence providing an empty 390 // If set to true, the handle will not draw anything, hence providing an empty
285 // widget. We need this because we may want to stop showing the handle while 391 // widget. We need this because we may want to stop showing the handle while
286 // it is being dragged. Since it is being dragged, we cannot destroy the 392 // it is being dragged. Since it is being dragged, we cannot destroy the
287 // handle. 393 // handle.
288 bool draw_invisible_; 394 bool draw_invisible_;
289 395
290 DISALLOW_COPY_AND_ASSIGN(EditingHandleView); 396 DISALLOW_COPY_AND_ASSIGN(EditingHandleView);
291 }; 397 };
292 398
293 TouchHandleWindowTargeter::TouchHandleWindowTargeter( 399 TouchHandleWindowTargeter::TouchHandleWindowTargeter(
294 aura::Window* window, 400 aura::Window* window,
295 EditingHandleView* handle_view) 401 EditingHandleView* handle_view)
296 : wm::MaskedWindowTargeter(window), 402 : wm::MaskedWindowTargeter(window),
297 handle_view_(handle_view) { 403 handle_view_(handle_view) {
298 } 404 }
299 405
300 bool TouchHandleWindowTargeter::GetHitTestMask(aura::Window* window, 406 bool TouchHandleWindowTargeter::GetHitTestMask(aura::Window* window,
301 gfx::Path* mask) const { 407 gfx::Path* mask) const {
302 const gfx::Rect& selection_rect = handle_view_->selection_rect(); 408 handle_view_->GetWidgetHitTestMask(mask);
303 gfx::Size image_size = GetHandleImageSize();
304 mask->addRect(SkIntToScalar(0), SkIntToScalar(selection_rect.height()),
305 SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding,
306 SkIntToScalar(selection_rect.height() + image_size.height() +
307 kSelectionHandleVertPadding));
308 return true; 409 return true;
309 } 410 }
310 411
311 TouchSelectionControllerImpl::TouchSelectionControllerImpl( 412 TouchSelectionControllerImpl::TouchSelectionControllerImpl(
312 ui::TouchEditable* client_view) 413 ui::TouchEditable* client_view)
313 : client_view_(client_view), 414 : client_view_(client_view),
314 client_widget_(NULL), 415 client_widget_(nullptr),
315 selection_handle_1_(new EditingHandleView(this, 416 selection_handle_1_(new EditingHandleView(this,
316 client_view->GetNativeView())), 417 client_view->GetNativeView())),
317 selection_handle_2_(new EditingHandleView(this, 418 selection_handle_2_(new EditingHandleView(this,
318 client_view->GetNativeView())), 419 client_view->GetNativeView())),
319 cursor_handle_(new EditingHandleView(this, 420 cursor_handle_(new EditingHandleView(this,
320 client_view->GetNativeView())), 421 client_view->GetNativeView())),
321 context_menu_(NULL), 422 context_menu_(nullptr),
322 dragging_handle_(NULL) { 423 dragging_handle_(nullptr) {
323 aura::Window* client_window = client_view_->GetNativeView(); 424 aura::Window* client_window = client_view_->GetNativeView();
324 client_window->AddObserver(this); 425 client_window->AddObserver(this);
325 client_widget_ = Widget::GetTopLevelWidgetForNativeView(client_window); 426 client_widget_ = Widget::GetTopLevelWidgetForNativeView(client_window);
326 if (client_widget_) 427 if (client_widget_)
327 client_widget_->AddObserver(this); 428 client_widget_->AddObserver(this);
328 aura::Env::GetInstance()->AddPreTargetHandler(this); 429 aura::Env::GetInstance()->AddPreTargetHandler(this);
329 } 430 }
330 431
331 TouchSelectionControllerImpl::~TouchSelectionControllerImpl() { 432 TouchSelectionControllerImpl::~TouchSelectionControllerImpl() {
332 HideContextMenu(); 433 HideContextMenu();
333 aura::Env::GetInstance()->RemovePreTargetHandler(this); 434 aura::Env::GetInstance()->RemovePreTargetHandler(this);
334 if (client_widget_) 435 if (client_widget_)
335 client_widget_->RemoveObserver(this); 436 client_widget_->RemoveObserver(this);
336 client_view_->GetNativeView()->RemoveObserver(this); 437 client_view_->GetNativeView()->RemoveObserver(this);
337 } 438 }
338 439
339 void TouchSelectionControllerImpl::SelectionChanged() { 440 void TouchSelectionControllerImpl::SelectionChanged() {
340 gfx::Rect r1, r2; 441 ui::SelectionBound anchor, focus;
341 client_view_->GetSelectionEndPoints(&r1, &r2); 442 client_view_->GetSelectionEndPoints(&anchor, &focus);
342 gfx::Rect screen_rect_1 = ConvertToScreen(client_view_, r1); 443 ui::SelectionBound screen_bound_anchor =
343 gfx::Rect screen_rect_2 = ConvertToScreen(client_view_, r2); 444 ConvertToScreen(client_view_, anchor);
445 ui::SelectionBound screen_bound_focus = ConvertToScreen(client_view_, focus);
344 gfx::Rect client_bounds = client_view_->GetBounds(); 446 gfx::Rect client_bounds = client_view_->GetBounds();
345 if (r1.y() < client_bounds.y()) 447 if (anchor.edge_top.y() < client_bounds.y())
346 r1.Inset(0, client_bounds.y() - r1.y(), 0, 0); 448 anchor.edge_top.set_y(client_bounds.y());
347 if (r2.y() < client_bounds.y()) 449 if (focus.edge_top.y() < client_bounds.y())
348 r2.Inset(0, client_bounds.y() - r2.y(), 0, 0); 450 focus.edge_top.set_y(client_bounds.y());
349 gfx::Rect screen_rect_1_clipped = ConvertToScreen(client_view_, r1); 451 ui::SelectionBound screen_bound_anchor_clipped =
350 gfx::Rect screen_rect_2_clipped = ConvertToScreen(client_view_, r2); 452 ConvertToScreen(client_view_, anchor);
351 if (screen_rect_1_clipped == selection_end_point_1_clipped_ && 453 ui::SelectionBound screen_bound_focus_clipped =
352 screen_rect_2_clipped == selection_end_point_2_clipped_) 454 ConvertToScreen(client_view_, focus);
455 if (screen_bound_anchor_clipped == selection_bound_1_clipped_ &&
456 screen_bound_focus_clipped == selection_bound_2_clipped_)
353 return; 457 return;
354 458
355 selection_end_point_1_ = screen_rect_1; 459 selection_bound_1_ = screen_bound_anchor;
356 selection_end_point_2_ = screen_rect_2; 460 selection_bound_2_ = screen_bound_focus;
357 selection_end_point_1_clipped_ = screen_rect_1_clipped; 461 selection_bound_1_clipped_ = screen_bound_anchor_clipped;
358 selection_end_point_2_clipped_ = screen_rect_2_clipped; 462 selection_bound_2_clipped_ = screen_bound_focus_clipped;
359 463
360 if (client_view_->DrawsHandles()) { 464 if (client_view_->DrawsHandles()) {
361 UpdateContextMenu(); 465 UpdateContextMenu();
362 return; 466 return;
363 } 467 }
468
364 if (dragging_handle_) { 469 if (dragging_handle_) {
mohsen 2014/11/07 16:52:27 During a drag handles might temporarily overlap, i
mfomitchev 2014/11/10 04:04:12 Another good catch. Fixed.
365 // We need to reposition only the selection handle that is being dragged. 470 // We need to reposition only the selection handle that is being dragged.
366 // The other handle stays the same. Also, the selection handle being dragged 471 // The other handle stays the same. Also, the selection handle being dragged
367 // will always be at the end of selection, while the other handle will be at 472 // will always be at the end of selection, while the other handle will be at
368 // the start. 473 // the start.
369 // If the new location of this handle is out of client view, its widget 474 // If the new location of this handle is out of client view, its widget
370 // should not get hidden, since it should still receive touch events. 475 // should not get hidden, since it should still receive touch events.
371 // Hence, we are not using |SetHandleSelectionRect()| method here. 476 // Hence, we are not using |SetHandleSelectionRect()| method here.
372 dragging_handle_->SetSelectionRectInScreen(screen_rect_2_clipped); 477 dragging_handle_->SetBoundInScreen(screen_bound_focus_clipped);
373 478
374 // Temporary fix for selection handle going outside a window. On a webpage, 479 // Temporary fix for selection handle going outside a window. On a webpage,
375 // the page should scroll if the selection handle is dragged outside the 480 // the page should scroll if the selection handle is dragged outside the
376 // window. That does not happen currently. So we just hide the handle for 481 // window. That does not happen currently. So we just hide the handle for
377 // now. 482 // now.
378 // TODO(varunjain): Fix this: crbug.com/269003 483 // TODO(varunjain): Fix this: crbug.com/269003
379 dragging_handle_->SetDrawInvisible(!ShouldShowHandleFor(r2)); 484 dragging_handle_->SetDrawInvisible(!ShouldShowHandleFor(focus));
380 485
381 if (dragging_handle_ != cursor_handle_.get()) { 486 if (dragging_handle_ != cursor_handle_.get()) {
382 // The non-dragging-handle might have recently become visible. 487 // The non-dragging-handle might have recently become visible.
383 EditingHandleView* non_dragging_handle = selection_handle_1_.get(); 488 EditingHandleView* non_dragging_handle = selection_handle_1_.get();
384 if (dragging_handle_ == selection_handle_1_) { 489 if (dragging_handle_ == selection_handle_1_) {
385 non_dragging_handle = selection_handle_2_.get(); 490 non_dragging_handle = selection_handle_2_.get();
386 // if handle 1 is being dragged, it is corresponding to the end of 491 // if handle 1 is being dragged, it is corresponding to the end of
387 // selection and the other handle to the start of selection. 492 // selection and the other handle to the start of selection.
388 selection_end_point_1_ = screen_rect_2; 493 selection_bound_1_ = screen_bound_focus;
389 selection_end_point_2_ = screen_rect_1; 494 selection_bound_2_ = screen_bound_anchor;
390 selection_end_point_1_clipped_ = screen_rect_2_clipped; 495 selection_bound_1_clipped_ = screen_bound_focus_clipped;
391 selection_end_point_2_clipped_ = screen_rect_1_clipped; 496 selection_bound_2_clipped_ = screen_bound_anchor_clipped;
392 } 497 }
393 SetHandleSelectionRect(non_dragging_handle, r1, screen_rect_1_clipped); 498 SetHandleBound(non_dragging_handle, anchor, screen_bound_anchor_clipped);
394 } 499 }
395 } else { 500 } else {
396 UpdateContextMenu(); 501 UpdateContextMenu();
397 502
398 // Check if there is any selection at all. 503 // Check if there is any selection at all.
399 if (screen_rect_1.origin() == screen_rect_2.origin()) { 504 if (screen_bound_anchor.edge_top == screen_bound_focus.edge_top) {
400 selection_handle_1_->SetWidgetVisible(false, false); 505 selection_handle_1_->SetWidgetVisible(false, false);
401 selection_handle_2_->SetWidgetVisible(false, false); 506 selection_handle_2_->SetWidgetVisible(false, false);
402 SetHandleSelectionRect(cursor_handle_.get(), r1, screen_rect_1_clipped); 507 SetHandleBound(cursor_handle_.get(), anchor, screen_bound_anchor_clipped);
403 return; 508 return;
404 } 509 }
405 510
406 cursor_handle_->SetWidgetVisible(false, false); 511 cursor_handle_->SetWidgetVisible(false, false);
407 SetHandleSelectionRect(selection_handle_1_.get(), r1, 512 SetHandleBound(
408 screen_rect_1_clipped); 513 selection_handle_1_.get(), anchor, screen_bound_anchor_clipped);
409 SetHandleSelectionRect(selection_handle_2_.get(), r2, 514 SetHandleBound(
410 screen_rect_2_clipped); 515 selection_handle_2_.get(), focus, screen_bound_focus_clipped);
411 } 516 }
412 } 517 }
413 518
414 bool TouchSelectionControllerImpl::IsHandleDragInProgress() { 519 bool TouchSelectionControllerImpl::IsHandleDragInProgress() {
415 return !!dragging_handle_; 520 return !!dragging_handle_;
416 } 521 }
417 522
418 void TouchSelectionControllerImpl::HideHandles(bool quick) { 523 void TouchSelectionControllerImpl::HideHandles(bool quick) {
419 selection_handle_1_->SetWidgetVisible(false, quick); 524 selection_handle_1_->SetWidgetVisible(false, quick);
420 selection_handle_2_->SetWidgetVisible(false, quick); 525 selection_handle_2_->SetWidgetVisible(false, quick);
(...skipping 14 matching lines...) Expand all
435 DCHECK(dragging_handle_); 540 DCHECK(dragging_handle_);
436 gfx::Point drag_pos_in_client = drag_pos; 541 gfx::Point drag_pos_in_client = drag_pos;
437 ConvertPointToClientView(dragging_handle_, &drag_pos_in_client); 542 ConvertPointToClientView(dragging_handle_, &drag_pos_in_client);
438 543
439 if (dragging_handle_ == cursor_handle_.get()) { 544 if (dragging_handle_ == cursor_handle_.get()) {
440 client_view_->MoveCaretTo(drag_pos_in_client); 545 client_view_->MoveCaretTo(drag_pos_in_client);
441 return; 546 return;
442 } 547 }
443 548
444 // Find the stationary selection handle. 549 // Find the stationary selection handle.
445 gfx::Rect fixed_handle_rect = selection_end_point_1_; 550 ui::SelectionBound anchor_bound =
446 if (selection_handle_1_ == dragging_handle_) 551 selection_handle_1_ == dragging_handle_ ? selection_bound_2_
447 fixed_handle_rect = selection_end_point_2_; 552 : selection_bound_1_;
448 553
449 // Find selection end points in client_view's coordinate system. 554 // Find selection end points in client_view's coordinate system.
450 gfx::Point p2 = fixed_handle_rect.origin(); 555 gfx::Point p2 = anchor_bound.edge_top;
451 p2.Offset(0, fixed_handle_rect.height() / 2); 556 p2.Offset(0, (anchor_bound.edge_bottom.y() - anchor_bound.edge_top.y()) / 2);
mohsen 2014/11/07 16:52:27 anchor_bound.GetHeight() / 2
mfomitchev 2014/11/10 04:04:12 Done.
452 client_view_->ConvertPointFromScreen(&p2); 557 client_view_->ConvertPointFromScreen(&p2);
453 558
454 // Instruct client_view to select the region between p1 and p2. The position 559 // Instruct client_view to select the region between p1 and p2. The position
455 // of |fixed_handle| is the start and that of |dragging_handle| is the end 560 // of |fixed_handle| is the start and that of |dragging_handle| is the end
456 // of selection. 561 // of selection.
457 client_view_->SelectRect(p2, drag_pos_in_client); 562 client_view_->SelectRect(p2, drag_pos_in_client);
458 } 563 }
459 564
460 void TouchSelectionControllerImpl::ConvertPointToClientView( 565 void TouchSelectionControllerImpl::ConvertPointToClientView(
461 EditingHandleView* source, gfx::Point* point) { 566 EditingHandleView* source, gfx::Point* point) {
462 View::ConvertPointToScreen(source, point); 567 View::ConvertPointToScreen(source, point);
463 client_view_->ConvertPointFromScreen(point); 568 client_view_->ConvertPointFromScreen(point);
464 } 569 }
465 570
466 void TouchSelectionControllerImpl::SetHandleSelectionRect( 571 void TouchSelectionControllerImpl::SetHandleBound(
467 EditingHandleView* handle, 572 EditingHandleView* handle,
468 const gfx::Rect& rect, 573 const ui::SelectionBound& bound,
469 const gfx::Rect& rect_in_screen) { 574 const ui::SelectionBound& bound_in_screen) {
470 handle->SetWidgetVisible(ShouldShowHandleFor(rect), false); 575 handle->SetWidgetVisible(ShouldShowHandleFor(bound), false);
471 if (handle->IsWidgetVisible()) 576 if (handle->IsWidgetVisible())
472 handle->SetSelectionRectInScreen(rect_in_screen); 577 handle->SetBoundInScreen(bound_in_screen);
473 } 578 }
474 579
475 bool TouchSelectionControllerImpl::ShouldShowHandleFor( 580 bool TouchSelectionControllerImpl::ShouldShowHandleFor(
476 const gfx::Rect& rect) const { 581 const ui::SelectionBound& bound) const {
477 if (rect.height() < kSelectionHandleBarMinHeight) 582 if (bound.edge_bottom.y() - bound.edge_top.y() < kSelectionHandleBarMinHeight)
mohsen 2014/11/07 16:52:27 GetHeight()
mfomitchev 2014/11/10 04:04:12 Done.
478 return false; 583 return false;
479 gfx::Rect bounds = client_view_->GetBounds(); 584 gfx::Rect client_bounds = client_view_->GetBounds();
480 bounds.Inset(0, 0, 0, -kSelectionHandleBarBottomAllowance); 585 client_bounds.Inset(0, 0, 0, -kSelectionHandleBarBottomAllowance);
481 return bounds.Contains(rect); 586 gfx::Rect selection_rect =
587 gfx::Rect(bound.edge_top, gfx::Size(0, bound.GetHeight()));
mohsen 2014/11/07 16:52:27 gfx::BoundingRect()
mfomitchev 2014/11/10 04:04:12 Done.
588 return client_bounds.Contains(selection_rect);
482 } 589 }
483 590
484 bool TouchSelectionControllerImpl::IsCommandIdEnabled(int command_id) const { 591 bool TouchSelectionControllerImpl::IsCommandIdEnabled(int command_id) const {
485 return client_view_->IsCommandIdEnabled(command_id); 592 return client_view_->IsCommandIdEnabled(command_id);
486 } 593 }
487 594
488 void TouchSelectionControllerImpl::ExecuteCommand(int command_id, 595 void TouchSelectionControllerImpl::ExecuteCommand(int command_id,
489 int event_flags) { 596 int event_flags) {
490 HideContextMenu(); 597 HideContextMenu();
491 client_view_->ExecuteCommand(command_id, event_flags); 598 client_view_->ExecuteCommand(command_id, event_flags);
492 } 599 }
493 600
494 void TouchSelectionControllerImpl::OpenContextMenu() { 601 void TouchSelectionControllerImpl::OpenContextMenu() {
495 // Context menu should appear centered on top of the selected region. 602 // Context menu should appear centered on top of the selected region.
496 const gfx::Rect rect = context_menu_->GetAnchorRect(); 603 const gfx::Rect rect = context_menu_->GetAnchorRect();
497 const gfx::Point anchor(rect.CenterPoint().x(), rect.y()); 604 const gfx::Point anchor(rect.CenterPoint().x(), rect.y());
498 HideContextMenu(); 605 HideContextMenu();
499 client_view_->OpenContextMenu(anchor); 606 client_view_->OpenContextMenu(anchor);
500 } 607 }
501 608
502 void TouchSelectionControllerImpl::OnMenuClosed(TouchEditingMenuView* menu) { 609 void TouchSelectionControllerImpl::OnMenuClosed(TouchEditingMenuView* menu) {
503 if (menu == context_menu_) 610 if (menu == context_menu_)
504 context_menu_ = NULL; 611 context_menu_ = nullptr;
505 } 612 }
506 613
507 void TouchSelectionControllerImpl::OnAncestorWindowTransformed( 614 void TouchSelectionControllerImpl::OnAncestorWindowTransformed(
508 aura::Window* window, 615 aura::Window* window,
509 aura::Window* ancestor) { 616 aura::Window* ancestor) {
510 client_view_->DestroyTouchSelection(); 617 client_view_->DestroyTouchSelection();
511 } 618 }
512 619
513 void TouchSelectionControllerImpl::OnWidgetClosing(Widget* widget) { 620 void TouchSelectionControllerImpl::OnWidgetClosing(Widget* widget) {
514 DCHECK_EQ(client_widget_, widget); 621 DCHECK_EQ(client_widget_, widget);
515 client_widget_ = NULL; 622 client_widget_ = nullptr;
516 } 623 }
517 624
518 void TouchSelectionControllerImpl::OnWidgetBoundsChanged( 625 void TouchSelectionControllerImpl::OnWidgetBoundsChanged(
519 Widget* widget, 626 Widget* widget,
520 const gfx::Rect& new_bounds) { 627 const gfx::Rect& new_bounds) {
521 DCHECK_EQ(client_widget_, widget); 628 DCHECK_EQ(client_widget_, widget);
522 SelectionChanged(); 629 SelectionChanged();
523 } 630 }
524 631
525 void TouchSelectionControllerImpl::OnKeyEvent(ui::KeyEvent* event) { 632 void TouchSelectionControllerImpl::OnKeyEvent(ui::KeyEvent* event) {
526 client_view_->DestroyTouchSelection(); 633 client_view_->DestroyTouchSelection();
527 } 634 }
528 635
529 void TouchSelectionControllerImpl::OnMouseEvent(ui::MouseEvent* event) { 636 void TouchSelectionControllerImpl::OnMouseEvent(ui::MouseEvent* event) {
530 aura::client::CursorClient* cursor_client = aura::client::GetCursorClient( 637 aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
531 client_view_->GetNativeView()->GetRootWindow()); 638 client_view_->GetNativeView()->GetRootWindow());
532 if (!cursor_client || cursor_client->IsMouseEventsEnabled()) 639 if (!cursor_client || cursor_client->IsMouseEventsEnabled())
533 client_view_->DestroyTouchSelection(); 640 client_view_->DestroyTouchSelection();
534 } 641 }
535 642
536 void TouchSelectionControllerImpl::OnScrollEvent(ui::ScrollEvent* event) { 643 void TouchSelectionControllerImpl::OnScrollEvent(ui::ScrollEvent* event) {
537 client_view_->DestroyTouchSelection(); 644 client_view_->DestroyTouchSelection();
538 } 645 }
539 646
540 void TouchSelectionControllerImpl::ContextMenuTimerFired() { 647 void TouchSelectionControllerImpl::ContextMenuTimerFired() {
541 // Get selection end points in client_view's space. 648 // Get selection end points in client_view's space.
542 gfx::Rect end_rect_1_in_screen; 649 ui::SelectionBound b1_in_screen = selection_bound_1_clipped_;
543 gfx::Rect end_rect_2_in_screen; 650 ui::SelectionBound b2_in_screen =
544 if (cursor_handle_->IsWidgetVisible()) { 651 cursor_handle_->IsWidgetVisible() ? b1_in_screen
545 end_rect_1_in_screen = selection_end_point_1_clipped_; 652 : selection_bound_2_clipped_;
546 end_rect_2_in_screen = end_rect_1_in_screen;
547 } else {
548 end_rect_1_in_screen = selection_end_point_1_clipped_;
549 end_rect_2_in_screen = selection_end_point_2_clipped_;
550 }
551
552 // Convert from screen to client. 653 // Convert from screen to client.
553 gfx::Rect end_rect_1(ConvertFromScreen(client_view_, end_rect_1_in_screen)); 654 ui::SelectionBound b1 = ConvertFromScreen(client_view_, b1_in_screen);
554 gfx::Rect end_rect_2(ConvertFromScreen(client_view_, end_rect_2_in_screen)); 655 ui::SelectionBound b2 = ConvertFromScreen(client_view_, b2_in_screen);
555 656
556 // if selection is completely inside the view, we display the context menu 657 // if selection is completely inside the view, we display the context menu
557 // in the middle of the end points on the top. Else, we show it above the 658 // in the middle of the end points on the top. Else, we show it above the
558 // visible handle. If no handle is visible, we do not show the menu. 659 // visible handle. If no handle is visible, we do not show the menu.
559 gfx::Rect menu_anchor; 660 gfx::Rect menu_anchor;
560 if (ShouldShowHandleFor(end_rect_1) && 661 if (ShouldShowHandleFor(b1) && ShouldShowHandleFor(b2))
561 ShouldShowHandleFor(end_rect_2)) 662 menu_anchor = ui::RectBetweenSelectionBounds(b1_in_screen, b2_in_screen);
562 menu_anchor = Union(end_rect_1_in_screen,end_rect_2_in_screen); 663 else if (ShouldShowHandleFor(b1))
563 else if (ShouldShowHandleFor(end_rect_1)) 664 menu_anchor = BoundToRect(b1_in_screen);
564 menu_anchor = end_rect_1_in_screen; 665 else if (ShouldShowHandleFor(b2))
565 else if (ShouldShowHandleFor(end_rect_2)) 666 menu_anchor = BoundToRect(b2_in_screen);
566 menu_anchor = end_rect_2_in_screen;
567 else 667 else
568 return; 668 return;
569 669
570 DCHECK(!context_menu_); 670 DCHECK(!context_menu_);
571 context_menu_ = TouchEditingMenuView::Create(this, menu_anchor, 671 context_menu_ = TouchEditingMenuView::Create(this, menu_anchor,
572 GetHandleImageSize(), 672 GetMaxHandleImageSize(),
573 client_view_->GetNativeView()); 673 client_view_->GetNativeView());
574 } 674 }
575 675
576 void TouchSelectionControllerImpl::StartContextMenuTimer() { 676 void TouchSelectionControllerImpl::StartContextMenuTimer() {
577 if (context_menu_timer_.IsRunning()) 677 if (context_menu_timer_.IsRunning())
578 return; 678 return;
579 context_menu_timer_.Start( 679 context_menu_timer_.Start(
580 FROM_HERE, 680 FROM_HERE,
581 base::TimeDelta::FromMilliseconds(kContextMenuTimoutMs), 681 base::TimeDelta::FromMilliseconds(kContextMenuTimoutMs),
582 this, 682 this,
583 &TouchSelectionControllerImpl::ContextMenuTimerFired); 683 &TouchSelectionControllerImpl::ContextMenuTimerFired);
584 } 684 }
585 685
586 void TouchSelectionControllerImpl::UpdateContextMenu() { 686 void TouchSelectionControllerImpl::UpdateContextMenu() {
587 // Hide context menu to be shown when the timer fires. 687 // Hide context menu to be shown when the timer fires.
588 HideContextMenu(); 688 HideContextMenu();
589 StartContextMenuTimer(); 689 StartContextMenuTimer();
590 } 690 }
591 691
592 void TouchSelectionControllerImpl::HideContextMenu() { 692 void TouchSelectionControllerImpl::HideContextMenu() {
593 if (context_menu_) 693 if (context_menu_)
594 context_menu_->Close(); 694 context_menu_->Close();
595 context_menu_ = NULL; 695 context_menu_ = nullptr;
596 context_menu_timer_.Stop(); 696 context_menu_timer_.Stop();
597 } 697 }
598 698
599 gfx::NativeView TouchSelectionControllerImpl::GetCursorHandleNativeView() { 699 gfx::NativeView TouchSelectionControllerImpl::GetCursorHandleNativeView() {
600 return cursor_handle_->GetWidget()->GetNativeView(); 700 return cursor_handle_->GetWidget()->GetNativeView();
601 } 701 }
602 702
603 gfx::Point TouchSelectionControllerImpl::GetSelectionHandle1Position() { 703 gfx::Rect TouchSelectionControllerImpl::GetSelectionHandle1Bounds() {
604 return selection_handle_1_->GetScreenPosition(); 704 return selection_handle_1_->GetBoundsInScreen();
605 } 705 }
606 706
607 gfx::Point TouchSelectionControllerImpl::GetSelectionHandle2Position() { 707 gfx::Rect TouchSelectionControllerImpl::GetSelectionHandle2Bounds() {
608 return selection_handle_2_->GetScreenPosition(); 708 return selection_handle_2_->GetBoundsInScreen();
609 } 709 }
610 710
611 gfx::Point TouchSelectionControllerImpl::GetCursorHandlePosition() { 711 gfx::Rect TouchSelectionControllerImpl::GetCursorHandleBounds() {
612 return cursor_handle_->GetScreenPosition(); 712 return cursor_handle_->GetBoundsInScreen();
613 } 713 }
614 714
615 bool TouchSelectionControllerImpl::IsSelectionHandle1Visible() { 715 bool TouchSelectionControllerImpl::IsSelectionHandle1Visible() {
616 return selection_handle_1_->IsWidgetVisible(); 716 return selection_handle_1_->IsWidgetVisible();
617 } 717 }
618 718
619 bool TouchSelectionControllerImpl::IsSelectionHandle2Visible() { 719 bool TouchSelectionControllerImpl::IsSelectionHandle2Visible() {
620 return selection_handle_2_->IsWidgetVisible(); 720 return selection_handle_2_->IsWidgetVisible();
621 } 721 }
622 722
623 bool TouchSelectionControllerImpl::IsCursorHandleVisible() { 723 bool TouchSelectionControllerImpl::IsCursorHandleVisible() {
624 return cursor_handle_->IsWidgetVisible(); 724 return cursor_handle_->IsWidgetVisible();
625 } 725 }
626 726
727 gfx::Rect TouchSelectionControllerImpl::GetExpectedHandleBounds(
728 const ui::SelectionBound& bound) {
729 return GetSelectionWidgetBounds(bound);
730 }
731
732 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle1View() {
733 return selection_handle_1_.get();
734 }
735
736 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle2View() {
737 return selection_handle_2_.get();
738 }
739
627 } // namespace views 740 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698