From ea8d9c9bcdeb48f41d1921183e86426f4857aae6 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Mon, 19 Sep 2011 21:11:44 +0930 Subject: [PATCH] cairo: fix setSoftMask to work with rotated or translated ctm - Getting the clip extents in device space requires transforming all four corners of the clip extents and translating by the group device offset other wise the device extents will not be correct for rotated ctm. - Adjust matrix to include translation of the clip extents origin since the mask surface does not start at (0,0). --- poppler/CairoOutputDev.cc | 62 ++++++++++++++++++++++++++++---------------- 1 files changed, 39 insertions(+), 23 deletions(-) diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc index 30c69f1..6cb69a2 100644 --- a/poppler/CairoOutputDev.cc +++ b/poppler/CairoOutputDev.cc @@ -78,6 +78,11 @@ static inline void printMatrix(cairo_matrix_t *matrix){ matrix->x0, matrix->y0); } + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + + //------------------------------------------------------------------------ // CairoImage //------------------------------------------------------------------------ @@ -410,8 +415,6 @@ void CairoOutputDev::updateMiterLimit(GfxState *state) { cairo_set_miter_limit (cairo_shape, state->getMiterLimit()); } -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) - void CairoOutputDev::updateLineWidth(GfxState *state) { LOG(printf ("line width: %f\n", state->getLineWidth())); adjusted_stroke_width = gFalse; @@ -1509,24 +1512,39 @@ void CairoOutputDev::setSoftMask(GfxState * state, double * bbox, GBool alpha, * So we paint the group to an image surface convert it to a luminocity map * and then use that as the mask. */ - double x1, y1, x2, y2, tmp; + /* Get clip extents in device space */ + double x1, y1, x2, y2, x_min, y_min, x_max, y_max; cairo_clip_extents(cairo, &x1, &y1, &x2, &y2); cairo_user_to_device(cairo, &x1, &y1); cairo_user_to_device(cairo, &x2, &y2); - if (x1 > x2) { - tmp = x1; - x1 = x2; - x2 = tmp; - } + x_min = MIN(x1, x2); + y_min = MIN(y1, y2); + x_max = MAX(x1, x2); + y_max = MAX(y1, y2); + cairo_clip_extents(cairo, &x1, &y1, &x2, &y2); + cairo_user_to_device(cairo, &x1, &y2); + cairo_user_to_device(cairo, &x2, &y1); + x_min = MIN(x_min,MIN(x1, x2)); + y_min = MIN(y_min,MIN(y1, y2)); + x_max = MAX(x_max,MAX(x1, x2)); + y_max = MAX(y_max,MAX(y1, y2)); + + int width = (int)(ceil(x_max) - floor(x_min)); + int height = (int)(ceil(y_max) - floor(y_min)); - if (y1 > y2) { - tmp = y1; - y1 = y2; - y2 = tmp; + /* Get group device offset */ + double x_offset, y_offset; + if (cairo_get_group_target(cairo) == cairo_get_target(cairo)) { + cairo_surface_get_device_offset(cairo_get_group_target(cairo), &x_offset, &y_offset); + } else { + cairo_surface_t *pats; + cairo_pattern_get_surface(group, &pats); + cairo_surface_get_device_offset(pats, &x_offset, &y_offset); } - int width = (int)(ceil(x2) - floor(x1)); - int height = (int)(ceil(y2) - floor(y1)); + /* Adjust extents by group offset */ + x_min += x_offset; + y_min += y_offset; cairo_surface_t *source = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *maskCtx = cairo_create(source); @@ -1541,19 +1559,15 @@ void CairoOutputDev::setSoftMask(GfxState * state, double * bbox, GBool alpha, colToDbl(backdropColorRGB.b)); cairo_paint(maskCtx); - cairo_matrix_t mat; + /* Copy source ctm to mask ctm and translate origin so that the + * mask appears it the same location on the source surface. */ + cairo_matrix_t mat, tmat; + cairo_matrix_init_translate(&tmat, -x_min, -y_min); cairo_get_matrix(cairo, &mat); + cairo_matrix_multiply(&mat, &mat, &tmat); cairo_set_matrix(maskCtx, &mat); /* make the device offset of the new mask match that of the group */ - double x_offset, y_offset; - if (cairo_get_group_target(cairo) == cairo_get_target(cairo)) { - cairo_surface_get_device_offset(cairo_get_group_target(cairo), &x_offset, &y_offset); - } else { - cairo_surface_t *pats; - cairo_pattern_get_surface(group, &pats); - cairo_surface_get_device_offset(pats, &x_offset, &y_offset); - } cairo_surface_set_device_offset(source, x_offset, y_offset); /* paint the group */ @@ -1594,6 +1608,8 @@ void CairoOutputDev::setSoftMask(GfxState * state, double * bbox, GBool alpha, } else { cairo_matrix_t patMatrix; cairo_pattern_get_matrix(group, &patMatrix); + /* Apply x_min, y_min offset to it appears in the same location as source. */ + cairo_matrix_multiply(&patMatrix, &patMatrix, &tmat); cairo_pattern_set_matrix(mask, &patMatrix); } -- 1.7.4.1