0

[headless] Add screen info rotation parameter

Screen rotation angle is exposed to the web platform as
ScreenDetailed.angle so we need a way to specify it in
--screen-info.

Drive by: tweaked isInternal comments for clarity and added
missing workArea info to ToString() result.

Change-Id: Iba7e6ce861a80fc7b67dde884967c89bdfad55fa
Cq-Include-Trybots: luci.chromium.try:mac12-tests,mac13-tests,mac14-tests
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6249675
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Commit-Queue: Peter Kvitek <kvitekp@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1418804}
This commit is contained in:
Peter Kvitek
2025-02-11 11:36:46 -08:00
committed by Chromium LUCI CQ
parent 8902e64367
commit 1369f70820
7 changed files with 90 additions and 4 deletions

@ -83,6 +83,11 @@ HeadlessScreen::HeadlessScreen(const gfx::Size& window_size,
display.UpdateWorkAreaFromInsets(it.work_area_insets);
}
if (it.rotation) {
CHECK(display::Display::IsValidRotation(it.rotation));
display.SetRotationAsDegree(it.rotation);
}
if (it.is_internal) {
internal_display_ids.insert(display.id());
}

@ -11,6 +11,7 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "third_party/re2/src/re2/re2.h"
#include "ui/display/display.h"
using re2::RE2;
@ -27,6 +28,7 @@ constexpr char kInvalidScreenIsInternal[] = "Invalid screen is internal: ";
constexpr char kInvalidScreenDevicePixelRatio[] =
"Invalid screen device pixel ratio: ";
constexpr char kInvalidWorkAreaInset[] = "Invalid work area inset: ";
constexpr char kInvalidRotation[] = "Invalid rotation: ";
// Screen Info parameters, keep in sync with window.getScreenDetails() output.
constexpr char kColorDepth[] = "colorDepth";
@ -37,6 +39,7 @@ constexpr char kWorkAreaLeft[] = "workAreaLeft";
constexpr char kWorkAreaRight[] = "workAreaRight";
constexpr char kWorkAreaTop[] = "workAreaTop";
constexpr char kWorkAreaBottom[] = "workAreaBottom";
constexpr char kRotation[] = "rotation";
constexpr int kMinColorDepth = 1;
constexpr float kMinDevicePixelRatio = 0.5f;
@ -92,7 +95,7 @@ std::string ParseScreenInfoParameter(std::string_view key,
return {};
}
// isInternal={0|1|false|true}
// isInternal=0|1|false|true
if (key == kIsInternal) {
std::optional<bool> is_internal_opt = GetBooleanParam(value);
if (!is_internal_opt) {
@ -153,6 +156,18 @@ std::string ParseScreenInfoParameter(std::string_view key,
return {};
}
// rotation=0|90|180|270
if (key == kRotation) {
int rotation;
if (!base::StringToInt(value, &rotation) ||
!display::Display::IsValidRotation(rotation)) {
return kInvalidRotation + std::string(value);
}
screen_info->rotation = rotation;
return {};
}
return kUnknownScreenInfoParam + std::string(key);
}
@ -246,9 +261,11 @@ HeadlessScreenInfo::FromString(std::string_view screen_info) {
std::string HeadlessScreenInfo::ToString() const {
return base::StringPrintf(
"%s color_depth=%d device_pixel_ratio=%g is_internal=%d label='%s'",
"%s color_depth=%d device_pixel_ratio=%g is_internal=%d label='%s' "
"workarea TLBR={%d,%d,%d,%d} rotation=%d",
bounds.ToString().c_str(), color_depth, device_pixel_ratio, is_internal,
label.c_str());
label.c_str(), work_area_insets.top(), work_area_insets.left(),
work_area_insets.bottom(), work_area_insets.right(), rotation);
}
} // namespace headless

@ -23,6 +23,7 @@ struct HEADLESS_EXPORT HeadlessScreenInfo {
float device_pixel_ratio = 1.0f;
bool is_internal = false;
std::string label;
int rotation = 0;
bool operator==(const HeadlessScreenInfo& other) const;
@ -37,12 +38,13 @@ struct HEADLESS_EXPORT HeadlessScreenInfo {
// Available named parameters:
// colorDepth=24
// devicePixelRatio=1
// isInternal=true
// isInternal=0|1|false|true
// label='primary monitor'
// workAreaLeft=0
// workAreaRight=0
// workAreaTop=0
// workAreaBottom=0
// rotation=0|90|180|270
//
// The first screen specified is assumed to be the primary screen. If origin
// is omitted for a secondary screen it will be automatically calculated to

@ -314,5 +314,29 @@ TEST(ScreenInfoTest, WorkArea) {
"Invalid work area inset: -42");
}
TEST(ScreenInfoTest, Rotation) {
EXPECT_EQ(HeadlessScreenInfo::FromString("{ rotation=0 }").value()[0],
HeadlessScreenInfo({.rotation = 0}));
EXPECT_EQ(HeadlessScreenInfo::FromString("{ rotation=90 }").value()[0],
HeadlessScreenInfo({.rotation = 90}));
EXPECT_EQ(HeadlessScreenInfo::FromString("{ rotation=180 }").value()[0],
HeadlessScreenInfo({.rotation = 180}));
EXPECT_EQ(HeadlessScreenInfo::FromString("{ rotation=270 }").value()[0],
HeadlessScreenInfo({.rotation = 270}));
// Invalid.
EXPECT_THAT(HeadlessScreenInfo::FromString("{ rotation=abc }").error(),
"Invalid rotation: abc");
EXPECT_THAT(HeadlessScreenInfo::FromString("{ rotation=-42 }").error(),
"Invalid rotation: -42");
EXPECT_THAT(HeadlessScreenInfo::FromString("{ rotation=42 }").error(),
"Invalid rotation: 42");
}
} // namespace
} // namespace headless

@ -0,0 +1,3 @@
Tests screen rotation angle.
Screen: 0,0 800x600
angle: 180

@ -0,0 +1,30 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(async function(testRunner) {
const {session, dp} =
await testRunner.startBlank('Tests screen rotation angle.');
const HttpInterceptor =
await testRunner.loadScript('../helpers/http-interceptor.js');
const httpInterceptor = await (new HttpInterceptor(testRunner, dp)).init();
httpInterceptor.setDisableRequestedUrlsLogging(true);
httpInterceptor.addResponse(
'https://example.com/index.html', `<html></html>`);
await dp.Browser.grantPermissions({permissions: ['windowManagement']});
await session.navigate('https://example.com/index.html');
const result = await session.evaluateAsync(async () => {
const cs = (await getScreenDetails()).currentScreen;
return `Screen: ${cs.left},${cs.top} ${cs.width}x${cs.height}\n` +
`angle: ${cs.orientation.angle}`;
});
testRunner.log(result);
testRunner.completeTest();
})

@ -682,6 +682,11 @@ HEADLESS_PROTOCOL_TEST_WITH_COMMAND_LINE_EXTRAS(
"sanity/screen-size-orientation.js",
"--screen-info={600x800}")
HEADLESS_PROTOCOL_TEST_WITH_COMMAND_LINE_EXTRAS(
ScreenRotationAngle,
"sanity/screen-rotation-angle.js",
"--screen-info={rotation=180}")
HEADLESS_PROTOCOL_TEST_WITH_COMMAND_LINE_EXTRAS(
ScreenOrientationLockNaturalLandscape,
"sanity/screen-orientation-lock-natural-landscape.js",