Skip to content

Commit

Permalink
Bug 1744687 - Part 1. Lock orientation backend for Windows Tablet. r=…
Browse files Browse the repository at this point in the history
…gsvelto

Since Windows tablet mode has a orientation lock API, this patch
implements orientation lock backend for Windows tablet mode.

`GetAutoRotationState` API recognizes whether orientation API is supported on
the device. So this fix uses this API to check orientation API capability.

Differential Revision: https://phabricator.services.mozilla.com/D162451
  • Loading branch information
makotokato committed Nov 24, 2022
1 parent d7e6eee commit 6c25d02
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 3 deletions.
2 changes: 1 addition & 1 deletion hal/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ elif CONFIG["OS_TARGET"] == "Linux":
elif CONFIG["OS_TARGET"] == "WINNT":
REQUIRES_UNIFIED_BUILD = True
UNIFIED_SOURCES += [
"fallback/FallbackScreenConfiguration.cpp",
"fallback/FallbackVibration.cpp",
"windows/WindowsScreenConfiguration.cpp",
"windows/WindowsSensor.cpp",
]
# WindowsBattery.cpp cannot be built in unified mode because it relies on HalImpl.h.
Expand Down
98 changes: 98 additions & 0 deletions hal/windows/WindowsScreenConfiguration.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "Hal.h"
#include "mozilla/WindowsVersion.h"
#include "mozilla/widget/ScreenManager.h"
#include "nsIWindowsUIUtils.h"
#include "WinUtils.h"

#include <windows.h>

namespace mozilla {
namespace hal_impl {

static decltype(SetDisplayAutoRotationPreferences)*
sSetDisplayAutoRotationPreferences = nullptr;

RefPtr<GenericNonExclusivePromise> LockScreenOrientation(
const hal::ScreenOrientation& aOrientation) {
// SetDisplayAutoRotationPreferences requires Win8, tablet mode and device
// support.
if (!IsWin8OrLater()) {
return GenericNonExclusivePromise::CreateAndReject(
NS_ERROR_DOM_NOT_SUPPORTED_ERR, __func__);
}
AR_STATE state;
if (!widget::WinUtils::GetAutoRotationState(&state)) {
return GenericNonExclusivePromise::CreateAndReject(
NS_ERROR_DOM_NOT_SUPPORTED_ERR, __func__);
}

if (state & (AR_DISABLED | AR_REMOTESESSION | AR_MULTIMON | AR_NOSENSOR |
AR_NOT_SUPPORTED | AR_LAPTOP | AR_DOCKED)) {
return GenericNonExclusivePromise::CreateAndReject(
NS_ERROR_DOM_NOT_SUPPORTED_ERR, __func__);
}

if (!sSetDisplayAutoRotationPreferences) {
HMODULE user32dll = GetModuleHandleW(L"user32.dll");
if (user32dll) {
sSetDisplayAutoRotationPreferences =
(decltype(SetDisplayAutoRotationPreferences)*)GetProcAddress(
user32dll, "SetDisplayAutoRotationPreferences");
}
if (!sSetDisplayAutoRotationPreferences) {
return GenericNonExclusivePromise::CreateAndReject(
NS_ERROR_DOM_NOT_SUPPORTED_ERR, __func__);
}
}

ORIENTATION_PREFERENCE orientation = ORIENTATION_PREFERENCE_NONE;

if (aOrientation == hal::ScreenOrientation::Default) {
// Actually, current screen is single and tablet mode according to
// GetAutoRotationState. So get primary screen data for natural orientation.
RefPtr<widget::Screen> screen =
widget::ScreenManager::GetSingleton().GetPrimaryScreen();
hal::ScreenOrientation defaultOrientation =
screen->GetDefaultOrientationType();
if (defaultOrientation == hal::ScreenOrientation::LandscapePrimary) {
orientation = ORIENTATION_PREFERENCE_LANDSCAPE;
} else {
orientation = ORIENTATION_PREFERENCE_PORTRAIT;
}
} else {
if (aOrientation & hal::ScreenOrientation::LandscapePrimary) {
orientation |= ORIENTATION_PREFERENCE_LANDSCAPE;
}
if (aOrientation & hal::ScreenOrientation::LandscapeSecondary) {
orientation |= ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED;
}
if (aOrientation & hal::ScreenOrientation::PortraitPrimary) {
orientation |= ORIENTATION_PREFERENCE_PORTRAIT;
}
if (aOrientation & hal::ScreenOrientation::PortraitSecondary) {
orientation |= ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED;
}
}

if (!sSetDisplayAutoRotationPreferences(orientation)) {
return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_DOM_ABORT_ERR,
__func__);
}

return GenericNonExclusivePromise::CreateAndResolve(true, __func__);
}

void UnlockScreenOrientation() {
if (!sSetDisplayAutoRotationPreferences) {
return;
}
// This does nothing if the device doesn't support orientation lock
sSetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_NONE);
}

} // namespace hal_impl
} // namespace mozilla
14 changes: 14 additions & 0 deletions widget/Screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,18 @@ Screen::GetIsPseudoDisplay(bool* aIsPseudoDisplay) {
return NS_OK;
}

hal::ScreenOrientation Screen::GetDefaultOrientationType() const {
if (mRect.Width() >= mRect.Height()) {
if (mOrientationAngle == 0 || mOrientationAngle == 180) {
return hal::ScreenOrientation::LandscapePrimary;
}
return hal::ScreenOrientation::PortraitPrimary;
}

if (mOrientationAngle == 0 || mOrientationAngle == 180) {
return hal::ScreenOrientation::PortraitPrimary;
}
return hal::ScreenOrientation::LandscapePrimary;
}

} // namespace mozilla::widget
6 changes: 6 additions & 0 deletions widget/Screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ class Screen final : public nsIScreen {
return mScreenOrientation;
}

/**
* Return default orientation type that angle is 0.
* This returns LandscapePrimary or PortraitPrimary.
*/
hal::ScreenOrientation GetDefaultOrientationType() const;

float GetDPI() const { return mDPI; }

const LayoutDeviceIntRect& GetRect() const { return mRect; }
Expand Down
5 changes: 3 additions & 2 deletions widget/windows/WinUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1525,7 +1525,8 @@ WinUtils::GetPowerPlatformRole() {
return power_determine_platform_role(POWER_PLATFORM_ROLE_V2);
}

static bool CallGetAutoRotationState(AR_STATE* aRotationState) {
// static
bool WinUtils::GetAutoRotationState(AR_STATE* aRotationState) {
typedef BOOL(WINAPI * GetAutoRotationStateFunc)(PAR_STATE pState);
static GetAutoRotationStateFunc get_auto_rotation_state_func =
reinterpret_cast<GetAutoRotationStateFunc>(::GetProcAddress(
Expand Down Expand Up @@ -1564,7 +1565,7 @@ static bool IsTabletDevice() {
// a convertible or a detachable. See:
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn629263(v=vs.85).aspx
AR_STATE rotation_state;
if (CallGetAutoRotationState(&rotation_state) &&
if (WinUtils::GetAutoRotationState(&rotation_state) &&
(rotation_state & (AR_NOT_SUPPORTED | AR_LAPTOP | AR_NOSENSOR))) {
return false;
}
Expand Down
2 changes: 2 additions & 0 deletions widget/windows/WinUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,8 @@ class WinUtils {
static nsresult RestoreHiDPIMode();
#endif

static bool GetAutoRotationState(AR_STATE* aRotationState);

private:
static WhitelistVec BuildWhitelist();

Expand Down

0 comments on commit 6c25d02

Please sign in to comment.