From d7492d70eee04f01e407b9813a2895b1e1223363 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 19 Aug 2011 23:23:24 +0930 Subject: [PATCH] cairo: fix stroke patterns Since cairo still does not yet have cairo_stroke_to_path(), this implements a workaround for stroke patterns. In clipToStrokePath, the stroke path and stroke parameters are saved. In tilingPatternFill and fill (used to draw shading patterns) if a stroke path clip has been saved, the current pattern is stroked instead of filled using the saved stroke. --- poppler/CairoOutputDev.cc | 52 ++++++++++++++++++++++++++++++++++++++++++++- poppler/CairoOutputDev.h | 17 +++++++++++++- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc index a19160d..114959b 100644 --- a/poppler/CairoOutputDev.cc +++ b/poppler/CairoOutputDev.cc @@ -132,6 +132,7 @@ CairoOutputDev::CairoOutputDev() { stroke_opacity = 1.0; fill_opacity = 1.0; textClipPath = NULL; + strokePathClip = NULL; haveCSPattern = gFalse; cairo = NULL; currentFont = NULL; @@ -667,6 +668,8 @@ void CairoOutputDev::fill(GfxState *state) { if (mask) { cairo_clip (cairo); cairo_mask (cairo, mask); + } else if (strokePathClip) { + fillToStrokePathClip(); } else { cairo_fill (cairo); } @@ -707,6 +710,7 @@ GBool CairoOutputDev::tilingPatternFill(GfxState *state, Catalog *cat, Object *s double xMin, yMin, xMax, yMax; double width, height; int surface_width, surface_height; + StrokePathClip *strokePathTmp; width = bbox[2] - bbox[0]; height = bbox[3] - bbox[1]; @@ -730,9 +734,12 @@ GBool CairoOutputDev::tilingPatternFill(GfxState *state, Catalog *cat, Object *s box.x1 = bbox[0]; box.y1 = bbox[1]; box.x2 = bbox[2]; box.y2 = bbox[3]; + strokePathTmp = strokePathClip; + strokePathClip = NULL; gfx = new Gfx(xref, this, resDict, catalog, &box, NULL); gfx->display(str); delete gfx; + strokePathClip = strokePathTmp; pattern = cairo_pattern_create_for_surface (cairo_get_target (cairo)); cairo_destroy (cairo); @@ -750,7 +757,11 @@ GBool CairoOutputDev::tilingPatternFill(GfxState *state, Catalog *cat, Object *s cairo_transform (cairo, &matrix); cairo_set_source (cairo, pattern); cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); - cairo_fill (cairo); + if (strokePathClip) { + fillToStrokePathClip(); + } else { + cairo_fill (cairo); + } cairo_pattern_destroy (pattern); @@ -981,6 +992,45 @@ void CairoOutputDev::eoClip(GfxState *state) { void CairoOutputDev::clipToStrokePath(GfxState *state) { LOG(printf("clip-to-stroke-path\n")); + strokePathClip = (StrokePathClip*)gmalloc (sizeof(*strokePathClip)); + doPath (cairo, state, state->getPath()); + strokePathClip->path = cairo_copy_path (cairo); + cairo_get_matrix (cairo, &strokePathClip->ctm); + strokePathClip->line_width = cairo_get_line_width (cairo); + strokePathClip->dash_count = cairo_get_dash_count (cairo); + if (strokePathClip->dash_count) { + strokePathClip->dashes = (double*) gmallocn (sizeof(double), strokePathClip->dash_count); + cairo_get_dash (cairo, strokePathClip->dashes, &strokePathClip->dash_offset); + } else { + strokePathClip->dashes = NULL; + } + strokePathClip->cap = cairo_get_line_cap (cairo); + strokePathClip->join = cairo_get_line_join (cairo); + strokePathClip->mitre = cairo_get_miter_limit (cairo); +} + +void CairoOutputDev::fillToStrokePathClip() { + cairo_save (cairo); + + cairo_set_matrix (cairo, &strokePathClip->ctm); + cairo_set_line_width (cairo, strokePathClip->line_width); + strokePathClip->dash_count = cairo_get_dash_count (cairo); + cairo_set_dash (cairo, strokePathClip->dashes, strokePathClip->dash_count, strokePathClip->dash_offset); + cairo_set_line_cap (cairo, strokePathClip->cap); + cairo_set_line_join (cairo, strokePathClip->join); + cairo_set_miter_limit (cairo, strokePathClip->mitre); + + cairo_new_path (cairo); + cairo_append_path (cairo, strokePathClip->path); + cairo_stroke (cairo); + + cairo_restore (cairo); + + cairo_path_destroy (strokePathClip->path); + if (strokePathClip->dashes) + gfree (strokePathClip->dashes); + gfree (strokePathClip); + strokePathClip = NULL; } void CairoOutputDev::beginString(GfxState *state, GooString *s) diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h index 67f7810..c71d86c 100644 --- a/poppler/CairoOutputDev.h +++ b/poppler/CairoOutputDev.h @@ -281,13 +281,26 @@ protected: GBool interpolate); GBool getStreamData (Stream *str, char **buffer, int *length); void setMimeData(Stream *str, Object *ref, cairo_surface_t *image); - + void fillToStrokePathClip(); + GfxRGB fill_color, stroke_color; cairo_pattern_t *fill_pattern, *stroke_pattern; double fill_opacity; double stroke_opacity; CairoFont *currentFont; - + + struct StrokePathClip { + cairo_path_t *path; + cairo_matrix_t ctm; + double line_width; + double *dashes; + int dash_count; + double dash_offset; + cairo_line_cap_t cap; + cairo_line_join_t join; + double mitre; + } *strokePathClip; + XRef *xref; // xref table for current document Catalog *catalog; -- 1.7.4.1