Ladybird: Update Android build to work with current LibWebView/LibCore

Also update to the latest gradle plugin versions and other dependencies
as recommended by Android Studio Jellyfish.
This commit is contained in:
Andrew Kaster 2024-05-04 06:08:53 -06:00 committed by Andrew Kaster
parent b562c9759d
commit 68ec099b66
Notes: sideshowbarker 2024-07-17 03:59:29 +09:00
25 changed files with 89 additions and 94 deletions

View file

@ -6,7 +6,7 @@ The Android port of Ladybird has straightforward integration with the Android St
Ensure that your system has the following tools available: Ensure that your system has the following tools available:
- Android Studio Giraffe 2022.3.1 Patch 1 or later - Android Studio Jellyfish 2023.3.1 or later
- CMake 3.23 or higher as the default CMake executable - CMake 3.23 or higher as the default CMake executable
- 20G or more storage space for SDKs + Emulator images + Gradle dependencies + build artifacts - 20G or more storage space for SDKs + Emulator images + Gradle dependencies + build artifacts

View file

@ -1,16 +1,17 @@
import com.android.build.gradle.internal.tasks.factory.dependsOn import com.android.build.gradle.internal.tasks.factory.dependsOn
plugins { plugins {
id("com.android.application") version "8.1.1" id("com.android.application") version "8.4.0"
id("org.jetbrains.kotlin.android") version "1.9.0" id("org.jetbrains.kotlin.android") version "1.9.0"
} }
var buildDir = layout.buildDirectory.get()
var cacheDir = System.getenv("SERENITY_CACHE_DIR") ?: "$buildDir/caches" var cacheDir = System.getenv("SERENITY_CACHE_DIR") ?: "$buildDir/caches"
task<Exec>("buildLagomTools") { task<Exec>("buildLagomTools") {
commandLine = listOf("./BuildLagomTools.sh") commandLine = listOf("./BuildLagomTools.sh")
environment = mapOf( environment = mapOf(
"BUILD_DIR" to "$buildDir", "BUILD_DIR" to buildDir,
"CACHE_DIR" to cacheDir, "CACHE_DIR" to cacheDir,
"PATH" to System.getenv("PATH")!! "PATH" to System.getenv("PATH")!!
) )
@ -20,12 +21,12 @@ tasks.named("prepareKotlinBuildScriptModel").dependsOn("buildLagomTools")
android { android {
namespace = "org.serenityos.ladybird" namespace = "org.serenityos.ladybird"
compileSdk = 33 compileSdk = 34
defaultConfig { defaultConfig {
applicationId = "org.serenityos.ladybird" applicationId = "org.serenityos.ladybird"
minSdk = 30 minSdk = 30
targetSdk = 33 targetSdk = 34
versionCode = 1 versionCode = 1
versionName = "1.0" versionName = "1.0"
@ -75,9 +76,9 @@ android {
} }
dependencies { dependencies {
implementation("androidx.core:core-ktx:1.10.1") implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.appcompat:appcompat:1.6.1") implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.9.0") implementation("com.google.android.material:material:1.12.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4") implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")

View file

@ -1,6 +1,6 @@
#Fri Sep 01 12:36:55 CEST 2023 #Fri Sep 01 12:36:55 CEST 2023
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View file

@ -50,7 +50,7 @@ ALooperEventLoopManager::ALooperEventLoopManager(jobject timer_service)
if (!m_register_timer) if (!m_register_timer)
TODO(); TODO();
m_unregister_timer = env.get()->GetMethodID(timer_service_class, "unregisterTimer", "(J)Z"); m_unregister_timer = env.get()->GetMethodID(timer_service_class, "unregisterTimer", "(J)V");
if (!m_unregister_timer) if (!m_unregister_timer)
TODO(); TODO();
env.get()->DeleteLocalRef(timer_service_class); env.get()->DeleteLocalRef(timer_service_class);
@ -85,7 +85,7 @@ NonnullOwnPtr<Core::EventLoopImplementation> ALooperEventLoopManager::make_imple
return ALooperEventLoopImplementation::create(); return ALooperEventLoopImplementation::create();
} }
int ALooperEventLoopManager::register_timer(Core::EventReceiver& receiver, int milliseconds, bool should_reload, Core::TimerShouldFireWhenNotVisible visibility) intptr_t ALooperEventLoopManager::register_timer(Core::EventReceiver& receiver, int milliseconds, bool should_reload, Core::TimerShouldFireWhenNotVisible visibility)
{ {
JavaEnvironment env(global_vm); JavaEnvironment env(global_vm);
auto& thread_data = EventLoopThreadData::the(); auto& thread_data = EventLoopThreadData::the();
@ -101,13 +101,12 @@ int ALooperEventLoopManager::register_timer(Core::EventReceiver& receiver, int m
return timer_id; return timer_id;
} }
bool ALooperEventLoopManager::unregister_timer(int timer_id) void ALooperEventLoopManager::unregister_timer(intptr_t timer_id)
{ {
if (auto timer = EventLoopThreadData::the().timers.take(timer_id); timer.has_value()) { if (auto timer = EventLoopThreadData::the().timers.take(timer_id); timer.has_value()) {
JavaEnvironment env(global_vm); JavaEnvironment env(global_vm);
return env.get()->CallBooleanMethod(m_timer_service, m_unregister_timer, timer_id); env.get()->CallVoidMethod(m_timer_service, m_unregister_timer, timer_id);
} }
return false;
} }
void ALooperEventLoopManager::register_notifier(Core::Notifier& notifier) void ALooperEventLoopManager::register_notifier(Core::Notifier& notifier)
@ -203,13 +202,23 @@ void ALooperEventLoopImplementation::post_event(Core::EventReceiver& receiver, N
wake(); wake();
} }
static int notifier_callback(int fd, int, void* data) static int notifier_callback(int fd, int events, void* data)
{ {
auto& notifier = *static_cast<Core::Notifier*>(data); auto& notifier = *static_cast<Core::Notifier*>(data);
VERIFY(fd == notifier.fd()); VERIFY(fd == notifier.fd());
Core::NotifierActivationEvent event(notifier.fd()); Core::NotificationType type = Core::NotificationType::None;
if (events & ALOOPER_EVENT_INPUT)
type |= Core::NotificationType::Read;
if (events & ALOOPER_EVENT_OUTPUT)
type |= Core::NotificationType::Write;
if (events & ALOOPER_EVENT_HANGUP)
type |= Core::NotificationType::HangUp;
if (events & ALOOPER_EVENT_ERROR)
type |= Core::NotificationType::Error;
Core::NotifierActivationEvent event(notifier.fd(), type);
notifier.dispatch_event(event); notifier.dispatch_event(event);
// Wake up from ALooper_pollAll, and service this event on the event queue // Wake up from ALooper_pollAll, and service this event on the event queue
@ -228,7 +237,12 @@ void ALooperEventLoopImplementation::register_notifier(Core::Notifier& notifier)
case Core::Notifier::Type::Write: case Core::Notifier::Type::Write:
event_flags = ALOOPER_EVENT_OUTPUT; event_flags = ALOOPER_EVENT_OUTPUT;
break; break;
case Core::Notifier::Type::Exceptional: case Core::Notifier::Type::Error:
event_flags = ALOOPER_EVENT_ERROR;
break;
case Core::Notifier::Type::HangUp:
event_flags = ALOOPER_EVENT_HANGUP;
break;
case Core::Notifier::Type::None: case Core::Notifier::Type::None:
TODO(); TODO();
} }

View file

@ -23,8 +23,8 @@ public:
virtual ~ALooperEventLoopManager() override; virtual ~ALooperEventLoopManager() override;
virtual NonnullOwnPtr<Core::EventLoopImplementation> make_implementation() override; virtual NonnullOwnPtr<Core::EventLoopImplementation> make_implementation() override;
virtual int register_timer(Core::EventReceiver&, int milliseconds, bool should_reload, Core::TimerShouldFireWhenNotVisible) override; virtual intptr_t register_timer(Core::EventReceiver&, int milliseconds, bool should_reload, Core::TimerShouldFireWhenNotVisible) override;
virtual bool unregister_timer(int timer_id) override; virtual void unregister_timer(intptr_t timer_id) override;
virtual void register_notifier(Core::Notifier&) override; virtual void register_notifier(Core::Notifier&) override;
virtual void unregister_notifier(Core::Notifier&) override; virtual void unregister_notifier(Core::Notifier&) override;

View file

@ -10,13 +10,12 @@
#include <LibCore/EventLoop.h> #include <LibCore/EventLoop.h>
#include <LibIPC/SingleServer.h> #include <LibIPC/SingleServer.h>
ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket) ErrorOr<int> service_main(int ipc_socket)
{ {
Core::EventLoop event_loop; Core::EventLoop event_loop;
auto socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket)); auto socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket));
auto client = TRY(ImageDecoder::ConnectionFromClient::try_create(move(socket))); auto client = TRY(ImageDecoder::ConnectionFromClient::try_create(move(socket)));
client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(fd_passing_socket)));
return event_loop.exec(); return event_loop.exec();
} }

View file

@ -177,7 +177,7 @@ ErrorOr<void> extract_tar_archive(String archive_file, ByteString output_directo
path = path.prepend(header.prefix()); path = path.prepend(header.prefix());
ByteString filename = get_override("path"sv).value_or(path.string()); ByteString filename = get_override("path"sv).value_or(path.string());
ByteString absolute_path = TRY(FileSystem::absolute_path(filename)).to_byte_string(); ByteString absolute_path = TRY(FileSystem::absolute_path(filename));
auto parent_path = LexicalPath(absolute_path).parent(); auto parent_path = LexicalPath(absolute_path).parent();
auto header_mode = TRY(header.mode()); auto header_mode = TRY(header.mode());

View file

@ -9,4 +9,4 @@
#include <AK/Error.h> #include <AK/Error.h>
#include <jni.h> #include <jni.h>
ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket); ErrorOr<int> service_main(int ipc_socket);

View file

@ -14,10 +14,9 @@
JavaVM* global_vm; JavaVM* global_vm;
extern "C" JNIEXPORT void JNICALL extern "C" JNIEXPORT void JNICALL
Java_org_serenityos_ladybird_LadybirdServiceBase_nativeThreadLoop(JNIEnv*, jobject /* thiz */, jint ipc_socket, jint fd_passing_socket) Java_org_serenityos_ladybird_LadybirdServiceBase_nativeThreadLoop(JNIEnv*, jobject /* thiz */, jint ipc_socket)
{ {
dbgln("New binding received, sockets {} and {}", ipc_socket, fd_passing_socket); auto ret = service_main(ipc_socket);
auto ret = service_main(ipc_socket, fd_passing_socket);
if (ret.is_error()) { if (ret.is_error()) {
warnln("Runtime Error: {}", ret.release_error()); warnln("Runtime Error: {}", ret.release_error());
} else { } else {

View file

@ -23,13 +23,13 @@
// FIXME: Share b/w RequestServer and WebSocket // FIXME: Share b/w RequestServer and WebSocket
ErrorOr<ByteString> find_certificates(StringView serenity_resource_root) ErrorOr<ByteString> find_certificates(StringView serenity_resource_root)
{ {
auto cert_path = ByteString::formatted("{}/ladybird/cacert.pem", serenity_resource_root); auto cert_path = ByteString::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root);
if (!FileSystem::exists(cert_path)) if (!FileSystem::exists(cert_path))
return Error::from_string_view("Don't know how to load certs!"sv); return Error::from_string_view("Don't know how to load certs!"sv);
return cert_path; return cert_path;
} }
ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket) ErrorOr<int> service_main(int ipc_socket)
{ {
// Ensure the certificates are read out here. // Ensure the certificates are read out here.
DefaultRootCACertificates::set_default_certificate_paths(Vector { TRY(find_certificates(s_serenity_resource_root)) }); DefaultRootCACertificates::set_default_certificate_paths(Vector { TRY(find_certificates(s_serenity_resource_root)) });
@ -43,7 +43,6 @@ ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
auto socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket)); auto socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket));
auto client = TRY(RequestServer::ConnectionFromClient::try_create(move(socket))); auto client = TRY(RequestServer::ConnectionFromClient::try_create(move(socket)));
client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(fd_passing_socket)));
return event_loop.exec(); return event_loop.exec();
} }

View file

@ -26,7 +26,7 @@ Java_org_serenityos_ladybird_TimerExecutorService_00024Timer_nativeRun(JNIEnv*,
if (!receiver->is_visible_for_timer_purposes()) if (!receiver->is_visible_for_timer_purposes())
return; return;
event_loop_impl.post_event(*receiver, make<Core::TimerEvent>(id)); event_loop_impl.post_event(*receiver, make<Core::TimerEvent>());
} }
// Flush the event loop on this thread to keep any garbage from building up // Flush the event loop on this thread to keep any garbage from building up
if (auto num_events = s_event_loop.pump(Core::EventLoop::WaitMode::PollForEvents); num_events != 0) { if (auto num_events = s_event_loop.pump(Core::EventLoop::WaitMode::PollForEvents); num_events != 0) {

View file

@ -19,6 +19,7 @@
#include <LibIPC/ConnectionFromClient.h> #include <LibIPC/ConnectionFromClient.h>
#include <LibImageDecoderClient/Client.h> #include <LibImageDecoderClient/Client.h>
#include <LibJS/Bytecode/Interpreter.h> #include <LibJS/Bytecode/Interpreter.h>
#include <LibProtocol/RequestClient.h>
#include <LibWeb/Bindings/MainThreadVM.h> #include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/HTML/Window.h> #include <LibWeb/HTML/Window.h>
#include <LibWeb/Loader/ContentFilter.h> #include <LibWeb/Loader/ContentFilter.h>
@ -37,13 +38,13 @@ static ErrorOr<NonnullRefPtr<Protocol::RequestClient>> bind_request_server_servi
} }
template ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>, Error> template ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>, Error>
bind_service<ImageDecoderClient::Client>(void (*)(int, int)); bind_service<ImageDecoderClient::Client>(void (*)(int));
static ErrorOr<void> load_content_filters(); static ErrorOr<void> load_content_filters();
static ErrorOr<void> load_autoplay_allowlist(); static ErrorOr<void> load_autoplay_allowlist();
ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket) ErrorOr<int> service_main(int ipc_socket)
{ {
Core::EventLoop event_loop; Core::EventLoop event_loop;
@ -75,13 +76,12 @@ ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
auto webcontent_socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket)); auto webcontent_socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket));
auto webcontent_client = TRY(WebContent::ConnectionFromClient::try_create(move(webcontent_socket))); auto webcontent_client = TRY(WebContent::ConnectionFromClient::try_create(move(webcontent_socket)));
webcontent_client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(fd_passing_socket)));
return event_loop.exec(); return event_loop.exec();
} }
template<typename Client> template<typename Client>
ErrorOr<NonnullRefPtr<Client>> bind_service(void (*bind_method)(int, int)) ErrorOr<NonnullRefPtr<Client>> bind_service(void (*bind_method)(int))
{ {
int socket_fds[2] {}; int socket_fds[2] {};
TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds)); TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds));
@ -89,20 +89,13 @@ ErrorOr<NonnullRefPtr<Client>> bind_service(void (*bind_method)(int, int))
int ui_fd = socket_fds[0]; int ui_fd = socket_fds[0];
int server_fd = socket_fds[1]; int server_fd = socket_fds[1];
int fd_passing_socket_fds[2] {};
TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fd_passing_socket_fds));
int ui_fd_passing_fd = fd_passing_socket_fds[0];
int server_fd_passing_fd = fd_passing_socket_fds[1];
// NOTE: The java object takes ownership of the socket fds // NOTE: The java object takes ownership of the socket fds
(*bind_method)(server_fd, server_fd_passing_fd); (*bind_method)(server_fd);
auto socket = TRY(Core::LocalSocket::adopt_fd(ui_fd)); auto socket = TRY(Core::LocalSocket::adopt_fd(ui_fd));
TRY(socket->set_blocking(true)); TRY(socket->set_blocking(true));
auto new_client = TRY(try_make_ref_counted<Client>(move(socket))); auto new_client = TRY(try_make_ref_counted<Client>(move(socket)));
new_client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(ui_fd_passing_fd)));
return new_client; return new_client;
} }

View file

@ -9,8 +9,7 @@
#include <AK/NonnullRefPtr.h> #include <AK/NonnullRefPtr.h>
template<typename Client> template<typename Client>
ErrorOr<NonnullRefPtr<Client>> bind_service(void (*bind_method)(int, int)); ErrorOr<NonnullRefPtr<Client>> bind_service(void (*bind_method)(int));
void bind_request_server_java(int ipc_socket, int fd_passing_socket); void bind_request_server_java(int ipc_socket);
void bind_web_socket_java(int ipc_socket, int fd_passing_socket); void bind_image_decoder_java(int ipc_socket);
void bind_image_decoder_java(int ipc_socket, int fd_passing_socket);

View file

@ -24,25 +24,25 @@ Java_org_serenityos_ladybird_WebContentService_nativeInit(JNIEnv* env, jobject t
global_class_reference = reinterpret_cast<jclass>(env->NewGlobalRef(local_class)); global_class_reference = reinterpret_cast<jclass>(env->NewGlobalRef(local_class));
env->DeleteLocalRef(local_class); env->DeleteLocalRef(local_class);
auto method = env->GetMethodID(global_class_reference, "bindRequestServer", "(II)V"); auto method = env->GetMethodID(global_class_reference, "bindRequestServer", "(I)V");
if (!method) if (!method)
TODO(); TODO();
bind_request_server_method = method; bind_request_server_method = method;
method = env->GetMethodID(global_class_reference, "bindImageDecoder", "(II)V"); method = env->GetMethodID(global_class_reference, "bindImageDecoder", "(I)V");
if (!method) if (!method)
TODO(); TODO();
bind_image_decoder_method = method; bind_image_decoder_method = method;
} }
void bind_request_server_java(int ipc_socket, int fd_passing_socket) void bind_request_server_java(int ipc_socket)
{ {
Ladybird::JavaEnvironment env(global_vm); Ladybird::JavaEnvironment env(global_vm);
env.get()->CallVoidMethod(global_instance, bind_request_server_method, ipc_socket, fd_passing_socket); env.get()->CallVoidMethod(global_instance, bind_request_server_method, ipc_socket);
} }
void bind_image_decoder_java(int ipc_socket, int fd_passing_socket) void bind_image_decoder_java(int ipc_socket)
{ {
Ladybird::JavaEnvironment env(global_vm); Ladybird::JavaEnvironment env(global_vm);
env.get()->CallVoidMethod(global_instance, bind_image_decoder_method, ipc_socket, fd_passing_socket); env.get()->CallVoidMethod(global_instance, bind_image_decoder_method, ipc_socket);
} }

View file

@ -6,6 +6,7 @@
#include "WebViewImplementationNative.h" #include "WebViewImplementationNative.h"
#include "JNIHelpers.h" #include "JNIHelpers.h"
#include <LibWebView/WebContentClient.h>
#include <Userland/Libraries/LibGfx/Bitmap.h> #include <Userland/Libraries/LibGfx/Bitmap.h>
#include <Userland/Libraries/LibGfx/Painter.h> #include <Userland/Libraries/LibGfx/Painter.h>
#include <Userland/Libraries/LibWeb/Crypto/Crypto.h> #include <Userland/Libraries/LibWeb/Crypto/Crypto.h>
@ -28,14 +29,14 @@ WebViewImplementationNative::WebViewImplementationNative(jobject thiz)
: m_java_instance(thiz) : m_java_instance(thiz)
{ {
// NOTE: m_java_instance's global ref is controlled by the JNI bindings // NOTE: m_java_instance's global ref is controlled by the JNI bindings
create_client(WebView::EnableCallgrindProfiling::No); initialize_client(CreateNewClient::Yes);
on_ready_to_paint = [this]() { on_ready_to_paint = [this]() {
JavaEnvironment env(global_vm); JavaEnvironment env(global_vm);
env.get()->CallVoidMethod(m_java_instance, invalidate_layout_method); env.get()->CallVoidMethod(m_java_instance, invalidate_layout_method);
}; };
on_load_start = [this](URL const& url, bool is_redirect) { on_load_start = [this](URL::URL const& url, bool is_redirect) {
JavaEnvironment env(global_vm); JavaEnvironment env(global_vm);
auto url_string = env.jstring_from_ak_string(MUST(url.to_string())); auto url_string = env.jstring_from_ak_string(MUST(url.to_string()));
env.get()->CallVoidMethod(m_java_instance, on_load_start_method, url_string, is_redirect); env.get()->CallVoidMethod(m_java_instance, on_load_start_method, url_string, is_redirect);
@ -43,7 +44,7 @@ WebViewImplementationNative::WebViewImplementationNative(jobject thiz)
}; };
} }
void WebViewImplementationNative::create_client(WebView::EnableCallgrindProfiling) void WebViewImplementationNative::initialize_client(WebView::ViewImplementation::CreateNewClient)
{ {
m_client_state = {}; m_client_state = {};
@ -56,9 +57,9 @@ void WebViewImplementationNative::create_client(WebView::EnableCallgrindProfilin
}; };
m_client_state.client_handle = MUST(Web::Crypto::generate_random_uuid()); m_client_state.client_handle = MUST(Web::Crypto::generate_random_uuid());
client().async_set_window_handle(m_client_state.client_handle); client().async_set_window_handle(0, m_client_state.client_handle);
client().async_set_device_pixels_per_css_pixel(m_device_pixel_ratio); client().async_set_device_pixels_per_css_pixel(0, m_device_pixel_ratio);
// FIXME: update_palette, update system fonts // FIXME: update_palette, update system fonts
} }
@ -93,14 +94,14 @@ void WebViewImplementationNative::paint_into_bitmap(void* android_bitmap_raw, An
void WebViewImplementationNative::set_viewport_geometry(int w, int h) void WebViewImplementationNative::set_viewport_geometry(int w, int h)
{ {
m_viewport_rect = { { 0, 0 }, { w, h } }; m_viewport_rect = { { 0, 0 }, { w, h } };
client().async_set_viewport_rect(m_viewport_rect); client().async_set_viewport_rect(0, m_viewport_rect);
handle_resize(); handle_resize();
} }
void WebViewImplementationNative::set_device_pixel_ratio(float f) void WebViewImplementationNative::set_device_pixel_ratio(float f)
{ {
m_device_pixel_ratio = f; m_device_pixel_ratio = f;
client().async_set_device_pixels_per_css_pixel(m_device_pixel_ratio); client().async_set_device_pixels_per_css_pixel(0, m_device_pixel_ratio);
} }
NonnullRefPtr<WebView::WebContentClient> WebViewImplementationNative::bind_web_content_client() NonnullRefPtr<WebView::WebContentClient> WebViewImplementationNative::bind_web_content_client()
@ -113,20 +114,13 @@ NonnullRefPtr<WebView::WebContentClient> WebViewImplementationNative::bind_web_c
int ui_fd = socket_fds[0]; int ui_fd = socket_fds[0];
int wc_fd = socket_fds[1]; int wc_fd = socket_fds[1];
int fd_passing_socket_fds[2] {};
MUST(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fd_passing_socket_fds));
int ui_fd_passing_fd = fd_passing_socket_fds[0];
int wc_fd_passing_fd = fd_passing_socket_fds[1];
// NOTE: The java object takes ownership of the socket fds // NOTE: The java object takes ownership of the socket fds
env.get()->CallVoidMethod(m_java_instance, bind_webcontent_method, wc_fd, wc_fd_passing_fd); env.get()->CallVoidMethod(m_java_instance, bind_webcontent_method, wc_fd);
auto socket = MUST(Core::LocalSocket::adopt_fd(ui_fd)); auto socket = MUST(Core::LocalSocket::adopt_fd(ui_fd));
MUST(socket->set_blocking(true)); MUST(socket->set_blocking(true));
auto new_client = make_ref_counted<WebView::WebContentClient>(move(socket), *this); auto new_client = make_ref_counted<WebView::WebContentClient>(move(socket), *this);
new_client->set_fd_passing_socket(MUST(Core::LocalSocket::adopt_fd(ui_fd_passing_fd)));
return new_client; return new_client;
} }

View file

@ -15,14 +15,14 @@ class WebViewImplementationNative : public WebView::ViewImplementation {
public: public:
WebViewImplementationNative(jobject thiz); WebViewImplementationNative(jobject thiz);
virtual Gfx::IntRect viewport_rect() const override { return m_viewport_rect; } virtual Web::DevicePixelRect viewport_rect() const override { return m_viewport_rect; }
virtual Gfx::IntPoint to_content_position(Gfx::IntPoint p) const override { return p; } virtual Gfx::IntPoint to_content_position(Gfx::IntPoint p) const override { return p; }
virtual Gfx::IntPoint to_widget_position(Gfx::IntPoint p) const override { return p; } virtual Gfx::IntPoint to_widget_position(Gfx::IntPoint p) const override { return p; }
virtual void update_zoom() override { } virtual void update_zoom() override { }
NonnullRefPtr<WebView::WebContentClient> bind_web_content_client(); NonnullRefPtr<WebView::WebContentClient> bind_web_content_client();
virtual void create_client(WebView::EnableCallgrindProfiling) override; virtual void initialize_client(CreateNewClient) override;
void paint_into_bitmap(void* android_bitmap_raw, AndroidBitmapInfo const& info); void paint_into_bitmap(void* android_bitmap_raw, AndroidBitmapInfo const& info);
@ -38,6 +38,6 @@ public:
private: private:
jobject m_java_instance = nullptr; jobject m_java_instance = nullptr;
Gfx::IntRect m_viewport_rect; Web::DevicePixelRect m_viewport_rect;
}; };
} }

View file

@ -23,7 +23,7 @@ Java_org_serenityos_ladybird_WebViewImplementation_00024Companion_nativeClassIni
WebViewImplementationNative::global_class_reference = reinterpret_cast<jclass>(env->NewGlobalRef(local_class)); WebViewImplementationNative::global_class_reference = reinterpret_cast<jclass>(env->NewGlobalRef(local_class));
env->DeleteLocalRef(local_class); env->DeleteLocalRef(local_class);
auto method = env->GetMethodID(WebViewImplementationNative::global_class_reference, "bindWebContentService", "(II)V"); auto method = env->GetMethodID(WebViewImplementationNative::global_class_reference, "bindWebContentService", "(I)V");
if (!method) if (!method)
TODO(); TODO();
WebViewImplementationNative::bind_webcontent_method = method; WebViewImplementationNative::bind_webcontent_method = method;

View file

@ -19,7 +19,7 @@ import java.lang.ref.WeakReference
import java.util.concurrent.Executors import java.util.concurrent.Executors
const val MSG_SET_RESOURCE_ROOT = 1 const val MSG_SET_RESOURCE_ROOT = 1
const val MSG_TRANSFER_SOCKETS = 2 const val MSG_TRANSFER_SOCKET = 2
abstract class LadybirdServiceBase(protected val TAG: String) : Service() { abstract class LadybirdServiceBase(protected val TAG: String) : Service() {
private val threadPool = Executors.newCachedThreadPool() private val threadPool = Executors.newCachedThreadPool()
@ -44,8 +44,7 @@ abstract class LadybirdServiceBase(protected val TAG: String) : Service() {
val bundle = msg.data val bundle = msg.data
// FIXME: Handle garbage messages from wierd clients // FIXME: Handle garbage messages from wierd clients
val ipcSocket = bundle.getParcelable<ParcelFileDescriptor>("IPC_SOCKET")!! val ipcSocket = bundle.getParcelable<ParcelFileDescriptor>("IPC_SOCKET")!!
val fdSocket = bundle.getParcelable<ParcelFileDescriptor>("FD_PASSING_SOCKET")!! createThread(ipcSocket)
createThread(ipcSocket, fdSocket)
} }
private fun handleSetResourceRoot(msg: Message) { private fun handleSetResourceRoot(msg: Message) {
@ -61,13 +60,13 @@ abstract class LadybirdServiceBase(protected val TAG: String) : Service() {
} }
private fun createThread(ipcSocket: ParcelFileDescriptor, fdSocket: ParcelFileDescriptor) { private fun createThread(ipcSocket: ParcelFileDescriptor) {
threadPool.execute { threadPool.execute {
nativeThreadLoop(ipcSocket.detachFd(), fdSocket.detachFd()) nativeThreadLoop(ipcSocket.detachFd())
} }
} }
private external fun nativeThreadLoop(ipcSocket: Int, fdPassingSocket: Int) private external fun nativeThreadLoop(ipcSocket: Int)
private external fun initNativeCode(resourceDir: String, tagName: String); private external fun initNativeCode(resourceDir: String, tagName: String);
abstract fun handleServiceSpecificMessage(msg: Message): Boolean abstract fun handleServiceSpecificMessage(msg: Message): Boolean
@ -78,7 +77,7 @@ abstract class LadybirdServiceBase(protected val TAG: String) : Service() {
Handler(Looper.getMainLooper()) { Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) { override fun handleMessage(msg: Message) {
when (msg.what) { when (msg.what) {
MSG_TRANSFER_SOCKETS -> service.get()?.handleTransferSockets(msg) MSG_TRANSFER_SOCKET -> service.get()?.handleTransferSockets(msg)
?: super.handleMessage(msg) ?: super.handleMessage(msg)
MSG_SET_RESOURCE_ROOT -> service.get()?.handleSetResourceRoot(msg) MSG_SET_RESOURCE_ROOT -> service.get()?.handleSetResourceRoot(msg)

View file

@ -15,7 +15,6 @@ import android.os.ParcelFileDescriptor
class LadybirdServiceConnection( class LadybirdServiceConnection(
private var ipcFd: Int, private var ipcFd: Int,
private var fdPassingFd: Int,
private var resourceDir: String private var resourceDir: String
) : ) :
ServiceConnection { ServiceConnection {
@ -36,9 +35,8 @@ class LadybirdServiceConnection(
init.data.putString("PATH", resourceDir) init.data.putString("PATH", resourceDir)
service!!.send(init) service!!.send(init)
val msg = Message.obtain(null, MSG_TRANSFER_SOCKETS) val msg = Message.obtain(null, MSG_TRANSFER_SOCKET)
msg.data.putParcelable("IPC_SOCKET", ParcelFileDescriptor.adoptFd(ipcFd)) msg.data.putParcelable("IPC_SOCKET", ParcelFileDescriptor.adoptFd(ipcFd))
msg.data.putParcelable("FD_PASSING_SOCKET", ParcelFileDescriptor.adoptFd(fdPassingFd))
service!!.send(msg) service!!.send(msg)
} }

View file

@ -30,7 +30,7 @@ class TimerExecutorService {
timer, timer,
milliseconds, milliseconds,
TimeUnit.MILLISECONDS TimeUnit.MILLISECONDS
) else executor.scheduleAtFixedRate( ) else executor.scheduleWithFixedDelay(
timer, timer,
milliseconds, milliseconds,
milliseconds, milliseconds,
@ -40,9 +40,9 @@ class TimerExecutorService {
return id return id
} }
fun unregisterTimer(id: Long): Boolean { fun unregisterTimer(id: Long) {
val timer = timers[id] ?: return false val timer = timers[id] ?: return
return timer.cancel(false) timer.cancel(false)
} }
private var nextId: Long = 0 private var nextId: Long = 0

View file

@ -20,9 +20,9 @@ class WebContentService : LadybirdServiceBase("WebContentService") {
nativeInit(); nativeInit();
} }
private fun bindRequestServer(ipcFd: Int, fdPassingFd: Int) private fun bindRequestServer(ipcFd: Int)
{ {
val connector = LadybirdServiceConnection(ipcFd, fdPassingFd, resourceDir) val connector = LadybirdServiceConnection(ipcFd, resourceDir)
connector.onDisconnect = { connector.onDisconnect = {
// FIXME: Notify impl that service is dead and might need restarted // FIXME: Notify impl that service is dead and might need restarted
Log.e(TAG, "RequestServer Died! :(") Log.e(TAG, "RequestServer Died! :(")
@ -35,9 +35,9 @@ class WebContentService : LadybirdServiceBase("WebContentService") {
) )
} }
private fun bindImageDecoder(ipcFd: Int, fdPassingFd: Int) private fun bindImageDecoder(ipcFd: Int)
{ {
val connector = LadybirdServiceConnection(ipcFd, fdPassingFd, resourceDir) val connector = LadybirdServiceConnection(ipcFd, resourceDir)
connector.onDisconnect = { connector.onDisconnect = {
// FIXME: Notify impl that service is dead and might need restarted // FIXME: Notify impl that service is dead and might need restarted
Log.e(TAG, "ImageDecoder Died! :(") Log.e(TAG, "ImageDecoder Died! :(")

View file

@ -41,11 +41,11 @@ class WebView(context: Context, attributeSet: AttributeSet) : View(context, attr
viewImpl.setViewportGeometry(w, h) viewImpl.setViewportGeometry(w, h)
} }
override fun onDraw(canvas: Canvas?) { override fun onDraw(canvas: Canvas) {
super.onDraw(canvas) super.onDraw(canvas)
viewImpl.drawIntoBitmap(contentBitmap); viewImpl.drawIntoBitmap(contentBitmap);
canvas?.drawBitmap(contentBitmap, 0f, 0f, null) canvas.drawBitmap(contentBitmap, 0f, 0f, null)
} }
} }

View file

@ -50,8 +50,8 @@ class WebViewImplementation(private val view: WebView) {
} }
// Functions called from native code // Functions called from native code
fun bindWebContentService(ipcFd: Int, fdPassingFd: Int) { fun bindWebContentService(ipcFd: Int) {
val connector = LadybirdServiceConnection(ipcFd, fdPassingFd, resourceDir) val connector = LadybirdServiceConnection(ipcFd, resourceDir)
connector.onDisconnect = { connector.onDisconnect = {
// FIXME: Notify impl that service is dead and might need restarted // FIXME: Notify impl that service is dead and might need restarted
Log.e("WebContentView", "WebContent Died! :(") Log.e("WebContentView", "WebContent Died! :(")

View file

@ -20,7 +20,7 @@ else()
endif() endif()
add_executable(ImageDecoder main.cpp) add_executable(ImageDecoder main.cpp)
target_link_libraries(ImageDecoder PRIVATE imagedecoder LibMain) target_link_libraries(ImageDecoder PRIVATE imagedecoder LibCore LibMain)
target_include_directories(imagedecoder PRIVATE ${SERENITY_SOURCE_DIR}/Userland/Services/) target_include_directories(imagedecoder PRIVATE ${SERENITY_SOURCE_DIR}/Userland/Services/)
target_include_directories(imagedecoder PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..) target_include_directories(imagedecoder PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..)

View file

@ -32,7 +32,7 @@ jobs:
value: '${{ parameters.host_cxx }}' value: '${{ parameters.host_cxx }}'
- name: ndk_version # only relevant for Android - name: ndk_version # only relevant for Android
value: '25.2.9519653' value: '26.1.10909125'
pool: pool:
vmImage: $(job_pool) vmImage: $(job_pool)