Commit eb0f3b02 authored by skyostil's avatar skyostil Committed by Commit bot

Implement a runtime headless mode for Linux

This patch implements a runtime headless mode (i.e., a
--headless command line switch) that makes it possible to
use a regular Chrome binary as a headless. When the binary
is launched with this switch, the main entrypoint calls
into the Headless Shell entrypoint, effectively starting
that shell instead of Chrome.

To make this possible we must remove the dependency from
Headless to Ozone, because Ozone is a build-time feature
which is generally not enabled for regular Chrome builds.
In practice this means implementing a new headless-specific
WindowTreeHost and modifying various graphics and input
entrypoints to do something appropriate in headless mode.

Since many of the modifications are in platform-specific
code, this initial patch only adds headless support in Linux.
Other platforms will be added later.

Design doc: https://docs.google.com/document/d/1aIJUzQr3eougZQp90bp4mqGr5gY6hdUice8UPa-Ys90/edit#

BUG=612904
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel

Review-Url: https://codereview.chromium.org/1991953002
Cr-Commit-Position: refs/heads/master@{#438152}
parent 58741900
...@@ -239,6 +239,9 @@ if (!is_android && !is_mac) { ...@@ -239,6 +239,9 @@ if (!is_android && !is_mac) {
# Needed to use the master_preferences functions # Needed to use the master_preferences functions
"//chrome/installer/util:with_no_strings", "//chrome/installer/util:with_no_strings",
"//content/public/app:both", "//content/public/app:both",
# For headless mode.
"//headless:headless_shell_lib",
] ]
if (enable_plugins && enable_pdf) { if (enable_plugins && enable_pdf) {
deps += [ "//pdf" ] deps += [ "//pdf" ]
......
...@@ -29,6 +29,7 @@ include_rules = [ ...@@ -29,6 +29,7 @@ include_rules = [
"+content/public/app", "+content/public/app",
"+content/public/browser/browser_main_runner.h", "+content/public/browser/browser_main_runner.h",
"+extensions/common/constants.h", "+extensions/common/constants.h",
"+headless/public", # For headless mode.
"+native_client/src/trusted/service_runtime/osx", "+native_client/src/trusted/service_runtime/osx",
"+remoting/client/plugin", "+remoting/client/plugin",
"+sandbox", "+sandbox",
......
...@@ -5,13 +5,16 @@ ...@@ -5,13 +5,16 @@
#include <stdint.h> #include <stdint.h>
#include "build/build_config.h" #include "build/build_config.h"
#include "base/command_line.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/app/chrome_main_delegate.h" #include "chrome/app/chrome_main_delegate.h"
#include "chrome/common/features.h" #include "chrome/common/features.h"
#include "content/public/app/content_main.h" #include "content/public/app/content_main.h"
#include "content/public/common/content_switches.h"
#include "headless/public/headless_shell.h"
#include "ui/gfx/switches.h"
#if BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES) #if BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
#include "base/command_line.h"
#include "chrome/app/mash/mash_runner.h" #include "chrome/app/mash/mash_runner.h"
#include "chrome/common/channel_info.h" #include "chrome/common/channel_info.h"
#include "components/version_info/version_info.h" #include "components/version_info/version_info.h"
...@@ -82,17 +85,22 @@ int ChromeMain(int argc, const char** argv) { ...@@ -82,17 +85,22 @@ int ChromeMain(int argc, const char** argv) {
params.argv = argv; params.argv = argv;
#endif #endif
#if BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
#if !defined(OS_WIN) #if !defined(OS_WIN)
base::CommandLine::Init(params.argc, params.argv); base::CommandLine::Init(params.argc, params.argv);
const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
ALLOW_UNUSED_LOCAL(command_line);
#endif #endif
#if defined(OS_LINUX)
if (command_line->HasSwitch(switches::kHeadless))
return headless::HeadlessShellMain(argc, argv);
#endif // defined(OS_LINUX)
#if BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
version_info::Channel channel = chrome::GetChannel(); version_info::Channel channel = chrome::GetChannel();
if (channel == version_info::Channel::CANARY || if (channel == version_info::Channel::CANARY ||
channel == version_info::Channel::UNKNOWN) { channel == version_info::Channel::UNKNOWN) {
const base::CommandLine& command_line = if (command_line->HasSwitch("mash"))
*base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch("mash"))
return MashMain(); return MashMain();
WaitForMashDebuggerIfNecessary(); WaitForMashDebuggerIfNecessary();
} }
......
...@@ -105,6 +105,7 @@ ...@@ -105,6 +105,7 @@
#include "skia/ext/skia_memory_dump_provider.h" #include "skia/ext/skia_memory_dump_provider.h"
#include "sql/sql_memory_dump_provider.h" #include "sql/sql_memory_dump_provider.h"
#include "ui/base/clipboard/clipboard.h" #include "ui/base/clipboard/clipboard.h"
#include "ui/gfx/switches.h"
#if defined(USE_AURA) || defined(OS_MACOSX) #if defined(USE_AURA) || defined(OS_MACOSX)
#include "content/browser/compositor/image_transport_factory.h" #include "content/browser/compositor/image_transport_factory.h"
...@@ -463,6 +464,8 @@ class GpuDataManagerVisualProxy : public GpuDataManagerObserver { ...@@ -463,6 +464,8 @@ class GpuDataManagerVisualProxy : public GpuDataManagerObserver {
} }
void OnGpuInfoUpdate() override { void OnGpuInfoUpdate() override {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
return;
gpu::GPUInfo gpu_info = gpu_data_manager_->GetGPUInfo(); gpu::GPUInfo gpu_info = gpu_data_manager_->GetGPUInfo();
if (!ui::XVisualManager::GetInstance()->OnGPUInfoChanged( if (!ui::XVisualManager::GetInstance()->OnGPUInfoChanged(
gpu_info.software_rendering || gpu_info.software_rendering ||
...@@ -1569,7 +1572,8 @@ bool BrowserMainLoop::InitializeToolkit() { ...@@ -1569,7 +1572,8 @@ bool BrowserMainLoop::InitializeToolkit() {
#if defined(USE_AURA) #if defined(USE_AURA)
#if defined(USE_X11) #if defined(USE_X11)
if (!gfx::GetXDisplay()) { if (!parsed_command_line_.HasSwitch(switches::kHeadless) &&
!gfx::GetXDisplay()) {
LOG(ERROR) << "Unable to open X display."; LOG(ERROR) << "Unable to open X display.";
return false; return false;
} }
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#include "ui/compositor/layer.h" #include "ui/compositor/layer.h"
#include "ui/display/types/display_snapshot.h" #include "ui/display/types/display_snapshot.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
#include "ui/gfx/switches.h"
#if defined(USE_AURA) #if defined(USE_AURA)
#include "content/browser/compositor/mus_browser_compositor_output_surface.h" #include "content/browser/compositor/mus_browser_compositor_output_surface.h"
...@@ -196,6 +197,10 @@ GpuProcessTransportFactory::~GpuProcessTransportFactory() { ...@@ -196,6 +197,10 @@ GpuProcessTransportFactory::~GpuProcessTransportFactory() {
std::unique_ptr<cc::SoftwareOutputDevice> std::unique_ptr<cc::SoftwareOutputDevice>
GpuProcessTransportFactory::CreateSoftwareOutputDevice( GpuProcessTransportFactory::CreateSoftwareOutputDevice(
ui::Compositor* compositor) { ui::Compositor* compositor) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kHeadless))
return base::WrapUnique(new cc::SoftwareOutputDevice);
#if defined(USE_AURA) #if defined(USE_AURA)
if (service_manager::ServiceManagerIsRemote()) { if (service_manager::ServiceManagerIsRemote()) {
NOTREACHED(); NOTREACHED();
...@@ -260,6 +265,10 @@ CreateOverlayCandidateValidator(gfx::AcceleratedWidget widget) { ...@@ -260,6 +265,10 @@ CreateOverlayCandidateValidator(gfx::AcceleratedWidget widget) {
} }
static bool ShouldCreateGpuCompositorFrameSink(ui::Compositor* compositor) { static bool ShouldCreateGpuCompositorFrameSink(ui::Compositor* compositor) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kHeadless))
return false;
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
// Software fallback does not happen on Chrome OS. // Software fallback does not happen on Chrome OS.
return true; return true;
......
...@@ -68,6 +68,7 @@ ...@@ -68,6 +68,7 @@
#include "services/service_manager/runner/common/client_util.h" #include "services/service_manager/runner/common/client_util.h"
#include "ui/base/ui_base_switches.h" #include "ui/base/ui_base_switches.h"
#include "ui/events/latency_info.h" #include "ui/events/latency_info.h"
#include "ui/gfx/switches.h"
#include "ui/gl/gl_switches.h" #include "ui/gl/gl_switches.h"
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
...@@ -134,6 +135,7 @@ static const char* const kSwitchNames[] = { ...@@ -134,6 +135,7 @@ static const char* const kSwitchNames[] = {
switches::kGpuSandboxAllowSysVShm, switches::kGpuSandboxAllowSysVShm,
switches::kGpuSandboxFailuresFatal, switches::kGpuSandboxFailuresFatal,
switches::kGpuSandboxStartEarly, switches::kGpuSandboxStartEarly,
switches::kHeadless,
switches::kLoggingLevel, switches::kLoggingLevel,
switches::kEnableLowEndDeviceMode, switches::kEnableLowEndDeviceMode,
switches::kDisableLowEndDeviceMode, switches::kDisableLowEndDeviceMode,
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h" #include "content/public/common/result_codes.h"
#include "ui/display/display_switches.h" #include "ui/display/display_switches.h"
#include "ui/gfx/switches.h"
namespace content { namespace content {
...@@ -252,6 +253,9 @@ void ZygoteCommunication::Init() { ...@@ -252,6 +253,9 @@ void ZygoteCommunication::Init() {
switches::kDisableSeccompFilterSandbox, switches::kDisableSeccompFilterSandbox,
switches::kEnableHeapProfiling, switches::kEnableHeapProfiling,
switches::kEnableLogging, // Support, e.g., --enable-logging=stderr. switches::kEnableLogging, // Support, e.g., --enable-logging=stderr.
// Need to tell the zygote that it is headless so that we don't try to use
// the wrong type of main delegate.
switches::kHeadless,
// Zygote process needs to know what resources to have loaded when it // Zygote process needs to know what resources to have loaded when it
// becomes a renderer process. // becomes a renderer process.
switches::kForceDeviceScaleFactor, switches::kLoggingLevel, switches::kForceDeviceScaleFactor, switches::kLoggingLevel,
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "gpu/ipc/service/gpu_memory_buffer_factory.h" #include "gpu/ipc/service/gpu_memory_buffer_factory.h"
#include "gpu/ipc/service/gpu_watchdog_thread.h" #include "gpu/ipc/service/gpu_watchdog_thread.h"
#include "ui/events/platform/platform_event_source.h" #include "ui/events/platform/platform_event_source.h"
#include "ui/gfx/switches.h"
#include "ui/gl/gl_context.h" #include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h" #include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h" #include "ui/gl/gl_surface.h"
...@@ -200,35 +201,39 @@ int GpuMain(const MainFunctionParams& parameters) { ...@@ -200,35 +201,39 @@ int GpuMain(const MainFunctionParams& parameters) {
// TODO(ericrk): Revisit this once we assess its impact on crbug.com/662802 // TODO(ericrk): Revisit this once we assess its impact on crbug.com/662802
// and crbug.com/609252. // and crbug.com/609252.
std::unique_ptr<base::MessageLoop> main_message_loop; std::unique_ptr<base::MessageLoop> main_message_loop;
if (command_line.HasSwitch(switches::kHeadless)) {
main_message_loop.reset(
new base::MessageLoop(base::MessageLoop::TYPE_DEFAULT));
} else {
#if defined(OS_WIN) #if defined(OS_WIN)
// OK to use default non-UI message loop because all GPU windows run on // OK to use default non-UI message loop because all GPU windows run on
// dedicated thread. // dedicated thread.
main_message_loop.reset( main_message_loop.reset(
new base::MessageLoop(base::MessageLoop::TYPE_DEFAULT)); new base::MessageLoop(base::MessageLoop::TYPE_DEFAULT));
#elif defined(USE_X11) #elif defined(USE_X11)
// We need a UI loop so that we can grab the Expose events. See GLSurfaceGLX // We need a UI loop so that we can grab the Expose events. See GLSurfaceGLX
// and https://crbug.com/326995. // and https://crbug.com/326995.
main_message_loop.reset(new base::MessageLoop(base::MessageLoop::TYPE_UI)); main_message_loop.reset(new base::MessageLoop(base::MessageLoop::TYPE_UI));
std::unique_ptr<ui::PlatformEventSource> event_source = std::unique_ptr<ui::PlatformEventSource> event_source =
ui::PlatformEventSource::CreateDefault(); ui::PlatformEventSource::CreateDefault();
#elif defined(USE_OZONE) && defined(OZONE_X11) #elif defined(USE_OZONE) && defined(OZONE_X11)
// If we might be running Ozone X11 we need a UI loop to grab Expose events. // If we might be running Ozone X11 we need a UI loop to grab Expose events.
// See GLSurfaceGLX and https://crbug.com/326995. // See GLSurfaceGLX and https://crbug.com/326995.
main_message_loop.reset(new base::MessageLoop(base::MessageLoop::TYPE_UI)); main_message_loop.reset(new base::MessageLoop(base::MessageLoop::TYPE_UI));
#elif defined(USE_OZONE) #elif defined(USE_OZONE)
main_message_loop.reset( main_message_loop.reset(
new base::MessageLoop(base::MessageLoop::TYPE_DEFAULT)); new base::MessageLoop(base::MessageLoop::TYPE_DEFAULT));
#elif defined(OS_LINUX) #elif defined(OS_LINUX)
#error "Unsupported Linux platform." #error "Unsupported Linux platform."
#elif defined(OS_MACOSX) #elif defined(OS_MACOSX)
// This is necessary for CoreAnimation layers hosted in the GPU process to be // This is necessary for CoreAnimation layers hosted in the GPU process to
// drawn. See http://crbug.com/312462. // be drawn. See http://crbug.com/312462.
std::unique_ptr<base::MessagePump> pump(new base::MessagePumpCFRunLoop()); std::unique_ptr<base::MessagePump> pump(new base::MessagePumpCFRunLoop());
main_message_loop.reset(new base::MessageLoop(std::move(pump))); main_message_loop.reset(new base::MessageLoop(std::move(pump)));
#else #else
main_message_loop.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO)); main_message_loop.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO));
#endif #endif
}
base::PlatformThread::SetName("CrGpuMain"); base::PlatformThread::SetName("CrGpuMain");
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "gpu/config/gpu_util.h" #include "gpu/config/gpu_util.h"
#include "gpu/ipc/service/gpu_watchdog_thread.h" #include "gpu/ipc/service/gpu_watchdog_thread.h"
#include "gpu/ipc/service/switches.h" #include "gpu/ipc/service/switches.h"
#include "ui/gfx/switches.h"
#include "ui/gl/gl_implementation.h" #include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_switches.h" #include "ui/gl/gl_switches.h"
#include "ui/gl/init/gl_factory.h" #include "ui/gl/init/gl_factory.h"
...@@ -127,6 +128,7 @@ bool GpuInit::InitializeAndStartSandbox(const base::CommandLine& command_line) { ...@@ -127,6 +128,7 @@ bool GpuInit::InitializeAndStartSandbox(const base::CommandLine& command_line) {
// to run slowly in that case. // to run slowly in that case.
bool enable_watchdog = bool enable_watchdog =
!command_line.HasSwitch(switches::kDisableGpuWatchdog) && !command_line.HasSwitch(switches::kDisableGpuWatchdog) &&
!command_line.HasSwitch(switches::kHeadless) &&
!RunningOnValgrind(); !RunningOnValgrind();
// Disable the watchdog in debug builds because they tend to only be run by // Disable the watchdog in debug builds because they tend to only be run by
......
...@@ -167,6 +167,8 @@ static_library("headless_lib") { ...@@ -167,6 +167,8 @@ static_library("headless_lib") {
"lib/browser/headless_devtools_client_impl.h", "lib/browser/headless_devtools_client_impl.h",
"lib/browser/headless_devtools_manager_delegate.cc", "lib/browser/headless_devtools_manager_delegate.cc",
"lib/browser/headless_devtools_manager_delegate.h", "lib/browser/headless_devtools_manager_delegate.h",
"lib/browser/headless_platform_event_source.cc",
"lib/browser/headless_platform_event_source.h",
"lib/browser/headless_screen.cc", "lib/browser/headless_screen.cc",
"lib/browser/headless_screen.h", "lib/browser/headless_screen.h",
"lib/browser/headless_url_request_context_getter.cc", "lib/browser/headless_url_request_context_getter.cc",
...@@ -175,14 +177,12 @@ static_library("headless_lib") { ...@@ -175,14 +177,12 @@ static_library("headless_lib") {
"lib/browser/headless_web_contents_impl.h", "lib/browser/headless_web_contents_impl.h",
"lib/browser/headless_window_parenting_client.cc", "lib/browser/headless_window_parenting_client.cc",
"lib/browser/headless_window_parenting_client.h", "lib/browser/headless_window_parenting_client.h",
"lib/browser/headless_window_tree_host.cc",
"lib/browser/headless_window_tree_host.h",
"lib/headless_content_client.cc", "lib/headless_content_client.cc",
"lib/headless_content_client.h", "lib/headless_content_client.h",
"lib/headless_content_main_delegate.cc", "lib/headless_content_main_delegate.cc",
"lib/headless_content_main_delegate.h", "lib/headless_content_main_delegate.h",
"lib/renderer/headless_content_renderer_client.cc",
"lib/renderer/headless_content_renderer_client.h",
"lib/utility/headless_content_utility_client.cc",
"lib/utility/headless_content_utility_client.h",
"public/headless_browser.cc", "public/headless_browser.cc",
"public/headless_browser.h", "public/headless_browser.h",
"public/headless_browser_context.h", "public/headless_browser_context.h",
...@@ -232,11 +232,8 @@ static_library("headless_lib") { ...@@ -232,11 +232,8 @@ static_library("headless_lib") {
"//components/security_state/core", "//components/security_state/core",
"//content/public/app:both", "//content/public/app:both",
"//content/public/browser", "//content/public/browser",
"//content/public/child",
"//content/public/common", "//content/public/common",
"//content/public/common:service_names", "//content/public/common:service_names",
"//content/public/renderer",
"//content/public/utility",
"//net", "//net",
"//services/service_manager/public/cpp", "//services/service_manager/public/cpp",
"//third_party/mesa:osmesa", "//third_party/mesa:osmesa",
...@@ -244,10 +241,14 @@ static_library("headless_lib") { ...@@ -244,10 +241,14 @@ static_library("headless_lib") {
"//ui/base", "//ui/base",
"//ui/compositor", "//ui/compositor",
"//ui/display", "//ui/display",
"//ui/ozone", "//ui/events/devices",
"//url", "//url",
] ]
if (use_ozone) {
deps += [ "//ui/ozone" ]
}
configs += [ ":headless_implementation" ] configs += [ ":headless_implementation" ]
} }
......
include_rules = [ include_rules = [
"+content/public", "+content/public/app",
"+content/public/browser",
"+content/public/common",
"+content/public/test",
"+mojo/public", "+mojo/public",
"+net", "+net",
"+ui/base", "+ui/base",
"+ui/base/resource", "+ui/base/resource",
"+ui/display", "+ui/display",
"+ui/events/devices",
"+ui/events/platform",
"+ui/gfx", "+ui/gfx",
"+ui/gfx/geometry", "+ui/gfx/geometry",
"+ui/gl", "+ui/gl",
......
...@@ -69,6 +69,7 @@ web pages. Its main classes are: ...@@ -69,6 +69,7 @@ web pages. Its main classes are:
## Documentation ## Documentation
* [Runtime headless mode for Chrome](https://docs.google.com/document/d/1aIJUzQr3eougZQp90bp4mqGr5gY6hdUice8UPa-Ys90/edit#)
* [Virtual Time in Blink](https://docs.google.com/document/d/1y9kdt_zezt7pbey6uzvt1dgklwc1ob_vy4nzo1zbqmo/edit#heading=h.tn3gd1y9ifml) * [Virtual Time in Blink](https://docs.google.com/document/d/1y9kdt_zezt7pbey6uzvt1dgklwc1ob_vy4nzo1zbqmo/edit#heading=h.tn3gd1y9ifml)
* [Headless Chrome architecture](https://docs.google.com/document/d/11zIkKkLBocofGgoTeeyibB2TZ_k7nR78v7kNelCatUE/edit) * [Headless Chrome architecture](https://docs.google.com/document/d/11zIkKkLBocofGgoTeeyibB2TZ_k7nR78v7kNelCatUE/edit)
* [Headless Chrome C++ DevTools API](https://docs.google.com/document/d/1rlqcp8nk-ZQvldNJWdbaMbwfDbJoOXvahPCDoPGOwhQ/edit#heading=h.ng2bxb15li9a) * [Headless Chrome C++ DevTools API](https://docs.google.com/document/d/1rlqcp8nk-ZQvldNJWdbaMbwfDbJoOXvahPCDoPGOwhQ/edit#heading=h.ng2bxb15li9a)
......
...@@ -19,9 +19,10 @@ ...@@ -19,9 +19,10 @@
#include "headless/lib/browser/headless_browser_main_parts.h" #include "headless/lib/browser/headless_browser_main_parts.h"
#include "headless/lib/browser/headless_web_contents_impl.h" #include "headless/lib/browser/headless_web_contents_impl.h"
#include "headless/lib/browser/headless_window_parenting_client.h" #include "headless/lib/browser/headless_window_parenting_client.h"
#include "headless/lib/browser/headless_window_tree_host.h"
#include "headless/lib/headless_content_main_delegate.h" #include "headless/lib/headless_content_main_delegate.h"
#include "ui/aura/env.h" #include "ui/aura/env.h"
#include "ui/aura/window_tree_host.h" #include "ui/events/devices/device_data_manager.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
namespace headless { namespace headless {
...@@ -119,8 +120,10 @@ void HeadlessBrowserImpl::set_browser_main_parts( ...@@ -119,8 +120,10 @@ void HeadlessBrowserImpl::set_browser_main_parts(
void HeadlessBrowserImpl::RunOnStartCallback() { void HeadlessBrowserImpl::RunOnStartCallback() {
DCHECK(aura::Env::GetInstance()); DCHECK(aura::Env::GetInstance());
ui::DeviceDataManager::CreateInstance();
window_tree_host_.reset( window_tree_host_.reset(
aura::WindowTreeHost::Create(gfx::Rect(options()->window_size))); new HeadlessWindowTreeHost(gfx::Rect(options()->window_size)));
window_tree_host_->InitHost(); window_tree_host_->InitHost();
window_parenting_client_.reset( window_parenting_client_.reset(
......
// Copyright 2015 The Chromium Authors. All rights reserved. // Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "headless/lib/utility/headless_content_utility_client.h" #include "headless/lib/browser/headless_platform_event_source.h"
namespace headless { namespace headless {
HeadlessContentUtilityClient::HeadlessContentUtilityClient() {} HeadlessPlatformEventSource::HeadlessPlatformEventSource() {}
HeadlessContentUtilityClient::~HeadlessContentUtilityClient() {} HeadlessPlatformEventSource::~HeadlessPlatformEventSource() {}
} // namespace headless } // namespace headless
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef HEADLESS_LIB_BROWSER_HEADLESS_PLATFORM_EVENT_SOURCE_H_
#define HEADLESS_LIB_BROWSER_HEADLESS_PLATFORM_EVENT_SOURCE_H_
#include "base/macros.h"
#include "ui/events/platform/platform_event_source.h"
namespace headless {
// A stub event source whose main purpose is to prevent the default platform
// event source from getting created.
class HeadlessPlatformEventSource : public ui::PlatformEventSource {
public:
HeadlessPlatformEventSource();
~HeadlessPlatformEventSource() override;
private:
DISALLOW_COPY_AND_ASSIGN(HeadlessPlatformEventSource);
};
} // namespace headless
#endif // HEADLESS_LIB_BROWSER_HEADLESS_PLATFORM_EVENT_SOURCE_H_
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/bindings_policy.h" #include "content/public/common/bindings_policy.h"
#include "content/public/common/origin_util.h" #include "content/public/common/origin_util.h"
#include "content/public/renderer/render_frame.h"
#include "headless/lib/browser/headless_browser_context_impl.h" #include "headless/lib/browser/headless_browser_context_impl.h"
#include "headless/lib/browser/headless_browser_impl.h" #include "headless/lib/browser/headless_browser_impl.h"
#include "headless/lib/browser/headless_browser_main_parts.h" #include "headless/lib/browser/headless_browser_main_parts.h"
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "headless/lib/browser/headless_window_tree_host.h"
#include "ui/gfx/icc_profile.h"
namespace headless {
HeadlessWindowTreeHost::HeadlessWindowTreeHost(const gfx::Rect& bounds)
: bounds_(bounds) {
CreateCompositor();
OnAcceleratedWidgetAvailable();
}
HeadlessWindowTreeHost::~HeadlessWindowTreeHost() {
DestroyCompositor();
DestroyDispatcher();
}
bool HeadlessWindowTreeHost::CanDispatchEvent(const ui::PlatformEvent& event) {
return false;
}
uint32_t HeadlessWindowTreeHost::DispatchEvent(const ui::PlatformEvent& event) {
return 0;
}
ui::EventSource* HeadlessWindowTreeHost::GetEventSource() {
return this;
}
gfx::AcceleratedWidget HeadlessWindowTreeHost::GetAcceleratedWidget() {
return gfx::AcceleratedWidget();
}
gfx::Rect HeadlessWindowTreeHost::GetBoundsInPixels() const {
return bounds_;
}
void HeadlessWindowTreeHost::SetBoundsInPixels(const gfx::Rect& bounds) {
bool origin_changed = bounds_.origin() != bounds.origin();
bool size_changed = bounds_.size() != bounds.size();
bounds_ = bounds;
if (origin_changed)
OnHostMovedInPixels(bounds.origin());
if (size_changed)
OnHostResizedInPixels(bounds.size());
}
void HeadlessWindowTreeHost::ShowImpl() {}
void HeadlessWindowTreeHost::HideImpl() {}
gfx::Point HeadlessWindowTreeHost::GetLocationOnScreenInPixels() const {
return gfx::Point();
}
void HeadlessWindowTreeHost::SetCapture() {}
void HeadlessWindowTreeHost::ReleaseCapture() {}
void HeadlessWindowTreeHost::SetCursorNative(gfx::NativeCursor cursor_type) {}
void HeadlessWindowTreeHost::MoveCursorToScreenLocationInPixels(
const gfx::Point& location) {}
void HeadlessWindowTreeHost::OnCursorVisibilityChangedNative(bool show) {}
gfx::ICCProfile HeadlessWindowTreeHost::GetICCProfileForCurrentDisplay() {
return gfx::ICCProfile();
}
} // namespace headless
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef HEADLESS_LIB_BROWSER_HEADLESS_WINDOW_TREE_HOST_H_
#define HEADLESS_LIB_BROWSER_HEADLESS_WINDOW_TREE_HOST_H_
#include "base/macros.h"
#include "ui/aura/window_tree_host.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/geometry/rect.h"
namespace headless {
class HeadlessWindowTreeHost : public aura::WindowTreeHost,
public ui::PlatformEventDispatcher {
public:
explicit HeadlessWindowTreeHost(const gfx::Rect& bounds);
~HeadlessWindowTreeHost() override;
// ui::PlatformEventDispatcher:
bool CanDispatchEvent(const ui::PlatformEvent& event) override;
uint32_t DispatchEvent(const ui::PlatformEvent& event) override;
// WindowTreeHost:
ui::EventSource* GetEventSource() override;
gfx::AcceleratedWidget GetAcceleratedWidget() override;
void ShowImpl() override;
void HideImpl() override;
gfx::Rect GetBoundsInPixels() const override;
void SetBoundsInPixels(const gfx::Rect& bounds) override;
gfx::Point GetLocationOnScreenInPixels() const override;
void SetCapture() override;
void ReleaseCapture() override;
void SetCursorNative(gfx::NativeCursor cursor_type) override;
void MoveCursorToScreenLocationInPixels(const gfx::Point& location) override;
void OnCursorVisibilityChangedNative(bool show) override;
gfx::ICCProfile GetICCProfileForCurrentDisplay() override;
private:
gfx::Rect bounds_;
DISALLOW_COPY_AND_ASSIGN(HeadlessWindowTreeHost);
};
} // namespace headless
#endif // HEADLESS_LIB_BROWSER_HEADLESS_WINDOW_TREE_HOST_H_
...@@ -12,9 +12,8 @@ ...@@ -12,9 +12,8 @@
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "headless/lib/browser/headless_browser_impl.h" #include "headless/lib/browser/headless_browser_impl.h"
#include "headless/lib/browser/headless_content_browser_client.h" #include "headless/lib/browser/headless_content_browser_client.h"
#include "headless/lib/renderer/headless_content_renderer_client.h"
#include "headless/lib/utility/headless_content_utility_client.h"
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/switches.h"
#include "ui/gl/gl_switches.h" #include "ui/gl/gl_switches.h"
#include "ui/ozone/public/ozone_switches.h" #include "ui/ozone/public/ozone_switches.h"
...@@ -42,15 +41,21 @@ HeadlessContentMainDelegate::~HeadlessContentMainDelegate() { ...@@ -42,15 +41,21 @@ HeadlessContentMainDelegate::~HeadlessContentMainDelegate() {
bool HeadlessContentMainDelegate::BasicStartupComplete(int* exit_code) { bool HeadlessContentMainDelegate::BasicStartupComplete(int* exit_code) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
// Make sure all processes know that we're in headless mode.
if (!command_line->HasSwitch(switches::kHeadless))
command_line->AppendSwitch(switches::kHeadless);
if (browser_->options()->single_process_mode) if (browser_->options()->single_process_mode)
command_line->AppendSwitch(switches::kSingleProcess); command_line->AppendSwitch(switches::kSingleProcess);
if (browser_->options()->disable_sandbox) if (browser_->options()->disable_sandbox)
command_line->AppendSwitch(switches::kNoSandbox); command_line->AppendSwitch(switches::kNoSandbox);
#if defined(USE_OZONE)
// The headless backend is automatically chosen for a headless build, but also // The headless backend is automatically chosen for a headless build, but also
// adding it here allows us to run in a non-headless build too. // adding it here allows us to run in a non-headless build too.
command_line->AppendSwitchASCII(switches::kOzonePlatform, "headless"); command_line->AppendSwitchASCII(switches::kOzonePlatform, "headless");
#endif
if (!browser_->options()->gl_implementation.empty()) { if (!browser_->options()->gl_implementation.empty()) {
command_line->AppendSwitchASCII(switches::kUseGL, command_line->AppendSwitchASCII(switches::kUseGL,
...@@ -117,16 +122,4 @@ HeadlessContentMainDelegate::CreateContentBrowserClient() { ...@@ -117,16 +122,4 @@ HeadlessContentMainDelegate::CreateContentBrowserClient() {
return browser_client_.get(); return browser_client_.get();
} }
content::ContentRendererClient*
HeadlessContentMainDelegate::CreateContentRendererClient() {
renderer_client_.reset(new HeadlessContentRendererClient);
return renderer_client_.get();
}
content::ContentUtilityClient*
HeadlessContentMainDelegate::CreateContentUtilityClient() {
utility_client_.reset(new HeadlessContentUtilityClient);
return utility_client_.get();
}
} // namespace headless } // namespace headless
...@@ -10,14 +10,13 @@ ...@@ -10,14 +10,13 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/macros.h" #include "base/macros.h"
#include "content/public/app/content_main_delegate.h" #include "content/public/app/content_main_delegate.h"
#include "headless/lib/browser/headless_platform_event_source.h"
#include "headless/lib/headless_content_client.h" #include "headless/lib/headless_content_client.h"
namespace headless { namespace headless {
class HeadlessBrowserImpl; class HeadlessBrowserImpl;
class HeadlessContentBrowserClient; class HeadlessContentBrowserClient;
class HeadlessContentUtilityClient;
class HeadlessContentRendererClient;
class HeadlessContentMainDelegate : public content::ContentMainDelegate { class HeadlessContentMainDelegate : public content::ContentMainDelegate {
public: public:
...@@ -33,8 +32,6 @@ class HeadlessContentMainDelegate : public content::ContentMainDelegate { ...@@ -33,8 +32,6 @@ class HeadlessContentMainDelegate : public content::ContentMainDelegate {
const content::MainFunctionParams& main_function_params) override; const content::MainFunctionParams& main_function_params) override;
void ZygoteForked() override; void ZygoteForked() override;
content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentBrowserClient* CreateContentBrowserClient() override;
content::ContentRendererClient* CreateContentRendererClient() override;
content::ContentUtilityClient* CreateContentUtilityClient() override;
HeadlessBrowserImpl* browser() const { return browser_.get(); } HeadlessBrowserImpl* browser() const { return browser_.get(); }
...@@ -46,9 +43,8 @@ class HeadlessContentMainDelegate : public content::ContentMainDelegate { ...@@ -46,9 +43,8 @@ class HeadlessContentMainDelegate : public content::ContentMainDelegate {
static HeadlessContentMainDelegate* GetInstance(); static HeadlessContentMainDelegate* GetInstance();
std::unique_ptr<HeadlessContentBrowserClient> browser_client_; std::unique_ptr<HeadlessContentBrowserClient> browser_client_;
std::unique_ptr<HeadlessContentRendererClient> renderer_client_;
std::unique_ptr<HeadlessContentUtilityClient> utility_client_;
HeadlessContentClient content_client_; HeadlessContentClient content_client_;
HeadlessPlatformEventSource platform_event_source_;
std::unique_ptr<HeadlessBrowserImpl> browser_; std::unique_ptr<HeadlessBrowserImpl> browser_;
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "headless/lib/renderer/headless_content_renderer_client.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/renderer/render_frame.h"
namespace headless {
HeadlessContentRendererClient::HeadlessContentRendererClient() {}
HeadlessContentRendererClient::~HeadlessContentRendererClient() {}
} // namespace headless
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef HEADLESS_LIB_RENDERER_HEADLESS_CONTENT_RENDERER_CLIENT_H_
#define HEADLESS_LIB_RENDERER_HEADLESS_CONTENT_RENDERER_CLIENT_H_
#include "content/public/renderer/content_renderer_client.h"
namespace headless {
class HeadlessContentRendererClient : public content::ContentRendererClient {
public:
HeadlessContentRendererClient();
~HeadlessContentRendererClient() override;
DISALLOW_COPY_AND_ASSIGN(HeadlessContentRendererClient);
};
} // namespace headless
#endif // HEADLESS_LIB_RENDERER_HEADLESS_CONTENT_RENDERER_CLIENT_H_
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef HEADLESS_LIB_UTILITY_HEADLESS_CONTENT_UTILITY_CLIENT_H_
#define HEADLESS_LIB_UTILITY_HEADLESS_CONTENT_UTILITY_CLIENT_H_
#include "content/public/utility/content_utility_client.h"
namespace headless {
class HeadlessContentUtilityClient : public content::ContentUtilityClient {
public:
HeadlessContentUtilityClient();
~HeadlessContentUtilityClient() override;
DISALLOW_COPY_AND_ASSIGN(HeadlessContentUtilityClient);
};
} // namespace headless
#endif // HEADLESS_LIB_UTILITY_HEADLESS_CONTENT_UTILITY_CLIENT_H_
...@@ -4,9 +4,11 @@ ...@@ -4,9 +4,11 @@
#include "ui/base/ime/input_method_factory.h" #include "ui/base/ime/input_method_factory.h"
#include "base/command_line.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "ui/base/ime/mock_input_method.h" #include "ui/base/ime/mock_input_method.h"
#include "ui/gfx/switches.h"
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "ui/base/ime/input_method_chromeos.h" #include "ui/base/ime/input_method_chromeos.h"
...@@ -49,6 +51,9 @@ std::unique_ptr<InputMethod> CreateInputMethod( ...@@ -49,6 +51,9 @@ std::unique_ptr<InputMethod> CreateInputMethod(
if (g_input_method_set_for_testing) if (g_input_method_set_for_testing)
return base::MakeUnique<MockInputMethod>(delegate); return base::MakeUnique<MockInputMethod>(delegate);
if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
return base::WrapUnique(new MockInputMethod(delegate));
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
return base::MakeUnique<InputMethodChromeOS>(delegate); return base::MakeUnique<InputMethodChromeOS>(delegate);
#elif defined(OS_WIN) #elif defined(OS_WIN)
......
...@@ -9,8 +9,9 @@ extern "C" { ...@@ -9,8 +9,9 @@ extern "C" {
#include <X11/Xlib.h> #include <X11/Xlib.h>
} }
#include "base/command_line.h"
#include "ui/gfx/icc_profile.h" #include "ui/gfx/icc_profile.h"
#include "ui/gfx/switches.h"
#include "ui/gfx/x/x11_types.h" #include "ui/gfx/x/x11_types.h"
namespace gfx { namespace gfx {
...@@ -18,6 +19,8 @@ namespace gfx { ...@@ -18,6 +19,8 @@ namespace gfx {
// static // static
ICCProfile ICCProfile::FromBestMonitor() { ICCProfile ICCProfile::FromBestMonitor() {
ICCProfile icc_profile; ICCProfile icc_profile;
if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
return icc_profile;
Atom property = XInternAtom(GetXDisplay(), "_ICC_PROFILE", true); Atom property = XInternAtom(GetXDisplay(), "_ICC_PROFILE", true);
if (property != None) { if (property != None) {
Atom prop_type = None; Atom prop_type = None;
......
...@@ -18,4 +18,7 @@ const char kDisableDirectWriteForUI[] = "disable-directwrite-for-ui"; ...@@ -18,4 +18,7 @@ const char kDisableDirectWriteForUI[] = "disable-directwrite-for-ui";
const char kEnableHarfBuzzRenderText[] = "enable-harfbuzz-rendertext"; const char kEnableHarfBuzzRenderText[] = "enable-harfbuzz-rendertext";
#endif #endif
// Run in headless mode, i.e., without a UI or display server dependencies.
const char kHeadless[] = "headless";
} // namespace switches } // namespace switches
...@@ -18,6 +18,8 @@ GFX_EXPORT extern const char kDisableDirectWriteForUI[]; ...@@ -18,6 +18,8 @@ GFX_EXPORT extern const char kDisableDirectWriteForUI[];
GFX_EXPORT extern const char kEnableHarfBuzzRenderText[]; GFX_EXPORT extern const char kEnableHarfBuzzRenderText[];
#endif #endif
GFX_EXPORT extern const char kHeadless[];
} // namespace switches } // namespace switches
#endif // UI_GFX_SWITCHES_H_ #endif // UI_GFX_SWITCHES_H_
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/path_service.h" #include "base/path_service.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "ui/gfx/switches.h"
#include "ui/gfx/x/x11_types.h" #include "ui/gfx/x/x11_types.h"
#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_egl_api_implementation.h" #include "ui/gl/gl_egl_api_implementation.h"
...@@ -124,6 +125,11 @@ bool InitializeStaticEGLInternal() { ...@@ -124,6 +125,11 @@ bool InitializeStaticEGLInternal() {
} // namespace } // namespace
bool InitializeGLOneOffPlatform() { bool InitializeGLOneOffPlatform() {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kHeadless))
return true;
switch (GetGLImplementation()) { switch (GetGLImplementation()) {
case kGLImplementationDesktopGL: case kGLImplementationDesktopGL:
if (!GLSurfaceGLX::InitializeOneOff()) { if (!GLSurfaceGLX::InitializeOneOff()) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment