Skip to content

Instantly share code, notes, and snippets.

@tiagovignatti
Created February 27, 2024 19:37
Show Gist options
  • Save tiagovignatti/42fef00d83dad37201e1f2b167b482e2 to your computer and use it in GitHub Desktop.
Save tiagovignatti/42fef00d83dad37201e1f2b167b482e2 to your computer and use it in GitHub Desktop.
diff --git a/weblayer/minimal/BUILD.gn b/weblayer/minimal/BUILD.gn
new file mode 100644
index 0000000000000..aede9ca971f11
--- /dev/null
+++ b/weblayer/minimal/BUILD.gn
@@ -0,0 +1,208 @@
+# Copyright 2019 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+import("//build/config/sanitizers/sanitizers.gni")
+import("//build/config/ui.gni")
+import("//build/config/win/console_app.gni")
+import("//build/config/win/manifest.gni")
+import("//tools/grit/grit_rule.gni")
+import("//tools/grit/repack.gni")
+import("//tools/v8_context_snapshot/v8_context_snapshot.gni")
+
+static_library("webengine_minimal_lib") {
+ testonly = true
+ sources = [
+ "app/shell_main_params.cc",
+ "app/shell_main_params.h",
+ "browser/shell.cc",
+ "browser/shell.h"
+ ]
+
+ configs += [ "//build/config:precompiled_headers" ]
+
+ public_deps = [ "//weblayer:weblayer_lib" ]
+ deps = [
+ ":resources",
+ "//base",
+ "//base:base_static",
+ "//base/third_party/dynamic_annotations",
+ "//net",
+ "//net:net_resources",
+ "//sandbox",
+ "//skia",
+ "//third_party/icu",
+ "//ui/base",
+ "//ui/base/clipboard",
+ "//ui/base/ime/init",
+ "//ui/display",
+ "//ui/events:events_base",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ "//ui/gfx/ipc",
+ "//ui/gfx/ipc/geometry",
+ "//ui/gfx/ipc/skia",
+ "//ui/gl",
+ "//ui/platform_window",
+ "//url",
+ "//v8",
+ "//weblayer:resources",
+ ]
+
+ if (toolkit_views) {
+ deps += [ "//ui/views" ]
+ }
+
+ if (use_aura) {
+ deps += [
+ "//ui/aura",
+ "//ui/aura:test_support",
+ "//ui/events",
+ "//ui/strings",
+ "//ui/wm",
+ ]
+
+ if (toolkit_views) {
+ sources += [ "browser/shell_views.cc" ]
+ deps += [
+ "//ui/color:color_headers",
+ "//ui/native_theme",
+ "//ui/resources",
+ "//ui/views:test_support",
+ "//ui/views/controls/webview",
+ "//ui/wm:test_support",
+ ]
+ }
+ }
+}
+
+grit("webengine_minimal_resources_grit") {
+ testonly = true
+
+ # External code should depend on ":resources" instead.
+ visibility = [ ":*" ]
+ source = "minimal_resources.grd"
+ outputs = [
+ "grit/shell_resources.h",
+ "webengine_minimal_resources.pak",
+ ]
+}
+
+copy("copy_minimal_resources") {
+ testonly = true
+
+ sources = [ "$target_gen_dir/webengine_minimal_resources.pak" ]
+ outputs = [ "$root_out_dir/webengine_minimal_resources.pak" ]
+
+ public_deps = [ ":webengine_minimal_resources_grit" ]
+}
+
+group("resources") {
+ testonly = true
+
+ public_deps = [ ":copy_minimal_resources" ]
+}
+
+repack("shell_pak") {
+ testonly = true
+
+ sources = [ "$root_gen_dir/weblayer/minimal/webengine_minimal_resources.pak" ]
+
+ deps = [ ":resources" ]
+ output = "$root_out_dir/webengine_minimal.pak"
+}
+
+repack("support_pak") {
+ testonly = true
+
+ sources = [
+ "$root_gen_dir/components/components_resources.pak",
+ "$root_gen_dir/components/components_resources_100_percent.pak",
+ "$root_gen_dir/components/strings/components_chromium_strings_en-US.pak",
+ "$root_gen_dir/components/strings/components_locale_settings_en-US.pak",
+ "$root_gen_dir/components/strings/components_strings_en-US.pak",
+ "$root_gen_dir/content/content_resources.pak",
+ "$root_gen_dir/mojo/public/js/mojo_bindings_resources.pak",
+ "$root_gen_dir/net/net_resources.pak",
+ "$root_gen_dir/third_party/blink/public/resources/blink_resources.pak",
+ "$root_gen_dir/third_party/blink/public/resources/blink_scaled_resources_100_percent.pak",
+ "$root_gen_dir/third_party/blink/public/strings/blink_strings_en-US.pak",
+ "$root_gen_dir/ui/resources/ui_resources_100_percent.pak",
+ "$root_gen_dir/ui/resources/webui_resources.pak",
+ "$root_gen_dir/ui/strings/app_locale_settings_en-US.pak",
+ "$root_gen_dir/ui/strings/ax_strings_en-US.pak",
+ "$root_gen_dir/ui/strings/ui_strings_en-US.pak",
+ "$root_gen_dir/weblayer/weblayer_resources.pak",
+ ]
+
+ deps = [
+ "//components/resources",
+ "//components/strings",
+ "//content:content_resources",
+ "//mojo/public/js:resources",
+ "//net:net_resources",
+ "//third_party/blink/public:resources",
+ "//third_party/blink/public:scaled_resources_100_percent",
+ "//third_party/blink/public/strings",
+ "//ui/resources",
+ "//ui/strings",
+ "//weblayer:resources",
+ ]
+
+ if (toolkit_views) {
+ deps += [ "//ui/views/resources" ]
+ sources +=
+ [ "$root_gen_dir/ui/views/resources/views_resources_100_percent.pak" ]
+ }
+
+ deps += [ "//content/browser/tracing:resources" ]
+ sources += [ "$root_gen_dir/content/browser/tracing/tracing_resources.pak" ]
+ output = "$root_out_dir/weblayer_minimal_support.pak"
+}
+
+repack("pak") {
+ testonly = true
+
+ sources = [
+ "$root_out_dir/webengine_minimal.pak",
+ "$root_out_dir/weblayer_minimal_support.pak",
+ ]
+
+ deps = [
+ ":shell_pak",
+ ":support_pak",
+ ]
+ output = "$root_out_dir/weblayer_minimal.pak"
+}
+
+executable("webengine_minimal") {
+ testonly = true
+
+ sources = [ "app/shell_main.cc", "app/shell.rc" ]
+ defines = []
+
+ deps = [
+ ":webengine_minimal_lib",
+ "//base",
+ "//build/win:default_exe_manifest",
+ "//net",
+ ]
+
+ data_deps = [
+ ":pak",
+ "//tools/v8_context_snapshot:v8_context_snapshot",
+ ]
+
+ deps += [ "//sandbox" ]
+ if (win_console_app) {
+ defines += [ "WIN_CONSOLE_APP" ]
+ } else {
+ # Set /SUBSYSTEM:WINDOWS unless a console build has been requested.
+ configs -= [ "//build/config/win:console" ]
+ configs += [ "//build/config/win:windowed" ]
+ }
+
+ data_deps +=
+ [ "//third_party/crashpad/crashpad/handler:crashpad_handler" ]
+}
diff --git a/weblayer/minimal/DEPS b/weblayer/minimal/DEPS
new file mode 100644
index 0000000000000..e81b184cb505b
--- /dev/null
+++ b/weblayer/minimal/DEPS
@@ -0,0 +1,12 @@
+include_rules = [
+ "+net",
+ "+ui/aura",
+ "+ui/base",
+ "+ui/color",
+ "+ui/display",
+ "+ui/events",
+ "+ui/gfx",
+ "+ui/native_theme",
+ "+ui/views",
+ "+ui/wm",
+]
diff --git a/weblayer/minimal/OWNERS b/weblayer/minimal/OWNERS
new file mode 100644
index 0000000000000..262cd04d1604e
--- /dev/null
+++ b/weblayer/minimal/OWNERS
@@ -0,0 +1,2 @@
+rayankans@chromium.org
+swestphal@chromium.org
\ No newline at end of file
diff --git a/weblayer/minimal/README.md b/weblayer/minimal/README.md
new file mode 100644
index 0000000000000..acd23ec868925
--- /dev/null
+++ b/weblayer/minimal/README.md
@@ -0,0 +1,18 @@
+# WebEngine Shell
+
+This directory contains a minimal shell that runs WebEngine.
+
+
+To build and run the sample app:
+
+```
+ $ autoninja -C out/Default run_webengine_shell_local
+ $ out/Default/bin/run_webengine_shell_local
+```
+
+To build and run the sample app with a browsing sandbox (limited capabilities):
+
+```
+ $ autoninja -C out/Default run_webengine_shell
+ $ out/Default/bin/run_webengine_shell
+```
\ No newline at end of file
diff --git a/weblayer/minimal/app/resource.h b/weblayer/minimal/app/resource.h
new file mode 100644
index 0000000000000..d4264ac980d55
--- /dev/null
+++ b/weblayer/minimal/app/resource.h
@@ -0,0 +1,44 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBLAYER_MINIMAL_APP_RESOURCE_H_
+#define WEBLAYER_MINIMAL_APP_RESOURCE_H_
+
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by shell.rc
+//
+
+#define IDR_MAINFRAME 128
+#define IDM_EXIT 105
+#define IDM_CLOSE_WINDOW 106
+#define IDM_NEW_WINDOW 107
+#define IDC_WEBLAYERSHELL 109
+#define IDD_ALERT 130
+#define IDD_CONFIRM 131
+#define IDD_PROMPT 132
+#define IDC_NAV_BACK 1001
+#define IDC_NAV_FORWARD 1002
+#define IDC_NAV_RELOAD 1003
+#define IDC_NAV_STOP 1004
+#define IDC_PROMPTEDIT 1005
+#define IDC_DIALOGTEXT 1006
+
+#ifndef IDC_STATIC
+#define IDC_STATIC -1
+#endif
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+#define _APS_NO_MFC 130
+#define _APS_NEXT_RESOURCE_VALUE 129
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 117
+#endif
+#endif
+
+#endif // WEBLAYER_MINIMAL_APP_RESOURCE_H_
\ No newline at end of file
diff --git a/weblayer/minimal/app/shell.rc b/weblayer/minimal/app/shell.rc
new file mode 100644
index 0000000000000..e3f88833d7ba9
--- /dev/null
+++ b/weblayer/minimal/app/shell.rc
@@ -0,0 +1,126 @@
+//Microsoft Visual C++ generated resource script.
+//
+#include "weblayer/minimal/app/resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ALERT DIALOGEX 0, 0, 241, 76
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Alert"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,184,55,50,14
+ LTEXT "",IDC_DIALOGTEXT,16,17,210,30
+END
+
+IDD_CONFIRM DIALOGEX 0, 0, 241, 76
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Confirm"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "Cancel",IDCANCEL,184,55,50,14
+ DEFPUSHBUTTON "OK",IDOK,131,55,50,14
+ LTEXT "",IDC_DIALOGTEXT,16,17,210,30
+END
+
+IDD_PROMPT DIALOGEX 0, 0, 241, 76
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Prompt"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,131,55,50,14
+ LTEXT "",IDC_DIALOGTEXT,16,17,210,18
+ PUSHBUTTON "Cancel",IDCANCEL,184,55,50,14
+ EDITTEXT IDC_PROMPTEDIT,15,33,210,14,ES_AUTOHSCROLL
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_ALERT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 234
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 69
+ END
+
+ IDD_CONFIRM, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 234
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 69
+ END
+
+ IDD_PROMPT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 234
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 69
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
diff --git a/weblayer/minimal/app/shell_main.cc b/weblayer/minimal/app/shell_main.cc
new file mode 100644
index 0000000000000..cc12cab70de1a
--- /dev/null
+++ b/weblayer/minimal/app/shell_main.cc
@@ -0,0 +1,26 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "build/build_config.h"
+#include "weblayer/public/main.h"
+#include "weblayer/minimal/app/shell_main_params.h"
+
+#if BUILDFLAG(IS_WIN)
+
+#if defined(WIN_CONSOLE_APP)
+int main() {
+ return weblayer::Main(weblayer::CreateMainParams());
+#else
+int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) {
+ return weblayer::Main(weblayer::CreateMainParams(), instance);
+#endif
+}
+
+#else
+
+int main(int argc, const char** argv) {
+ return weblayer::Main(weblayer::CreateMainParams(), argc, argv);
+}
+
+#endif // BUILDFLAG(IS_WIN)
diff --git a/weblayer/minimal/app/shell_main_params.cc b/weblayer/minimal/app/shell_main_params.cc
new file mode 100644
index 0000000000000..4ef6dfb1be1fe
--- /dev/null
+++ b/weblayer/minimal/app/shell_main_params.cc
@@ -0,0 +1,104 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "weblayer/minimal/app/shell_main_params.h"
+
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/functional/callback.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "net/base/filename_util.h"
+#include "url/gurl.h"
+#include "weblayer/public/main.h"
+#include "weblayer/public/profile.h"
+#include "weblayer/minimal/browser/shell.h"
+
+namespace weblayer {
+
+namespace {
+
+GURL GetStartupURL() {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+#if BUILDFLAG(IS_ANDROID)
+ // Delay renderer creation on Android until surface is ready.
+ return GURL();
+#else
+ const base::CommandLine::StringVector& args = command_line->GetArgs();
+
+ if (args.empty())
+ return GURL("https://www.google.com/");
+
+#if BUILDFLAG(IS_WIN)
+ GURL url(base::WideToUTF16(args[0]));
+#else
+ GURL url(args[0]);
+#endif
+ if (url.is_valid() && url.has_scheme())
+ return url;
+
+ return net::FilePathToFileURL(
+ base::MakeAbsoluteFilePath(base::FilePath(args[0])));
+#endif
+}
+
+class MainDelegateImpl : public MainDelegate {
+ public:
+ void PreMainMessageLoopRun() override {
+ // On Android the Profile is created and owned in Java via an
+ // embedder-specific call to WebLayer.createBrowserFragment().
+#if !BUILDFLAG(IS_ANDROID)
+ InitializeProfile();
+#endif
+
+ Shell::Initialize();
+
+#if BUILDFLAG(IS_ANDROID)
+ Shell::CreateNewWindow(GetStartupURL(), gfx::Size());
+#else
+ Shell::CreateNewWindow(profile_.get(), GetStartupURL(), gfx::Size());
+#endif
+ }
+
+ void PostMainMessageLoopRun() override {
+#if !BUILDFLAG(IS_ANDROID)
+ DestroyProfile();
+#endif
+ }
+
+ void SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure) override {
+ Shell::SetMainMessageLoopQuitClosure(std::move(quit_closure));
+ }
+
+ private:
+#if !BUILDFLAG(IS_ANDROID)
+ void InitializeProfile() {
+ profile_ = Profile::Create("web_minimal", false);
+ }
+
+ void DestroyProfile() { profile_.reset(); }
+
+ std::unique_ptr<Profile> profile_;
+#endif
+};
+
+} // namespace
+
+MainParams CreateMainParams() {
+ static MainDelegateImpl weblayer_delegate;
+ MainParams params;
+ params.delegate = &weblayer_delegate;
+
+ base::PathService::Get(base::DIR_EXE, &params.log_filename);
+ params.log_filename = params.log_filename.AppendASCII("webengine_minimal.log");
+
+ params.pak_name = "weblayer.pak";
+
+ return params;
+}
+
+} // namespace weblayer
diff --git a/weblayer/minimal/app/shell_main_params.h b/weblayer/minimal/app/shell_main_params.h
new file mode 100644
index 0000000000000..705a8686a8def
--- /dev/null
+++ b/weblayer/minimal/app/shell_main_params.h
@@ -0,0 +1,15 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBLAYER_MINIMAL_APP_SHELL_MAIN_PARAMS_H_
+#define WEBLAYER_MINIMAL_APP_SHELL_MAIN_PARAMS_H_
+
+namespace weblayer {
+struct MainParams;
+
+MainParams CreateMainParams();
+
+} // namespace weblayer
+
+#endif // WEBLAYER_MINIMAL_APP_SHELL_MAIN_PARAMS_H_
diff --git a/weblayer/minimal/browser/shell.cc b/weblayer/minimal/browser/shell.cc
new file mode 100644
index 0000000000000..2456000c85f9b
--- /dev/null
+++ b/weblayer/minimal/browser/shell.cc
@@ -0,0 +1,211 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "weblayer/minimal/browser/shell.h"
+
+#include <stddef.h>
+
+#include <string>
+#include <utility>
+
+#include "base/no_destructor.h"
+#include "base/run_loop.h"
+#include "base/strings/string_util.h"
+#include "build/build_config.h"
+#include "url/gurl.h"
+#include "weblayer/browser/browser_impl.h"
+#include "weblayer/browser/profile_impl.h"
+#include "weblayer/browser/tab_impl.h"
+#include "weblayer/public/navigation_controller.h"
+#include "weblayer/public/prerender_controller.h"
+
+namespace weblayer {
+
+// Null until/unless the default main message loop is running.
+base::NoDestructor<base::OnceClosure> g_quit_main_message_loop;
+
+const int kDefaultTestWindowWidthDip = 1000;
+const int kDefaultTestWindowHeightDip = 700;
+
+std::vector<Shell*> Shell::windows_;
+
+Shell::Shell(std::unique_ptr<Browser> browser)
+ : browser_(std::move(browser)), window_(nullptr) {
+ windows_.push_back(this);
+ if (tab()) {
+ tab()->AddObserver(this);
+ tab()->GetNavigationController()->AddObserver(this);
+#if !BUILDFLAG(IS_ANDROID) // Android does this in Java.
+ static_cast<TabImpl*>(tab())->profile()->SetDownloadDelegate(this);
+#endif
+ }
+}
+
+Shell::~Shell() {
+ if (tab()) {
+ tab()->GetNavigationController()->RemoveObserver(this);
+ tab()->RemoveObserver(this);
+#if !BUILDFLAG(IS_ANDROID) // Android does this in Java.
+ static_cast<TabImpl*>(tab())->profile()->SetDownloadDelegate(nullptr);
+#endif
+ }
+ PlatformCleanUp();
+
+ for (size_t i = 0; i < windows_.size(); ++i) {
+ if (windows_[i] == this) {
+ windows_.erase(windows_.begin() + i);
+ break;
+ }
+ }
+
+ // Always destroy WebContents before calling PlatformExit(). WebContents
+ // destruction sequence may depend on the resources destroyed in
+ // PlatformExit() (e.g. the display::Screen singleton).
+ if (tab()) {
+ auto* const profile = static_cast<TabImpl*>(tab())->profile();
+ profile->GetPrerenderController()->DestroyAllContents();
+ }
+ browser_.reset();
+
+ if (windows_.empty()) {
+ PlatformExit();
+
+ if (*g_quit_main_message_loop)
+ std::move(*g_quit_main_message_loop).Run();
+ }
+}
+
+Shell* Shell::CreateShell(std::unique_ptr<Browser> browser,
+ const gfx::Size& initial_size) {
+ Shell* shell = new Shell(std::move(browser));
+ shell->PlatformCreateWindow(initial_size.width(), initial_size.height());
+
+ shell->PlatformSetContents();
+
+ shell->PlatformResizeSubViews();
+
+ return shell;
+}
+
+void Shell::CloseAllWindows() {
+ std::vector<Shell*> open_windows(windows_);
+ for (size_t i = 0; i < open_windows.size(); ++i)
+ open_windows[i]->Close();
+
+ // Pump the message loop to allow window teardown tasks to run.
+ base::RunLoop().RunUntilIdle();
+}
+
+void Shell::SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure) {
+ *g_quit_main_message_loop = std::move(quit_closure);
+}
+
+Tab* Shell::tab() {
+ if (!browser())
+ return nullptr;
+ if (browser()->GetTabs().empty())
+ return nullptr;
+ return browser()->GetTabs()[0];
+}
+
+Browser* Shell::browser() {
+ return browser_.get();
+}
+
+void Shell::Initialize() {
+ PlatformInitialize(GetShellDefaultSize());
+}
+
+void Shell::DisplayedUrlChanged(const GURL& url) {
+ PlatformSetAddressBarURL(url);
+}
+
+void Shell::LoadStateChanged(bool is_loading, bool should_show_loading_ui) {
+ NavigationController* navigation_controller =
+ tab()->GetNavigationController();
+
+ PlatformEnableUIControl(STOP_BUTTON, is_loading && should_show_loading_ui);
+
+ // TODO(estade): These should be updated in callbacks that correspond to the
+ // back/forward list changing, such as NavigationEntriesDeleted.
+ PlatformEnableUIControl(BACK_BUTTON, navigation_controller->CanGoBack());
+ PlatformEnableUIControl(FORWARD_BUTTON,
+ navigation_controller->CanGoForward());
+}
+
+void Shell::LoadProgressChanged(double progress) {
+ PlatformSetLoadProgress(progress);
+}
+
+bool Shell::InterceptDownload(const GURL& url,
+ const std::string& user_agent,
+ const std::string& content_disposition,
+ const std::string& mime_type,
+ int64_t content_length) {
+ return false;
+}
+
+void Shell::AllowDownload(Tab* tab,
+ const GURL& url,
+ const std::string& request_method,
+ absl::optional<url::Origin> request_initiator,
+ AllowDownloadCallback callback) {
+ std::move(callback).Run(true);
+}
+
+gfx::Size Shell::AdjustWindowSize(const gfx::Size& initial_size) {
+ if (!initial_size.IsEmpty())
+ return initial_size;
+ return GetShellDefaultSize();
+}
+
+Shell* Shell::CreateNewWindow(Profile* web_profile,
+ const GURL& url,
+ const gfx::Size& initial_size) {
+ auto browser = Browser::Create(web_profile, nullptr);
+ browser->CreateTab();
+ return CreateNewWindowWithBrowser(std::move(browser), url, initial_size);
+}
+
+Shell* Shell::CreateNewWindowWithBrowser(std::unique_ptr<Browser> browser,
+ const GURL& url,
+ const gfx::Size& initial_size) {
+ Shell* shell =
+ CreateShell(std::move(browser), AdjustWindowSize(initial_size));
+ if (!url.is_empty())
+ shell->LoadURL(url);
+ return shell;
+}
+
+void Shell::LoadURL(const GURL& url) {
+ tab()->GetNavigationController()->Navigate(url);
+}
+
+void Shell::GoBackOrForward(int offset) {
+ if (offset == -1)
+ tab()->GetNavigationController()->GoBack();
+ else if (offset == 1)
+ tab()->GetNavigationController()->GoForward();
+}
+
+void Shell::Reload() {
+ tab()->GetNavigationController()->Reload();
+}
+
+void Shell::ReloadBypassingCache() {}
+
+void Shell::Stop() {
+ tab()->GetNavigationController()->Stop();
+}
+
+gfx::Size Shell::GetShellDefaultSize() {
+ static gfx::Size default_shell_size;
+ if (!default_shell_size.IsEmpty())
+ return default_shell_size;
+ default_shell_size =
+ gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip);
+ return default_shell_size;
+}
+
+} // namespace weblayer
diff --git a/weblayer/minimal/browser/shell.h b/weblayer/minimal/browser/shell.h
new file mode 100644
index 0000000000000..37df4492eb20e
--- /dev/null
+++ b/weblayer/minimal/browser/shell.h
@@ -0,0 +1,184 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBLAYER_MINIMAL_BROWSER_SHELL_H_
+#define WEBLAYER_MINIMAL_BROWSER_SHELL_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/functional/callback_forward.h"
+#include "base/memory/raw_ptr.h"
+#include "build/build_config.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/native_widget_types.h"
+#include "weblayer/public/download_delegate.h"
+#include "weblayer/public/navigation_observer.h"
+#include "weblayer/public/tab_observer.h"
+
+#if BUILDFLAG(IS_ANDROID)
+#include "base/android/scoped_java_ref.h"
+#elif defined(USE_AURA)
+namespace views {
+class Widget;
+class ViewsDelegate;
+} // namespace views
+#if !BUILDFLAG(IS_CHROMEOS)
+namespace display {
+class Screen;
+}
+namespace wm {
+class WMState;
+}
+#endif
+#endif // defined(USE_AURA)
+
+class GURL;
+
+namespace weblayer {
+class Browser;
+class Profile;
+class Tab;
+
+// This represents one window of the Web Shell, i.e. all the UI including
+// buttons and url bar, as well as the web content area.
+class Shell : public TabObserver,
+ public NavigationObserver,
+ public DownloadDelegate {
+ public:
+ ~Shell() override;
+
+ void LoadURL(const GURL& url);
+ void GoBackOrForward(int offset);
+ void Reload();
+ void ReloadBypassingCache();
+ void Stop();
+ void Close();
+
+ // Do one time initialization at application startup.
+ static void Initialize();
+
+#if BUILDFLAG(IS_ANDROID)
+ static Shell* CreateNewWindow(const GURL& url, const gfx::Size& initial_size);
+#else
+ static Shell* CreateNewWindow(Profile* web_profile,
+ const GURL& url,
+ const gfx::Size& initial_size);
+#endif
+
+ // Returns the currently open windows.
+ static std::vector<Shell*>& windows() { return windows_; }
+
+ // Closes all windows, pumps teardown tasks, then returns. The main message
+ // loop will be signalled to quit, before the call returns.
+ static void CloseAllWindows();
+
+ // Stores the supplied |quit_closure|, to be run when the last Shell
+ // instance is destroyed.
+ static void SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure);
+
+ Tab* tab();
+ Browser* browser();
+
+ gfx::NativeWindow window() { return window_; }
+
+ static gfx::Size GetShellDefaultSize();
+
+ private:
+ enum UIControl { BACK_BUTTON, FORWARD_BUTTON, STOP_BUTTON };
+
+ static Shell* CreateNewWindowWithBrowser(std::unique_ptr<Browser> browser,
+ const GURL& url,
+ const gfx::Size& initial_size);
+
+ explicit Shell(std::unique_ptr<Browser> browser);
+
+ // TabObserver implementation:
+ void DisplayedUrlChanged(const GURL& url) override;
+
+ // NavigationObserver implementation:
+ void LoadStateChanged(bool is_loading, bool should_show_loading_ui) override;
+ void LoadProgressChanged(double progress) override;
+
+ // DownloadDelegate implementation:
+ bool InterceptDownload(const GURL& url,
+ const std::string& user_agent,
+ const std::string& content_disposition,
+ const std::string& mime_type,
+ int64_t content_length) override;
+ void AllowDownload(Tab* tab,
+ const GURL& url,
+ const std::string& request_method,
+ absl::optional<url::Origin> request_initiator,
+ AllowDownloadCallback callback) override;
+
+ // Helper to create a new Shell.
+ static Shell* CreateShell(std::unique_ptr<Browser> browser,
+ const gfx::Size& initial_size);
+
+ // Helper for one time initialization of application
+ static void PlatformInitialize(const gfx::Size& default_window_size);
+
+ // Helper for one time deinitialization of platform specific state.
+ static void PlatformExit();
+
+ // Adjust the size when Blink sends 0 for width and/or height.
+ // This happens when Blink requests a default-sized window.
+ static gfx::Size AdjustWindowSize(const gfx::Size& initial_size);
+
+ // All the methods that begin with Platform need to be implemented by the
+ // platform specific Shell implementation.
+ // Called from the destructor to let each platform do any necessary cleanup.
+ void PlatformCleanUp();
+
+ // Creates the main window GUI.
+ void PlatformCreateWindow(int width, int height);
+
+ // Links the WebContents into the newly created window.
+ void PlatformSetContents();
+
+ // Resize the content area and GUI.
+ void PlatformResizeSubViews();
+
+ // Enable/disable a button.
+ void PlatformEnableUIControl(UIControl control, bool is_enabled);
+
+ // Updates the url in the url bar.
+ void PlatformSetAddressBarURL(const GURL& url);
+
+ // Sets the load progress indicator in the UI.
+ void PlatformSetLoadProgress(double progress);
+
+ // Set the title of shell window
+ void PlatformSetTitle(const std::u16string& title);
+
+ std::unique_ptr<Browser> browser_;
+
+ gfx::NativeWindow window_;
+
+ gfx::Size content_size_;
+
+#if BUILDFLAG(IS_ANDROID)
+ base::android::ScopedJavaGlobalRef<jobject> java_object_;
+#elif defined(USE_AURA)
+ static wm::WMState* wm_state_;
+ static display::Screen* screen_;
+#if defined(TOOLKIT_VIEWS)
+ static views::ViewsDelegate* views_delegate_;
+
+ raw_ptr<views::Widget> window_widget_;
+#endif // defined(TOOLKIT_VIEWS)
+#endif // defined(USE_AURA)
+
+ // A container of all the open windows. We use a vector so we can keep track
+ // of ordering.
+ static std::vector<Shell*> windows_;
+};
+
+} // namespace weblayer
+
+#endif // WEBLAYER_MINIMAL_BROWSER_SHELL_H_
diff --git a/weblayer/minimal/browser/shell_views.cc b/weblayer/minimal/browser/shell_views.cc
new file mode 100644
index 0000000000000..ab3c7c8223a03
--- /dev/null
+++ b/weblayer/minimal/browser/shell_views.cc
@@ -0,0 +1,397 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/functional/bind.h"
+#include "base/memory/raw_ptr.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/color/color_id.h"
+#include "ui/events/event.h"
+#include "ui/views/background.h"
+#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/controls/webview/webview.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/flex_layout_view.h"
+#include "ui/views/test/desktop_test_views_delegate.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "weblayer/public/tab.h"
+#include "weblayer/minimal/browser/shell.h"
+
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS)
+#include "ui/display/screen.h"
+#include "ui/views/widget/desktop_aura/desktop_screen.h"
+#include "ui/wm/core/wm_state.h"
+#endif
+
+#if BUILDFLAG(IS_WIN)
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+namespace weblayer {
+
+namespace {
+
+// Maintain the UI controls and web view for web shell
+class ShellWindowDelegateView : public views::WidgetDelegateView,
+ public views::TextfieldController {
+ public:
+ METADATA_HEADER(ShellWindowDelegateView);
+
+ enum UIControl { BACK_BUTTON, FORWARD_BUTTON, STOP_BUTTON };
+
+ explicit ShellWindowDelegateView(Shell* shell) : shell_(shell) {
+ SetHasWindowSizeControls(true);
+ InitShellWindow();
+ }
+
+ ShellWindowDelegateView(const ShellWindowDelegateView&) = delete;
+ ShellWindowDelegateView& operator=(const ShellWindowDelegateView&) = delete;
+
+ ~ShellWindowDelegateView() override = default;
+
+ // Update the state of UI controls
+ void SetAddressBarURL(const GURL& url) {
+ url_entry_->SetText(base::ASCIIToUTF16(url.spec()));
+ }
+
+ void AttachTab(Tab* tab, const gfx::Size& size) {
+ contents_view_->SetUseDefaultFillLayout(true);
+ // If there was a previous WebView in this Shell it should be removed and
+ // deleted.
+ if (web_view_)
+ contents_view_->RemoveChildViewT(web_view_.get());
+
+ views::Builder<views::View>(contents_view_.get())
+ .AddChild(views::Builder<views::WebView>()
+ .CopyAddressTo(&web_view_)
+ .SetPreferredSize(size))
+ .BuildChildren();
+ tab->AttachToView(web_view_);
+ web_view_->SizeToPreferredSize();
+
+ // Resize the widget, keeping the same origin.
+ gfx::Rect bounds = GetWidget()->GetWindowBoundsInScreen();
+ bounds.set_size(GetWidget()->GetRootView()->GetPreferredSize());
+ GetWidget()->SetBounds(bounds);
+ }
+
+ void SetWindowTitle(const std::u16string& title) { title_ = title; }
+
+ void EnableUIControl(UIControl control, bool is_enabled) {
+ if (control == BACK_BUTTON) {
+ back_button_->SetState(is_enabled ? views::Button::STATE_NORMAL
+ : views::Button::STATE_DISABLED);
+ } else if (control == FORWARD_BUTTON) {
+ forward_button_->SetState(is_enabled ? views::Button::STATE_NORMAL
+ : views::Button::STATE_DISABLED);
+ } else if (control == STOP_BUTTON) {
+ stop_button_->SetState(is_enabled ? views::Button::STATE_NORMAL
+ : views::Button::STATE_DISABLED);
+ if (!is_enabled)
+ UpdateLoadProgress();
+ }
+ }
+
+ void UpdateLoadProgress(double progress = 0.) {
+ std::string stop_text("Stop");
+ if (stop_button_->GetState() == views::Button::STATE_NORMAL)
+ stop_text = base::StringPrintf("Stop (%.0f%%)", progress * 100);
+ stop_button_->SetText(base::ASCIIToUTF16(stop_text));
+ }
+
+ private:
+ // Initialize the UI control contained in shell window
+ void InitShellWindow() {
+ auto toolbar_button_rule = [](const views::View* view,
+ const views::SizeBounds& size_bounds) {
+ gfx::Size preferred_size = view->GetPreferredSize();
+ if (size_bounds != views::SizeBounds() &&
+ size_bounds.width().is_bounded()) {
+ preferred_size.set_width(std::max(
+ std::min(size_bounds.width().value(), preferred_size.width()),
+ preferred_size.width() / 2));
+ }
+ return preferred_size;
+ };
+
+ auto* box_layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
+ views::BoxLayout::Orientation::kVertical));
+
+ views::Builder<views::WidgetDelegateView>(this)
+ .SetBackground(
+ views::CreateThemedSolidBackground(ui::kColorWindowBackground))
+ .AddChildren(
+ views::Builder<views::FlexLayoutView>()
+ .CopyAddressTo(&toolbar_view_)
+ .SetOrientation(views::LayoutOrientation::kHorizontal)
+ // Top/Left/Right padding = 2, Bottom padding = 5
+ .SetProperty(views::kMarginsKey, gfx::Insets::TLBR(2, 2, 5, 2))
+ .AddChildren(
+ views::Builder<views::MdTextButton>()
+ .CopyAddressTo(&back_button_)
+ .SetText(u"Back")
+ .SetCallback(base::BindRepeating(
+ &Shell::GoBackOrForward,
+ base::Unretained(shell_.get()), -1))
+ .SetProperty(
+ views::kFlexBehaviorKey,
+ views::FlexSpecification(
+ base::BindRepeating(toolbar_button_rule))),
+ views::Builder<views::MdTextButton>()
+ .CopyAddressTo(&forward_button_)
+ .SetText(u"Forward")
+ .SetCallback(base::BindRepeating(
+ &Shell::GoBackOrForward,
+ base::Unretained(shell_.get()), 1))
+ .SetProperty(
+ views::kFlexBehaviorKey,
+ views::FlexSpecification(
+ base::BindRepeating(toolbar_button_rule))),
+ views::Builder<views::MdTextButton>()
+ .CopyAddressTo(&refresh_button_)
+ .SetText(u"Refresh")
+ .SetCallback(base::BindRepeating(
+ &Shell::Reload, base::Unretained(shell_.get())))
+ .SetProperty(
+ views::kFlexBehaviorKey,
+ views::FlexSpecification(
+ base::BindRepeating(toolbar_button_rule))),
+ views::Builder<views::MdTextButton>()
+ .CopyAddressTo(&stop_button_)
+ .SetText(u"Stop (100%)")
+ .SetCallback(base::BindRepeating(
+ &Shell::Stop, base::Unretained(shell_.get())))
+ .SetProperty(
+ views::kFlexBehaviorKey,
+ views::FlexSpecification(
+ base::BindRepeating(toolbar_button_rule))),
+ views::Builder<views::Textfield>()
+ .CopyAddressTo(&url_entry_)
+ .SetAccessibleName(u"Enter URL")
+ .SetController(this)
+ .SetTextInputType(
+ ui::TextInputType::TEXT_INPUT_TYPE_URL)
+ .SetProperty(
+ views::kFlexBehaviorKey,
+ views::FlexSpecification(
+ views::MinimumFlexSizeRule::kScaleToMinimum,
+ views::MaximumFlexSizeRule::kUnbounded))
+ // Left padding = 2, Right padding = 2
+ .SetProperty(views::kMarginsKey,
+ gfx::Insets::TLBR(0, 2, 0, 2))),
+ views::Builder<views::View>()
+ .CopyAddressTo(&contents_view_)
+ .SetUseDefaultFillLayout(true)
+ .SetProperty(views::kMarginsKey, gfx::Insets::TLBR(0, 2, 0, 2)),
+ views::Builder<views::View>().SetProperty(
+ views::kMarginsKey, gfx::Insets::TLBR(0, 0, 5, 0)))
+ .BuildChildren();
+ box_layout->SetFlexForView(contents_view_, 1);
+ }
+
+ void InitAccelerators() {
+ // This function must be called when part of the widget hierarchy.
+ DCHECK(GetWidget());
+ static const ui::KeyboardCode keys[] = {ui::VKEY_F5, ui::VKEY_BROWSER_BACK,
+ ui::VKEY_BROWSER_FORWARD};
+ for (size_t i = 0; i < std::size(keys); ++i) {
+ GetFocusManager()->RegisterAccelerator(
+ ui::Accelerator(keys[i], ui::EF_NONE),
+ ui::AcceleratorManager::kNormalPriority, this);
+ }
+ }
+
+ // Overridden from TextfieldController
+ void ContentsChanged(views::Textfield* sender,
+ const std::u16string& new_contents) override {}
+
+ bool HandleKeyEvent(views::Textfield* sender,
+ const ui::KeyEvent& key_event) override {
+ if (key_event.type() == ui::ET_KEY_PRESSED && sender == url_entry_ &&
+ key_event.key_code() == ui::VKEY_RETURN) {
+ std::string text = base::UTF16ToUTF8(url_entry_->GetText());
+ GURL url(text);
+ if (!url.has_scheme()) {
+ url = GURL(std::string("http://") + std::string(text));
+ url_entry_->SetText(base::ASCIIToUTF16(url.spec()));
+ }
+ shell_->LoadURL(url);
+ return true;
+ }
+ return false;
+ }
+
+ // Overridden from WidgetDelegateView
+ std::u16string GetWindowTitle() const override { return title_; }
+
+ // Overridden from View
+ gfx::Size GetMinimumSize() const override {
+ // We want to be able to make the window smaller than its initial
+ // (preferred) size.
+ return gfx::Size();
+ }
+ void AddedToWidget() override { InitAccelerators(); }
+
+ // Overridden from AcceleratorTarget:
+ bool AcceleratorPressed(const ui::Accelerator& accelerator) override {
+ switch (accelerator.key_code()) {
+ case ui::VKEY_F5:
+ shell_->Reload();
+ return true;
+ case ui::VKEY_BROWSER_BACK:
+ shell_->GoBackOrForward(-1);
+ return true;
+ case ui::VKEY_BROWSER_FORWARD:
+ shell_->GoBackOrForward(1);
+ return true;
+ default:
+ return views::WidgetDelegateView::AcceleratorPressed(accelerator);
+ }
+ }
+
+ private:
+ std::unique_ptr<Shell> shell_;
+
+ // Window title
+ std::u16string title_;
+
+ // Toolbar view contains forward/backward/reload button and URL entry
+ raw_ptr<views::View> toolbar_view_ = nullptr;
+ raw_ptr<views::Button> back_button_ = nullptr;
+ raw_ptr<views::Button> forward_button_ = nullptr;
+ raw_ptr<views::Button> refresh_button_ = nullptr;
+ raw_ptr<views::MdTextButton> stop_button_ = nullptr;
+ raw_ptr<views::Textfield> url_entry_ = nullptr;
+
+ // Contents view contains the WebBrowser view
+ raw_ptr<views::View> contents_view_ = nullptr;
+ raw_ptr<views::WebView> web_view_ = nullptr;
+};
+
+BEGIN_METADATA(ShellWindowDelegateView, views::WidgetDelegateView)
+END_METADATA
+
+} // namespace
+
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS)
+// static
+wm::WMState* Shell::wm_state_ = nullptr;
+display::Screen* Shell::screen_ = nullptr;
+#endif
+// static
+views::ViewsDelegate* Shell::views_delegate_ = nullptr;
+
+// static
+void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
+#if BUILDFLAG(IS_WIN)
+ _setmode(_fileno(stdout), _O_BINARY);
+ _setmode(_fileno(stderr), _O_BINARY);
+#endif
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS)
+ wm_state_ = new wm::WMState;
+ CHECK(!display::Screen::GetScreen());
+ screen_ = views::CreateDesktopScreen().release();
+#endif
+ views_delegate_ = new views::DesktopTestViewsDelegate();
+}
+
+void Shell::PlatformExit() {
+ delete views_delegate_;
+ views_delegate_ = nullptr;
+ // delete platform_;
+ // platform_ = nullptr;
+#if defined(USE_AURA)
+ delete screen_;
+ screen_ = nullptr;
+ delete wm_state_;
+ wm_state_ = nullptr;
+#endif
+}
+
+void Shell::PlatformCleanUp() {}
+
+void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
+ ShellWindowDelegateView* delegate_view =
+ static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
+ if (control == BACK_BUTTON) {
+ delegate_view->EnableUIControl(ShellWindowDelegateView::BACK_BUTTON,
+ is_enabled);
+ } else if (control == FORWARD_BUTTON) {
+ delegate_view->EnableUIControl(ShellWindowDelegateView::FORWARD_BUTTON,
+ is_enabled);
+ } else if (control == STOP_BUTTON) {
+ delegate_view->EnableUIControl(ShellWindowDelegateView::STOP_BUTTON,
+ is_enabled);
+ }
+}
+
+void Shell::PlatformSetAddressBarURL(const GURL& url) {
+ ShellWindowDelegateView* delegate_view =
+ static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
+ delegate_view->SetAddressBarURL(url);
+}
+
+void Shell::PlatformSetLoadProgress(double progress) {
+ ShellWindowDelegateView* delegate_view =
+ static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
+ delegate_view->UpdateLoadProgress(progress);
+}
+
+void Shell::PlatformCreateWindow(int width, int height) {
+ window_widget_ = new views::Widget;
+ views::Widget::InitParams params;
+ params.bounds = gfx::Rect(0, 0, width, height);
+ params.delegate = new ShellWindowDelegateView(this);
+ params.wm_class_class = "chromium-web_shell";
+ params.wm_class_name = params.wm_class_class;
+ window_widget_->Init(std::move(params));
+
+ content_size_ = gfx::Size(width, height);
+
+ // |window_widget_| is made visible in PlatformSetContents(), so that the
+ // platform-window size does not need to change due to layout again.
+ window_ = window_widget_->GetNativeWindow();
+}
+
+void Shell::PlatformSetContents() {
+ views::WidgetDelegate* widget_delegate = window_widget_->widget_delegate();
+ ShellWindowDelegateView* delegate_view =
+ static_cast<ShellWindowDelegateView*>(widget_delegate);
+ delegate_view->AttachTab(tab(), content_size_);
+ window_->GetHost()->Show();
+ window_widget_->Show();
+}
+
+void Shell::PlatformResizeSubViews() {}
+
+void Shell::Close() {
+ window_widget_->CloseNow();
+}
+
+void Shell::PlatformSetTitle(const std::u16string& title) {
+ ShellWindowDelegateView* delegate_view =
+ static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
+ delegate_view->SetWindowTitle(title);
+ window_widget_->UpdateWindowTitle();
+}
+
+} // namespace weblayer
diff --git a/weblayer/minimal/minimal_resources.grd b/weblayer/minimal/minimal_resources.grd
new file mode 100644
index 0000000000000..28ea5d5128985
--- /dev/null
+++ b/weblayer/minimal/minimal_resources.grd
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
+ <outputs>
+ <output filename="grit/shell_resources.h" type="rc_header">
+ <emit emit_type='prepend'></emit>
+ </output>
+ <output filename="webengine_minimal_resources.pak" type="data_package" />
+ </outputs>
+ <translations />
+</grit>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment