Home | History | Annotate | Download | only in renderer_host
      1 // Copyright (c) 2012 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 "content/browser/renderer_host/render_widget_host_view_base.h"
      6 
      7 #include "base/logging.h"
      8 #include "content/browser/accessibility/browser_accessibility_manager.h"
      9 #include "content/browser/gpu/gpu_data_manager_impl.h"
     10 #include "content/browser/renderer_host/input/synthetic_gesture_target_base.h"
     11 #include "content/browser/renderer_host/render_process_host_impl.h"
     12 #include "content/browser/renderer_host/render_widget_host_impl.h"
     13 #include "content/port/browser/render_widget_host_view_frame_subscriber.h"
     14 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
     15 #include "ui/gfx/display.h"
     16 #include "ui/gfx/screen.h"
     17 #include "ui/gfx/size_conversions.h"
     18 #include "ui/gfx/size_f.h"
     19 
     20 #if defined(OS_WIN)
     21 #include "base/command_line.h"
     22 #include "base/message_loop/message_loop.h"
     23 #include "base/win/wrapped_window_proc.h"
     24 #include "content/browser/plugin_process_host.h"
     25 #include "content/browser/plugin_service_impl.h"
     26 #include "content/common/plugin_constants_win.h"
     27 #include "content/common/webplugin_geometry.h"
     28 #include "content/public/browser/browser_thread.h"
     29 #include "content/public/browser/child_process_data.h"
     30 #include "content/public/common/content_switches.h"
     31 #include "ui/gfx/gdi_util.h"
     32 #include "ui/gfx/win/dpi.h"
     33 #include "ui/gfx/win/hwnd_util.h"
     34 #endif
     35 
     36 #if defined(TOOLKIT_GTK)
     37 #include <gdk/gdkx.h>
     38 #include <gtk/gtk.h>
     39 
     40 #include "content/browser/renderer_host/gtk_window_utils.h"
     41 #endif
     42 
     43 namespace content {
     44 
     45 // static
     46 RenderWidgetHostViewPort* RenderWidgetHostViewPort::FromRWHV(
     47     RenderWidgetHostView* rwhv) {
     48   return static_cast<RenderWidgetHostViewPort*>(rwhv);
     49 }
     50 
     51 // static
     52 RenderWidgetHostViewPort* RenderWidgetHostViewPort::CreateViewForWidget(
     53     RenderWidgetHost* widget) {
     54   return FromRWHV(RenderWidgetHostView::CreateViewForWidget(widget));
     55 }
     56 
     57 #if defined(OS_WIN)
     58 
     59 namespace {
     60 
     61 // |window| is the plugin HWND, created and destroyed in the plugin process.
     62 // |parent| is the parent HWND, created and destroyed on the browser UI thread.
     63 void NotifyPluginProcessHostHelper(HWND window, HWND parent, int tries) {
     64   // How long to wait between each try.
     65   static const int kTryDelayMs = 200;
     66 
     67   DWORD plugin_process_id;
     68   bool found_starting_plugin_process = false;
     69   GetWindowThreadProcessId(window, &plugin_process_id);
     70   for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
     71     if (!iter.GetData().handle) {
     72       found_starting_plugin_process = true;
     73       continue;
     74     }
     75     if (base::GetProcId(iter.GetData().handle) == plugin_process_id) {
     76       iter->AddWindow(parent);
     77       return;
     78     }
     79   }
     80 
     81   if (found_starting_plugin_process) {
     82     // A plugin process has started but we don't have its handle yet.  Since
     83     // it's most likely the one for this plugin, try a few more times after a
     84     // delay.
     85     if (tries > 0) {
     86       base::MessageLoop::current()->PostDelayedTask(
     87           FROM_HERE,
     88           base::Bind(&NotifyPluginProcessHostHelper, window, parent, tries - 1),
     89           base::TimeDelta::FromMilliseconds(kTryDelayMs));
     90       return;
     91     }
     92   }
     93 
     94   // The plugin process might have died in the time to execute the task, don't
     95   // leak the HWND.
     96   PostMessage(parent, WM_CLOSE, 0, 0);
     97 }
     98 
     99 // The plugin wrapper window which lives in the browser process has this proc
    100 // as its window procedure. We only handle the WM_PARENTNOTIFY message sent by
    101 // windowed plugins for mouse input. This is forwarded off to the wrappers
    102 // parent which is typically the RVH window which turns on user gesture.
    103 LRESULT CALLBACK PluginWrapperWindowProc(HWND window, unsigned int message,
    104                                          WPARAM wparam, LPARAM lparam) {
    105   if (message == WM_PARENTNOTIFY) {
    106     switch (LOWORD(wparam)) {
    107       case WM_LBUTTONDOWN:
    108       case WM_RBUTTONDOWN:
    109       case WM_MBUTTONDOWN:
    110         ::SendMessage(GetParent(window), message, wparam, lparam);
    111         return 0;
    112       default:
    113         break;
    114     }
    115   }
    116   return ::DefWindowProc(window, message, wparam, lparam);
    117 }
    118 
    119 bool IsPluginWrapperWindow(HWND window) {
    120   return gfx::GetClassNameW(window) ==
    121       base::string16(kWrapperNativeWindowClassName);
    122 }
    123 
    124 // Create an intermediate window between the given HWND and its parent.
    125 HWND ReparentWindow(HWND window, HWND parent) {
    126   static ATOM atom = 0;
    127   static HMODULE instance = NULL;
    128   if (!atom) {
    129     WNDCLASSEX window_class;
    130     base::win::InitializeWindowClass(
    131         kWrapperNativeWindowClassName,
    132         &base::win::WrappedWindowProc<PluginWrapperWindowProc>,
    133         CS_DBLCLKS,
    134         0,
    135         0,
    136         NULL,
    137         // xxx reinterpret_cast<HBRUSH>(COLOR_WINDOW+1),
    138         reinterpret_cast<HBRUSH>(COLOR_GRAYTEXT+1),
    139         NULL,
    140         NULL,
    141         NULL,
    142         &window_class);
    143     instance = window_class.hInstance;
    144     atom = RegisterClassEx(&window_class);
    145   }
    146   DCHECK(atom);
    147 
    148   HWND new_parent = CreateWindowEx(
    149       WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
    150       MAKEINTATOM(atom), 0,
    151       WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
    152       0, 0, 0, 0, parent, 0, instance, 0);
    153   gfx::CheckWindowCreated(new_parent);
    154   ::SetParent(window, new_parent);
    155   // How many times we try to find a PluginProcessHost whose process matches
    156   // the HWND.
    157   static const int kMaxTries = 5;
    158   BrowserThread::PostTask(
    159       BrowserThread::IO,
    160       FROM_HERE,
    161       base::Bind(&NotifyPluginProcessHostHelper, window, new_parent,
    162                  kMaxTries));
    163   return new_parent;
    164 }
    165 
    166 BOOL CALLBACK PaintEnumChildProc(HWND hwnd, LPARAM lparam) {
    167   if (!PluginServiceImpl::GetInstance()->IsPluginWindow(hwnd))
    168     return TRUE;
    169 
    170   gfx::Rect* rect = reinterpret_cast<gfx::Rect*>(lparam);
    171   gfx::Rect rect_in_pixels = gfx::win::DIPToScreenRect(*rect);
    172   static UINT msg = RegisterWindowMessage(kPaintMessageName);
    173   WPARAM wparam = MAKEWPARAM(rect_in_pixels.x(), rect_in_pixels.y());
    174   lparam = MAKELPARAM(rect_in_pixels.width(), rect_in_pixels.height());
    175 
    176   // SendMessage gets the message across much quicker than PostMessage, since it
    177   // doesn't get queued.  When the plugin thread calls PeekMessage or other
    178   // Win32 APIs, sent messages are dispatched automatically.
    179   SendNotifyMessage(hwnd, msg, wparam, lparam);
    180 
    181   return TRUE;
    182 }
    183 
    184 // Windows callback for OnDestroy to detach the plugin windows.
    185 BOOL CALLBACK DetachPluginWindowsCallbackInternal(HWND window, LPARAM param) {
    186   RenderWidgetHostViewBase::DetachPluginWindowsCallback(window);
    187   return TRUE;
    188 }
    189 
    190 }  // namespace
    191 
    192 // static
    193 void RenderWidgetHostViewBase::DetachPluginWindowsCallback(HWND window) {
    194   if (PluginServiceImpl::GetInstance()->IsPluginWindow(window) &&
    195       !IsHungAppWindow(window)) {
    196     ::ShowWindow(window, SW_HIDE);
    197     SetParent(window, NULL);
    198   }
    199 }
    200 
    201 // static
    202 void RenderWidgetHostViewBase::MovePluginWindowsHelper(
    203     HWND parent,
    204     const std::vector<WebPluginGeometry>& moves) {
    205   if (moves.empty())
    206     return;
    207 
    208   bool oop_plugins =
    209     !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) &&
    210     !CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessPlugins);
    211 
    212   HDWP defer_window_pos_info =
    213       ::BeginDeferWindowPos(static_cast<int>(moves.size()));
    214 
    215   if (!defer_window_pos_info) {
    216     NOTREACHED();
    217     return;
    218   }
    219 
    220 #if defined(USE_AURA)
    221   std::vector<RECT> invalidate_rects;
    222 #endif
    223 
    224   for (size_t i = 0; i < moves.size(); ++i) {
    225     unsigned long flags = 0;
    226     const WebPluginGeometry& move = moves[i];
    227     HWND window = move.window;
    228 
    229     // As the plugin parent window which lives on the browser UI thread is
    230     // destroyed asynchronously, it is possible that we have a stale window
    231     // sent in by the renderer for moving around.
    232     // Note: get the parent before checking if the window is valid, to avoid a
    233     // race condition where the window is destroyed after the check but before
    234     // the GetParent call.
    235     HWND cur_parent = ::GetParent(window);
    236     if (!::IsWindow(window))
    237       continue;
    238 
    239     if (!PluginServiceImpl::GetInstance()->IsPluginWindow(window)) {
    240       // The renderer should only be trying to move plugin windows. However,
    241       // this may happen as a result of a race condition (i.e. even after the
    242       // check right above), so we ignore it.
    243       continue;
    244     }
    245 
    246     if (oop_plugins) {
    247       if (cur_parent == GetDesktopWindow()) {
    248         // The plugin window hasn't been parented yet, add an intermediate
    249         // window that lives on this thread to speed up scrolling. Note this
    250         // only works with out of process plugins since we depend on
    251         // PluginProcessHost to destroy the intermediate HWNDs.
    252         cur_parent = ReparentWindow(window, parent);
    253         ::ShowWindow(window, SW_SHOW);  // Window was created hidden.
    254       } else if (!IsPluginWrapperWindow(cur_parent)) {
    255         continue;  // Race if plugin process is shutting down.
    256       }
    257 
    258       // We move the intermediate parent window which doesn't result in cross-
    259       // process synchronous Windows messages.
    260       window = cur_parent;
    261     } else {
    262       if (cur_parent == GetDesktopWindow())
    263         SetParent(window, parent);
    264     }
    265 
    266     if (move.visible)
    267       flags |= SWP_SHOWWINDOW;
    268     else
    269       flags |= SWP_HIDEWINDOW;
    270 
    271 #if defined(USE_AURA)
    272     if (GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
    273       // Without this flag, Windows repaints the parent area uncovered by this
    274       // move. However when software compositing is used the clipping region is
    275       // ignored. Since in Aura the browser chrome could be under the plugin, if
    276       // if Windows tries to paint it synchronously inside EndDeferWindowsPos
    277       // then it won't have the data and it will flash white. So instead we
    278       // manually redraw the plugin.
    279       // Why not do this for native Windows? Not sure if there are any
    280       // performance issues with this.
    281       flags |= SWP_NOREDRAW;
    282     }
    283 #endif
    284 
    285     if (move.rects_valid) {
    286       gfx::Rect clip_rect_in_pixel = gfx::win::DIPToScreenRect(move.clip_rect);
    287       HRGN hrgn = ::CreateRectRgn(clip_rect_in_pixel.x(),
    288                                   clip_rect_in_pixel.y(),
    289                                   clip_rect_in_pixel.right(),
    290                                   clip_rect_in_pixel.bottom());
    291       gfx::SubtractRectanglesFromRegion(hrgn, move.cutout_rects);
    292 
    293       // Note: System will own the hrgn after we call SetWindowRgn,
    294       // so we don't need to call DeleteObject(hrgn)
    295       ::SetWindowRgn(window, hrgn, !move.clip_rect.IsEmpty());
    296 
    297 #if defined(USE_AURA)
    298       // When using the software compositor, if the clipping rectangle is empty
    299       // then DeferWindowPos won't redraw the newly uncovered area under the
    300       // plugin.
    301       if (clip_rect_in_pixel.IsEmpty() &&
    302           !GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
    303         RECT r;
    304         GetClientRect(window, &r);
    305         MapWindowPoints(window, parent, reinterpret_cast<POINT*>(&r), 2);
    306         invalidate_rects.push_back(r);
    307       }
    308 #endif
    309     } else {
    310       flags |= SWP_NOMOVE;
    311       flags |= SWP_NOSIZE;
    312     }
    313 
    314     gfx::Rect window_rect_in_pixel =
    315         gfx::win::DIPToScreenRect(move.window_rect);
    316     defer_window_pos_info = ::DeferWindowPos(defer_window_pos_info,
    317                                              window, NULL,
    318                                              window_rect_in_pixel.x(),
    319                                              window_rect_in_pixel.y(),
    320                                              window_rect_in_pixel.width(),
    321                                              window_rect_in_pixel.height(),
    322                                              flags);
    323 
    324     if (!defer_window_pos_info) {
    325       DCHECK(false) << "DeferWindowPos failed, so all plugin moves ignored.";
    326       return;
    327     }
    328   }
    329 
    330   ::EndDeferWindowPos(defer_window_pos_info);
    331 
    332 #if defined(USE_AURA)
    333   if (GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
    334     for (size_t i = 0; i < moves.size(); ++i) {
    335       const WebPluginGeometry& move = moves[i];
    336       RECT r;
    337       GetWindowRect(move.window, &r);
    338       gfx::Rect gr(r);
    339       PaintEnumChildProc(move.window, reinterpret_cast<LPARAM>(&gr));
    340     }
    341   } else {
    342       for (size_t i = 0; i < invalidate_rects.size(); ++i) {
    343       ::RedrawWindow(
    344           parent, &invalidate_rects[i], NULL,
    345           // These flags are from WebPluginDelegateImpl::NativeWndProc.
    346           RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_FRAME | RDW_UPDATENOW);
    347     }
    348   }
    349 #endif
    350 }
    351 
    352 // static
    353 void RenderWidgetHostViewBase::PaintPluginWindowsHelper(
    354     HWND parent, const gfx::Rect& damaged_screen_rect) {
    355   LPARAM lparam = reinterpret_cast<LPARAM>(&damaged_screen_rect);
    356   EnumChildWindows(parent, PaintEnumChildProc, lparam);
    357 }
    358 
    359 // static
    360 void RenderWidgetHostViewBase::DetachPluginsHelper(HWND parent) {
    361   // When a tab is closed all its child plugin windows are destroyed
    362   // automatically. This happens before plugins get any notification that its
    363   // instances are tearing down.
    364   //
    365   // Plugins like Quicktime assume that their windows will remain valid as long
    366   // as they have plugin instances active. Quicktime crashes in this case
    367   // because its windowing code cleans up an internal data structure that the
    368   // handler for NPP_DestroyStream relies on.
    369   //
    370   // The fix is to detach plugin windows from web contents when it is going
    371   // away. This will prevent the plugin windows from getting destroyed
    372   // automatically. The detached plugin windows will get cleaned up in proper
    373   // sequence as part of the usual cleanup when the plugin instance goes away.
    374   EnumChildWindows(parent, DetachPluginWindowsCallbackInternal, NULL);
    375 }
    376 
    377 #endif  // OS_WIN
    378 
    379 namespace {
    380 
    381 // How many microseconds apart input events should be flushed.
    382 const int kFlushInputRateInUs = 16666;
    383 
    384 }
    385 
    386 RenderWidgetHostViewBase::RenderWidgetHostViewBase()
    387     : popup_type_(blink::WebPopupTypeNone),
    388       mouse_locked_(false),
    389       showing_context_menu_(false),
    390       selection_text_offset_(0),
    391       selection_range_(gfx::Range::InvalidRange()),
    392       current_device_scale_factor_(0),
    393       renderer_frame_number_(0) {
    394 }
    395 
    396 RenderWidgetHostViewBase::~RenderWidgetHostViewBase() {
    397   DCHECK(!mouse_locked_);
    398 }
    399 
    400 bool RenderWidgetHostViewBase::OnMessageReceived(const IPC::Message& msg){
    401   return false;
    402 }
    403 
    404 void RenderWidgetHostViewBase::SetBackground(const SkBitmap& background) {
    405   background_ = background;
    406 }
    407 
    408 const SkBitmap& RenderWidgetHostViewBase::GetBackground() {
    409   return background_;
    410 }
    411 
    412 gfx::Size RenderWidgetHostViewBase::GetPhysicalBackingSize() const {
    413   gfx::NativeView view = GetNativeView();
    414   gfx::Display display =
    415       gfx::Screen::GetScreenFor(view)->GetDisplayNearestWindow(view);
    416   return gfx::ToCeiledSize(gfx::ScaleSize(GetViewBounds().size(),
    417                                           display.device_scale_factor()));
    418 }
    419 
    420 float RenderWidgetHostViewBase::GetOverdrawBottomHeight() const {
    421   return 0.f;
    422 }
    423 
    424 void RenderWidgetHostViewBase::SelectionChanged(const base::string16& text,
    425                                                 size_t offset,
    426                                                 const gfx::Range& range) {
    427   selection_text_ = text;
    428   selection_text_offset_ = offset;
    429   selection_range_.set_start(range.start());
    430   selection_range_.set_end(range.end());
    431 }
    432 
    433 bool RenderWidgetHostViewBase::IsShowingContextMenu() const {
    434   return showing_context_menu_;
    435 }
    436 
    437 void RenderWidgetHostViewBase::SetShowingContextMenu(bool showing) {
    438   DCHECK_NE(showing_context_menu_, showing);
    439   showing_context_menu_ = showing;
    440 }
    441 
    442 base::string16 RenderWidgetHostViewBase::GetSelectedText() const {
    443   if (!selection_range_.IsValid())
    444     return base::string16();
    445   return selection_text_.substr(
    446       selection_range_.GetMin() - selection_text_offset_,
    447       selection_range_.length());
    448 }
    449 
    450 bool RenderWidgetHostViewBase::IsMouseLocked() {
    451   return mouse_locked_;
    452 }
    453 
    454 void RenderWidgetHostViewBase::UnhandledWheelEvent(
    455     const blink::WebMouseWheelEvent& event) {
    456   // Most implementations don't need to do anything here.
    457 }
    458 
    459 InputEventAckState RenderWidgetHostViewBase::FilterInputEvent(
    460     const blink::WebInputEvent& input_event) {
    461   // By default, input events are simply forwarded to the renderer.
    462   return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
    463 }
    464 
    465 void RenderWidgetHostViewBase::OnDidFlushInput() {
    466   // The notification can safely be ignored by most implementations.
    467 }
    468 
    469 void RenderWidgetHostViewBase::OnSetNeedsFlushInput() {
    470   if (flush_input_timer_.IsRunning())
    471     return;
    472 
    473   flush_input_timer_.Start(
    474       FROM_HERE,
    475       base::TimeDelta::FromMicroseconds(kFlushInputRateInUs),
    476       this,
    477       &RenderWidgetHostViewBase::FlushInput);
    478 }
    479 
    480 void RenderWidgetHostViewBase::GestureEventAck(int gesture_event_type,
    481                                                InputEventAckState ack_result) {}
    482 
    483 void RenderWidgetHostViewBase::SetPopupType(blink::WebPopupType popup_type) {
    484   popup_type_ = popup_type;
    485 }
    486 
    487 blink::WebPopupType RenderWidgetHostViewBase::GetPopupType() {
    488   return popup_type_;
    489 }
    490 
    491 BrowserAccessibilityManager*
    492     RenderWidgetHostViewBase::GetBrowserAccessibilityManager() const {
    493   return browser_accessibility_manager_.get();
    494 }
    495 
    496 void RenderWidgetHostViewBase::SetBrowserAccessibilityManager(
    497     BrowserAccessibilityManager* manager) {
    498   browser_accessibility_manager_.reset(manager);
    499 }
    500 
    501 void RenderWidgetHostViewBase::UpdateScreenInfo(gfx::NativeView view) {
    502   RenderWidgetHostImpl* impl = NULL;
    503   if (GetRenderWidgetHost())
    504     impl = RenderWidgetHostImpl::From(GetRenderWidgetHost());
    505 
    506   if (impl)
    507     impl->SendScreenRects();
    508 
    509   if (HasDisplayPropertyChanged(view) && impl)
    510     impl->NotifyScreenInfoChanged();
    511 }
    512 
    513 bool RenderWidgetHostViewBase::HasDisplayPropertyChanged(gfx::NativeView view) {
    514   gfx::Display display =
    515       gfx::Screen::GetScreenFor(view)->GetDisplayNearestWindow(view);
    516   if (current_display_area_ == display.work_area() &&
    517       current_device_scale_factor_ == display.device_scale_factor()) {
    518     return false;
    519   }
    520   current_display_area_ = display.work_area();
    521   current_device_scale_factor_ = display.device_scale_factor();
    522   return true;
    523 }
    524 
    525 void RenderWidgetHostViewBase::ProcessAckedTouchEvent(
    526     const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) {
    527 }
    528 
    529 scoped_ptr<SyntheticGestureTarget>
    530 RenderWidgetHostViewBase::CreateSyntheticGestureTarget() {
    531   RenderWidgetHostImpl* host =
    532       RenderWidgetHostImpl::From(GetRenderWidgetHost());
    533   return scoped_ptr<SyntheticGestureTarget>(
    534       new SyntheticGestureTargetBase(host));
    535 }
    536 
    537 // Platform implementation should override this method to allow frame
    538 // subscription. Frame subscriber is set to RenderProcessHost, which is
    539 // platform independent. It should be set to the specific presenter on each
    540 // platform.
    541 bool RenderWidgetHostViewBase::CanSubscribeFrame() const {
    542   NOTIMPLEMENTED();
    543   return false;
    544 }
    545 
    546 // Base implementation for this method sets the subscriber to RenderProcessHost,
    547 // which is platform independent. Note: Implementation only support subscribing
    548 // to accelerated composited frames.
    549 void RenderWidgetHostViewBase::BeginFrameSubscription(
    550     scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) {
    551   RenderWidgetHostImpl* impl = NULL;
    552   if (GetRenderWidgetHost())
    553     impl = RenderWidgetHostImpl::From(GetRenderWidgetHost());
    554   if (!impl)
    555     return;
    556   RenderProcessHostImpl* render_process_host =
    557       static_cast<RenderProcessHostImpl*>(impl->GetProcess());
    558   render_process_host->BeginFrameSubscription(impl->GetRoutingID(),
    559                                               subscriber.Pass());
    560 }
    561 
    562 void RenderWidgetHostViewBase::EndFrameSubscription() {
    563   RenderWidgetHostImpl* impl = NULL;
    564   if (GetRenderWidgetHost())
    565     impl = RenderWidgetHostImpl::From(GetRenderWidgetHost());
    566   if (!impl)
    567     return;
    568   RenderProcessHostImpl* render_process_host =
    569       static_cast<RenderProcessHostImpl*>(impl->GetProcess());
    570   render_process_host->EndFrameSubscription(impl->GetRoutingID());
    571 }
    572 
    573 void RenderWidgetHostViewBase::OnOverscrolled(
    574     gfx::Vector2dF accumulated_overscroll,
    575     gfx::Vector2dF current_fling_velocity) {
    576 }
    577 
    578 uint32 RenderWidgetHostViewBase::RendererFrameNumber() {
    579   return renderer_frame_number_;
    580 }
    581 
    582 void RenderWidgetHostViewBase::DidReceiveRendererFrame() {
    583   ++renderer_frame_number_;
    584 }
    585 
    586 void RenderWidgetHostViewBase::FlushInput() {
    587   RenderWidgetHostImpl* impl = NULL;
    588   if (GetRenderWidgetHost())
    589     impl = RenderWidgetHostImpl::From(GetRenderWidgetHost());
    590   if (!impl)
    591     return;
    592   impl->FlushInput();
    593 }
    594 
    595 }  // namespace content
    596