[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:

committed by
Chromium LUCI CQ

parent
8902e64367
commit
1369f70820
@ -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
|
30
headless/test/data/protocol/sanity/screen-rotation-angle.js
Normal file
30
headless/test/data/protocol/sanity/screen-rotation-angle.js
Normal file
@ -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",
|
||||
|
Reference in New Issue
Block a user