From 3dbf8deeb8a9f72ae073f8cc65b9aa7d16b857eb Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Thu, 24 Nov 2022 15:10:15 +0000 Subject: [PATCH] Bug 1744687 - Part 1. Lock orientation backend for Windows Tablet. r=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 --- hal/moz.build | 2 +- hal/windows/WindowsScreenConfiguration.cpp | 98 ++++++++++++++++++++++ widget/Screen.cpp | 14 ++++ widget/Screen.h | 6 ++ widget/windows/WinUtils.cpp | 5 +- widget/windows/WinUtils.h | 2 + 6 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 hal/windows/WindowsScreenConfiguration.cpp diff --git a/hal/moz.build b/hal/moz.build index 0dcac7690171..43b93290da37 100644 --- a/hal/moz.build +++ b/hal/moz.build @@ -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. diff --git a/hal/windows/WindowsScreenConfiguration.cpp b/hal/windows/WindowsScreenConfiguration.cpp new file mode 100644 index 000000000000..27843ede8c76 --- /dev/null +++ b/hal/windows/WindowsScreenConfiguration.cpp @@ -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 + +namespace mozilla { +namespace hal_impl { + +static decltype(SetDisplayAutoRotationPreferences)* + sSetDisplayAutoRotationPreferences = nullptr; + +RefPtr 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 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 diff --git a/widget/Screen.cpp b/widget/Screen.cpp index 19a95acba522..f9bfa86402a0 100644 --- a/widget/Screen.cpp +++ b/widget/Screen.cpp @@ -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 diff --git a/widget/Screen.h b/widget/Screen.h index 056a45a51d7f..f3f8b4a628af 100644 --- a/widget/Screen.h +++ b/widget/Screen.h @@ -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; } diff --git a/widget/windows/WinUtils.cpp b/widget/windows/WinUtils.cpp index 9b76019e287d..c531e17a3449 100644 --- a/widget/windows/WinUtils.cpp +++ b/widget/windows/WinUtils.cpp @@ -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(::GetProcAddress( @@ -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; } diff --git a/widget/windows/WinUtils.h b/widget/windows/WinUtils.h index 6e85e083b463..b7a53ce7d323 100644 --- a/widget/windows/WinUtils.h +++ b/widget/windows/WinUtils.h @@ -608,6 +608,8 @@ class WinUtils { static nsresult RestoreHiDPIMode(); #endif + static bool GetAutoRotationState(AR_STATE* aRotationState); + private: static WhitelistVec BuildWhitelist();