mirror of
https://github.com/netsurf-browser/netsurf
synced 2025-03-30 19:02:52 +03:00
Change GTK plotting to use cairo surfaces throughout
svn path=/trunk/netsurf/; revision=13354
This commit is contained in:
parent
4dd695c156
commit
df18a97143
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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 \
|
||||
|
342
gtk/bitmap.c
342
gtk/bitmap.c
@ -25,27 +25,17 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "content/content.h"
|
||||
#include "gtk/bitmap.h"
|
||||
#include "gtk/scaffolding.h"
|
||||
#include "gtk/bitmap.h"
|
||||
#include "image/bitmap.h"
|
||||
#include "utils/log.h"
|
||||
|
||||
|
||||
struct bitmap {
|
||||
GdkPixbuf *primary;
|
||||
GdkPixbuf *pretile_x;
|
||||
GdkPixbuf *pretile_y;
|
||||
GdkPixbuf *pretile_xy;
|
||||
bool opaque;
|
||||
};
|
||||
|
||||
#define MIN_PRETILE_WIDTH 256
|
||||
#define MIN_PRETILE_HEIGHT 256
|
||||
|
||||
|
||||
/**
|
||||
* Create a bitmap.
|
||||
@ -58,18 +48,24 @@ struct bitmap {
|
||||
|
||||
void *bitmap_create(int width, int height, unsigned int state)
|
||||
{
|
||||
struct bitmap *bmp = malloc(sizeof(struct bitmap));
|
||||
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;
|
||||
}
|
||||
|
14
gtk/bitmap.h
14
gtk/bitmap.h
@ -19,15 +19,13 @@
|
||||
#ifndef NS_GTK_BITMAP_H
|
||||
#define NS_GTK_BITMAP_H
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <cairo.h>
|
||||
#include "image/bitmap.h"
|
||||
|
||||
GdkPixbuf *gtk_bitmap_get_primary(struct bitmap*);
|
||||
GdkPixbuf *gtk_bitmap_get_pretile_x(struct bitmap*);
|
||||
GdkPixbuf *gtk_bitmap_get_pretile_y(struct bitmap*);
|
||||
GdkPixbuf *gtk_bitmap_get_pretile_xy(struct bitmap*);
|
||||
|
||||
|
||||
struct bitmap {
|
||||
cairo_surface_t *surface; /* original cairo surface */
|
||||
cairo_surface_t *scsurface; /* scaled surface */
|
||||
bool converted; /** set if the surface data has been converted */
|
||||
};
|
||||
|
||||
#endif /* NS_GTK_BITMAP_H */
|
||||
|
124
gtk/gdk.c
Normal file
124
gtk/gdk.c
Normal 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
35
gtk/gdk.h
Normal 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 */
|
123
gtk/plotters.c
123
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);
|
||||
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;
|
||||
|
201
gtk/print.c
201
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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
13
image/gif.c
13
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user