NetSurf
bitmap.c
Go to the documentation of this file.
1/*
2 * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/**
20 * \file
21 * GTK bitmap handling.
22 *
23 * This implements the bitmap interface using cairo image surfaces
24 */
25
26#include <assert.h>
27#include <stdbool.h>
28#include <string.h>
29#include <stdlib.h>
30#include <cairo.h>
31#include <gtk/gtk.h>
32
33#include "utils/utils.h"
34#include "utils/errors.h"
35#include "netsurf/content.h"
36#include "netsurf/bitmap.h"
37#include "netsurf/plotters.h"
38
39#include "gtk/scaffolding.h"
40#include "gtk/plotters.h"
41#include "gtk/bitmap.h"
42
43
44/**
45 * Create a bitmap.
46 *
47 * \param width width of image in pixels
48 * \param height height of image in pixels
49 * \param flags flags for bitmap creation
50 * \return an opaque struct bitmap, or NULL on memory exhaustion
51 */
52static void *bitmap_create(int width, int height, enum gui_bitmap_flags flags)
53{
54 struct bitmap *gbitmap;
55
56 if (width == 0 || height == 0) {
57 return NULL;
58 }
59
60 gbitmap = calloc(1, sizeof(struct bitmap));
61 if (gbitmap != NULL) {
62 if (flags & BITMAP_OPAQUE) {
63 gbitmap->opaque = true;
64 }
65
66 gbitmap->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
67 if (cairo_surface_status(gbitmap->surface) != CAIRO_STATUS_SUCCESS) {
68 cairo_surface_destroy(gbitmap->surface);
69 free(gbitmap);
70 gbitmap = NULL;
71 }
72 }
73
74 return gbitmap;
75}
76
77
78/**
79 * Sets whether a bitmap should be plotted opaque
80 *
81 * \param vbitmap a bitmap, as returned by bitmap_create()
82 * \param opaque whether the bitmap should be plotted opaque
83 */
84static void bitmap_set_opaque(void *vbitmap, bool opaque)
85{
86 struct bitmap *gbitmap = (struct bitmap *)vbitmap;
87
88 gbitmap->opaque = opaque;
89}
90
91
92/**
93 * Gets whether a bitmap should be plotted opaque
94 *
95 * \param vbitmap a bitmap, as returned by bitmap_create()
96 */
97static bool bitmap_get_opaque(void *vbitmap)
98{
99 struct bitmap *gbitmap = (struct bitmap *)vbitmap;
100
101 return gbitmap->opaque;
102}
103
104
105/**
106 * Return a pointer to the pixel data in a bitmap.
107 *
108 * \param vbitmap a bitmap, as returned by bitmap_create()
109 * \return pointer to the pixel buffer
110 *
111 * The pixel data is packed as BITMAP_FORMAT, possibly with padding at the end
112 * of rows. The width of a row in bytes is given by bitmap_get_rowstride().
113 */
114static unsigned char *bitmap_get_buffer(void *vbitmap)
115{
116 struct bitmap *gbitmap = (struct bitmap *)vbitmap;
117 uint8_t *pixels;
118
119 assert(gbitmap);
120
121 cairo_surface_flush(gbitmap->surface);
122 pixels = cairo_image_surface_get_data(gbitmap->surface);
123
124 return (unsigned char *) pixels;
125}
126
127
128/**
129 * Find the width of a pixel row in bytes.
130 *
131 * \param vbitmap a bitmap, as returned by bitmap_create()
132 * \return width of a pixel row in the bitmap
133 */
134static size_t bitmap_get_rowstride(void *vbitmap)
135{
136 struct bitmap *gbitmap = (struct bitmap *)vbitmap;
137 assert(gbitmap);
138
139 return cairo_image_surface_get_stride(gbitmap->surface);
140}
141
142
143/**
144 * Free a bitmap.
145 *
146 * \param vbitmap a bitmap, as returned by bitmap_create()
147 */
148static void bitmap_destroy(void *vbitmap)
149{
150 struct bitmap *gbitmap = (struct bitmap *)vbitmap;
151 assert(gbitmap);
152
153 if (gbitmap->surface != NULL) {
154 cairo_surface_destroy(gbitmap->surface);
155 }
156 if (gbitmap->scsurface != NULL) {
157 cairo_surface_destroy(gbitmap->scsurface);
158 }
159 free(gbitmap);
160}
161
162
163/**
164 * The bitmap image has changed, so flush any persistant cache.
165 *
166 * \param vbitmap a bitmap, as returned by bitmap_create()
167 */
168static void bitmap_modified(void *vbitmap)
169{
170 struct bitmap *gbitmap = (struct bitmap *)vbitmap;
171
172 assert(gbitmap);
173
174 cairo_surface_mark_dirty(gbitmap->surface);
175}
176
177/* exported interface documented in gtk/bitmap.h */
178int nsgtk_bitmap_get_width(void *vbitmap)
179{
180 struct bitmap *gbitmap = (struct bitmap *)vbitmap;
181 assert(gbitmap);
182
183 return cairo_image_surface_get_width(gbitmap->surface);
184}
185
186/* exported interface documented in gtk/bitmap.h */
187int nsgtk_bitmap_get_height(void *vbitmap)
188{
189 struct bitmap *gbitmap = (struct bitmap *)vbitmap;
190 assert(gbitmap);
191
192 return cairo_image_surface_get_height(gbitmap->surface);
193}
194
195/**
196 * Render content into a bitmap.
197 *
198 * \param bitmap The bitmap to draw to
199 * \param content The content to render
200 * \return true on success and bitmap updated else false
201 */
202static nserror
204{
205 cairo_surface_t *dsurface = bitmap->surface;
206 cairo_surface_t *surface;
207 cairo_t *old_cr;
208 gint dwidth, dheight;
209 int cwidth, cheight;
210 struct redraw_context ctx = {
211 .interactive = false,
212 .background_images = true,
213 .plot = &nsgtk_plotters
214 };
215
216 assert(content);
217 assert(bitmap);
218
219 dwidth = cairo_image_surface_get_width(dsurface);
220 dheight = cairo_image_surface_get_height(dsurface);
221
222 /* Calculate size of buffer to render the content into */
223 /* Get the width from the content width, unless it exceeds 1024,
224 * in which case we use 1024. This means we never create excessively
225 * large render buffers for huge contents, which would eat memory and
226 * cripple performance.
227 */
228 cwidth = min(max(content_get_width(content), dwidth), 1024);
229
230 /* The height is set in proportion with the width, according to the
231 * aspect ratio of the required thumbnail. */
232 cheight = ((cwidth * dheight) + (dwidth / 2)) / dwidth;
233
234 /* At this point, we MUST have decided to render something non-zero sized */
235 assert(cwidth > 0);
236 assert(cheight > 0);
237
238 /* Create surface to render into */
239 surface = cairo_surface_create_similar(dsurface, CAIRO_CONTENT_COLOR_ALPHA, cwidth, cheight);
240
241 if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
242 cairo_surface_destroy(surface);
243 return false;
244 }
245
246 old_cr = current_cr;
247 current_cr = cairo_create(surface);
248
249 /* render the content */
250 content_scaled_redraw(content, cwidth, cheight, &ctx);
251
252 cairo_destroy(current_cr);
253 current_cr = old_cr;
254
255 cairo_t *cr = cairo_create(dsurface);
256
257 /* Scale *before* setting the source surface (1) */
258 cairo_scale (cr, (double)dwidth / cwidth, (double)dheight / cheight);
259 cairo_set_source_surface (cr, surface, 0, 0);
260
261 /* To avoid getting the edge pixels blended with 0 alpha,
262 * which would occur with the default EXTEND_NONE. Use
263 * EXTEND_PAD for 1.2 or newer (2)
264 */
265 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REFLECT);
266
267 /* Replace the destination with the source instead of overlaying */
268 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
269
270 /* Do the actual drawing */
271 cairo_paint(cr);
272
273 cairo_destroy(cr);
274
275 cairo_surface_destroy(surface);
276
277 return NSERROR_OK;
278}
279
280
283 .destroy = bitmap_destroy,
284 .set_opaque = bitmap_set_opaque,
285 .get_opaque = bitmap_get_opaque,
286 .get_buffer = bitmap_get_buffer,
287 .get_rowstride = bitmap_get_rowstride,
288 .get_width = nsgtk_bitmap_get_width,
289 .get_height = nsgtk_bitmap_get_height,
290 .modified = bitmap_modified,
291 .render = bitmap_render,
292};
293
Error codes.
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_OK
No error.
Definition: errors.h:30
static void bitmap_set_opaque(void *vbitmap, bool opaque)
Sets whether a bitmap should be plotted opaque.
Definition: bitmap.c:84
static struct gui_bitmap_table bitmap_table
Definition: bitmap.c:281
static void bitmap_modified(void *vbitmap)
The bitmap image has changed, so flush any persistant cache.
Definition: bitmap.c:168
static bool bitmap_get_opaque(void *vbitmap)
Gets whether a bitmap should be plotted opaque.
Definition: bitmap.c:97
static nserror bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content)
Render content into a bitmap.
Definition: bitmap.c:203
struct gui_bitmap_table * nsgtk_bitmap_table
Definition: bitmap.c:294
int nsgtk_bitmap_get_height(void *vbitmap)
Definition: bitmap.c:187
static unsigned char * bitmap_get_buffer(void *vbitmap)
Return a pointer to the pixel data in a bitmap.
Definition: bitmap.c:114
static size_t bitmap_get_rowstride(void *vbitmap)
Find the width of a pixel row in bytes.
Definition: bitmap.c:134
static void * bitmap_create(int width, int height, enum gui_bitmap_flags flags)
Create a bitmap.
Definition: bitmap.c:52
int nsgtk_bitmap_get_width(void *vbitmap)
Definition: bitmap.c:178
static void bitmap_destroy(void *vbitmap)
Free a bitmap.
Definition: bitmap.c:148
Target independent plotting GTK+ interface.
const struct plotter_table nsgtk_plotters
GTK plotter table.
Definition: plotters.c:647
cairo_t * current_cr
Definition: plotters.c:42
Generic bitmap handling interface.
gui_bitmap_flags
Bitmap creation flags.
Definition: bitmap.h:36
@ BITMAP_OPAQUE
image is opaque
Definition: bitmap.h:38
Public content interface.
int content_get_width(struct hlcache_handle *h)
Retrieve width of content.
Definition: content.c:1158
bool content_scaled_redraw(struct hlcache_handle *h, int width, int height, const struct redraw_context *ctx)
Redraw a content with scale set for horizontal fit.
Definition: content.c:583
Target independent plotting interface.
int width
Definition: gui.c:160
int height
Definition: gui.c:161
Interface to utility string handling.
RISC OS wimp toolkit bitmap.
Definition: bitmap.c:68
cairo_surface_t * surface
Definition: bitmap.h:27
cairo_surface_t * scsurface
Definition: bitmap.h:28
bool opaque
Whether the bitmap is opaque.
Definition: bitmap.c:74
Content which corresponds to a single URL.
Bitmap operations.
Definition: bitmap.h:125
void *(* create)(int width, int height, enum gui_bitmap_flags flags)
Create a new bitmap.
Definition: bitmap.h:136
High-level cache handle.
Definition: hlcache.c:66
Redraw context.
Definition: plotters.h:51
bool interactive
Redraw to show interactive features.
Definition: plotters.h:59
Interface to a number of general purpose functionality.
#define min(x, y)
Definition: utils.h:46
#define max(x, y)
Definition: utils.h:50