diff options
author | Adrian Johnson <ajohnson@redneon.com> | 2007-04-27 16:01:56 -0700 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2007-04-27 16:13:01 -0700 |
commit | 179e3399101b5a0daa907dcfe1f9f11ae8fe691e (patch) | |
tree | a28d3e82f4bad3b7c6cf82eb8c6b8d6c3f51430f | |
parent | 1816d7c590ae4d423f9314a8a7794e2cae854da3 (diff) |
PDF: Change CTM to identity
Some PDF viewers forget the CTM when drawing gradient patterns
with SMasks. This patch works around these bugs by using the default
identity matrix for the CTM. All paths are transformed from
cairo to pdf coordinates before writing to the pdf file.
-rw-r--r-- | src/cairo-pdf-surface-private.h | 1 | ||||
-rw-r--r-- | src/cairo-pdf-surface.c | 135 |
2 files changed, 67 insertions, 69 deletions
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h index 31ebc2607..1af2ad06b 100644 --- a/src/cairo-pdf-surface-private.h +++ b/src/cairo-pdf-surface-private.h @@ -58,6 +58,7 @@ struct _cairo_pdf_surface { double width; double height; + cairo_matrix_t cairo_to_pdf; cairo_array_t objects; cairo_array_t pages; diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 339865457..00dcd7c73 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -245,6 +245,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, surface->width = width; surface->height = height; + cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, height); _cairo_array_init (&surface->objects, sizeof (cairo_pdf_object_t)); _cairo_array_init (&surface->pages, sizeof (cairo_pdf_resource_t)); @@ -663,10 +664,6 @@ _cairo_pdf_surface_start_page (void *abstract_surface) if (status) return status; - _cairo_output_stream_printf (surface->output, - "1 0 0 -1 0 %f cm\r\n", - surface->height); - return CAIRO_STATUS_SUCCESS; } @@ -1422,8 +1419,8 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface, { cairo_pdf_resource_t pattern_resource, smask; cairo_pdf_resource_t color_function, alpha_function; - double x0, y0, x1, y1; - cairo_matrix_t p2u; + double x1, y1, x2, y2; + cairo_matrix_t pat_to_pdf; cairo_extend_t extend; cairo_status_t status; @@ -1439,32 +1436,33 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface, if (status) return status; - p2u = pattern->base.base.matrix; - status = cairo_matrix_invert (&p2u); + pat_to_pdf = pattern->base.base.matrix; + status = cairo_matrix_invert (&pat_to_pdf); if (status) return status; - x0 = _cairo_fixed_to_double (pattern->gradient.p1.x); - y0 = _cairo_fixed_to_double (pattern->gradient.p1.y); - cairo_matrix_transform_point (&p2u, &x0, &y0); - x1 = _cairo_fixed_to_double (pattern->gradient.p2.x); - y1 = _cairo_fixed_to_double (pattern->gradient.p2.y); - cairo_matrix_transform_point (&p2u, &x1, &y1); + cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf); + x1 = _cairo_fixed_to_double (pattern->gradient.p1.x); + y1 = _cairo_fixed_to_double (pattern->gradient.p1.y); + x2 = _cairo_fixed_to_double (pattern->gradient.p2.x); + y2 = _cairo_fixed_to_double (pattern->gradient.p2.y); pattern_resource = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, "%d 0 obj\r\n" "<< /Type /Pattern\r\n" " /PatternType 2\r\n" - " /Matrix [ 1 0 0 -1 0 %f ]\r\n" + " /Matrix [ %f %f %f %f %f %f ]\r\n" " /Shading\r\n" " << /ShadingType 2\r\n" " /ColorSpace /DeviceRGB\r\n" " /Coords [ %f %f %f %f ]\r\n" " /Function %d 0 R\r\n", pattern_resource.id, - surface->height, - x0, y0, x1, y1, + pat_to_pdf.xx, pat_to_pdf.yx, + pat_to_pdf.xy, pat_to_pdf.yy, + pat_to_pdf.x0, pat_to_pdf.y0, + x1, y1, x2, y2, color_function.id); if (extend == CAIRO_EXTEND_PAD) { @@ -1491,15 +1489,17 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface, "%d 0 obj\r\n" "<< /Type /Pattern\r\n" " /PatternType 2\r\n" - " /Matrix [ 1 0 0 -1 0 %f ]\r\n" + " /Matrix [ %f %f %f %f %f %f ]\r\n" " /Shading\r\n" " << /ShadingType 2\r\n" " /ColorSpace /DeviceGray\r\n" " /Coords [ %f %f %f %f ]\r\n" " /Function %d 0 R\r\n", mask_resource.id, - surface->height, - x0, y0, x1, y1, + pat_to_pdf.xx, pat_to_pdf.yx, + pat_to_pdf.xy, pat_to_pdf.yy, + pat_to_pdf.x0, pat_to_pdf.y0, + x1, y1, x2, y2, alpha_function.id); if (extend == CAIRO_EXTEND_PAD) { @@ -1541,8 +1541,8 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface, { cairo_pdf_resource_t pattern_resource, smask; cairo_pdf_resource_t color_function, alpha_function; - double x0, y0, x1, y1, r0, r1; - cairo_matrix_t p2u, pdf_p2d; + double x1, y1, x2, y2, r1, r2; + cairo_matrix_t pat_to_pdf; cairo_extend_t extend; cairo_status_t status; @@ -1558,22 +1558,18 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface, if (status) return status; - p2u = pattern->base.base.matrix; - status = cairo_matrix_invert (&p2u); + pat_to_pdf = pattern->base.base.matrix; + status = cairo_matrix_invert (&pat_to_pdf); if (status) return status; - x0 = _cairo_fixed_to_double (pattern->gradient.c1.x); - y0 = _cairo_fixed_to_double (pattern->gradient.c1.y); - r0 = _cairo_fixed_to_double (pattern->gradient.c1.radius); - x1 = _cairo_fixed_to_double (pattern->gradient.c2.x); - y1 = _cairo_fixed_to_double (pattern->gradient.c2.y); - r1 = _cairo_fixed_to_double (pattern->gradient.c2.radius); - - cairo_matrix_init_identity (&pdf_p2d); - cairo_matrix_translate (&pdf_p2d, 0.0, surface->height); - cairo_matrix_scale (&pdf_p2d, 1.0, -1.0); - cairo_matrix_multiply (&pdf_p2d, &p2u, &pdf_p2d); + cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf); + x1 = _cairo_fixed_to_double (pattern->gradient.c1.x); + y1 = _cairo_fixed_to_double (pattern->gradient.c1.y); + r1 = _cairo_fixed_to_double (pattern->gradient.c1.radius); + x2 = _cairo_fixed_to_double (pattern->gradient.c2.x); + y2 = _cairo_fixed_to_double (pattern->gradient.c2.y); + r2 = _cairo_fixed_to_double (pattern->gradient.c2.radius); pattern_resource = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, @@ -1587,10 +1583,10 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface, " /Coords [ %f %f %f %f %f %f ]\r\n" " /Function %d 0 R\r\n", pattern_resource.id, - pdf_p2d.xx, pdf_p2d.yx, - pdf_p2d.xy, pdf_p2d.yy, - pdf_p2d.x0, pdf_p2d.y0, - x0, y0, r0, x1, y1, r1, + pat_to_pdf.xx, pat_to_pdf.yx, + pat_to_pdf.xy, pat_to_pdf.yy, + pat_to_pdf.x0, pat_to_pdf.y0, + x1, y1, r1, x2, y2, r2, color_function.id); if (extend == CAIRO_EXTEND_PAD) { @@ -1624,10 +1620,10 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface, " /Coords [ %f %f %f %f %f %f ]\r\n" " /Function %d 0 R\r\n", mask_resource.id, - pdf_p2d.xx, pdf_p2d.yx, - pdf_p2d.xy, pdf_p2d.yy, - pdf_p2d.x0, pdf_p2d.y0, - x0, y0, r0, x1, y1, r1, + pat_to_pdf.xx, pat_to_pdf.yx, + pat_to_pdf.xy, pat_to_pdf.yy, + pat_to_pdf.x0, pat_to_pdf.y0, + x1, y1, r1, x2, y2, r2, alpha_function.id); if (extend == CAIRO_EXTEND_PAD) { @@ -1767,6 +1763,7 @@ _cairo_pdf_surface_get_extents (void *abstract_surface, typedef struct _pdf_path_info { cairo_output_stream_t *output; + cairo_matrix_t *cairo_to_pdf; cairo_matrix_t *ctm_inverse; } pdf_path_info_t; @@ -1777,6 +1774,8 @@ _cairo_pdf_path_move_to (void *closure, cairo_point_t *point) double x = _cairo_fixed_to_double (point->x); double y = _cairo_fixed_to_double (point->y); + if (info->cairo_to_pdf) + cairo_matrix_transform_point (info->cairo_to_pdf, &x, &y); if (info->ctm_inverse) cairo_matrix_transform_point (info->ctm_inverse, &x, &y); @@ -1793,6 +1792,8 @@ _cairo_pdf_path_line_to (void *closure, cairo_point_t *point) double x = _cairo_fixed_to_double (point->x); double y = _cairo_fixed_to_double (point->y); + if (info->cairo_to_pdf) + cairo_matrix_transform_point (info->cairo_to_pdf, &x, &y); if (info->ctm_inverse) cairo_matrix_transform_point (info->ctm_inverse, &x, &y); @@ -1815,6 +1816,11 @@ _cairo_pdf_path_curve_to (void *closure, double dx = _cairo_fixed_to_double (d->x); double dy = _cairo_fixed_to_double (d->y); + if (info->cairo_to_pdf) { + cairo_matrix_transform_point (info->cairo_to_pdf, &bx, &by); + cairo_matrix_transform_point (info->cairo_to_pdf, &cx, &cy); + cairo_matrix_transform_point (info->cairo_to_pdf, &dx, &dy); + } if (info->ctm_inverse) { cairo_matrix_transform_point (info->ctm_inverse, &bx, &by); cairo_matrix_transform_point (info->ctm_inverse, &cx, &cy); @@ -1863,6 +1869,7 @@ _cairo_pdf_surface_intersect_clip_path (void *abstract_surface, } info.output = surface->output; + info.cairo_to_pdf = &surface->cairo_to_pdf; info.ctm_inverse = NULL; status = _cairo_path_fixed_interpret (path, @@ -2581,6 +2588,7 @@ _cairo_pdf_surface_emit_outline_glyph (cairo_pdf_surface_t *surface, -_cairo_fixed_to_double (scaled_glyph->bbox.p1.y)); info.output = surface->output; + info.cairo_to_pdf = &surface->cairo_to_pdf; info.ctm_inverse = NULL; status = _cairo_path_fixed_interpret (scaled_glyph->path, @@ -3143,9 +3151,6 @@ _cairo_pdf_surface_paint (void *abstract_surface, status = _cairo_pdf_surface_begin_group (surface, &group); if (status) return status; - _cairo_output_stream_printf (surface->output, - "1 0 0 -1 0 %f cm\r\n", - surface->height); } else { _cairo_output_stream_printf (surface->output, "q "); } @@ -3160,8 +3165,7 @@ _cairo_pdf_surface_paint (void *abstract_surface, _cairo_pdf_surface_end_group (surface); _cairo_output_stream_printf (surface->output, - "q 1 0 0 -1 0 %f cm /sm%d gs /res%d Do Q\r\n", - surface->height, + "q /sm%d gs /res%d Do Q\r\n", surface->emitted_pattern.smask, group.id); } else { @@ -3268,6 +3272,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface, cairo_pdf_resource_t group = {0}; /* squelch bogus compiler warning */ pdf_path_info_t info; cairo_status_t status; + cairo_matrix_t m; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _cairo_pdf_surface_analyze_operation (surface, op, source); @@ -3282,9 +3287,6 @@ _cairo_pdf_surface_stroke (void *abstract_surface, status = _cairo_pdf_surface_begin_group (surface, &group); if (status) return status; - _cairo_output_stream_printf (surface->output, - "1 0 0 -1 0 %f cm\r\n", - surface->height); } else { _cairo_output_stream_printf (surface->output, "q "); } @@ -3297,12 +3299,14 @@ _cairo_pdf_surface_stroke (void *abstract_surface, return status; info.output = surface->output; + info.cairo_to_pdf = NULL; info.ctm_inverse = ctm_inverse; + cairo_matrix_multiply (&m, ctm, &surface->cairo_to_pdf); _cairo_output_stream_printf (surface->output, "q %f %f %f %f %f %f cm\r\n", - ctm->xx, ctm->yx, ctm->xy, ctm->yy, - ctm->x0, ctm->y0); + m.xx, m.yx, m.xy, m.yy, + m.x0, m.y0); status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, @@ -3318,8 +3322,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface, _cairo_pdf_surface_end_group (surface); _cairo_output_stream_printf (surface->output, - "q 1 0 0 -1 0 %f cm /sm%d gs /res%d Do Q\r\n", - surface->height, + "q /sm%d gs /res%d Do Q\r\n", surface->emitted_pattern.smask, group.id); } else { @@ -3357,15 +3360,13 @@ _cairo_pdf_surface_fill (void *abstract_surface, status = _cairo_pdf_surface_begin_group (surface, &group); if (status) return status; - _cairo_output_stream_printf (surface->output, - "1 0 0 -1 0 %f cm\r\n", - surface->height); } else { _cairo_output_stream_printf (surface->output, "q "); } _cairo_pdf_surface_select_pattern (surface, FALSE); info.output = surface->output; + info.cairo_to_pdf = &surface->cairo_to_pdf; info.ctm_inverse = NULL; status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, @@ -3394,8 +3395,7 @@ _cairo_pdf_surface_fill (void *abstract_surface, _cairo_pdf_surface_end_group (surface); _cairo_output_stream_printf (surface->output, - "q 1 0 0 -1 0 %f cm /sm%d gs /res%d Do Q\r\n", - surface->height, + "q /sm%d gs /res%d Do Q\r\n", surface->emitted_pattern.smask, group.id); } else { @@ -3438,9 +3438,6 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface, status = _cairo_pdf_surface_begin_group (surface, &group); if (status) return status; - _cairo_output_stream_printf (surface->output, - "1 0 0 -1 0 %f cm\r\n", - surface->height); } else { _cairo_output_stream_printf (surface->output, "q "); } @@ -3491,11 +3488,11 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface, _cairo_output_stream_printf (surface->output, "%f %f %f %f %f %f Tm\r\n", scaled_font->scale.xx, - scaled_font->scale.yx, + -scaled_font->scale.yx, -scaled_font->scale.xy, - -scaled_font->scale.yy, + scaled_font->scale.yy, glyphs[i].x, - glyphs[i].y); + surface->height - glyphs[i].y); current_subset_id = subset_glyph.subset_id; Tlm_x = glyphs[i].x; Tlm_y = glyphs[i].y; @@ -3512,7 +3509,8 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface, _cairo_output_stream_printf (surface->output, "%f %f Td\r\n", (glyphs[i].x - Tlm_x)/scaled_font->scale.xx, - (glyphs[i].y - Tlm_y)/-scaled_font->scale.yy); + -(glyphs[i].y - Tlm_y)/scaled_font->scale.yy); + Tlm_x = glyphs[i].x; Tlm_y = glyphs[i].y; Tm_x = Tlm_x; @@ -3588,8 +3586,7 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface, _cairo_pdf_surface_end_group (surface); _cairo_output_stream_printf (surface->output, - "q 1 0 0 -1 0 %f cm /sm%d gs /res%d Do Q\r\n", - surface->height, + "q /sm%d gs /res%d Do Q\r\n", surface->emitted_pattern.smask, group.id); } else { |