summaryrefslogtreecommitdiff
path: root/source/fitz/pixmap.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2017-10-25 12:10:24 +0100
committerRobin Watts <robin.watts@artifex.com>2017-10-25 18:02:04 +0100
commitec07e5377383b36a9fe714a1ad15b70b5df8a4a3 (patch)
tree4fc30442410f7147f1447bd3e75bf96b4c6822b1 /source/fitz/pixmap.c
parent88f009ec79eb9b5d5773d7073523cb0aaaef6303 (diff)
downloadmupdf-ec07e5377383b36a9fe714a1ad15b70b5df8a4a3.tar.xz
Fix multithreaded crash with tiled regions.
Michael has found a crash when scrolling quickly through pages with gsview. 2 Threads are redrawing at the same time from a display list. The problem comes when both threads happen to be trying to draw the same tile from the cache at the same time. The current code alters the ->{x,y} values of the pixmap from the cache as it tiles. If 2 threads are using the same tile at the same time, this causes a race condition which can upset the clipping calculations and we can access out of range. The solution is to make a new 'wrapper' fz_pixmap around the same data, and to alter the x/y values there instead. We therefore introduce a (hopefully generally useful) function fz_new_pixmap_from_pixmap, and use that.
Diffstat (limited to 'source/fitz/pixmap.c')
-rw-r--r--source/fitz/pixmap.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/source/fitz/pixmap.c b/source/fitz/pixmap.c
index 4e3f62cb..93f8fed6 100644
--- a/source/fitz/pixmap.c
+++ b/source/fitz/pixmap.c
@@ -26,6 +26,7 @@ fz_drop_pixmap_imp(fz_context *ctx, fz_storable *pix_)
fz_drop_separations(ctx, pix->seps);
if (pix->flags & FZ_PIXMAP_FLAG_FREE_SAMPLES)
fz_free(ctx, pix->samples);
+ fz_drop_pixmap(ctx, pix->underlying);
fz_free(ctx, pix);
}
@@ -126,6 +127,40 @@ fz_new_pixmap_with_bbox_and_data(fz_context *ctx, fz_colorspace *colorspace, con
return pixmap;
}
+fz_pixmap *fz_new_pixmap_from_pixmap(fz_context *ctx, fz_pixmap *pixmap, const fz_irect *rect)
+{
+ fz_irect local_rect;
+ fz_pixmap *subpix;
+
+ if (!pixmap)
+ return NULL;
+
+ if (rect == NULL)
+ {
+ rect = &local_rect;
+ local_rect.x0 = pixmap->x;
+ local_rect.y0 = pixmap->y;
+ local_rect.x1 = pixmap->x + pixmap->w;
+ local_rect.y1 = pixmap->y + pixmap->h;
+ }
+ else if (rect->x0 < pixmap->x || rect->y0 < pixmap->y || rect->x1 > pixmap->x + pixmap->w || rect->y1 > pixmap->y + pixmap->h)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Pixmap region is not a subarea");
+
+ subpix = fz_malloc_struct(ctx, fz_pixmap);
+ *subpix = *pixmap;
+ subpix->x = rect->x0;
+ subpix->y = rect->y0;
+ subpix->w = rect->x1 - rect->x0;
+ subpix->h = rect->y1 - rect->y0;
+ subpix->samples += (rect->x0 - pixmap->x) + (rect->y0 - pixmap->y) * pixmap->stride;
+ subpix->underlying = fz_keep_pixmap(ctx, pixmap);
+ subpix->colorspace = fz_keep_colorspace(ctx, pixmap->colorspace);
+ subpix->seps = fz_keep_separations(ctx, pixmap->seps);
+ subpix->flags &= ~FZ_PIXMAP_FLAG_FREE_SAMPLES;
+
+ return subpix;
+}
+
fz_irect *
fz_pixmap_bbox(fz_context *ctx, const fz_pixmap *pix, fz_irect *bbox)
{