Skip to content

Commit fcc7f33

Browse files
committed
LibWebView: Wire geolocation through WebContent
Connect WebContent geolocation requests to the browser-process provider owned by Application. Responses are keyed by request ID and guarded by the originating view, page, and client handle so late callbacks from navigation or teardown are ignored. Active native watches are stopped when WebContent cancels them, when a permission-denied response terminates the watch, or when the owning view is destroyed.
1 parent d43da44 commit fcc7f33

13 files changed

Lines changed: 346 additions & 9 deletions

Libraries/LibWeb/HTML/LocalTraversableNavigable.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -150,21 +150,15 @@ GC::Ref<LocalTraversableNavigable> LocalTraversableNavigable::create_a_fresh_top
150150
auto traversable = create_a_new_top_level_traversable(page, nullptr, {});
151151
page->set_top_level_traversable(traversable);
152152

153-
// AD-HOC: Set the default top-level emulated position data for the traversable, which points to Market St. SF.
154-
// FIXME: We should not emulate by default, but ask the user what to do. E.g. disable Geolocation, set an emulated
155-
// position, or allow Ladybird to engage with the system's geolocation services. This is completely separate
156-
// from the permission model for "powerful features" such as Geolocation.
153+
// AD-HOC: Set default emulated position data for the traversable. The UI process will override this with the
154+
// user's geolocation settings via IPC, but this ensures a safe default if the IPC hasn't arrived yet.
157155
auto& realm = traversable->active_document()->realm();
158156
auto emulated_position_coordinates = realm.create<Geolocation::GeolocationCoordinates>(
159157
realm,
160158
Geolocation::CoordinatesData {
161159
.accuracy = 100.0,
162160
.latitude = 37.7647658,
163161
.longitude = -122.4345892,
164-
.altitude = 60.0,
165-
.altitude_accuracy = 10.0,
166-
.heading = 0.0,
167-
.speed = 0.0,
168162
});
169163
traversable->set_emulated_position_data(emulated_position_coordinates);
170164

Libraries/LibWebView/Application.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,6 +2043,49 @@ void Application::toggle_bookmark_for_view(ViewImplementation& view)
20432043
});
20442044
}
20452045

2046+
ErrorOr<NonnullRawPtr<Core::GeolocationProvider>> Application::ensure_geolocation_provider()
2047+
{
2048+
if (!m_geolocation_provider)
2049+
m_geolocation_provider = TRY(Core::GeolocationProvider::create());
2050+
2051+
return NonnullRawPtr { *m_geolocation_provider };
2052+
}
2053+
2054+
static Core::GeolocationError geolocation_provider_unavailable_error(Error const& error)
2055+
{
2056+
return {
2057+
.type = Core::GeolocationError::Type::PositionUnavailable,
2058+
.message = MUST(String::from_utf8(error.string_literal())),
2059+
};
2060+
}
2061+
2062+
void Application::request_geolocation_position(Core::GeolocationProvider::SuccessCallback on_success, Core::GeolocationProvider::ErrorCallback on_error)
2063+
{
2064+
auto provider = ensure_geolocation_provider();
2065+
if (provider.is_error()) {
2066+
on_error(geolocation_provider_unavailable_error(provider.error()));
2067+
return;
2068+
}
2069+
provider.value()->request_current_position(move(on_success), move(on_error));
2070+
}
2071+
2072+
ErrorOr<Core::GeolocationProvider::WatchId, Core::GeolocationError> Application::start_watching_geolocation_position(Core::GeolocationProvider::SuccessCallback on_success, Core::GeolocationProvider::ErrorCallback on_error)
2073+
{
2074+
auto provider = ensure_geolocation_provider();
2075+
if (provider.is_error())
2076+
return geolocation_provider_unavailable_error(provider.error());
2077+
2078+
return provider.value()->start_watching_position(move(on_success), move(on_error));
2079+
}
2080+
2081+
void Application::stop_watching_geolocation_position(Core::GeolocationProvider::WatchId watch_id)
2082+
{
2083+
if (!m_geolocation_provider)
2084+
return;
2085+
2086+
m_geolocation_provider->stop_watching_position(watch_id);
2087+
}
2088+
20462089
void Application::create_bookmark_menu_items(Optional<MenuData> data)
20472090
{
20482091
auto const& [menu, items, target_folder_id] = data.ensure([&]() -> MenuData {

Libraries/LibWebView/Application.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
#include <AK/ByteString.h>
1010
#include <AK/Function.h>
1111
#include <AK/LexicalPath.h>
12+
#include <AK/NonnullRawPtr.h>
1213
#include <AK/Optional.h>
1314
#include <LibCore/AnonymousBuffer.h>
1415
#include <LibCore/EventLoop.h>
1516
#include <LibCore/Forward.h>
17+
#include <LibCore/GeolocationProvider.h>
1618
#include <LibDatabase/Forward.h>
1719
#include <LibDevTools/DevToolsDelegate.h>
1820
#include <LibDevTools/Forward.h>
@@ -125,6 +127,10 @@ class WEBVIEW_API Application : public DevTools::DevToolsDelegate {
125127
void set_browser_process_transport_handler(Function<void(NonnullOwnPtr<IPC::Transport>)> handler);
126128
#endif
127129

130+
void request_geolocation_position(Core::GeolocationProvider::SuccessCallback on_success, Core::GeolocationProvider::ErrorCallback on_error);
131+
ErrorOr<Core::GeolocationProvider::WatchId, Core::GeolocationError> start_watching_geolocation_position(Core::GeolocationProvider::SuccessCallback on_success, Core::GeolocationProvider::ErrorCallback on_error);
132+
void stop_watching_geolocation_position(Core::GeolocationProvider::WatchId);
133+
128134
ErrorOr<NonnullRefPtr<WebContentClient>> launch_web_content_process(ViewImplementation&);
129135
struct ChildFrameWebContentProcess {
130136
NonnullRefPtr<WebContentClient> client;
@@ -297,6 +303,7 @@ class WEBVIEW_API Application : public DevTools::DevToolsDelegate {
297303
ErrorOr<void> launch_image_decoder_server();
298304
ErrorOr<void> launch_devtools_server();
299305
ErrorOr<void> load_content_blocker_lists();
306+
ErrorOr<NonnullRawPtr<Core::GeolocationProvider>> ensure_geolocation_provider();
300307

301308
void initialize_actions();
302309
void update_vertical_tabs_action();
@@ -427,6 +434,7 @@ class WEBVIEW_API Application : public DevTools::DevToolsDelegate {
427434
OwnPtr<StorageJar> m_storage_jar;
428435
OwnPtr<PrivateBrowsingSession> m_private_browsing_session;
429436

437+
OwnPtr<Core::GeolocationProvider> m_geolocation_provider;
430438
OwnPtr<Core::TimeZoneWatcher> m_time_zone_watcher;
431439

432440
Core::EventLoop* m_event_loop { nullptr };

Libraries/LibWebView/ViewImplementation.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <LibURL/Parser.h>
2020
#include <LibWeb/CSS/SystemColor.h>
2121
#include <LibWeb/Crypto/Crypto.h>
22+
#include <LibWeb/Geolocation/GeolocationPositionError.h>
2223
#include <LibWeb/Infra/Strings.h>
2324
#include <LibWeb/WebDriver/Error.h>
2425
#include <LibWebView/Application.h>
@@ -85,6 +86,10 @@ ViewImplementation::ViewImplementation(IsPrivate is_private)
8586

8687
ViewImplementation::~ViewImplementation()
8788
{
89+
for (auto const& watch : m_geolocation_watch_ids)
90+
Application::the().stop_watching_geolocation_position(watch.value);
91+
m_geolocation_watch_ids.clear();
92+
8893
all_views().remove(m_view_id);
8994

9095
if (m_client_state.client)
@@ -1475,6 +1480,88 @@ void ViewImplementation::initialize_client(CreateNewClient create_new_client)
14751480
browsing_behavior_changed();
14761481
autoplay_settings_changed();
14771482
global_privacy_control_changed();
1483+
geolocation_settings_changed();
1484+
1485+
auto make_geolocation_success_handler = [this](u64 request_id) {
1486+
auto weak_this = make_weak_ptr();
1487+
auto request_page_id = page_id();
1488+
auto request_client_handle = m_client_state.client_handle;
1489+
1490+
return [weak_this, request_page_id, request_client_handle, request_id](Core::GeolocationCoordinates coords) {
1491+
auto* view = weak_this.ptr();
1492+
if (!view || !view->m_client_state.client || view->m_client_state.page_index != request_page_id || view->m_client_state.client_handle != request_client_handle)
1493+
return;
1494+
1495+
view->client().async_geolocation_position_response(request_page_id, request_id,
1496+
coords.latitude, coords.longitude, coords.accuracy,
1497+
coords.altitude, coords.altitude_accuracy,
1498+
coords.heading, coords.speed, {});
1499+
};
1500+
};
1501+
1502+
auto make_geolocation_error_handler = [this](u64 request_id, bool is_watch) {
1503+
using ErrorCode = Web::Geolocation::GeolocationPositionError::ErrorCode;
1504+
1505+
auto weak_this = make_weak_ptr();
1506+
auto request_page_id = page_id();
1507+
auto request_client_handle = m_client_state.client_handle;
1508+
1509+
return [weak_this, request_page_id, request_client_handle, request_id, is_watch](Core::GeolocationError error) {
1510+
auto* view = weak_this.ptr();
1511+
if (!view || !view->m_client_state.client || view->m_client_state.page_index != request_page_id || view->m_client_state.client_handle != request_client_handle)
1512+
return;
1513+
1514+
ErrorCode code;
1515+
switch (error.type) {
1516+
case Core::GeolocationError::Type::PermissionDenied:
1517+
code = ErrorCode::PermissionDenied;
1518+
break;
1519+
case Core::GeolocationError::Type::Timeout:
1520+
code = ErrorCode::Timeout;
1521+
break;
1522+
case Core::GeolocationError::Type::PositionUnavailable:
1523+
code = ErrorCode::PositionUnavailable;
1524+
break;
1525+
}
1526+
1527+
if (is_watch && code == ErrorCode::PermissionDenied) {
1528+
auto provider_watch_id = view->m_geolocation_watch_ids.take(request_id);
1529+
if (provider_watch_id.has_value())
1530+
Application::the().stop_watching_geolocation_position(*provider_watch_id);
1531+
}
1532+
1533+
view->client().async_geolocation_position_response(request_page_id, request_id,
1534+
{}, {}, {}, {}, {}, {}, {},
1535+
to_underlying(code));
1536+
};
1537+
};
1538+
1539+
on_request_geolocation_position = [make_geolocation_success_handler, make_geolocation_error_handler](u64 request_id) {
1540+
Application::the().request_geolocation_position(
1541+
make_geolocation_success_handler(request_id),
1542+
make_geolocation_error_handler(request_id, false));
1543+
};
1544+
1545+
on_start_geolocation_position_watch = [this, make_geolocation_success_handler, make_geolocation_error_handler](u64 request_id) {
1546+
auto provider_watch_id = Application::the().start_watching_geolocation_position(
1547+
make_geolocation_success_handler(request_id),
1548+
make_geolocation_error_handler(request_id, true));
1549+
1550+
if (provider_watch_id.is_error()) {
1551+
make_geolocation_error_handler(request_id, true)(provider_watch_id.release_error());
1552+
return;
1553+
}
1554+
1555+
m_geolocation_watch_ids.set(request_id, provider_watch_id.release_value());
1556+
};
1557+
1558+
on_stop_geolocation_position_watch = [this](u64 request_id) {
1559+
auto provider_watch_id = m_geolocation_watch_ids.take(request_id);
1560+
if (!provider_watch_id.has_value())
1561+
return;
1562+
1563+
Application::the().stop_watching_geolocation_position(*provider_watch_id);
1564+
};
14781565

14791566
// If DevTools is connected, notify the new WebContent process.
14801567
if (m_devtools_connected)
@@ -2115,7 +2202,25 @@ void ViewImplementation::geolocation_settings_changed()
21152202
{
21162203
using ErrorCode = Web::Geolocation::GeolocationPositionError::ErrorCode;
21172204

2205+
auto stop_native_position_watches = [this](Optional<ErrorCode> error_code) {
2206+
auto geolocation_watch_ids = move(m_geolocation_watch_ids);
2207+
m_geolocation_watch_ids.clear();
2208+
2209+
for (auto const& watch : geolocation_watch_ids) {
2210+
Application::the().stop_watching_geolocation_position(watch.value);
2211+
2212+
if (error_code.has_value()) {
2213+
client().async_geolocation_position_response(page_id(), watch.key,
2214+
{}, {}, {}, {}, {}, {}, {},
2215+
to_underlying(*error_code));
2216+
} else {
2217+
client().async_cancel_geolocation_position_request(page_id(), watch.key);
2218+
}
2219+
}
2220+
};
2221+
21182222
if (Application::web_content_options().is_test_mode == IsTestMode::Yes) {
2223+
stop_native_position_watches({});
21192224
client().async_set_geolocation_emulated_position(page_id(), 37.7647658, -122.4345892, 100.0, 0.0, 0.0, 0.0, 0.0, {});
21202225
return;
21212226
}
@@ -2124,9 +2229,11 @@ void ViewImplementation::geolocation_settings_changed()
21242229

21252230
switch (settings.geolocation_mode()) {
21262231
case GeolocationMode::Disabled:
2232+
stop_native_position_watches(ErrorCode::PermissionDenied);
21272233
client().async_set_geolocation_emulated_position(page_id(), {}, {}, {}, {}, {}, {}, {}, to_underlying(ErrorCode::PermissionDenied));
21282234
break;
21292235
case GeolocationMode::Emulated: {
2236+
stop_native_position_watches({});
21302237
auto const& coords = settings.emulated_geolocation_coordinates();
21312238
client().async_set_geolocation_emulated_position(page_id(), coords.latitude, coords.longitude, coords.accuracy, coords.altitude, coords.altitude_accuracy, coords.heading, coords.speed, {});
21322239
break;

Libraries/LibWebView/ViewImplementation.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <AK/Forward.h>
1111
#include <AK/Function.h>
12+
#include <AK/HashMap.h>
1213
#include <AK/JsonArray.h>
1314
#include <AK/JsonObject.h>
1415
#include <AK/JsonValue.h>
@@ -18,8 +19,10 @@
1819
#include <AK/String.h>
1920
#include <AK/Types.h>
2021
#include <AK/Utf16String.h>
22+
#include <AK/Weakable.h>
2123
#include <LibCore/AnonymousBuffer.h>
2224
#include <LibCore/Forward.h>
25+
#include <LibCore/GeolocationProvider.h>
2326
#include <LibCore/Promise.h>
2427
#include <LibCore/SharedVersion.h>
2528
#include <LibDevTools/DevToolsDelegate.h>
@@ -63,7 +66,8 @@ namespace WebView {
6366

6467
class WEBVIEW_API ViewImplementation
6568
: public SettingsObserver
66-
, public BookmarkStoreObserver {
69+
, public BookmarkStoreObserver
70+
, public Weakable<ViewImplementation> {
6771
friend class WebContentClient;
6872

6973
public:
@@ -365,6 +369,9 @@ class WEBVIEW_API ViewImplementation
365369
Function<void()> on_fullscreen_window;
366370
Function<void()> on_exit_fullscreen_window;
367371
Function<void(Color current_color)> on_request_color_picker;
372+
Function<void(u64 request_id)> on_request_geolocation_position;
373+
Function<void(u64 request_id)> on_start_geolocation_position_watch;
374+
Function<void(u64 request_id)> on_stop_geolocation_position_watch;
368375
Function<void(Web::HTML::FileFilter const& accepted_file_types, Web::HTML::AllowMultipleFiles)> on_request_file_picker;
369376
Function<void(Gfx::IntPoint content_position, i32 minimum_width, Vector<Web::HTML::SelectItem> items)> on_request_select_dropdown;
370377
Function<void(Web::KeyEvent const&)> on_finish_handling_key_event;
@@ -477,6 +484,7 @@ class WEBVIEW_API ViewImplementation
477484
virtual void browsing_behavior_changed() override;
478485
virtual void autoplay_settings_changed() override;
479486
virtual void global_privacy_control_changed() override;
487+
virtual void geolocation_settings_changed() override;
480488

481489
virtual void bookmarks_changed() override;
482490
void update_bookmark_action();
@@ -618,6 +626,8 @@ class WEBVIEW_API ViewImplementation
618626

619627
Web::ViewportIsFullscreen m_is_fullscreen { Web::ViewportIsFullscreen::No };
620628

629+
HashMap<u64, Core::GeolocationProvider::WatchId> m_geolocation_watch_ids;
630+
621631
Core::AnonymousBuffer m_document_cookie_version_buffer;
622632
HashMap<String, Core::SharedVersionIndex> m_document_cookie_version_indices;
623633
DevTools::DevToolsDelegate::OnHostCookieChange m_on_host_cookie_change;

Libraries/LibWebView/WebContentClient.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1707,6 +1707,30 @@ void WebContentClient::did_request_color_picker(u64 page_id, Color current_color
17071707
}
17081708
}
17091709

1710+
void WebContentClient::did_request_geolocation_position(u64 page_id, u64 request_id)
1711+
{
1712+
if (auto view = view_for_page_id(page_id); view.has_value()) {
1713+
if (view->on_request_geolocation_position)
1714+
view->on_request_geolocation_position(request_id);
1715+
}
1716+
}
1717+
1718+
void WebContentClient::did_start_geolocation_position_watch(u64 page_id, u64 request_id)
1719+
{
1720+
if (auto view = view_for_page_id(page_id); view.has_value()) {
1721+
if (view->on_start_geolocation_position_watch)
1722+
view->on_start_geolocation_position_watch(request_id);
1723+
}
1724+
}
1725+
1726+
void WebContentClient::did_stop_geolocation_position_watch(u64 page_id, u64 request_id)
1727+
{
1728+
if (auto view = view_for_page_id(page_id); view.has_value()) {
1729+
if (view->on_stop_geolocation_position_watch)
1730+
view->on_stop_geolocation_position_watch(request_id);
1731+
}
1732+
}
1733+
17101734
void WebContentClient::did_request_file_picker(u64 page_id, Web::HTML::FileFilter accepted_file_types, Web::HTML::AllowMultipleFiles allow_multiple_files)
17111735
{
17121736
if (auto view = view_for_page_id(page_id); view.has_value()) {

Libraries/LibWebView/WebContentClient.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ class WEBVIEW_API WebContentClient final
231231
virtual void did_request_exit_fullscreen(u64 page_id) override;
232232
virtual void did_request_file(u64 page_id, ByteString path, i32) override;
233233
virtual void did_request_color_picker(u64 page_id, Color current_color) override;
234+
virtual void did_request_geolocation_position(u64 page_id, u64 request_id) override;
235+
virtual void did_start_geolocation_position_watch(u64 page_id, u64 request_id) override;
236+
virtual void did_stop_geolocation_position_watch(u64 page_id, u64 request_id) override;
234237
virtual void did_request_file_picker(u64 page_id, Web::HTML::FileFilter accepted_file_types, Web::HTML::AllowMultipleFiles) override;
235238
virtual void did_request_select_dropdown(u64 page_id, Gfx::IntPoint content_position, i32 minimum_width, Vector<Web::HTML::SelectItem> items) override;
236239
virtual void did_finish_handling_input_event(u64 page_id, Web::EventResult event_result) override;

Services/WebContent/ConnectionFromClient.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,6 +2347,24 @@ void ConnectionFromClient::set_enable_global_privacy_control(u64, bool enable)
23472347
Web::ResourceLoader::the().set_enable_global_privacy_control(enable);
23482348
}
23492349

2350+
void ConnectionFromClient::set_geolocation_emulated_position(u64 page_id, Optional<double> latitude, Optional<double> longitude, Optional<double> accuracy, Optional<double> altitude, Optional<double> altitude_accuracy, Optional<double> heading, Optional<double> speed, Optional<u16> error_code)
2351+
{
2352+
if (auto page = this->page(page_id); page.has_value())
2353+
page->set_geolocation_emulated_position(latitude, longitude, accuracy, altitude, altitude_accuracy, heading, speed, error_code);
2354+
}
2355+
2356+
void ConnectionFromClient::cancel_geolocation_position_request(u64 page_id, u64 request_id)
2357+
{
2358+
if (auto page = this->page(page_id); page.has_value())
2359+
page->cancel_geolocation_position_request(request_id);
2360+
}
2361+
2362+
void ConnectionFromClient::geolocation_position_response(u64 page_id, u64 request_id, Optional<double> latitude, Optional<double> longitude, Optional<double> accuracy, Optional<double> altitude, Optional<double> altitude_accuracy, Optional<double> heading, Optional<double> speed, Optional<u16> error_code)
2363+
{
2364+
if (auto page = this->page(page_id); page.has_value())
2365+
page->geolocation_position_response(request_id, latitude, longitude, accuracy, altitude, altitude_accuracy, heading, speed, error_code);
2366+
}
2367+
23502368
void ConnectionFromClient::set_has_focus(u64 page_id, bool has_focus)
23512369
{
23522370
if (auto page = this->page(page_id); page.has_value())

Services/WebContent/ConnectionFromClient.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ class ConnectionFromClient final
163163
virtual void set_preferred_languages(u64 page_id, Vector<String>) override;
164164
virtual void set_browsing_behavior(u64 page_id, WebView::BrowsingBehavior) override;
165165
virtual void set_enable_global_privacy_control(u64 page_id, bool) override;
166+
virtual void set_geolocation_emulated_position(u64 page_id, Optional<double> latitude, Optional<double> longitude, Optional<double> accuracy, Optional<double> altitude, Optional<double> altitude_accuracy, Optional<double> heading, Optional<double> speed, Optional<u16> error_code) override;
167+
virtual void cancel_geolocation_position_request(u64 page_id, u64 request_id) override;
168+
virtual void geolocation_position_response(u64 page_id, u64 request_id, Optional<double> latitude, Optional<double> longitude, Optional<double> accuracy, Optional<double> altitude, Optional<double> altitude_accuracy, Optional<double> heading, Optional<double> speed, Optional<u16> error_code) override;
166169
virtual void set_has_focus(u64 page_id, bool) override;
167170
virtual void set_is_scripting_enabled(u64 page_id, bool) override;
168171
virtual void set_zoom_level(u64 page_id, double zoom_level) override;

0 commit comments

Comments
 (0)