summaryrefslogtreecommitdiffstats
path: root/gfx/cairo/win32-printing-axis-swap.patch
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/cairo/win32-printing-axis-swap.patch')
-rw-r--r--gfx/cairo/win32-printing-axis-swap.patch292
1 files changed, 292 insertions, 0 deletions
diff --git a/gfx/cairo/win32-printing-axis-swap.patch b/gfx/cairo/win32-printing-axis-swap.patch
new file mode 100644
index 000000000..87a1a91e4
--- /dev/null
+++ b/gfx/cairo/win32-printing-axis-swap.patch
@@ -0,0 +1,292 @@
+# HG changeset patch
+# User Lee Salzman <lsalzman@mozilla.com>
+# Date 1445463645 14400
+# Wed Oct 21 17:40:45 2015 -0400
+# Node ID 9e84563cbd73c5b0993dfd018ca25b660b667e94
+# Parent 2d3fd51c4182c253a2f102655e8e9e466032853f
+workaround for Windows printer drivers that can't handle swapped X and Y axes
+
+diff --git a/gfx/cairo/cairo/src/cairo-matrix.c b/gfx/cairo/cairo/src/cairo-matrix.c
+--- a/gfx/cairo/cairo/src/cairo-matrix.c
++++ b/gfx/cairo/cairo/src/cairo-matrix.c
+@@ -873,42 +873,56 @@ cairo_bool_t
+ (Note that the minor axis length is at the minimum of the above solution,
+ which is just sqrt ( f - sqrt(g² + h²) ) given the symmetry of (D)).
+
+
+ For another derivation of the same result, using Singular Value Decomposition,
+ see doc/tutorial/src/singular.c.
+ */
+
+-/* determine the length of the major axis of a circle of the given radius
+- after applying the transformation matrix. */
+-double
+-_cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
+- double radius)
++/* determine the length of the major and minor axes of a circle of the given
++ radius after applying the transformation matrix. */
++void
++_cairo_matrix_transformed_circle_axes (const cairo_matrix_t *matrix,
++ double radius,
++ double *major,
++ double *minor)
+ {
+- double a, b, c, d, f, g, h, i, j;
++ double a, b, c, d, f, g, h, i, j, k;
+
+ _cairo_matrix_get_affine (matrix,
+ &a, &b,
+ &c, &d,
+ NULL, NULL);
+
+ i = a*a + b*b;
+ j = c*c + d*d;
++ k = a*c + b*d;
+
+ f = 0.5 * (i + j);
+ g = 0.5 * (i - j);
+- h = a*c + b*d;
++ h = hypot (g, k);
+
+- return radius * sqrt (f + hypot (g, h));
++ if (major)
++ *major = radius * sqrt (f + h);
++ if (minor)
++ *minor = radius * sqrt (f - h);
++}
+
+- /*
+- * we don't need the minor axis length, which is
+- * double min = radius * sqrt (f - sqrt (g*g+h*h));
+- */
++/* determine the length of the major axis of a circle of the given radius
++ after applying the transformation matrix. */
++double
++_cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
++ double radius)
++{
++ double major;
++
++ _cairo_matrix_transformed_circle_axes (matrix, radius, &major, NULL);
++
++ return major;
+ }
+
+ void
+ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
+ pixman_transform_t *pixman_transform,
+ double xc,
+ double yc)
+ {
+diff --git a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c
+--- a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c
++++ b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c
+@@ -610,16 +610,17 @@ static cairo_status_t
+ int x_tile, y_tile, left, right, top, bottom;
+ RECT clip;
+ const cairo_color_t *background_color;
+ const unsigned char *mime_data;
+ unsigned long mime_size;
+ cairo_image_info_t mime_info;
+ cairo_bool_t use_mime;
+ DWORD mime_type;
++ cairo_bool_t axis_swap;
+
+ /* If we can't use StretchDIBits with this surface, we can't do anything
+ * here.
+ */
+ if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
+@@ -658,39 +659,65 @@ static cairo_status_t
+ &mime_size,
+ &mime_info);
+ }
+ if (_cairo_status_is_error (status))
+ return status;
+
+ use_mime = (status == CAIRO_STATUS_SUCCESS);
+
+- if (!use_mime && image->format != CAIRO_FORMAT_RGB24) {
++ m = pattern->base.matrix;
++ status = cairo_matrix_invert (&m);
++ /* _cairo_pattern_set_matrix guarantees invertibility */
++ assert (status == CAIRO_STATUS_SUCCESS);
++ cairo_matrix_multiply (&m, &m, &surface->ctm);
++ cairo_matrix_multiply (&m, &m, &surface->gdi_ctm);
++ /* Check if the matrix swaps the X and Y axes by checking if the diagonal
++ * is effectively zero. This can happen, for example, if it was composed
++ * with a rotation such as a landscape transform. Some printing devices
++ * don't support such transforms in StretchDIBits.
++ */
++ axis_swap = fabs (m.xx*image->width) < 1 && fabs (m.yy*image->height) < 1;
++
++ if (!use_mime && (image->format != CAIRO_FORMAT_RGB24 || axis_swap)) {
+ cairo_surface_t *opaque_surface;
+ cairo_surface_pattern_t image_pattern;
+ cairo_solid_pattern_t background_pattern;
++ int width = image->width, height = image->height;
+
++ if (axis_swap) {
++ width = image->height;
++ height = image->width;
++ }
+ opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+- image->width,
+- image->height);
++ width,
++ height);
+ if (opaque_surface->status) {
+ status = opaque_surface->status;
+ goto CLEANUP_OPAQUE_IMAGE;
+ }
+
+- _cairo_pattern_init_solid (&background_pattern,
+- background_color);
+- status = _cairo_surface_paint (opaque_surface,
+- CAIRO_OPERATOR_SOURCE,
+- &background_pattern.base,
+- NULL);
+- if (status)
+- goto CLEANUP_OPAQUE_IMAGE;
++ if (image->format != CAIRO_FORMAT_RGB24) {
++ _cairo_pattern_init_solid (&background_pattern,
++ background_color);
++ status = _cairo_surface_paint (opaque_surface,
++ CAIRO_OPERATOR_SOURCE,
++ &background_pattern.base,
++ NULL);
++ if (status)
++ goto CLEANUP_OPAQUE_IMAGE;
++ }
+
+ _cairo_pattern_init_for_surface (&image_pattern, &image->base);
++ if (axis_swap) {
++ /* swap the X and Y axes to undo the axis swap in the matrix */
++ cairo_matrix_t swap_xy = { 0, 1, 1, 0, 0, 0 };
++ cairo_pattern_set_matrix (&image_pattern.base, &swap_xy);
++ cairo_matrix_multiply (&m, &swap_xy, &m);
++ }
+ status = _cairo_surface_paint (opaque_surface,
+ CAIRO_OPERATOR_OVER,
+ &image_pattern.base,
+ NULL);
+ _cairo_pattern_fini (&image_pattern.base);
+ if (status)
+ goto CLEANUP_OPAQUE_IMAGE;
+
+@@ -706,23 +733,16 @@ static cairo_status_t
+ bi.bmiHeader.biXPelsPerMeter = PELS_72DPI;
+ bi.bmiHeader.biYPelsPerMeter = PELS_72DPI;
+ bi.bmiHeader.biPlanes = 1;
+ bi.bmiHeader.biBitCount = 32;
+ bi.bmiHeader.biCompression = use_mime ? mime_type : BI_RGB;
+ bi.bmiHeader.biClrUsed = 0;
+ bi.bmiHeader.biClrImportant = 0;
+
+- m = pattern->base.matrix;
+- status = cairo_matrix_invert (&m);
+- /* _cairo_pattern_set_matrix guarantees invertibility */
+- assert (status == CAIRO_STATUS_SUCCESS);
+-
+- cairo_matrix_multiply (&m, &m, &surface->gdi_ctm);
+- cairo_matrix_multiply(&m, &m, &surface->ctm);
+ SaveDC (surface->dc);
+ _cairo_matrix_to_win32_xform (&m, &xform);
+
+ if (! SetWorldTransform (surface->dc, &xform)) {
+ status = _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint_image_pattern");
+ goto CLEANUP_OPAQUE_IMAGE;
+ }
+
+@@ -1260,16 +1280,17 @@ static cairo_int_status_t
+ DWORD pen_width;
+ DWORD *dash_array;
+ HGDIOBJ obj;
+ unsigned int i;
+ cairo_solid_pattern_t clear;
+ cairo_matrix_t mat;
+ double scale;
+ double scaled_width;
++ double major, minor;
+
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (status)
+ return status;
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ _cairo_win32_printing_surface_init_clear_color (surface, &clear);
+ source = (cairo_pattern_t*) &clear;
+@@ -1350,22 +1371,40 @@ static cairo_int_status_t
+ if (status)
+ return status;
+
+ /*
+ * Switch to user space to set line parameters
+ */
+ SaveDC (surface->dc);
+
+- _cairo_matrix_to_win32_xform (&mat, &xform);
+- xform.eDx = 0.0f;
+- xform.eDy = 0.0f;
++ /* Some printers don't handle transformed strokes. Avoid the transform
++ * if not required for the pen shape. Use the SVD here to find the major
++ * and minor scales then check if they differ by more than 1 device unit.
++ * If the difference is smaller, then just treat the scaling as uniform.
++ * This check ignores rotations as the pen shape is symmetric before
++ * transformation.
++ */
++ _cairo_matrix_transformed_circle_axes (&mat, scale, &major, &minor);
++ if (fabs (major - minor) > 1) {
++ /* Check if the matrix swaps the X and Y axes such that the diagonal
++ * is nearly zero. This was observed to cause problems with XPS export.
++ */
++ if (fabs (mat.xx) < 1e-6 && fabs (mat.yy) < 1e-6) {
++ /* swap the X and Y axes to undo the axis swap in the matrix */
++ cairo_matrix_t swap_xy = { 0, 1, 1, 0, 0, 0 };
++ cairo_matrix_multiply (&mat, &swap_xy, &mat);
++ }
++ _cairo_matrix_to_win32_xform (&mat, &xform);
++ xform.eDx = 0.0f;
++ xform.eDy = 0.0f;
+
+- if (!ModifyWorldTransform (surface->dc, &xform, MWT_LEFTMULTIPLY))
+- return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SetWorldTransform");
++ if (!ModifyWorldTransform (surface->dc, &xform, MWT_LEFTMULTIPLY))
++ return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SetWorldTransform");
++ }
+
+ if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
+ StrokePath (surface->dc);
+ } else {
+ if (!WidenPath (surface->dc))
+ return _cairo_win32_print_gdi_error ("_win32_surface_stroke:WidenPath");
+ if (!SelectClipPath (surface->dc, RGN_AND))
+ return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectClipPath");
+diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h
+--- a/gfx/cairo/cairo/src/cairoint.h
++++ b/gfx/cairo/cairo/src/cairoint.h
+@@ -2115,16 +2115,22 @@ cairo_private cairo_bool_t
+ int *itx, int *ity);
+
+ cairo_private cairo_bool_t
+ _cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix);
+
+ cairo_private cairo_bool_t
+ _cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix) cairo_pure;
+
++cairo_private void
++_cairo_matrix_transformed_circle_axes (const cairo_matrix_t *matrix,
++ double radius,
++ double *major,
++ double *minor);
++
+ cairo_private double
+ _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
+ double radius) cairo_pure;
+
+ cairo_private void
+ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
+ pixman_transform_t *pixman_transform,
+ double xc,