blob: 1ab00dfa12866d15c41d0cb815ce0091f08d72af [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/screen_orientation/screen_orientation_provider.h"
#include "base/callback_helpers.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/screen_orientation_delegate.h"
#include "content/public/browser/web_contents.h"
#include "third_party/WebKit/public/platform/modules/screen_orientation/WebLockOrientationError.h"
namespace content {
using device::mojom::ScreenOrientationLockResult;
ScreenOrientationDelegate* ScreenOrientationProvider::delegate_ = nullptr;
ScreenOrientationProvider::ScreenOrientationProvider(WebContents* web_contents)
: WebContentsObserver(web_contents),
lock_applied_(false),
bindings_(web_contents, this) {}
ScreenOrientationProvider::~ScreenOrientationProvider() = default;
void ScreenOrientationProvider::LockOrientation(
blink::WebScreenOrientationLockType orientation,
const LockOrientationCallback& callback) {
// Cancel any pending lock request.
NotifyLockResult(ScreenOrientationLockResult::
SCREEN_ORIENTATION_LOCK_RESULT_ERROR_CANCELED);
// Record new pending lock request.
pending_callback_ = callback;
if (!delegate_ || !delegate_->ScreenOrientationProviderSupported()) {
NotifyLockResult(ScreenOrientationLockResult::
SCREEN_ORIENTATION_LOCK_RESULT_ERROR_NOT_AVAILABLE);
return;
}
if (delegate_->FullScreenRequired(web_contents())) {
RenderViewHostImpl* rvhi =
static_cast<RenderViewHostImpl*>(web_contents()->GetRenderViewHost());
if (!rvhi) {
NotifyLockResult(ScreenOrientationLockResult::
SCREEN_ORIENTATION_LOCK_RESULT_ERROR_CANCELED);
return;
}
if (!static_cast<WebContentsImpl*>(web_contents())
->IsFullscreenForCurrentTab()) {
NotifyLockResult(
ScreenOrientationLockResult::
SCREEN_ORIENTATION_LOCK_RESULT_ERROR_FULLSCREEN_REQUIRED);
return;
}
}
if (orientation == blink::WebScreenOrientationLockNatural) {
orientation = GetNaturalLockType();
if (orientation == blink::WebScreenOrientationLockDefault) {
// We are in a broken state, let's pretend we got canceled.
NotifyLockResult(ScreenOrientationLockResult::
SCREEN_ORIENTATION_LOCK_RESULT_ERROR_CANCELED);
return;
}
}
lock_applied_ = true;
delegate_->Lock(web_contents(), orientation);
// If the orientation we are locking to matches the current orientation, we
// should succeed immediately.
if (LockMatchesCurrentOrientation(orientation)) {
NotifyLockResult(
ScreenOrientationLockResult::SCREEN_ORIENTATION_LOCK_RESULT_SUCCESS);
return;
}
pending_lock_orientation_ = orientation;
}
void ScreenOrientationProvider::UnlockOrientation() {
// Cancel any pending lock request.
NotifyLockResult(ScreenOrientationLockResult::
SCREEN_ORIENTATION_LOCK_RESULT_ERROR_CANCELED);
if (!lock_applied_ || !delegate_)
return;
delegate_->Unlock(web_contents());
lock_applied_ = false;
}
void ScreenOrientationProvider::OnOrientationChange() {
if (!pending_lock_orientation_.has_value())
return;
if (LockMatchesCurrentOrientation(pending_lock_orientation_.value())) {
DCHECK(!pending_callback_.is_null());
NotifyLockResult(
ScreenOrientationLockResult::SCREEN_ORIENTATION_LOCK_RESULT_SUCCESS);
}
}
void ScreenOrientationProvider::NotifyLockResult(
ScreenOrientationLockResult result) {
if (!pending_callback_.is_null())
base::ResetAndReturn(&pending_callback_).Run(result);
pending_lock_orientation_.reset();
}
void ScreenOrientationProvider::SetDelegate(
ScreenOrientationDelegate* delegate) {
delegate_ = delegate;
}
void ScreenOrientationProvider::DidToggleFullscreenModeForTab(
bool entered_fullscreen,
bool will_cause_resize) {
if (!lock_applied_ || !delegate_)
return;
// If fullscreen is not required in order to lock orientation, don't unlock
// when fullscreen state changes.
if (!delegate_->FullScreenRequired(web_contents()))
return;
DCHECK(!entered_fullscreen);
UnlockOrientation();
}
void ScreenOrientationProvider::DidFinishNavigation(
NavigationHandle* navigation_handle) {
if (!navigation_handle->IsInMainFrame() ||
!navigation_handle->HasCommitted() || navigation_handle->IsSamePage()) {
return;
}
UnlockOrientation();
}
blink::WebScreenOrientationLockType
ScreenOrientationProvider::GetNaturalLockType() const {
RenderWidgetHost* rwh = web_contents()->GetRenderViewHost()->GetWidget();
if (!rwh)
return blink::WebScreenOrientationLockDefault;
ScreenInfo screen_info;
rwh->GetScreenInfo(&screen_info);
switch (screen_info.orientation_type) {
case SCREEN_ORIENTATION_VALUES_PORTRAIT_PRIMARY:
case SCREEN_ORIENTATION_VALUES_PORTRAIT_SECONDARY:
if (screen_info.orientation_angle == 0 ||
screen_info.orientation_angle == 180) {
return blink::WebScreenOrientationLockPortraitPrimary;
}
return blink::WebScreenOrientationLockLandscapePrimary;
case SCREEN_ORIENTATION_VALUES_LANDSCAPE_PRIMARY:
case SCREEN_ORIENTATION_VALUES_LANDSCAPE_SECONDARY:
if (screen_info.orientation_angle == 0 ||
screen_info.orientation_angle == 180) {
return blink::WebScreenOrientationLockLandscapePrimary;
}
return blink::WebScreenOrientationLockPortraitPrimary;
default:
break;
}
NOTREACHED();
return blink::WebScreenOrientationLockDefault;
}
bool ScreenOrientationProvider::LockMatchesCurrentOrientation(
blink::WebScreenOrientationLockType lock) {
RenderWidgetHost* rwh = web_contents()->GetRenderViewHost()->GetWidget();
if (!rwh)
return false;
ScreenInfo screen_info;
rwh->GetScreenInfo(&screen_info);
switch (lock) {
case blink::WebScreenOrientationLockPortraitPrimary:
return screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_PORTRAIT_PRIMARY;
case blink::WebScreenOrientationLockPortraitSecondary:
return screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_PORTRAIT_SECONDARY;
case blink::WebScreenOrientationLockLandscapePrimary:
return screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_LANDSCAPE_PRIMARY;
case blink::WebScreenOrientationLockLandscapeSecondary:
return screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_LANDSCAPE_SECONDARY;
case blink::WebScreenOrientationLockLandscape:
return screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_LANDSCAPE_PRIMARY ||
screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_LANDSCAPE_SECONDARY;
case blink::WebScreenOrientationLockPortrait:
return screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_PORTRAIT_PRIMARY ||
screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_PORTRAIT_SECONDARY;
case blink::WebScreenOrientationLockAny:
return true;
case blink::WebScreenOrientationLockNatural:
case blink::WebScreenOrientationLockDefault:
NOTREACHED();
return false;
}
NOTREACHED();
return false;
}
} // namespace content