summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;