summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Sanders <vince@netsurf-browser.org>2011-12-30 00:58:35 +0000
committerVincent Sanders <vince@netsurf-browser.org>2011-12-30 00:58:35 +0000
commitdf18a971435c35963bb8ea94efc0d5326ad66ff0 (patch)
tree0f0ccea83c6f4cd82d7195478d7bd35f7ae89e31
parent4dd695c156879ad845a33ad8ef9748b0f54a4f1a (diff)
downloadnetsurf-df18a971435c35963bb8ea94efc0d5326ad66ff0.tar.gz
netsurf-df18a971435c35963bb8ea94efc0d5326ad66ff0.tar.bz2
Change GTK plotting to use cairo surfaces throughout
svn path=/trunk/netsurf/; revision=13354
-rw-r--r--Docs/BUILDING-GTK2
-rw-r--r--content/content.h18
-rw-r--r--desktop/plot_style.h5
-rw-r--r--gtk/Makefile.target2
-rw-r--r--gtk/bitmap.c344
-rw-r--r--gtk/bitmap.h14
-rw-r--r--gtk/gdk.c124
-rw-r--r--gtk/gdk.h35
-rw-r--r--gtk/plotters.c125
-rw-r--r--gtk/print.c201
-rw-r--r--gtk/scaffolding.c63
-rw-r--r--gtk/thumbnail.c83
-rw-r--r--gtk/treeview.c7
-rw-r--r--gtk/window.c7
-rw-r--r--image/gif.c13
-rw-r--r--image/image.c69
-rw-r--r--image/image.h13
-rw-r--r--image/image_cache.c17
-rw-r--r--image/png.c4
-rw-r--r--render/html_redraw.c1
20 files changed, 724 insertions, 423 deletions
diff --git a/Docs/BUILDING-GTK b/Docs/BUILDING-GTK
index a28d6e516..8d2f21541 100644
--- a/Docs/BUILDING-GTK
+++ b/Docs/BUILDING-GTK
@@ -67,7 +67,7 @@
Debian-like OS:
$ apt-get install libglade2-dev libcurl3-dev libxml2-dev libmng-dev
- $ apt-get install librsvg2-dev liblcms1-dev
+ $ apt-get install librsvg2-dev liblcms1-dev libjpeg-dev
Recent OS versions might need libcurl4-dev instead of libcurl3-dev but
note that when it has not been built with OpenSSL, the SSL_CTX is not
diff --git a/content/content.h b/content/content.h
index 580b2dacb..bdeeae48b 100644
--- a/content/content.h
+++ b/content/content.h
@@ -112,25 +112,25 @@ union content_msg_data {
struct content_rfc5988_link *rfc5988_link;
};
-
+/** parameters to content redraw */
struct content_redraw_data {
- int x; /** coordinate for top-left of redraw */
- int y; /** coordinate for top-left of redraw */
+ int x; /**< coordinate for top-left of redraw */
+ int y; /**< coordinate for top-left of redraw */
/** dimensions to render content at
* (for scaling contents with intrinsic dimensions) */
- int width; /* horizontal */
- int height; /* vertical */
+ int width; /**< horizontal dimension */
+ int height; /**< vertical dimension */
- /** the background colour */
+ /** The background colour */
colour background_colour;
/** Scale for redraw
* (for scaling contents without intrinsic dimensions) */
- float scale; /* scale factor */
+ float scale; /**< Scale factor for redraw */
- bool repeat_x; /* whether content is tiled in x direction */
- bool repeat_y; /* whether content is tiled in y direction */
+ bool repeat_x; /**< whether content is tiled in x direction */
+ bool repeat_y; /**< whether content is tiled in y direction */
};
/* The following are for hlcache */
diff --git a/desktop/plot_style.h b/desktop/plot_style.h
index e6229e256..057e40fa6 100644
--- a/desktop/plot_style.h
+++ b/desktop/plot_style.h
@@ -64,10 +64,15 @@
(((((c0 >> 8) & 0xff) + ((c1 >> 8) & 0xff)) >> 1) << 8) | \
((((c0 & 0xff) + (c1 & 0xff)) >> 1) << 0)
+/* get a bitmap pixel (image/bitmap.h) into a plot colour */
+#define pixel_to_colour(b) \
+ b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)
+
/**
* Colour type: XBGR
*/
typedef uint32_t colour;
+
/**
* Magical transparent value
*/
diff --git a/gtk/Makefile.target b/gtk/Makefile.target
index cce1fe7ef..1086d426f 100644
--- a/gtk/Makefile.target
+++ b/gtk/Makefile.target
@@ -71,7 +71,7 @@ endif
# S_GTK are sources purely for the GTK build
S_GTK := font_pango.c bitmap.c gui.c schedule.c thumbnail.c plotters.c \
- treeview.c scaffolding.c completion.c login.c throbber.c \
+ treeview.c scaffolding.c gdk.c completion.c login.c throbber.c \
selection.c history.c window.c filetype.c download.c menu.c \
print.c save.c search.c tabs.c theme.c toolbar.c \
sexy_icon_entry.c compat.c cookies.c hotlist.c system_colour.c \
diff --git a/gtk/bitmap.c b/gtk/bitmap.c
index 5dafb129e..7d8e82ddb 100644
--- a/gtk/bitmap.c
+++ b/gtk/bitmap.c
@@ -25,27 +25,17 @@
#include <assert.h>
#include <stdbool.h>
#include <string.h>
-#include <gdk/gdk.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include <cairo.h>
+#include <gtk/gtk.h>
#include "content/content.h"
-#include "gtk/bitmap.h"
#include "gtk/scaffolding.h"
+#include "gtk/bitmap.h"
#include "image/bitmap.h"
#include "utils/log.h"
-struct bitmap {
- GdkPixbuf *primary;
- GdkPixbuf *pretile_x;
- GdkPixbuf *pretile_y;
- GdkPixbuf *pretile_xy;
- bool opaque;
-};
-
-#define MIN_PRETILE_WIDTH 256
-#define MIN_PRETILE_HEIGHT 256
-
/**
* Create a bitmap.
@@ -58,18 +48,24 @@ struct bitmap {
void *bitmap_create(int width, int height, unsigned int state)
{
- struct bitmap *bmp = malloc(sizeof(struct bitmap));
-
- bmp->primary = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true,
- 8, width, height);
-
- /* fill the pixbuf in with 100% transparent black, as the memory
- * won't have been cleared.
- */
- gdk_pixbuf_fill(bmp->primary, 0);
- bmp->pretile_x = bmp->pretile_y = bmp->pretile_xy = NULL;
- bmp->opaque = (state & BITMAP_OPAQUE) != 0;
- return bmp;
+ struct bitmap *gbitmap;
+
+ gbitmap = calloc(1, sizeof(struct bitmap));
+ if (gbitmap != NULL) {
+ if ((state & BITMAP_OPAQUE) != 0) {
+ gbitmap->surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
+ } else {
+ gbitmap->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+ }
+
+ if (cairo_surface_status(gbitmap->surface) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy(gbitmap->surface);
+ free(gbitmap);
+ gbitmap = NULL;
+ }
+ }
+
+ return gbitmap;
}
@@ -81,9 +77,47 @@ void *bitmap_create(int width, int height, unsigned int state)
*/
void bitmap_set_opaque(void *vbitmap, bool opaque)
{
- struct bitmap *bitmap = (struct bitmap *)vbitmap;
- assert(bitmap);
- bitmap->opaque = opaque;
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ cairo_format_t fmt;
+ cairo_surface_t *nsurface = NULL;
+
+ assert(gbitmap);
+
+ fmt = cairo_image_surface_get_format(gbitmap->surface);
+ if (fmt == CAIRO_FORMAT_RGB24) {
+ if (opaque == false) {
+ /* opaque to transparent */
+ nsurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ cairo_image_surface_get_width(gbitmap->surface),
+ cairo_image_surface_get_height(gbitmap->surface));
+
+ }
+
+ } else {
+ if (opaque == true) {
+ /* transparent to opaque */
+ nsurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
+ cairo_image_surface_get_width(gbitmap->surface),
+ cairo_image_surface_get_height(gbitmap->surface));
+
+ }
+ }
+
+ if (nsurface != NULL) {
+ if (cairo_surface_status(nsurface) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy(nsurface);
+ } else {
+ memcpy(cairo_image_surface_get_data(nsurface),
+ cairo_image_surface_get_data(gbitmap->surface),
+ cairo_image_surface_get_stride(gbitmap->surface) * cairo_image_surface_get_height(gbitmap->surface));
+ cairo_surface_destroy(gbitmap->surface);
+ gbitmap->surface = nsurface;
+
+ cairo_surface_mark_dirty(gbitmap->surface);
+
+ }
+
+ }
}
@@ -95,10 +129,25 @@ void bitmap_set_opaque(void *vbitmap, bool opaque)
*/
bool bitmap_test_opaque(void *vbitmap)
{
- struct bitmap *bitmap = (struct bitmap *)vbitmap;
- assert(bitmap);
-/* todo: test if bitmap is opaque */
- return false;
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ unsigned char *pixels;
+ int pcount;
+ int ploop;
+
+ assert(gbitmap);
+
+ pixels = cairo_image_surface_get_data(gbitmap->surface);
+
+ pcount = cairo_image_surface_get_stride(gbitmap->surface) *
+ cairo_image_surface_get_height(gbitmap->surface);
+
+ for (ploop = 3; ploop < pcount; ploop += 4) {
+ if (pixels[ploop] != 0xff) {
+ return false;
+ }
+ }
+
+ return true;
}
@@ -109,9 +158,17 @@ bool bitmap_test_opaque(void *vbitmap)
*/
bool bitmap_get_opaque(void *vbitmap)
{
- struct bitmap *bitmap = (struct bitmap *)vbitmap;
- assert(bitmap);
- return bitmap->opaque;
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ cairo_format_t fmt;
+
+ assert(gbitmap);
+
+ fmt = cairo_image_surface_get_format(gbitmap->surface);
+ if (fmt == CAIRO_FORMAT_RGB24) {
+ return true;
+ }
+
+ return false;
}
@@ -127,9 +184,12 @@ bool bitmap_get_opaque(void *vbitmap)
unsigned char *bitmap_get_buffer(void *vbitmap)
{
- struct bitmap *bitmap = (struct bitmap *)vbitmap;
- assert(bitmap);
- return (unsigned char *)gdk_pixbuf_get_pixels(bitmap->primary);
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ assert(gbitmap);
+
+ cairo_surface_flush(gbitmap->surface);
+
+ return cairo_image_surface_get_data(gbitmap->surface);
}
@@ -142,9 +202,10 @@ unsigned char *bitmap_get_buffer(void *vbitmap)
size_t bitmap_get_rowstride(void *vbitmap)
{
- struct bitmap *bitmap = (struct bitmap *)vbitmap;
- assert(bitmap);
- return gdk_pixbuf_get_rowstride(bitmap->primary);
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ assert(gbitmap);
+
+ return cairo_image_surface_get_stride(gbitmap->surface);
}
@@ -157,21 +218,13 @@ size_t bitmap_get_rowstride(void *vbitmap)
size_t bitmap_get_bpp(void *vbitmap)
{
- struct bitmap *bitmap = (struct bitmap *)vbitmap;
- assert(bitmap);
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ assert(gbitmap);
+
return 4;
}
-static void
-gtk_bitmap_free_pretiles(struct bitmap *bitmap)
-{
-#define FREE_TILE(XY) if (bitmap->pretile_##XY) g_object_unref(bitmap->pretile_##XY); bitmap->pretile_##XY = NULL
- FREE_TILE(x);
- FREE_TILE(y);
- FREE_TILE(xy);
-#undef FREE_TILE
-}
/**
* Free a bitmap.
@@ -181,11 +234,16 @@ gtk_bitmap_free_pretiles(struct bitmap *bitmap)
void bitmap_destroy(void *vbitmap)
{
- struct bitmap *bitmap = (struct bitmap *)vbitmap;
- assert(bitmap);
- gtk_bitmap_free_pretiles(bitmap);
- g_object_unref(bitmap->primary);
- free(bitmap);
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ assert(gbitmap);
+
+ if (gbitmap->surface != NULL) {
+ cairo_surface_destroy(gbitmap->surface);
+ }
+ if (gbitmap->scsurface != NULL) {
+ cairo_surface_destroy(gbitmap->scsurface);
+ }
+ free(gbitmap);
}
@@ -200,16 +258,10 @@ void bitmap_destroy(void *vbitmap)
bool bitmap_save(void *vbitmap, const char *path, unsigned flags)
{
- struct bitmap *bitmap = (struct bitmap *)vbitmap;
- GError *err = NULL;
-
- gdk_pixbuf_save(bitmap->primary, path, "png", &err, NULL);
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ assert(gbitmap);
- if (err == NULL)
- /* TODO: report an error here */
- return false;
-
- return true;
+ return false;
}
@@ -219,8 +271,52 @@ bool bitmap_save(void *vbitmap, const char *path, unsigned flags)
* \param bitmap a bitmap, as returned by bitmap_create()
*/
void bitmap_modified(void *vbitmap) {
- struct bitmap *bitmap = (struct bitmap *)vbitmap;
- gtk_bitmap_free_pretiles(bitmap);
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ int pixel_loop;
+ int pixel_count;
+ uint32_t *pixels;
+ uint32_t pixel;
+ cairo_format_t fmt;
+
+ assert(gbitmap);
+
+ fmt = cairo_image_surface_get_format(gbitmap->surface);
+
+ pixel_count = cairo_image_surface_get_width(gbitmap->surface) *
+ cairo_image_surface_get_height(gbitmap->surface);
+ pixels = (uint32_t *)cairo_image_surface_get_data(gbitmap->surface);
+
+ if (fmt == CAIRO_FORMAT_RGB24) {
+ for (pixel_loop=0; pixel_loop < pixel_count; pixel_loop++) {
+ pixel = pixels[pixel_loop];
+ pixels[pixel_loop] = (pixel & 0xff00ff00) |
+ ((pixel & 0xff) << 16) |
+ ((pixel & 0xff0000) >> 16);
+ }
+ } else {
+ uint8_t t, r, g, b;
+ for (pixel_loop=0; pixel_loop < pixel_count; pixel_loop++) {
+ pixel = pixels[pixel_loop];
+ t = (pixel & 0xff000000) >> 24;
+ if (t == 0) {
+ pixels[pixel_loop] = 0;
+ } else {
+ r = (pixel & 0xff0000) >> 16;
+ g = (pixel & 0xff00) >> 8;
+ b = pixel & 0xff;
+
+ pixels[pixel_loop] = (t << 24) |
+ ((r * t) >> 8) |
+ ((g * t) >> 8) << 8 |
+ ((b * t) >> 8) << 16;
+
+ }
+ }
+ }
+
+ cairo_surface_mark_dirty(gbitmap->surface);
+
+ gbitmap->converted = true;
}
@@ -236,113 +332,17 @@ void bitmap_set_suspendable(void *vbitmap, void *private_word,
}
int bitmap_get_width(void *vbitmap){
- struct bitmap *bitmap = (struct bitmap *)vbitmap;
- return gdk_pixbuf_get_width(bitmap->primary);
-}
-
-int bitmap_get_height(void *vbitmap){
- struct bitmap *bitmap = (struct bitmap *)vbitmap;
- return gdk_pixbuf_get_height(bitmap->primary);
-}
-
-static GdkPixbuf *
-gtk_bitmap_generate_pretile(GdkPixbuf *primary, int repeat_x, int repeat_y)
-{
- int width = gdk_pixbuf_get_width(primary);
- int height = gdk_pixbuf_get_height(primary);
- size_t primary_stride = gdk_pixbuf_get_rowstride(primary);
- GdkPixbuf *result = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8,
- width * repeat_x, height * repeat_y);
- char *target_buffer = (char *)gdk_pixbuf_get_pixels(result);
- int x,y,row;
- /* This algorithm won't work if the strides are not multiples */
- assert((size_t)gdk_pixbuf_get_rowstride(result) ==
- (primary_stride * repeat_x));
-
- if (repeat_x == 1 && repeat_y == 1) {
- g_object_ref(primary);
- g_object_unref(result);
- return primary;
- }
-
- for (y = 0; y < repeat_y; ++y) {
- char *primary_buffer = (char *)gdk_pixbuf_get_pixels(primary);
- for (row = 0; row < height; ++row) {
- for (x = 0; x < repeat_x; ++x) {
- memcpy(target_buffer,
- primary_buffer, primary_stride);
- target_buffer += primary_stride;
- }
- primary_buffer += primary_stride;
- }
- }
- return result;
-}
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ assert(gbitmap);
-/**
- * The primary image associated with this bitmap object.
- *
- * \param bitmap a bitmap, as returned by bitmap_create()
- */
-GdkPixbuf *
-gtk_bitmap_get_primary(struct bitmap *bitmap)
-{
- if (bitmap != NULL)
- return bitmap->primary;
- else
- return NULL;
+ return cairo_image_surface_get_width(gbitmap->surface);
}
-/**
- * The X-pretiled image associated with this bitmap object.
- *
- * \param bitmap a bitmap, as returned by bitmap_create()
- */
-GdkPixbuf *
-gtk_bitmap_get_pretile_x(struct bitmap* bitmap)
-{
- if (!bitmap->pretile_x) {
- int width = gdk_pixbuf_get_width(bitmap->primary);
- int xmult = (MIN_PRETILE_WIDTH + width - 1)/width;
- LOG(("Pretiling %p for X*%d", bitmap, xmult));
- bitmap->pretile_x = gtk_bitmap_generate_pretile(bitmap->primary, xmult, 1);
- }
- return bitmap->pretile_x;
+int bitmap_get_height(void *vbitmap){
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ assert(gbitmap);
+ return cairo_image_surface_get_height(gbitmap->surface);
}
-/**
- * The Y-pretiled image associated with this bitmap object.
- *
- * \param bitmap a bitmap, as returned by bitmap_create()
- */
-GdkPixbuf *
-gtk_bitmap_get_pretile_y(struct bitmap* bitmap)
-{
- if (!bitmap->pretile_y) {
- int height = gdk_pixbuf_get_height(bitmap->primary);
- int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height;
- LOG(("Pretiling %p for Y*%d", bitmap, ymult));
- bitmap->pretile_y = gtk_bitmap_generate_pretile(bitmap->primary, 1, ymult);
- }
- return bitmap->pretile_y;
-}
-/**
- * The XY-pretiled image associated with this bitmap object.
- *
- * \param bitmap a bitmap, as returned by bitmap_create()
- */
-GdkPixbuf *
-gtk_bitmap_get_pretile_xy(struct bitmap* bitmap)
-{
- if (!bitmap->pretile_xy) {
- int width = gdk_pixbuf_get_width(bitmap->primary);
- int height = gdk_pixbuf_get_height(bitmap->primary);
- int xmult = (MIN_PRETILE_WIDTH + width - 1)/width;
- int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height;
- LOG(("Pretiling %p for X*%d Y*%d", bitmap, xmult, ymult));
- bitmap->pretile_xy = gtk_bitmap_generate_pretile(bitmap->primary, xmult, ymult);
- }
- return bitmap->pretile_xy;
-}
diff --git a/gtk/bitmap.h b/gtk/bitmap.h
index d936f7d76..62d50f47c 100644
--- a/gtk/bitmap.h
+++ b/gtk/bitmap.h
@@ -19,15 +19,13 @@
#ifndef NS_GTK_BITMAP_H
#define NS_GTK_BITMAP_H
-#include <gdk/gdk.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <cairo.h>
#include "image/bitmap.h"
-GdkPixbuf *gtk_bitmap_get_primary(struct bitmap*);
-GdkPixbuf *gtk_bitmap_get_pretile_x(struct bitmap*);
-GdkPixbuf *gtk_bitmap_get_pretile_y(struct bitmap*);
-GdkPixbuf *gtk_bitmap_get_pretile_xy(struct bitmap*);
-
-
+struct bitmap {
+ cairo_surface_t *surface; /* original cairo surface */
+ cairo_surface_t *scsurface; /* scaled surface */
+ bool converted; /** set if the surface data has been converted */
+};
#endif /* NS_GTK_BITMAP_H */
diff --git a/gtk/gdk.c b/gtk/gdk.c
new file mode 100644
index 000000000..22569285d
--- /dev/null
+++ b/gtk/gdk.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+
+#include "utils/log.h"
+
+#include "gtk/gdk.h"
+
+static void
+convert_alpha(guchar *dest_data,
+ int dest_stride,
+ guchar *src_data,
+ int src_stride,
+ int width,
+ int height)
+{
+ int x, y;
+
+ for (y = 0; y < height; y++) {
+ guint32 *src = (guint32 *) src_data;
+
+ for (x = 0; x < width; x++) {
+ guint alpha = src[x] >> 24;
+
+ if (alpha == 0) {
+ dest_data[x * 4 + 0] = 0;
+ dest_data[x * 4 + 1] = 0;
+ dest_data[x * 4 + 2] = 0;
+ } else {
+ dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
+ dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
+ dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
+ }
+ dest_data[x * 4 + 3] = alpha;
+ }
+
+ src_data += src_stride;
+ dest_data += dest_stride;
+ }
+}
+
+
+GdkPixbuf *
+nsgdk_pixbuf_get_from_surface(cairo_surface_t *surface, int scwidth, int scheight)
+{
+ int width, height; /* source width and height */
+ cairo_surface_t *scsurface; /* scaled surface */
+ cairo_t *cr; /* cairo context for scaled surface */
+ GdkPixbuf *pixbuf; /* The result pixel buffer */
+
+ /* create pixmap */
+ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, scwidth, scheight);
+ if (pixbuf == NULL) {
+ return NULL;
+ }
+
+ memset(gdk_pixbuf_get_pixels(pixbuf),
+ 0xff,
+ gdk_pixbuf_get_rowstride(pixbuf) * scheight);
+
+ /* scale cairo surface into new surface the target size */
+ cairo_surface_flush(surface); /* ensure source surface is ready */
+
+ /* get source surface dimensions */
+ width = cairo_image_surface_get_width(surface);
+ height = cairo_image_surface_get_height(surface);
+
+ /* scaled surface always has an alpha chanel for ease */
+ scsurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, scwidth, scheight);
+ if (cairo_surface_status(scsurface) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy(scsurface);
+ g_object_unref(pixbuf);
+ LOG(("Surface creation failed"));
+ return NULL;
+ }
+
+ cr = cairo_create(scsurface);
+
+ /* Scale *before* setting the source surface */
+ cairo_scale(cr, (double)scwidth / width, (double)scheight / height);
+ cairo_set_source_surface(cr, surface, 0, 0);
+
+ /* To avoid getting the edge pixels blended with 0
+ * alpha, which would occur with the default
+ * EXTEND_NONE. Use EXTEND_PAD for 1.2 or newer
+ */
+ cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REFLECT);
+
+ /* Replace the destination with the source instead of overlaying */
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+
+ /* Do the actual drawing */
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
+
+ /* copy data from surface into pixmap */
+ convert_alpha(gdk_pixbuf_get_pixels(pixbuf),
+ gdk_pixbuf_get_rowstride(pixbuf),
+ cairo_image_surface_get_data(scsurface),
+ cairo_image_surface_get_stride(scsurface),
+ scwidth, scheight);
+
+ cairo_surface_destroy(scsurface);
+
+ return pixbuf;
+}
+
diff --git a/gtk/gdk.h b/gtk/gdk.h
new file mode 100644
index 000000000..2fcee07f1
--- /dev/null
+++ b/gtk/gdk.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * GDK support functions for missing interfaces
+ */
+
+#ifndef NETSURF_GTK_GDK_H_
+#define NETSURF_GTK_GDK_H_
+
+#include <gtk/gtk.h>
+
+/** obtain a pixbuf of the specified size from a cairo surface.
+ *
+ * This is the same as the GTK+ 3 gdk_pixbuf_get_from_surface but
+ * actually works and is available on gtk 2
+ */
+GdkPixbuf *nsgdk_pixbuf_get_from_surface(cairo_surface_t *surface, int width, int height);
+
+#endif /* NETSURF_GTK_GDK_H */
diff --git a/gtk/plotters.c b/gtk/plotters.c
index 0469b8dfb..4c9627380 100644
--- a/gtk/plotters.c
+++ b/gtk/plotters.c
@@ -42,7 +42,6 @@
#include "gtk/bitmap.h"
GtkWidget *current_widget;
-GdkDrawable *current_drawable;
cairo_t *current_cr;
static GdkRectangle cliprect;
@@ -281,7 +280,7 @@ static bool nsgtk_plot_text(int x, int y, const char *text, size_t length,
static bool nsgtk_plot_pixbuf(int x, int y, int width, int height,
- GdkPixbuf *pixbuf, colour bg)
+ struct bitmap *bitmap, colour bg)
{
/* XXX: This currently ignores the background colour supplied.
* Does this matter?
@@ -289,6 +288,9 @@ static bool nsgtk_plot_pixbuf(int x, int y, int width, int height,
int x0, y0, x1, y1;
int dsrcx, dsrcy, dwidth, dheight;
+ int bmwidth, bmheight;
+
+ cairo_surface_t *bmsurface = bitmap->surface;
/* Bail early if we can */
if (width == 0 || height == 0)
@@ -309,21 +311,20 @@ static bool nsgtk_plot_pixbuf(int x, int y, int width, int height,
y1 = (y + height) - (cliprect.y + cliprect.height);
/* Set initial draw geometry */
- dsrcx = dsrcy = 0;
+ dsrcx = x;
+ dsrcy = y;
dwidth = width;
dheight = height;
/* Manually clip draw coordinates to area of image to be rendered */
if (x0 > 0) {
/* Clip left */
- dsrcx = x0;
- x += x0;
+ dsrcx += x0;
dwidth -= x0;
}
if (y0 > 0) {
/* Clip top */
- dsrcy = y0;
- y += y0;
+ dsrcy += y0;
dheight -= y0;
}
if (x1 > 0) {
@@ -339,40 +340,58 @@ static bool nsgtk_plot_pixbuf(int x, int y, int width, int height,
/* Nothing to plot */
return true;
+ bmwidth = cairo_image_surface_get_width(bmsurface);
+ bmheight = cairo_image_surface_get_height(bmsurface);
+
/* Render the bitmap */
- if (gdk_pixbuf_get_width(pixbuf) == width &&
- gdk_pixbuf_get_height(pixbuf) == height) {
+ if ((bmwidth == width) && (bmheight == height)) {
/* Bitmap is not scaled */
/* Plot the bitmap */
- gdk_cairo_set_source_pixbuf(current_cr, pixbuf, x - dsrcx, y -dsrcy);
- cairo_rectangle(current_cr, x , y , dwidth, dheight);
+ cairo_set_source_surface(current_cr, bmsurface, x, y);
+ cairo_rectangle(current_cr, dsrcx, dsrcy, dwidth, dheight);
cairo_fill(current_cr);
} else {
/* Bitmap is scaled */
- /* Get scale factors */
- double sx = (double)width / gdk_pixbuf_get_width(pixbuf);
- double sy = (double)height / gdk_pixbuf_get_height(pixbuf);
-
- /* Create bitmap for scaled image portion */
- GdkPixbuf *scaled = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8,
- dwidth, dheight);
- /* Only scale up the portion of the bitmap that we are
- * interested in rendering */
- gdk_pixbuf_scale(pixbuf, scaled,
- 0, 0, dwidth, dheight,
- -dsrcx, -dsrcy, sx, sy,
- option_render_resample ? GDK_INTERP_BILINEAR :
- GDK_INTERP_NEAREST);
- if (!scaled)
- return false;
+ if ((bitmap->scsurface != NULL) &&
+ ((cairo_image_surface_get_width(bitmap->scsurface) != width) ||
+ (cairo_image_surface_get_height(bitmap->scsurface) != height))){
+ cairo_surface_destroy(bitmap->scsurface);
+ bitmap->scsurface = NULL;
+ }
+
+ if (bitmap->scsurface == NULL) {
+ bitmap->scsurface = cairo_surface_create_similar(bmsurface,CAIRO_CONTENT_COLOR_ALPHA, width, height);
+ cairo_t *cr = cairo_create(bitmap->scsurface);
+
+ /* Scale *before* setting the source surface (1) */
+ cairo_scale(cr, (double)width / bmwidth, (double)height / bmheight);
+ cairo_set_source_surface(cr, bmsurface, 0, 0);
+
+ /* To avoid getting the edge pixels blended with 0
+ * alpha, which would occur with the default
+ * EXTEND_NONE. Use EXTEND_PAD for 1.2 or newer (2)
+ */
+ cairo_pattern_set_extend(cairo_get_source(cr),
+ CAIRO_EXTEND_REFLECT);
+
+ /* Replace the destination with the source instead of
+ * overlaying
+ */
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+
+ /* Do the actual drawing */
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
+ }
/* Plot the scaled bitmap */
- gdk_cairo_set_source_pixbuf(current_cr, scaled, x, y);
- cairo_rectangle(current_cr, x , y , dwidth, dheight);
+ cairo_set_source_surface(current_cr, bitmap->scsurface, x, y);
+ cairo_rectangle(current_cr, dsrcx, dsrcy, dwidth, dheight);
cairo_fill(current_cr);
- g_object_unref(scaled);
+
}
return true;
@@ -383,52 +402,46 @@ static bool nsgtk_plot_bitmap(int x, int y, int width, int height,
bitmap_flags_t flags)
{
int doneheight = 0, donewidth = 0;
- GdkPixbuf *primary;
- GdkPixbuf *pretiled = NULL;
-
bool repeat_x = (flags & BITMAPF_REPEAT_X);
bool repeat_y = (flags & BITMAPF_REPEAT_Y);
if (!(repeat_x || repeat_y)) {
/* Not repeating at all, so just pass it on */
- primary = gtk_bitmap_get_primary(bitmap);
- return nsgtk_plot_pixbuf(x, y, width, height, primary, bg);
+ return nsgtk_plot_pixbuf(x, y, width, height, bitmap, bg);
}
- if (repeat_x && !repeat_y)
- pretiled = gtk_bitmap_get_pretile_x(bitmap);
- if (repeat_x && repeat_y)
- pretiled = gtk_bitmap_get_pretile_xy(bitmap);
- if (!repeat_x && repeat_y)
- pretiled = gtk_bitmap_get_pretile_y(bitmap);
+ width = bitmap_get_width(bitmap);
+ height = bitmap_get_height(bitmap);
- assert(pretiled != NULL);
-
- primary = gtk_bitmap_get_primary(bitmap);
- /* use the primary and pretiled widths to scale the w/h provided */
- width *= gdk_pixbuf_get_width(pretiled);
- width /= gdk_pixbuf_get_width(primary);
- height *= gdk_pixbuf_get_height(pretiled);
- height /= gdk_pixbuf_get_height(primary);
+ /* Bail early if we can */
+ if (width == 0 || height == 0)
+ /* Nothing to plot */
+ return true;
- if (y > cliprect.y)
+ if (y > cliprect.y) {
doneheight = (cliprect.y - height) + ((y - cliprect.y) % height);
- else
+ } else {
doneheight = y;
+ }
while (doneheight < (cliprect.y + cliprect.height)) {
- if (x > cliprect.x)
+ if (x > cliprect.x) {
donewidth = (cliprect.x - width) + ((x - cliprect.x) % width);
- else
+ } else {
donewidth = x;
+ }
+
while (donewidth < (cliprect.x + cliprect.width)) {
nsgtk_plot_pixbuf(donewidth, doneheight,
- width, height, pretiled, bg);
+ width, height, bitmap, bg);
donewidth += width;
- if (!repeat_x) break;
+ if (!repeat_x)
+ break;
}
doneheight += height;
- if (!repeat_y) break;
+
+ if (!repeat_y)
+ break;
}
return true;
diff --git a/gtk/print.c b/gtk/print.c
index f0f205e42..63489884a 100644
--- a/gtk/print.c
+++ b/gtk/print.c
@@ -72,40 +72,6 @@ static inline void nsgtk_print_set_colour(colour c)
g / 255.0, b / 255.0, 1.0);
}
-static bool nsgtk_print_plot_pixbuf(int x, int y, int width, int height,
- GdkPixbuf *pixbuf, colour bg)
-{
- /* XXX: This currently ignores the background colour supplied.
- * Does this matter?
- */
-
- if (width == 0 || height == 0)
- return true;
-
- if (gdk_pixbuf_get_width(pixbuf) == width &&
- gdk_pixbuf_get_height(pixbuf) == height) {
- gdk_cairo_set_source_pixbuf(gtk_print_current_cr, pixbuf, x, y);
- cairo_paint(gtk_print_current_cr);
- } else {
- GdkPixbuf *scaled;
- scaled = gdk_pixbuf_scale_simple(pixbuf,
- width, height,
- /* plotting for the printer doesn't have
- * to be fast so we can use always the
- * interp_style that gives better quality
- */
- GDK_INTERP_BILINEAR);
- if (!scaled)
- return false;
-
- gdk_cairo_set_source_pixbuf(gtk_print_current_cr, scaled, x, y);
- cairo_paint(gtk_print_current_cr);
-
- g_object_unref(scaled);
- }
-
- return true;
-}
static bool gtk_print_font_paint(int x, int y,
@@ -368,63 +334,166 @@ static bool nsgtk_print_plot_path(const float *p, unsigned int n, colour fill,
return true;
}
+
+static bool nsgtk_print_plot_pixbuf(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg)
+{
+ int x0, y0, x1, y1;
+ int dsrcx, dsrcy, dwidth, dheight;
+ int bmwidth, bmheight;
+
+ cairo_surface_t *bmsurface = bitmap->surface;
+
+ /* Bail early if we can */
+ if (width == 0 || height == 0)
+ /* Nothing to plot */
+ return true;
+ if ((x > (cliprect.x + cliprect.width)) ||
+ ((x + width) < cliprect.x) ||
+ (y > (cliprect.y + cliprect.height)) ||
+ ((y + height) < cliprect.y)) {
+ /* Image completely outside clip region */
+ return true;
+ }
+
+ /* Get clip rectangle / image rectangle edge differences */
+ x0 = cliprect.x - x;
+ y0 = cliprect.y - y;
+ x1 = (x + width) - (cliprect.x + cliprect.width);
+ y1 = (y + height) - (cliprect.y + cliprect.height);
+
+ /* Set initial draw geometry */
+ dsrcx = x;
+ dsrcy = y;
+ dwidth = width;
+ dheight = height;
+
+ /* Manually clip draw coordinates to area of image to be rendered */
+ if (x0 > 0) {
+ /* Clip left */
+ dsrcx += x0;
+ dwidth -= x0;
+ }
+ if (y0 > 0) {
+ /* Clip top */
+ dsrcy += y0;
+ dheight -= y0;
+ }
+ if (x1 > 0) {
+ /* Clip right */
+ dwidth -= x1;
+ }
+ if (y1 > 0) {
+ /* Clip bottom */
+ dheight -= y1;
+ }
+
+ if (dwidth == 0 || dheight == 0)
+ /* Nothing to plot */
+ return true;
+
+ bmwidth = cairo_image_surface_get_width(bmsurface);
+ bmheight = cairo_image_surface_get_height(bmsurface);
+
+ /* Render the bitmap */
+ if ((bmwidth == width) && (bmheight == height)) {
+ /* Bitmap is not scaled */
+ /* Plot the bitmap */
+ cairo_set_source_surface(gtk_print_current_cr, bmsurface, x, y);
+ cairo_rectangle(gtk_print_current_cr, dsrcx, dsrcy, dwidth, dheight);
+ cairo_fill(gtk_print_current_cr);
+
+ } else {
+ /* Bitmap is scaled */
+ if ((bitmap->scsurface != NULL) &&
+ ((cairo_image_surface_get_width(bitmap->scsurface) != width) ||
+ (cairo_image_surface_get_height(bitmap->scsurface) != height))){
+ cairo_surface_destroy(bitmap->scsurface);
+ bitmap->scsurface = NULL;
+ }
+
+ if (bitmap->scsurface == NULL) {
+ bitmap->scsurface = cairo_surface_create_similar(bmsurface,CAIRO_CONTENT_COLOR_ALPHA, width, height);
+ cairo_t *cr = cairo_create(bitmap->scsurface);
+
+ /* Scale *before* setting the source surface (1) */
+ cairo_scale(cr, (double)width / bmwidth, (double)height / bmheight);
+ cairo_set_source_surface(cr, bmsurface, 0, 0);
+
+ /* To avoid getting the edge pixels blended with 0
+ * alpha, which would occur with the default
+ * EXTEND_NONE. Use EXTEND_PAD for 1.2 or newer (2)
+ */
+ cairo_pattern_set_extend(cairo_get_source(cr),
+ CAIRO_EXTEND_REFLECT);
+
+ /* Replace the destination with the source instead of
+ * overlaying
+ */
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+
+ /* Do the actual drawing */
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
+
+ }
+ /* Plot the scaled bitmap */
+ cairo_set_source_surface(gtk_print_current_cr, bitmap->scsurface, x, y);
+ cairo_rectangle(gtk_print_current_cr, dsrcx, dsrcy, dwidth, dheight);
+ cairo_fill(gtk_print_current_cr);
+
+ }
+
+ return true;
+}
+
+
static bool nsgtk_print_plot_bitmap(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bitmap_flags_t flags)
{
int doneheight = 0, donewidth = 0;
- GdkPixbuf *primary;
- GdkPixbuf *pretiled = NULL;
-
- bool repeat_x = (flags & BITMAPF_REPEAT_X);
- bool repeat_y = (flags & BITMAPF_REPEAT_Y);
+ bool repeat_x = (flags & BITMAPF_REPEAT_X);
+ bool repeat_y = (flags & BITMAPF_REPEAT_Y);
if (!(repeat_x || repeat_y)) {
/* Not repeating at all, so just pass it on */
- primary = gtk_bitmap_get_primary(bitmap);
- return nsgtk_print_plot_pixbuf(x, y, width, height, primary, bg);
+ return nsgtk_print_plot_pixbuf(x, y, width, height, bitmap, bg);
}
- if (repeat_x && !repeat_y)
- pretiled = gtk_bitmap_get_pretile_x(bitmap);
- if (repeat_x && repeat_y)
- pretiled = gtk_bitmap_get_pretile_xy(bitmap);
- if (!repeat_x && repeat_y)
- pretiled = gtk_bitmap_get_pretile_y(bitmap);
-
- assert(pretiled != NULL);
+ width = bitmap_get_width(bitmap);
+ height = bitmap_get_height(bitmap);
- primary = gtk_bitmap_get_primary(bitmap);
-
- /* use the primary and pretiled widths to scale the w/h provided */
- width *= gdk_pixbuf_get_width(pretiled);
- width /= gdk_pixbuf_get_width(primary);
- height *= gdk_pixbuf_get_height(pretiled);
- height /= gdk_pixbuf_get_height(primary);
+ /* Bail early if we can */
+ if (width == 0 || height == 0)
+ /* Nothing to plot */
+ return true;
if (y > cliprect.y) {
- doneheight = (cliprect.y - height) +
- ((y - cliprect.y) % height);
- } else
+ doneheight = (cliprect.y - height) + ((y - cliprect.y) % height);
+ } else {
doneheight = y;
+ }
while (doneheight < (cliprect.y + cliprect.height)) {
if (x > cliprect.x) {
- donewidth = (cliprect.x - width) +
- ((x - cliprect.x) % width);
- } else
+ donewidth = (cliprect.x - width) + ((x - cliprect.x) % width);
+ } else {
donewidth = x;
+ }
while (donewidth < (cliprect.x + cliprect.width)) {
nsgtk_print_plot_pixbuf(donewidth, doneheight,
- width, height, pretiled, bg);
+ width, height, bitmap, bg);
donewidth += width;
- if (!repeat_x) break;
+ if (!repeat_x)
+ break;
}
-
doneheight += height;
- if (!repeat_y) break;
+ if (!repeat_y)
+ break;
}
return true;
diff --git a/gtk/scaffolding.c b/gtk/scaffolding.c
index a816423a9..7d2814165 100644
--- a/gtk/scaffolding.c
+++ b/gtk/scaffolding.c
@@ -76,6 +76,7 @@
#include "gtk/options.h"
#include "gtk/sexy_icon_entry.h"
#include "gtk/compat.h"
+#include "gtk/gdk.h"
#include "image/ico.h"
#include "render/box.h"
#include "render/font.h"
@@ -1517,9 +1518,8 @@ static gboolean nsgtk_history_expose_event(GtkWidget *widget,
};
current_widget = widget;
- current_drawable = widget->window;
- current_cr = gdk_cairo_create(current_drawable);
+ current_cr = gdk_cairo_create(widget->window);
clip.x0 = event->area.x;
clip.y0 = event->area.y;
@@ -1993,6 +1993,23 @@ void gui_window_stop_throbber(struct gui_window* _g)
gtk_image_set_from_pixbuf(g->throbber, nsgtk_throbber->framedata[0]);
}
+static GtkImage *
+nsgtk_image_new_from_surface(cairo_surface_t *surface, int w, int h)
+{
+ GdkPixbuf *pixbuf;
+ GtkImage *image = NULL;
+
+ pixbuf = nsgdk_pixbuf_get_from_surface(surface, w, h);
+
+ if (pixbuf != NULL) {
+ image = GTK_IMAGE(gtk_image_new_from_pixbuf(pixbuf));
+ }
+
+ g_object_unref(pixbuf);
+
+ return image;
+}
+
/**
* set favicon
*/
@@ -2002,23 +2019,16 @@ void gui_window_set_icon(struct gui_window *_g, hlcache_handle *icon)
struct bitmap *icon_bitmap;
GtkImage *iconImage = NULL;
- if (g->top_level != _g)
+ if (g->top_level != _g) {
return;
-
+ }
icon_bitmap = (icon != NULL) ? content_get_bitmap(icon) : NULL;
if (icon_bitmap != NULL) {
- GdkPixbuf *pb = gtk_bitmap_get_primary(icon_bitmap);
-
- if ((pb != NULL) &&
- (gdk_pixbuf_get_width(pb) > 0) &&
- (gdk_pixbuf_get_height(pb) > 0)) {
- pb = gdk_pixbuf_scale_simple(pb, 16, 16, GDK_INTERP_HYPER);
- iconImage = GTK_IMAGE(gtk_image_new_from_pixbuf(pb));
- }
+ iconImage = nsgtk_image_new_from_surface(icon_bitmap->surface, 16, 16);
}
+
if (iconImage == NULL) {
- /** \todo Does pb need cleaning up? */
char imagepath[strlen(res_dir_location) +
SLEN("favicon.png") + 1];
sprintf(imagepath, "%sfavicon.png", res_dir_location);
@@ -2028,8 +2038,10 @@ void gui_window_set_icon(struct gui_window *_g, hlcache_handle *icon)
if (iconImage == NULL)
return;
- if (g->icoFav != NULL)
+ if (g->icoFav != NULL) {
g_object_unref(g->icoFav);
+ }
+
g->icoFav = iconImage;
sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(g->url_bar),
@@ -2039,7 +2051,7 @@ void gui_window_set_icon(struct gui_window *_g, hlcache_handle *icon)
void gui_window_set_search_ico(hlcache_handle *ico)
{
- GdkPixbuf *pbico;
+ GdkPixbuf *pbico = NULL;
GtkImage *searchico;
struct bitmap *ico_bitmap;
nsgtk_scaffolding *current;
@@ -2051,17 +2063,13 @@ void gui_window_set_search_ico(hlcache_handle *ico)
if (ico_bitmap == NULL)
return;
- pbico = gtk_bitmap_get_primary(ico_bitmap);
- if (pbico != NULL && gdk_pixbuf_get_width(pbico) > 0 &&
- gdk_pixbuf_get_height(pbico) > 0) {
- pbico = gdk_pixbuf_scale_simple(pbico, 20, 20,
- GDK_INTERP_HYPER);
- searchico = GTK_IMAGE(gtk_image_new_from_pixbuf(pbico));
- } else {
- /** \todo Does pbico need cleaning up? */
+ pbico = nsgdk_pixbuf_get_from_surface(ico_bitmap->surface, 16, 16);
+ if (pbico == NULL) {
return;
}
+ searchico = GTK_IMAGE(gtk_image_new_from_pixbuf(pbico));
+
/* add ico to each window's toolbar */
for (current = scaf_list; current != NULL; current = current->next) {
if (searchico != NULL) {
@@ -2072,11 +2080,12 @@ void gui_window_set_search_ico(hlcache_handle *ico)
SEXY_ICON_ENTRY_PRIMARY,
current->webSearchIco);
}
- if (pbico != NULL)
- searchico = GTK_IMAGE(gtk_image_new_from_pixbuf(pbico));
- else
- searchico = NULL;
+
+ searchico = GTK_IMAGE(gtk_image_new_from_pixbuf(pbico));
}
+
+ g_object_unref(pbico);
+
}
bool nsgtk_scaffolding_is_busy(nsgtk_scaffolding *g)
diff --git a/gtk/thumbnail.c b/gtk/thumbnail.c
index d7d45d9e1..b09b8dd2f 100644
--- a/gtk/thumbnail.c
+++ b/gtk/thumbnail.c
@@ -52,15 +52,11 @@
bool thumbnail_create(hlcache_handle *content, struct bitmap *bitmap,
const char *url)
{
- GdkPixbuf *pixbuf;
+ cairo_surface_t *dsurface = bitmap->surface;
+ cairo_surface_t *surface;
+ cairo_t *old_cr;
+ gint dwidth, dheight;
int cwidth, cheight;
- gint width;
- gint height;
- gint depth;
- GdkPixmap *pixmap;
- GdkPixbuf *big;
- double scale;
-
struct redraw_context ctx = {
.interactive = false,
.background_images = true,
@@ -70,11 +66,8 @@ bool thumbnail_create(hlcache_handle *content, struct bitmap *bitmap,
assert(content);
assert(bitmap);
- /* Get details of required final thumbnail image */
- pixbuf = gtk_bitmap_get_primary(bitmap);
- width = gdk_pixbuf_get_width(pixbuf);
- height = gdk_pixbuf_get_height(pixbuf);
- depth = (gdk_screen_get_system_visual(gdk_screen_get_default()))->depth;
+ dwidth = cairo_image_surface_get_width(dsurface);
+ dheight = cairo_image_surface_get_height(dsurface);
/* Calculate size of buffer to render the content into */
/* We get the width from the content width, unless it exceeds 1024,
@@ -82,55 +75,53 @@ bool thumbnail_create(hlcache_handle *content, struct bitmap *bitmap,
* large render buffers for huge contents, which would eat memory and
* cripple performance. */
cwidth = min(content_get_width(content), 1024);
+
/* The height is set in proportion with the width, according to the
* aspect ratio of the required thumbnail. */
- cheight = ((cwidth * height) + (width / 2)) / width;
-
- /* Create buffer to render into */
- pixmap = gdk_pixmap_new(NULL, cwidth, cheight, depth);
-
- if (pixmap == NULL) {
- /* the creation failed for some reason: most likely because
- * we've been asked to create with with at least one dimention
- * as zero. The RISC OS thumbnail generator returns false
- * from here when it can't create a bitmap, so we assume it's
- * safe to do so here too.
- */
+ cheight = ((cwidth * dheight) + (dwidth / 2)) / dwidth;
+
+ /* Create surface to render into */
+ surface = cairo_surface_create_similar(dsurface, CAIRO_CONTENT_COLOR_ALPHA, cwidth, cheight);
+
+ if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy(surface);
return false;
}
- gdk_drawable_set_colormap(pixmap, gdk_colormap_get_system());
-
- /* set to plot to pixmap */
- current_drawable = pixmap;
- current_cr = gdk_cairo_create(current_drawable);
+ old_cr = current_cr;
+ current_cr = cairo_create(surface);
/* render the content */
thumbnail_redraw(content, cwidth, cheight, &ctx);
- /* get the pixbuf we rendered the content into */
- big = gdk_pixbuf_get_from_drawable(NULL, pixmap, NULL, 0, 0, 0, 0,
- cwidth, cheight);
+ cairo_destroy(current_cr);
+ current_cr = old_cr;
+
+ cairo_t *cr = cairo_create(dsurface);
- /* resample the large plot down to the size of our thumbnail */
- scale = (double)width / (double)cwidth;
- gdk_pixbuf_scale(big, pixbuf, 0, 0, width, height, 0, 0,
- scale, scale, GDK_INTERP_TILES);
+ /* Scale *before* setting the source surface (1) */
+ cairo_scale (cr, (double)dwidth / cwidth, (double)dheight / cheight);
+ cairo_set_source_surface (cr, surface, 0, 0);
- /* As a debugging aid, try this to dump out a copy of the thumbnail as
- * a PNG: gdk_pixbuf_save(pixbuf, "thumbnail.png", "png", NULL, NULL);
+ /* To avoid getting the edge pixels blended with 0 alpha,
+ * which would occur with the default EXTEND_NONE. Use
+ * EXTEND_PAD for 1.2 or newer (2)
*/
+ cairo_pattern_set_extend (cairo_get_source(cr), CAIRO_EXTEND_REFLECT);
- /* register the thumbnail with the URL */
- if (url)
- urldb_set_thumbnail(url, bitmap);
+ /* Replace the destination with the source instead of overlaying */
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- bitmap_modified(bitmap);
+ /* Do the actual drawing */
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
- cairo_destroy(current_cr);
+ cairo_surface_destroy(surface);
- g_object_unref(pixmap);
- g_object_unref(big);
+ /* register the thumbnail with the URL */
+ if (url)
+ urldb_set_thumbnail(url, bitmap);
return true;
}
diff --git a/gtk/treeview.c b/gtk/treeview.c
index e8f25a0f3..7e690e7db 100644
--- a/gtk/treeview.c
+++ b/gtk/treeview.c
@@ -182,12 +182,7 @@ gboolean nsgtk_tree_window_expose_event(GtkWidget *widget,
height = event->area.height;
current_widget = widget;
- current_drawable = widget->window;
- current_cr = gdk_cairo_create(current_drawable);
-
- current_widget = widget;
- current_drawable = widget->window;
- current_cr = gdk_cairo_create(current_drawable);
+ current_cr = gdk_cairo_create(widget->window);
tree_set_redraw(tree, true);
tree_draw(tree, 0, 0, x, y, width, height, &ctx);
diff --git a/gtk/window.c b/gtk/window.c
index c8e62bd16..c2f2c6aa1 100644
--- a/gtk/window.c
+++ b/gtk/window.c
@@ -157,10 +157,8 @@ static gboolean nsgtk_window_expose_event(GtkWidget *widget,
assert(z);
assert(GTK_WIDGET(g->layout) == widget);
-
current_widget = (GtkWidget *)g->layout;
- current_drawable = g->layout->bin_window;
- current_cr = gdk_cairo_create(current_drawable);
+ current_cr = gdk_cairo_create(g->layout->bin_window);
clip.x0 = event->area.x;
clip.y0 = event->area.y;
@@ -169,8 +167,9 @@ static gboolean nsgtk_window_expose_event(GtkWidget *widget,
browser_window_redraw(g->bw, 0, 0, &clip, &ctx);
- if (g->careth != 0)
+ if (g->careth != 0) {
nsgtk_plot_caret(g->caretx, g->carety, g->careth);
+ }
current_widget = NULL;
cairo_destroy(current_cr);
diff --git a/image/gif.c b/image/gif.c
index 098287573..8cb89c7d7 100644
--- a/image/gif.c
+++ b/image/gif.c
@@ -39,6 +39,7 @@
#include "content/hlcache.h"
#include "desktop/options.h"
#include "desktop/plotters.h"
+#include "image/image.h"
#include "image/bitmap.h"
#include "image/gif.h"
#include "utils/log.h"
@@ -337,7 +338,6 @@ static bool nsgif_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
nsgif_content *gif = (nsgif_content *) c;
- bitmap_flags_t flags = BITMAPF_NONE;
if (gif->current_frame != gif->gif->decoded_frame) {
if (nsgif_get_frame(gif) != GIF_OK) {
@@ -345,16 +345,7 @@ static bool nsgif_redraw(struct content *c, struct content_redraw_data *data,
}
}
- if ((data->width == -1) && (data->height == -1))
- return true;
-
- if (data->repeat_x)
- flags |= BITMAPF_REPEAT_X;
- if (data->repeat_y)
- flags |= BITMAPF_REPEAT_Y;
-
- return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
- gif->gif->frame_image, data->background_colour, flags);
+ return image_bitmap_plot(gif->gif->frame_image, data, clip, ctx);
}
diff --git a/image/image.c b/image/image.c
index cf5badc4d..becf221b9 100644
--- a/image/image.c
+++ b/image/image.c
@@ -22,8 +22,11 @@
#include <string.h>
#include "utils/errors.h"
+#include "utils/config.h"
+#include "utils/log.h"
+#include "desktop/plotters.h"
+#include "image/bitmap.h"
-#include "image/image.h"
#include "image/bmp.h"
#include "image/gif.h"
#include "image/ico.h"
@@ -35,7 +38,7 @@
#include "image/svg.h"
#include "image/webp.h"
-#include "utils/config.h"
+#include "image/image.h"
/**
* Initialise image content handlers
@@ -114,3 +117,65 @@ nserror image_init(void)
return NSERROR_OK;
}
+
+bool image_bitmap_plot(struct bitmap *bitmap,
+ struct content_redraw_data *data,
+ const struct rect *clip,
+ const struct redraw_context *ctx)
+{
+ bitmap_flags_t flags = BITMAPF_NONE;
+
+ int width;
+ int height;
+ unsigned char *pixel;
+ plot_style_t fill_style;
+ struct rect area;
+
+ width = bitmap_get_width(bitmap);
+ if (width == 1) {
+ height = bitmap_get_height(bitmap);
+ if (height == 1) {
+ /* optimise 1x1 bitmap plot */
+ pixel = bitmap_get_buffer(bitmap);
+ fill_style.fill_colour = pixel_to_colour(pixel);
+
+ if (bitmap_get_opaque(bitmap) ||
+ ((fill_style.fill_colour & 0xff000000) == 0xff000000)) {
+
+ area = *clip;
+
+ if (data->repeat_x != true) {
+ area.x0 = data->x;
+ area.x1 = data->x + data->width;
+ }
+
+ if (data->repeat_y != true) {
+ area.y0 = data->y;
+ area.y1 = data->y + data->height;
+ }
+
+ fill_style.stroke_type = PLOT_OP_TYPE_NONE;
+ fill_style.fill_type = PLOT_OP_TYPE_SOLID;
+
+ return ctx->plot->rectangle(area.x0, area.y0,
+ area.x1, area.y1,
+ &fill_style);
+
+ } else if ((fill_style.fill_colour & 0xff000000) == 0) {
+ /* transparent pixel used as spacer, skip it */
+ return true;
+ }
+ }
+ }
+
+ /* do the plot */
+ if (data->repeat_x)
+ flags |= BITMAPF_REPEAT_X;
+ if (data->repeat_y)
+ flags |= BITMAPF_REPEAT_Y;
+
+ return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
+ bitmap, data->background_colour, flags);
+
+
+}
diff --git a/image/image.h b/image/image.h
index 7a698e54e..eb9482583 100644
--- a/image/image.h
+++ b/image/image.h
@@ -25,6 +25,19 @@
#include "utils/errors.h"
+/** Initialise the content handlers for image types.
+ */
nserror image_init(void);
+/** Common image content handler bitmap plot call.
+ *
+ * This plots the specified bitmap controlled by the redraw context
+ * and specific content redraw data. It is a helper specifically
+ * provided for image content handlers redraw callback.
+ */
+bool image_bitmap_plot(struct bitmap *bitmap,
+ struct content_redraw_data *data,
+ const struct rect *clip,
+ const struct redraw_context *ctx);
+
#endif
diff --git a/image/image_cache.c b/image/image_cache.c
index 354aee2ce..c31d3e964 100644
--- a/image/image_cache.c
+++ b/image/image_cache.c
@@ -22,13 +22,12 @@
#include <stdbool.h>
#include <string.h>
-#include "utils/errors.h"
-#include "utils/utils.h"
-#include "utils/log.h"
-#include "utils/config.h"
#include "utils/schedule.h"
+#include "utils/log.h"
#include "content/content_protected.h"
+
#include "image/image_cache.h"
+#include "image/image.h"
/** Age of an entry within the cache
*
@@ -712,7 +711,6 @@ bool image_cache_redraw(struct content *c,
const struct rect *clip,
const struct redraw_context *ctx)
{
- bitmap_flags_t flags = BITMAPF_NONE;
struct image_cache_entry_s *centry;
/* get the cache entry */
@@ -746,14 +744,7 @@ bool image_cache_redraw(struct content *c,
centry->redraw_count++;
centry->redraw_age = image_cache->current_age;
- /* do the plot */
- if (data->repeat_x)
- flags |= BITMAPF_REPEAT_X;
- if (data->repeat_y)
- flags |= BITMAPF_REPEAT_Y;
-
- return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
- centry->bitmap, data->background_colour, flags);
+ return image_bitmap_plot(centry->bitmap, data, clip, ctx);
}
void image_cache_destroy(struct content *content)
diff --git a/image/png.c b/image/png.c
index fefb956b2..7c0aa56f1 100644
--- a/image/png.c
+++ b/image/png.c
@@ -498,7 +498,9 @@ png_cache_convert_error:
free((png_bytep *) row_pointers);
- return (struct bitmap *) bitmap;
+ bitmap_modified((struct bitmap *)bitmap);
+
+ return (struct bitmap *)bitmap;
}
static bool nspng_convert(struct content *c)
diff --git a/render/html_redraw.c b/render/html_redraw.c
index 5ed45d91b..bfef82406 100644
--- a/render/html_redraw.c
+++ b/render/html_redraw.c
@@ -2173,6 +2173,7 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
width = content_get_width(background->background);
height = content_get_height(background->background);
+ /* ensure clip area only as large as required */
if (!repeat_x) {
if (r.x0 < x)
r.x0 = x;