From efd1df2bbd79b64c89b0bb7a91bd0334e97aee6d 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 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 | 44 +++++++++++++++++++++++++++----------------- 1 files changed, 27 insertions(+), 17 deletions(-) diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc index 30c69f1..e320cf6 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,25 @@ 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; - } - - if (y1 > y2) { - tmp = y1; - y1 = y2; - y2 = 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(x2) - floor(x1)); - int height = (int)(ceil(y2) - floor(y1)); + int width = (int)(ceil(x_max) - floor(x_min)); + int height = (int)(ceil(y_max) - floor(y_min)); cairo_surface_t *source = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *maskCtx = cairo_create(source); @@ -1541,8 +1545,12 @@ 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 */ @@ -1594,6 +1602,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