aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/ephy-web-app-utils.c228
-rw-r--r--lib/ephy-web-app-utils.h10
-rw-r--r--src/window-commands.c196
3 files changed, 402 insertions, 32 deletions
diff --git a/lib/ephy-web-app-utils.c b/lib/ephy-web-app-utils.c
index 1bd1a2f8d..203a771f8 100644
--- a/lib/ephy-web-app-utils.c
+++ b/lib/ephy-web-app-utils.c
@@ -35,6 +35,234 @@
#define EPHY_WEB_APP_DESKTOP_FILE_PREFIX "epiphany-"
+static char *
+resolve_uri (WebKitWebView *view,
+ const char *uri)
+{
+ SoupURI *base;
+ SoupURI *new;
+ const char *base_uri;
+ char *ret;
+
+ if (uri == NULL)
+ return NULL;
+
+ base_uri = webkit_web_view_get_uri (view);
+ if (base_uri == NULL)
+ return NULL;
+
+ base = soup_uri_new (base_uri);
+ new = soup_uri_new_with_base (base, uri);
+ soup_uri_free (base);
+ ret = soup_uri_to_string (new, FALSE);
+ soup_uri_free (new);
+
+ return ret;
+}
+
+#ifdef HAVE_WEBKIT2
+/* TODO: DOM Bindindgs */
+#else
+static gboolean
+get_icon_from_mstile (WebKitWebView *view,
+ char **uri_out,
+ char **color_out)
+{
+ gboolean ret;
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *metas;
+ gulong length, i;
+ char *image = NULL;
+ char *color = NULL;
+
+ document = webkit_web_view_get_dom_document (view);
+ metas = webkit_dom_document_get_elements_by_tag_name (document, "meta");
+ length = webkit_dom_node_list_get_length (metas);
+
+ for (i = 0; i < length; i++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (metas, i);
+ char *name;
+
+ name = webkit_dom_html_meta_element_get_name (WEBKIT_DOM_HTML_META_ELEMENT (node));
+ if (g_strcmp0 (name, "msapplication-TileImage") == 0) {
+ if (image == NULL)
+ image = webkit_dom_html_meta_element_get_content (WEBKIT_DOM_HTML_META_ELEMENT (node));
+ } else if (g_strcmp0 (name, "msapplication-TileColor") == 0) {
+ if (color == NULL)
+ color = webkit_dom_html_meta_element_get_content (WEBKIT_DOM_HTML_META_ELEMENT (node));
+ }
+ }
+
+ ret = (image != NULL && *image != '\0');
+
+ if (uri_out != NULL)
+ *uri_out = g_strdup (image);
+ if (color_out != NULL)
+ *color_out = g_strdup (color);
+
+ g_free (image);
+ g_free (color);
+
+ return ret;
+}
+
+static gboolean
+get_icon_from_ogp (WebKitWebView *view,
+ char **uri_out,
+ char **color_out)
+{
+ gboolean ret;
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *metas;
+ gulong length, i;
+ char *image = NULL;
+ char *color = NULL;
+
+ document = webkit_web_view_get_dom_document (view);
+ metas = webkit_dom_document_get_elements_by_tag_name (document, "meta");
+ length = webkit_dom_node_list_get_length (metas);
+
+ for (i = 0; i < length && image == NULL; i++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (metas, i);
+ char *property;
+ char *itemprop;
+
+ property = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "property");
+ itemprop = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "itemprop");
+ if (g_strcmp0 (property, "og:image") == 0 ||
+ g_strcmp0 (itemprop, "image") == 0) {
+ image = webkit_dom_html_meta_element_get_content (WEBKIT_DOM_HTML_META_ELEMENT (node));
+ }
+ g_free (property);
+ g_free (itemprop);
+ }
+
+ ret = (image != NULL && *image != '\0');
+
+ if (uri_out != NULL)
+ *uri_out = g_strdup (image);
+ if (color_out != NULL)
+ *color_out = g_strdup (color);
+
+ return ret;
+}
+
+static gboolean
+get_icon_from_touch_icon (WebKitWebView *view,
+ char **uri_out,
+ char **color_out)
+{
+ gboolean ret;
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *links;
+ gulong length, i;
+ char *image = NULL;
+ char *color = NULL;
+
+ document = webkit_web_view_get_dom_document (view);
+ links = webkit_dom_document_get_elements_by_tag_name (document, "link");
+ length = webkit_dom_node_list_get_length (links);
+
+ for (i = 0; i < length && image == NULL; i++) {
+ char *rel;
+ WebKitDOMNode *node = webkit_dom_node_list_item (links, i);
+
+ rel = webkit_dom_html_link_element_get_rel (WEBKIT_DOM_HTML_LINK_ELEMENT (node));
+ /* TODO: support more than one possible icon. */
+ if (g_strcmp0 (rel, "apple-touch-icon") == 0 ||
+ g_strcmp0 (rel, "apple-touch-icon-precomposed") == 0) {
+ image = webkit_dom_html_link_element_get_href (WEBKIT_DOM_HTML_LINK_ELEMENT (node));
+ }
+ g_free (rel);
+ }
+
+ ret = (image != NULL && *image != '\0');
+
+ if (uri_out != NULL)
+ *uri_out = g_strdup (image);
+ if (color_out != NULL)
+ *color_out = g_strdup (color);
+
+ return ret;
+}
+
+static gboolean
+get_icon_from_favicon (WebKitWebView *view,
+ char **uri_out,
+ char **color_out)
+{
+ gboolean ret;
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *links;
+ gulong length, i;
+ char *image = NULL;
+ char *color = NULL;
+
+ document = webkit_web_view_get_dom_document (view);
+ links = webkit_dom_document_get_elements_by_tag_name (document, "link");
+ length = webkit_dom_node_list_get_length (links);
+
+ for (i = 0; i < length; i++) {
+ char *rel;
+ WebKitDOMNode *node = webkit_dom_node_list_item (links, i);
+
+ rel = webkit_dom_html_link_element_get_rel (WEBKIT_DOM_HTML_LINK_ELEMENT (node));
+ if (g_strcmp0 (rel, "shortcut-icon") == 0 ||
+ g_strcmp0 (rel, "shortcut icon") == 0 ||
+ g_strcmp0 (rel, "icon shortcut") == 0 ||
+ g_strcmp0 (rel, "icon") == 0) {
+ image = webkit_dom_html_link_element_get_href (WEBKIT_DOM_HTML_LINK_ELEMENT (node));
+ }
+ g_free (rel);
+ }
+
+ ret = (image != NULL && *image != '\0');
+
+ if (uri_out != NULL)
+ *uri_out = g_strdup (image);
+ if (color_out != NULL)
+ *color_out = g_strdup (color);
+
+ return ret;
+}
+#endif /* HAVE_WEBKIT2 */
+
+gboolean
+ephy_web_view_get_best_icon (WebKitWebView *view,
+ char **uri,
+ GdkRGBA *rgba)
+{
+ gboolean ret = FALSE;
+ char *image = NULL;
+ char *color = NULL;
+
+#ifdef HAVE_WEBKIT2
+ /* TODO: DOM Bindindgs */
+#else
+
+ /* First try to get a mstile, then try OGP, then favicon */
+
+ ret = get_icon_from_mstile (view, &image, &color);
+ if (! ret)
+ ret = get_icon_from_ogp (view, &image, &color);
+ if (! ret)
+ ret = get_icon_from_touch_icon (view, &image, &color);
+ if (! ret)
+ ret = get_icon_from_favicon (view, &image, &color);
+
+#endif
+
+ if (uri != NULL)
+ *uri = resolve_uri (view, image);
+ if (rgba != NULL && color != NULL)
+ gdk_rgba_parse (rgba, color);
+
+ g_free (image);
+ g_free (color);
+
+ return ret;
+}
+
/* This is necessary because of gnome-shell's guessing of a .desktop
filename from WM_CLASS property. */
static char *
diff --git a/lib/ephy-web-app-utils.h b/lib/ephy-web-app-utils.h
index 54968df80..adb254e5f 100644
--- a/lib/ephy-web-app-utils.h
+++ b/lib/ephy-web-app-utils.h
@@ -27,6 +27,12 @@
#include <glib.h>
#include <gtk/gtk.h>
+#ifdef HAVE_WEBKIT2
+#include <webkit2/webkit2.h>
+#else
+#include <webkit/webkit.h>
+#endif
+
G_BEGIN_DECLS
typedef struct {
@@ -52,6 +58,10 @@ void ephy_web_application_free_application_list (GList *list);
gboolean ephy_web_application_exists (const char *name);
+gboolean ephy_web_view_get_best_icon (WebKitWebView *view,
+ char **uri,
+ GdkRGBA *rgba);
+
G_END_DECLS
#endif
diff --git a/src/window-commands.c b/src/window-commands.c
index bd6902f85..da9393476 100644
--- a/src/window-commands.c
+++ b/src/window-commands.c
@@ -65,6 +65,8 @@
#include <webkit/webkit.h>
#endif
+#define DEFAULT_ICON_SIZE 144
+
void
window_cmd_file_print (GtkAction *action,
EphyWindow *window)
@@ -370,6 +372,7 @@ typedef struct {
GtkWidget *spinner;
GtkWidget *box;
char *icon_href;
+ GdkRGBA icon_rgba;
} EphyApplicationDialogData;
static void
@@ -380,18 +383,154 @@ ephy_application_dialog_data_free (EphyApplicationDialogData *data)
}
static void
+rounded_rectangle (cairo_t *cr,
+ gdouble aspect,
+ gdouble x,
+ gdouble y,
+ gdouble corner_radius,
+ gdouble width,
+ gdouble height)
+{
+ gdouble radius;
+ gdouble degrees;
+
+ radius = corner_radius / aspect;
+ degrees = G_PI / 180.0;
+
+ cairo_new_sub_path (cr);
+ cairo_arc (cr,
+ x + width - radius,
+ y + radius,
+ radius,
+ -90 * degrees,
+ 0 * degrees);
+ cairo_arc (cr,
+ x + width - radius,
+ y + height - radius,
+ radius,
+ 0 * degrees,
+ 90 * degrees);
+ cairo_arc (cr,
+ x + radius,
+ y + height - radius,
+ radius,
+ 90 * degrees,
+ 180 * degrees);
+ cairo_arc (cr,
+ x + radius,
+ y + radius,
+ radius,
+ 180 * degrees,
+ 270 * degrees);
+ cairo_close_path (cr);
+}
+
+static GdkPixbuf *
+frame_pixbuf (GdkPixbuf *pixbuf,
+ GdkRGBA *rgba,
+ int width,
+ int height)
+{
+ GdkPixbuf *framed;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ int frame_width;
+ int radius;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ width, height);
+ cr = cairo_create (surface);
+
+ frame_width = 0;
+ radius = 20;
+
+ rounded_rectangle (cr,
+ 1.0,
+ frame_width + 0.5,
+ frame_width + 0.5,
+ radius,
+ width - frame_width * 2 - 1,
+ height - frame_width * 2 - 1);
+ if (rgba != NULL)
+ cairo_set_source_rgba (cr,
+ rgba->red,
+ rgba->green,
+ rgba->blue,
+ rgba->alpha);
+ else
+ cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.3);
+ cairo_fill_preserve (cr);
+
+ if (pixbuf != NULL) {
+ GdkPixbuf *scaled;
+ int w;
+ int h;
+
+ w = gdk_pixbuf_get_width (pixbuf);
+ h = gdk_pixbuf_get_height (pixbuf);
+
+ if (w < 48 || h < 48) {
+ scaled = gdk_pixbuf_scale_simple (pixbuf, w * 3, h * 3, GDK_INTERP_NEAREST);
+ } else if (w > width || h > height) {
+ double ws, hs, s;
+
+ ws = (double) width / w;
+ hs = (double) height / h;
+ s = MIN (ws, hs);
+ scaled = gdk_pixbuf_scale_simple (pixbuf, w * s, h * s, GDK_INTERP_BILINEAR);
+ } else {
+ scaled = g_object_ref (pixbuf);
+ }
+
+ w = gdk_pixbuf_get_width (scaled);
+ h = gdk_pixbuf_get_height (scaled);
+
+ gdk_cairo_set_source_pixbuf (cr, scaled,
+ (width - w) / 2,
+ (height - h) / 2);
+ g_object_unref (scaled);
+ cairo_fill (cr);
+ }
+
+ framed = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height);
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ return framed;
+}
+
+static void
take_page_snapshot_and_set_image (EphyApplicationDialogData *data)
{
GdkPixbuf *snapshot;
+ GdkPixbuf *framed;
int x, y, w, h;
x = y = 0;
- w = h = 128; /* GNOME hi-res icon size. */
+ w = h = DEFAULT_ICON_SIZE;
snapshot = ephy_web_view_get_snapshot (data->view, x, y, w, h);
-
- gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), snapshot);
+ framed = frame_pixbuf (snapshot, NULL, w, h);
g_object_unref (snapshot);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), framed);
+ g_object_unref (framed);
+}
+
+static void
+set_app_icon_from_filename (EphyApplicationDialogData *data,
+ const char *filename)
+{
+ GdkPixbuf *pixbuf;
+ GdkPixbuf *framed;
+
+ pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+ if (pixbuf == NULL)
+ return;
+
+ framed = frame_pixbuf (pixbuf, &data->icon_rgba, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE);
+ g_object_unref (pixbuf);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), framed);
+ g_object_unref (framed);
}
#ifdef HAVE_WEBKIT2
@@ -402,7 +541,7 @@ download_finished_cb (WebKitDownload *download,
char *filename;
filename = g_filename_from_uri (webkit_download_get_destination (download), NULL, NULL);
- gtk_image_set_from_file (GTK_IMAGE (data->image), filename);
+ set_app_icon_from_filename (data, filename);
g_free (filename);
}
@@ -429,7 +568,7 @@ download_status_changed_cb (WebKitDownload *download,
case WEBKIT_DOWNLOAD_STATUS_FINISHED:
filename = g_filename_from_uri (webkit_download_get_destination_uri (download),
NULL, NULL);
- gtk_image_set_from_file (GTK_IMAGE (data->image), filename);
+ set_app_icon_from_filename (data, filename);
g_free (filename);
break;
case WEBKIT_DOWNLOAD_STATUS_ERROR:
@@ -486,39 +625,28 @@ download_icon_and_set_image (EphyApplicationDialogData *data)
#endif
}
+
static void
fill_default_application_image (EphyApplicationDialogData *data)
{
-#ifdef HAVE_WEBKIT2
- /* TODO: DOM Bindindgs */
-#else
- WebKitDOMDocument *document;
- WebKitDOMNodeList *links;
- gulong length, i;
+ gboolean res;
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (data->view));
- links = webkit_dom_document_get_elements_by_tag_name (document, "link");
- length = webkit_dom_node_list_get_length (links);
+ data->icon_rgba.red = 0.5;
+ data->icon_rgba.green = 0.5;
+ data->icon_rgba.blue = 0.5;
+ data->icon_rgba.alpha = 0.3;
- for (i = 0; i < length; i++)
+ res = ephy_web_view_get_best_icon (WEBKIT_WEB_VIEW (data->view),
+ &data->icon_href,
+ &data->icon_rgba);
+ if (res)
{
- char *rel;
- WebKitDOMNode *node = webkit_dom_node_list_item (links, i);
- rel = webkit_dom_html_link_element_get_rel (WEBKIT_DOM_HTML_LINK_ELEMENT (node));
- /* TODO: support more than one possible icon. */
- if (g_strcmp0 (rel, "apple-touch-icon") == 0 ||
- g_strcmp0 (rel, "apple-touch-icon-precomposed") == 0)
- {
- data->icon_href = webkit_dom_html_link_element_get_href (WEBKIT_DOM_HTML_LINK_ELEMENT (node));
- download_icon_and_set_image (data);
- g_free (rel);
- return;
- }
+ download_icon_and_set_image (data);
+ }
+ else
+ {
+ take_page_snapshot_and_set_image (data);
}
-#endif
- /* If we make it here, no "apple-touch-icon" link was
- * found. Take a snapshot of the page. */
- take_page_snapshot_and_set_image (data);
}
typedef struct {
@@ -718,6 +846,7 @@ window_cmd_file_save_as_application (GtkAction *action,
GtkWidget *dialog, *box, *image, *entry, *content_area;
EphyWebView *view;
EphyApplicationDialogData *data;
+ GdkPixbuf *pixbuf;
embed = ephy_embed_container_get_active_child (EPHY_EMBED_CONTAINER (window));
g_return_if_fail (embed != NULL);
@@ -742,8 +871,11 @@ window_cmd_file_save_as_application (GtkAction *action,
gtk_container_add (GTK_CONTAINER (content_area), box);
image = gtk_image_new ();
- gtk_widget_set_size_request (image, 128, 128);
+ gtk_widget_set_size_request (image, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE);
gtk_container_add (GTK_CONTAINER (box), image);
+ pixbuf = frame_pixbuf (NULL, NULL, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
+ g_object_unref (pixbuf);
entry = gtk_entry_new ();
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);