ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / content / browser / renderer_host / render_widget_host_view_base.cc
blob6e49da5a4c4350ee3013a789b99526d8e7c68547
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.
5 #include "content/browser/renderer_host/render_widget_host_view_base.h"
7 #include "base/logging.h"
8 #include "base/profiler/scoped_tracker.h"
9 #include "content/browser/accessibility/browser_accessibility_manager.h"
10 #include "content/browser/gpu/gpu_data_manager_impl.h"
11 #include "content/browser/renderer_host/input/synthetic_gesture_target_base.h"
12 #include "content/browser/renderer_host/render_process_host_impl.h"
13 #include "content/browser/renderer_host/render_widget_host_impl.h"
14 #include "content/common/content_switches_internal.h"
15 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
16 #include "ui/gfx/display.h"
17 #include "ui/gfx/geometry/size_conversions.h"
18 #include "ui/gfx/geometry/size_f.h"
19 #include "ui/gfx/screen.h"
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
37 namespace content {
39 #if defined(OS_WIN)
41 namespace {
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;
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;
57 if (base::GetProcId(iter.GetData().handle) == plugin_process_id) {
58 iter->AddWindow(parent);
59 return;
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;
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);
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 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
88 tracked_objects::ScopedTracker tracking_profile(
89 FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 PluginWrapperWindowProc"));
91 if (message == WM_PARENTNOTIFY) {
92 switch (LOWORD(wparam)) {
93 case WM_LBUTTONDOWN:
94 case WM_RBUTTONDOWN:
95 case WM_MBUTTONDOWN:
96 ::SendMessage(GetParent(window), message, wparam, lparam);
97 return 0;
98 default:
99 break;
102 return ::DefWindowProc(window, message, wparam, lparam);
105 bool IsPluginWrapperWindow(HWND window) {
106 return gfx::GetClassNameW(window) ==
107 base::string16(kWrapperNativeWindowClassName);
110 // Create an intermediate window between the given HWND and its parent.
111 HWND ReparentWindow(HWND window, HWND parent) {
112 static ATOM atom = 0;
113 static HMODULE instance = NULL;
114 if (!atom) {
115 WNDCLASSEX window_class;
116 base::win::InitializeWindowClass(
117 kWrapperNativeWindowClassName,
118 &base::win::WrappedWindowProc<PluginWrapperWindowProc>,
119 CS_DBLCLKS,
122 NULL,
123 // xxx reinterpret_cast<HBRUSH>(COLOR_WINDOW+1),
124 reinterpret_cast<HBRUSH>(COLOR_GRAYTEXT+1),
125 NULL,
126 NULL,
127 NULL,
128 &window_class);
129 instance = window_class.hInstance;
130 atom = RegisterClassEx(&window_class);
132 DCHECK(atom);
134 HWND new_parent = CreateWindowEx(
135 WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
136 MAKEINTATOM(atom), 0,
137 WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
138 0, 0, 0, 0, parent, 0, instance, 0);
139 gfx::CheckWindowCreated(new_parent);
140 ::SetParent(window, new_parent);
141 // How many times we try to find a PluginProcessHost whose process matches
142 // the HWND.
143 static const int kMaxTries = 5;
144 BrowserThread::PostTask(
145 BrowserThread::IO,
146 FROM_HERE,
147 base::Bind(&NotifyPluginProcessHostHelper, window, new_parent,
148 kMaxTries));
149 return new_parent;
152 BOOL CALLBACK PaintEnumChildProc(HWND hwnd, LPARAM lparam) {
153 if (!PluginServiceImpl::GetInstance()->IsPluginWindow(hwnd))
154 return TRUE;
156 gfx::Rect* rect = reinterpret_cast<gfx::Rect*>(lparam);
157 gfx::Rect rect_in_pixels = gfx::win::DIPToScreenRect(*rect);
158 static UINT msg = RegisterWindowMessage(kPaintMessageName);
159 WPARAM wparam = MAKEWPARAM(rect_in_pixels.x(), rect_in_pixels.y());
160 lparam = MAKELPARAM(rect_in_pixels.width(), rect_in_pixels.height());
162 // SendMessage gets the message across much quicker than PostMessage, since it
163 // doesn't get queued. When the plugin thread calls PeekMessage or other
164 // Win32 APIs, sent messages are dispatched automatically.
165 SendNotifyMessage(hwnd, msg, wparam, lparam);
167 return TRUE;
170 // Windows callback for OnDestroy to detach the plugin windows.
171 BOOL CALLBACK DetachPluginWindowsCallbackInternal(HWND window, LPARAM param) {
172 RenderWidgetHostViewBase::DetachPluginWindowsCallback(window);
173 return TRUE;
176 } // namespace
178 // static
179 void RenderWidgetHostViewBase::DetachPluginWindowsCallback(HWND window) {
180 if (PluginServiceImpl::GetInstance()->IsPluginWindow(window) &&
181 !IsHungAppWindow(window)) {
182 ::ShowWindow(window, SW_HIDE);
183 SetParent(window, NULL);
187 // static
188 void RenderWidgetHostViewBase::MovePluginWindowsHelper(
189 HWND parent,
190 const std::vector<WebPluginGeometry>& moves) {
191 if (moves.empty())
192 return;
194 bool oop_plugins = !base::CommandLine::ForCurrentProcess()->HasSwitch(
195 switches::kSingleProcess);
197 HDWP defer_window_pos_info =
198 ::BeginDeferWindowPos(static_cast<int>(moves.size()));
200 if (!defer_window_pos_info) {
201 NOTREACHED();
202 return;
205 #if defined(USE_AURA)
206 std::vector<RECT> invalidate_rects;
207 #endif
209 for (size_t i = 0; i < moves.size(); ++i) {
210 unsigned long flags = 0;
211 const WebPluginGeometry& move = moves[i];
212 HWND window = move.window;
214 // As the plugin parent window which lives on the browser UI thread is
215 // destroyed asynchronously, it is possible that we have a stale window
216 // sent in by the renderer for moving around.
217 // Note: get the parent before checking if the window is valid, to avoid a
218 // race condition where the window is destroyed after the check but before
219 // the GetParent call.
220 HWND cur_parent = ::GetParent(window);
221 if (!::IsWindow(window))
222 continue;
224 if (!PluginServiceImpl::GetInstance()->IsPluginWindow(window)) {
225 // The renderer should only be trying to move plugin windows. However,
226 // this may happen as a result of a race condition (i.e. even after the
227 // check right above), so we ignore it.
228 continue;
231 if (oop_plugins) {
232 if (cur_parent == GetDesktopWindow()) {
233 // The plugin window hasn't been parented yet, add an intermediate
234 // window that lives on this thread to speed up scrolling. Note this
235 // only works with out of process plugins since we depend on
236 // PluginProcessHost to destroy the intermediate HWNDs.
237 cur_parent = ReparentWindow(window, parent);
238 ::ShowWindow(window, SW_SHOW); // Window was created hidden.
239 } else if (!IsPluginWrapperWindow(cur_parent)) {
240 continue; // Race if plugin process is shutting down.
243 // We move the intermediate parent window which doesn't result in cross-
244 // process synchronous Windows messages.
245 window = cur_parent;
246 } else {
247 if (cur_parent == GetDesktopWindow())
248 SetParent(window, parent);
251 if (move.visible)
252 flags |= SWP_SHOWWINDOW;
253 else
254 flags |= SWP_HIDEWINDOW;
256 #if defined(USE_AURA)
257 if (GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
258 // Without this flag, Windows repaints the parent area uncovered by this
259 // move. However when software compositing is used the clipping region is
260 // ignored. Since in Aura the browser chrome could be under the plugin, if
261 // if Windows tries to paint it synchronously inside EndDeferWindowsPos
262 // then it won't have the data and it will flash white. So instead we
263 // manually redraw the plugin.
264 // Why not do this for native Windows? Not sure if there are any
265 // performance issues with this.
266 flags |= SWP_NOREDRAW;
268 #endif
270 if (move.rects_valid) {
271 gfx::Rect clip_rect_in_pixel = gfx::win::DIPToScreenRect(move.clip_rect);
272 HRGN hrgn = ::CreateRectRgn(clip_rect_in_pixel.x(),
273 clip_rect_in_pixel.y(),
274 clip_rect_in_pixel.right(),
275 clip_rect_in_pixel.bottom());
276 gfx::SubtractRectanglesFromRegion(hrgn, move.cutout_rects);
278 // Note: System will own the hrgn after we call SetWindowRgn,
279 // so we don't need to call DeleteObject(hrgn)
280 ::SetWindowRgn(window, hrgn,
281 !move.clip_rect.IsEmpty() && (flags & SWP_NOREDRAW) == 0);
283 #if defined(USE_AURA)
284 // When using the software compositor, if the clipping rectangle is empty
285 // then DeferWindowPos won't redraw the newly uncovered area under the
286 // plugin.
287 if (clip_rect_in_pixel.IsEmpty() &&
288 !GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
289 RECT r;
290 GetClientRect(window, &r);
291 MapWindowPoints(window, parent, reinterpret_cast<POINT*>(&r), 2);
292 invalidate_rects.push_back(r);
294 #endif
295 } else {
296 flags |= SWP_NOMOVE;
297 flags |= SWP_NOSIZE;
300 gfx::Rect window_rect_in_pixel =
301 gfx::win::DIPToScreenRect(move.window_rect);
302 defer_window_pos_info = ::DeferWindowPos(defer_window_pos_info,
303 window, NULL,
304 window_rect_in_pixel.x(),
305 window_rect_in_pixel.y(),
306 window_rect_in_pixel.width(),
307 window_rect_in_pixel.height(),
308 flags);
310 if (!defer_window_pos_info) {
311 DCHECK(false) << "DeferWindowPos failed, so all plugin moves ignored.";
312 return;
316 ::EndDeferWindowPos(defer_window_pos_info);
318 #if defined(USE_AURA)
319 if (GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
320 for (size_t i = 0; i < moves.size(); ++i) {
321 const WebPluginGeometry& move = moves[i];
322 RECT r;
323 GetWindowRect(move.window, &r);
324 gfx::Rect gr(r);
325 PaintEnumChildProc(move.window, reinterpret_cast<LPARAM>(&gr));
327 } else {
328 for (size_t i = 0; i < invalidate_rects.size(); ++i) {
329 ::RedrawWindow(
330 parent, &invalidate_rects[i], NULL,
331 // These flags are from WebPluginDelegateImpl::NativeWndProc.
332 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_FRAME | RDW_UPDATENOW);
335 #endif
338 // static
339 void RenderWidgetHostViewBase::PaintPluginWindowsHelper(
340 HWND parent, const gfx::Rect& damaged_screen_rect) {
341 LPARAM lparam = reinterpret_cast<LPARAM>(&damaged_screen_rect);
342 EnumChildWindows(parent, PaintEnumChildProc, lparam);
345 // static
346 void RenderWidgetHostViewBase::DetachPluginsHelper(HWND parent) {
347 // When a tab is closed all its child plugin windows are destroyed
348 // automatically. This happens before plugins get any notification that its
349 // instances are tearing down.
351 // Plugins like Quicktime assume that their windows will remain valid as long
352 // as they have plugin instances active. Quicktime crashes in this case
353 // because its windowing code cleans up an internal data structure that the
354 // handler for NPP_DestroyStream relies on.
356 // The fix is to detach plugin windows from web contents when it is going
357 // away. This will prevent the plugin windows from getting destroyed
358 // automatically. The detached plugin windows will get cleaned up in proper
359 // sequence as part of the usual cleanup when the plugin instance goes away.
360 EnumChildWindows(parent, DetachPluginWindowsCallbackInternal, NULL);
363 #endif // OS_WIN
365 namespace {
367 // How many microseconds apart input events should be flushed.
368 const int kFlushInputRateInUs = 16666;
372 RenderWidgetHostViewBase::RenderWidgetHostViewBase()
373 : popup_type_(blink::WebPopupTypeNone),
374 background_color_(SK_ColorWHITE),
375 mouse_locked_(false),
376 showing_context_menu_(false),
377 selection_text_offset_(0),
378 selection_range_(gfx::Range::InvalidRange()),
379 current_device_scale_factor_(0),
380 current_display_rotation_(gfx::Display::ROTATE_0),
381 pinch_zoom_enabled_(content::IsPinchToZoomEnabled()),
382 renderer_frame_number_(0),
383 weak_factory_(this) {
386 RenderWidgetHostViewBase::~RenderWidgetHostViewBase() {
387 DCHECK(!mouse_locked_);
390 bool RenderWidgetHostViewBase::OnMessageReceived(const IPC::Message& msg){
391 return false;
394 void RenderWidgetHostViewBase::SetBackgroundColor(SkColor color) {
395 background_color_ = color;
398 void RenderWidgetHostViewBase::SetBackgroundColorToDefault() {
399 SetBackgroundColor(SK_ColorWHITE);
402 bool RenderWidgetHostViewBase::GetBackgroundOpaque() {
403 return SkColorGetA(background_color_) == SK_AlphaOPAQUE;
406 gfx::Size RenderWidgetHostViewBase::GetPhysicalBackingSize() const {
407 gfx::NativeView view = GetNativeView();
408 gfx::Display display =
409 gfx::Screen::GetScreenFor(view)->GetDisplayNearestWindow(view);
410 return gfx::ToCeiledSize(gfx::ScaleSize(GetRequestedRendererSize(),
411 display.device_scale_factor()));
414 bool RenderWidgetHostViewBase::DoTopControlsShrinkBlinkSize() const {
415 return false;
418 float RenderWidgetHostViewBase::GetTopControlsHeight() const {
419 return 0.f;
422 void RenderWidgetHostViewBase::SelectionChanged(const base::string16& text,
423 size_t offset,
424 const gfx::Range& range) {
425 selection_text_ = text;
426 selection_text_offset_ = offset;
427 selection_range_.set_start(range.start());
428 selection_range_.set_end(range.end());
431 gfx::Size RenderWidgetHostViewBase::GetRequestedRendererSize() const {
432 return GetViewBounds().size();
435 ui::TextInputClient* RenderWidgetHostViewBase::GetTextInputClient() {
436 NOTREACHED();
437 return NULL;
440 bool RenderWidgetHostViewBase::IsShowingContextMenu() const {
441 return showing_context_menu_;
444 void RenderWidgetHostViewBase::SetShowingContextMenu(bool showing) {
445 DCHECK_NE(showing_context_menu_, showing);
446 showing_context_menu_ = showing;
449 base::string16 RenderWidgetHostViewBase::GetSelectedText() const {
450 if (!selection_range_.IsValid())
451 return base::string16();
452 return selection_text_.substr(
453 selection_range_.GetMin() - selection_text_offset_,
454 selection_range_.length());
457 bool RenderWidgetHostViewBase::IsMouseLocked() {
458 return mouse_locked_;
461 InputEventAckState RenderWidgetHostViewBase::FilterInputEvent(
462 const blink::WebInputEvent& input_event) {
463 // By default, input events are simply forwarded to the renderer.
464 return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
467 void RenderWidgetHostViewBase::OnDidFlushInput() {
468 // The notification can safely be ignored by most implementations.
471 void RenderWidgetHostViewBase::OnSetNeedsFlushInput() {
472 if (flush_input_timer_.IsRunning())
473 return;
475 flush_input_timer_.Start(
476 FROM_HERE,
477 base::TimeDelta::FromMicroseconds(kFlushInputRateInUs),
478 this,
479 &RenderWidgetHostViewBase::FlushInput);
482 void RenderWidgetHostViewBase::WheelEventAck(
483 const blink::WebMouseWheelEvent& event,
484 InputEventAckState ack_result) {
487 void RenderWidgetHostViewBase::GestureEventAck(
488 const blink::WebGestureEvent& event,
489 InputEventAckState ack_result) {
492 void RenderWidgetHostViewBase::SetPopupType(blink::WebPopupType popup_type) {
493 popup_type_ = popup_type;
496 blink::WebPopupType RenderWidgetHostViewBase::GetPopupType() {
497 return popup_type_;
500 BrowserAccessibilityManager*
501 RenderWidgetHostViewBase::CreateBrowserAccessibilityManager(
502 BrowserAccessibilityDelegate* delegate) {
503 NOTREACHED();
504 return NULL;
507 void RenderWidgetHostViewBase::AccessibilityShowMenu(const gfx::Point& point) {
510 gfx::Point RenderWidgetHostViewBase::AccessibilityOriginInScreen(
511 const gfx::Rect& bounds) {
512 return bounds.origin();
515 gfx::AcceleratedWidget
516 RenderWidgetHostViewBase::AccessibilityGetAcceleratedWidget() {
517 return gfx::kNullAcceleratedWidget;
520 gfx::NativeViewAccessible
521 RenderWidgetHostViewBase::AccessibilityGetNativeViewAccessible() {
522 return NULL;
525 void RenderWidgetHostViewBase::UpdateScreenInfo(gfx::NativeView view) {
526 RenderWidgetHostImpl* impl = NULL;
527 if (GetRenderWidgetHost())
528 impl = RenderWidgetHostImpl::From(GetRenderWidgetHost());
530 if (impl)
531 impl->SendScreenRects();
533 if (HasDisplayPropertyChanged(view) && impl)
534 impl->NotifyScreenInfoChanged();
537 bool RenderWidgetHostViewBase::HasDisplayPropertyChanged(gfx::NativeView view) {
538 gfx::Display display =
539 gfx::Screen::GetScreenFor(view)->GetDisplayNearestWindow(view);
540 if (current_display_area_ == display.work_area() &&
541 current_device_scale_factor_ == display.device_scale_factor() &&
542 current_display_rotation_ == display.rotation()) {
543 return false;
546 current_display_area_ = display.work_area();
547 current_device_scale_factor_ = display.device_scale_factor();
548 current_display_rotation_ = display.rotation();
549 return true;
552 base::WeakPtr<RenderWidgetHostViewBase> RenderWidgetHostViewBase::GetWeakPtr() {
553 return weak_factory_.GetWeakPtr();
556 scoped_ptr<SyntheticGestureTarget>
557 RenderWidgetHostViewBase::CreateSyntheticGestureTarget() {
558 RenderWidgetHostImpl* host =
559 RenderWidgetHostImpl::From(GetRenderWidgetHost());
560 return scoped_ptr<SyntheticGestureTarget>(
561 new SyntheticGestureTargetBase(host));
564 // Platform implementation should override this method to allow frame
565 // subscription. Frame subscriber is set to RenderProcessHost, which is
566 // platform independent. It should be set to the specific presenter on each
567 // platform.
568 bool RenderWidgetHostViewBase::CanSubscribeFrame() const {
569 NOTIMPLEMENTED();
570 return false;
573 // Base implementation for this method sets the subscriber to RenderProcessHost,
574 // which is platform independent. Note: Implementation only support subscribing
575 // to accelerated composited frames.
576 void RenderWidgetHostViewBase::BeginFrameSubscription(
577 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) {
578 RenderWidgetHostImpl* impl = NULL;
579 if (GetRenderWidgetHost())
580 impl = RenderWidgetHostImpl::From(GetRenderWidgetHost());
581 if (!impl)
582 return;
583 RenderProcessHostImpl* render_process_host =
584 static_cast<RenderProcessHostImpl*>(impl->GetProcess());
585 render_process_host->BeginFrameSubscription(impl->GetRoutingID(),
586 subscriber.Pass());
589 void RenderWidgetHostViewBase::EndFrameSubscription() {
590 RenderWidgetHostImpl* impl = NULL;
591 if (GetRenderWidgetHost())
592 impl = RenderWidgetHostImpl::From(GetRenderWidgetHost());
593 if (!impl)
594 return;
595 RenderProcessHostImpl* render_process_host =
596 static_cast<RenderProcessHostImpl*>(impl->GetProcess());
597 render_process_host->EndFrameSubscription(impl->GetRoutingID());
600 uint32 RenderWidgetHostViewBase::RendererFrameNumber() {
601 return renderer_frame_number_;
604 void RenderWidgetHostViewBase::DidReceiveRendererFrame() {
605 ++renderer_frame_number_;
608 void RenderWidgetHostViewBase::FlushInput() {
609 RenderWidgetHostImpl* impl = NULL;
610 if (GetRenderWidgetHost())
611 impl = RenderWidgetHostImpl::From(GetRenderWidgetHost());
612 if (!impl)
613 return;
614 impl->FlushInput();
617 SkColorType RenderWidgetHostViewBase::PreferredReadbackFormat() {
618 return kN32_SkColorType;
621 void RenderWidgetHostViewBase::OnTextSurroundingSelectionResponse(
622 const base::string16& content,
623 size_t start_offset,
624 size_t end_offset) {
625 NOTIMPLEMENTED();
628 void RenderWidgetHostViewBase::ShowDisambiguationPopup(
629 const gfx::Rect& rect_pixels,
630 const SkBitmap& zoomed_bitmap) {
631 NOTIMPLEMENTED();
634 gfx::Size RenderWidgetHostViewBase::GetVisibleViewportSize() const {
635 return GetViewBounds().size();
638 void RenderWidgetHostViewBase::SetInsets(const gfx::Insets& insets) {
639 NOTIMPLEMENTED();
642 // static
643 blink::WebScreenOrientationType
644 RenderWidgetHostViewBase::GetOrientationTypeForMobile(
645 const gfx::Display& display) {
646 int angle = display.RotationAsDegree();
647 const gfx::Rect& bounds = display.bounds();
649 // Whether the device's natural orientation is portrait.
650 bool natural_portrait = false;
651 if (angle == 0 || angle == 180) // The device is in its natural orientation.
652 natural_portrait = bounds.height() >= bounds.width();
653 else
654 natural_portrait = bounds.height() <= bounds.width();
656 switch (angle) {
657 case 0:
658 return natural_portrait ? blink::WebScreenOrientationPortraitPrimary
659 : blink::WebScreenOrientationLandscapePrimary;
660 case 90:
661 return natural_portrait ? blink::WebScreenOrientationLandscapePrimary
662 : blink::WebScreenOrientationPortraitSecondary;
663 case 180:
664 return natural_portrait ? blink::WebScreenOrientationPortraitSecondary
665 : blink::WebScreenOrientationLandscapeSecondary;
666 case 270:
667 return natural_portrait ? blink::WebScreenOrientationLandscapeSecondary
668 : blink::WebScreenOrientationPortraitPrimary;
669 default:
670 NOTREACHED();
671 return blink::WebScreenOrientationPortraitPrimary;
675 // static
676 blink::WebScreenOrientationType
677 RenderWidgetHostViewBase::GetOrientationTypeForDesktop(
678 const gfx::Display& display) {
679 static int primary_landscape_angle = -1;
680 static int primary_portrait_angle = -1;
682 int angle = display.RotationAsDegree();
683 const gfx::Rect& bounds = display.bounds();
684 bool is_portrait = bounds.height() >= bounds.width();
686 if (is_portrait && primary_portrait_angle == -1)
687 primary_portrait_angle = angle;
689 if (!is_portrait && primary_landscape_angle == -1)
690 primary_landscape_angle = angle;
692 if (is_portrait) {
693 return primary_portrait_angle == angle
694 ? blink::WebScreenOrientationPortraitPrimary
695 : blink::WebScreenOrientationPortraitSecondary;
698 return primary_landscape_angle == angle
699 ? blink::WebScreenOrientationLandscapePrimary
700 : blink::WebScreenOrientationLandscapeSecondary;
703 void RenderWidgetHostViewBase::OnDidNavigateMainFrameToNewPage() {
706 } // namespace content