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

Side by Side Diff: chrome/browser/renderer_host/render_widget_host_view_views.cc

Issue 8598024: Now that we are doing a hard-cut-over to Aura, remove a bunch of *Views based classes that are ob... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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.
4
5 #include "chrome/browser/renderer_host/render_widget_host_view_views.h"
6
7 #include <algorithm>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/logging.h"
13 #include "base/message_loop.h"
14 #include "base/metrics/histogram.h"
15 #include "base/string_number_conversions.h"
16 #include "base/time.h"
17 #include "base/utf_string_conversions.h"
18 #include "chrome/common/chrome_notification_types.h"
19 #include "chrome/common/native_web_keyboard_event_views.h"
20 #include "chrome/common/render_messages.h"
21 #include "content/browser/renderer_host/backing_store_skia.h"
22 #include "content/browser/renderer_host/render_widget_host.h"
23 #include "content/public/browser/notification_service.h"
24 #include "content/public/common/result_codes.h"
25 #include "grit/ui_strings.h"
26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderli ne.h"
27 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
28 #include "third_party/WebKit/Source/WebKit/chromium/public/gtk/WebInputEventFact ory.h"
29 #include "third_party/WebKit/Source/WebKit/chromium/public/x11/WebScreenInfoFact ory.h"
30 #include "ui/base/clipboard/clipboard.h"
31 #include "ui/base/text/text_elider.h"
32 #include "ui/gfx/canvas.h"
33 #include "ui/gfx/canvas_skia.h"
34 #include "ui/views/events/event.h"
35 #include "ui/views/ime/input_method.h"
36 #include "views/views_delegate.h"
37 #include "views/widget/tooltip_manager.h"
38 #include "views/widget/widget.h"
39
40 #if defined(UI_COMPOSITOR_IMAGE_TRANSPORT)
41 #include "content/browser/renderer_host/accelerated_surface_container_linux.h"
42 #include "ui/gfx/gl/gl_bindings.h"
43 #endif
44
45 #if defined(TOOLKIT_USES_GTK)
46 #include <gdk/gdkx.h>
47 #include <gtk/gtk.h>
48 #include <gtk/gtkwindow.h>
49
50 #include "content/browser/renderer_host/gtk_window_utils.h"
51 #include "views/widget/native_widget_gtk.h"
52 #endif
53
54 #if defined(OS_POSIX)
55 #include "content/browser/renderer_host/gtk_window_utils.h"
56 #endif
57
58 static const int kMaxWindowWidth = 4000;
59 static const int kMaxWindowHeight = 4000;
60 static const int kTouchControllerUpdateDelay = 150;
61
62 // static
63 const char RenderWidgetHostViewViews::kViewClassName[] =
64 "browser/renderer_host/RenderWidgetHostViewViews";
65
66 using WebKit::WebInputEventFactory;
67 using WebKit::WebMouseWheelEvent;
68 using WebKit::WebTouchEvent;
69
70 namespace {
71
72 int WebInputEventFlagsFromViewsEvent(const views::Event& event) {
73 int modifiers = 0;
74
75 if (event.IsShiftDown())
76 modifiers |= WebKit::WebInputEvent::ShiftKey;
77 if (event.IsControlDown())
78 modifiers |= WebKit::WebInputEvent::ControlKey;
79 if (event.IsAltDown())
80 modifiers |= WebKit::WebInputEvent::AltKey;
81 if (event.IsCapsLockDown())
82 modifiers |= WebKit::WebInputEvent::CapsLockOn;
83
84 return modifiers;
85 }
86
87 void InitializeWebMouseEventFromViewsEvent(const views::LocatedEvent& event,
88 const gfx::Point& origin,
89 WebKit::WebMouseEvent* wmevent) {
90 wmevent->timeStampSeconds = base::Time::Now().ToDoubleT();
91 wmevent->modifiers = WebInputEventFlagsFromViewsEvent(event);
92
93 wmevent->windowX = wmevent->x = event.x();
94 wmevent->windowY = wmevent->y = event.y();
95 wmevent->globalX = wmevent->x + origin.x();
96 wmevent->globalY = wmevent->y + origin.y();
97 }
98
99 } // namespace
100
101 RenderWidgetHostViewViews::RenderWidgetHostViewViews(RenderWidgetHost* host)
102 : host_(host),
103 about_to_validate_and_paint_(false),
104 is_hidden_(false),
105 is_loading_(false),
106 native_cursor_(gfx::kNullCursor),
107 is_showing_context_menu_(false),
108 visually_deemphasized_(false),
109 touch_event_(),
110 text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
111 has_composition_text_(false),
112 ALLOW_THIS_IN_INITIALIZER_LIST(touch_selection_controller_(
113 views::TouchSelectionController::create(this))),
114 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
115 set_focusable(true);
116 host_->SetView(this);
117
118 #if defined(TOUCH_UI)
119 SetPaintToLayer(true);
120 registrar_.Add(this,
121 chrome::NOTIFICATION_KEYBOARD_VISIBLE_BOUNDS_CHANGED,
122 content::NotificationService::AllSources());
123 #endif
124 }
125
126 RenderWidgetHostViewViews::~RenderWidgetHostViewViews() {
127 }
128
129 void RenderWidgetHostViewViews::InitAsChild() {
130 Show();
131 }
132
133 void RenderWidgetHostViewViews::InitAsPopup(
134 RenderWidgetHostView* parent_host_view,
135 const gfx::Rect& pos) {
136 RenderWidgetHostViewViews* parent =
137 static_cast<RenderWidgetHostViewViews*>(parent_host_view);
138 parent->AddChildView(this);
139 // If the parent loses focus then the popup will close. So we need
140 // to tell the parent it's showing a popup so that it doesn't respond to
141 // blurs.
142 parent->is_showing_context_menu_ = true;
143
144 // pos is in screen coordinates but a view is positioned relative
145 // to its parent. Here we convert screen coordinates to relative
146 // coordinates.
147 gfx::Point p(pos.x() - parent_host_view->GetViewBounds().x(),
148 pos.y() - parent_host_view->GetViewBounds().y());
149 views::View::SetBounds(p.x(), p.y(), pos.width(), pos.height());
150 Show();
151
152 if (NeedsInputGrab()) {
153 set_focusable(true);
154 RequestFocus();
155 }
156 }
157
158 void RenderWidgetHostViewViews::InitAsFullscreen(
159 RenderWidgetHostView* /*reference_host_view*/) {
160 NOTIMPLEMENTED();
161 }
162
163 RenderWidgetHost* RenderWidgetHostViewViews::GetRenderWidgetHost() const {
164 return host_;
165 }
166
167 void RenderWidgetHostViewViews::DidBecomeSelected() {
168 if (!is_hidden_)
169 return;
170
171 if (tab_switch_paint_time_.is_null())
172 tab_switch_paint_time_ = base::TimeTicks::Now();
173 is_hidden_ = false;
174 if (host_)
175 host_->WasRestored();
176 }
177
178 void RenderWidgetHostViewViews::WasHidden() {
179 if (is_hidden_)
180 return;
181
182 // If we receive any more paint messages while we are hidden, we want to
183 // ignore them so we don't re-allocate the backing store. We will paint
184 // everything again when we become selected again.
185 is_hidden_ = true;
186
187 // If we have a renderer, then inform it that we are being hidden so it can
188 // reduce its resource utilization.
189 if (host_)
190 host_->WasHidden();
191
192 weak_factory_.InvalidateWeakPtrs();
193 }
194
195 void RenderWidgetHostViewViews::SetSize(const gfx::Size& size) {
196 // This is called when webkit has sent us a Move message.
197 int width = std::min(size.width(), kMaxWindowWidth);
198 int height = std::min(size.height(), kMaxWindowHeight);
199 if (requested_size_.width() != width ||
200 requested_size_.height() != height) {
201 requested_size_ = gfx::Size(width, height);
202 views::View::SetBounds(x(), y(), width, height);
203 if (host_)
204 host_->WasResized();
205 }
206 }
207
208 void RenderWidgetHostViewViews::SetBounds(const gfx::Rect& rect) {
209 // TODO(oshima): chromeos/touch doesn't allow moving window.
210 SetSize(rect.size());
211 }
212
213 gfx::NativeView RenderWidgetHostViewViews::GetNativeView() const {
214 // TODO(oshima): There is no native view here for RWHVV.
215 // Use top level widget's native view for now. This is not
216 // correct and has to be fixed somehow.
217 return GetWidget() ? GetWidget()->GetNativeView() : NULL;
218 }
219
220 gfx::NativeViewId RenderWidgetHostViewViews::GetNativeViewId() const {
221 #if defined(OS_WIN)
222 // TODO(oshima): Windows uses message filter to handle inquiry for
223 // window/screen info, which requires HWND. Just pass the
224 // browser window's HWND (same as before) for now.
225 return reinterpret_cast<gfx::NativeViewId>(GetNativeView());
226 #else
227 return reinterpret_cast<gfx::NativeViewId>(
228 const_cast<RenderWidgetHostViewViews*>(this));
229 #endif
230 }
231
232 void RenderWidgetHostViewViews::MovePluginWindows(
233 const std::vector<webkit::npapi::WebPluginGeometry>& moves) {
234 // TODO(anicolao): NIY
235 // NOTIMPLEMENTED();
236 }
237
238 bool RenderWidgetHostViewViews::HasFocus() const {
239 return View::HasFocus();
240 }
241
242 void RenderWidgetHostViewViews::Show() {
243 SetVisible(true);
244 }
245
246 void RenderWidgetHostViewViews::Hide() {
247 SetVisible(false);
248 }
249
250 bool RenderWidgetHostViewViews::IsShowing() {
251 return IsVisible();
252 }
253
254 gfx::Rect RenderWidgetHostViewViews::GetViewBounds() const {
255 return GetScreenBounds();
256 }
257
258 void RenderWidgetHostViewViews::SetIsLoading(bool is_loading) {
259 is_loading_ = is_loading;
260 #if defined(TOOLKIT_USES_GTK)
261 // Only call ShowCurrentCursor() when it will actually change the cursor.
262 if (current_cursor_.GetCursorType() == GDK_LAST_CURSOR)
263 ShowCurrentCursor();
264 #endif // TOOLKIT_USES_GTK
265 }
266
267 void RenderWidgetHostViewViews::TextInputStateChanged(
268 ui::TextInputType type,
269 bool can_compose_inline) {
270 // TODO(kinaba): currently, can_compose_inline is ignored and always treated
271 // as true. We need to support "can_compose_inline=false" for PPAPI plugins
272 // that may want to avoid drawing composition-text by themselves and pass
273 // the responsibility to the browser.
274
275 // This is async message and by the time the ipc arrived,
276 // RWHVV may be detached from Top level widget, in which case
277 // GetInputMethod may return NULL;
278 views::InputMethod* input_method = GetInputMethod();
279
280 if (text_input_type_ != type) {
281 text_input_type_ = type;
282 if (input_method)
283 input_method->OnTextInputTypeChanged(this);
284 }
285 }
286
287 void RenderWidgetHostViewViews::ImeCancelComposition() {
288 DCHECK(GetInputMethod());
289 GetInputMethod()->CancelComposition(this);
290 has_composition_text_ = false;
291 }
292
293 void RenderWidgetHostViewViews::DidUpdateBackingStore(
294 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy,
295 const std::vector<gfx::Rect>& copy_rects) {
296 if (is_hidden_)
297 return;
298
299 // TODO(darin): Implement the equivalent of Win32's ScrollWindowEX. Can that
300 // be done using XCopyArea? Perhaps similar to
301 // BackingStore::ScrollBackingStore?
302 if (about_to_validate_and_paint_)
303 invalid_rect_ = invalid_rect_.Union(scroll_rect);
304 else
305 SchedulePaintInRect(scroll_rect);
306
307 for (size_t i = 0; i < copy_rects.size(); ++i) {
308 // Avoid double painting. NOTE: This is only relevant given the call to
309 // Paint(scroll_rect) above.
310 gfx::Rect rect = copy_rects[i].Subtract(scroll_rect);
311 if (rect.IsEmpty())
312 continue;
313
314 if (about_to_validate_and_paint_)
315 invalid_rect_ = invalid_rect_.Union(rect);
316 else
317 SchedulePaintInRect(rect);
318 }
319 invalid_rect_ = invalid_rect_.Intersect(bounds());
320 }
321
322 void RenderWidgetHostViewViews::RenderViewGone(base::TerminationStatus status,
323 int error_code) {
324 DCHECK(host_);
325 host_->ViewDestroyed();
326 Destroy();
327 }
328
329 void RenderWidgetHostViewViews::Destroy() {
330 // host_'s destruction brought us here, null it out so we don't use it
331 host_ = NULL;
332 if (parent()) {
333 if (IsPopup()) {
334 static_cast<RenderWidgetHostViewViews*>
335 (parent())->is_showing_context_menu_ = false;
336 // We're hiding the popup so we need to make sure we repaint
337 // what's underneath.
338 parent()->SchedulePaintInRect(bounds());
339 }
340 parent()->RemoveChildView(this);
341 }
342 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
343
344 #if defined(UI_COMPOSITOR_IMAGE_TRANSPORT)
345 // Send out all outstanding ACKs so that we don't block the GPU
346 // process.
347 for (std::vector< base::Callback<void(void)> >::const_iterator
348 it = on_compositing_ended_callbacks_.begin();
349 it != on_compositing_ended_callbacks_.end(); ++it) {
350 it->Run();
351 }
352 on_compositing_ended_callbacks_.clear();
353
354 // Remove dangling reference.
355 if (GetWidget() && GetWidget()->GetCompositor()) {
356 ui::Compositor *compositor = GetWidget()->GetCompositor();
357 if (compositor->HasObserver(this))
358 compositor->RemoveObserver(this);
359 }
360 #endif
361 }
362
363 void RenderWidgetHostViewViews::SetTooltipText(const string16& tip) {
364 const int kMaxTooltipLength = 8 << 10;
365 // Clamp the tooltip length to kMaxTooltipLength so that we don't
366 // accidentally DOS the user with a mega tooltip.
367 tooltip_text_ = ui::TruncateString(tip, kMaxTooltipLength);
368 if (GetWidget())
369 GetWidget()->TooltipTextChanged(this);
370 }
371
372 void RenderWidgetHostViewViews::SelectionChanged(const string16& text,
373 size_t offset,
374 const ui::Range& range) {
375 RenderWidgetHostView::SelectionChanged(text, offset, range);
376 // TODO(anicolao): deal with the clipboard without GTK
377 NOTIMPLEMENTED();
378 }
379
380 void RenderWidgetHostViewViews::SelectionBoundsChanged(
381 const gfx::Rect& start_rect,
382 const gfx::Rect& end_rect) {
383 views::InputMethod* input_method = GetInputMethod();
384
385 if (selection_start_rect_ == start_rect && selection_end_rect_ == end_rect)
386 return;
387
388 selection_start_rect_ = start_rect;
389 selection_end_rect_ = end_rect;
390
391 if (input_method)
392 input_method->OnCaretBoundsChanged(this);
393
394 // TODO(sad): This is a workaround for a webkit bug:
395 // https://bugs.webkit.org/show_bug.cgi?id=67464
396 // Remove this when the bug gets fixed.
397 //
398 // Webkit can send spurious selection-change on text-input (e.g. when
399 // inserting text at the beginning of a non-empty text control). But in those
400 // cases, it does send the correct selection information quickly afterwards.
401 // So delay the notification to the touch-selection controller.
402 if (!weak_factory_.HasWeakPtrs()) {
403 MessageLoop::current()->PostDelayedTask(FROM_HERE,
404 base::Bind(
405 &RenderWidgetHostViewViews::UpdateTouchSelectionController,
406 weak_factory_.GetWeakPtr()),
407 kTouchControllerUpdateDelay);
408 }
409 }
410
411 void RenderWidgetHostViewViews::Observe(
412 int type,
413 const content::NotificationSource& source,
414 const content::NotificationDetails& details) {
415 #if defined(TOUCH_UI)
416 if (type != chrome::NOTIFICATION_KEYBOARD_VISIBLE_BOUNDS_CHANGED) {
417 NOTREACHED();
418 return;
419 }
420
421 if (!GetWidget())
422 return;
423
424 gfx::Rect keyboard_rect = *content::Details<gfx::Rect>(details).ptr();
425 if (keyboard_rect != keyboard_rect_) {
426 keyboard_rect_ = keyboard_rect;
427 gfx::Rect screen_bounds = GetScreenBounds();
428 gfx::Rect intersecting_rect = screen_bounds.Intersect(keyboard_rect);
429 gfx::Rect available_rect = screen_bounds.Subtract(intersecting_rect);
430
431 // Convert available rect to window (RWHVV) coordinates.
432 gfx::Point origin = available_rect.origin();
433 gfx::Rect r = GetWidget()->GetClientAreaScreenBounds();
434 origin.SetPoint(origin.x() - r.x(), origin.y() - r.y());
435 views::View::ConvertPointFromWidget(this, &origin);
436 available_rect.set_origin(origin);
437 if (!available_rect.IsEmpty())
438 host_->ScrollFocusedEditableNodeIntoRect(available_rect);
439 }
440 #endif
441 }
442
443 void RenderWidgetHostViewViews::ShowingContextMenu(bool showing) {
444 is_showing_context_menu_ = showing;
445 }
446
447 BackingStore* RenderWidgetHostViewViews::AllocBackingStore(
448 const gfx::Size& size) {
449 return new BackingStoreSkia(host_, size);
450 }
451
452 void RenderWidgetHostViewViews::OnAcceleratedCompositingStateChange() {
453 #if defined(TOOLKIT_USES_GTK)
454 bool activated = host_->is_accelerated_compositing_active();
455 #if defined(UI_COMPOSITOR_IMAGE_TRANSPORT)
456 // If we don't use a views compositor, we currently have no way of
457 // supporting rendering via the GPU process.
458 if (!get_use_acceleration_when_possible() && activated)
459 NOTREACHED();
460 #else
461 if (activated)
462 NOTIMPLEMENTED();
463 #endif
464 #endif
465 }
466
467 void RenderWidgetHostViewViews::SetBackground(const SkBitmap& background) {
468 RenderWidgetHostView::SetBackground(background);
469 if (host_)
470 host_->SetBackground(background);
471 }
472
473 void RenderWidgetHostViewViews::SetVisuallyDeemphasized(
474 const SkColor* color, bool animate) {
475 // TODO(anicolao)
476 }
477
478 void RenderWidgetHostViewViews::UnhandledWheelEvent(
479 const WebKit::WebMouseWheelEvent& event) {
480 }
481
482 void RenderWidgetHostViewViews::SetHasHorizontalScrollbar(
483 bool has_horizontal_scrollbar) {
484 }
485
486 void RenderWidgetHostViewViews::SetScrollOffsetPinning(
487 bool is_pinned_to_left, bool is_pinned_to_right) {
488 }
489
490 bool RenderWidgetHostViewViews::LockMouse() {
491 NOTIMPLEMENTED();
492 return false;
493 }
494
495 void RenderWidgetHostViewViews::UnlockMouse() {
496 NOTIMPLEMENTED();
497 }
498
499 void RenderWidgetHostViewViews::SelectRect(const gfx::Point& start,
500 const gfx::Point& end) {
501 if (host_)
502 host_->SelectRange(start, end);
503 }
504
505 bool RenderWidgetHostViewViews::IsCommandIdChecked(int command_id) const {
506 NOTREACHED();
507 return true;
508 }
509
510 bool RenderWidgetHostViewViews::IsCommandIdEnabled(int command_id) const {
511 bool editable = GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE;
512 bool has_selection = !selection_range_.is_empty();
513 string16 result;
514 switch (command_id) {
515 case IDS_APP_CUT:
516 return editable && has_selection;
517 case IDS_APP_COPY:
518 return has_selection;
519 case IDS_APP_PASTE:
520 views::ViewsDelegate::views_delegate->GetClipboard()->
521 ReadText(ui::Clipboard::BUFFER_STANDARD, &result);
522 return editable && !result.empty();
523 case IDS_APP_DELETE:
524 return editable && has_selection;
525 case IDS_APP_SELECT_ALL:
526 return true;
527 default:
528 NOTREACHED();
529 return false;
530 }
531 return true;
532 }
533
534 bool RenderWidgetHostViewViews::GetAcceleratorForCommandId(
535 int command_id,
536 ui::Accelerator* accelerator) {
537 NOTREACHED();
538 return true;
539 }
540
541 void RenderWidgetHostViewViews::ExecuteCommand(int command_id) {
542 switch (command_id) {
543 case IDS_APP_CUT:
544 host_->Cut();
545 break;
546 case IDS_APP_COPY:
547 host_->Copy();
548 break;
549 case IDS_APP_PASTE:
550 host_->Paste();
551 break;
552 case IDS_APP_DELETE:
553 host_->Delete();
554 break;
555 case IDS_APP_SELECT_ALL:
556 host_->SelectAll();
557 break;
558 default:
559 NOTREACHED();
560 }
561 }
562
563 std::string RenderWidgetHostViewViews::GetClassName() const {
564 return kViewClassName;
565 }
566
567 gfx::NativeCursor RenderWidgetHostViewViews::GetCursor(
568 const views::MouseEvent& event) {
569 return native_cursor_;
570 }
571
572 bool RenderWidgetHostViewViews::OnMousePressed(const views::MouseEvent& event) {
573 // The special buttons on a mouse (e.g. back, forward etc.) are not correctly
574 // recognized by views Events. Ignore those events here, so that the event
575 // bubbles up the view hierarchy and the appropriate parent view can handle
576 // them.
577 if (!(event.flags() & (ui::EF_LEFT_BUTTON_DOWN |
578 ui::EF_RIGHT_BUTTON_DOWN |
579 ui::EF_MIDDLE_BUTTON_DOWN))) {
580 return false;
581 }
582
583 if (!host_)
584 return false;
585
586 RequestFocus();
587
588 // Confirm existing composition text on mouse click events, to make sure
589 // the input caret won't be moved with an ongoing composition text.
590 FinishImeCompositionSession();
591
592 // TODO(anicolao): validate event generation.
593 WebKit::WebMouseEvent e = WebMouseEventFromViewsEvent(event);
594
595 // TODO(anicolao): deal with double clicks
596 e.type = WebKit::WebInputEvent::MouseDown;
597 e.clickCount = 1;
598
599 host_->ForwardMouseEvent(e);
600 return true;
601 }
602
603 bool RenderWidgetHostViewViews::OnMouseDragged(const views::MouseEvent& event) {
604 OnMouseMoved(event);
605 return true;
606 }
607
608 void RenderWidgetHostViewViews::OnMouseReleased(
609 const views::MouseEvent& event) {
610 if (!(event.flags() & (ui::EF_LEFT_BUTTON_DOWN |
611 ui::EF_RIGHT_BUTTON_DOWN |
612 ui::EF_MIDDLE_BUTTON_DOWN))) {
613 return;
614 }
615
616 if (!host_)
617 return;
618
619 WebKit::WebMouseEvent e = WebMouseEventFromViewsEvent(event);
620 e.type = WebKit::WebInputEvent::MouseUp;
621 e.clickCount = 1;
622 host_->ForwardMouseEvent(e);
623 }
624
625 void RenderWidgetHostViewViews::OnMouseMoved(const views::MouseEvent& event) {
626 if (!host_)
627 return;
628
629 WebKit::WebMouseEvent e = WebMouseEventFromViewsEvent(event);
630 e.type = WebKit::WebInputEvent::MouseMove;
631 host_->ForwardMouseEvent(e);
632 }
633
634 void RenderWidgetHostViewViews::OnMouseEntered(const views::MouseEvent& event) {
635 // Already generated synthetically by webkit.
636 }
637
638 void RenderWidgetHostViewViews::OnMouseExited(const views::MouseEvent& event) {
639 // Already generated synthetically by webkit.
640 }
641
642 bool RenderWidgetHostViewViews::OnKeyPressed(const views::KeyEvent& event) {
643 // TODO(suzhe): Support editor key bindings.
644 if (!host_)
645 return false;
646 host_->ForwardKeyboardEvent(NativeWebKeyboardEventViews(event));
647 return true;
648 }
649
650 bool RenderWidgetHostViewViews::OnKeyReleased(const views::KeyEvent& event) {
651 if (!host_)
652 return false;
653 host_->ForwardKeyboardEvent(NativeWebKeyboardEventViews(event));
654 return true;
655 }
656
657 bool RenderWidgetHostViewViews::OnMouseWheel(
658 const views::MouseWheelEvent& event) {
659 if (!host_)
660 return false;
661
662 WebMouseWheelEvent wmwe;
663 InitializeWebMouseEventFromViewsEvent(event, GetMirroredPosition(), &wmwe);
664
665 wmwe.type = WebKit::WebInputEvent::MouseWheel;
666 wmwe.button = WebKit::WebMouseEvent::ButtonNone;
667
668 // TODO(sadrul): How do we determine if it's a horizontal scroll?
669 wmwe.deltaY = event.offset();
670 wmwe.wheelTicksY = wmwe.deltaY > 0 ? 1 : -1;
671
672 host_->ForwardWheelEvent(wmwe);
673 return true;
674 }
675
676 ui::TextInputClient* RenderWidgetHostViewViews::GetTextInputClient() {
677 return this;
678 }
679
680 bool RenderWidgetHostViewViews::GetTooltipText(const gfx::Point& p,
681 string16* tooltip) const {
682 if (tooltip_text_.length() == 0)
683 return false;
684 *tooltip = tooltip_text_;
685 return true;
686 }
687
688 // ui::TextInputClient implementation -----------------------------------------
689 void RenderWidgetHostViewViews::SetCompositionText(
690 const ui::CompositionText& composition) {
691 if (!host_)
692 return;
693
694 // ui::CompositionUnderline should be identical to
695 // WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely.
696 COMPILE_ASSERT(sizeof(ui::CompositionUnderline) ==
697 sizeof(WebKit::WebCompositionUnderline),
698 ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff);
699
700 // TODO(suzhe): convert both renderer_host and renderer to use
701 // ui::CompositionText.
702 const std::vector<WebKit::WebCompositionUnderline>& underlines =
703 reinterpret_cast<const std::vector<WebKit::WebCompositionUnderline>&>(
704 composition.underlines);
705
706 // TODO(suzhe): due to a bug of webkit, we can't use selection range with
707 // composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788
708 host_->ImeSetComposition(composition.text, underlines,
709 composition.selection.end(),
710 composition.selection.end());
711
712 has_composition_text_ = !composition.text.empty();
713 }
714
715 void RenderWidgetHostViewViews::ConfirmCompositionText() {
716 if (host_ && has_composition_text_)
717 host_->ImeConfirmComposition();
718 has_composition_text_ = false;
719 }
720
721 void RenderWidgetHostViewViews::ClearCompositionText() {
722 if (host_ && has_composition_text_)
723 host_->ImeCancelComposition();
724 has_composition_text_ = false;
725 }
726
727 void RenderWidgetHostViewViews::InsertText(const string16& text) {
728 DCHECK(text_input_type_ != ui::TEXT_INPUT_TYPE_NONE);
729 if (host_)
730 host_->ImeConfirmComposition(text);
731 has_composition_text_ = false;
732 }
733
734 void RenderWidgetHostViewViews::InsertChar(char16 ch, int flags) {
735 if (host_) {
736 NativeWebKeyboardEventViews::FromViewsEvent from_views_event;
737 NativeWebKeyboardEventViews wke(ch, flags, base::Time::Now().ToDoubleT(),
738 from_views_event);
739 host_->ForwardKeyboardEvent(wke);
740 }
741 }
742
743 ui::TextInputType RenderWidgetHostViewViews::GetTextInputType() const {
744 return text_input_type_;
745 }
746
747 gfx::Rect RenderWidgetHostViewViews::GetCaretBounds() {
748 return selection_start_rect_.Union(selection_end_rect_);
749 }
750
751 bool RenderWidgetHostViewViews::HasCompositionText() {
752 return has_composition_text_;
753 }
754
755 bool RenderWidgetHostViewViews::GetTextRange(ui::Range* range) {
756 range->set_start(selection_text_offset_);
757 range->set_end(selection_text_offset_ + selection_text_.length());
758 return true;
759 }
760
761 bool RenderWidgetHostViewViews::GetCompositionTextRange(ui::Range* range) {
762 // TODO(suzhe): implement this method when fixing http://crbug.com/55130.
763 NOTIMPLEMENTED();
764 return false;
765 }
766
767 bool RenderWidgetHostViewViews::GetSelectionRange(ui::Range* range) {
768 range->set_start(selection_range_.start());
769 range->set_end(selection_range_.end());
770 return true;
771 }
772
773 bool RenderWidgetHostViewViews::SetSelectionRange(const ui::Range& range) {
774 // TODO(suzhe): implement this method when fixing http://crbug.com/55130.
775 NOTIMPLEMENTED();
776 return false;
777 }
778
779 bool RenderWidgetHostViewViews::DeleteRange(const ui::Range& range) {
780 // TODO(suzhe): implement this method when fixing http://crbug.com/55130.
781 NOTIMPLEMENTED();
782 return false;
783 }
784
785 bool RenderWidgetHostViewViews::GetTextFromRange(
786 const ui::Range& range,
787 string16* text) {
788 ui::Range selection_text_range(selection_text_offset_,
789 selection_text_offset_ + selection_text_.length());
790
791 if (!selection_text_range.Contains(range)) {
792 text->clear();
793 return false;
794 }
795 if (selection_text_range.EqualsIgnoringDirection(range)) {
796 // Avoid calling substr which performance is low.
797 *text = selection_text_;
798 } else {
799 *text = selection_text_.substr(
800 range.GetMin() - selection_text_offset_,
801 range.length());
802 }
803 return true;
804 }
805
806 void RenderWidgetHostViewViews::OnInputMethodChanged() {
807 if (!host_)
808 return;
809
810 DCHECK(GetInputMethod());
811 host_->SetInputMethodActive(GetInputMethod()->IsActive());
812
813 // TODO(suzhe): implement the newly added “locale” property of HTML DOM
814 // TextEvent.
815 }
816
817 bool RenderWidgetHostViewViews::ChangeTextDirectionAndLayoutAlignment(
818 base::i18n::TextDirection direction) {
819 if (!host_)
820 return false;
821 host_->UpdateTextDirection(
822 direction == base::i18n::RIGHT_TO_LEFT ?
823 WebKit::WebTextDirectionRightToLeft :
824 WebKit::WebTextDirectionLeftToRight);
825 host_->NotifyTextDirection();
826 return true;
827 }
828
829 void RenderWidgetHostViewViews::OnPaint(gfx::Canvas* canvas) {
830 if (is_hidden_ || !host_)
831 return;
832
833 DCHECK(!host_->is_accelerated_compositing_active() ||
834 get_use_acceleration_when_possible());
835
836 // If we aren't using the views compositor, then
837 // paint a "hole" in the canvas so that the render of the web page is on
838 // top of whatever else has already been painted in the views hierarchy.
839 // Later views might still get to paint on top.
840 if (!get_use_acceleration_when_possible())
841 canvas->FillRect(SK_ColorBLACK, GetLocalBounds(), SkXfermode::kClear_Mode);
842
843 DCHECK(!about_to_validate_and_paint_);
844
845 // TODO(anicolao): get the damage somehow
846 // invalid_rect_ = damage_rect;
847 invalid_rect_ = bounds();
848 gfx::Point origin;
849 ConvertPointToWidget(this, &origin);
850
851 about_to_validate_and_paint_ = true;
852 BackingStore* backing_store = host_->GetBackingStore(true);
853 // Calling GetBackingStore maybe have changed |invalid_rect_|...
854 about_to_validate_and_paint_ = false;
855
856 gfx::Rect paint_rect = gfx::Rect(0, 0, kMaxWindowWidth, kMaxWindowHeight);
857 paint_rect = paint_rect.Intersect(invalid_rect_);
858
859 if (backing_store) {
860 #if defined(TOOLKIT_USES_GTK)
861 // Only render the widget if it is attached to a window; there's a short
862 // period where this object isn't attached to a window but hasn't been
863 // Destroy()ed yet and it receives paint messages...
864 if (IsReadyToPaint()) {
865 #endif
866 if (!visually_deemphasized_) {
867 // In the common case, use XCopyArea. We don't draw more than once, so
868 // we don't need to double buffer.
869 if (IsPopup()) {
870 origin.SetPoint(origin.x() + paint_rect.x(),
871 origin.y() + paint_rect.y());
872 paint_rect.SetRect(0, 0, paint_rect.width(), paint_rect.height());
873 }
874 static_cast<BackingStoreSkia*>(backing_store)->SkiaShowRect(
875 gfx::Point(paint_rect.x(), paint_rect.y()), canvas);
876 } else {
877 // TODO(sad)
878 NOTIMPLEMENTED();
879 }
880 #if defined(TOOLKIT_USES_GTK)
881 }
882 #endif
883 if (!whiteout_start_time_.is_null()) {
884 base::TimeDelta whiteout_duration = base::TimeTicks::Now() -
885 whiteout_start_time_;
886 UMA_HISTOGRAM_TIMES("MPArch.RWHH_WhiteoutDuration", whiteout_duration);
887
888 // Reset the start time to 0 so that we start recording again the next
889 // time the backing store is NULL...
890 whiteout_start_time_ = base::TimeTicks();
891 }
892 if (!tab_switch_paint_time_.is_null()) {
893 base::TimeDelta tab_switch_paint_duration = base::TimeTicks::Now() -
894 tab_switch_paint_time_;
895 UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration",
896 tab_switch_paint_duration);
897 // Reset tab_switch_paint_time_ to 0 so future tab selections are
898 // recorded.
899 tab_switch_paint_time_ = base::TimeTicks();
900 }
901 } else {
902 if (whiteout_start_time_.is_null())
903 whiteout_start_time_ = base::TimeTicks::Now();
904
905 if (get_use_acceleration_when_possible())
906 canvas->FillRect(SK_ColorWHITE, GetLocalBounds());
907 }
908 }
909
910 void RenderWidgetHostViewViews::Focus() {
911 RequestFocus();
912 }
913
914 void RenderWidgetHostViewViews::Blur() {
915 // TODO(estade): We should be clearing native focus as well, but I know of no
916 // way to do that without focusing another widget.
917 if (host_) {
918 host_->SetActive(false);
919 host_->Blur();
920 }
921 }
922
923 void RenderWidgetHostViewViews::OnFocus() {
924 if (!host_)
925 return;
926
927 DCHECK(GetInputMethod());
928 View::OnFocus();
929 ShowCurrentCursor();
930 host_->GotFocus();
931 host_->SetActive(true);
932 host_->SetInputMethodActive(GetInputMethod()->IsActive());
933
934 UpdateTouchSelectionController();
935 }
936
937 void RenderWidgetHostViewViews::OnBlur() {
938 if (!host_)
939 return;
940 View::OnBlur();
941 // If we are showing a context menu, maintain the illusion that webkit has
942 // focus.
943 if (!is_showing_context_menu_ && !is_hidden_)
944 host_->Blur();
945 host_->SetInputMethodActive(false);
946
947 if (touch_selection_controller_.get())
948 touch_selection_controller_->ClientViewLostFocus();
949 }
950
951 bool RenderWidgetHostViewViews::NeedsInputGrab() {
952 return popup_type_ == WebKit::WebPopupTypeSelect;
953 }
954
955 bool RenderWidgetHostViewViews::IsPopup() {
956 return popup_type_ != WebKit::WebPopupTypeNone;
957 }
958
959 WebKit::WebMouseEvent RenderWidgetHostViewViews::WebMouseEventFromViewsEvent(
960 const views::MouseEvent& event) {
961 WebKit::WebMouseEvent wmevent;
962 InitializeWebMouseEventFromViewsEvent(event, GetMirroredPosition(), &wmevent);
963
964 // Setting |wmevent.button| is not necessary for -move events, but it is
965 // necessary for -clicks and -drags.
966 if (event.IsMiddleMouseButton()) {
967 wmevent.modifiers |= WebKit::WebInputEvent::MiddleButtonDown;
968 wmevent.button = WebKit::WebMouseEvent::ButtonMiddle;
969 }
970 if (event.IsRightMouseButton()) {
971 wmevent.modifiers |= WebKit::WebInputEvent::RightButtonDown;
972 wmevent.button = WebKit::WebMouseEvent::ButtonRight;
973 }
974 if (event.IsLeftMouseButton()) {
975 wmevent.modifiers |= WebKit::WebInputEvent::LeftButtonDown;
976 wmevent.button = WebKit::WebMouseEvent::ButtonLeft;
977 }
978
979 return wmevent;
980 }
981
982 void RenderWidgetHostViewViews::FinishImeCompositionSession() {
983 if (!has_composition_text_)
984 return;
985 if (host_)
986 host_->ImeConfirmComposition();
987 DCHECK(GetInputMethod());
988 GetInputMethod()->CancelComposition(this);
989 has_composition_text_ = false;
990 }
991
992 void RenderWidgetHostViewViews::UpdateTouchSelectionController() {
993 gfx::Point start = selection_start_rect_.origin();
994 start.Offset(0, selection_start_rect_.height());
995 gfx::Point end = selection_end_rect_.origin();
996 end.Offset(0, selection_end_rect_.height());
997
998 if (touch_selection_controller_.get())
999 touch_selection_controller_->SelectionChanged(start, end);
1000 }
1001
1002 #if !defined(OS_WIN)
1003 void RenderWidgetHostViewViews::UpdateCursor(const WebCursor& cursor) {
1004 // Optimize the common case, where the cursor hasn't changed.
1005 // However, we can switch between different pixmaps, so only on the
1006 // non-pixmap branch.
1007 #if defined(TOOLKIT_USES_GTK)
1008 if (current_cursor_.GetCursorType() != GDK_CURSOR_IS_PIXMAP &&
1009 current_cursor_.GetCursorType() == cursor.GetCursorType()) {
1010 return;
1011 }
1012 #endif
1013 current_cursor_ = cursor;
1014 ShowCurrentCursor();
1015 }
1016
1017 void RenderWidgetHostViewViews::ShowCurrentCursor() {
1018 #if !defined(USE_AURA)
1019 // The widget may not have a window. If that's the case, abort mission. This
1020 // is the same issue as that explained above in Paint().
1021 if (!IsReadyToPaint())
1022 return;
1023 #endif
1024
1025 native_cursor_ = current_cursor_.GetNativeCursor();
1026 }
1027
1028 #if defined(TOOLKIT_USES_GTK)
1029 bool RenderWidgetHostViewViews::IsReadyToPaint() {
1030 views::Widget* top = NULL;
1031
1032 // TODO(oshima): move this functionality to Widget.
1033 if (views::ViewsDelegate::views_delegate &&
1034 views::ViewsDelegate::views_delegate->GetDefaultParentView()) {
1035 top = views::ViewsDelegate::views_delegate->GetDefaultParentView()->
1036 GetWidget();
1037 } else {
1038 // Use GetTopLevelWidget()'s native view to get platform
1039 // native widget. This is a workaround to get window's NativeWidgetGtk
1040 // under both views desktop (where toplevel is NativeWidgetViews,
1041 // whose GetNativeView returns gtk widget of the native window)
1042 // and non views desktop (where toplevel is NativeWidgetGtk).
1043 top = GetWidget() ?
1044 views::Widget::GetWidgetForNativeView(
1045 GetWidget()->GetTopLevelWidget()->GetNativeView()) :
1046 NULL;
1047 }
1048
1049 return top ?
1050 !!(static_cast<const views::NativeWidgetGtk*>(top->native_widget())->
1051 window_contents()->window) : false;
1052 }
1053 #endif
1054
1055 #endif // !OS_WIN
1056
1057 #if defined(TOOLKIT_USES_GTK)
1058 void RenderWidgetHostViewViews::CreatePluginContainer(
1059 gfx::PluginWindowHandle id) {
1060 // TODO(anicolao): plugin_container_manager_.CreatePluginContainer(id);
1061 }
1062
1063 void RenderWidgetHostViewViews::DestroyPluginContainer(
1064 gfx::PluginWindowHandle id) {
1065 // TODO(anicolao): plugin_container_manager_.DestroyPluginContainer(id);
1066 }
1067
1068 #endif // TOOLKIT_USES_GTK
1069
1070 #if defined(OS_POSIX) || defined(USE_AURA)
1071 void RenderWidgetHostViewViews::GetDefaultScreenInfo(
1072 WebKit::WebScreenInfo* results) {
1073 NOTIMPLEMENTED();
1074 }
1075
1076 void RenderWidgetHostViewViews::GetScreenInfo(WebKit::WebScreenInfo* results) {
1077 #if !defined(USE_AURA)
1078 views::Widget* widget = GetWidget() ? GetWidget()->GetTopLevelWidget() : NULL;
1079 if (widget && widget->GetNativeView())
1080 content::GetScreenInfoFromNativeWindow(widget->GetNativeView()->window,
1081 results);
1082 else
1083 RenderWidgetHostView::GetDefaultScreenInfo(results);
1084 #else
1085 RenderWidgetHostView::GetDefaultScreenInfo(results);
1086 #endif
1087 }
1088
1089 gfx::Rect RenderWidgetHostViewViews::GetRootWindowBounds() {
1090 views::Widget* widget = GetWidget() ? GetWidget()->GetTopLevelWidget() : NULL;
1091 return widget ? widget->GetWindowScreenBounds() : gfx::Rect();
1092 }
1093 #endif
1094
1095 #if !defined(OS_WIN) && !defined(UI_COMPOSITOR_IMAGE_TRANSPORT)
1096 gfx::PluginWindowHandle RenderWidgetHostViewViews::GetCompositingSurface() {
1097 // TODO(oshima): The original implementation was broken as
1098 // GtkNativeViewManager doesn't know about NativeWidgetGtk. Figure
1099 // out if this makes sense without compositor. If it does, then find
1100 // out the right way to handle.
1101 NOTIMPLEMENTED();
1102 return gfx::kNullPluginWindow;
1103 }
1104 #endif
1105
1106 #if defined(UI_COMPOSITOR_IMAGE_TRANSPORT)
1107 gfx::PluginWindowHandle RenderWidgetHostViewViews::GetCompositingSurface() {
1108 // On TOUCH_UI builds, the GPU process renders to an offscreen surface
1109 // (created by the GPU process), which is later displayed by the browser.
1110 // As the GPU process creates this surface, we can return any non-zero value.
1111 return 1;
1112 }
1113
1114 void RenderWidgetHostViewViews::AcceleratedSurfaceNew(
1115 int32 width,
1116 int32 height,
1117 uint64* surface_id,
1118 TransportDIB::Handle* surface_handle) {
1119 scoped_refptr<AcceleratedSurfaceContainerLinux> surface(
1120 AcceleratedSurfaceContainerLinux::Create(gfx::Size(width, height)));
1121 if (!surface->Initialize(surface_id)) {
1122 LOG(ERROR) << "Failed to create AcceleratedSurfaceContainer";
1123 return;
1124 }
1125 *surface_handle = surface->Handle();
1126
1127 accelerated_surface_containers_[*surface_id] = surface;
1128 }
1129
1130 void RenderWidgetHostViewViews::AcceleratedSurfaceRelease(uint64 surface_id) {
1131 accelerated_surface_containers_.erase(surface_id);
1132 }
1133
1134 void RenderWidgetHostViewViews::AcceleratedSurfaceBuffersSwapped(
1135 uint64 surface_id,
1136 int32 route_id,
1137 int gpu_host_id) {
1138 SetExternalTexture(accelerated_surface_containers_[surface_id]->GetTexture());
1139 glFlush();
1140
1141 if (!GetWidget() || !GetWidget()->GetCompositor()) {
1142 // We have no compositor, so we have no way to display the surface.
1143 // Must still send the ACK.
1144 host_->AcknowledgeSwapBuffers(route_id, gpu_host_id);
1145 } else {
1146 // Add sending an ACK to the list of things to do OnCompositingEnded
1147 on_compositing_ended_callbacks_.push_back(
1148 base::Bind(&RenderWidgetHost::AcknowledgeSwapBuffers,
1149 base::Unretained(host_), route_id, gpu_host_id));
1150 ui::Compositor *compositor = GetWidget()->GetCompositor();
1151 if (!compositor->HasObserver(this))
1152 compositor->AddObserver(this);
1153 }
1154 }
1155
1156 void RenderWidgetHostViewViews::OnCompositingEnded(ui::Compositor* compositor) {
1157 for (std::vector< base::Callback<void(void)> >::const_iterator
1158 it = on_compositing_ended_callbacks_.begin();
1159 it != on_compositing_ended_callbacks_.end(); ++it) {
1160 it->Run();
1161 }
1162 on_compositing_ended_callbacks_.clear();
1163 compositor->RemoveObserver(this);
1164 }
1165
1166 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698