WebKitGeolocationManager.cpp [plain text]
#include "config.h"
#include "WebKitGeolocationManager.h"
#include "APIGeolocationProvider.h"
#include "GeoclueGeolocationProvider.h"
#include "WebGeolocationPosition.h"
#include "WebKitGeolocationManagerPrivate.h"
#include <glib/gi18n-lib.h>
#include <wtf/WallTime.h>
#include <wtf/glib/WTFGType.h>
using namespace WebKit;
using namespace WebCore;
enum {
PROP_0,
PROP_ENABLE_HIGH_ACCURACY
};
enum {
START,
STOP,
LAST_SIGNAL
};
struct _WebKitGeolocationPosition {
_WebKitGeolocationPosition() = default;
_WebKitGeolocationPosition(double latitude, double longitude, double accuracy)
{
position.timestamp = WallTime::now().secondsSinceEpoch().value();
position.latitude = latitude;
position.longitude = longitude;
position.accuracy = accuracy;
}
explicit _WebKitGeolocationPosition(GeolocationPosition&& corePosition)
: position(WTFMove(corePosition))
{
}
explicit _WebKitGeolocationPosition(const GeolocationPosition& other)
{
position = other;
}
GeolocationPosition position;
};
G_DEFINE_BOXED_TYPE(WebKitGeolocationPosition, webkit_geolocation_position, webkit_geolocation_position_copy, webkit_geolocation_position_free)
WebKitGeolocationPosition* webkit_geolocation_position_new(double latitude, double longitude, double accuracy)
{
auto* position = static_cast<WebKitGeolocationPosition*>(fastMalloc(sizeof(WebKitGeolocationPosition)));
new (position) WebKitGeolocationPosition(latitude, longitude, accuracy);
return position;
}
WebKitGeolocationPosition* webkit_geolocation_position_copy(WebKitGeolocationPosition* position)
{
g_return_val_if_fail(position, nullptr);
auto* copy = static_cast<WebKitGeolocationPosition*>(fastMalloc(sizeof(WebKitGeolocationPosition)));
new (copy) WebKitGeolocationPosition(position->position);
return copy;
}
void webkit_geolocation_position_free(WebKitGeolocationPosition* position)
{
g_return_if_fail(position);
position->~WebKitGeolocationPosition();
fastFree(position);
}
void webkit_geolocation_position_set_timestamp(WebKitGeolocationPosition* position, guint64 timestamp)
{
g_return_if_fail(position);
position->position.timestamp = timestamp ? static_cast<double>(timestamp) : WallTime::now().secondsSinceEpoch().value();
}
void webkit_geolocation_position_set_altitude(WebKitGeolocationPosition* position, double altitude)
{
g_return_if_fail(position);
position->position.altitude = altitude;
}
void webkit_geolocation_position_set_altitude_accuracy(WebKitGeolocationPosition* position, double altitudeAccuracy)
{
g_return_if_fail(position);
position->position.altitudeAccuracy = altitudeAccuracy;
}
void webkit_geolocation_position_set_heading(WebKitGeolocationPosition* position, double heading)
{
g_return_if_fail(position);
position->position.heading = heading;
}
void webkit_geolocation_position_set_speed(WebKitGeolocationPosition* position, double speed)
{
g_return_if_fail(position);
position->position.speed = speed;
}
struct _WebKitGeolocationManagerPrivate {
RefPtr<WebGeolocationManagerProxy> manager;
bool highAccuracyEnabled;
std::unique_ptr<GeoclueGeolocationProvider> geoclueProvider;
};
static guint signals[LAST_SIGNAL] = { 0, };
WEBKIT_DEFINE_TYPE(WebKitGeolocationManager, webkit_geolocation_manager, G_TYPE_OBJECT)
static void webkitGeolocationManagerStart(WebKitGeolocationManager* manager)
{
gboolean returnValue;
g_signal_emit(manager, signals[START], 0, &returnValue);
if (returnValue) {
manager->priv->geoclueProvider = nullptr;
return;
}
if (!manager->priv->geoclueProvider) {
manager->priv->geoclueProvider = std::make_unique<GeoclueGeolocationProvider>();
manager->priv->geoclueProvider->setEnableHighAccuracy(manager->priv->highAccuracyEnabled);
}
manager->priv->geoclueProvider->start([manager](GeolocationPosition&& corePosition, Optional<CString> error) {
if (error) {
webkit_geolocation_manager_failed(manager, error->data());
return;
}
WebKitGeolocationPosition position(WTFMove(corePosition));
webkit_geolocation_manager_update_position(manager, &position);
});
}
static void webkitGeolocationManagerStop(WebKitGeolocationManager* manager)
{
g_signal_emit(manager, signals[STOP], 0, nullptr);
if (manager->priv->geoclueProvider)
manager->priv->geoclueProvider->stop();
}
static void webkitGeolocationManagerSetEnableHighAccuracy(WebKitGeolocationManager* manager, bool enabled)
{
if (manager->priv->highAccuracyEnabled == enabled)
return;
manager->priv->highAccuracyEnabled = enabled;
g_object_notify(G_OBJECT(manager), "enable-high-accuracy");
if (manager->priv->geoclueProvider)
manager->priv->geoclueProvider->setEnableHighAccuracy(enabled);
}
class GeolocationProvider final : public API::GeolocationProvider {
public:
explicit GeolocationProvider(WebKitGeolocationManager* manager)
: m_manager(manager)
{
}
private:
void startUpdating(WebGeolocationManagerProxy&) override
{
webkitGeolocationManagerStart(m_manager);
}
void stopUpdating(WebGeolocationManagerProxy&) override
{
webkitGeolocationManagerStop(m_manager);
}
void setEnableHighAccuracy(WebGeolocationManagerProxy&, bool enabled) override
{
webkitGeolocationManagerSetEnableHighAccuracy(m_manager, enabled);
}
WebKitGeolocationManager* m_manager;
};
WebKitGeolocationManager* webkitGeolocationManagerCreate(WebGeolocationManagerProxy* proxy)
{
auto* manager = WEBKIT_GEOLOCATION_MANAGER(g_object_new(WEBKIT_TYPE_GEOLOCATION_MANAGER, nullptr));
manager->priv->manager = proxy;
proxy->setProvider(std::make_unique<GeolocationProvider>(manager));
return manager;
}
static void webkitGeolocationManagerGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
{
WebKitGeolocationManager* manager = WEBKIT_GEOLOCATION_MANAGER(object);
switch (propId) {
case PROP_ENABLE_HIGH_ACCURACY:
g_value_set_boolean(value, webkit_geolocation_manager_get_enable_high_accuracy(manager));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
}
}
static void webkit_geolocation_manager_class_init(WebKitGeolocationManagerClass* geolocationManagerClass)
{
GObjectClass* gObjectClass = G_OBJECT_CLASS(geolocationManagerClass);
gObjectClass->get_property = webkitGeolocationManagerGetProperty;
g_object_class_install_property(
gObjectClass,
PROP_ENABLE_HIGH_ACCURACY,
g_param_spec_boolean(
"enable-high-accuracy",
_("Enable high accuracy"),
_("Whether high accuracy is enabled"),
FALSE,
WEBKIT_PARAM_READABLE));
signals[START] = g_signal_new(
"start",
G_TYPE_FROM_CLASS(geolocationManagerClass),
G_SIGNAL_RUN_LAST,
0,
g_signal_accumulator_true_handled, nullptr,
g_cclosure_marshal_generic,
G_TYPE_BOOLEAN, 0);
signals[STOP] = g_signal_new(
"stop",
G_TYPE_FROM_CLASS(geolocationManagerClass),
G_SIGNAL_RUN_LAST,
0,
nullptr, nullptr,
g_cclosure_marshal_generic,
G_TYPE_NONE, 0);
}
void webkit_geolocation_manager_update_position(WebKitGeolocationManager* manager, WebKitGeolocationPosition* position)
{
g_return_if_fail(WEBKIT_IS_GEOLOCATION_MANAGER(manager));
g_return_if_fail(position);
GeolocationPosition corePosition = position->position;
auto wkPosition = WebGeolocationPosition::create(WTFMove(corePosition));
manager->priv->manager->providerDidChangePosition(wkPosition.ptr());
}
void webkit_geolocation_manager_failed(WebKitGeolocationManager* manager, const char* errorMessage)
{
g_return_if_fail(WEBKIT_IS_GEOLOCATION_MANAGER(manager));
manager->priv->manager->providerDidFailToDeterminePosition(String::fromUTF8(errorMessage));
}
gboolean webkit_geolocation_manager_get_enable_high_accuracy(WebKitGeolocationManager* manager)
{
g_return_val_if_fail(WEBKIT_IS_GEOLOCATION_MANAGER(manager), FALSE);
return manager->priv->highAccuracyEnabled;
}