[Mac] Implement Ambient Light API
[chromium-blink-merge.git] / content / browser / web_contents / touch_editable_impl_aura.cc
blobc7adfd8742629b0c59323064875a9c63cd26d26a
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
3 // found in the LICENSE file.
5 #include "content/browser/web_contents/touch_editable_impl_aura.h"
7 #include "content/browser/renderer_host/render_widget_host_impl.h"
8 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
9 #include "content/browser/web_contents/web_contents_impl.h"
10 #include "content/common/view_messages.h"
11 #include "content/public/browser/render_view_host.h"
12 #include "content/public/browser/render_widget_host.h"
13 #include "ui/aura/client/screen_position_client.h"
14 #include "ui/aura/window.h"
15 #include "ui/aura/window_tree_host.h"
16 #include "ui/base/clipboard/clipboard.h"
17 #include "ui/base/touch/selection_bound.h"
18 #include "ui/base/ui_base_switches_util.h"
19 #include "ui/gfx/range/range.h"
20 #include "ui/strings/grit/ui_strings.h"
21 #include "ui/wm/public/activation_client.h"
23 namespace content {
25 ////////////////////////////////////////////////////////////////////////////////
26 // TouchEditableImplAura, public:
28 TouchEditableImplAura::~TouchEditableImplAura() {
29 Cleanup();
32 // static
33 TouchEditableImplAura* TouchEditableImplAura::Create() {
34 if (switches::IsTouchEditingEnabled())
35 return new TouchEditableImplAura();
36 return NULL;
39 void TouchEditableImplAura::AttachToView(RenderWidgetHostViewAura* view) {
40 if (rwhva_ == view)
41 return;
43 Cleanup();
44 if (!view)
45 return;
47 rwhva_ = view;
48 rwhva_->set_touch_editing_client(this);
51 void TouchEditableImplAura::UpdateEditingController() {
52 if (!rwhva_ || !rwhva_->HasFocus())
53 return;
55 if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE ||
56 selection_anchor_ != selection_focus_) {
57 if (touch_selection_controller_)
58 touch_selection_controller_->SelectionChanged();
59 } else {
60 EndTouchEditing(false);
64 void TouchEditableImplAura::OverscrollStarted() {
65 scrolls_in_progress_++;
68 void TouchEditableImplAura::OverscrollCompleted() {
69 ScrollEnded();
72 ////////////////////////////////////////////////////////////////////////////////
73 // TouchEditableImplAura, RenderWidgetHostViewAura::TouchEditingClient
74 // implementation:
76 void TouchEditableImplAura::StartTouchEditing() {
77 if (!rwhva_ || !rwhva_->HasFocus())
78 return;
80 if (!touch_selection_controller_) {
81 touch_selection_controller_.reset(
82 ui::TouchEditingControllerDeprecated::Create(this));
84 if (touch_selection_controller_)
85 touch_selection_controller_->SelectionChanged();
88 void TouchEditableImplAura::EndTouchEditing(bool quick) {
89 if (touch_selection_controller_) {
90 if (touch_selection_controller_->IsHandleDragInProgress()) {
91 touch_selection_controller_->SelectionChanged();
92 } else {
93 selection_gesture_in_process_ = false;
94 touch_selection_controller_->HideHandles(quick);
95 touch_selection_controller_.reset();
100 void TouchEditableImplAura::OnSelectionOrCursorChanged(
101 const ui::SelectionBound& anchor,
102 const ui::SelectionBound& focus) {
103 selection_anchor_ = anchor;
104 selection_focus_ = focus;
106 // If touch editing handles were not visible, we bring them up only if the
107 // current event is a gesture event, no scroll/fling/overscoll is in progress,
108 // and there is non-zero selection on the page
109 if (selection_gesture_in_process_ && !scrolls_in_progress_ &&
110 selection_anchor_ != selection_focus_) {
111 StartTouchEditing();
112 selection_gesture_in_process_ = false;
115 UpdateEditingController();
118 void TouchEditableImplAura::OnTextInputTypeChanged(ui::TextInputType type) {
119 text_input_type_ = type;
122 bool TouchEditableImplAura::HandleInputEvent(const ui::Event* event) {
123 DCHECK(rwhva_);
124 if (!event->IsGestureEvent()) {
125 // Ignore all non-gesture events. Non-gesture events that can deactivate
126 // touch editing are handled in TouchSelectionControllerImpl.
127 return false;
130 const ui::GestureEvent* gesture_event =
131 static_cast<const ui::GestureEvent*>(event);
132 switch (event->type()) {
133 case ui::ET_GESTURE_TAP:
134 // When the user taps, we want to show touch editing handles if user
135 // tapped on selected text.
136 if (gesture_event->details().tap_count() == 1 &&
137 selection_anchor_ != selection_focus_) {
138 gfx::Rect selection_rect =
139 ui::RectBetweenSelectionBounds(selection_anchor_, selection_focus_);
140 // When tap is on selection, show handles and mark event as handled only
141 // if handles are not present or text is not editable. Otherwise, do not
142 // set event as handles so that event is forwarded to the renderer to
143 // update selection/cursor.
144 if (selection_rect.Contains(gesture_event->location()) &&
145 (text_input_type_ == ui::TEXT_INPUT_TYPE_NONE ||
146 !touch_selection_controller_)) {
147 StartTouchEditing();
148 return true;
151 // For single taps, not inside selected region, we want to show handles
152 // only when the tap is on an already focused textfield.
153 textfield_was_focused_on_tap_ =
154 gesture_event->details().tap_count() == 1 &&
155 text_input_type_ != ui::TEXT_INPUT_TYPE_NONE;
156 break;
157 case ui::ET_GESTURE_LONG_PRESS:
158 selection_gesture_in_process_ = true;
159 break;
160 case ui::ET_GESTURE_SCROLL_BEGIN:
161 scrolls_in_progress_++;
162 // We need to hide selection handles during scroll (including fling and
163 // overscroll), but they should be re-activated after scrolling if:
164 // - an existing scroll decided that handles should be shown after
165 // scrolling; or
166 // - the gesture in progress is going to end in selection; or
167 // - selection handles are currently active.
168 handles_hidden_due_to_scroll_ = handles_hidden_due_to_scroll_ ||
169 selection_gesture_in_process_ ||
170 touch_selection_controller_ != NULL;
171 selection_gesture_in_process_ = false;
172 EndTouchEditing(true);
173 break;
174 case ui::ET_GESTURE_SCROLL_END:
175 ScrollEnded();
176 break;
177 default:
178 break;
180 return false;
183 void TouchEditableImplAura::GestureEventAck(int gesture_event_type) {
184 DCHECK(rwhva_);
185 if (gesture_event_type == blink::WebInputEvent::GestureTap &&
186 text_input_type_ != ui::TEXT_INPUT_TYPE_NONE &&
187 textfield_was_focused_on_tap_) {
188 StartTouchEditing();
189 UpdateEditingController();
193 void TouchEditableImplAura::DidStopFlinging() {
194 ScrollEnded();
197 void TouchEditableImplAura::OnViewDestroyed() {
198 Cleanup();
201 ////////////////////////////////////////////////////////////////////////////////
202 // TouchEditableImplAura, ui::TouchEditable implementation:
204 void TouchEditableImplAura::SelectRect(const gfx::Point& start,
205 const gfx::Point& end) {
206 RenderWidgetHost* host = rwhva_->GetRenderWidgetHost();
207 RenderViewHost* rvh = RenderViewHost::From(host);
208 WebContentsImpl* wc =
209 static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(rvh));
210 wc->SelectRange(start, end);
213 void TouchEditableImplAura::MoveCaretTo(const gfx::Point& point) {
214 if (!rwhva_)
215 return;
217 RenderWidgetHostImpl* host = RenderWidgetHostImpl::From(
218 rwhva_->GetRenderWidgetHost());
219 host->MoveCaret(point);
222 void TouchEditableImplAura::GetSelectionEndPoints(ui::SelectionBound* anchor,
223 ui::SelectionBound* focus) {
224 *anchor = selection_anchor_;
225 *focus = selection_focus_;
228 gfx::Rect TouchEditableImplAura::GetBounds() {
229 return rwhva_ ? gfx::Rect(rwhva_->GetNativeView()->bounds().size()) :
230 gfx::Rect();
233 gfx::NativeView TouchEditableImplAura::GetNativeView() const {
234 return rwhva_ ? rwhva_->GetNativeView()->GetToplevelWindow() : NULL;
237 void TouchEditableImplAura::ConvertPointToScreen(gfx::Point* point) {
238 if (!rwhva_)
239 return;
240 aura::Window* window = rwhva_->GetNativeView();
241 aura::client::ScreenPositionClient* screen_position_client =
242 aura::client::GetScreenPositionClient(window->GetRootWindow());
243 if (screen_position_client)
244 screen_position_client->ConvertPointToScreen(window, point);
247 void TouchEditableImplAura::ConvertPointFromScreen(gfx::Point* point) {
248 if (!rwhva_)
249 return;
250 aura::Window* window = rwhva_->GetNativeView();
251 aura::client::ScreenPositionClient* screen_position_client =
252 aura::client::GetScreenPositionClient(window->GetRootWindow());
253 if (screen_position_client)
254 screen_position_client->ConvertPointFromScreen(window, point);
257 bool TouchEditableImplAura::DrawsHandles() {
258 return false;
261 void TouchEditableImplAura::OpenContextMenu(const gfx::Point& anchor) {
262 if (!rwhva_)
263 return;
264 gfx::Point point = anchor;
265 ConvertPointFromScreen(&point);
266 RenderWidgetHost* host = rwhva_->GetRenderWidgetHost();
267 host->Send(new ViewMsg_ShowContextMenu(
268 host->GetRoutingID(), ui::MENU_SOURCE_TOUCH_EDIT_MENU, point));
269 EndTouchEditing(false);
272 bool TouchEditableImplAura::IsCommandIdChecked(int command_id) const {
273 NOTREACHED();
274 return false;
277 bool TouchEditableImplAura::IsCommandIdEnabled(int command_id) const {
278 if (!rwhva_)
279 return false;
280 bool editable = rwhva_->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE;
281 bool readable = rwhva_->GetTextInputType() != ui::TEXT_INPUT_TYPE_PASSWORD;
282 gfx::Range selection_range;
283 rwhva_->GetSelectionRange(&selection_range);
284 bool has_selection = !selection_range.is_empty();
285 switch (command_id) {
286 case IDS_APP_CUT:
287 return editable && readable && has_selection;
288 case IDS_APP_COPY:
289 return readable && has_selection;
290 case IDS_APP_PASTE: {
291 base::string16 result;
292 ui::Clipboard::GetForCurrentThread()->ReadText(
293 ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
294 return editable && !result.empty();
296 case IDS_APP_DELETE:
297 return editable && has_selection;
298 case IDS_APP_SELECT_ALL:
299 return true;
300 default:
301 return false;
305 bool TouchEditableImplAura::GetAcceleratorForCommandId(
306 int command_id,
307 ui::Accelerator* accelerator) {
308 return false;
311 void TouchEditableImplAura::ExecuteCommand(int command_id, int event_flags) {
312 RenderWidgetHost* host = rwhva_->GetRenderWidgetHost();
313 RenderViewHost* rvh = RenderViewHost::From(host);
314 WebContents* wc = WebContents::FromRenderViewHost(rvh);
316 switch (command_id) {
317 case IDS_APP_CUT:
318 wc->Cut();
319 break;
320 case IDS_APP_COPY:
321 wc->Copy();
322 break;
323 case IDS_APP_PASTE:
324 wc->Paste();
325 break;
326 case IDS_APP_DELETE:
327 wc->Delete();
328 break;
329 case IDS_APP_SELECT_ALL:
330 wc->SelectAll();
331 break;
332 default:
333 NOTREACHED();
334 break;
336 EndTouchEditing(false);
339 void TouchEditableImplAura::DestroyTouchSelection() {
340 EndTouchEditing(false);
343 ////////////////////////////////////////////////////////////////////////////////
344 // TouchEditableImplAura, private:
346 TouchEditableImplAura::TouchEditableImplAura()
347 : text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
348 rwhva_(NULL),
349 selection_gesture_in_process_(false),
350 handles_hidden_due_to_scroll_(false),
351 scrolls_in_progress_(0),
352 textfield_was_focused_on_tap_(false) {
355 void TouchEditableImplAura::ScrollEnded() {
356 scrolls_in_progress_--;
357 // If there is no scrolling left in progress, show selection handles if they
358 // were hidden due to scroll and there is a selection.
359 if (!scrolls_in_progress_ && handles_hidden_due_to_scroll_ &&
360 (selection_anchor_ != selection_focus_ ||
361 text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)) {
362 StartTouchEditing();
363 UpdateEditingController();
364 handles_hidden_due_to_scroll_ = false;
368 void TouchEditableImplAura::Cleanup() {
369 if (rwhva_) {
370 rwhva_->set_touch_editing_client(NULL);
371 rwhva_ = NULL;
373 text_input_type_ = ui::TEXT_INPUT_TYPE_NONE;
374 EndTouchEditing(true);
375 selection_gesture_in_process_ = false;
376 handles_hidden_due_to_scroll_ = false;
377 scrolls_in_progress_ = 0;
380 } // namespace content