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