0

[headless] Change string window state representation to enum class

This CL replaces string window state representation with more
appropriate enum class. There are no changes in behavior expected.

Change-Id: Ib46c61dbe084b927c1c03b5a268169193464c9d8
Cq-Include-Trybots: luci.chromium.try:mac12-tests,mac13-tests,mac14-tests
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6175359
Commit-Queue: Peter Kvitek <kvitekp@chromium.org>
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1407683}
This commit is contained in:
Peter Kvitek
2025-01-16 17:56:46 -08:00
committed by Chromium LUCI CQ
parent 4859a04d2e
commit e4e6310195
8 changed files with 140 additions and 43 deletions

@ -270,6 +270,7 @@ component("headless_non_renderer") {
"lib/browser/headless_screen_orientation_delegate.h",
"lib/browser/headless_web_contents_impl.cc",
"lib/browser/headless_web_contents_impl.h",
"lib/browser/headless_window_state.cc",
"lib/browser/headless_window_tree_host.h",
"lib/browser/protocol/browser_handler.cc",
"lib/browser/protocol/browser_handler.h",
@ -296,6 +297,7 @@ component("headless_non_renderer") {
"public/headless_browser_context.h",
"public/headless_export.h",
"public/headless_web_contents.h",
"public/headless_window_state.h",
"public/internal/message_dispatcher.h",
"public/internal/value_conversions.h",
"public/switches.h",

@ -390,13 +390,13 @@ HeadlessWebContentsImpl::CreateForChildContents(
// setting.
child->begin_frame_control_enabled_ = parent->begin_frame_control_enabled_;
child->InitializeWindow(child->web_contents_->GetContainerBounds(),
/*window_state=*/"normal");
HeadlessWindowState::kNormal);
return child;
}
void HeadlessWebContentsImpl::InitializeWindow(
const gfx::Rect& bounds,
const std::string& window_state) {
HeadlessWindowState window_state) {
static int window_id = 1;
window_id_ = window_id++;
@ -405,15 +405,18 @@ void HeadlessWebContentsImpl::InitializeWindow(
SetWindowState(window_state);
}
void HeadlessWebContentsImpl::SetWindowState(const std::string& state) {
if (state == "normal" || state == "maximized" || state == "fullscreen") {
web_contents_->WasShown();
} else if (state == "minimized") {
web_contents_->WasHidden();
} else {
NOTREACHED() << "Unknown window state: " << state;
void HeadlessWebContentsImpl::SetWindowState(HeadlessWindowState window_state) {
switch (window_state) {
case HeadlessWindowState::kNormal:
case HeadlessWindowState::kMaximized:
case HeadlessWindowState::kFullscreen:
web_contents_->WasShown();
break;
case HeadlessWindowState::kMinimized:
web_contents_->WasHidden();
break;
}
window_state_ = state;
window_state_ = window_state;
}
void HeadlessWebContentsImpl::SetBounds(const gfx::Rect& bounds) {
@ -548,7 +551,7 @@ HeadlessWebContents::Builder& HeadlessWebContents::Builder::SetWindowBounds(
}
HeadlessWebContents::Builder& HeadlessWebContents::Builder::SetWindowState(
std::string_view window_state) {
HeadlessWindowState window_state) {
window_state_ = window_state;
return *this;
}

@ -17,6 +17,7 @@
#include "headless/lib/browser/headless_window_tree_host.h"
#include "headless/public/headless_export.h"
#include "headless/public/headless_web_contents.h"
#include "headless/public/headless_window_state.h"
class SkBitmap;
@ -65,10 +66,10 @@ class HEADLESS_EXPORT HeadlessWebContentsImpl : public HeadlessWebContents {
return window_tree_host_.get();
}
int window_id() const { return window_id_; }
const std::string& window_state() const { return window_state_; }
HeadlessWindowState window_state() const { return window_state_; }
// Set the WebContent's platform window state and visibility.
void SetWindowState(const std::string& state);
void SetWindowState(HeadlessWindowState window_state);
// Set bounds of WebContent's platform window.
void SetBounds(const gfx::Rect& bounds);
@ -93,7 +94,7 @@ class HEADLESS_EXPORT HeadlessWebContentsImpl : public HeadlessWebContents {
std::unique_ptr<content::WebContents> web_contents);
void InitializeWindow(const gfx::Rect& bounds,
const std::string& window_state);
HeadlessWindowState window_state);
uint64_t begin_frame_sequence_number_ =
viz::BeginFrameArgs::kStartingFrameNumber;
@ -103,7 +104,7 @@ class HEADLESS_EXPORT HeadlessWebContentsImpl : public HeadlessWebContents {
std::unique_ptr<Delegate> web_contents_delegate_;
std::unique_ptr<HeadlessWindowTreeHost> window_tree_host_;
int window_id_ = 0;
std::string window_state_;
HeadlessWindowState window_state_ = HeadlessWindowState::kNormal;
std::unique_ptr<content::WebContents> const web_contents_;
class PendingFrame;

@ -0,0 +1,49 @@
// 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.
#include "headless/public/headless_window_state.h"
#include "base/containers/flat_map.h"
#include "base/no_destructor.h"
#include "headless/lib/browser/protocol/target_handler.h"
namespace headless {
std::string GetProtocolWindowState(HeadlessWindowState window_state) {
switch (window_state) {
case HeadlessWindowState::kNormal:
return protocol::Target::WindowStateEnum::Normal;
case HeadlessWindowState::kMinimized:
return protocol::Target::WindowStateEnum::Minimized;
case HeadlessWindowState::kMaximized:
return protocol::Target::WindowStateEnum::Maximized;
case HeadlessWindowState::kFullscreen:
return protocol::Target::WindowStateEnum::Fullscreen;
}
}
std::optional<HeadlessWindowState> GetWindowStateFromProtocol(
std::string_view window_state) {
static const base::NoDestructor<
base::flat_map<std::string_view, HeadlessWindowState>>
kWindowStateMap({
{protocol::Target::WindowStateEnum::Normal,
HeadlessWindowState::kNormal},
{protocol::Target::WindowStateEnum::Minimized,
HeadlessWindowState::kMinimized},
{protocol::Target::WindowStateEnum::Maximized,
HeadlessWindowState::kMaximized},
{protocol::Target::WindowStateEnum::Fullscreen,
HeadlessWindowState::kFullscreen},
});
const auto it = kWindowStateMap->find(window_state);
if (it != kWindowStateMap->cend()) {
return it->second;
}
return std::nullopt;
}
} // namespace headless

@ -10,6 +10,8 @@
#include "content/public/browser/web_contents.h"
#include "headless/lib/browser/headless_browser_impl.h"
#include "headless/lib/browser/headless_web_contents_impl.h"
#include "headless/lib/browser/protocol/target_handler.h"
#include "headless/public/headless_window_state.h"
namespace headless {
namespace protocol {
@ -24,7 +26,7 @@ std::unique_ptr<Browser::Bounds> CreateBrowserBounds(
.SetTop(bounds.y())
.SetWidth(bounds.width())
.SetHeight(bounds.height())
.SetWindowState(web_contents->window_state())
.SetWindowState(GetProtocolWindowState(web_contents->window_state()))
.Build();
}
@ -97,20 +99,30 @@ Response BrowserHandler::SetWindowBounds(
bounds.set_height(window_bounds->GetHeight(bounds.height()));
}
const std::string window_state = window_bounds->GetWindowState("normal");
if (set_bounds && window_state != "normal") {
return Response::ServerError(
"The 'minimized', 'maximized' and 'fullscreen' states cannot be "
"combined with 'left', 'top', 'width' or 'height'");
std::optional<HeadlessWindowState> headless_window_state;
if (window_bounds->HasWindowState()) {
std::string protocol_window_state = window_bounds->GetWindowState().value();
headless_window_state = GetWindowStateFromProtocol(protocol_window_state);
if (!headless_window_state) {
return Response::InvalidParams("Invalid window state: " +
protocol_window_state);
}
if (set_bounds && headless_window_state != HeadlessWindowState::kNormal) {
return Response::InvalidParams(
"The 'minimized', 'maximized' and 'fullscreen' states cannot be "
"combined with 'left', 'top', 'width' or 'height'");
}
}
if (set_bounds && web_contents->window_state() != "normal") {
return Response::ServerError(
if (set_bounds &&
web_contents->window_state() != HeadlessWindowState::kNormal) {
return Response::InvalidParams(
"To resize minimized/maximized/fullscreen window, restore it to normal "
"state first.");
}
web_contents->SetWindowState(window_state);
web_contents->SetWindowState(
headless_window_state.value_or(HeadlessWindowState::kNormal));
web_contents->SetBounds(bounds);
return Response::Success();
}

@ -11,6 +11,7 @@
#include "headless/lib/browser/headless_browser_context_impl.h"
#include "headless/lib/browser/headless_browser_impl.h"
#include "headless/lib/browser/headless_web_contents_impl.h"
#include "headless/public/headless_window_state.h"
#include "ui/gfx/geometry/rect.h"
namespace headless {
@ -49,17 +50,12 @@ Response TargetHandler::CreateTarget(
}
#endif
std::optional<HeadlessWindowState> headless_window_state;
if (window_state) {
static std::string_view kWindowStates[] = {
protocol::Target::WindowStateEnum::Normal,
protocol::Target::WindowStateEnum::Minimized,
protocol::Target::WindowStateEnum::Maximized,
protocol::Target::WindowStateEnum::Fullscreen,
};
if (std::ranges::find(kWindowStates, *window_state) ==
std::end(kWindowStates)) {
return protocol::Response::ServerError("Invalid target window state: " +
*window_state);
headless_window_state = GetWindowStateFromProtocol(*window_state);
if (!headless_window_state) {
return Response::InvalidParams("Invalid target window state: " +
*window_state);
}
}
@ -83,15 +79,19 @@ Response TargetHandler::CreateTarget(
gurl = GURL(url::kAboutBlankURL);
}
const gfx::Rect target_window_bounds(
left.value_or(0), top.value_or(0),
width.value_or(browser_->options()->window_size.width()),
height.value_or(browser_->options()->window_size.height()));
const HeadlessWindowState target_window_state =
headless_window_state.value_or(HeadlessWindowState::kNormal);
HeadlessWebContentsImpl* web_contents_impl = HeadlessWebContentsImpl::From(
context->CreateWebContentsBuilder()
.SetInitialURL(gurl)
.SetWindowBounds(gfx::Rect(
left.value_or(0), top.value_or(0),
width.value_or(browser_->options()->window_size.width()),
height.value_or(browser_->options()->window_size.height())))
.SetWindowState(
window_state.value_or(protocol::Target::WindowStateEnum::Normal))
.SetWindowBounds(target_window_bounds)
.SetWindowState(target_window_state)
.SetEnableBeginFrameControl(
enable_begin_frame_control.value_or(false))
.Build());

@ -10,6 +10,7 @@
#include "base/memory/raw_ptr.h"
#include "base/process/kill.h"
#include "headless/public/headless_export.h"
#include "headless/public/headless_window_state.h"
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
@ -53,8 +54,8 @@ class HEADLESS_EXPORT HeadlessWebContents::Builder {
// options).
Builder& SetWindowBounds(const gfx::Rect& bounds);
// Specify the initial window state. Default is 'normal'.
Builder& SetWindowState(std::string_view window_state);
// Specify the initial window state, default is kNormal.
Builder& SetWindowState(HeadlessWindowState window_state);
// Specify whether BeginFrames should be controlled via DevTools commands.
Builder& SetEnableBeginFrameControl(bool enable_begin_frame_control);
@ -75,7 +76,7 @@ class HEADLESS_EXPORT HeadlessWebContents::Builder {
GURL initial_url_ = GURL("about:blank");
gfx::Rect window_bounds_;
std::string window_state_ = "normal";
HeadlessWindowState window_state_ = HeadlessWindowState::kNormal;
bool enable_begin_frame_control_ = false;
};

@ -0,0 +1,29 @@
// 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.
#ifndef HEADLESS_PUBLIC_HEADLESS_WINDOW_STATE_H_
#define HEADLESS_PUBLIC_HEADLESS_WINDOW_STATE_H_
#include <optional>
#include <string>
#include <string_view>
namespace headless {
// Represents headless window state. Since headless does not have window
// representation the state is maintained by HeadlessWebContents.
enum class HeadlessWindowState { kNormal, kMinimized, kMaximized, kFullscreen };
// Return string window state representation for use with DevTools Protocol
// methods.
std::string GetProtocolWindowState(HeadlessWindowState window_state);
// Return enum window state representation given the DevTools Protocol string
// representation.
std::optional<HeadlessWindowState> GetWindowStateFromProtocol(
std::string_view window_state);
} // namespace headless
#endif // HEADLESS_PUBLIC_HEADLESS_WINDOW_STATE_H_