diff options
-rw-r--r-- | xps/ghostxps.h | 21 | ||||
-rw-r--r-- | xps/xpsglyphs.c | 9 | ||||
-rw-r--r-- | xps/xpsgradient.c | 23 | ||||
-rw-r--r-- | xps/xpsimage.c | 6 | ||||
-rw-r--r-- | xps/xpsopacity.c | 9 | ||||
-rw-r--r-- | xps/xpspage.c | 33 | ||||
-rw-r--r-- | xps/xpspath.c | 155 | ||||
-rw-r--r-- | xps/xpstile.c | 21 |
8 files changed, 233 insertions, 44 deletions
diff --git a/xps/ghostxps.h b/xps/ghostxps.h index 50613bb54..c0ee53f16 100644 --- a/xps/ghostxps.h +++ b/xps/ghostxps.h @@ -52,6 +52,16 @@ #define dpf #endif +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a,b) ((a) < (b) ? (b) : (a)) +#endif +#ifndef ABS +#define ABS(a) ((a) < 0 ? -(a) : (a)) +#endif + /* * Forward declarations. */ @@ -178,6 +188,13 @@ struct xps_context_s * 1=nonzero, 0=evenodd */ int fill_rule; + + /* We often need the bounding box for the current + * area of the page affected by drawing operations. + * We keep these bounds updated every time we + * clip. The coordinates are in device space. + */ + gs_rect bounds; }; struct xps_part_s @@ -323,8 +340,10 @@ int xps_parse_brush(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *node); int xps_parse_element(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *node); void xps_set_color(xps_context_t *ctx, float *argb); -int xps_clip(xps_context_t *ctx); +int xps_clip(xps_context_t *ctx, gs_rect *saved_bounds); +int xps_unclip(xps_context_t *ctx, gs_rect *saved_bounds); int xps_fill(xps_context_t *ctx); +void xps_bounds_in_user_space(xps_context_t *ctx, gs_rect *user); /* * Static XML resources. diff --git a/xps/xpsglyphs.c b/xps/xpsglyphs.c index 15da97a25..d7ca80140 100644 --- a/xps/xpsglyphs.c +++ b/xps/xpsglyphs.c @@ -458,6 +458,8 @@ xps_parse_glyphs(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *root) int is_sideways = 0; int bidi_level = 0; + gs_rect saved_bounds; + /* * Extract attributes and extended attributes. */ @@ -578,7 +580,7 @@ xps_parse_glyphs(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *root) if (clip_tag) xps_parse_path_geometry(ctx, dict, clip_tag); - xps_clip(ctx); + xps_clip(ctx, &saved_bounds); } font_size = atof(font_size_att); @@ -631,6 +633,11 @@ xps_parse_glyphs(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *root) gs_grestore(ctx->pgs); + if (clip_att || clip_tag) + { + xps_unclip(ctx, &saved_bounds); + } + return 0; } diff --git a/xps/xpsgradient.c b/xps/xpsgradient.c index 18747e7f4..fbbfa47cb 100644 --- a/xps/xpsgradient.c +++ b/xps/xpsgradient.c @@ -224,7 +224,6 @@ xps_draw_one_radial_gradient(xps_context_t *ctx, gs_shading_t *shading; gs_shading_R_params_t params; gs_color_space *colorspace; - gs_fixed_rect rect; int code; gs_shading_R_params_init(¶ms); @@ -252,11 +251,6 @@ xps_draw_one_radial_gradient(xps_context_t *ctx, if (code < 0) return gs_throw(-1, "gs_shading_R_init failed"); - rect.p.x = int2fixed(-10000); - rect.p.y = int2fixed(-10000); - rect.q.x = int2fixed(10000); - rect.q.y = int2fixed(10000); - code = gs_shfill(ctx->pgs, shading); if (code < 0) { @@ -282,7 +276,6 @@ xps_draw_one_linear_gradient(xps_context_t *ctx, gs_shading_t *shading; gs_shading_A_params_t params; gs_color_space *colorspace; - gs_fixed_rect rect; int code; gs_shading_A_params_init(¶ms); @@ -308,11 +301,6 @@ xps_draw_one_linear_gradient(xps_context_t *ctx, if (code < 0) return gs_throw(-1, "gs_shading_A_init failed"); - rect.p.x = int2fixed(-10000); - rect.p.y = int2fixed(-10000); - rect.q.x = int2fixed(10000); - rect.q.y = int2fixed(10000); - code = gs_shfill(ctx->pgs, shading); if (code < 0) { @@ -480,6 +468,8 @@ xps_parse_gradient_brush(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *r gs_matrix transform; int spread_method; + gs_rect saved_bounds; + gs_function_t *color_func; gs_function_t *opacity_func; int has_opacity = 0; @@ -538,7 +528,7 @@ xps_parse_gradient_brush(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *r has_opacity = xps_gradient_has_transparent_colors(stop_offsets, stop_colors, stop_count); - xps_clip(ctx); + xps_clip(ctx, &saved_bounds); gs_gsave(ctx->pgs); @@ -558,11 +548,7 @@ xps_parse_gradient_brush(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *r gs_transparency_group_params_t tgp; gs_rect bbox; - /* ahem. FIXME. */ - bbox.p.x = 0; - bbox.p.y = 0; - bbox.q.x = 1000; - bbox.q.y = 1000; + xps_bounds_in_user_space(ctx, &bbox); gs_trans_mask_params_init(¶ms, TRANSPARENCY_MASK_Alpha); gs_begin_transparency_mask(ctx->pgs, ¶ms, &bbox, 0); @@ -584,6 +570,7 @@ xps_parse_gradient_brush(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *r gs_grestore(ctx->pgs); + xps_unclip(ctx, &saved_bounds); xps_free_gradient_stop_function(ctx, opacity_func); xps_free_gradient_stop_function(ctx, color_func); diff --git a/xps/xpsimage.c b/xps/xpsimage.c index 88f9fbfda..8931093c4 100644 --- a/xps/xpsimage.c +++ b/xps/xpsimage.c @@ -224,11 +224,7 @@ xps_paint_image_brush(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *root dputs("xps_paint_image_brush with alpha channel\n"); - /* ahem. FIXME. */ - bbox.p.x = 0; - bbox.p.y = 0; - bbox.q.x = 1000; - bbox.q.y = 1000; + xps_bounds_in_user_space(ctx, &bbox); gs_trans_mask_params_init(¶ms, TRANSPARENCY_MASK_Alpha); gs_begin_transparency_mask(ctx->pgs, ¶ms, &bbox, 0); diff --git a/xps/xpsopacity.c b/xps/xpsopacity.c index 06c837789..75dd0549e 100644 --- a/xps/xpsopacity.c +++ b/xps/xpsopacity.c @@ -17,21 +17,16 @@ xps_begin_opacity(xps_context_t *ctx, xps_resource_t *dict, char *opacity_att, x opacity = atof(opacity_att); gs_setopacityalpha(ctx->pgs, opacity); - // TODO: this is not good. we need to get visible bbox somehow. - bbox.p.x = 0.0; - bbox.p.y = 0.0; - bbox.q.x = 1000.0; - bbox.p.y = 1000.0; + xps_bounds_in_user_space(ctx, &bbox); if (opacity_mask_tag) { - /* TODO: opacity masks with image brushes don't work */ - dprintf1("begin opacity mask (%s)\n", xps_tag(opacity_mask_tag)); gs_trans_mask_params_init(&tmp, TRANSPARENCY_MASK_Luminosity); gs_begin_transparency_mask(ctx->pgs, &tmp, &bbox, 0); + /* Need a path to fill/clip for the brush */ gs_moveto(ctx->pgs, bbox.p.x, bbox.p.y); gs_lineto(ctx->pgs, bbox.p.x, bbox.q.y); gs_lineto(ctx->pgs, bbox.q.x, bbox.q.y); diff --git a/xps/xpspage.c b/xps/xpspage.c index b8271190f..08975958a 100644 --- a/xps/xpspage.c +++ b/xps/xpspage.c @@ -14,6 +14,8 @@ int xps_parse_canvas(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *root) xps_item_t *clip_tag = NULL; xps_item_t *opacity_mask_tag = NULL; + gs_rect saved_bounds; + gs_matrix transform; transform_att = xps_att(root, "RenderTransform"); @@ -54,16 +56,13 @@ int xps_parse_canvas(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *root) xps_parse_matrix_transform(ctx, transform_tag, &transform); gs_concat(ctx->pgs, &transform); - if (clip_att) - { - xps_parse_abbreviated_geometry(ctx, clip_att); - xps_clip(ctx); - } - - if (clip_tag) + if (clip_att || clip_tag) { - xps_parse_path_geometry(ctx, dict, clip_tag); - xps_clip(ctx); + if (clip_att) + xps_parse_abbreviated_geometry(ctx, clip_att); + if (clip_tag) + xps_parse_path_geometry(ctx, dict, clip_tag); + xps_clip(ctx, &saved_bounds); } xps_begin_opacity(ctx, dict, opacity_att, opacity_mask_tag); @@ -73,6 +72,11 @@ int xps_parse_canvas(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *root) xps_parse_element(ctx, dict, node); } + if (clip_att || clip_tag) + { + xps_unclip(ctx, &saved_bounds); + } + xps_end_opacity(ctx, dict, opacity_att, opacity_mask_tag); gs_grestore(ctx->pgs); @@ -93,6 +97,9 @@ xps_parse_fixed_page(xps_context_t *ctx, xps_part_t *part) char *width_att; char *height_att; int code; + gs_matrix ctm; + gs_point pt0, pt1; + gs_rect rc; dprintf1("processing page %s\n", part->name); @@ -166,6 +173,14 @@ xps_parse_fixed_page(xps_context_t *ctx, xps_part_t *part) code = gs_erasepage(pgs); if (code < 0) return gs_rethrow(code, "cannot clear page"); + + /* set initial bounds to cover the page */ + gs_currentmatrix(pgs, &ctm); + gs_point_transform(0.0, 0.0, &ctm, &rc.p); + gs_point_transform(atoi(width_att), atoi(height_att), &ctm, &rc.q); + if (rc.p.x > rc.q.x) { float t = rc.p.x; rc.p.x = rc.q.x; rc.q.x = t; } + if (rc.p.y > rc.q.y) { float t = rc.p.y; rc.p.y = rc.q.y; rc.q.y = t; } + ctx->bounds = rc; } code = gs_push_pdf14trans_device(ctx->pgs); diff --git a/xps/xpspath.c b/xps/xpspath.c index 85a4af999..18a48a69f 100644 --- a/xps/xpspath.c +++ b/xps/xpspath.c @@ -1,13 +1,157 @@ #include "ghostxps.h" +static void +xps_grow_rect(gs_rect *rect, float x, float y) +{ + if (x < rect->p.x) rect->p.x = x; + if (y < rect->p.y) rect->p.y = y; + if (x > rect->q.x) rect->q.x = x; + if (y > rect->q.y) rect->q.y = y; +} + +void +xps_bounds_in_user_space(xps_context_t *ctx, gs_rect *user) +{ + gs_matrix ctm; + gs_matrix inv; + gs_point a, b, c, d; + float x0, y0, x1, y1; + + gs_currentmatrix(ctx->pgs, &ctm); + gs_matrix_invert(&ctm, &inv); + + gs_point_transform(ctx->bounds.p.x, ctx->bounds.p.y, &inv, &a); + gs_point_transform(ctx->bounds.p.x, ctx->bounds.q.y, &inv, &b); + gs_point_transform(ctx->bounds.q.x, ctx->bounds.q.y, &inv, &c); + gs_point_transform(ctx->bounds.q.x, ctx->bounds.p.y, &inv, &d); + + user->p.x = MIN(MIN(a.x, b.x), MIN(c.x, d.x)); + user->p.y = MIN(MIN(a.y, b.y), MIN(c.y, d.y)); + user->q.x = MAX(MAX(a.x, b.x), MAX(c.x, d.x)); + user->q.y = MAX(MAX(a.y, b.y), MAX(c.y, d.y)); + +#if 0 + user->p.x = 0.0; + user->p.y = 0.0; + user->q.x = 1000.0; + user->q.y = 1000.0; +#endif + +} + +static void +xps_update_bounds(xps_context_t *ctx, gs_rect *save) +{ + segment *seg; + curve_segment *cseg; + gs_point pt; + gs_rect rc; + + save->p.x = ctx->bounds.p.x; + save->p.y = ctx->bounds.p.y; + save->q.x = ctx->bounds.q.x; + save->q.y = ctx->bounds.q.y; + + /* get bounds of current path (that is about to be clipped) */ + /* the coordinates of the path segments are already in device space (yay!) */ + + seg = (segment*)ctx->pgs->path->first_subpath; + rc.p.x = rc.q.x = fixed2float(seg->pt.x); + rc.p.y = rc.q.y = fixed2float(seg->pt.y); + + while (seg) + { + switch (seg->type) + { + case s_start: + xps_grow_rect(&rc, fixed2float(seg->pt.x), fixed2float(seg->pt.y)); + break; + case s_line: + xps_grow_rect(&rc, fixed2float(seg->pt.x), fixed2float(seg->pt.y)); + break; + case s_line_close: + break; + case s_curve: + cseg = (curve_segment*)seg; + xps_grow_rect(&rc, fixed2float(cseg->p1.x), fixed2float(cseg->p1.y)); + xps_grow_rect(&rc, fixed2float(cseg->p2.x), fixed2float(cseg->p2.y)); + xps_grow_rect(&rc, fixed2float(seg->pt.x), fixed2float(seg->pt.y)); + break; + } + seg = seg->next; + } + + /* intersect with old bounds, and fix degenerate case */ + + rect_intersect(ctx->bounds, rc); + + if (ctx->bounds.q.x < ctx->bounds.p.x) + ctx->bounds.q.x = ctx->bounds.p.x; + if (ctx->bounds.q.y < ctx->bounds.p.y) + ctx->bounds.q.y = ctx->bounds.p.y; +} + +static void +xps_restore_bounds(xps_context_t *ctx, gs_rect *save) +{ + ctx->bounds.p.x = save->p.x; + ctx->bounds.p.y = save->p.y; + ctx->bounds.q.x = save->q.x; + ctx->bounds.q.y = save->q.y; +} + +void +xps_debug_bounds(xps_context_t *ctx) +{ + gs_matrix mat; + + gs_gsave(ctx->pgs); + + dprintf6("bounds: debug [%g %g %g %g] w=%g h=%g\n", + ctx->bounds.p.x, ctx->bounds.p.y, + ctx->bounds.q.x, ctx->bounds.q.y, + ctx->bounds.q.x - ctx->bounds.p.x, + ctx->bounds.q.y - ctx->bounds.p.y); + + gs_make_identity(&mat); + gs_setmatrix(ctx->pgs, &mat); + + gs_setgray(ctx->pgs, 0.3); + gs_moveto(ctx->pgs, ctx->bounds.p.x, ctx->bounds.p.y); + gs_lineto(ctx->pgs, ctx->bounds.q.x, ctx->bounds.q.y); + gs_moveto(ctx->pgs, ctx->bounds.q.x, ctx->bounds.p.y); + gs_lineto(ctx->pgs, ctx->bounds.p.x, ctx->bounds.q.y); + + gs_moveto(ctx->pgs, ctx->bounds.p.x, ctx->bounds.p.y); + gs_lineto(ctx->pgs, ctx->bounds.p.x, ctx->bounds.q.y); + gs_lineto(ctx->pgs, ctx->bounds.q.x, ctx->bounds.q.y); + gs_lineto(ctx->pgs, ctx->bounds.q.x, ctx->bounds.p.y); + gs_closepath(ctx->pgs); + + gs_stroke(ctx->pgs); + + gs_grestore(ctx->pgs); +} + int -xps_clip(xps_context_t *ctx) +xps_unclip(xps_context_t *ctx, gs_rect *saved_bounds) { + xps_restore_bounds(ctx, saved_bounds); + return 0; +} + +int +xps_clip(xps_context_t *ctx, gs_rect *saved_bounds) +{ + xps_update_bounds(ctx, saved_bounds); + if (ctx->fill_rule == 0) gs_eoclip(ctx->pgs); else gs_clip(ctx->pgs); + gs_newpath(ctx->pgs); + return 0; } @@ -674,6 +818,8 @@ xps_parse_path(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *root) float miterlimit; float argb[4]; + gs_rect saved_bounds; + gs_gsave(ctx->pgs); /* @@ -820,7 +966,7 @@ xps_parse_path(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *root) if (clip_tag) xps_parse_path_geometry(ctx, dict, clip_tag); - xps_clip(ctx); + xps_clip(ctx, &saved_bounds); } xps_begin_opacity(ctx, dict, opacity_att, opacity_mask_tag); @@ -878,6 +1024,11 @@ xps_parse_path(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *root) xps_parse_brush(ctx, dict, stroke_tag); } + if (clip_att || clip_tag) + { + xps_unclip(ctx, &saved_bounds); + } + xps_end_opacity(ctx, dict, opacity_att, opacity_mask_tag); gs_grestore(ctx->pgs); diff --git a/xps/xpstile.c b/xps/xpstile.c index 41f015ddd..0988774a5 100644 --- a/xps/xpstile.c +++ b/xps/xpstile.c @@ -22,6 +22,7 @@ static int xps_paint_tiling_brush_clipped(struct tile_closure_s *c) { xps_context_t *ctx = c->ctx; + gs_rect saved_bounds; int code; gs_moveto(ctx->pgs, c->viewbox.p.x, c->viewbox.p.y); @@ -32,8 +33,22 @@ xps_paint_tiling_brush_clipped(struct tile_closure_s *c) gs_clip(ctx->pgs); gs_newpath(ctx->pgs); + /* tile paint functions use a different device + * with a different coord space, so we have to + * tweak the bounds. + */ + + saved_bounds = ctx->bounds; + dprintf4("tiled bounds [%g %g %g %g]\n", + saved_bounds.p.x, saved_bounds.p.y, + saved_bounds.q.x, saved_bounds.q.y); + + ctx->bounds = c->viewbox; // transform? + code = c->func(c->ctx, c->dict, c->tag, c->user); + ctx->bounds = saved_bounds; + return code; } @@ -221,7 +236,9 @@ xps_parse_tiling_brush(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *roo } else { - xps_clip(ctx); + gs_rect saved_bounds; + + xps_clip(ctx, &saved_bounds); gs_concat(ctx->pgs, &transform); @@ -238,6 +255,8 @@ xps_parse_tiling_brush(xps_context_t *ctx, xps_resource_t *dict, xps_item_t *roo gs_newpath(ctx->pgs); func(ctx, dict, root, user); + + xps_unclip(ctx, &saved_bounds); } xps_end_opacity(ctx, dict, opacity_att, NULL); |