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"
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"
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;
57 if (base::GetProcId(iter
.GetData().handle
) == plugin_process_id
) {
58 iter
->AddWindow(parent
);
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
68 base::MessageLoop::current()->PostDelayedTask(
70 base::Bind(&NotifyPluginProcessHostHelper
, window
, parent
, tries
- 1),
71 base::TimeDelta::FromMilliseconds(kTryDelayMs
));
76 // The plugin process might have died in the time to execute the task, don't
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
)) {
96 ::SendMessage(GetParent(window
), message
, wparam
, lparam
);
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
;
115 WNDCLASSEX window_class
;
116 base::win::InitializeWindowClass(
117 kWrapperNativeWindowClassName
,
118 &base::win::WrappedWindowProc
<PluginWrapperWindowProc
>,
123 // xxx reinterpret_cast<HBRUSH>(COLOR_WINDOW+1),
124 reinterpret_cast<HBRUSH
>(COLOR_GRAYTEXT
+1),
129 instance
= window_class
.hInstance
;
130 atom
= RegisterClassEx(&window_class
);
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
143 static const int kMaxTries
= 5;
144 BrowserThread::PostTask(
147 base::Bind(&NotifyPluginProcessHostHelper
, window
, new_parent
,
152 BOOL CALLBACK
PaintEnumChildProc(HWND hwnd
, LPARAM lparam
) {
153 if (!PluginServiceImpl::GetInstance()->IsPluginWindow(hwnd
))
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
);
170 // Windows callback for OnDestroy to detach the plugin windows.
171 BOOL CALLBACK
DetachPluginWindowsCallbackInternal(HWND window
, LPARAM param
) {
172 RenderWidgetHostViewBase::DetachPluginWindowsCallback(window
);
179 void RenderWidgetHostViewBase::DetachPluginWindowsCallback(HWND window
) {
180 if (PluginServiceImpl::GetInstance()->IsPluginWindow(window
) &&
181 !IsHungAppWindow(window
)) {
182 ::ShowWindow(window
, SW_HIDE
);
183 SetParent(window
, NULL
);
188 void RenderWidgetHostViewBase::MovePluginWindowsHelper(
190 const std::vector
<WebPluginGeometry
>& moves
) {
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
) {
205 #if defined(USE_AURA)
206 std::vector
<RECT
> invalidate_rects
;
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
))
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.
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.
247 if (cur_parent
== GetDesktopWindow())
248 SetParent(window
, parent
);
252 flags
|= SWP_SHOWWINDOW
;
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
;
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
287 if (clip_rect_in_pixel
.IsEmpty() &&
288 !GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
290 GetClientRect(window
, &r
);
291 MapWindowPoints(window
, parent
, reinterpret_cast<POINT
*>(&r
), 2);
292 invalidate_rects
.push_back(r
);
300 gfx::Rect window_rect_in_pixel
=
301 gfx::win::DIPToScreenRect(move
.window_rect
);
302 defer_window_pos_info
= ::DeferWindowPos(defer_window_pos_info
,
304 window_rect_in_pixel
.x(),
305 window_rect_in_pixel
.y(),
306 window_rect_in_pixel
.width(),
307 window_rect_in_pixel
.height(),
310 if (!defer_window_pos_info
) {
311 DCHECK(false) << "DeferWindowPos failed, so all plugin moves ignored.";
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
];
323 GetWindowRect(move
.window
, &r
);
325 PaintEnumChildProc(move
.window
, reinterpret_cast<LPARAM
>(&gr
));
328 for (size_t i
= 0; i
< invalidate_rects
.size(); ++i
) {
330 parent
, &invalidate_rects
[i
], NULL
,
331 // These flags are from WebPluginDelegateImpl::NativeWndProc.
332 RDW_INVALIDATE
| RDW_ALLCHILDREN
| RDW_FRAME
| RDW_UPDATENOW
);
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
);
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
);
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
){
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 {
418 float RenderWidgetHostViewBase::GetTopControlsHeight() const {
422 void RenderWidgetHostViewBase::SelectionChanged(const base::string16
& text
,
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() {
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::OnSetNeedsFlushInput() {
468 if (flush_input_timer_
.IsRunning())
471 flush_input_timer_
.Start(
473 base::TimeDelta::FromMicroseconds(kFlushInputRateInUs
),
475 &RenderWidgetHostViewBase::FlushInput
);
478 void RenderWidgetHostViewBase::WheelEventAck(
479 const blink::WebMouseWheelEvent
& event
,
480 InputEventAckState ack_result
) {
483 void RenderWidgetHostViewBase::GestureEventAck(
484 const blink::WebGestureEvent
& event
,
485 InputEventAckState ack_result
) {
488 void RenderWidgetHostViewBase::SetPopupType(blink::WebPopupType popup_type
) {
489 popup_type_
= popup_type
;
492 blink::WebPopupType
RenderWidgetHostViewBase::GetPopupType() {
496 BrowserAccessibilityManager
*
497 RenderWidgetHostViewBase::CreateBrowserAccessibilityManager(
498 BrowserAccessibilityDelegate
* delegate
) {
503 void RenderWidgetHostViewBase::AccessibilityShowMenu(const gfx::Point
& point
) {
506 gfx::Point
RenderWidgetHostViewBase::AccessibilityOriginInScreen(
507 const gfx::Rect
& bounds
) {
508 return bounds
.origin();
511 gfx::AcceleratedWidget
512 RenderWidgetHostViewBase::AccessibilityGetAcceleratedWidget() {
513 return gfx::kNullAcceleratedWidget
;
516 gfx::NativeViewAccessible
517 RenderWidgetHostViewBase::AccessibilityGetNativeViewAccessible() {
521 void RenderWidgetHostViewBase::UpdateScreenInfo(gfx::NativeView view
) {
522 RenderWidgetHostImpl
* impl
= NULL
;
523 if (GetRenderWidgetHost())
524 impl
= RenderWidgetHostImpl::From(GetRenderWidgetHost());
527 impl
->SendScreenRects();
529 if (HasDisplayPropertyChanged(view
) && impl
)
530 impl
->NotifyScreenInfoChanged();
533 bool RenderWidgetHostViewBase::HasDisplayPropertyChanged(gfx::NativeView view
) {
534 gfx::Display display
=
535 gfx::Screen::GetScreenFor(view
)->GetDisplayNearestWindow(view
);
536 if (current_display_area_
== display
.work_area() &&
537 current_device_scale_factor_
== display
.device_scale_factor() &&
538 current_display_rotation_
== display
.rotation()) {
542 current_display_area_
= display
.work_area();
543 current_device_scale_factor_
= display
.device_scale_factor();
544 current_display_rotation_
= display
.rotation();
548 base::WeakPtr
<RenderWidgetHostViewBase
> RenderWidgetHostViewBase::GetWeakPtr() {
549 return weak_factory_
.GetWeakPtr();
552 scoped_ptr
<SyntheticGestureTarget
>
553 RenderWidgetHostViewBase::CreateSyntheticGestureTarget() {
554 RenderWidgetHostImpl
* host
=
555 RenderWidgetHostImpl::From(GetRenderWidgetHost());
556 return scoped_ptr
<SyntheticGestureTarget
>(
557 new SyntheticGestureTargetBase(host
));
560 // Platform implementation should override this method to allow frame
561 // subscription. Frame subscriber is set to RenderProcessHost, which is
562 // platform independent. It should be set to the specific presenter on each
564 bool RenderWidgetHostViewBase::CanSubscribeFrame() const {
569 // Base implementation for this method sets the subscriber to RenderProcessHost,
570 // which is platform independent. Note: Implementation only support subscribing
571 // to accelerated composited frames.
572 void RenderWidgetHostViewBase::BeginFrameSubscription(
573 scoped_ptr
<RenderWidgetHostViewFrameSubscriber
> subscriber
) {
574 RenderWidgetHostImpl
* impl
= NULL
;
575 if (GetRenderWidgetHost())
576 impl
= RenderWidgetHostImpl::From(GetRenderWidgetHost());
579 RenderProcessHostImpl
* render_process_host
=
580 static_cast<RenderProcessHostImpl
*>(impl
->GetProcess());
581 render_process_host
->BeginFrameSubscription(impl
->GetRoutingID(),
585 void RenderWidgetHostViewBase::EndFrameSubscription() {
586 RenderWidgetHostImpl
* impl
= NULL
;
587 if (GetRenderWidgetHost())
588 impl
= RenderWidgetHostImpl::From(GetRenderWidgetHost());
591 RenderProcessHostImpl
* render_process_host
=
592 static_cast<RenderProcessHostImpl
*>(impl
->GetProcess());
593 render_process_host
->EndFrameSubscription(impl
->GetRoutingID());
596 uint32
RenderWidgetHostViewBase::RendererFrameNumber() {
597 return renderer_frame_number_
;
600 void RenderWidgetHostViewBase::DidReceiveRendererFrame() {
601 ++renderer_frame_number_
;
604 void RenderWidgetHostViewBase::FlushInput() {
605 RenderWidgetHostImpl
* impl
= NULL
;
606 if (GetRenderWidgetHost())
607 impl
= RenderWidgetHostImpl::From(GetRenderWidgetHost());
613 SkColorType
RenderWidgetHostViewBase::PreferredReadbackFormat() {
614 return kN32_SkColorType
;
617 void RenderWidgetHostViewBase::OnTextSurroundingSelectionResponse(
618 const base::string16
& content
,
624 void RenderWidgetHostViewBase::ShowDisambiguationPopup(
625 const gfx::Rect
& rect_pixels
,
626 const SkBitmap
& zoomed_bitmap
) {
630 gfx::Size
RenderWidgetHostViewBase::GetVisibleViewportSize() const {
631 return GetViewBounds().size();
634 void RenderWidgetHostViewBase::SetInsets(const gfx::Insets
& insets
) {
639 blink::WebScreenOrientationType
640 RenderWidgetHostViewBase::GetOrientationTypeForMobile(
641 const gfx::Display
& display
) {
642 int angle
= display
.RotationAsDegree();
643 const gfx::Rect
& bounds
= display
.bounds();
645 // Whether the device's natural orientation is portrait.
646 bool natural_portrait
= false;
647 if (angle
== 0 || angle
== 180) // The device is in its natural orientation.
648 natural_portrait
= bounds
.height() >= bounds
.width();
650 natural_portrait
= bounds
.height() <= bounds
.width();
654 return natural_portrait
? blink::WebScreenOrientationPortraitPrimary
655 : blink::WebScreenOrientationLandscapePrimary
;
657 return natural_portrait
? blink::WebScreenOrientationLandscapePrimary
658 : blink::WebScreenOrientationPortraitSecondary
;
660 return natural_portrait
? blink::WebScreenOrientationPortraitSecondary
661 : blink::WebScreenOrientationLandscapeSecondary
;
663 return natural_portrait
? blink::WebScreenOrientationLandscapeSecondary
664 : blink::WebScreenOrientationPortraitPrimary
;
667 return blink::WebScreenOrientationPortraitPrimary
;
672 blink::WebScreenOrientationType
673 RenderWidgetHostViewBase::GetOrientationTypeForDesktop(
674 const gfx::Display
& display
) {
675 static int primary_landscape_angle
= -1;
676 static int primary_portrait_angle
= -1;
678 int angle
= display
.RotationAsDegree();
679 const gfx::Rect
& bounds
= display
.bounds();
680 bool is_portrait
= bounds
.height() >= bounds
.width();
682 if (is_portrait
&& primary_portrait_angle
== -1)
683 primary_portrait_angle
= angle
;
685 if (!is_portrait
&& primary_landscape_angle
== -1)
686 primary_landscape_angle
= angle
;
689 return primary_portrait_angle
== angle
690 ? blink::WebScreenOrientationPortraitPrimary
691 : blink::WebScreenOrientationPortraitSecondary
;
694 return primary_landscape_angle
== angle
695 ? blink::WebScreenOrientationLandscapePrimary
696 : blink::WebScreenOrientationLandscapeSecondary
;
699 void RenderWidgetHostViewBase::OnDidNavigateMainFrameToNewPage() {
702 } // namespace content