blob: 6d2e9140bb5766ce633e09c4f9deef0f2e5838a2 [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 <utility>
#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"
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,
LockOrientationCallback callback) {
// Cancel any pending lock request.
NotifyLockResult(ScreenOrientationLockResult::
SCREEN_ORIENTATION_LOCK_RESULT_ERROR_CANCELED);
// Record new pending lock request.
pending_callback_ = std::move(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::kWebScreenOrientationLockNatural) {
orientation = GetNaturalLockType();
if (orientation == blink::kWebScreenOrientationLockDefault) {
// 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;
}
ScreenOrientationDelegate* ScreenOrientationProvider::GetDelegateForTesting() {
return 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->IsSameDocument()) {
return;
}
UnlockOrientation();
}
blink::WebScreenOrientationLockType
ScreenOrientationProvider::GetNaturalLockType() const {
RenderWidgetHost* rwh = web_contents()->GetRenderViewHost()->GetWidget();
if (!rwh)
return blink::kWebScreenOrientationLockDefault;
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::kWebScreenOrientationLockPortraitPrimary;
}
return blink::kWebScreenOrientationLockLandscapePrimary;
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::kWebScreenOrientationLockLandscapePrimary;
}
return blink::kWebScreenOrientationLockPortraitPrimary;
default:
break;
}
NOTREACHED();
return blink::kWebScreenOrientationLockDefault;
}
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::kWebScreenOrientationLockPortraitPrimary:
return screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_PORTRAIT_PRIMARY;
case blink::kWebScreenOrientationLockPortraitSecondary:
return screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_PORTRAIT_SECONDARY;
case blink::kWebScreenOrientationLockLandscapePrimary:
return screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_LANDSCAPE_PRIMARY;
case blink::kWebScreenOrientationLockLandscapeSecondary:
return screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_LANDSCAPE_SECONDARY;
case blink::kWebScreenOrientationLockLandscape:
return screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_LANDSCAPE_PRIMARY ||
screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_LANDSCAPE_SECONDARY;
case blink::kWebScreenOrientationLockPortrait:
return screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_PORTRAIT_PRIMARY ||
screen_info.orientation_type ==
SCREEN_ORIENTATION_VALUES_PORTRAIT_SECONDARY;
case blink::kWebScreenOrientationLockAny:
return true;
case blink::kWebScreenOrientationLockNatural:
case blink::kWebScreenOrientationLockDefault:
NOTREACHED();
return false;
}
NOTREACHED();
return false;
}
} // namespace content