Add render to bitmap operations and update gtk to provide it.

This commit is contained in:
Vincent Sanders 2015-04-22 23:13:24 +01:00
parent df3a889435
commit de98108e7f
3 changed files with 126 additions and 27 deletions

View File

@ -620,6 +620,10 @@ static nserror verify_bitmap_register(struct gui_bitmap_table *gbt)
return NSERROR_BAD_PARAMETER;
}
if (gbt->render == NULL) {
return NSERROR_BAD_PARAMETER;
}
return NSERROR_OK;
}

View File

@ -32,8 +32,11 @@
#include "utils/log.h"
#include "content/content.h"
#include "image/bitmap.h"
#include "desktop/plotters.h"
#include "desktop/thumbnail.h"
#include "gtk/scaffolding.h"
#include "gtk/plotters.h"
#include "gtk/bitmap.h"
@ -86,17 +89,17 @@ static void bitmap_set_opaque(void *vbitmap, bool opaque)
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),
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),
nsurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
cairo_image_surface_get_width(gbitmap->surface),
cairo_image_surface_get_height(gbitmap->surface));
}
@ -106,8 +109,8 @@ static void bitmap_set_opaque(void *vbitmap, bool opaque)
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),
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;
@ -116,7 +119,7 @@ static void bitmap_set_opaque(void *vbitmap, bool opaque)
}
}
}
}
@ -137,13 +140,13 @@ static bool bitmap_test_opaque(void *vbitmap)
pixels = cairo_image_surface_get_data(gbitmap->surface);
pcount = cairo_image_surface_get_stride(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;
@ -190,7 +193,7 @@ static unsigned char *bitmap_get_buffer(void *vbitmap)
cairo_format_t fmt;
assert(gbitmap);
cairo_surface_flush(gbitmap->surface);
pixels = cairo_image_surface_get_data(gbitmap->surface);
@ -259,7 +262,7 @@ static unsigned char *bitmap_get_buffer(void *vbitmap)
}
gbitmap->converted = false;
return (unsigned char *) pixels;
}
@ -341,7 +344,7 @@ static void bitmap_modified(void *vbitmap)
{
struct bitmap *gbitmap = (struct bitmap *)vbitmap;
int pixel_loop;
int pixel_count;
int pixel_count;
uint8_t *pixels;
uint32_t t, r, g, b;
cairo_format_t fmt;
@ -350,7 +353,7 @@ static void bitmap_modified(void *vbitmap)
fmt = cairo_image_surface_get_format(gbitmap->surface);
pixel_count = cairo_image_surface_get_width(gbitmap->surface) *
pixel_count = cairo_image_surface_get_width(gbitmap->surface) *
cairo_image_surface_get_height(gbitmap->surface);
pixels = cairo_image_surface_get_data(gbitmap->surface);
@ -411,7 +414,7 @@ static void bitmap_modified(void *vbitmap)
#endif
}
}
cairo_surface_mark_dirty(gbitmap->surface);
gbitmap->converted = true;
@ -435,6 +438,88 @@ int nsgtk_bitmap_get_height(void *vbitmap)
return cairo_image_surface_get_height(gbitmap->surface);
}
/**
* Render content into a bitmap.
*
* \param content content structure to thumbnail
* \param bitmap the bitmap to draw to
* \return true on success and bitmap updated else false
*/
static nserror
bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content)
{
cairo_surface_t *dsurface = bitmap->surface;
cairo_surface_t *surface;
cairo_t *old_cr;
gint dwidth, dheight;
int cwidth, cheight;
struct redraw_context ctx = {
.interactive = false,
.background_images = true,
.plot = &nsgtk_plotters
};
assert(content);
assert(bitmap);
dwidth = cairo_image_surface_get_width(dsurface);
dheight = cairo_image_surface_get_height(dsurface);
/* Calculate size of buffer to render the content into */
/* Get the width from the content width, unless it exceeds 1024,
* in which case we use 1024. This means we never create excessively
* large render buffers for huge contents, which would eat memory and
* cripple performance.
*/
cwidth = min(max(content_get_width(content), dwidth), 1024);
/* The height is set in proportion with the width, according to the
* aspect ratio of the required thumbnail. */
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;
}
old_cr = current_cr;
current_cr = cairo_create(surface);
/* render the content */
thumbnail_redraw(content, cwidth, cheight, &ctx);
cairo_destroy(current_cr);
current_cr = old_cr;
cairo_t *cr = cairo_create(dsurface);
/* Scale *before* setting the source surface (1) */
cairo_scale (cr, (double)dwidth / cwidth, (double)dheight / cheight);
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 (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);
cairo_surface_destroy(surface);
return NSERROR_OK;
}
static struct gui_bitmap_table bitmap_table = {
.create = bitmap_create,
.destroy = bitmap_destroy,
@ -448,6 +533,7 @@ static struct gui_bitmap_table bitmap_table = {
.get_bpp = bitmap_get_bpp,
.save = bitmap_save,
.modified = bitmap_modified,
.render = bitmap_render,
};
struct gui_bitmap_table *nsgtk_bitmap_table = &bitmap_table;

View File

@ -28,27 +28,27 @@
* For example, an opaque 1x1 pixel image would yield the following bitmap
* data:
*
* Red : 0xff 0x00 0x00 0x00
* Green: 0x00 0xff 0x00 0x00
* Blue : 0x00 0x00 0xff 0x00
* > Red : 0xff 0x00 0x00 0x00
* > Green: 0x00 0xff 0x00 0x00
* > Blue : 0x00 0x00 0xff 0x00
*
* Any attempt to read pixels by casting bitmap data to uint32_t or similar
* will need to cater for the order of bytes in a word being different on
* big and little endian systems. To avoid confusion, it is recommended
* that pixel data is loaded as follows:
*
* uint32_t read_pixel(const uint8_t *bmp)
* {
* // red green blue alpha
* return bmp[0] | (bmp[1] << 8) | (bmp[2] << 16) | (bmp[3] << 24);
* }
* uint32_t read_pixel(const uint8_t *bmp)
* {
* // red green blue alpha
* return bmp[0] | (bmp[1] << 8) | (bmp[2] << 16) | (bmp[3] << 24);
* }
*
* and *not* as follows:
*
* uint32_t read_pixel(const uint8_t *bmp)
* {
* return *((uint32_t *) bmp);
* }
* uint32_t read_pixel(const uint8_t *bmp)
* {
* return *((uint32_t *) bmp);
* }
*/
#ifndef _NETSURF_IMAGE_BITMAP_H_
@ -61,6 +61,7 @@
struct content;
struct bitmap;
struct hlcache_handle;
/**
* Bitmap operations.
@ -163,6 +164,14 @@ struct gui_bitmap_table {
* \param bitmap The bitmap set as modified.
*/
void (*modified)(void *bitmap);
/**
* Render content into a bitmap.
*
* \param bitmap The bitmap to render into.
* \param content The content to render.
*/
nserror (*render)(struct bitmap *bitmap, struct hlcache_handle *content);
};
#endif