Home | History | Annotate | Download | only in renderer_host
      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/command_line.h"
     11 #include "base/logging.h"
     12 #include "base/message_loop.h"
     13 #include "base/metrics/histogram.h"
     14 #include "base/string_number_conversions.h"
     15 #include "base/task.h"
     16 #include "base/time.h"
     17 #include "chrome/common/render_messages.h"
     18 #include "content/browser/renderer_host/backing_store_skia.h"
     19 #include "content/browser/renderer_host/backing_store_x.h"
     20 #include "content/browser/renderer_host/render_widget_host.h"
     21 #include "content/common/native_web_keyboard_event.h"
     22 #include "content/common/result_codes.h"
     23 #include "content/common/view_messages.h"
     24 #include "third_party/WebKit/Source/WebKit/chromium/public/gtk/WebInputEventFactory.h"
     25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
     26 #include "ui/base/keycodes/keyboard_code_conversion_gtk.h"
     27 #include "ui/base/l10n/l10n_util.h"
     28 #include "ui/base/x/x11_util.h"
     29 #include "ui/gfx/canvas.h"
     30 #include "ui/gfx/canvas_skia.h"
     31 #include "ui/gfx/gtk_native_view_id_manager.h"
     32 #include "views/events/event.h"
     33 #include "views/ime/input_method.h"
     34 #include "views/widget/widget.h"
     35 #include "views/widget/widget_gtk.h"
     36 
     37 static const int kMaxWindowWidth = 4000;
     38 static const int kMaxWindowHeight = 4000;
     39 static const char kRenderWidgetHostViewKey[] = "__RENDER_WIDGET_HOST_VIEW__";
     40 static const char kBackingStoreSkiaSwitch[] = "use-backing-store-skia";
     41 
     42 // Copied from third_party/WebKit/Source/WebCore/page/EventHandler.cpp
     43 //
     44 // Match key code of composition keydown event on windows.
     45 // IE sends VK_PROCESSKEY which has value 229;
     46 //
     47 // Please refer to following documents for detals:
     48 // - Virtual-Key Codes
     49 //   http://msdn.microsoft.com/en-us/library/ms645540(VS.85).aspx
     50 // - How the IME System Works
     51 //   http://msdn.microsoft.com/en-us/library/cc194848.aspx
     52 // - ImmGetVirtualKey Function
     53 //   http://msdn.microsoft.com/en-us/library/dd318570(VS.85).aspx
     54 static const int kCompositionEventKeyCode = 229;
     55 
     56 using WebKit::WebInputEventFactory;
     57 using WebKit::WebMouseWheelEvent;
     58 using WebKit::WebTouchEvent;
     59 
     60 const char RenderWidgetHostViewViews::kViewClassName[] =
     61     "browser/renderer_host/RenderWidgetHostViewViews";
     62 
     63 namespace {
     64 
     65 bool UsingBackingStoreSkia() {
     66   static bool decided = false;
     67   static bool use_skia = false;
     68   if (!decided) {
     69     CommandLine* cmdline = CommandLine::ForCurrentProcess();
     70     use_skia = (cmdline && cmdline->HasSwitch(kBackingStoreSkiaSwitch));
     71     decided = true;
     72   }
     73 
     74   return use_skia;
     75 }
     76 
     77 int WebInputEventFlagsFromViewsEvent(const views::Event& event) {
     78   int modifiers = 0;
     79 
     80   if (event.IsShiftDown())
     81     modifiers |= WebKit::WebInputEvent::ShiftKey;
     82   if (event.IsControlDown())
     83     modifiers |= WebKit::WebInputEvent::ControlKey;
     84   if (event.IsAltDown())
     85     modifiers |= WebKit::WebInputEvent::AltKey;
     86   if (event.IsCapsLockDown())
     87     modifiers |= WebKit::WebInputEvent::CapsLockOn;
     88 
     89   return modifiers;
     90 }
     91 
     92 WebKit::WebTouchPoint::State TouchPointStateFromEvent(
     93     const views::TouchEvent* event) {
     94   switch (event->type()) {
     95     case ui::ET_TOUCH_PRESSED:
     96       return WebKit::WebTouchPoint::StatePressed;
     97     case ui::ET_TOUCH_RELEASED:
     98       return WebKit::WebTouchPoint::StateReleased;
     99     case ui::ET_TOUCH_MOVED:
    100       return WebKit::WebTouchPoint::StateMoved;
    101     case ui::ET_TOUCH_CANCELLED:
    102       return WebKit::WebTouchPoint::StateCancelled;
    103     default:
    104       return WebKit::WebTouchPoint::StateUndefined;
    105   }
    106 }
    107 
    108 WebKit::WebInputEvent::Type TouchEventTypeFromEvent(
    109     const views::TouchEvent* event) {
    110   switch (event->type()) {
    111     case ui::ET_TOUCH_PRESSED:
    112       return WebKit::WebInputEvent::TouchStart;
    113     case ui::ET_TOUCH_RELEASED:
    114       return WebKit::WebInputEvent::TouchEnd;
    115     case ui::ET_TOUCH_MOVED:
    116       return WebKit::WebInputEvent::TouchMove;
    117     case ui::ET_TOUCH_CANCELLED:
    118       return WebKit::WebInputEvent::TouchCancel;
    119     default:
    120       return WebKit::WebInputEvent::Undefined;
    121   }
    122 }
    123 
    124 void UpdateTouchPointPosition(const views::TouchEvent* event,
    125                               const gfx::Point& origin,
    126                               WebKit::WebTouchPoint* tpoint) {
    127   tpoint->position.x = event->x();
    128   tpoint->position.y = event->y();
    129 
    130   tpoint->screenPosition.x = tpoint->position.x + origin.x();
    131   tpoint->screenPosition.y = tpoint->position.y + origin.y();
    132 }
    133 
    134 void InitializeWebMouseEventFromViewsEvent(const views::LocatedEvent& event,
    135                                            const gfx::Point& origin,
    136                                            WebKit::WebMouseEvent* wmevent) {
    137   wmevent->timeStampSeconds = base::Time::Now().ToDoubleT();
    138   wmevent->modifiers = WebInputEventFlagsFromViewsEvent(event);
    139 
    140   wmevent->windowX = wmevent->x = event.x();
    141   wmevent->windowY = wmevent->y = event.y();
    142   wmevent->globalX = wmevent->x + origin.x();
    143   wmevent->globalY = wmevent->y + origin.y();
    144 }
    145 
    146 }  // namespace
    147 
    148 // static
    149 RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget(
    150     RenderWidgetHost* widget) {
    151   return new RenderWidgetHostViewViews(widget);
    152 }
    153 
    154 RenderWidgetHostViewViews::RenderWidgetHostViewViews(RenderWidgetHost* host)
    155     : host_(host),
    156       about_to_validate_and_paint_(false),
    157       is_hidden_(false),
    158       is_loading_(false),
    159       native_cursor_(NULL),
    160       is_showing_context_menu_(false),
    161       visually_deemphasized_(false),
    162       touch_event_(),
    163       text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
    164       has_composition_text_(false) {
    165   SetFocusable(true);
    166   host_->set_view(this);
    167 }
    168 
    169 RenderWidgetHostViewViews::~RenderWidgetHostViewViews() {
    170 }
    171 
    172 void RenderWidgetHostViewViews::InitAsChild() {
    173   Show();
    174 }
    175 
    176 void RenderWidgetHostViewViews::InitAsPopup(
    177     RenderWidgetHostView* parent_host_view,
    178     const gfx::Rect& pos) {
    179   // TODO(anicolao): figure out cases where popups occur and implement
    180   NOTIMPLEMENTED();
    181 }
    182 
    183 void RenderWidgetHostViewViews::InitAsFullscreen() {
    184   NOTIMPLEMENTED();
    185 }
    186 
    187 RenderWidgetHost* RenderWidgetHostViewViews::GetRenderWidgetHost() const {
    188   return host_;
    189 }
    190 
    191 void RenderWidgetHostViewViews::DidBecomeSelected() {
    192   if (!is_hidden_)
    193     return;
    194 
    195   if (tab_switch_paint_time_.is_null())
    196     tab_switch_paint_time_ = base::TimeTicks::Now();
    197   is_hidden_ = false;
    198   if (host_)
    199     host_->WasRestored();
    200 }
    201 
    202 void RenderWidgetHostViewViews::WasHidden() {
    203   if (is_hidden_)
    204     return;
    205 
    206   // If we receive any more paint messages while we are hidden, we want to
    207   // ignore them so we don't re-allocate the backing store.  We will paint
    208   // everything again when we become selected again.
    209   is_hidden_ = true;
    210 
    211   // If we have a renderer, then inform it that we are being hidden so it can
    212   // reduce its resource utilization.
    213   if (host_)
    214     host_->WasHidden();
    215 }
    216 
    217 void RenderWidgetHostViewViews::SetSize(const gfx::Size& size) {
    218   // This is called when webkit has sent us a Move message.
    219   int width = std::min(size.width(), kMaxWindowWidth);
    220   int height = std::min(size.height(), kMaxWindowHeight);
    221   if (requested_size_.width() != width ||
    222       requested_size_.height() != height) {
    223     requested_size_ = gfx::Size(width, height);
    224     views::View::SetBounds(x(), y(), width, height);
    225     if (host_)
    226       host_->WasResized();
    227   }
    228 }
    229 
    230 void RenderWidgetHostViewViews::SetBounds(const gfx::Rect& rect) {
    231   NOTIMPLEMENTED();
    232 }
    233 
    234 gfx::NativeView RenderWidgetHostViewViews::GetNativeView() {
    235   if (GetWidget())
    236     return GetWidget()->GetNativeView();
    237   return NULL;
    238 }
    239 
    240 void RenderWidgetHostViewViews::MovePluginWindows(
    241     const std::vector<webkit::npapi::WebPluginGeometry>& moves) {
    242   // TODO(anicolao): NIY
    243   // NOTIMPLEMENTED();
    244 }
    245 
    246 bool RenderWidgetHostViewViews::HasFocus() {
    247   return View::HasFocus();
    248 }
    249 
    250 void RenderWidgetHostViewViews::Show() {
    251   SetVisible(true);
    252 }
    253 
    254 void RenderWidgetHostViewViews::Hide() {
    255   SetVisible(false);
    256 }
    257 
    258 bool RenderWidgetHostViewViews::IsShowing() {
    259   return IsVisible();
    260 }
    261 
    262 gfx::Rect RenderWidgetHostViewViews::GetViewBounds() const {
    263   return bounds();
    264 }
    265 
    266 void RenderWidgetHostViewViews::UpdateCursor(const WebCursor& cursor) {
    267   // Optimize the common case, where the cursor hasn't changed.
    268   // However, we can switch between different pixmaps, so only on the
    269   // non-pixmap branch.
    270   if (current_cursor_.GetCursorType() != GDK_CURSOR_IS_PIXMAP &&
    271       current_cursor_.GetCursorType() == cursor.GetCursorType()) {
    272     return;
    273   }
    274 
    275   current_cursor_ = cursor;
    276   ShowCurrentCursor();
    277 }
    278 
    279 void RenderWidgetHostViewViews::SetIsLoading(bool is_loading) {
    280   is_loading_ = is_loading;
    281   // Only call ShowCurrentCursor() when it will actually change the cursor.
    282   if (current_cursor_.GetCursorType() == GDK_LAST_CURSOR)
    283     ShowCurrentCursor();
    284 }
    285 
    286 void RenderWidgetHostViewViews::ImeUpdateTextInputState(
    287     WebKit::WebTextInputType type,
    288     const gfx::Rect& caret_rect) {
    289   DCHECK(GetInputMethod());
    290   ui::TextInputType new_type = static_cast<ui::TextInputType>(type);
    291   if (text_input_type_ != new_type) {
    292     text_input_type_ = new_type;
    293     GetInputMethod()->OnTextInputTypeChanged(this);
    294   }
    295   if (caret_bounds_ != caret_rect) {
    296     caret_bounds_ = caret_rect;
    297     GetInputMethod()->OnCaretBoundsChanged(this);
    298   }
    299 }
    300 
    301 void RenderWidgetHostViewViews::ImeCancelComposition() {
    302   DCHECK(GetInputMethod());
    303   GetInputMethod()->CancelComposition(this);
    304   has_composition_text_ = false;
    305 }
    306 
    307 void RenderWidgetHostViewViews::DidUpdateBackingStore(
    308     const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy,
    309     const std::vector<gfx::Rect>& copy_rects) {
    310   if (is_hidden_)
    311     return;
    312 
    313   // TODO(darin): Implement the equivalent of Win32's ScrollWindowEX.  Can that
    314   // be done using XCopyArea?  Perhaps similar to
    315   // BackingStore::ScrollBackingStore?
    316   if (about_to_validate_and_paint_)
    317     invalid_rect_ = invalid_rect_.Union(scroll_rect);
    318   else
    319     SchedulePaintInRect(scroll_rect);
    320 
    321   for (size_t i = 0; i < copy_rects.size(); ++i) {
    322     // Avoid double painting.  NOTE: This is only relevant given the call to
    323     // Paint(scroll_rect) above.
    324     gfx::Rect rect = copy_rects[i].Subtract(scroll_rect);
    325     if (rect.IsEmpty())
    326       continue;
    327 
    328     if (about_to_validate_and_paint_)
    329       invalid_rect_ = invalid_rect_.Union(rect);
    330     else
    331       SchedulePaintInRect(rect);
    332   }
    333   invalid_rect_ = invalid_rect_.Intersect(bounds());
    334 }
    335 
    336 void RenderWidgetHostViewViews::RenderViewGone(base::TerminationStatus status,
    337                                                int error_code) {
    338   DCHECK(host_);
    339   host_->ViewDestroyed();
    340   Destroy();
    341 }
    342 
    343 void RenderWidgetHostViewViews::Destroy() {
    344   // host_'s destruction brought us here, null it out so we don't use it
    345   host_ = NULL;
    346 
    347   if (parent())
    348     parent()->RemoveChildView(this);
    349   MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    350 }
    351 
    352 void RenderWidgetHostViewViews::SetTooltipText(const std::wstring& tip) {
    353   // TODO(anicolao): decide if we want tooltips for touch (none specified
    354   // right now/might want a press-and-hold display)
    355   // NOTIMPLEMENTED(); ... too annoying, it triggers for every mousemove
    356 }
    357 
    358 void RenderWidgetHostViewViews::SelectionChanged(const std::string& text) {
    359   // TODO(anicolao): deal with the clipboard without GTK
    360   NOTIMPLEMENTED();
    361 }
    362 
    363 void RenderWidgetHostViewViews::ShowingContextMenu(bool showing) {
    364   is_showing_context_menu_ = showing;
    365 }
    366 
    367 BackingStore* RenderWidgetHostViewViews::AllocBackingStore(
    368     const gfx::Size& size) {
    369   gfx::NativeView nview = GetInnerNativeView();
    370   if (!nview)
    371     return NULL;
    372 
    373   if (UsingBackingStoreSkia()) {
    374     return new BackingStoreSkia(host_, size);
    375   } else {
    376     return new BackingStoreX(host_, size,
    377                              ui::GetVisualFromGtkWidget(nview),
    378                              gtk_widget_get_visual(nview)->depth);
    379   }
    380 }
    381 
    382 void RenderWidgetHostViewViews::SetBackground(const SkBitmap& background) {
    383   RenderWidgetHostView::SetBackground(background);
    384   if (host_)
    385     host_->Send(new ViewMsg_SetBackground(host_->routing_id(), background));
    386 }
    387 
    388 void RenderWidgetHostViewViews::CreatePluginContainer(
    389     gfx::PluginWindowHandle id) {
    390   // TODO(anicolao): plugin_container_manager_.CreatePluginContainer(id);
    391 }
    392 
    393 void RenderWidgetHostViewViews::DestroyPluginContainer(
    394     gfx::PluginWindowHandle id) {
    395   // TODO(anicolao): plugin_container_manager_.DestroyPluginContainer(id);
    396 }
    397 
    398 void RenderWidgetHostViewViews::SetVisuallyDeemphasized(
    399     const SkColor* color, bool animate) {
    400   // TODO(anicolao)
    401 }
    402 
    403 bool RenderWidgetHostViewViews::ContainsNativeView(
    404     gfx::NativeView native_view) const {
    405   // TODO(port)
    406   NOTREACHED() <<
    407     "RenderWidgetHostViewViews::ContainsNativeView not implemented.";
    408   return false;
    409 }
    410 
    411 void RenderWidgetHostViewViews::AcceleratedCompositingActivated(
    412     bool activated) {
    413   // TODO(anicolao): figure out if we need something here
    414   if (activated)
    415     NOTIMPLEMENTED();
    416 }
    417 
    418 gfx::PluginWindowHandle RenderWidgetHostViewViews::GetCompositingSurface() {
    419   GtkNativeViewManager* manager = GtkNativeViewManager::GetInstance();
    420   gfx::PluginWindowHandle surface = gfx::kNullPluginWindow;
    421   gfx::NativeViewId view_id = gfx::IdFromNativeView(GetInnerNativeView());
    422 
    423   if (!manager->GetXIDForId(&surface, view_id)) {
    424     DLOG(ERROR) << "Can't find XID for view id " << view_id;
    425   }
    426   return surface;
    427 }
    428 
    429 gfx::NativeView RenderWidgetHostViewViews::GetInnerNativeView() const {
    430   // TODO(sad): Ideally this function should be equivalent to GetNativeView, and
    431   // WidgetGtk-specific function call should not be necessary.
    432   const views::WidgetGtk* widget =
    433       static_cast<const views::WidgetGtk*>(GetWidget());
    434   return widget ? widget->window_contents() : NULL;
    435 }
    436 
    437 std::string RenderWidgetHostViewViews::GetClassName() const {
    438   return kViewClassName;
    439 }
    440 
    441 gfx::NativeCursor RenderWidgetHostViewViews::GetCursorForPoint(
    442     ui::EventType type, const gfx::Point& point) {
    443   return native_cursor_;
    444 }
    445 
    446 bool RenderWidgetHostViewViews::OnMousePressed(const views::MouseEvent& event) {
    447   if (!host_)
    448     return false;
    449 
    450   RequestFocus();
    451 
    452   // Confirm existing composition text on mouse click events, to make sure
    453   // the input caret won't be moved with an ongoing composition text.
    454   FinishImeCompositionSession();
    455 
    456   // TODO(anicolao): validate event generation.
    457   WebKit::WebMouseEvent e = WebMouseEventFromViewsEvent(event);
    458 
    459   // TODO(anicolao): deal with double clicks
    460   e.type = WebKit::WebInputEvent::MouseDown;
    461   e.clickCount = 1;
    462 
    463   host_->ForwardMouseEvent(e);
    464   return true;
    465 }
    466 
    467 bool RenderWidgetHostViewViews::OnMouseDragged(const views::MouseEvent& event) {
    468   OnMouseMoved(event);
    469   return true;
    470 }
    471 
    472 void RenderWidgetHostViewViews::OnMouseReleased(
    473     const views::MouseEvent& event) {
    474   if (!host_)
    475     return;
    476 
    477   WebKit::WebMouseEvent e = WebMouseEventFromViewsEvent(event);
    478   e.type = WebKit::WebInputEvent::MouseUp;
    479   e.clickCount = 1;
    480   host_->ForwardMouseEvent(e);
    481 }
    482 
    483 void RenderWidgetHostViewViews::OnMouseMoved(const views::MouseEvent& event) {
    484   if (!host_)
    485     return;
    486 
    487   WebKit::WebMouseEvent e = WebMouseEventFromViewsEvent(event);
    488   e.type = WebKit::WebInputEvent::MouseMove;
    489   host_->ForwardMouseEvent(e);
    490 }
    491 
    492 void RenderWidgetHostViewViews::OnMouseEntered(const views::MouseEvent& event) {
    493   // Already generated synthetically by webkit.
    494 }
    495 
    496 void RenderWidgetHostViewViews::OnMouseExited(const views::MouseEvent& event) {
    497   // Already generated synthetically by webkit.
    498 }
    499 
    500 views::View::TouchStatus RenderWidgetHostViewViews::OnTouchEvent(
    501     const views::TouchEvent& event) {
    502   if (!host_)
    503     return TOUCH_STATUS_UNKNOWN;
    504 
    505   // Update the list of touch points first.
    506   WebKit::WebTouchPoint* point = NULL;
    507   TouchStatus status = TOUCH_STATUS_UNKNOWN;
    508 
    509   switch (event.type()) {
    510     case ui::ET_TOUCH_PRESSED:
    511       // Add a new touch point.
    512       if (touch_event_.touchPointsLength <
    513           WebTouchEvent::touchPointsLengthCap) {
    514         point = &touch_event_.touchPoints[touch_event_.touchPointsLength++];
    515         point->id = event.identity();
    516 
    517         if (touch_event_.touchPointsLength == 1) {
    518           // A new touch sequence has started.
    519           status = TOUCH_STATUS_START;
    520 
    521           // We also want the focus.
    522           RequestFocus();
    523 
    524           // Confirm existing composition text on touch press events, to make
    525           // sure the input caret won't be moved with an ongoing composition
    526           // text.
    527           FinishImeCompositionSession();
    528         }
    529       }
    530       break;
    531     case ui::ET_TOUCH_RELEASED:
    532     case ui::ET_TOUCH_CANCELLED:
    533     case ui::ET_TOUCH_MOVED: {
    534       // The touch point should have been added to the event from an earlier
    535       // _PRESSED event. So find that.
    536       // At the moment, only a maximum of 4 touch-points are allowed. So a
    537       // simple loop should be sufficient.
    538       for (int i = 0; i < touch_event_.touchPointsLength; ++i) {
    539         point = touch_event_.touchPoints + i;
    540         if (point->id == event.identity()) {
    541           break;
    542         }
    543         point = NULL;
    544       }
    545       break;
    546     }
    547     default:
    548       DLOG(WARNING) << "Unknown touch event " << event.type();
    549       break;
    550   }
    551 
    552   if (!point)
    553     return TOUCH_STATUS_UNKNOWN;
    554 
    555   if (status != TOUCH_STATUS_START)
    556     status = TOUCH_STATUS_CONTINUE;
    557 
    558   // Update the location and state of the point.
    559   point->state = TouchPointStateFromEvent(&event);
    560   if (point->state == WebKit::WebTouchPoint::StateMoved) {
    561     // It is possible for badly written touch drivers to emit Move events even
    562     // when the touch location hasn't changed. In such cases, consume the event
    563     // and pretend nothing happened.
    564     if (point->position.x == event.x() && point->position.y == event.y()) {
    565       return status;
    566     }
    567   }
    568   UpdateTouchPointPosition(&event, GetMirroredPosition(), point);
    569 
    570   // Mark the rest of the points as stationary.
    571   for (int i = 0; i < touch_event_.touchPointsLength; ++i) {
    572     WebKit::WebTouchPoint* iter = touch_event_.touchPoints + i;
    573     if (iter != point) {
    574       iter->state = WebKit::WebTouchPoint::StateStationary;
    575     }
    576   }
    577 
    578   // Update the type of the touch event.
    579   touch_event_.type = TouchEventTypeFromEvent(&event);
    580   touch_event_.timeStampSeconds = base::Time::Now().ToDoubleT();
    581 
    582   // The event and all the touches have been updated. Dispatch.
    583   host_->ForwardTouchEvent(touch_event_);
    584 
    585   // If the touch was released, then remove it from the list of touch points.
    586   if (event.type() == ui::ET_TOUCH_RELEASED) {
    587     --touch_event_.touchPointsLength;
    588     for (int i = point - touch_event_.touchPoints;
    589          i < touch_event_.touchPointsLength;
    590          ++i) {
    591       touch_event_.touchPoints[i] = touch_event_.touchPoints[i + 1];
    592     }
    593     if (touch_event_.touchPointsLength == 0)
    594       status = TOUCH_STATUS_END;
    595   } else if (event.type() == ui::ET_TOUCH_CANCELLED) {
    596     status = TOUCH_STATUS_CANCEL;
    597   }
    598 
    599   return status;
    600 }
    601 
    602 bool RenderWidgetHostViewViews::OnKeyPressed(const views::KeyEvent& event) {
    603   // TODO(suzhe): Support editor key bindings.
    604   if (!host_)
    605     return false;
    606   host_->ForwardKeyboardEvent(NativeWebKeyboardEvent(event));
    607   return true;
    608 }
    609 
    610 bool RenderWidgetHostViewViews::OnKeyReleased(const views::KeyEvent& event) {
    611   if (!host_)
    612     return false;
    613   host_->ForwardKeyboardEvent(NativeWebKeyboardEvent(event));
    614   return true;
    615 }
    616 
    617 bool RenderWidgetHostViewViews::OnMouseWheel(
    618     const views::MouseWheelEvent& event) {
    619   if (!host_)
    620     return false;
    621 
    622   WebMouseWheelEvent wmwe;
    623   InitializeWebMouseEventFromViewsEvent(event, GetMirroredPosition(), &wmwe);
    624 
    625   wmwe.type = WebKit::WebInputEvent::MouseWheel;
    626   wmwe.button = WebKit::WebMouseEvent::ButtonNone;
    627 
    628   // TODO(sadrul): How do we determine if it's a horizontal scroll?
    629   wmwe.deltaY = event.offset();
    630   wmwe.wheelTicksY = wmwe.deltaY > 0 ? 1 : -1;
    631 
    632   host_->ForwardWheelEvent(wmwe);
    633   return true;
    634 }
    635 
    636 views::TextInputClient* RenderWidgetHostViewViews::GetTextInputClient() {
    637   return this;
    638 }
    639 
    640 // TextInputClient implementation ---------------------------------------------
    641 void RenderWidgetHostViewViews::SetCompositionText(
    642     const ui::CompositionText& composition) {
    643   if (!host_)
    644     return;
    645 
    646   // ui::CompositionUnderline should be identical to
    647   // WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely.
    648   COMPILE_ASSERT(sizeof(ui::CompositionUnderline) ==
    649                  sizeof(WebKit::WebCompositionUnderline),
    650                  ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff);
    651 
    652   // TODO(suzhe): convert both renderer_host and renderer to use
    653   // ui::CompositionText.
    654   const std::vector<WebKit::WebCompositionUnderline>& underlines =
    655       reinterpret_cast<const std::vector<WebKit::WebCompositionUnderline>&>(
    656           composition.underlines);
    657 
    658   // TODO(suzhe): due to a bug of webkit, we can't use selection range with
    659   // composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788
    660   host_->ImeSetComposition(composition.text, underlines,
    661                            composition.selection.end(),
    662                            composition.selection.end());
    663 
    664   has_composition_text_ = !composition.text.empty();
    665 }
    666 
    667 void RenderWidgetHostViewViews::ConfirmCompositionText() {
    668   if (host_ && has_composition_text_)
    669     host_->ImeConfirmComposition();
    670   has_composition_text_ = false;
    671 }
    672 
    673 void RenderWidgetHostViewViews::ClearCompositionText() {
    674   if (host_ && has_composition_text_)
    675     host_->ImeCancelComposition();
    676   has_composition_text_ = false;
    677 }
    678 
    679 void RenderWidgetHostViewViews::InsertText(const string16& text) {
    680   DCHECK(text_input_type_ != ui::TEXT_INPUT_TYPE_NONE);
    681   if (host_)
    682     host_->ImeConfirmComposition(text);
    683   has_composition_text_ = false;
    684 }
    685 
    686 void RenderWidgetHostViewViews::InsertChar(char16 ch, int flags) {
    687   if (host_) {
    688     NativeWebKeyboardEvent::FromViewsEvent from_views_event;
    689     NativeWebKeyboardEvent wke(ch, flags, base::Time::Now().ToDoubleT(),
    690                                from_views_event);
    691     host_->ForwardKeyboardEvent(wke);
    692   }
    693 }
    694 
    695 ui::TextInputType RenderWidgetHostViewViews::GetTextInputType() {
    696   return text_input_type_;
    697 }
    698 
    699 gfx::Rect RenderWidgetHostViewViews::GetCaretBounds() {
    700   return caret_bounds_;
    701 }
    702 
    703 bool RenderWidgetHostViewViews::HasCompositionText() {
    704   return has_composition_text_;
    705 }
    706 
    707 bool RenderWidgetHostViewViews::GetTextRange(ui::Range* range) {
    708   // TODO(suzhe): implement this method when fixing http://crbug.com/55130.
    709   NOTIMPLEMENTED();
    710   return false;
    711 }
    712 
    713 bool RenderWidgetHostViewViews::GetCompositionTextRange(ui::Range* range) {
    714   // TODO(suzhe): implement this method when fixing http://crbug.com/55130.
    715   NOTIMPLEMENTED();
    716   return false;
    717 }
    718 
    719 bool RenderWidgetHostViewViews::GetSelectionRange(ui::Range* range) {
    720   // TODO(suzhe): implement this method when fixing http://crbug.com/55130.
    721   NOTIMPLEMENTED();
    722   return false;
    723 }
    724 
    725 bool RenderWidgetHostViewViews::SetSelectionRange(const ui::Range& range) {
    726   // TODO(suzhe): implement this method when fixing http://crbug.com/55130.
    727   NOTIMPLEMENTED();
    728   return false;
    729 }
    730 
    731 bool RenderWidgetHostViewViews::DeleteRange(const ui::Range& range) {
    732   // TODO(suzhe): implement this method when fixing http://crbug.com/55130.
    733   NOTIMPLEMENTED();
    734   return false;
    735 }
    736 
    737 bool RenderWidgetHostViewViews::GetTextFromRange(
    738     const ui::Range& range,
    739     const base::Callback<void(const string16&)>& callback) {
    740   // TODO(suzhe): implement this method when fixing http://crbug.com/55130.
    741   NOTIMPLEMENTED();
    742   return false;
    743 }
    744 
    745 void RenderWidgetHostViewViews::OnInputMethodChanged() {
    746   if (!host_)
    747     return;
    748 
    749   DCHECK(GetInputMethod());
    750   host_->SetInputMethodActive(GetInputMethod()->IsActive());
    751 
    752   // TODO(suzhe): implement the newly added locale property of HTML DOM
    753   // TextEvent.
    754 }
    755 
    756 bool RenderWidgetHostViewViews::ChangeTextDirectionAndLayoutAlignment(
    757       base::i18n::TextDirection direction) {
    758   if (!host_)
    759     return false;
    760   host_->UpdateTextDirection(
    761       direction == base::i18n::RIGHT_TO_LEFT ?
    762       WebKit::WebTextDirectionRightToLeft :
    763       WebKit::WebTextDirectionLeftToRight);
    764   host_->NotifyTextDirection();
    765   return true;
    766 }
    767 
    768 views::View* RenderWidgetHostViewViews::GetOwnerViewOfTextInputClient() {
    769   return this;
    770 }
    771 
    772 void RenderWidgetHostViewViews::OnPaint(gfx::Canvas* canvas) {
    773   if (is_hidden_ || !host_)
    774     return;
    775 
    776   // Paint a "hole" in the canvas so that the render of the web page is on
    777   // top of whatever else has already been painted in the views hierarchy.
    778   // Later views might still get to paint on top.
    779   canvas->FillRectInt(SK_ColorBLACK, 0, 0,
    780                       bounds().width(), bounds().height(),
    781                       SkXfermode::kClear_Mode);
    782 
    783   // Don't do any painting if the GPU process is rendering directly
    784   // into the View.
    785   if (host_->is_accelerated_compositing_active())
    786     return;
    787 
    788   GdkWindow* window = GetInnerNativeView()->window;
    789   DCHECK(!about_to_validate_and_paint_);
    790 
    791   // TODO(anicolao): get the damage somehow
    792   // invalid_rect_ = damage_rect;
    793   invalid_rect_ = bounds();
    794   gfx::Point origin;
    795   ConvertPointToWidget(this, &origin);
    796 
    797   about_to_validate_and_paint_ = true;
    798   BackingStore* backing_store = host_->GetBackingStore(true);
    799   // Calling GetBackingStore maybe have changed |invalid_rect_|...
    800   about_to_validate_and_paint_ = false;
    801 
    802   gfx::Rect paint_rect = gfx::Rect(0, 0, kMaxWindowWidth, kMaxWindowHeight);
    803   paint_rect = paint_rect.Intersect(invalid_rect_);
    804 
    805   if (backing_store) {
    806     // Only render the widget if it is attached to a window; there's a short
    807     // period where this object isn't attached to a window but hasn't been
    808     // Destroy()ed yet and it receives paint messages...
    809     if (window) {
    810       if (!visually_deemphasized_) {
    811         // In the common case, use XCopyArea. We don't draw more than once, so
    812         // we don't need to double buffer.
    813 
    814         if (UsingBackingStoreSkia()) {
    815           static_cast<BackingStoreSkia*>(backing_store)->SkiaShowRect(
    816               gfx::Point(paint_rect.x(), paint_rect.y()), canvas);
    817         } else {
    818           static_cast<BackingStoreX*>(backing_store)->XShowRect(origin,
    819               paint_rect, ui::GetX11WindowFromGdkWindow(window));
    820         }
    821       } else if (!UsingBackingStoreSkia()) {
    822         // If the grey blend is showing, we make two drawing calls. Use double
    823         // buffering to prevent flicker. Use CairoShowRect because XShowRect
    824         // shortcuts GDK's double buffering.
    825         GdkRectangle rect = { paint_rect.x(), paint_rect.y(),
    826                               paint_rect.width(), paint_rect.height() };
    827         gdk_window_begin_paint_rect(window, &rect);
    828 
    829         static_cast<BackingStoreX*>(backing_store)->CairoShowRect(
    830             paint_rect, GDK_DRAWABLE(window));
    831 
    832         cairo_t* cr = gdk_cairo_create(window);
    833         gdk_cairo_rectangle(cr, &rect);
    834         cairo_set_source_rgba(cr, 0, 0, 0, 0.7);
    835         cairo_fill(cr);
    836         cairo_destroy(cr);
    837 
    838         gdk_window_end_paint(window);
    839       } else {
    840         // TODO(sad)
    841         NOTIMPLEMENTED();
    842       }
    843     }
    844     if (!whiteout_start_time_.is_null()) {
    845       base::TimeDelta whiteout_duration = base::TimeTicks::Now() -
    846           whiteout_start_time_;
    847       UMA_HISTOGRAM_TIMES("MPArch.RWHH_WhiteoutDuration", whiteout_duration);
    848 
    849       // Reset the start time to 0 so that we start recording again the next
    850       // time the backing store is NULL...
    851       whiteout_start_time_ = base::TimeTicks();
    852     }
    853     if (!tab_switch_paint_time_.is_null()) {
    854       base::TimeDelta tab_switch_paint_duration = base::TimeTicks::Now() -
    855           tab_switch_paint_time_;
    856       UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration",
    857           tab_switch_paint_duration);
    858       // Reset tab_switch_paint_time_ to 0 so future tab selections are
    859       // recorded.
    860       tab_switch_paint_time_ = base::TimeTicks();
    861     }
    862   } else {
    863     if (whiteout_start_time_.is_null())
    864       whiteout_start_time_ = base::TimeTicks::Now();
    865   }
    866 }
    867 
    868 void RenderWidgetHostViewViews::Focus() {
    869   RequestFocus();
    870 }
    871 
    872 void RenderWidgetHostViewViews::Blur() {
    873   // TODO(estade): We should be clearing native focus as well, but I know of no
    874   // way to do that without focusing another widget.
    875   if (host_)
    876     host_->Blur();
    877 }
    878 
    879 void RenderWidgetHostViewViews::OnFocus() {
    880   if (!host_)
    881     return;
    882 
    883   DCHECK(GetInputMethod());
    884   View::OnFocus();
    885   ShowCurrentCursor();
    886   host_->GotFocus();
    887   host_->SetInputMethodActive(GetInputMethod()->IsActive());
    888 }
    889 
    890 void RenderWidgetHostViewViews::OnBlur() {
    891   if (!host_)
    892     return;
    893   View::OnBlur();
    894   // If we are showing a context menu, maintain the illusion that webkit has
    895   // focus.
    896   if (!is_showing_context_menu_ && !is_hidden_)
    897     host_->Blur();
    898   host_->SetInputMethodActive(false);
    899 }
    900 
    901 bool RenderWidgetHostViewViews::NeedsInputGrab() {
    902   return popup_type_ == WebKit::WebPopupTypeSelect;
    903 }
    904 
    905 bool RenderWidgetHostViewViews::IsPopup() {
    906   return popup_type_ != WebKit::WebPopupTypeNone;
    907 }
    908 
    909 void RenderWidgetHostViewViews::ShowCurrentCursor() {
    910   // The widget may not have a window. If that's the case, abort mission. This
    911   // is the same issue as that explained above in Paint().
    912   if (!GetInnerNativeView() || !GetInnerNativeView()->window)
    913     return;
    914 
    915   native_cursor_ = current_cursor_.GetNativeCursor();
    916 }
    917 
    918 WebKit::WebMouseEvent RenderWidgetHostViewViews::WebMouseEventFromViewsEvent(
    919     const views::MouseEvent& event) {
    920   WebKit::WebMouseEvent wmevent;
    921   InitializeWebMouseEventFromViewsEvent(event, GetMirroredPosition(), &wmevent);
    922 
    923   // Setting |wmevent.button| is not necessary for -move events, but it is
    924   // necessary for -clicks and -drags.
    925   if (event.IsMiddleMouseButton()) {
    926     wmevent.modifiers |= WebKit::WebInputEvent::MiddleButtonDown;
    927     wmevent.button = WebKit::WebMouseEvent::ButtonMiddle;
    928   }
    929   if (event.IsRightMouseButton()) {
    930     wmevent.modifiers |= WebKit::WebInputEvent::RightButtonDown;
    931     wmevent.button = WebKit::WebMouseEvent::ButtonRight;
    932   }
    933   if (event.IsLeftMouseButton()) {
    934     wmevent.modifiers |= WebKit::WebInputEvent::LeftButtonDown;
    935     wmevent.button = WebKit::WebMouseEvent::ButtonLeft;
    936   }
    937 
    938   return wmevent;
    939 }
    940 
    941 void RenderWidgetHostViewViews::FinishImeCompositionSession() {
    942   if (!has_composition_text_)
    943     return;
    944   if (host_)
    945     host_->ImeConfirmComposition();
    946   DCHECK(GetInputMethod());
    947   GetInputMethod()->CancelComposition(this);
    948   has_composition_text_ = false;
    949 }
    950 
    951 // static
    952 RenderWidgetHostView*
    953     RenderWidgetHostView::GetRenderWidgetHostViewFromNativeView(
    954         gfx::NativeView widget) {
    955   gpointer user_data = g_object_get_data(G_OBJECT(widget),
    956                                          kRenderWidgetHostViewKey);
    957   return reinterpret_cast<RenderWidgetHostView*>(user_data);
    958 }
    959