summaryrefslogtreecommitdiff
path: root/frontends/gtk
diff options
context:
space:
mode:
authorMichael Drake <michael.drake@codethink.co.uk>2017-04-26 12:33:57 +0100
committerMichael Drake <michael.drake@codethink.co.uk>2017-04-26 12:38:04 +0100
commit4b76d2096d4622fed8641b24f9dfe4ce782e307e (patch)
treec251948d8e6d776b2a9b4bf5704060701df37f98 /frontends/gtk
parent796bb0f652a5557f6903d96c6b7652a1565e6885 (diff)
downloadnetsurf-4b76d2096d4622fed8641b24f9dfe4ce782e307e.tar.gz
netsurf-4b76d2096d4622fed8641b24f9dfe4ce782e307e.tar.bz2
GTK: Optimise tiled bitmap plotting, and scaled bitmap rendering.
We now let Cairo deal with the tiling. Also we don't keep cached scaled bitmaps any more. The speedup for small bitmap tile sizes is huge.
Diffstat (limited to 'frontends/gtk')
-rw-r--r--frontends/gtk/plotters.c228
1 files changed, 79 insertions, 149 deletions
diff --git a/frontends/gtk/plotters.c b/frontends/gtk/plotters.c
index 2ed1d066a..c57b03294 100644
--- a/frontends/gtk/plotters.c
+++ b/frontends/gtk/plotters.c
@@ -485,132 +485,6 @@ nsgtk_plot_path(const struct redraw_context *ctx,
/**
- * plot a pixbuf
- *
- * \param x x coordinate to put pixmap
- * \param y y coordinate to put pixmap
- * \param width width of pixmap
- * \param height height of pixmap
- * \param bitmap The bitmap to plot
- * \param bg the background colour
- */
-static nserror
-nsgtk_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 NSERROR_OK;
- 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 NSERROR_OK;
- }
-
- /* 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 NSERROR_OK;
-
- 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(current_cr, bmsurface, x, y);
- cairo_rectangle(current_cr, dsrcx, dsrcy, dwidth, dheight);
- cairo_fill(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(current_cr, bitmap->scsurface, x, y);
- cairo_rectangle(current_cr, dsrcx, dsrcy, dwidth, dheight);
- cairo_fill(current_cr);
-
-
- }
-
- return NSERROR_OK;
-}
-
-
-/**
* Plot a bitmap
*
* Tiled plot of a bitmap image. (x,y) gives the top left
@@ -643,44 +517,100 @@ nsgtk_plot_bitmap(const struct redraw_context *ctx,
colour bg,
bitmap_flags_t flags)
{
- int doneheight = 0, donewidth = 0;
bool repeat_x = (flags & BITMAPF_REPEAT_X);
bool repeat_y = (flags & BITMAPF_REPEAT_Y);
+ GdkRectangle cliprect_bitmap;
+ cairo_surface_t *img_surface;
+ int img_width, img_height;
/* Bail early if we can */
- if (width == 0 || height == 0)
+ if (width <= 0 || height <= 0) {
/* Nothing to plot */
return NSERROR_OK;
+ }
- if (!(repeat_x || repeat_y)) {
- /* Not repeating at all, so just pass it on */
- return nsgtk_plot_pixbuf(x, y, width, height, bitmap, bg);
+ /* Copy the clip rectangle into bitmap plot clip rectangle */
+ cliprect_bitmap = cliprect;
+
+ /* Constrain bitmap plot rectangle for any lack of tiling */
+ if (!repeat_x) {
+ if (cliprect_bitmap.width > width) {
+ cliprect_bitmap.width = width;
+ }
+ if (cliprect_bitmap.x < x) {
+ cliprect_bitmap.x = x;
+ cliprect_bitmap.width -= x - cliprect_bitmap.x;
+ }
+ }
+ if (!repeat_y) {
+ if (cliprect_bitmap.height > height) {
+ cliprect_bitmap.height = height;
+ }
+ if (cliprect_bitmap.y < y) {
+ cliprect_bitmap.y = y;
+ cliprect_bitmap.height -= y - cliprect_bitmap.y;
+ }
}
- if (y > cliprect.y) {
- doneheight = (cliprect.y - height) + ((y - cliprect.y) % height);
- } else {
- doneheight = y;
+ /* Bail early if we can */
+ if (cliprect_bitmap.width <= 0 || cliprect_bitmap.height <= 0) {
+ /* Nothing to plot */
+ return NSERROR_OK;
}
- while (doneheight < (cliprect.y + cliprect.height)) {
- if (x > cliprect.x) {
- donewidth = (cliprect.x - width) + ((x - cliprect.x) % width);
- } else {
- donewidth = x;
+ /* Get the image's surface and intrinsic dimensions */
+ img_surface = bitmap->surface;
+ img_width = cairo_image_surface_get_width(img_surface);
+ img_height = cairo_image_surface_get_height(img_surface);
+
+ /* Set the source surface */
+ if ((img_width == width) && (img_height == height)) {
+ /* Non-scaled rendering */
+ cairo_set_source_surface(current_cr, img_surface, x, y);
+
+ /* Enable tiling if we're repeating */
+ if (repeat_x || repeat_y) {
+ cairo_pattern_set_extend(
+ cairo_get_source(current_cr),
+ CAIRO_EXTEND_REPEAT);
}
- while (donewidth < (cliprect.x + cliprect.width)) {
- nsgtk_plot_pixbuf(donewidth, doneheight,
- width, height, bitmap, bg);
- donewidth += width;
- if (!repeat_x)
- break;
+ /* Render the bitmap */
+ cairo_rectangle(current_cr,
+ cliprect_bitmap.x,
+ cliprect_bitmap.y,
+ cliprect_bitmap.width,
+ cliprect_bitmap.height);
+ cairo_fill(current_cr);
+ } else {
+ /* Scaled rendering */
+ double scale_x = (double)width / img_width;
+ double scale_y = (double)height / img_height;
+
+ /* Save cairo rendering context state before scaling */
+ cairo_save(current_cr);
+ cairo_scale(current_cr, scale_x, scale_y);
+
+ cairo_set_source_surface(current_cr, img_surface,
+ x / scale_x, y / scale_y);
+
+ /* Enable tiling if we're repeating */
+ if (repeat_x || repeat_y) {
+ cairo_pattern_set_extend(
+ cairo_get_source(current_cr),
+ CAIRO_EXTEND_REPEAT);
}
- doneheight += height;
- if (!repeat_y)
- break;
+ /* Render the bitmap */
+ cairo_rectangle(current_cr,
+ cliprect_bitmap.x / scale_x,
+ cliprect_bitmap.y / scale_y,
+ cliprect_bitmap.width / scale_x,
+ cliprect_bitmap.height / scale_y);
+ cairo_fill(current_cr);
+
+ /* Restore pre-scaling cairo rendering state */
+ cairo_restore(current_cr);
}
return NSERROR_OK;