mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-05 15:49:11 +00:00
LibWebView+UI: Migrate Ladybird's command line flags to LibWebView
Currently, if we want to add a new e.g. WebContent command line option, we have to add it to all of Qt, AppKit, and headless-browser. (Or worse, we only add it to one of these, and we have feature disparity). To prevent this, this moves command line flags to WebView::Application. The flags are assigned to ChromeOptions and WebContentOptions structs. Each chrome can still add its platform-specific options; for example, the Qt chrome has a flag to enable Qt networking. There should be no behavior change here, other than that AppKit will now support command line flags that were previously only supported by Qt.
This commit is contained in:
parent
0e640f6f70
commit
5f8d852dae
Notes:
github-actions[bot]
2024-08-01 09:39:41 +00:00
Author: https://github.com/trflynn89
Commit: 5f8d852dae
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/910
Reviewed-by: https://github.com/ADKaster
35 changed files with 427 additions and 440 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -7,8 +7,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Error.h>
|
#include <AK/Error.h>
|
||||||
#include <AK/Vector.h>
|
|
||||||
#include <LibIPC/Forward.h>
|
#include <LibIPC/Forward.h>
|
||||||
|
#include <LibMain/Main.h>
|
||||||
|
#include <LibURL/URL.h>
|
||||||
#include <LibWebView/Forward.h>
|
#include <LibWebView/Forward.h>
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
@ -19,9 +20,10 @@ class WebViewBridge;
|
||||||
|
|
||||||
@interface Application : NSApplication
|
@interface Application : NSApplication
|
||||||
|
|
||||||
- (instancetype)init;
|
- (void)setupWebViewApplication:(Main::Arguments&)arguments
|
||||||
|
newTabPageURL:(URL::URL)new_tab_page_url;
|
||||||
|
|
||||||
- (ErrorOr<void>)launchRequestServer:(Vector<ByteString> const&)certificates;
|
- (ErrorOr<void>)launchRequestServer;
|
||||||
- (ErrorOr<void>)launchImageDecoder;
|
- (ErrorOr<void>)launchImageDecoder;
|
||||||
- (ErrorOr<NonnullRefPtr<WebView::WebContentClient>>)launchWebContent:(Ladybird::WebViewBridge&)web_view_bridge;
|
- (ErrorOr<NonnullRefPtr<WebView::WebContentClient>>)launchWebContent:(Ladybird::WebViewBridge&)web_view_bridge;
|
||||||
- (ErrorOr<IPC::File>)launchWebWorker;
|
- (ErrorOr<IPC::File>)launchWebWorker;
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/ByteString.h>
|
|
||||||
#include <Application/ApplicationBridge.h>
|
#include <Application/ApplicationBridge.h>
|
||||||
#include <LibCore/EventLoop.h>
|
#include <LibCore/EventLoop.h>
|
||||||
#include <LibCore/ThreadEventQueue.h>
|
#include <LibCore/ThreadEventQueue.h>
|
||||||
|
@ -25,20 +24,17 @@
|
||||||
|
|
||||||
@implementation Application
|
@implementation Application
|
||||||
|
|
||||||
- (instancetype)init
|
|
||||||
{
|
|
||||||
if (self = [super init]) {
|
|
||||||
m_application_bridge = make<Ladybird::ApplicationBridge>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Public methods
|
#pragma mark - Public methods
|
||||||
|
|
||||||
- (ErrorOr<void>)launchRequestServer:(Vector<ByteString> const&)certificates
|
- (void)setupWebViewApplication:(Main::Arguments&)arguments
|
||||||
|
newTabPageURL:(URL::URL)new_tab_page_url
|
||||||
{
|
{
|
||||||
return m_application_bridge->launch_request_server(certificates);
|
m_application_bridge = Ladybird::ApplicationBridge::create(arguments, move(new_tab_page_url));
|
||||||
|
}
|
||||||
|
|
||||||
|
- (ErrorOr<void>)launchRequestServer
|
||||||
|
{
|
||||||
|
return m_application_bridge->launch_request_server();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ErrorOr<void>)launchImageDecoder
|
- (ErrorOr<void>)launchImageDecoder
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/ByteString.h>
|
|
||||||
#include <Application/ApplicationBridge.h>
|
#include <Application/ApplicationBridge.h>
|
||||||
#include <Ladybird/AppKit/UI/LadybirdWebViewBridge.h>
|
#include <Ladybird/AppKit/UI/LadybirdWebViewBridge.h>
|
||||||
#include <Ladybird/HelperProcess.h>
|
#include <Ladybird/HelperProcess.h>
|
||||||
|
@ -23,17 +22,17 @@ struct ApplicationBridgeImpl {
|
||||||
RefPtr<ImageDecoderClient::Client> image_decoder_client;
|
RefPtr<ImageDecoderClient::Client> image_decoder_client;
|
||||||
};
|
};
|
||||||
|
|
||||||
ApplicationBridge::ApplicationBridge()
|
ApplicationBridge::ApplicationBridge(Badge<WebView::Application>, Main::Arguments&)
|
||||||
: m_impl(make<ApplicationBridgeImpl>())
|
: m_impl(make<ApplicationBridgeImpl>())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationBridge::~ApplicationBridge() = default;
|
ApplicationBridge::~ApplicationBridge() = default;
|
||||||
|
|
||||||
ErrorOr<void> ApplicationBridge::launch_request_server(Vector<ByteString> const& certificates)
|
ErrorOr<void> ApplicationBridge::launch_request_server()
|
||||||
{
|
{
|
||||||
auto request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv));
|
auto request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv));
|
||||||
auto protocol_client = TRY(launch_request_server_process(request_server_paths, s_ladybird_resource_root, certificates));
|
auto protocol_client = TRY(launch_request_server_process(request_server_paths, s_ladybird_resource_root));
|
||||||
|
|
||||||
m_impl->request_server_client = move(protocol_client);
|
m_impl->request_server_client = move(protocol_client);
|
||||||
return {};
|
return {};
|
||||||
|
@ -79,7 +78,7 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> ApplicationBridge::launch_web_
|
||||||
auto image_decoder_socket = TRY(connect_new_image_decoder_client(*m_impl->image_decoder_client));
|
auto image_decoder_socket = TRY(connect_new_image_decoder_client(*m_impl->image_decoder_client));
|
||||||
|
|
||||||
auto web_content_paths = TRY(get_paths_for_helper_process("WebContent"sv));
|
auto web_content_paths = TRY(get_paths_for_helper_process("WebContent"sv));
|
||||||
auto web_content = TRY(launch_web_content_process(web_view_bridge, web_content_paths, web_view_bridge.web_content_options(), move(image_decoder_socket), move(request_server_socket)));
|
auto web_content = TRY(launch_web_content_process(web_view_bridge, web_content_paths, move(image_decoder_socket), move(request_server_socket)));
|
||||||
|
|
||||||
return web_content;
|
return web_content;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/NonnullOwnPtr.h>
|
#include <AK/NonnullOwnPtr.h>
|
||||||
#include <AK/Vector.h>
|
|
||||||
#include <LibIPC/Forward.h>
|
#include <LibIPC/Forward.h>
|
||||||
|
#include <LibWebView/Application.h>
|
||||||
#include <LibWebView/Forward.h>
|
#include <LibWebView/Forward.h>
|
||||||
|
|
||||||
namespace Ladybird {
|
namespace Ladybird {
|
||||||
|
@ -16,12 +16,13 @@ namespace Ladybird {
|
||||||
struct ApplicationBridgeImpl;
|
struct ApplicationBridgeImpl;
|
||||||
class WebViewBridge;
|
class WebViewBridge;
|
||||||
|
|
||||||
class ApplicationBridge {
|
class ApplicationBridge : public WebView::Application {
|
||||||
|
WEB_VIEW_APPLICATION(ApplicationBridge)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ApplicationBridge();
|
|
||||||
~ApplicationBridge();
|
~ApplicationBridge();
|
||||||
|
|
||||||
ErrorOr<void> launch_request_server(Vector<ByteString> const& certificates);
|
ErrorOr<void> launch_request_server();
|
||||||
ErrorOr<void> launch_image_decoder();
|
ErrorOr<void> launch_image_decoder();
|
||||||
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content(WebViewBridge&);
|
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content(WebViewBridge&);
|
||||||
ErrorOr<IPC::File> launch_web_worker();
|
ErrorOr<IPC::File> launch_web_worker();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -8,8 +8,6 @@
|
||||||
|
|
||||||
#include <AK/Optional.h>
|
#include <AK/Optional.h>
|
||||||
#include <AK/StringView.h>
|
#include <AK/StringView.h>
|
||||||
#include <AK/Vector.h>
|
|
||||||
#include <Ladybird/Types.h>
|
|
||||||
#include <LibURL/URL.h>
|
#include <LibURL/URL.h>
|
||||||
#include <LibWeb/CSS/PreferredColorScheme.h>
|
#include <LibWeb/CSS/PreferredColorScheme.h>
|
||||||
#include <LibWeb/CSS/PreferredContrast.h>
|
#include <LibWeb/CSS/PreferredContrast.h>
|
||||||
|
@ -24,12 +22,7 @@
|
||||||
|
|
||||||
@interface ApplicationDelegate : NSObject <NSApplicationDelegate>
|
@interface ApplicationDelegate : NSObject <NSApplicationDelegate>
|
||||||
|
|
||||||
- (nullable instancetype)init:(Vector<URL::URL>)initial_urls
|
- (nullable instancetype)initWithCookieJar:(NonnullOwnPtr<WebView::CookieJar>)cookie_jar;
|
||||||
newTabPageURL:(URL::URL)new_tab_page_url
|
|
||||||
withCookieJar:(NonnullOwnPtr<WebView::CookieJar>)cookie_jar
|
|
||||||
webContentOptions:(Ladybird::WebContentOptions const&)web_content_options
|
|
||||||
webdriverContentIPCPath:(StringView)webdriver_content_ipc_path
|
|
||||||
allowPopups:(BOOL)allow_popups;
|
|
||||||
|
|
||||||
- (nonnull TabController*)createNewTab:(Optional<URL::URL> const&)url
|
- (nonnull TabController*)createNewTab:(Optional<URL::URL> const&)url
|
||||||
fromTab:(nullable Tab*)tab
|
fromTab:(nullable Tab*)tab
|
||||||
|
@ -46,8 +39,6 @@
|
||||||
- (void)removeTab:(nonnull TabController*)controller;
|
- (void)removeTab:(nonnull TabController*)controller;
|
||||||
|
|
||||||
- (WebView::CookieJar&)cookieJar;
|
- (WebView::CookieJar&)cookieJar;
|
||||||
- (Ladybird::WebContentOptions const&)webContentOptions;
|
|
||||||
- (Optional<StringView> const&)webdriverContentIPCPath;
|
|
||||||
- (Web::CSS::PreferredColorScheme)preferredColorScheme;
|
- (Web::CSS::PreferredColorScheme)preferredColorScheme;
|
||||||
- (Web::CSS::PreferredContrast)preferredContrast;
|
- (Web::CSS::PreferredContrast)preferredContrast;
|
||||||
- (Web::CSS::PreferredMotion)preferredMotion;
|
- (Web::CSS::PreferredMotion)preferredMotion;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <LibWebView/Application.h>
|
||||||
#include <LibWebView/SearchEngine.h>
|
#include <LibWebView/SearchEngine.h>
|
||||||
|
|
||||||
#import <Application/ApplicationDelegate.h>
|
#import <Application/ApplicationDelegate.h>
|
||||||
|
@ -29,23 +30,15 @@
|
||||||
|
|
||||||
@interface ApplicationDelegate () <TaskManagerDelegate>
|
@interface ApplicationDelegate () <TaskManagerDelegate>
|
||||||
{
|
{
|
||||||
Vector<URL::URL> m_initial_urls;
|
|
||||||
URL::URL m_new_tab_page_url;
|
|
||||||
|
|
||||||
// This will always be populated, but we cannot have a non-default constructible instance variable.
|
// This will always be populated, but we cannot have a non-default constructible instance variable.
|
||||||
OwnPtr<WebView::CookieJar> m_cookie_jar;
|
OwnPtr<WebView::CookieJar> m_cookie_jar;
|
||||||
|
|
||||||
Ladybird::WebContentOptions m_web_content_options;
|
|
||||||
Optional<StringView> m_webdriver_content_ipc_path;
|
|
||||||
|
|
||||||
Web::CSS::PreferredColorScheme m_preferred_color_scheme;
|
Web::CSS::PreferredColorScheme m_preferred_color_scheme;
|
||||||
Web::CSS::PreferredContrast m_preferred_contrast;
|
Web::CSS::PreferredContrast m_preferred_contrast;
|
||||||
Web::CSS::PreferredMotion m_preferred_motion;
|
Web::CSS::PreferredMotion m_preferred_motion;
|
||||||
ByteString m_navigator_compatibility_mode;
|
ByteString m_navigator_compatibility_mode;
|
||||||
|
|
||||||
WebView::SearchEngine m_search_engine;
|
WebView::SearchEngine m_search_engine;
|
||||||
|
|
||||||
BOOL m_allow_popups;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (nonatomic, strong) NSMutableArray<TabController*>* managed_tabs;
|
@property (nonatomic, strong) NSMutableArray<TabController*>* managed_tabs;
|
||||||
|
@ -68,12 +61,7 @@
|
||||||
|
|
||||||
@implementation ApplicationDelegate
|
@implementation ApplicationDelegate
|
||||||
|
|
||||||
- (instancetype)init:(Vector<URL::URL>)initial_urls
|
- (instancetype)initWithCookieJar:(NonnullOwnPtr<WebView::CookieJar>)cookie_jar
|
||||||
newTabPageURL:(URL::URL)new_tab_page_url
|
|
||||||
withCookieJar:(NonnullOwnPtr<WebView::CookieJar>)cookie_jar
|
|
||||||
webContentOptions:(Ladybird::WebContentOptions const&)web_content_options
|
|
||||||
webdriverContentIPCPath:(StringView)webdriver_content_ipc_path
|
|
||||||
allowPopups:(BOOL)allow_popups
|
|
||||||
{
|
{
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
[NSApp setMainMenu:[[NSMenu alloc] init]];
|
[NSApp setMainMenu:[[NSMenu alloc] init]];
|
||||||
|
@ -91,25 +79,14 @@
|
||||||
|
|
||||||
self.managed_tabs = [[NSMutableArray alloc] init];
|
self.managed_tabs = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
m_initial_urls = move(initial_urls);
|
|
||||||
m_new_tab_page_url = move(new_tab_page_url);
|
|
||||||
|
|
||||||
m_cookie_jar = move(cookie_jar);
|
m_cookie_jar = move(cookie_jar);
|
||||||
|
|
||||||
m_web_content_options = web_content_options;
|
|
||||||
|
|
||||||
if (!webdriver_content_ipc_path.is_empty()) {
|
|
||||||
m_webdriver_content_ipc_path = webdriver_content_ipc_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_preferred_color_scheme = Web::CSS::PreferredColorScheme::Auto;
|
m_preferred_color_scheme = Web::CSS::PreferredColorScheme::Auto;
|
||||||
m_preferred_contrast = Web::CSS::PreferredContrast::Auto;
|
m_preferred_contrast = Web::CSS::PreferredContrast::Auto;
|
||||||
m_preferred_motion = Web::CSS::PreferredMotion::Auto;
|
m_preferred_motion = Web::CSS::PreferredMotion::Auto;
|
||||||
m_navigator_compatibility_mode = "chrome";
|
m_navigator_compatibility_mode = "chrome";
|
||||||
m_search_engine = WebView::default_search_engine();
|
m_search_engine = WebView::default_search_engine();
|
||||||
|
|
||||||
m_allow_popups = allow_popups;
|
|
||||||
|
|
||||||
// Reduce the tooltip delay, as the default delay feels quite long.
|
// Reduce the tooltip delay, as the default delay feels quite long.
|
||||||
[[NSUserDefaults standardUserDefaults] setObject:@100 forKey:@"NSInitialToolTipDelay"];
|
[[NSUserDefaults standardUserDefaults] setObject:@100 forKey:@"NSInitialToolTipDelay"];
|
||||||
}
|
}
|
||||||
|
@ -124,7 +101,7 @@
|
||||||
activateTab:(Web::HTML::ActivateTab)activate_tab
|
activateTab:(Web::HTML::ActivateTab)activate_tab
|
||||||
{
|
{
|
||||||
auto* controller = [self createNewTab:activate_tab fromTab:tab];
|
auto* controller = [self createNewTab:activate_tab fromTab:tab];
|
||||||
[controller loadURL:url.value_or(m_new_tab_page_url)];
|
[controller loadURL:url.value_or(WebView::Application::chrome_options().new_tab_page_url)];
|
||||||
|
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
@ -166,16 +143,6 @@
|
||||||
return *m_cookie_jar;
|
return *m_cookie_jar;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (Ladybird::WebContentOptions const&)webContentOptions
|
|
||||||
{
|
|
||||||
return m_web_content_options;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (Optional<StringView> const&)webdriverContentIPCPath
|
|
||||||
{
|
|
||||||
return m_webdriver_content_ipc_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (Web::CSS::PreferredColorScheme)preferredColorScheme
|
- (Web::CSS::PreferredColorScheme)preferredColorScheme
|
||||||
{
|
{
|
||||||
return m_preferred_color_scheme;
|
return m_preferred_color_scheme;
|
||||||
|
@ -213,7 +180,7 @@
|
||||||
- (nonnull TabController*)createNewTab:(Web::HTML::ActivateTab)activate_tab
|
- (nonnull TabController*)createNewTab:(Web::HTML::ActivateTab)activate_tab
|
||||||
fromTab:(nullable Tab*)tab
|
fromTab:(nullable Tab*)tab
|
||||||
{
|
{
|
||||||
auto* controller = [[TabController alloc] init:!m_allow_popups];
|
auto* controller = [[TabController alloc] init];
|
||||||
[controller showWindow:nil];
|
[controller showWindow:nil];
|
||||||
|
|
||||||
if (tab) {
|
if (tab) {
|
||||||
|
@ -740,7 +707,7 @@
|
||||||
{
|
{
|
||||||
Tab* tab = nil;
|
Tab* tab = nil;
|
||||||
|
|
||||||
for (auto const& url : m_initial_urls) {
|
for (auto const& url : WebView::Application::chrome_options().urls) {
|
||||||
auto activate_tab = tab == nil ? Web::HTML::ActivateTab::Yes : Web::HTML::ActivateTab::No;
|
auto activate_tab = tab == nil ? Web::HTML::ActivateTab::Yes : Web::HTML::ActivateTab::No;
|
||||||
|
|
||||||
auto* controller = [self createNewTab:url
|
auto* controller = [self createNewTab:url
|
||||||
|
@ -749,8 +716,6 @@
|
||||||
|
|
||||||
tab = (Tab*)[controller window];
|
tab = (Tab*)[controller window];
|
||||||
}
|
}
|
||||||
|
|
||||||
m_initial_urls.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationWillTerminate:(NSNotification*)notification
|
- (void)applicationWillTerminate:(NSNotification*)notification
|
||||||
|
|
|
@ -104,7 +104,7 @@ struct HideCursor {
|
||||||
// This returns device pixel ratio of the screen the window is opened in
|
// This returns device pixel ratio of the screen the window is opened in
|
||||||
auto device_pixel_ratio = [[NSScreen mainScreen] backingScaleFactor];
|
auto device_pixel_ratio = [[NSScreen mainScreen] backingScaleFactor];
|
||||||
|
|
||||||
m_web_view_bridge = MUST(Ladybird::WebViewBridge::create(move(screen_rects), device_pixel_ratio, [delegate webContentOptions], [delegate webdriverContentIPCPath], [delegate preferredColorScheme], [delegate preferredContrast], [delegate preferredMotion]));
|
m_web_view_bridge = MUST(Ladybird::WebViewBridge::create(move(screen_rects), device_pixel_ratio, [delegate preferredColorScheme], [delegate preferredContrast], [delegate preferredMotion]));
|
||||||
[self setWebViewCallbacks];
|
[self setWebViewCallbacks];
|
||||||
|
|
||||||
m_web_view_bridge->initialize_client();
|
m_web_view_bridge->initialize_client();
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Ladybird/HelperProcess.h>
|
#include <Ladybird/HelperProcess.h>
|
||||||
#include <Ladybird/Types.h>
|
|
||||||
#include <Ladybird/Utilities.h>
|
#include <Ladybird/Utilities.h>
|
||||||
#include <LibGfx/Font/FontDatabase.h>
|
#include <LibGfx/Font/FontDatabase.h>
|
||||||
#include <LibGfx/Rect.h>
|
#include <LibGfx/Rect.h>
|
||||||
#include <LibIPC/File.h>
|
#include <LibIPC/File.h>
|
||||||
#include <LibWeb/Crypto/Crypto.h>
|
#include <LibWeb/Crypto/Crypto.h>
|
||||||
|
#include <LibWebView/Application.h>
|
||||||
#include <UI/LadybirdWebViewBridge.h>
|
#include <UI/LadybirdWebViewBridge.h>
|
||||||
|
|
||||||
#import <UI/Palette.h>
|
#import <UI/Palette.h>
|
||||||
|
@ -23,15 +23,13 @@ static T scale_for_device(T size, float device_pixel_ratio)
|
||||||
return size.template to_type<float>().scaled(device_pixel_ratio).template to_type<int>();
|
return size.template to_type<float>().scaled(device_pixel_ratio).template to_type<int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<NonnullOwnPtr<WebViewBridge>> WebViewBridge::create(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, WebContentOptions const& web_content_options, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme preferred_color_scheme, Web::CSS::PreferredContrast preferred_contrast, Web::CSS::PreferredMotion preferred_motion)
|
ErrorOr<NonnullOwnPtr<WebViewBridge>> WebViewBridge::create(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, Web::CSS::PreferredColorScheme preferred_color_scheme, Web::CSS::PreferredContrast preferred_contrast, Web::CSS::PreferredMotion preferred_motion)
|
||||||
{
|
{
|
||||||
return adopt_nonnull_own_or_enomem(new (nothrow) WebViewBridge(move(screen_rects), device_pixel_ratio, web_content_options, move(webdriver_content_ipc_path), preferred_color_scheme, preferred_contrast, preferred_motion));
|
return adopt_nonnull_own_or_enomem(new (nothrow) WebViewBridge(move(screen_rects), device_pixel_ratio, preferred_color_scheme, preferred_contrast, preferred_motion));
|
||||||
}
|
}
|
||||||
|
|
||||||
WebViewBridge::WebViewBridge(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, WebContentOptions const& web_content_options, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme preferred_color_scheme, Web::CSS::PreferredContrast preferred_contrast, Web::CSS::PreferredMotion preferred_motion)
|
WebViewBridge::WebViewBridge(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, Web::CSS::PreferredColorScheme preferred_color_scheme, Web::CSS::PreferredContrast preferred_contrast, Web::CSS::PreferredMotion preferred_motion)
|
||||||
: m_screen_rects(move(screen_rects))
|
: m_screen_rects(move(screen_rects))
|
||||||
, m_web_content_options(web_content_options)
|
|
||||||
, m_webdriver_content_ipc_path(move(webdriver_content_ipc_path))
|
|
||||||
, m_preferred_color_scheme(preferred_color_scheme)
|
, m_preferred_color_scheme(preferred_color_scheme)
|
||||||
, m_preferred_contrast(preferred_contrast)
|
, m_preferred_contrast(preferred_contrast)
|
||||||
, m_preferred_motion(preferred_motion)
|
, m_preferred_motion(preferred_motion)
|
||||||
|
@ -168,8 +166,8 @@ void WebViewBridge::initialize_client(CreateNewClient)
|
||||||
client().async_update_screen_rects(m_client_state.page_index, m_screen_rects, 0);
|
client().async_update_screen_rects(m_client_state.page_index, m_screen_rects, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_webdriver_content_ipc_path.has_value()) {
|
if (auto const& webdriver_content_ipc_path = WebView::Application::chrome_options().webdriver_content_ipc_path; webdriver_content_ipc_path.has_value()) {
|
||||||
client().async_connect_to_webdriver(m_client_state.page_index, *m_webdriver_content_ipc_path);
|
client().async_connect_to_webdriver(m_client_state.page_index, *webdriver_content_ipc_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -7,7 +7,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <Ladybird/Types.h>
|
|
||||||
#include <LibGfx/Point.h>
|
#include <LibGfx/Point.h>
|
||||||
#include <LibGfx/Rect.h>
|
#include <LibGfx/Rect.h>
|
||||||
#include <LibGfx/Size.h>
|
#include <LibGfx/Size.h>
|
||||||
|
@ -22,13 +21,11 @@ namespace Ladybird {
|
||||||
|
|
||||||
class WebViewBridge final : public WebView::ViewImplementation {
|
class WebViewBridge final : public WebView::ViewImplementation {
|
||||||
public:
|
public:
|
||||||
static ErrorOr<NonnullOwnPtr<WebViewBridge>> create(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, WebContentOptions const&, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme, Web::CSS::PreferredContrast, Web::CSS::PreferredMotion);
|
static ErrorOr<NonnullOwnPtr<WebViewBridge>> create(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, Web::CSS::PreferredColorScheme, Web::CSS::PreferredContrast, Web::CSS::PreferredMotion);
|
||||||
virtual ~WebViewBridge() override;
|
virtual ~WebViewBridge() override;
|
||||||
|
|
||||||
virtual void initialize_client(CreateNewClient = CreateNewClient::Yes) override;
|
virtual void initialize_client(CreateNewClient = CreateNewClient::Yes) override;
|
||||||
|
|
||||||
WebContentOptions const& web_content_options() const { return m_web_content_options; }
|
|
||||||
|
|
||||||
float device_pixel_ratio() const { return m_device_pixel_ratio; }
|
float device_pixel_ratio() const { return m_device_pixel_ratio; }
|
||||||
void set_device_pixel_ratio(float device_pixel_ratio);
|
void set_device_pixel_ratio(float device_pixel_ratio);
|
||||||
float inverse_device_pixel_ratio() const { return 1.0f / m_device_pixel_ratio; }
|
float inverse_device_pixel_ratio() const { return 1.0f / m_device_pixel_ratio; }
|
||||||
|
@ -59,7 +56,7 @@ public:
|
||||||
Function<void()> on_zoom_level_changed;
|
Function<void()> on_zoom_level_changed;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WebViewBridge(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, WebContentOptions const&, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme, Web::CSS::PreferredContrast, Web::CSS::PreferredMotion);
|
WebViewBridge(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, Web::CSS::PreferredColorScheme, Web::CSS::PreferredContrast, Web::CSS::PreferredMotion);
|
||||||
|
|
||||||
virtual void update_zoom() override;
|
virtual void update_zoom() override;
|
||||||
virtual Web::DevicePixelSize viewport_size() const override;
|
virtual Web::DevicePixelSize viewport_size() const override;
|
||||||
|
@ -69,9 +66,6 @@ private:
|
||||||
Vector<Web::DevicePixelRect> m_screen_rects;
|
Vector<Web::DevicePixelRect> m_screen_rects;
|
||||||
Gfx::IntSize m_viewport_size;
|
Gfx::IntSize m_viewport_size;
|
||||||
|
|
||||||
WebContentOptions m_web_content_options;
|
|
||||||
Optional<StringView> m_webdriver_content_ipc_path;
|
|
||||||
|
|
||||||
Web::CSS::PreferredColorScheme m_preferred_color_scheme { Web::CSS::PreferredColorScheme::Auto };
|
Web::CSS::PreferredColorScheme m_preferred_color_scheme { Web::CSS::PreferredColorScheme::Auto };
|
||||||
Web::CSS::PreferredContrast m_preferred_contrast { Web::CSS::PreferredContrast::Auto };
|
Web::CSS::PreferredContrast m_preferred_contrast { Web::CSS::PreferredContrast::Auto };
|
||||||
Web::CSS::PreferredMotion m_preferred_motion { Web::CSS::PreferredMotion::Auto };
|
Web::CSS::PreferredMotion m_preferred_motion { Web::CSS::PreferredMotion::Auto };
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -22,7 +22,7 @@ struct TabSettings {
|
||||||
|
|
||||||
@interface TabController : NSWindowController <NSWindowDelegate>
|
@interface TabController : NSWindowController <NSWindowDelegate>
|
||||||
|
|
||||||
- (instancetype)init:(BOOL)block_popups;
|
- (instancetype)init;
|
||||||
|
|
||||||
- (void)loadURL:(URL::URL const&)url;
|
- (void)loadURL:(URL::URL const&)url;
|
||||||
- (void)loadHTML:(StringView)html url:(URL::URL const&)url;
|
- (void)loadHTML:(StringView)html url:(URL::URL const&)url;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <LibWeb/Loader/UserAgent.h>
|
#include <LibWeb/Loader/UserAgent.h>
|
||||||
|
#include <LibWebView/Application.h>
|
||||||
#include <LibWebView/SearchEngine.h>
|
#include <LibWebView/SearchEngine.h>
|
||||||
#include <LibWebView/URL.h>
|
#include <LibWebView/URL.h>
|
||||||
#include <LibWebView/UserAgent.h>
|
#include <LibWebView/UserAgent.h>
|
||||||
|
@ -82,7 +83,7 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
|
||||||
@synthesize new_tab_toolbar_item = _new_tab_toolbar_item;
|
@synthesize new_tab_toolbar_item = _new_tab_toolbar_item;
|
||||||
@synthesize tab_overview_toolbar_item = _tab_overview_toolbar_item;
|
@synthesize tab_overview_toolbar_item = _tab_overview_toolbar_item;
|
||||||
|
|
||||||
- (instancetype)init:(BOOL)block_popups
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
self.toolbar = [[NSToolbar alloc] initWithIdentifier:TOOLBAR_IDENTIFIER];
|
self.toolbar = [[NSToolbar alloc] initWithIdentifier:TOOLBAR_IDENTIFIER];
|
||||||
|
@ -91,7 +92,7 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
|
||||||
[self.toolbar setAllowsUserCustomization:NO];
|
[self.toolbar setAllowsUserCustomization:NO];
|
||||||
[self.toolbar setSizeMode:NSToolbarSizeModeRegular];
|
[self.toolbar setSizeMode:NSToolbarSizeModeRegular];
|
||||||
|
|
||||||
m_settings = { .block_popups = block_popups };
|
m_settings = { .block_popups = WebView::Application::chrome_options().allow_popups == WebView::AllowPopups::Yes ? NO : YES };
|
||||||
m_can_navigate_back = false;
|
m_can_navigate_back = false;
|
||||||
m_can_navigate_forward = false;
|
m_can_navigate_forward = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -7,9 +7,7 @@
|
||||||
#include <AK/Enumerate.h>
|
#include <AK/Enumerate.h>
|
||||||
#include <Ladybird/DefaultSettings.h>
|
#include <Ladybird/DefaultSettings.h>
|
||||||
#include <Ladybird/MachPortServer.h>
|
#include <Ladybird/MachPortServer.h>
|
||||||
#include <Ladybird/Types.h>
|
|
||||||
#include <Ladybird/Utilities.h>
|
#include <Ladybird/Utilities.h>
|
||||||
#include <LibCore/ArgsParser.h>
|
|
||||||
#include <LibGfx/Font/FontDatabase.h>
|
#include <LibGfx/Font/FontDatabase.h>
|
||||||
#include <LibMain/Main.h>
|
#include <LibMain/Main.h>
|
||||||
#include <LibWebView/Application.h>
|
#include <LibWebView/Application.h>
|
||||||
|
@ -30,33 +28,10 @@
|
||||||
# error "This project requires ARC"
|
# error "This project requires ARC"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static Vector<URL::URL> sanitize_urls(Vector<ByteString> const& raw_urls)
|
static void open_urls_from_client(Vector<URL::URL> const& urls, WebView::NewWindow new_window)
|
||||||
{
|
|
||||||
Vector<URL::URL> sanitized_urls;
|
|
||||||
for (auto const& raw_url : raw_urls) {
|
|
||||||
if (auto url = WebView::sanitize_url(raw_url); url.has_value())
|
|
||||||
sanitized_urls.append(url.release_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sanitized_urls.is_empty()) {
|
|
||||||
URL::URL new_tab_page_url = Browser::default_new_tab_url;
|
|
||||||
sanitized_urls.append(move(new_tab_page_url));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sanitized_urls;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class NewWindow {
|
|
||||||
No,
|
|
||||||
Yes,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void open_urls_from_client(Vector<ByteString> const& raw_urls, NewWindow new_window)
|
|
||||||
{
|
{
|
||||||
ApplicationDelegate* delegate = [NSApp delegate];
|
ApplicationDelegate* delegate = [NSApp delegate];
|
||||||
Tab* tab = new_window == NewWindow::Yes ? nil : [delegate activeTab];
|
Tab* tab = new_window == WebView::NewWindow::Yes ? nil : [delegate activeTab];
|
||||||
|
|
||||||
auto urls = sanitize_urls(raw_urls);
|
|
||||||
|
|
||||||
for (auto [i, url] : enumerate(urls)) {
|
for (auto [i, url] : enumerate(urls)) {
|
||||||
auto activate_tab = i == 0 ? Web::HTML::ActivateTab::Yes : Web::HTML::ActivateTab::No;
|
auto activate_tab = i == 0 ? Web::HTML::ActivateTab::Yes : Web::HTML::ActivateTab::No;
|
||||||
|
@ -76,51 +51,33 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
Application* application = [Application sharedApplication];
|
Application* application = [Application sharedApplication];
|
||||||
|
|
||||||
Core::EventLoopManager::install(*new Ladybird::CFEventLoopManager);
|
Core::EventLoopManager::install(*new Ladybird::CFEventLoopManager);
|
||||||
WebView::Application web_view_app(arguments.argc, arguments.argv);
|
[application setupWebViewApplication:arguments newTabPageURL:Browser::default_new_tab_url];
|
||||||
|
|
||||||
platform_init();
|
platform_init();
|
||||||
|
|
||||||
Vector<ByteString> raw_urls;
|
|
||||||
Vector<ByteString> certificates;
|
|
||||||
StringView webdriver_content_ipc_path;
|
|
||||||
bool debug_web_content = false;
|
|
||||||
bool log_all_js_exceptions = false;
|
|
||||||
bool enable_http_cache = false;
|
|
||||||
bool new_window = false;
|
|
||||||
bool force_new_process = false;
|
|
||||||
bool allow_popups = false;
|
|
||||||
|
|
||||||
Core::ArgsParser args_parser;
|
|
||||||
args_parser.set_general_help("The Ladybird web browser");
|
|
||||||
args_parser.add_positional_argument(raw_urls, "URLs to open", "url", Core::ArgsParser::Required::No);
|
|
||||||
args_parser.add_option(webdriver_content_ipc_path, "Path to WebDriver IPC for WebContent", "webdriver-content-path", 0, "path", Core::ArgsParser::OptionHideMode::CommandLineAndMarkdown);
|
|
||||||
args_parser.add_option(debug_web_content, "Wait for debugger to attach to WebContent", "debug-web-content");
|
|
||||||
args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate");
|
|
||||||
args_parser.add_option(log_all_js_exceptions, "Log all JavaScript exceptions", "log-all-js-exceptions");
|
|
||||||
args_parser.add_option(enable_http_cache, "Enable HTTP cache", "enable-http-cache");
|
|
||||||
args_parser.add_option(new_window, "Force opening in a new window", "new-window", 'n');
|
|
||||||
args_parser.add_option(force_new_process, "Force creation of new browser/chrome process", "force-new-process");
|
|
||||||
args_parser.add_option(allow_popups, "Disable popup blocking by default", "allow-popups");
|
|
||||||
args_parser.parse(arguments);
|
|
||||||
|
|
||||||
auto chrome_process = TRY(WebView::ChromeProcess::create());
|
auto chrome_process = TRY(WebView::ChromeProcess::create());
|
||||||
if (!force_new_process && TRY(chrome_process.connect(raw_urls, new_window)) == WebView::ChromeProcess::ProcessDisposition::ExitProcess) {
|
|
||||||
|
if (auto const& chrome_options = WebView::Application::chrome_options(); chrome_options.force_new_process == WebView::ForceNewProcess::No) {
|
||||||
|
auto disposition = TRY(chrome_process.connect(chrome_options.raw_urls, chrome_options.new_window));
|
||||||
|
|
||||||
|
if (disposition == WebView::ChromeProcess::ProcessDisposition::ExitProcess) {
|
||||||
outln("Opening in existing process");
|
outln("Opening in existing process");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
chrome_process.on_new_tab = [&](auto const& raw_urls) {
|
chrome_process.on_new_tab = [&](auto const& raw_urls) {
|
||||||
open_urls_from_client(raw_urls, NewWindow::No);
|
open_urls_from_client(raw_urls, WebView::NewWindow::No);
|
||||||
};
|
};
|
||||||
|
|
||||||
chrome_process.on_new_window = [&](auto const& raw_urls) {
|
chrome_process.on_new_window = [&](auto const& raw_urls) {
|
||||||
open_urls_from_client(raw_urls, NewWindow::Yes);
|
open_urls_from_client(raw_urls, WebView::NewWindow::Yes);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto mach_port_server = make<Ladybird::MachPortServer>();
|
auto mach_port_server = make<Ladybird::MachPortServer>();
|
||||||
set_mach_server_name(mach_port_server->server_port_name());
|
set_mach_server_name(mach_port_server->server_port_name());
|
||||||
mach_port_server->on_receive_child_mach_port = [&web_view_app](auto pid, auto port) {
|
mach_port_server->on_receive_child_mach_port = [&](auto pid, auto port) {
|
||||||
web_view_app.set_process_mach_port(pid, move(port));
|
WebView::Application::the().set_process_mach_port(pid, move(port));
|
||||||
};
|
};
|
||||||
mach_port_server->on_receive_backing_stores = [](Ladybird::MachPortServer::BackingStoresMessage message) {
|
mach_port_server->on_receive_backing_stores = [](Ladybird::MachPortServer::BackingStoresMessage message) {
|
||||||
if (auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id); view.has_value())
|
if (auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id); view.has_value())
|
||||||
|
@ -131,28 +88,12 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
auto cookie_jar = TRY(WebView::CookieJar::create(*database));
|
auto cookie_jar = TRY(WebView::CookieJar::create(*database));
|
||||||
|
|
||||||
// FIXME: Create an abstraction to re-spawn the RequestServer and re-hook up its client hooks to each tab on crash
|
// FIXME: Create an abstraction to re-spawn the RequestServer and re-hook up its client hooks to each tab on crash
|
||||||
TRY([application launchRequestServer:certificates]);
|
TRY([application launchRequestServer]);
|
||||||
|
|
||||||
TRY([application launchImageDecoder]);
|
TRY([application launchImageDecoder]);
|
||||||
|
|
||||||
StringBuilder command_line_builder;
|
auto* delegate = [[ApplicationDelegate alloc] initWithCookieJar:move(cookie_jar)];
|
||||||
command_line_builder.join(' ', arguments.strings);
|
|
||||||
Ladybird::WebContentOptions web_content_options {
|
|
||||||
.command_line = MUST(command_line_builder.to_string()),
|
|
||||||
.executable_path = MUST(String::from_byte_string(MUST(Core::System::current_executable_path()))),
|
|
||||||
.wait_for_debugger = debug_web_content ? Ladybird::WaitForDebugger::Yes : Ladybird::WaitForDebugger::No,
|
|
||||||
.log_all_js_exceptions = log_all_js_exceptions ? Ladybird::LogAllJSExceptions::Yes : Ladybird::LogAllJSExceptions::No,
|
|
||||||
.enable_http_cache = enable_http_cache ? Ladybird::EnableHTTPCache::Yes : Ladybird::EnableHTTPCache::No,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto* delegate = [[ApplicationDelegate alloc] init:sanitize_urls(raw_urls)
|
|
||||||
newTabPageURL:URL::URL { Browser::default_new_tab_url }
|
|
||||||
withCookieJar:move(cookie_jar)
|
|
||||||
webContentOptions:web_content_options
|
|
||||||
webdriverContentIPCPath:webdriver_content_ipc_path
|
|
||||||
allowPopups:allow_popups];
|
|
||||||
|
|
||||||
[NSApp setDelegate:delegate];
|
[NSApp setDelegate:delegate];
|
||||||
|
|
||||||
return web_view_app.exec();
|
return WebView::Application::the().execute();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ set(LADYBIRD_SOURCES
|
||||||
)
|
)
|
||||||
set(LADYBIRD_HEADERS
|
set(LADYBIRD_HEADERS
|
||||||
HelperProcess.h
|
HelperProcess.h
|
||||||
Types.h
|
|
||||||
Utilities.h
|
Utilities.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,10 @@ static ErrorOr<NonnullRefPtr<ClientType>> launch_server_process(
|
||||||
StringView server_name,
|
StringView server_name,
|
||||||
ReadonlySpan<ByteString> candidate_server_paths,
|
ReadonlySpan<ByteString> candidate_server_paths,
|
||||||
Vector<ByteString> arguments,
|
Vector<ByteString> arguments,
|
||||||
Ladybird::EnableCallgrindProfiling enable_callgrind_profiling,
|
WebView::EnableCallgrindProfiling enable_callgrind_profiling,
|
||||||
ClientArguments&&... client_arguments)
|
ClientArguments&&... client_arguments)
|
||||||
{
|
{
|
||||||
if (enable_callgrind_profiling == Ladybird::EnableCallgrindProfiling::Yes) {
|
if (enable_callgrind_profiling == WebView::EnableCallgrindProfiling::Yes) {
|
||||||
arguments.prepend({
|
arguments.prepend({
|
||||||
"--tool=callgrind"sv,
|
"--tool=callgrind"sv,
|
||||||
"--instr-atstart=no"sv,
|
"--instr-atstart=no"sv,
|
||||||
|
@ -29,7 +29,7 @@ static ErrorOr<NonnullRefPtr<ClientType>> launch_server_process(
|
||||||
for (auto [i, path] : enumerate(candidate_server_paths)) {
|
for (auto [i, path] : enumerate(candidate_server_paths)) {
|
||||||
Core::ProcessSpawnOptions options { .name = server_name, .arguments = arguments };
|
Core::ProcessSpawnOptions options { .name = server_name, .arguments = arguments };
|
||||||
|
|
||||||
if (enable_callgrind_profiling == Ladybird::EnableCallgrindProfiling::Yes) {
|
if (enable_callgrind_profiling == WebView::EnableCallgrindProfiling::Yes) {
|
||||||
options.executable = "valgrind"sv;
|
options.executable = "valgrind"sv;
|
||||||
options.search_for_executable_in_path = true;
|
options.search_for_executable_in_path = true;
|
||||||
arguments[2] = path;
|
arguments[2] = path;
|
||||||
|
@ -47,7 +47,7 @@ static ErrorOr<NonnullRefPtr<ClientType>> launch_server_process(
|
||||||
|
|
||||||
WebView::Application::the().add_child_process(WebView::Process { WebView::process_type_from_name(server_name), process.client, move(process.process) });
|
WebView::Application::the().add_child_process(WebView::Process { WebView::process_type_from_name(server_name), process.client, move(process.process) });
|
||||||
|
|
||||||
if (enable_callgrind_profiling == Ladybird::EnableCallgrindProfiling::Yes) {
|
if (enable_callgrind_profiling == WebView::EnableCallgrindProfiling::Yes) {
|
||||||
dbgln();
|
dbgln();
|
||||||
dbgln("\033[1;45mLaunched {} process under callgrind!\033[0m", server_name);
|
dbgln("\033[1;45mLaunched {} process under callgrind!\033[0m", server_name);
|
||||||
dbgln("\033[100mRun `\033[4mcallgrind_control -i on\033[24m` to start instrumentation and `\033[4mcallgrind_control -i off\033[24m` stop it again.\033[0m");
|
dbgln("\033[100mRun `\033[4mcallgrind_control -i on\033[24m` to start instrumentation and `\033[4mcallgrind_control -i off\033[24m` stop it again.\033[0m");
|
||||||
|
@ -69,10 +69,11 @@ static ErrorOr<NonnullRefPtr<ClientType>> launch_server_process(
|
||||||
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
||||||
WebView::ViewImplementation& view,
|
WebView::ViewImplementation& view,
|
||||||
ReadonlySpan<ByteString> candidate_web_content_paths,
|
ReadonlySpan<ByteString> candidate_web_content_paths,
|
||||||
Ladybird::WebContentOptions const& web_content_options,
|
|
||||||
IPC::File image_decoder_socket,
|
IPC::File image_decoder_socket,
|
||||||
Optional<IPC::File> request_server_socket)
|
Optional<IPC::File> request_server_socket)
|
||||||
{
|
{
|
||||||
|
auto const& web_content_options = WebView::Application::web_content_options();
|
||||||
|
|
||||||
Vector<ByteString> arguments {
|
Vector<ByteString> arguments {
|
||||||
"--command-line"sv,
|
"--command-line"sv,
|
||||||
web_content_options.command_line.to_byte_string(),
|
web_content_options.command_line.to_byte_string(),
|
||||||
|
@ -84,19 +85,19 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
||||||
arguments.append("--config-path"sv);
|
arguments.append("--config-path"sv);
|
||||||
arguments.append(web_content_options.config_path.value());
|
arguments.append(web_content_options.config_path.value());
|
||||||
}
|
}
|
||||||
if (web_content_options.is_layout_test_mode == Ladybird::IsLayoutTestMode::Yes)
|
if (web_content_options.is_layout_test_mode == WebView::IsLayoutTestMode::Yes)
|
||||||
arguments.append("--layout-test-mode"sv);
|
arguments.append("--layout-test-mode"sv);
|
||||||
if (web_content_options.use_lagom_networking == Ladybird::UseLagomNetworking::Yes)
|
if (web_content_options.use_lagom_networking == WebView::UseLagomNetworking::Yes)
|
||||||
arguments.append("--use-lagom-networking"sv);
|
arguments.append("--use-lagom-networking"sv);
|
||||||
if (web_content_options.wait_for_debugger == Ladybird::WaitForDebugger::Yes)
|
if (web_content_options.wait_for_debugger == WebView::WaitForDebugger::Yes)
|
||||||
arguments.append("--wait-for-debugger"sv);
|
arguments.append("--wait-for-debugger"sv);
|
||||||
if (web_content_options.log_all_js_exceptions == Ladybird::LogAllJSExceptions::Yes)
|
if (web_content_options.log_all_js_exceptions == WebView::LogAllJSExceptions::Yes)
|
||||||
arguments.append("--log-all-js-exceptions"sv);
|
arguments.append("--log-all-js-exceptions"sv);
|
||||||
if (web_content_options.enable_idl_tracing == Ladybird::EnableIDLTracing::Yes)
|
if (web_content_options.enable_idl_tracing == WebView::EnableIDLTracing::Yes)
|
||||||
arguments.append("--enable-idl-tracing"sv);
|
arguments.append("--enable-idl-tracing"sv);
|
||||||
if (web_content_options.enable_http_cache == Ladybird::EnableHTTPCache::Yes)
|
if (web_content_options.enable_http_cache == WebView::EnableHTTPCache::Yes)
|
||||||
arguments.append("--enable-http-cache"sv);
|
arguments.append("--enable-http-cache"sv);
|
||||||
if (web_content_options.expose_internals_object == Ladybird::ExposeInternalsObject::Yes)
|
if (web_content_options.expose_internals_object == WebView::ExposeInternalsObject::Yes)
|
||||||
arguments.append("--expose-internals-object"sv);
|
arguments.append("--expose-internals-object"sv);
|
||||||
if (auto server = mach_server_name(); server.has_value()) {
|
if (auto server = mach_server_name(); server.has_value()) {
|
||||||
arguments.append("--mach-server-name"sv);
|
arguments.append("--mach-server-name"sv);
|
||||||
|
@ -121,7 +122,7 @@ ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process(
|
||||||
arguments.append(server.value());
|
arguments.append(server.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
return launch_server_process<ImageDecoderClient::Client>("ImageDecoder"sv, candidate_image_decoder_paths, arguments, Ladybird::EnableCallgrindProfiling::No);
|
return launch_server_process<ImageDecoderClient::Client>("ImageDecoder"sv, candidate_image_decoder_paths, arguments, WebView::EnableCallgrindProfiling::No);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process(ReadonlySpan<ByteString> candidate_web_worker_paths, RefPtr<Protocol::RequestClient> request_client)
|
ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process(ReadonlySpan<ByteString> candidate_web_worker_paths, RefPtr<Protocol::RequestClient> request_client)
|
||||||
|
@ -132,13 +133,13 @@ ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process(Rea
|
||||||
arguments.append("--request-server-socket"sv);
|
arguments.append("--request-server-socket"sv);
|
||||||
arguments.append(ByteString::number(socket.fd()));
|
arguments.append(ByteString::number(socket.fd()));
|
||||||
arguments.append("--use-lagom-networking"sv);
|
arguments.append("--use-lagom-networking"sv);
|
||||||
return launch_server_process<Web::HTML::WebWorkerClient>("WebWorker"sv, candidate_web_worker_paths, move(arguments), Ladybird::EnableCallgrindProfiling::No);
|
return launch_server_process<Web::HTML::WebWorkerClient>("WebWorker"sv, candidate_web_worker_paths, move(arguments), WebView::EnableCallgrindProfiling::No);
|
||||||
}
|
}
|
||||||
|
|
||||||
return launch_server_process<Web::HTML::WebWorkerClient>("WebWorker"sv, candidate_web_worker_paths, move(arguments), Ladybird::EnableCallgrindProfiling::No);
|
return launch_server_process<Web::HTML::WebWorkerClient>("WebWorker"sv, candidate_web_worker_paths, move(arguments), WebView::EnableCallgrindProfiling::No);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<Protocol::RequestClient>> launch_request_server_process(ReadonlySpan<ByteString> candidate_request_server_paths, StringView serenity_resource_root, Vector<ByteString> const& certificates)
|
ErrorOr<NonnullRefPtr<Protocol::RequestClient>> launch_request_server_process(ReadonlySpan<ByteString> candidate_request_server_paths, StringView serenity_resource_root)
|
||||||
{
|
{
|
||||||
Vector<ByteString> arguments;
|
Vector<ByteString> arguments;
|
||||||
|
|
||||||
|
@ -147,7 +148,7 @@ ErrorOr<NonnullRefPtr<Protocol::RequestClient>> launch_request_server_process(Re
|
||||||
arguments.append(serenity_resource_root);
|
arguments.append(serenity_resource_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& certificate : certificates)
|
for (auto const& certificate : WebView::Application::chrome_options().certificates)
|
||||||
arguments.append(ByteString::formatted("--certificate={}", certificate));
|
arguments.append(ByteString::formatted("--certificate={}", certificate));
|
||||||
|
|
||||||
if (auto server = mach_server_name(); server.has_value()) {
|
if (auto server = mach_server_name(); server.has_value()) {
|
||||||
|
@ -155,7 +156,7 @@ ErrorOr<NonnullRefPtr<Protocol::RequestClient>> launch_request_server_process(Re
|
||||||
arguments.append(server.value());
|
arguments.append(server.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
return launch_server_process<Protocol::RequestClient>("RequestServer"sv, candidate_request_server_paths, move(arguments), Ladybird::EnableCallgrindProfiling::No);
|
return launch_server_process<Protocol::RequestClient>("RequestServer"sv, candidate_request_server_paths, move(arguments), WebView::EnableCallgrindProfiling::No);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<IPC::File> connect_new_request_server_client(Protocol::RequestClient& client)
|
ErrorOr<IPC::File> connect_new_request_server_client(Protocol::RequestClient& client)
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Types.h"
|
|
||||||
#include <AK/Error.h>
|
#include <AK/Error.h>
|
||||||
#include <AK/Optional.h>
|
#include <AK/Optional.h>
|
||||||
#include <AK/Span.h>
|
#include <AK/Span.h>
|
||||||
|
@ -20,13 +19,12 @@
|
||||||
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
||||||
WebView::ViewImplementation& view,
|
WebView::ViewImplementation& view,
|
||||||
ReadonlySpan<ByteString> candidate_web_content_paths,
|
ReadonlySpan<ByteString> candidate_web_content_paths,
|
||||||
Ladybird::WebContentOptions const&,
|
|
||||||
IPC::File image_decoder_socket,
|
IPC::File image_decoder_socket,
|
||||||
Optional<IPC::File> request_server_socket = {});
|
Optional<IPC::File> request_server_socket = {});
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process(ReadonlySpan<ByteString> candidate_image_decoder_paths);
|
ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process(ReadonlySpan<ByteString> candidate_image_decoder_paths);
|
||||||
ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process(ReadonlySpan<ByteString> candidate_web_worker_paths, RefPtr<Protocol::RequestClient>);
|
ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process(ReadonlySpan<ByteString> candidate_web_worker_paths, RefPtr<Protocol::RequestClient>);
|
||||||
ErrorOr<NonnullRefPtr<Protocol::RequestClient>> launch_request_server_process(ReadonlySpan<ByteString> candidate_request_server_paths, StringView serenity_resource_root, Vector<ByteString> const& certificates);
|
ErrorOr<NonnullRefPtr<Protocol::RequestClient>> launch_request_server_process(ReadonlySpan<ByteString> candidate_request_server_paths, StringView serenity_resource_root);
|
||||||
|
|
||||||
ErrorOr<IPC::File> connect_new_request_server_client(Protocol::RequestClient&);
|
ErrorOr<IPC::File> connect_new_request_server_client(Protocol::RequestClient&);
|
||||||
ErrorOr<IPC::File> connect_new_image_decoder_client(ImageDecoderClient::Client&);
|
ErrorOr<IPC::File> connect_new_image_decoder_client(ImageDecoderClient::Client&);
|
||||||
|
|
|
@ -4,21 +4,34 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
#include "StringUtils.h"
|
|
||||||
#include "TaskManagerWindow.h"
|
|
||||||
#include <Ladybird/HelperProcess.h>
|
#include <Ladybird/HelperProcess.h>
|
||||||
|
#include <Ladybird/Qt/Application.h>
|
||||||
|
#include <Ladybird/Qt/Settings.h>
|
||||||
|
#include <Ladybird/Qt/StringUtils.h>
|
||||||
|
#include <Ladybird/Qt/TaskManagerWindow.h>
|
||||||
#include <Ladybird/Utilities.h>
|
#include <Ladybird/Utilities.h>
|
||||||
|
#include <LibCore/ArgsParser.h>
|
||||||
#include <LibWebView/URL.h>
|
#include <LibWebView/URL.h>
|
||||||
#include <QFileOpenEvent>
|
#include <QFileOpenEvent>
|
||||||
|
|
||||||
namespace Ladybird {
|
namespace Ladybird {
|
||||||
|
|
||||||
Application::Application(int& argc, char** argv)
|
Application::Application(Badge<WebView::Application>, Main::Arguments& arguments)
|
||||||
: QApplication(argc, argv)
|
: QApplication(arguments.argc, arguments.argv)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::create_platform_arguments(Core::ArgsParser& args_parser)
|
||||||
|
{
|
||||||
|
args_parser.add_option(m_enable_qt_networking, "Enable Qt as the backend networking service", "enable-qt-networking");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::create_platform_options(WebView::ChromeOptions&, WebView::WebContentOptions& web_content_options)
|
||||||
|
{
|
||||||
|
web_content_options.config_path = Settings::the()->directory();
|
||||||
|
web_content_options.use_lagom_networking = m_enable_qt_networking ? WebView::UseLagomNetworking::No : WebView::UseLagomNetworking::Yes;
|
||||||
|
}
|
||||||
|
|
||||||
Application::~Application()
|
Application::~Application()
|
||||||
{
|
{
|
||||||
close_task_manager_window();
|
close_task_manager_window();
|
||||||
|
@ -77,10 +90,10 @@ ErrorOr<void> Application::initialize_image_decoder()
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::show_task_manager_window(WebContentOptions const& web_content_options)
|
void Application::show_task_manager_window()
|
||||||
{
|
{
|
||||||
if (!m_task_manager_window) {
|
if (!m_task_manager_window) {
|
||||||
m_task_manager_window = new TaskManagerWindow(nullptr, web_content_options);
|
m_task_manager_window = new TaskManagerWindow(nullptr);
|
||||||
}
|
}
|
||||||
m_task_manager_window->show();
|
m_task_manager_window->show();
|
||||||
m_task_manager_window->activateWindow();
|
m_task_manager_window->activateWindow();
|
||||||
|
@ -96,9 +109,9 @@ void Application::close_task_manager_window()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowserWindow& Application::new_window(Vector<URL::URL> const& initial_urls, WebView::CookieJar& cookie_jar, WebContentOptions const& web_content_options, StringView webdriver_content_ipc_path, bool allow_popups, BrowserWindow::IsPopupWindow is_popup_window, Tab* parent_tab, Optional<u64> page_index)
|
BrowserWindow& Application::new_window(Vector<URL::URL> const& initial_urls, WebView::CookieJar& cookie_jar, BrowserWindow::IsPopupWindow is_popup_window, Tab* parent_tab, Optional<u64> page_index)
|
||||||
{
|
{
|
||||||
auto* window = new BrowserWindow(initial_urls, cookie_jar, web_content_options, webdriver_content_ipc_path, allow_popups, is_popup_window, parent_tab, move(page_index));
|
auto* window = new BrowserWindow(initial_urls, cookie_jar, is_popup_window, parent_tab, move(page_index));
|
||||||
set_active_window(*window);
|
set_active_window(*window);
|
||||||
window->show();
|
window->show();
|
||||||
if (initial_urls.is_empty()) {
|
if (initial_urls.is_empty()) {
|
||||||
|
|
|
@ -12,15 +12,18 @@
|
||||||
#include <LibImageDecoderClient/Client.h>
|
#include <LibImageDecoderClient/Client.h>
|
||||||
#include <LibProtocol/RequestClient.h>
|
#include <LibProtocol/RequestClient.h>
|
||||||
#include <LibURL/URL.h>
|
#include <LibURL/URL.h>
|
||||||
|
#include <LibWebView/Application.h>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
||||||
namespace Ladybird {
|
namespace Ladybird {
|
||||||
|
|
||||||
class Application : public QApplication {
|
class Application
|
||||||
|
: public QApplication
|
||||||
|
, public WebView::Application {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
WEB_VIEW_APPLICATION(Application)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Application(int& argc, char** argv);
|
|
||||||
virtual ~Application() override;
|
virtual ~Application() override;
|
||||||
|
|
||||||
virtual bool event(QEvent* event) override;
|
virtual bool event(QEvent* event) override;
|
||||||
|
@ -31,15 +34,20 @@ public:
|
||||||
NonnullRefPtr<ImageDecoderClient::Client> image_decoder_client() const { return *m_image_decoder_client; }
|
NonnullRefPtr<ImageDecoderClient::Client> image_decoder_client() const { return *m_image_decoder_client; }
|
||||||
ErrorOr<void> initialize_image_decoder();
|
ErrorOr<void> initialize_image_decoder();
|
||||||
|
|
||||||
BrowserWindow& new_window(Vector<URL::URL> const& initial_urls, WebView::CookieJar&, WebContentOptions const&, StringView webdriver_content_ipc_path, bool allow_popups, BrowserWindow::IsPopupWindow is_popup_window = BrowserWindow::IsPopupWindow::No, Tab* parent_tab = nullptr, Optional<u64> page_index = {});
|
BrowserWindow& new_window(Vector<URL::URL> const& initial_urls, WebView::CookieJar&, BrowserWindow::IsPopupWindow is_popup_window = BrowserWindow::IsPopupWindow::No, Tab* parent_tab = nullptr, Optional<u64> page_index = {});
|
||||||
|
|
||||||
void show_task_manager_window(WebContentOptions const&);
|
void show_task_manager_window();
|
||||||
void close_task_manager_window();
|
void close_task_manager_window();
|
||||||
|
|
||||||
BrowserWindow& active_window() { return *m_active_window; }
|
BrowserWindow& active_window() { return *m_active_window; }
|
||||||
void set_active_window(BrowserWindow& w) { m_active_window = &w; }
|
void set_active_window(BrowserWindow& w) { m_active_window = &w; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
virtual void create_platform_arguments(Core::ArgsParser&) override;
|
||||||
|
virtual void create_platform_options(WebView::ChromeOptions&, WebView::WebContentOptions&) override;
|
||||||
|
|
||||||
|
bool m_enable_qt_networking { false };
|
||||||
|
|
||||||
TaskManagerWindow* m_task_manager_window { nullptr };
|
TaskManagerWindow* m_task_manager_window { nullptr };
|
||||||
BrowserWindow* m_active_window { nullptr };
|
BrowserWindow* m_active_window { nullptr };
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <LibWeb/CSS/PreferredContrast.h>
|
#include <LibWeb/CSS/PreferredContrast.h>
|
||||||
#include <LibWeb/CSS/PreferredMotion.h>
|
#include <LibWeb/CSS/PreferredMotion.h>
|
||||||
#include <LibWeb/Loader/UserAgent.h>
|
#include <LibWeb/Loader/UserAgent.h>
|
||||||
|
#include <LibWebView/Application.h>
|
||||||
#include <LibWebView/CookieJar.h>
|
#include <LibWebView/CookieJar.h>
|
||||||
#include <LibWebView/UserAgent.h>
|
#include <LibWebView/UserAgent.h>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
@ -71,13 +72,10 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, WebView::CookieJar& cookie_jar, WebContentOptions const& web_content_options, StringView webdriver_content_ipc_path, bool allow_popups, IsPopupWindow is_popup_window, Tab* parent_tab, Optional<u64> page_index)
|
BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, WebView::CookieJar& cookie_jar, IsPopupWindow is_popup_window, Tab* parent_tab, Optional<u64> page_index)
|
||||||
: m_tabs_container(new TabWidget(this))
|
: m_tabs_container(new TabWidget(this))
|
||||||
, m_new_tab_button_toolbar(new QToolBar("New Tab", m_tabs_container))
|
, m_new_tab_button_toolbar(new QToolBar("New Tab", m_tabs_container))
|
||||||
, m_cookie_jar(cookie_jar)
|
, m_cookie_jar(cookie_jar)
|
||||||
, m_web_content_options(web_content_options)
|
|
||||||
, m_webdriver_content_ipc_path(webdriver_content_ipc_path)
|
|
||||||
, m_allow_popups(allow_popups)
|
|
||||||
, m_is_popup_window(is_popup_window)
|
, m_is_popup_window(is_popup_window)
|
||||||
{
|
{
|
||||||
setWindowIcon(app_icon());
|
setWindowIcon(app_icon());
|
||||||
|
@ -365,7 +363,7 @@ BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, WebView::Cook
|
||||||
task_manager_action->setShortcuts({ QKeySequence("Ctrl+Shift+M") });
|
task_manager_action->setShortcuts({ QKeySequence("Ctrl+Shift+M") });
|
||||||
inspect_menu->addAction(task_manager_action);
|
inspect_menu->addAction(task_manager_action);
|
||||||
QObject::connect(task_manager_action, &QAction::triggered, this, [&] {
|
QObject::connect(task_manager_action, &QAction::triggered, this, [&] {
|
||||||
static_cast<Ladybird::Application*>(QApplication::instance())->show_task_manager_window(m_web_content_options);
|
static_cast<Ladybird::Application*>(QApplication::instance())->show_task_manager_window();
|
||||||
});
|
});
|
||||||
|
|
||||||
auto* debug_menu = m_hamburger_menu->addMenu("&Debug");
|
auto* debug_menu = m_hamburger_menu->addMenu("&Debug");
|
||||||
|
@ -556,7 +554,7 @@ BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, WebView::Cook
|
||||||
|
|
||||||
m_block_pop_ups_action = new QAction("Block Pop-ups", this);
|
m_block_pop_ups_action = new QAction("Block Pop-ups", this);
|
||||||
m_block_pop_ups_action->setCheckable(true);
|
m_block_pop_ups_action->setCheckable(true);
|
||||||
m_block_pop_ups_action->setChecked(!allow_popups);
|
m_block_pop_ups_action->setChecked(WebView::Application::chrome_options().allow_popups == WebView::AllowPopups::No);
|
||||||
debug_menu->addAction(m_block_pop_ups_action);
|
debug_menu->addAction(m_block_pop_ups_action);
|
||||||
QObject::connect(m_block_pop_ups_action, &QAction::triggered, this, [this] {
|
QObject::connect(m_block_pop_ups_action, &QAction::triggered, this, [this] {
|
||||||
bool state = m_block_pop_ups_action->isChecked();
|
bool state = m_block_pop_ups_action->isChecked();
|
||||||
|
@ -599,7 +597,7 @@ BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, WebView::Cook
|
||||||
tab.focus_location_editor();
|
tab.focus_location_editor();
|
||||||
});
|
});
|
||||||
QObject::connect(m_new_window_action, &QAction::triggered, this, [this] {
|
QObject::connect(m_new_window_action, &QAction::triggered, this, [this] {
|
||||||
(void)static_cast<Ladybird::Application*>(QApplication::instance())->new_window({}, m_cookie_jar, m_web_content_options, m_webdriver_content_ipc_path, m_allow_popups);
|
(void)static_cast<Ladybird::Application*>(QApplication::instance())->new_window({}, m_cookie_jar);
|
||||||
});
|
});
|
||||||
QObject::connect(open_file_action, &QAction::triggered, this, &BrowserWindow::open_file);
|
QObject::connect(open_file_action, &QAction::triggered, this, &BrowserWindow::open_file);
|
||||||
QObject::connect(settings_action, &QAction::triggered, this, [this] {
|
QObject::connect(settings_action, &QAction::triggered, this, [this] {
|
||||||
|
@ -666,15 +664,11 @@ BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, WebView::Cook
|
||||||
|
|
||||||
if (parent_tab) {
|
if (parent_tab) {
|
||||||
new_child_tab(Web::HTML::ActivateTab::Yes, *parent_tab, AK::move(page_index));
|
new_child_tab(Web::HTML::ActivateTab::Yes, *parent_tab, AK::move(page_index));
|
||||||
} else {
|
|
||||||
if (initial_urls.is_empty()) {
|
|
||||||
new_tab_from_url(ak_url_from_qstring(Settings::the()->new_tab_page()), Web::HTML::ActivateTab::Yes);
|
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < initial_urls.size(); ++i) {
|
for (size_t i = 0; i < initial_urls.size(); ++i) {
|
||||||
new_tab_from_url(initial_urls[i], (i == 0) ? Web::HTML::ActivateTab::Yes : Web::HTML::ActivateTab::No);
|
new_tab_from_url(initial_urls[i], (i == 0) ? Web::HTML::ActivateTab::Yes : Web::HTML::ActivateTab::No);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
m_new_tab_button_toolbar->addAction(m_new_tab_action);
|
m_new_tab_button_toolbar->addAction(m_new_tab_action);
|
||||||
m_new_tab_button_toolbar->setMovable(false);
|
m_new_tab_button_toolbar->setMovable(false);
|
||||||
|
@ -726,7 +720,7 @@ Tab& BrowserWindow::create_new_tab(Web::HTML::ActivateTab activate_tab, Tab& par
|
||||||
if (!page_index.has_value())
|
if (!page_index.has_value())
|
||||||
return create_new_tab(activate_tab);
|
return create_new_tab(activate_tab);
|
||||||
|
|
||||||
auto* tab = new Tab(this, m_web_content_options, m_webdriver_content_ipc_path, parent.view().client(), page_index.value());
|
auto* tab = new Tab(this, parent.view().client(), page_index.value());
|
||||||
|
|
||||||
// FIXME: Merge with other overload
|
// FIXME: Merge with other overload
|
||||||
if (m_current_tab == nullptr) {
|
if (m_current_tab == nullptr) {
|
||||||
|
@ -743,7 +737,7 @@ Tab& BrowserWindow::create_new_tab(Web::HTML::ActivateTab activate_tab, Tab& par
|
||||||
|
|
||||||
Tab& BrowserWindow::create_new_tab(Web::HTML::ActivateTab activate_tab)
|
Tab& BrowserWindow::create_new_tab(Web::HTML::ActivateTab activate_tab)
|
||||||
{
|
{
|
||||||
auto* tab = new Tab(this, m_web_content_options, m_webdriver_content_ipc_path);
|
auto* tab = new Tab(this);
|
||||||
|
|
||||||
if (m_current_tab == nullptr) {
|
if (m_current_tab == nullptr) {
|
||||||
set_current_tab(tab);
|
set_current_tab(tab);
|
||||||
|
@ -775,7 +769,7 @@ void BrowserWindow::initialize_tab(Tab* tab)
|
||||||
|
|
||||||
tab->view().on_new_web_view = [this, tab](auto activate_tab, Web::HTML::WebViewHints hints, Optional<u64> page_index) {
|
tab->view().on_new_web_view = [this, tab](auto activate_tab, Web::HTML::WebViewHints hints, Optional<u64> page_index) {
|
||||||
if (hints.popup) {
|
if (hints.popup) {
|
||||||
auto& window = static_cast<Ladybird::Application*>(QApplication::instance())->new_window({}, m_cookie_jar, m_web_content_options, m_webdriver_content_ipc_path, m_allow_popups, IsPopupWindow::Yes, tab, AK::move(page_index));
|
auto& window = static_cast<Ladybird::Application*>(QApplication::instance())->new_window({}, m_cookie_jar, IsPopupWindow::Yes, tab, AK::move(page_index));
|
||||||
window.set_window_rect(hints.screen_x, hints.screen_y, hints.width, hints.height);
|
window.set_window_rect(hints.screen_x, hints.screen_y, hints.width, hints.height);
|
||||||
return window.current_tab()->view().handle();
|
return window.current_tab()->view().handle();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
#include "Tab.h"
|
#include "Tab.h"
|
||||||
#include <Ladybird/Qt/FindInPageWidget.h>
|
#include <Ladybird/Qt/FindInPageWidget.h>
|
||||||
#include <Ladybird/Types.h>
|
|
||||||
#include <LibCore/Forward.h>
|
#include <LibCore/Forward.h>
|
||||||
#include <LibWeb/HTML/ActivateTab.h>
|
#include <LibWeb/HTML/ActivateTab.h>
|
||||||
#include <LibWeb/HTML/AudioPlayState.h>
|
#include <LibWeb/HTML/AudioPlayState.h>
|
||||||
|
@ -36,7 +35,7 @@ public:
|
||||||
Yes,
|
Yes,
|
||||||
};
|
};
|
||||||
|
|
||||||
BrowserWindow(Vector<URL::URL> const& initial_urls, WebView::CookieJar&, WebContentOptions const&, StringView webdriver_content_ipc_path, bool allow_popups, IsPopupWindow is_popup_window = IsPopupWindow::No, Tab* parent_tab = nullptr, Optional<u64> page_index = {});
|
BrowserWindow(Vector<URL::URL> const& initial_urls, WebView::CookieJar&, IsPopupWindow is_popup_window = IsPopupWindow::No, Tab* parent_tab = nullptr, Optional<u64> page_index = {});
|
||||||
|
|
||||||
WebContentView& view() const { return m_current_tab->view(); }
|
WebContentView& view() const { return m_current_tab->view(); }
|
||||||
|
|
||||||
|
@ -215,10 +214,6 @@ private:
|
||||||
|
|
||||||
WebView::CookieJar& m_cookie_jar;
|
WebView::CookieJar& m_cookie_jar;
|
||||||
|
|
||||||
WebContentOptions m_web_content_options;
|
|
||||||
StringView m_webdriver_content_ipc_path;
|
|
||||||
|
|
||||||
bool m_allow_popups { false };
|
|
||||||
IsPopupWindow m_is_popup_window { IsPopupWindow::No };
|
IsPopupWindow m_is_popup_window { IsPopupWindow::No };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ extern bool is_using_dark_system_theme(QWidget&);
|
||||||
InspectorWidget::InspectorWidget(QWidget* tab, WebContentView& content_view)
|
InspectorWidget::InspectorWidget(QWidget* tab, WebContentView& content_view)
|
||||||
: QWidget(tab, Qt::Window)
|
: QWidget(tab, Qt::Window)
|
||||||
{
|
{
|
||||||
m_inspector_view = new WebContentView(this, content_view.web_content_options(), {});
|
m_inspector_view = new WebContentView(this);
|
||||||
|
|
||||||
if (is_using_dark_system_theme(*this))
|
if (is_using_dark_system_theme(*this))
|
||||||
m_inspector_view->update_palette(WebContentView::PaletteMode::Dark);
|
m_inspector_view->update_palette(WebContentView::PaletteMode::Dark);
|
||||||
|
|
|
@ -47,7 +47,7 @@ static QIcon default_favicon()
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tab::Tab(BrowserWindow* window, WebContentOptions const& web_content_options, StringView webdriver_content_ipc_path, RefPtr<WebView::WebContentClient> parent_client, size_t page_index)
|
Tab::Tab(BrowserWindow* window, RefPtr<WebView::WebContentClient> parent_client, size_t page_index)
|
||||||
: QWidget(window)
|
: QWidget(window)
|
||||||
, m_window(window)
|
, m_window(window)
|
||||||
{
|
{
|
||||||
|
@ -55,7 +55,7 @@ Tab::Tab(BrowserWindow* window, WebContentOptions const& web_content_options, St
|
||||||
m_layout->setSpacing(0);
|
m_layout->setSpacing(0);
|
||||||
m_layout->setContentsMargins(0, 0, 0, 0);
|
m_layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
m_view = new WebContentView(this, web_content_options, webdriver_content_ipc_path, parent_client, page_index);
|
m_view = new WebContentView(this, parent_client, page_index);
|
||||||
m_find_in_page = new FindInPageWidget(this, m_view);
|
m_find_in_page = new FindInPageWidget(this, m_view);
|
||||||
m_find_in_page->setVisible(false);
|
m_find_in_page->setVisible(false);
|
||||||
m_toolbar = new QToolBar(this);
|
m_toolbar = new QToolBar(this);
|
||||||
|
|
|
@ -29,7 +29,7 @@ class Tab final : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Tab(BrowserWindow* window, WebContentOptions const&, StringView webdriver_content_ipc_path, RefPtr<WebView::WebContentClient> parent_client = nullptr, size_t page_index = 0);
|
Tab(BrowserWindow* window, RefPtr<WebView::WebContentClient> parent_client = nullptr, size_t page_index = 0);
|
||||||
virtual ~Tab() override;
|
virtual ~Tab() override;
|
||||||
|
|
||||||
WebContentView& view() { return *m_view; }
|
WebContentView& view() { return *m_view; }
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
|
|
||||||
namespace Ladybird {
|
namespace Ladybird {
|
||||||
|
|
||||||
TaskManagerWindow::TaskManagerWindow(QWidget* parent, WebContentOptions const& web_content_options)
|
TaskManagerWindow::TaskManagerWindow(QWidget* parent)
|
||||||
: QWidget(parent, Qt::WindowFlags(Qt::WindowType::Window))
|
: QWidget(parent, Qt::WindowFlags(Qt::WindowType::Window))
|
||||||
, m_web_view(new WebContentView(this, web_content_options, {}))
|
, m_web_view(new WebContentView(this))
|
||||||
{
|
{
|
||||||
setLayout(new QVBoxLayout);
|
setLayout(new QVBoxLayout);
|
||||||
layout()->addWidget(m_web_view);
|
layout()->addWidget(m_web_view);
|
||||||
|
|
|
@ -16,7 +16,7 @@ class TaskManagerWindow : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TaskManagerWindow(QWidget* parent, WebContentOptions const&);
|
explicit TaskManagerWindow(QWidget* parent);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void showEvent(QShowEvent*) override;
|
virtual void showEvent(QShowEvent*) override;
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <LibWeb/UIEvents/KeyCode.h>
|
#include <LibWeb/UIEvents/KeyCode.h>
|
||||||
#include <LibWeb/UIEvents/MouseButton.h>
|
#include <LibWeb/UIEvents/MouseButton.h>
|
||||||
#include <LibWeb/Worker/WebWorkerClient.h>
|
#include <LibWeb/Worker/WebWorkerClient.h>
|
||||||
|
#include <LibWebView/Application.h>
|
||||||
#include <LibWebView/WebContentClient.h>
|
#include <LibWebView/WebContentClient.h>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QCursor>
|
#include <QCursor>
|
||||||
|
@ -50,10 +51,8 @@ namespace Ladybird {
|
||||||
|
|
||||||
bool is_using_dark_system_theme(QWidget&);
|
bool is_using_dark_system_theme(QWidget&);
|
||||||
|
|
||||||
WebContentView::WebContentView(QWidget* window, WebContentOptions const& web_content_options, StringView webdriver_content_ipc_path, RefPtr<WebView::WebContentClient> parent_client, size_t page_index)
|
WebContentView::WebContentView(QWidget* window, RefPtr<WebView::WebContentClient> parent_client, size_t page_index)
|
||||||
: QAbstractScrollArea(window)
|
: QAbstractScrollArea(window)
|
||||||
, m_web_content_options(web_content_options)
|
|
||||||
, m_webdriver_content_ipc_path(webdriver_content_ipc_path)
|
|
||||||
{
|
{
|
||||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
@ -133,7 +132,7 @@ WebContentView::WebContentView(QWidget* window, WebContentOptions const& web_con
|
||||||
|
|
||||||
on_request_worker_agent = [&]() {
|
on_request_worker_agent = [&]() {
|
||||||
RefPtr<Protocol::RequestClient> request_server_client {};
|
RefPtr<Protocol::RequestClient> request_server_client {};
|
||||||
if (m_web_content_options.use_lagom_networking == Ladybird::UseLagomNetworking::Yes)
|
if (WebView::Application::web_content_options().use_lagom_networking == WebView::UseLagomNetworking::Yes)
|
||||||
request_server_client = static_cast<Ladybird::Application*>(QApplication::instance())->request_server_client;
|
request_server_client = static_cast<Ladybird::Application*>(QApplication::instance())->request_server_client;
|
||||||
|
|
||||||
auto worker_client = MUST(launch_web_worker_process(MUST(get_paths_for_helper_process("WebWorker"sv)), request_server_client));
|
auto worker_client = MUST(launch_web_worker_process(MUST(get_paths_for_helper_process("WebWorker"sv)), request_server_client));
|
||||||
|
@ -574,7 +573,7 @@ void WebContentView::initialize_client(WebView::ViewImplementation::CreateNewCli
|
||||||
m_client_state = {};
|
m_client_state = {};
|
||||||
|
|
||||||
Optional<IPC::File> request_server_socket;
|
Optional<IPC::File> request_server_socket;
|
||||||
if (m_web_content_options.use_lagom_networking == UseLagomNetworking::Yes) {
|
if (WebView::Application::web_content_options().use_lagom_networking == WebView::UseLagomNetworking::Yes) {
|
||||||
auto& protocol = static_cast<Ladybird::Application*>(QApplication::instance())->request_server_client;
|
auto& protocol = static_cast<Ladybird::Application*>(QApplication::instance())->request_server_client;
|
||||||
|
|
||||||
// FIXME: Fail to open the tab, rather than crashing the whole application if this fails
|
// FIXME: Fail to open the tab, rather than crashing the whole application if this fails
|
||||||
|
@ -586,7 +585,7 @@ void WebContentView::initialize_client(WebView::ViewImplementation::CreateNewCli
|
||||||
auto image_decoder_socket = connect_new_image_decoder_client(*image_decoder).release_value_but_fixme_should_propagate_errors();
|
auto image_decoder_socket = connect_new_image_decoder_client(*image_decoder).release_value_but_fixme_should_propagate_errors();
|
||||||
|
|
||||||
auto candidate_web_content_paths = get_paths_for_helper_process("WebContent"sv).release_value_but_fixme_should_propagate_errors();
|
auto candidate_web_content_paths = get_paths_for_helper_process("WebContent"sv).release_value_but_fixme_should_propagate_errors();
|
||||||
auto new_client = launch_web_content_process(*this, candidate_web_content_paths, m_web_content_options, AK::move(image_decoder_socket), AK::move(request_server_socket)).release_value_but_fixme_should_propagate_errors();
|
auto new_client = launch_web_content_process(*this, candidate_web_content_paths, AK::move(image_decoder_socket), AK::move(request_server_socket)).release_value_but_fixme_should_propagate_errors();
|
||||||
|
|
||||||
m_client_state.client = new_client;
|
m_client_state.client = new_client;
|
||||||
} else {
|
} else {
|
||||||
|
@ -607,8 +606,8 @@ void WebContentView::initialize_client(WebView::ViewImplementation::CreateNewCli
|
||||||
|
|
||||||
update_screen_rects();
|
update_screen_rects();
|
||||||
|
|
||||||
if (!m_webdriver_content_ipc_path.is_empty())
|
if (auto webdriver_content_ipc_path = WebView::Application::chrome_options().webdriver_content_ipc_path; webdriver_content_ipc_path.has_value())
|
||||||
client().async_connect_to_webdriver(m_client_state.page_index, m_webdriver_content_ipc_path);
|
client().async_connect_to_webdriver(m_client_state.page_index, *webdriver_content_ipc_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContentView::update_cursor(Gfx::StandardCursor cursor)
|
void WebContentView::update_cursor(Gfx::StandardCursor cursor)
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
#include <AK/OwnPtr.h>
|
#include <AK/OwnPtr.h>
|
||||||
#include <Ladybird/Types.h>
|
|
||||||
#include <LibGfx/Forward.h>
|
#include <LibGfx/Forward.h>
|
||||||
#include <LibGfx/Rect.h>
|
#include <LibGfx/Rect.h>
|
||||||
#include <LibGfx/StandardCursor.h>
|
#include <LibGfx/StandardCursor.h>
|
||||||
|
@ -46,7 +45,7 @@ class WebContentView final
|
||||||
, public WebView::ViewImplementation {
|
, public WebView::ViewImplementation {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
WebContentView(QWidget* window, WebContentOptions const&, StringView webdriver_content_ipc_path, RefPtr<WebView::WebContentClient> parent_client = nullptr, size_t page_index = 0);
|
WebContentView(QWidget* window, RefPtr<WebView::WebContentClient> parent_client = nullptr, size_t page_index = 0);
|
||||||
virtual ~WebContentView() override;
|
virtual ~WebContentView() override;
|
||||||
|
|
||||||
Function<String(const URL::URL&, Web::HTML::ActivateTab)> on_tab_open_request;
|
Function<String(const URL::URL&, Web::HTML::ActivateTab)> on_tab_open_request;
|
||||||
|
@ -85,8 +84,6 @@ public:
|
||||||
|
|
||||||
QPoint map_point_to_global_position(Gfx::IntPoint) const;
|
QPoint map_point_to_global_position(Gfx::IntPoint) const;
|
||||||
|
|
||||||
WebContentOptions const& web_content_options() const { return m_web_content_options; }
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void urls_dropped(QList<QUrl> const&);
|
void urls_dropped(QList<QUrl> const&);
|
||||||
|
|
||||||
|
@ -113,9 +110,6 @@ private:
|
||||||
bool m_should_show_line_box_borders { false };
|
bool m_should_show_line_box_borders { false };
|
||||||
|
|
||||||
Gfx::IntSize m_viewport_size;
|
Gfx::IntSize m_viewport_size;
|
||||||
|
|
||||||
WebContentOptions m_web_content_options;
|
|
||||||
StringView m_webdriver_content_ipc_path;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,72 +62,32 @@ static ErrorOr<void> handle_attached_debugger()
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static Vector<URL::URL> sanitize_urls(Vector<ByteString> const& raw_urls)
|
|
||||||
{
|
|
||||||
Vector<URL::URL> sanitized_urls;
|
|
||||||
for (auto const& raw_url : raw_urls) {
|
|
||||||
if (auto url = WebView::sanitize_url(raw_url); url.has_value())
|
|
||||||
sanitized_urls.append(url.release_value());
|
|
||||||
}
|
|
||||||
return sanitized_urls;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
{
|
{
|
||||||
AK::set_rich_debug_enabled(true);
|
AK::set_rich_debug_enabled(true);
|
||||||
|
|
||||||
Ladybird::Application app(arguments.argc, arguments.argv);
|
|
||||||
|
|
||||||
Core::EventLoopManager::install(*new Ladybird::EventLoopManagerQt);
|
Core::EventLoopManager::install(*new Ladybird::EventLoopManagerQt);
|
||||||
WebView::Application webview_app(arguments.argc, arguments.argv);
|
|
||||||
static_cast<Ladybird::EventLoopImplementationQt&>(Core::EventLoop::current().impl()).set_main_loop();
|
|
||||||
|
|
||||||
|
auto app = Ladybird::Application::create(arguments, ak_url_from_qstring(Ladybird::Settings::the()->new_tab_page()));
|
||||||
|
|
||||||
|
static_cast<Ladybird::EventLoopImplementationQt&>(Core::EventLoop::current().impl()).set_main_loop();
|
||||||
TRY(handle_attached_debugger());
|
TRY(handle_attached_debugger());
|
||||||
|
|
||||||
platform_init();
|
platform_init();
|
||||||
|
|
||||||
Vector<ByteString> raw_urls;
|
|
||||||
StringView webdriver_content_ipc_path;
|
|
||||||
Vector<ByteString> certificates;
|
|
||||||
bool enable_callgrind_profiling = false;
|
|
||||||
bool disable_sql_database = false;
|
|
||||||
bool enable_qt_networking = false;
|
|
||||||
bool expose_internals_object = false;
|
|
||||||
bool debug_web_content = false;
|
|
||||||
bool log_all_js_exceptions = false;
|
|
||||||
bool enable_idl_tracing = false;
|
|
||||||
bool enable_http_cache = false;
|
|
||||||
bool new_window = false;
|
|
||||||
bool force_new_process = false;
|
|
||||||
bool allow_popups = false;
|
|
||||||
|
|
||||||
Core::ArgsParser args_parser;
|
|
||||||
args_parser.set_general_help("The Ladybird web browser :^)");
|
|
||||||
args_parser.add_positional_argument(raw_urls, "URLs to open", "url", Core::ArgsParser::Required::No);
|
|
||||||
args_parser.add_option(webdriver_content_ipc_path, "Path to WebDriver IPC for WebContent", "webdriver-content-path", 0, "path", Core::ArgsParser::OptionHideMode::CommandLineAndMarkdown);
|
|
||||||
args_parser.add_option(enable_callgrind_profiling, "Enable Callgrind profiling", "enable-callgrind-profiling", 'P');
|
|
||||||
args_parser.add_option(disable_sql_database, "Disable SQL database", "disable-sql-database");
|
|
||||||
args_parser.add_option(enable_qt_networking, "Enable Qt as the backend networking service", "enable-qt-networking");
|
|
||||||
args_parser.add_option(debug_web_content, "Wait for debugger to attach to WebContent", "debug-web-content");
|
|
||||||
args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate");
|
|
||||||
args_parser.add_option(log_all_js_exceptions, "Log all JavaScript exceptions", "log-all-js-exceptions");
|
|
||||||
args_parser.add_option(enable_idl_tracing, "Enable IDL tracing", "enable-idl-tracing");
|
|
||||||
args_parser.add_option(enable_http_cache, "Enable HTTP cache", "enable-http-cache");
|
|
||||||
args_parser.add_option(expose_internals_object, "Expose internals object", "expose-internals-object");
|
|
||||||
args_parser.add_option(new_window, "Force opening in a new window", "new-window", 'n');
|
|
||||||
args_parser.add_option(force_new_process, "Force creation of new browser/chrome process", "force-new-process");
|
|
||||||
args_parser.add_option(allow_popups, "Disable popup blocking by default", "allow-popups");
|
|
||||||
args_parser.parse(arguments);
|
|
||||||
|
|
||||||
auto chrome_process = TRY(WebView::ChromeProcess::create());
|
auto chrome_process = TRY(WebView::ChromeProcess::create());
|
||||||
if (!force_new_process && TRY(chrome_process.connect(raw_urls, new_window)) == WebView::ChromeProcess::ProcessDisposition::ExitProcess) {
|
|
||||||
|
if (app->chrome_options().force_new_process == WebView::ForceNewProcess::No) {
|
||||||
|
auto disposition = TRY(chrome_process.connect(app->chrome_options().raw_urls, app->chrome_options().new_window));
|
||||||
|
|
||||||
|
if (disposition == WebView::ChromeProcess::ProcessDisposition::ExitProcess) {
|
||||||
outln("Opening in existing process");
|
outln("Opening in existing process");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
chrome_process.on_new_tab = [&](auto const& raw_urls) {
|
chrome_process.on_new_tab = [&](auto const& urls) {
|
||||||
auto& window = app.active_window();
|
auto& window = app->active_window();
|
||||||
auto urls = sanitize_urls(raw_urls);
|
|
||||||
for (size_t i = 0; i < urls.size(); ++i) {
|
for (size_t i = 0; i < urls.size(); ++i) {
|
||||||
window.new_tab_from_url(urls[i], (i == 0) ? Web::HTML::ActivateTab::Yes : Web::HTML::ActivateTab::No);
|
window.new_tab_from_url(urls[i], (i == 0) ? Web::HTML::ActivateTab::Yes : Web::HTML::ActivateTab::No);
|
||||||
}
|
}
|
||||||
|
@ -136,16 +96,16 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
window.raise();
|
window.raise();
|
||||||
};
|
};
|
||||||
|
|
||||||
app.on_open_file = [&](auto file_url) {
|
app->on_open_file = [&](auto file_url) {
|
||||||
auto& window = app.active_window();
|
auto& window = app->active_window();
|
||||||
window.view().load(file_url);
|
window.view().load(file_url);
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(AK_OS_MACOS)
|
#if defined(AK_OS_MACOS)
|
||||||
auto mach_port_server = make<Ladybird::MachPortServer>();
|
auto mach_port_server = make<Ladybird::MachPortServer>();
|
||||||
set_mach_server_name(mach_port_server->server_port_name());
|
set_mach_server_name(mach_port_server->server_port_name());
|
||||||
mach_port_server->on_receive_child_mach_port = [&webview_app](auto pid, auto port) {
|
mach_port_server->on_receive_child_mach_port = [&app](auto pid, auto port) {
|
||||||
webview_app.set_process_mach_port(pid, move(port));
|
app->set_process_mach_port(pid, move(port));
|
||||||
};
|
};
|
||||||
mach_port_server->on_receive_backing_stores = [](Ladybird::MachPortServer::BackingStoresMessage message) {
|
mach_port_server->on_receive_backing_stores = [](Ladybird::MachPortServer::BackingStoresMessage message) {
|
||||||
if (auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id); view.has_value())
|
if (auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id); view.has_value())
|
||||||
|
@ -156,40 +116,25 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
copy_default_config_files(Ladybird::Settings::the()->directory());
|
copy_default_config_files(Ladybird::Settings::the()->directory());
|
||||||
|
|
||||||
RefPtr<WebView::Database> database;
|
RefPtr<WebView::Database> database;
|
||||||
if (!disable_sql_database)
|
if (app->chrome_options().disable_sql_database == WebView::DisableSQLDatabase::No)
|
||||||
database = TRY(WebView::Database::create());
|
database = TRY(WebView::Database::create());
|
||||||
|
|
||||||
auto cookie_jar = database ? TRY(WebView::CookieJar::create(*database)) : WebView::CookieJar::create();
|
auto cookie_jar = database ? TRY(WebView::CookieJar::create(*database)) : WebView::CookieJar::create();
|
||||||
|
|
||||||
// FIXME: Create an abstraction to re-spawn the RequestServer and re-hook up its client hooks to each tab on crash
|
// FIXME: Create an abstraction to re-spawn the RequestServer and re-hook up its client hooks to each tab on crash
|
||||||
if (!enable_qt_networking) {
|
if (app->web_content_options().use_lagom_networking == WebView::UseLagomNetworking::Yes) {
|
||||||
auto request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv));
|
auto request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv));
|
||||||
auto protocol_client = TRY(launch_request_server_process(request_server_paths, s_ladybird_resource_root, certificates));
|
auto protocol_client = TRY(launch_request_server_process(request_server_paths, s_ladybird_resource_root));
|
||||||
app.request_server_client = move(protocol_client);
|
app->request_server_client = move(protocol_client);
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY(app.initialize_image_decoder());
|
TRY(app->initialize_image_decoder());
|
||||||
|
|
||||||
StringBuilder command_line_builder;
|
|
||||||
command_line_builder.join(' ', arguments.strings);
|
|
||||||
Ladybird::WebContentOptions web_content_options {
|
|
||||||
.command_line = MUST(command_line_builder.to_string()),
|
|
||||||
.executable_path = MUST(String::from_byte_string(MUST(Core::System::current_executable_path()))),
|
|
||||||
.config_path = Ladybird::Settings::the()->directory(),
|
|
||||||
.enable_callgrind_profiling = enable_callgrind_profiling ? Ladybird::EnableCallgrindProfiling::Yes : Ladybird::EnableCallgrindProfiling::No,
|
|
||||||
.use_lagom_networking = enable_qt_networking ? Ladybird::UseLagomNetworking::No : Ladybird::UseLagomNetworking::Yes,
|
|
||||||
.wait_for_debugger = debug_web_content ? Ladybird::WaitForDebugger::Yes : Ladybird::WaitForDebugger::No,
|
|
||||||
.log_all_js_exceptions = log_all_js_exceptions ? Ladybird::LogAllJSExceptions::Yes : Ladybird::LogAllJSExceptions::No,
|
|
||||||
.enable_idl_tracing = enable_idl_tracing ? Ladybird::EnableIDLTracing::Yes : Ladybird::EnableIDLTracing::No,
|
|
||||||
.enable_http_cache = enable_http_cache ? Ladybird::EnableHTTPCache::Yes : Ladybird::EnableHTTPCache::No,
|
|
||||||
.expose_internals_object = expose_internals_object ? Ladybird::ExposeInternalsObject::Yes : Ladybird::ExposeInternalsObject::No,
|
|
||||||
};
|
|
||||||
|
|
||||||
chrome_process.on_new_window = [&](auto const& urls) {
|
chrome_process.on_new_window = [&](auto const& urls) {
|
||||||
app.new_window(sanitize_urls(urls), *cookie_jar, web_content_options, webdriver_content_ipc_path, allow_popups);
|
app->new_window(urls, *cookie_jar);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto& window = app.new_window(sanitize_urls(raw_urls), *cookie_jar, web_content_options, webdriver_content_ipc_path, allow_popups);
|
auto& window = app->new_window(app->chrome_options().urls, *cookie_jar);
|
||||||
window.setWindowTitle("Ladybird");
|
window.setWindowTitle("Ladybird");
|
||||||
|
|
||||||
if (Ladybird::Settings::the()->is_maximized()) {
|
if (Ladybird::Settings::the()->is_maximized()) {
|
||||||
|
@ -203,5 +148,5 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
|
|
||||||
window.show();
|
window.show();
|
||||||
|
|
||||||
return webview_app.exec();
|
return app->execute();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Debug.h>
|
#include <AK/Debug.h>
|
||||||
|
#include <LibCore/ArgsParser.h>
|
||||||
#include <LibImageDecoderClient/Client.h>
|
#include <LibImageDecoderClient/Client.h>
|
||||||
#include <LibWebView/Application.h>
|
#include <LibWebView/Application.h>
|
||||||
|
#include <LibWebView/URL.h>
|
||||||
#include <LibWebView/WebContentClient.h>
|
#include <LibWebView/WebContentClient.h>
|
||||||
|
|
||||||
namespace WebView {
|
namespace WebView {
|
||||||
|
|
||||||
Application* Application::s_the = nullptr;
|
Application* Application::s_the = nullptr;
|
||||||
|
|
||||||
Application::Application(int, char**)
|
Application::Application()
|
||||||
{
|
{
|
||||||
VERIFY(!s_the);
|
VERIFY(!s_the);
|
||||||
s_the = this;
|
s_the = this;
|
||||||
|
@ -28,7 +30,70 @@ Application::~Application()
|
||||||
s_the = nullptr;
|
s_the = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Application::exec()
|
void Application::initialize(Main::Arguments const& arguments, URL::URL new_tab_page_url)
|
||||||
|
{
|
||||||
|
Vector<ByteString> raw_urls;
|
||||||
|
Vector<ByteString> certificates;
|
||||||
|
bool new_window = false;
|
||||||
|
bool force_new_process = false;
|
||||||
|
bool allow_popups = false;
|
||||||
|
bool disable_sql_database = false;
|
||||||
|
Optional<StringView> webdriver_content_ipc_path;
|
||||||
|
bool enable_callgrind_profiling = false;
|
||||||
|
bool debug_web_content = false;
|
||||||
|
bool log_all_js_exceptions = false;
|
||||||
|
bool enable_idl_tracing = false;
|
||||||
|
bool enable_http_cache = false;
|
||||||
|
bool expose_internals_object = false;
|
||||||
|
|
||||||
|
Core::ArgsParser args_parser;
|
||||||
|
args_parser.set_general_help("The Ladybird web browser :^)");
|
||||||
|
args_parser.add_positional_argument(raw_urls, "URLs to open", "url", Core::ArgsParser::Required::No);
|
||||||
|
args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate");
|
||||||
|
args_parser.add_option(new_window, "Force opening in a new window", "new-window", 'n');
|
||||||
|
args_parser.add_option(force_new_process, "Force creation of new browser/chrome process", "force-new-process");
|
||||||
|
args_parser.add_option(allow_popups, "Disable popup blocking by default", "allow-popups");
|
||||||
|
args_parser.add_option(disable_sql_database, "Disable SQL database", "disable-sql-database");
|
||||||
|
args_parser.add_option(webdriver_content_ipc_path, "Path to WebDriver IPC for WebContent", "webdriver-content-path", 0, "path", Core::ArgsParser::OptionHideMode::CommandLineAndMarkdown);
|
||||||
|
args_parser.add_option(enable_callgrind_profiling, "Enable Callgrind profiling", "enable-callgrind-profiling", 'P');
|
||||||
|
args_parser.add_option(debug_web_content, "Wait for debugger to attach to WebContent", "debug-web-content");
|
||||||
|
args_parser.add_option(log_all_js_exceptions, "Log all JavaScript exceptions", "log-all-js-exceptions");
|
||||||
|
args_parser.add_option(enable_idl_tracing, "Enable IDL tracing", "enable-idl-tracing");
|
||||||
|
args_parser.add_option(enable_http_cache, "Enable HTTP cache", "enable-http-cache");
|
||||||
|
args_parser.add_option(expose_internals_object, "Expose internals object", "expose-internals-object");
|
||||||
|
|
||||||
|
create_platform_arguments(args_parser);
|
||||||
|
args_parser.parse(arguments);
|
||||||
|
|
||||||
|
m_chrome_options = {
|
||||||
|
.urls = sanitize_urls(raw_urls, new_tab_page_url),
|
||||||
|
.raw_urls = move(raw_urls),
|
||||||
|
.new_tab_page_url = move(new_tab_page_url),
|
||||||
|
.certificates = move(certificates),
|
||||||
|
.new_window = new_window ? NewWindow::Yes : NewWindow::No,
|
||||||
|
.force_new_process = force_new_process ? ForceNewProcess::Yes : ForceNewProcess::No,
|
||||||
|
.allow_popups = allow_popups ? AllowPopups::Yes : AllowPopups::No,
|
||||||
|
.disable_sql_database = disable_sql_database ? DisableSQLDatabase::Yes : DisableSQLDatabase::No,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (webdriver_content_ipc_path.has_value())
|
||||||
|
m_chrome_options.webdriver_content_ipc_path = *webdriver_content_ipc_path;
|
||||||
|
|
||||||
|
m_web_content_options = {
|
||||||
|
.command_line = MUST(String::join(' ', arguments.strings)),
|
||||||
|
.executable_path = MUST(String::from_byte_string(MUST(Core::System::current_executable_path()))),
|
||||||
|
.enable_callgrind_profiling = enable_callgrind_profiling ? EnableCallgrindProfiling::Yes : EnableCallgrindProfiling::No,
|
||||||
|
.wait_for_debugger = debug_web_content ? WaitForDebugger::Yes : WaitForDebugger::No,
|
||||||
|
.log_all_js_exceptions = log_all_js_exceptions ? LogAllJSExceptions::Yes : LogAllJSExceptions::No,
|
||||||
|
.enable_idl_tracing = enable_idl_tracing ? EnableIDLTracing::Yes : EnableIDLTracing::No,
|
||||||
|
.enable_http_cache = enable_http_cache ? EnableHTTPCache::Yes : EnableHTTPCache::No,
|
||||||
|
.expose_internals_object = expose_internals_object ? ExposeInternalsObject::Yes : ExposeInternalsObject::No,
|
||||||
|
};
|
||||||
|
|
||||||
|
create_platform_options(m_chrome_options, m_web_content_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Application::execute()
|
||||||
{
|
{
|
||||||
int ret = m_event_loop.exec();
|
int ret = m_event_loop.exec();
|
||||||
m_in_shutdown = true;
|
m_in_shutdown = true;
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Badge.h>
|
||||||
#include <LibCore/EventLoop.h>
|
#include <LibCore/EventLoop.h>
|
||||||
|
#include <LibMain/Main.h>
|
||||||
|
#include <LibURL/URL.h>
|
||||||
|
#include <LibWebView/Options.h>
|
||||||
#include <LibWebView/Process.h>
|
#include <LibWebView/Process.h>
|
||||||
#include <LibWebView/ProcessManager.h>
|
#include <LibWebView/ProcessManager.h>
|
||||||
|
|
||||||
|
@ -22,13 +26,15 @@ class Application {
|
||||||
AK_MAKE_NONCOPYABLE(Application);
|
AK_MAKE_NONCOPYABLE(Application);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Application(int argc, char** argv);
|
|
||||||
virtual ~Application();
|
virtual ~Application();
|
||||||
|
|
||||||
int exec();
|
int execute();
|
||||||
|
|
||||||
static Application& the() { return *s_the; }
|
static Application& the() { return *s_the; }
|
||||||
|
|
||||||
|
static ChromeOptions const& chrome_options() { return the().m_chrome_options; }
|
||||||
|
static WebContentOptions const& web_content_options() { return the().m_web_content_options; }
|
||||||
|
|
||||||
Core::EventLoop& event_loop() { return m_event_loop; }
|
Core::EventLoop& event_loop() { return m_event_loop; }
|
||||||
|
|
||||||
void add_child_process(Process&&);
|
void add_child_process(Process&&);
|
||||||
|
@ -44,14 +50,42 @@ public:
|
||||||
String generate_process_statistics_html();
|
String generate_process_statistics_html();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
template<DerivedFrom<Application> ApplicationType>
|
||||||
|
static NonnullOwnPtr<ApplicationType> create(Main::Arguments& arguments, URL::URL new_tab_page_url)
|
||||||
|
{
|
||||||
|
auto app = adopt_own(*new ApplicationType { {}, arguments });
|
||||||
|
app->initialize(arguments, move(new_tab_page_url));
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
Application();
|
||||||
|
|
||||||
virtual void process_did_exit(Process&&);
|
virtual void process_did_exit(Process&&);
|
||||||
|
|
||||||
|
virtual void create_platform_arguments(Core::ArgsParser&) { }
|
||||||
|
virtual void create_platform_options(ChromeOptions&, WebContentOptions&) { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void initialize(Main::Arguments const& arguments, URL::URL new_tab_page_url);
|
||||||
|
|
||||||
static Application* s_the;
|
static Application* s_the;
|
||||||
|
|
||||||
|
ChromeOptions m_chrome_options;
|
||||||
|
WebContentOptions m_web_content_options;
|
||||||
|
|
||||||
Core::EventLoop m_event_loop;
|
Core::EventLoop m_event_loop;
|
||||||
ProcessManager m_process_manager;
|
ProcessManager m_process_manager;
|
||||||
bool m_in_shutdown { false };
|
bool m_in_shutdown { false };
|
||||||
} SWIFT_IMMORTAL_REFERENCE;
|
} SWIFT_IMMORTAL_REFERENCE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define WEB_VIEW_APPLICATION(ApplicationType) \
|
||||||
|
public: \
|
||||||
|
static NonnullOwnPtr<ApplicationType> create(Main::Arguments& arguments, URL::URL new_tab_page_url) \
|
||||||
|
{ \
|
||||||
|
return WebView::Application::create<ApplicationType>(arguments, move(new_tab_page_url)); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
ApplicationType(Badge<WebView::Application>, Main::Arguments&);
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
#include <LibCore/StandardPaths.h>
|
#include <LibCore/StandardPaths.h>
|
||||||
#include <LibCore/System.h>
|
#include <LibCore/System.h>
|
||||||
#include <LibIPC/ConnectionToServer.h>
|
#include <LibIPC/ConnectionToServer.h>
|
||||||
|
#include <LibWebView/Application.h>
|
||||||
#include <LibWebView/ChromeProcess.h>
|
#include <LibWebView/ChromeProcess.h>
|
||||||
|
#include <LibWebView/URL.h>
|
||||||
|
|
||||||
namespace WebView {
|
namespace WebView {
|
||||||
|
|
||||||
|
@ -32,7 +34,7 @@ ErrorOr<ChromeProcess> ChromeProcess::create()
|
||||||
return ChromeProcess {};
|
return ChromeProcess {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<ChromeProcess::ProcessDisposition> ChromeProcess::connect(Vector<ByteString> const& raw_urls, bool new_window)
|
ErrorOr<ChromeProcess::ProcessDisposition> ChromeProcess::connect(Vector<ByteString> const& raw_urls, NewWindow new_window)
|
||||||
{
|
{
|
||||||
static constexpr auto process_name = "Ladybird"sv;
|
static constexpr auto process_name = "Ladybird"sv;
|
||||||
|
|
||||||
|
@ -52,12 +54,12 @@ ErrorOr<ChromeProcess::ProcessDisposition> ChromeProcess::connect(Vector<ByteStr
|
||||||
return ProcessDisposition::ContinueMainProcess;
|
return ProcessDisposition::ContinueMainProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> ChromeProcess::connect_as_client(ByteString const& socket_path, Vector<ByteString> const& raw_urls, bool new_window)
|
ErrorOr<void> ChromeProcess::connect_as_client(ByteString const& socket_path, Vector<ByteString> const& raw_urls, NewWindow new_window)
|
||||||
{
|
{
|
||||||
auto socket = TRY(Core::LocalSocket::connect(socket_path));
|
auto socket = TRY(Core::LocalSocket::connect(socket_path));
|
||||||
auto client = UIProcessClient::construct(move(socket));
|
auto client = UIProcessClient::construct(move(socket));
|
||||||
|
|
||||||
if (new_window) {
|
if (new_window == NewWindow::Yes) {
|
||||||
if (!client->send_sync_but_allow_failure<Messages::UIProcessServer::CreateNewWindow>(raw_urls))
|
if (!client->send_sync_but_allow_failure<Messages::UIProcessServer::CreateNewWindow>(raw_urls))
|
||||||
dbgln("Failed to send CreateNewWindow message to UIProcess");
|
dbgln("Failed to send CreateNewWindow message to UIProcess");
|
||||||
} else {
|
} else {
|
||||||
|
@ -121,13 +123,13 @@ void UIProcessConnectionFromClient::die()
|
||||||
void UIProcessConnectionFromClient::create_new_tab(Vector<ByteString> const& urls)
|
void UIProcessConnectionFromClient::create_new_tab(Vector<ByteString> const& urls)
|
||||||
{
|
{
|
||||||
if (on_new_tab)
|
if (on_new_tab)
|
||||||
on_new_tab(urls);
|
on_new_tab(sanitize_urls(urls, Application::chrome_options().new_tab_page_url));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIProcessConnectionFromClient::create_new_window(Vector<ByteString> const& urls)
|
void UIProcessConnectionFromClient::create_new_window(Vector<ByteString> const& urls)
|
||||||
{
|
{
|
||||||
if (on_new_window)
|
if (on_new_window)
|
||||||
on_new_window(urls);
|
on_new_window(sanitize_urls(urls, Application::chrome_options().new_tab_page_url));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <LibIPC/ConnectionFromClient.h>
|
#include <LibIPC/ConnectionFromClient.h>
|
||||||
#include <LibIPC/Forward.h>
|
#include <LibIPC/Forward.h>
|
||||||
#include <LibIPC/MultiServer.h>
|
#include <LibIPC/MultiServer.h>
|
||||||
|
#include <LibWebView/Options.h>
|
||||||
#include <LibWebView/UIProcessClientEndpoint.h>
|
#include <LibWebView/UIProcessClientEndpoint.h>
|
||||||
#include <LibWebView/UIProcessServerEndpoint.h>
|
#include <LibWebView/UIProcessServerEndpoint.h>
|
||||||
|
|
||||||
|
@ -28,8 +29,8 @@ public:
|
||||||
|
|
||||||
virtual void die() override;
|
virtual void die() override;
|
||||||
|
|
||||||
Function<void(Vector<ByteString> const& urls)> on_new_tab;
|
Function<void(Vector<URL::URL> const&)> on_new_tab;
|
||||||
Function<void(Vector<ByteString> const& urls)> on_new_window;
|
Function<void(Vector<URL::URL> const&)> on_new_window;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UIProcessConnectionFromClient(NonnullOwnPtr<Core::LocalSocket>, int client_id);
|
UIProcessConnectionFromClient(NonnullOwnPtr<Core::LocalSocket>, int client_id);
|
||||||
|
@ -51,15 +52,15 @@ public:
|
||||||
static ErrorOr<ChromeProcess> create();
|
static ErrorOr<ChromeProcess> create();
|
||||||
~ChromeProcess();
|
~ChromeProcess();
|
||||||
|
|
||||||
ErrorOr<ProcessDisposition> connect(Vector<ByteString> const& raw_urls, bool new_window);
|
ErrorOr<ProcessDisposition> connect(Vector<ByteString> const& raw_urls, NewWindow new_window);
|
||||||
|
|
||||||
Function<void(Vector<ByteString> const& raw_urls)> on_new_tab;
|
Function<void(Vector<URL::URL> const&)> on_new_tab;
|
||||||
Function<void(Vector<ByteString> const& raw_urls)> on_new_window;
|
Function<void(Vector<URL::URL> const&)> on_new_window;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ChromeProcess() = default;
|
ChromeProcess() = default;
|
||||||
|
|
||||||
ErrorOr<void> connect_as_client(ByteString const& socket_path, Vector<ByteString> const& raw_urls, bool new_window);
|
ErrorOr<void> connect_as_client(ByteString const& socket_path, Vector<ByteString> const& raw_urls, NewWindow new_window);
|
||||||
ErrorOr<void> connect_as_server(ByteString const& socket_path);
|
ErrorOr<void> connect_as_server(ByteString const& socket_path);
|
||||||
|
|
||||||
OwnPtr<IPC::MultiServer<UIProcessConnectionFromClient>> m_server_connection;
|
OwnPtr<IPC::MultiServer<UIProcessConnectionFromClient>> m_server_connection;
|
||||||
|
|
|
@ -6,48 +6,84 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/ByteString.h>
|
||||||
|
#include <AK/Optional.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
|
#include <AK/Vector.h>
|
||||||
|
#include <LibURL/URL.h>
|
||||||
|
|
||||||
namespace Ladybird {
|
namespace WebView {
|
||||||
|
|
||||||
|
enum class NewWindow {
|
||||||
|
No,
|
||||||
|
Yes,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ForceNewProcess {
|
||||||
|
No,
|
||||||
|
Yes,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class AllowPopups {
|
||||||
|
No,
|
||||||
|
Yes,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class DisableSQLDatabase {
|
||||||
|
No,
|
||||||
|
Yes,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChromeOptions {
|
||||||
|
Vector<URL::URL> urls;
|
||||||
|
Vector<ByteString> raw_urls;
|
||||||
|
URL::URL new_tab_page_url;
|
||||||
|
Vector<ByteString> certificates {};
|
||||||
|
NewWindow new_window { NewWindow::No };
|
||||||
|
ForceNewProcess force_new_process { ForceNewProcess::No };
|
||||||
|
AllowPopups allow_popups { AllowPopups::No };
|
||||||
|
DisableSQLDatabase disable_sql_database { DisableSQLDatabase::No };
|
||||||
|
Optional<ByteString> webdriver_content_ipc_path {};
|
||||||
|
};
|
||||||
|
|
||||||
enum class EnableCallgrindProfiling {
|
enum class EnableCallgrindProfiling {
|
||||||
No,
|
No,
|
||||||
Yes
|
Yes,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class IsLayoutTestMode {
|
enum class IsLayoutTestMode {
|
||||||
No,
|
No,
|
||||||
Yes
|
Yes,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class UseLagomNetworking {
|
enum class UseLagomNetworking {
|
||||||
No,
|
No,
|
||||||
Yes
|
Yes,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class WaitForDebugger {
|
enum class WaitForDebugger {
|
||||||
No,
|
No,
|
||||||
Yes
|
Yes,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class LogAllJSExceptions {
|
enum class LogAllJSExceptions {
|
||||||
No,
|
No,
|
||||||
Yes
|
Yes,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EnableIDLTracing {
|
enum class EnableIDLTracing {
|
||||||
No,
|
No,
|
||||||
Yes
|
Yes,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EnableHTTPCache {
|
enum class EnableHTTPCache {
|
||||||
No,
|
No,
|
||||||
Yes
|
Yes,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ExposeInternalsObject {
|
enum class ExposeInternalsObject {
|
||||||
No,
|
No,
|
||||||
Yes
|
Yes,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WebContentOptions {
|
struct WebContentOptions {
|
|
@ -72,6 +72,22 @@ Optional<URL::URL> sanitize_url(StringView url, Optional<StringView> search_engi
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<URL::URL> sanitize_urls(ReadonlySpan<ByteString> raw_urls, URL::URL const& new_tab_page_url)
|
||||||
|
{
|
||||||
|
Vector<URL::URL> sanitized_urls;
|
||||||
|
sanitized_urls.ensure_capacity(raw_urls.size());
|
||||||
|
|
||||||
|
for (auto const& raw_url : raw_urls) {
|
||||||
|
if (auto url = sanitize_url(raw_url); url.has_value())
|
||||||
|
sanitized_urls.unchecked_append(url.release_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sanitized_urls.is_empty())
|
||||||
|
sanitized_urls.append(new_tab_page_url);
|
||||||
|
|
||||||
|
return sanitized_urls;
|
||||||
|
}
|
||||||
|
|
||||||
static URLParts break_file_url_into_parts(URL::URL const& url, StringView url_string)
|
static URLParts break_file_url_into_parts(URL::URL const& url, StringView url_string)
|
||||||
{
|
{
|
||||||
auto scheme = url_string.substring_view(0, url.scheme().bytes_as_string_view().length() + "://"sv.length());
|
auto scheme = url_string.substring_view(0, url.scheme().bytes_as_string_view().length() + "://"sv.length());
|
||||||
|
|
|
@ -20,6 +20,7 @@ enum class AppendTLD {
|
||||||
Yes,
|
Yes,
|
||||||
};
|
};
|
||||||
Optional<URL::URL> sanitize_url(StringView, Optional<StringView> search_engine = {}, AppendTLD = AppendTLD::No);
|
Optional<URL::URL> sanitize_url(StringView, Optional<StringView> search_engine = {}, AppendTLD = AppendTLD::No);
|
||||||
|
Vector<URL::URL> sanitize_urls(ReadonlySpan<ByteString> raw_urls, URL::URL const& new_tab_page_url);
|
||||||
|
|
||||||
struct URLParts {
|
struct URLParts {
|
||||||
StringView scheme_and_subdomain;
|
StringView scheme_and_subdomain;
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <Ladybird/HelperProcess.h>
|
#include <Ladybird/HelperProcess.h>
|
||||||
#include <Ladybird/Types.h>
|
|
||||||
#include <Ladybird/Utilities.h>
|
#include <Ladybird/Utilities.h>
|
||||||
#include <LibCore/ArgsParser.h>
|
#include <LibCore/ArgsParser.h>
|
||||||
#include <LibCore/ConfigFile.h>
|
#include <LibCore/ConfigFile.h>
|
||||||
|
@ -64,13 +63,13 @@ static StringView s_current_test_path;
|
||||||
|
|
||||||
class HeadlessWebContentView final : public WebView::ViewImplementation {
|
class HeadlessWebContentView final : public WebView::ViewImplementation {
|
||||||
public:
|
public:
|
||||||
static ErrorOr<NonnullOwnPtr<HeadlessWebContentView>> create(Core::AnonymousBuffer theme, Gfx::IntSize const& window_size, String const& command_line, StringView web_driver_ipc_path, Ladybird::IsLayoutTestMode is_layout_test_mode = Ladybird::IsLayoutTestMode::No, Vector<ByteString> const& certificates = {}, StringView resources_folder = {})
|
static ErrorOr<NonnullOwnPtr<HeadlessWebContentView>> create(Core::AnonymousBuffer theme, Gfx::IntSize const& window_size, StringView resources_folder)
|
||||||
{
|
{
|
||||||
RefPtr<Protocol::RequestClient> request_client;
|
RefPtr<Protocol::RequestClient> request_client;
|
||||||
RefPtr<ImageDecoderClient::Client> image_decoder_client;
|
RefPtr<ImageDecoderClient::Client> image_decoder_client;
|
||||||
|
|
||||||
auto request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv));
|
auto request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv));
|
||||||
request_client = TRY(launch_request_server_process(request_server_paths, resources_folder, certificates));
|
request_client = TRY(launch_request_server_process(request_server_paths, resources_folder));
|
||||||
|
|
||||||
auto image_decoder_paths = TRY(get_paths_for_helper_process("ImageDecoder"sv));
|
auto image_decoder_paths = TRY(get_paths_for_helper_process("ImageDecoder"sv));
|
||||||
image_decoder_client = TRY(launch_image_decoder_process(image_decoder_paths));
|
image_decoder_client = TRY(launch_image_decoder_process(image_decoder_paths));
|
||||||
|
@ -80,17 +79,11 @@ public:
|
||||||
|
|
||||||
auto view = TRY(adopt_nonnull_own_or_enomem(new (nothrow) HeadlessWebContentView(move(database), move(cookie_jar), image_decoder_client, request_client)));
|
auto view = TRY(adopt_nonnull_own_or_enomem(new (nothrow) HeadlessWebContentView(move(database), move(cookie_jar), image_decoder_client, request_client)));
|
||||||
|
|
||||||
Ladybird::WebContentOptions web_content_options {
|
|
||||||
.command_line = command_line,
|
|
||||||
.executable_path = MUST(String::from_byte_string(MUST(Core::System::current_executable_path()))),
|
|
||||||
.is_layout_test_mode = is_layout_test_mode,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto request_server_socket = TRY(connect_new_request_server_client(*request_client));
|
auto request_server_socket = TRY(connect_new_request_server_client(*request_client));
|
||||||
auto image_decoder_socket = TRY(connect_new_image_decoder_client(*image_decoder_client));
|
auto image_decoder_socket = TRY(connect_new_image_decoder_client(*image_decoder_client));
|
||||||
|
|
||||||
auto candidate_web_content_paths = TRY(get_paths_for_helper_process("WebContent"sv));
|
auto candidate_web_content_paths = TRY(get_paths_for_helper_process("WebContent"sv));
|
||||||
view->m_client_state.client = TRY(launch_web_content_process(*view, candidate_web_content_paths, web_content_options, move(image_decoder_socket), move(request_server_socket)));
|
view->m_client_state.client = TRY(launch_web_content_process(*view, candidate_web_content_paths, move(image_decoder_socket), move(request_server_socket)));
|
||||||
|
|
||||||
view->client().async_update_system_theme(0, move(theme));
|
view->client().async_update_system_theme(0, move(theme));
|
||||||
|
|
||||||
|
@ -98,8 +91,8 @@ public:
|
||||||
view->client().async_set_viewport_size(0, view->m_viewport_size.to_type<Web::DevicePixels>());
|
view->client().async_set_viewport_size(0, view->m_viewport_size.to_type<Web::DevicePixels>());
|
||||||
view->client().async_set_window_size(0, window_size.to_type<Web::DevicePixels>());
|
view->client().async_set_window_size(0, window_size.to_type<Web::DevicePixels>());
|
||||||
|
|
||||||
if (!web_driver_ipc_path.is_empty())
|
if (auto web_driver_ipc_path = WebView::Application::chrome_options().webdriver_content_ipc_path; web_driver_ipc_path.has_value())
|
||||||
view->client().async_connect_to_webdriver(0, web_driver_ipc_path);
|
view->client().async_connect_to_webdriver(0, *web_driver_ipc_path);
|
||||||
|
|
||||||
view->m_client_state.client->on_web_content_process_crash = [] {
|
view->m_client_state.client->on_web_content_process_crash = [] {
|
||||||
warnln("\033[31;1mWebContent Crashed!!\033[0m");
|
warnln("\033[31;1mWebContent Crashed!!\033[0m");
|
||||||
|
@ -189,7 +182,7 @@ private:
|
||||||
RefPtr<ImageDecoderClient::Client> m_image_decoder_client;
|
RefPtr<ImageDecoderClient::Client> m_image_decoder_client;
|
||||||
};
|
};
|
||||||
|
|
||||||
static ErrorOr<NonnullRefPtr<Core::Timer>> load_page_for_screenshot_and_exit(Core::EventLoop& event_loop, HeadlessWebContentView& view, URL::URL url, int screenshot_timeout)
|
static ErrorOr<NonnullRefPtr<Core::Timer>> load_page_for_screenshot_and_exit(Core::EventLoop& event_loop, HeadlessWebContentView& view, URL::URL const& url, int screenshot_timeout)
|
||||||
{
|
{
|
||||||
// FIXME: Allow passing the output path as an argument.
|
// FIXME: Allow passing the output path as an argument.
|
||||||
static constexpr auto output_file_path = "output.png"sv;
|
static constexpr auto output_file_path = "output.png"sv;
|
||||||
|
@ -248,7 +241,7 @@ static StringView test_result_to_string(TestResult result)
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
static ErrorOr<TestResult> run_dump_test(HeadlessWebContentView& view, StringView input_path, StringView expectation_path, TestMode mode, int timeout_in_milliseconds = DEFAULT_TIMEOUT_MS)
|
static ErrorOr<TestResult> run_dump_test(HeadlessWebContentView& view, URL::URL const& url, StringView expectation_path, TestMode mode, int timeout_in_milliseconds = DEFAULT_TIMEOUT_MS)
|
||||||
{
|
{
|
||||||
Core::EventLoop loop;
|
Core::EventLoop loop;
|
||||||
bool did_timeout = false;
|
bool did_timeout = false;
|
||||||
|
@ -258,8 +251,6 @@ static ErrorOr<TestResult> run_dump_test(HeadlessWebContentView& view, StringVie
|
||||||
loop.quit(0);
|
loop.quit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto url = URL::create_with_file_scheme(TRY(FileSystem::real_path(input_path)));
|
|
||||||
|
|
||||||
String result;
|
String result;
|
||||||
auto did_finish_test = false;
|
auto did_finish_test = false;
|
||||||
auto did_finish_loading = false;
|
auto did_finish_loading = false;
|
||||||
|
@ -335,9 +326,9 @@ static ErrorOr<TestResult> run_dump_test(HeadlessWebContentView& view, StringVie
|
||||||
auto const color_output = isatty(STDOUT_FILENO) ? Diff::ColorOutput::Yes : Diff::ColorOutput::No;
|
auto const color_output = isatty(STDOUT_FILENO) ? Diff::ColorOutput::Yes : Diff::ColorOutput::No;
|
||||||
|
|
||||||
if (color_output == Diff::ColorOutput::Yes)
|
if (color_output == Diff::ColorOutput::Yes)
|
||||||
outln("\n\033[33;1mTest failed\033[0m: {}", input_path);
|
outln("\n\033[33;1mTest failed\033[0m: {}", url);
|
||||||
else
|
else
|
||||||
outln("\nTest failed: {}", input_path);
|
outln("\nTest failed: {}", url);
|
||||||
|
|
||||||
auto hunks = TRY(Diff::from_text(expectation, actual, 3));
|
auto hunks = TRY(Diff::from_text(expectation, actual, 3));
|
||||||
auto out = TRY(Core::File::standard_output());
|
auto out = TRY(Core::File::standard_output());
|
||||||
|
@ -349,7 +340,7 @@ static ErrorOr<TestResult> run_dump_test(HeadlessWebContentView& view, StringVie
|
||||||
return TestResult::Fail;
|
return TestResult::Fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ErrorOr<TestResult> run_ref_test(HeadlessWebContentView& view, StringView input_path, bool dump_failed_ref_tests, int timeout_in_milliseconds = DEFAULT_TIMEOUT_MS)
|
static ErrorOr<TestResult> run_ref_test(HeadlessWebContentView& view, URL::URL const& url, bool dump_failed_ref_tests, int timeout_in_milliseconds = DEFAULT_TIMEOUT_MS)
|
||||||
{
|
{
|
||||||
Core::EventLoop loop;
|
Core::EventLoop loop;
|
||||||
bool did_timeout = false;
|
bool did_timeout = false;
|
||||||
|
@ -370,10 +361,10 @@ static ErrorOr<TestResult> run_ref_test(HeadlessWebContentView& view, StringView
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
view.on_text_test_finish = [&] {
|
view.on_text_test_finish = [&] {
|
||||||
dbgln("Unexpected text test finished during ref test for {}", input_path);
|
dbgln("Unexpected text test finished during ref test for {}", url);
|
||||||
};
|
};
|
||||||
|
|
||||||
view.load(URL::create_with_file_scheme(TRY(FileSystem::real_path(input_path))));
|
view.load(url);
|
||||||
|
|
||||||
timeout_timer->start();
|
timeout_timer->start();
|
||||||
loop.exec();
|
loop.exec();
|
||||||
|
@ -388,8 +379,8 @@ static ErrorOr<TestResult> run_ref_test(HeadlessWebContentView& view, StringView
|
||||||
return TestResult::Pass;
|
return TestResult::Pass;
|
||||||
|
|
||||||
if (dump_failed_ref_tests) {
|
if (dump_failed_ref_tests) {
|
||||||
warnln("\033[33;1mRef test {} failed; dumping screenshots\033[0m", input_path);
|
warnln("\033[33;1mRef test {} failed; dumping screenshots\033[0m", url);
|
||||||
auto title = LexicalPath::title(input_path);
|
auto title = LexicalPath::title(url.serialize_path());
|
||||||
auto dump_screenshot = [&](Gfx::Bitmap& bitmap, StringView path) -> ErrorOr<void> {
|
auto dump_screenshot = [&](Gfx::Bitmap& bitmap, StringView path) -> ErrorOr<void> {
|
||||||
auto screenshot_file = TRY(Core::File::open(path, Core::File::OpenMode::Write));
|
auto screenshot_file = TRY(Core::File::open(path, Core::File::OpenMode::Write));
|
||||||
auto encoded_data = TRY(Gfx::PNGWriter::encode(bitmap));
|
auto encoded_data = TRY(Gfx::PNGWriter::encode(bitmap));
|
||||||
|
@ -462,13 +453,15 @@ static ErrorOr<TestResult> run_test(HeadlessWebContentView& view, StringView inp
|
||||||
view.load(URL::URL("about:blank"sv));
|
view.load(URL::URL("about:blank"sv));
|
||||||
MUST(promise->await());
|
MUST(promise->await());
|
||||||
|
|
||||||
|
auto url = URL::create_with_file_scheme(TRY(FileSystem::real_path(input_path)));
|
||||||
s_current_test_path = input_path;
|
s_current_test_path = input_path;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case TestMode::Text:
|
case TestMode::Text:
|
||||||
case TestMode::Layout:
|
case TestMode::Layout:
|
||||||
return run_dump_test(view, input_path, expectation_path, mode);
|
return run_dump_test(view, url, expectation_path, mode);
|
||||||
case TestMode::Ref:
|
case TestMode::Ref:
|
||||||
return run_ref_test(view, input_path, dump_failed_ref_tests);
|
return run_ref_test(view, url, dump_failed_ref_tests);
|
||||||
default:
|
default:
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -633,28 +626,11 @@ static ErrorOr<int> run_tests(HeadlessWebContentView& view, StringView test_root
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
struct Application : public WebView::Application {
|
||||||
{
|
WEB_VIEW_APPLICATION(Application)
|
||||||
WebView::Application app(arguments.argc, arguments.argv);
|
|
||||||
|
|
||||||
int screenshot_timeout = 1;
|
virtual void create_platform_arguments(Core::ArgsParser& args_parser) override
|
||||||
StringView raw_url;
|
{
|
||||||
auto resources_folder = "/res"sv;
|
|
||||||
StringView web_driver_ipc_path;
|
|
||||||
bool dump_failed_ref_tests = false;
|
|
||||||
bool dump_layout_tree = false;
|
|
||||||
bool dump_text = false;
|
|
||||||
bool dump_gc_graph = false;
|
|
||||||
bool is_layout_test_mode = false;
|
|
||||||
StringView test_root_path;
|
|
||||||
ByteString test_glob;
|
|
||||||
Vector<ByteString> certificates;
|
|
||||||
|
|
||||||
platform_init();
|
|
||||||
resources_folder = s_ladybird_resource_root;
|
|
||||||
|
|
||||||
Core::ArgsParser args_parser;
|
|
||||||
args_parser.set_general_help("This utility runs the Browser in headless mode.");
|
|
||||||
args_parser.add_option(screenshot_timeout, "Take a screenshot after [n] seconds (default: 1)", "screenshot", 's', "n");
|
args_parser.add_option(screenshot_timeout, "Take a screenshot after [n] seconds (default: 1)", "screenshot", 's', "n");
|
||||||
args_parser.add_option(dump_layout_tree, "Dump layout tree and exit", "dump-layout-tree", 'd');
|
args_parser.add_option(dump_layout_tree, "Dump layout tree and exit", "dump-layout-tree", 'd');
|
||||||
args_parser.add_option(dump_text, "Dump text and exit", "dump-text", 'T');
|
args_parser.add_option(dump_text, "Dump text and exit", "dump-text", 'T');
|
||||||
|
@ -663,53 +639,75 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
args_parser.add_option(dump_failed_ref_tests, "Dump screenshots of failing ref tests", "dump-failed-ref-tests", 'D');
|
args_parser.add_option(dump_failed_ref_tests, "Dump screenshots of failing ref tests", "dump-failed-ref-tests", 'D');
|
||||||
args_parser.add_option(dump_gc_graph, "Dump GC graph", "dump-gc-graph", 'G');
|
args_parser.add_option(dump_gc_graph, "Dump GC graph", "dump-gc-graph", 'G');
|
||||||
args_parser.add_option(resources_folder, "Path of the base resources folder (defaults to /res)", "resources", 'r', "resources-root-path");
|
args_parser.add_option(resources_folder, "Path of the base resources folder (defaults to /res)", "resources", 'r', "resources-root-path");
|
||||||
args_parser.add_option(web_driver_ipc_path, "Path to the WebDriver IPC socket", "webdriver-ipc-path", 0, "path");
|
|
||||||
args_parser.add_option(is_layout_test_mode, "Enable layout test mode", "layout-test-mode");
|
args_parser.add_option(is_layout_test_mode, "Enable layout test mode", "layout-test-mode");
|
||||||
args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate");
|
}
|
||||||
args_parser.add_positional_argument(raw_url, "URL to open", "url", Core::ArgsParser::Required::No);
|
|
||||||
args_parser.parse(arguments);
|
|
||||||
|
|
||||||
Core::ResourceImplementation::install(make<Core::ResourceImplementationFile>(MUST(String::from_utf8(resources_folder))));
|
|
||||||
|
|
||||||
auto theme_path = LexicalPath::join(resources_folder, "themes"sv, "Default.ini"sv);
|
|
||||||
auto theme = TRY(Gfx::load_system_theme(theme_path.string()));
|
|
||||||
|
|
||||||
// FIXME: Allow passing the window size as an argument.
|
|
||||||
static constexpr Gfx::IntSize window_size { 800, 600 };
|
|
||||||
|
|
||||||
|
virtual void create_platform_options(WebView::ChromeOptions&, WebView::WebContentOptions& web_content_options) override
|
||||||
|
{
|
||||||
if (!test_root_path.is_empty()) {
|
if (!test_root_path.is_empty()) {
|
||||||
// --run-tests implies --layout-test-mode.
|
// --run-tests implies --layout-test-mode.
|
||||||
is_layout_test_mode = true;
|
is_layout_test_mode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder command_line_builder;
|
web_content_options.is_layout_test_mode = is_layout_test_mode ? WebView::IsLayoutTestMode::Yes : WebView::IsLayoutTestMode::No;
|
||||||
command_line_builder.join(' ', arguments.strings);
|
|
||||||
auto view = TRY(HeadlessWebContentView::create(move(theme), window_size, MUST(command_line_builder.to_string()), web_driver_ipc_path, is_layout_test_mode ? Ladybird::IsLayoutTestMode::Yes : Ladybird::IsLayoutTestMode::No, certificates, resources_folder));
|
|
||||||
|
|
||||||
if (!test_root_path.is_empty()) {
|
|
||||||
test_glob = ByteString::formatted("*{}*", test_glob);
|
|
||||||
return run_tests(*view, test_root_path, test_glob, dump_failed_ref_tests, dump_gc_graph);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto url = WebView::sanitize_url(raw_url);
|
int screenshot_timeout { 1 };
|
||||||
if (!url.has_value()) {
|
ByteString resources_folder { s_ladybird_resource_root };
|
||||||
warnln("Invalid URL: \"{}\"", raw_url);
|
bool dump_failed_ref_tests { false };
|
||||||
|
bool dump_layout_tree { false };
|
||||||
|
bool dump_text { false };
|
||||||
|
bool dump_gc_graph { false };
|
||||||
|
bool is_layout_test_mode { false };
|
||||||
|
StringView test_root_path;
|
||||||
|
ByteString test_glob;
|
||||||
|
};
|
||||||
|
|
||||||
|
Application::Application(Badge<WebView::Application>, Main::Arguments&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
|
{
|
||||||
|
platform_init();
|
||||||
|
|
||||||
|
auto app = Application::create(arguments, "about:newtab"sv);
|
||||||
|
|
||||||
|
Core::ResourceImplementation::install(make<Core::ResourceImplementationFile>(MUST(String::from_byte_string(app->resources_folder))));
|
||||||
|
|
||||||
|
auto theme_path = LexicalPath::join(app->resources_folder, "themes"sv, "Default.ini"sv);
|
||||||
|
auto theme = TRY(Gfx::load_system_theme(theme_path.string()));
|
||||||
|
|
||||||
|
// FIXME: Allow passing the window size as an argument.
|
||||||
|
static constexpr Gfx::IntSize window_size { 800, 600 };
|
||||||
|
|
||||||
|
auto view = TRY(HeadlessWebContentView::create(move(theme), window_size, app->resources_folder));
|
||||||
|
|
||||||
|
if (!app->test_root_path.is_empty()) {
|
||||||
|
auto test_glob = ByteString::formatted("*{}*", app->test_glob);
|
||||||
|
return run_tests(*view, app->test_root_path, test_glob, app->dump_failed_ref_tests, app->dump_gc_graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
VERIFY(!WebView::Application::chrome_options().urls.is_empty());
|
||||||
|
auto const& url = WebView::Application::chrome_options().urls.first();
|
||||||
|
if (!url.is_valid()) {
|
||||||
|
warnln("Invalid URL: \"{}\"", url);
|
||||||
return Error::from_string_literal("Invalid URL");
|
return Error::from_string_literal("Invalid URL");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dump_layout_tree) {
|
if (app->dump_layout_tree) {
|
||||||
TRY(run_dump_test(*view, raw_url, ""sv, TestMode::Layout));
|
TRY(run_dump_test(*view, url, ""sv, TestMode::Layout));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dump_text) {
|
if (app->dump_text) {
|
||||||
TRY(run_dump_test(*view, raw_url, ""sv, TestMode::Text));
|
TRY(run_dump_test(*view, url, ""sv, TestMode::Text));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (web_driver_ipc_path.is_empty()) {
|
if (!WebView::Application::chrome_options().webdriver_content_ipc_path.has_value()) {
|
||||||
auto timer = TRY(load_page_for_screenshot_and_exit(Core::EventLoop::current(), *view, url.value(), screenshot_timeout));
|
auto timer = TRY(load_page_for_screenshot_and_exit(Core::EventLoop::current(), *view, url, app->screenshot_timeout));
|
||||||
return app.exec();
|
return app->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue