WebKitDownload.cpp [plain text]
#include "config.h"
#include "WebKitDownload.h"
#include "WebKitDownloadPrivate.h"
#include "WebKitMarshal.h"
#include "WebKitURIResponsePrivate.h"
#include <WebCore/ErrorsGtk.h>
#include <WebCore/ResourceResponse.h>
#include <glib/gi18n-lib.h>
#include <wtf/gobject/GOwnPtr.h>
#include <wtf/gobject/GRefPtr.h>
using namespace WebKit;
using namespace WebCore;
enum {
RECEIVED_DATA,
FINISHED,
FAILED,
DECIDE_DESTINATION,
CREATED_DESTINATION,
LAST_SIGNAL
};
enum {
PROP_0,
PROP_DESTINATION,
PROP_RESPONSE,
PROP_ESTIMATED_PROGRESS
};
struct _WebKitDownloadPrivate {
WKRetainPtr<WKDownloadRef> wkDownload;
GRefPtr<WebKitURIResponse> response;
CString destinationURI;
guint64 currentSize;
bool isCancelled;
GOwnPtr<GTimer> timer;
gdouble lastProgress;
gdouble lastElapsed;
};
static guint signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE(WebKitDownload, webkit_download, G_TYPE_OBJECT)
static void webkitDownloadFinalize(GObject* object)
{
WEBKIT_DOWNLOAD(object)->priv->~WebKitDownloadPrivate();
G_OBJECT_CLASS(webkit_download_parent_class)->finalize(object);
}
static void webkitDownloadGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
{
WebKitDownload* download = WEBKIT_DOWNLOAD(object);
switch (propId) {
case PROP_DESTINATION:
g_value_set_string(value, webkit_download_get_destination(download));
break;
case PROP_RESPONSE:
g_value_set_object(value, webkit_download_get_response(download));
break;
case PROP_ESTIMATED_PROGRESS:
g_value_set_double(value, webkit_download_get_estimated_progress(download));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
}
}
static gboolean webkitDownloadDecideDestination(WebKitDownload* download, const gchar* suggestedFilename)
{
if (!download->priv->destinationURI.isNull())
return FALSE;
GOwnPtr<char> destination(g_build_filename(g_get_user_special_dir(G_USER_DIRECTORY_DOWNLOAD), suggestedFilename, NULL));
GOwnPtr<char> destinationURI(g_filename_to_uri(destination.get(), 0, 0));
download->priv->destinationURI = destinationURI.get();
g_object_notify(G_OBJECT(download), "destination");
return TRUE;
}
static void webkit_download_init(WebKitDownload* download)
{
WebKitDownloadPrivate* priv = G_TYPE_INSTANCE_GET_PRIVATE(download, WEBKIT_TYPE_DOWNLOAD, WebKitDownloadPrivate);
download->priv = priv;
new (priv) WebKitDownloadPrivate();
}
static void webkit_download_class_init(WebKitDownloadClass* downloadClass)
{
GObjectClass* objectClass = G_OBJECT_CLASS(downloadClass);
objectClass->get_property = webkitDownloadGetProperty;
objectClass->finalize = webkitDownloadFinalize;
downloadClass->decide_destination = webkitDownloadDecideDestination;
g_object_class_install_property(objectClass,
PROP_DESTINATION,
g_param_spec_string("destination",
_("Destination"),
_("The local URI to where the download will be saved"),
0,
WEBKIT_PARAM_READABLE));
g_object_class_install_property(objectClass,
PROP_RESPONSE,
g_param_spec_object("response",
_("Response"),
_("The response of the download"),
WEBKIT_TYPE_URI_RESPONSE,
WEBKIT_PARAM_READABLE));
g_object_class_install_property(objectClass,
PROP_ESTIMATED_PROGRESS,
g_param_spec_double("estimated-progress",
_("Estimated Progress"),
_("Determines the current progress of the download"),
0.0, 1.0, 1.0,
WEBKIT_PARAM_READABLE));
signals[RECEIVED_DATA] =
g_signal_new("received-data",
G_TYPE_FROM_CLASS(objectClass),
G_SIGNAL_RUN_LAST,
0, 0, 0,
webkit_marshal_VOID__UINT64,
G_TYPE_NONE, 1,
G_TYPE_UINT64);
signals[FINISHED] =
g_signal_new("finished",
G_TYPE_FROM_CLASS(objectClass),
G_SIGNAL_RUN_LAST,
0, 0, 0,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[FAILED] =
g_signal_new("failed",
G_TYPE_FROM_CLASS(objectClass),
G_SIGNAL_RUN_LAST,
0, 0, 0,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1,
G_TYPE_POINTER);
signals[DECIDE_DESTINATION] =
g_signal_new("decide-destination",
G_TYPE_FROM_CLASS(objectClass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(WebKitDownloadClass, decide_destination),
g_signal_accumulator_true_handled, NULL,
webkit_marshal_BOOLEAN__STRING,
G_TYPE_BOOLEAN, 1,
G_TYPE_STRING);
signals[CREATED_DESTINATION] =
g_signal_new("created-destination",
G_TYPE_FROM_CLASS(objectClass),
G_SIGNAL_RUN_LAST,
0, 0, 0,
g_cclosure_marshal_VOID__STRING,
G_TYPE_BOOLEAN, 1,
G_TYPE_STRING);
g_type_class_add_private(downloadClass, sizeof(WebKitDownloadPrivate));
}
WebKitDownload* webkitDownloadCreate(WKDownloadRef wkDownload)
{
ASSERT(wkDownload);
WebKitDownload* download = WEBKIT_DOWNLOAD(g_object_new(WEBKIT_TYPE_DOWNLOAD, NULL));
download->priv->wkDownload = wkDownload;
return download;
}
void webkitDownloadSetResponse(WebKitDownload* download, WebKitURIResponse* response)
{
download->priv->response = response;
g_object_notify(G_OBJECT(download), "response");
}
bool webkitDownloadIsCancelled(WebKitDownload* download)
{
return download->priv->isCancelled;
}
void webkitDownloadNotifyProgress(WebKitDownload* download, guint64 bytesReceived)
{
WebKitDownloadPrivate* priv = download->priv;
if (priv->isCancelled)
return;
if (!download->priv->timer)
download->priv->timer.set(g_timer_new());
priv->currentSize += bytesReceived;
g_signal_emit(download, signals[RECEIVED_DATA], 0, bytesReceived);
gdouble currentElapsed = g_timer_elapsed(priv->timer.get(), 0);
gdouble currentProgress = webkit_download_get_estimated_progress(download);
if (priv->lastElapsed
&& priv->lastProgress
&& (currentElapsed - priv->lastElapsed) < 0.016
&& (currentProgress - priv->lastProgress) < 0.01
&& currentProgress < 1.0) {
return;
}
priv->lastElapsed = currentElapsed;
priv->lastProgress = currentProgress;
g_object_notify(G_OBJECT(download), "estimated-progress");
}
void webkitDownloadFailed(WebKitDownload* download, const ResourceError& resourceError)
{
GOwnPtr<GError> webError(g_error_new_literal(g_quark_from_string(resourceError.domain().utf8().data()),
resourceError.errorCode(),
resourceError.localizedDescription().utf8().data()));
if (download->priv->timer)
g_timer_stop(download->priv->timer.get());
g_signal_emit(download, signals[FAILED], 0, webError.get());
g_signal_emit(download, signals[FINISHED], 0, NULL);
}
void webkitDownloadCancelled(WebKitDownload* download)
{
WebKitDownloadPrivate* priv = download->priv;
webkitDownloadFailed(download, downloadCancelledByUserError(priv->response ? webkitURIResponseGetResourceResponse(priv->response.get()) : ResourceResponse()));
}
void webkitDownloadFinished(WebKitDownload* download)
{
if (download->priv->isCancelled) {
webkitDownloadCancelled(download);
return;
}
if (download->priv->timer)
g_timer_stop(download->priv->timer.get());
g_signal_emit(download, signals[FINISHED], 0, NULL);
}
CString webkitDownloadDecideDestinationWithSuggestedFilename(WebKitDownload* download, const CString& suggestedFilename)
{
if (download->priv->isCancelled)
return "";
gboolean returnValue;
g_signal_emit(download, signals[DECIDE_DESTINATION], 0, suggestedFilename.data(), &returnValue);
return download->priv->destinationURI;
}
void webkitDownloadDestinationCreated(WebKitDownload* download, const CString& destinationURI)
{
if (download->priv->isCancelled)
return;
gboolean returnValue;
g_signal_emit(download, signals[CREATED_DESTINATION], 0, destinationURI.data(), &returnValue);
}
const gchar* webkit_download_get_destination(WebKitDownload* download)
{
g_return_val_if_fail(WEBKIT_IS_DOWNLOAD(download), 0);
return download->priv->destinationURI.data();
}
void webkit_download_set_destination(WebKitDownload* download, const gchar* uri)
{
g_return_if_fail(WEBKIT_IS_DOWNLOAD(download));
g_return_if_fail(uri);
WebKitDownloadPrivate* priv = download->priv;
if (priv->destinationURI == uri)
return;
priv->destinationURI = uri;
g_object_notify(G_OBJECT(download), "destination");
}
WebKitURIResponse* webkit_download_get_response(WebKitDownload* download)
{
g_return_val_if_fail(WEBKIT_IS_DOWNLOAD(download), 0);
return download->priv->response.get();
}
void webkit_download_cancel(WebKitDownload* download)
{
g_return_if_fail(WEBKIT_IS_DOWNLOAD(download));
download->priv->isCancelled = true;
WKDownloadCancel(download->priv->wkDownload.get());
}
gdouble webkit_download_get_estimated_progress(WebKitDownload* download)
{
g_return_val_if_fail(WEBKIT_IS_DOWNLOAD(download), 0);
WebKitDownloadPrivate* priv = download->priv;
if (!priv->response)
return 0;
guint64 contentLength = webkit_uri_response_get_content_length(priv->response.get());
if (!contentLength)
return 0;
return static_cast<gdouble>(priv->currentSize) / static_cast<gdouble>(contentLength);
}
gdouble webkit_download_get_elapsed_time(WebKitDownload* download)
{
g_return_val_if_fail(WEBKIT_IS_DOWNLOAD(download), 0);
WebKitDownloadPrivate* priv = download->priv;
if (!priv->timer)
return 0;
return g_timer_elapsed(priv->timer.get(), 0);
}