poppler/CairoOutputDev.cc | 97 ++++++++++++++++++++++++++++------------------ poppler/CairoOutputDev.h | 6 +- 2 files changed, 65 insertions(+), 38 deletions(-)
New commits: commit 4bb34757dbbff780baba053371274c05b29771e1 Author: Adrian Johnson <[email protected]> Date: Mon Sep 19 21:11:44 2011 +0930 cairo: fix setSoftMask bugs - 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). - the ctm when called cairo_mask() needs to be the same as the ctm when the mask was created. - implement transfer function in setSoftMask Bug 41005 diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc index 30c69f1..fae0136 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 //------------------------------------------------------------------------ @@ -261,6 +266,7 @@ void CairoOutputDev::saveState(GfxState *state) { MaskStack *ms = new MaskStack; ms->mask = cairo_pattern_reference(mask); + ms->mask_matrix = mask_matrix; ms->next = maskStack; maskStack = ms; } @@ -284,6 +290,7 @@ void CairoOutputDev::restoreState(GfxState *state) { if (mask) cairo_pattern_destroy(mask); mask = ms->mask; + mask_matrix = ms->mask_matrix; maskStack = ms->next; delete ms; } @@ -410,8 +417,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; @@ -725,7 +730,10 @@ void CairoOutputDev::fill(GfxState *state) { //XXX: how do we get the path if (mask) { cairo_clip (cairo); + cairo_save (cairo); + cairo_set_matrix (cairo, &mask_matrix); cairo_mask (cairo, mask); + cairo_restore (cairo); } else if (strokePathClip) { fillToStrokePathClip(); } else { @@ -1477,7 +1485,10 @@ void CairoOutputDev::paintTransparencyGroup(GfxState * /*state*/, double * /*bbo if (status) printf("BAD status: %s\n", cairo_status_to_string(status)); } else { + cairo_save(cairo); + cairo_set_matrix(cairo, &mask_matrix); cairo_mask(cairo, mask); + cairo_restore(cairo); cairo_pattern_destroy(mask); mask = NULL; @@ -1486,14 +1497,14 @@ void CairoOutputDev::paintTransparencyGroup(GfxState * /*state*/, double * /*bbo popTransparencyGroup(); } -static uint32_t luminocity(uint32_t x) +static int luminocity(uint32_t x) { int r = (x >> 16) & 0xff; int g = (x >> 8) & 0xff; int b = (x >> 0) & 0xff; // an arbitrary integer approximation of .3*r + .59*g + .11*b int y = (r*19661+g*38666+b*7209 + 32829)>>16; - return y << 24; + return y; } @@ -1509,24 +1520,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 +1567,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 */ @@ -1569,37 +1591,37 @@ void CairoOutputDev::setSoftMask(GfxState * state, double * bbox, GBool alpha, int stride = cairo_image_surface_get_stride(source)/4; for (int y=0; y<height; y++) { for (int x=0; x<width; x++) { - source_data[y*stride + x] = luminocity(source_data[y*stride + x]); - -#if 0 - here is how splash deals with the transferfunction we should deal with this - at some point + int lum; + lum = luminocity(source_data[y*stride + x]); if (transferFunc) { - transferFunc->transform(&lum, &lum2); - } else { - lum2 = lum; + double lum_in, lum_out; + lum_in = lum/256.0; + transferFunc->transform(&lum_in, &lum_out); + lum = (int)(lum_out * 255.0 + 0.5); } - p[x] = (int)(lum2 * 255.0 + 0.5); -#endif - + source_data[y*stride + x] = lum << 24; } } cairo_surface_mark_dirty (source); /* setup the new mask pattern */ mask = cairo_pattern_create_for_surface(source); + cairo_get_matrix(cairo, &mask_matrix); if (cairo_get_group_target(cairo) == cairo_get_target(cairo)) { cairo_pattern_set_matrix(mask, &mat); } 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); } cairo_surface_destroy(source); } else { mask = cairo_pattern_reference(group); + cairo_get_matrix(cairo, &mask_matrix); } popTransparencyGroup(); @@ -1818,6 +1840,7 @@ void CairoOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, if (mask) cairo_pattern_destroy (mask); mask = cairo_pop_group (cairo); + cairo_get_matrix (cairo, &mask_matrix); } } @@ -1897,6 +1920,7 @@ void CairoOutputDev::drawImageMaskRegular(GfxState *state, Object *ref, Stream * if (state->getFillColorSpace()->getMode() == csPattern) { mask = cairo_pattern_reference (pattern); + cairo_get_matrix (cairo, &mask_matrix); } else if (!printing) { cairo_save (cairo); cairo_rectangle (cairo, 0., 0., 1., 1.); @@ -2169,6 +2193,7 @@ void CairoOutputDev::drawImageMaskPrescaled(GfxState *state, Object *ref, Stream } mask = cairo_pattern_reference (pattern); + cairo_get_matrix (cairo, &mask_matrix); } else { cairo_save (cairo); diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h index 0f202a5..949d459 100644 --- a/poppler/CairoOutputDev.h +++ b/poppler/CairoOutputDev.h @@ -341,6 +341,7 @@ protected: cairo_pattern_t *group; cairo_pattern_t *shape; cairo_pattern_t *mask; + cairo_matrix_t mask_matrix; cairo_surface_t *cairo_shape_surface; cairo_t *cairo_shape; int knockoutCount; @@ -351,8 +352,9 @@ protected: } * groupColorSpaceStack; struct MaskStack { - cairo_pattern_t *mask; - struct MaskStack *next; + cairo_pattern_t *mask; + cairo_matrix_t mask_matrix; + struct MaskStack *next; } *maskStack; GBool haveCSPattern; // set if text has been drawn with a _______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
