Re: _cairo_surface_wrapper_get_target_extents() too small
Guillaume Ayoub <[email protected]>
| Newsgroups | gmane.comp.lib.cairo |
|---|---|
| Message-ID | <1368445620.2072.24.camel@liZe76> |
Le vendredi 29 mars 2013 à 22:55 +0100, Guillaume Ayoub a écrit : > Le vendredi 29 mars 2013 à 15:43 +0100, Simon Sapin a écrit : > > Le 27/03/2013 13:12, Simon Sapin a écrit : > > > Hi, > > > > > > When rendering to PDF with WeasyPrint a document containing a SVG image, > > > SVG elements in the right and bottom of the image are not shown in some > > > cases. > > > > > > git bisect indicates that the bug appeared in this cairo commit: > > > > > > http://cgit.freedesktop.org/cairo/commit/?id=09b42c748e9dbcc923560c7d8bf5298fbffe95ef > > > > > > Reverting it on top of today’s master fixes the bug. > > > > > > > > > WeasyPrint has CairoSVG render the image to an intermediate cairo SVG > > > surface, which is then used in surface pattern as a source to paint in > > > the final PDF surface. The bug appears when the target context has a > > > scale to make the image smaller than its "intrinsic" size. Making the > > > SVG surface smaller (with its content scaled accordingly) and > > > compensating with a scale on the target surface works around the problem. > > > > > > Apparently, the rectangle returned by > > > _cairo_surface_wrapper_get_target_extents() is smaller than it should > > > be. Something is transformed wrong, but I’m not sure what coordinate > > > system each rectangle is supposed to be in. > > > > > > Based on further research, it appears that the wrapper->transform value > > in _cairo_surface_wrapper_get_target_extents() should account for the > > target context’s transformation matrix, but doesn’t. wrapper->transform > > is always the identity matrix in our tests, even though the context has > > a non-identity transform when painting the surface pattern. > > > > Removing any calls to cairo_save() and cairo_restore() also works around > > the issue, but for reasons we do not understand. > > I finally think that I have found what's happening. > > In cairo-analysis-surface, the transformation matrix is stored in > surface->ctm, and this matrix is handled by _add_operation for all the > operations added in the analysis surface. In > _analyze_recording_surface_pattern, the ctm surface is set, everything > is OK for the future operations. > > But _analyze_recording_surface_pattern calls > _cairo_recording_surface_replay_and_create_regions, calling > _cairo_recording_surface_replay_internal, calling > _cairo_surface_wrapper_get_target_extents. As replay_and_create_regions > calls replay_internal without the surface_transform parameter, the > original transformation matrix is lost. get_target_extents relies on > wrapper.transform that is not set, and get_target_extents then uses the > original size of the target to reduce the extents rectangle, instead of > using the size multiplied by the transformation matrix. > > A simple solution to fix this is to add a surface_transform parameter to > _cairo_recording_surface_replay_and_create_regions (as it is done in > _cairo_recording_surface_replay_with_clip), and to use the invert matrix > of &tmp->ctm as surface_transform parameter of > _cairo_recording_surface_replay_and_create_regions. Here is a simple patch solving this issue. This patch adds a "surface_transform" parameter to replay_and_create_regions. It was already done in surface_replay_with_clip (it is needed for the clip), but it's also needed by replay_and_create_regions, because get_target_extents clips the target surface for performance issues (that's what the "culprit" commit 09b42c7 does). I can provide further information if needed. -- Guillaume -- cairo mailing list [email protected] http://lists.cairographics.org/mailman/listinfo/cairo
cairo-fix-extents.patch
(text/x-patch, 3.2 KB)
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 8516094..d3afd9f 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -144,7 +144,7 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
const cairo_surface_pattern_t *surface_pattern;
cairo_analysis_surface_t *tmp;
cairo_surface_t *source, *proxy;
- cairo_matrix_t p2d;
+ cairo_matrix_t p2d, surface_transform;
cairo_status_t status, analysis_status;
assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
@@ -171,9 +171,11 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
cairo_matrix_multiply (&tmp->ctm, &p2d, &surface->ctm);
tmp->has_ctm = ! _cairo_matrix_is_identity (&tmp->ctm);
+ surface_transform = tmp->ctm;
+ status = cairo_matrix_invert (&surface_transform);
source = _cairo_surface_get_source (source, NULL);
status = _cairo_recording_surface_replay_and_create_regions (source,
- &tmp->base);
+ &surface_transform, &tmp->base);
analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS;
detach_proxy (proxy);
cairo_surface_destroy (&tmp->base);
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index fe9ccee..8371474 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -354,7 +354,7 @@ _paint_page (cairo_paginated_surface_t *surface)
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_ANALYZE);
status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface,
- analysis);
+ NULL, analysis);
if (status)
goto FAIL;
diff --git a/src/cairo-recording-surface-private.h b/src/cairo-recording-surface-private.h
index 0235b0f..aee7887 100644
--- a/src/cairo-recording-surface-private.h
+++ b/src/cairo-recording-surface-private.h
@@ -167,6 +167,7 @@ _cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
cairo_private cairo_status_t
_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
+ const cairo_matrix_t *surface_transform,
cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_recording_surface_replay_region (cairo_surface_t *surface,
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index c6d34c0..0f1a06d 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -1917,9 +1917,10 @@ _cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
*/
cairo_status_t
_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
+ const cairo_matrix_t *surface_transform,
cairo_surface_t *target)
{
- return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, NULL, NULL,
+ return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, NULL, surface_transform,
target, NULL,
CAIRO_RECORDING_CREATE_REGIONS,
CAIRO_RECORDING_REGION_ALL);
signature.asc
(application/pgp-signature, 490 B)
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQEcBAABAgAGBQJRkNK0AAoJEFDXmmt3d/ODvPwH/Ajcgi26Lq+kcMGgkN1aeW+c jpH7ZJy9jgVk493y9dPbxHvu7JuUfUcO1xyE2QrOtRjyWE5ZcmeBY+bff8DDwWzr 1XfEG9EI9SzEixOxb8GAmrc4Nf5yVMXJLtIPBKkSA/eycfl6+2SI3XOnngiYStM6 +Umq5QfCgXtTKBJrftzSIY+7WTRdnxQztbB+hVMS494TRmVQZG73LtCQiY0wuJSy Ah7O283AHEoDM+XhNqoKDX4YQdBBuJOjwIBYLBsg6t3IX4f6z6BI+R8iwz9Il2XT 8SP/jq4hzeqpa5t5fC13xmNof0aLuZf5/v5lfoTmqj6ud1z9g8IUkFPuAI2ezg4= =rScX -----END PGP SIGNATURE-----