From df18a971435c35963bb8ea94efc0d5326ad66ff0 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Fri, 30 Dec 2011 00:58:35 +0000 Subject: Change GTK plotting to use cairo surfaces throughout svn path=/trunk/netsurf/; revision=13354 --- Docs/BUILDING-GTK | 2 +- content/content.h | 18 +-- desktop/plot_style.h | 5 + gtk/Makefile.target | 2 +- gtk/bitmap.c | 344 +++++++++++++++++++++++++-------------------------- gtk/bitmap.h | 14 +-- gtk/gdk.c | 124 +++++++++++++++++++ gtk/gdk.h | 35 ++++++ gtk/plotters.c | 125 ++++++++++--------- gtk/print.c | 201 ++++++++++++++++++++---------- gtk/scaffolding.c | 63 ++++++---- gtk/thumbnail.c | 83 ++++++------- gtk/treeview.c | 7 +- gtk/window.c | 7 +- image/gif.c | 13 +- image/image.c | 69 ++++++++++- image/image.h | 13 ++ image/image_cache.c | 17 +-- image/png.c | 4 +- render/html_redraw.c | 1 + 20 files changed, 724 insertions(+), 423 deletions(-) create mode 100644 gtk/gdk.c create mode 100644 gtk/gdk.h 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 #include #include -#include -#include + +#include +#include #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 -#include +#include #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 + * + * 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 . + */ + +#include + +#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 + * + * 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 . + */ + +/** \file + * GDK support functions for missing interfaces + */ + +#ifndef NETSURF_GTK_GDK_H_ +#define NETSURF_GTK_GDK_H_ + +#include + +/** 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 #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 #include -#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; -- cgit v1.2.3