summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xps/ghostxps.h21
-rw-r--r--xps/xpsglyphs.c9
-rw-r--r--xps/xpsgradient.c23
-rw-r--r--xps/xpsimage.c6
-rw-r--r--xps/xpsopacity.c9
-rw-r--r--xps/xpspage.c33
-rw-r--r--xps/xpspath.c155
-rw-r--r--xps/xpstile.c21
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(&params);
@@ -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(&params);
@@ -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(&params, TRANSPARENCY_MASK_Alpha);
gs_begin_transparency_mask(ctx->pgs, &params, &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(&params, TRANSPARENCY_MASK_Alpha);
gs_begin_transparency_mask(ctx->pgs, &params, &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);