Change GTK plotting to use cairo surfaces throughout

svn path=/trunk/netsurf/; revision=13354
This commit is contained in:
Vincent Sanders 2011-12-30 00:58:35 +00:00
parent 4dd695c156
commit df18a97143
20 changed files with 721 additions and 420 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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
*/

View File

@ -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 \

View File

@ -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));
struct bitmap *gbitmap;
bmp->primary = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true,
8, width, height);
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);
}
/* 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;
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;
struct bitmap *gbitmap = (struct bitmap *)vbitmap;
assert(gbitmap);
gdk_pixbuf_save(bitmap->primary, path, "png", &err, NULL);
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);
struct bitmap *gbitmap = (struct bitmap *)vbitmap;
assert(gbitmap);
return cairo_image_surface_get_width(gbitmap->surface);
}
int bitmap_get_height(void *vbitmap){
struct bitmap *bitmap = (struct bitmap *)vbitmap;
return gdk_pixbuf_get_height(bitmap->primary);
struct bitmap *gbitmap = (struct bitmap *)vbitmap;
assert(gbitmap);
return cairo_image_surface_get_height(gbitmap->surface);
}
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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}

View File

@ -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 */

124
gtk/gdk.c Normal file
View File

@ -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;
}

35
gtk/gdk.h Normal file
View File

@ -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 */

View File

@ -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);
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;
}
/* 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) {
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);
/* Bail early if we can */
if (width == 0 || height == 0)
/* Nothing to plot */
return true;
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);
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;

View File

@ -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;

View File

@ -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)

View File

@ -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,56 +75,54 @@ 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;
cheight = ((cwidth * dheight) + (dwidth / 2)) / dwidth;
/* 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.
*/
/* 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;
/* 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);
cairo_t *cr = cairo_create(dsurface);
/* 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);
/* 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);
/* register the thumbnail with the URL */
if (url)
urldb_set_thumbnail(url, bitmap);
bitmap_modified(bitmap);
cairo_destroy(current_cr);
g_object_unref(pixmap);
g_object_unref(big);
return true;
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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;