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