1# HG changeset patch 2# User Lee Salzman <lsalzman@mozilla.com> 3# Date 1445463645 14400 4# Wed Oct 21 17:40:45 2015 -0400 5# Node ID 9e84563cbd73c5b0993dfd018ca25b660b667e94 6# Parent 2d3fd51c4182c253a2f102655e8e9e466032853f 7workaround for Windows printer drivers that can't handle swapped X and Y axes 8 9diff --git a/gfx/cairo/cairo/src/cairo-matrix.c b/gfx/cairo/cairo/src/cairo-matrix.c 10--- a/gfx/cairo/cairo/src/cairo-matrix.c 11+++ b/gfx/cairo/cairo/src/cairo-matrix.c 12@@ -873,42 +873,56 @@ cairo_bool_t 13 (Note that the minor axis length is at the minimum of the above solution, 14 which is just sqrt ( f - sqrt(g² + h²) ) given the symmetry of (D)). 15 16 17 For another derivation of the same result, using Singular Value Decomposition, 18 see doc/tutorial/src/singular.c. 19 */ 20 21-/* determine the length of the major axis of a circle of the given radius 22- after applying the transformation matrix. */ 23-double 24-_cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix, 25- double radius) 26+/* determine the length of the major and minor axes of a circle of the given 27+ radius after applying the transformation matrix. */ 28+void 29+_cairo_matrix_transformed_circle_axes (const cairo_matrix_t *matrix, 30+ double radius, 31+ double *major, 32+ double *minor) 33 { 34- double a, b, c, d, f, g, h, i, j; 35+ double a, b, c, d, f, g, h, i, j, k; 36 37 _cairo_matrix_get_affine (matrix, 38 &a, &b, 39 &c, &d, 40 NULL, NULL); 41 42 i = a*a + b*b; 43 j = c*c + d*d; 44+ k = a*c + b*d; 45 46 f = 0.5 * (i + j); 47 g = 0.5 * (i - j); 48- h = a*c + b*d; 49+ h = hypot (g, k); 50 51- return radius * sqrt (f + hypot (g, h)); 52+ if (major) 53+ *major = radius * sqrt (f + h); 54+ if (minor) 55+ *minor = radius * sqrt (f - h); 56+} 57 58- /* 59- * we don't need the minor axis length, which is 60- * double min = radius * sqrt (f - sqrt (g*g+h*h)); 61- */ 62+/* determine the length of the major axis of a circle of the given radius 63+ after applying the transformation matrix. */ 64+double 65+_cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix, 66+ double radius) 67+{ 68+ double major; 69+ 70+ _cairo_matrix_transformed_circle_axes (matrix, radius, &major, NULL); 71+ 72+ return major; 73 } 74 75 void 76 _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, 77 pixman_transform_t *pixman_transform, 78 double xc, 79 double yc) 80 { 81diff --git a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c 82--- a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c 83+++ b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c 84@@ -610,16 +610,17 @@ static cairo_status_t 85 int x_tile, y_tile, left, right, top, bottom; 86 RECT clip; 87 const cairo_color_t *background_color; 88 const unsigned char *mime_data; 89 unsigned long mime_size; 90 cairo_image_info_t mime_info; 91 cairo_bool_t use_mime; 92 DWORD mime_type; 93+ cairo_bool_t axis_swap; 94 95 /* If we can't use StretchDIBits with this surface, we can't do anything 96 * here. 97 */ 98 if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB)) 99 return CAIRO_INT_STATUS_UNSUPPORTED; 100 101 if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) 102@@ -658,39 +659,65 @@ static cairo_status_t 103 &mime_size, 104 &mime_info); 105 } 106 if (_cairo_status_is_error (status)) 107 return status; 108 109 use_mime = (status == CAIRO_STATUS_SUCCESS); 110 111- if (!use_mime && image->format != CAIRO_FORMAT_RGB24) { 112+ m = pattern->base.matrix; 113+ status = cairo_matrix_invert (&m); 114+ /* _cairo_pattern_set_matrix guarantees invertibility */ 115+ assert (status == CAIRO_STATUS_SUCCESS); 116+ cairo_matrix_multiply (&m, &m, &surface->ctm); 117+ cairo_matrix_multiply (&m, &m, &surface->gdi_ctm); 118+ /* Check if the matrix swaps the X and Y axes by checking if the diagonal 119+ * is effectively zero. This can happen, for example, if it was composed 120+ * with a rotation such as a landscape transform. Some printing devices 121+ * don't support such transforms in StretchDIBits. 122+ */ 123+ axis_swap = fabs (m.xx*image->width) < 1 && fabs (m.yy*image->height) < 1; 124+ 125+ if (!use_mime && (image->format != CAIRO_FORMAT_RGB24 || axis_swap)) { 126 cairo_surface_t *opaque_surface; 127 cairo_surface_pattern_t image_pattern; 128 cairo_solid_pattern_t background_pattern; 129+ int width = image->width, height = image->height; 130 131+ if (axis_swap) { 132+ width = image->height; 133+ height = image->width; 134+ } 135 opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 136- image->width, 137- image->height); 138+ width, 139+ height); 140 if (opaque_surface->status) { 141 status = opaque_surface->status; 142 goto CLEANUP_OPAQUE_IMAGE; 143 } 144 145- _cairo_pattern_init_solid (&background_pattern, 146- background_color); 147- status = _cairo_surface_paint (opaque_surface, 148- CAIRO_OPERATOR_SOURCE, 149- &background_pattern.base, 150- NULL); 151- if (status) 152- goto CLEANUP_OPAQUE_IMAGE; 153+ if (image->format != CAIRO_FORMAT_RGB24) { 154+ _cairo_pattern_init_solid (&background_pattern, 155+ background_color); 156+ status = _cairo_surface_paint (opaque_surface, 157+ CAIRO_OPERATOR_SOURCE, 158+ &background_pattern.base, 159+ NULL); 160+ if (status) 161+ goto CLEANUP_OPAQUE_IMAGE; 162+ } 163 164 _cairo_pattern_init_for_surface (&image_pattern, &image->base); 165+ if (axis_swap) { 166+ /* swap the X and Y axes to undo the axis swap in the matrix */ 167+ cairo_matrix_t swap_xy = { 0, 1, 1, 0, 0, 0 }; 168+ cairo_pattern_set_matrix (&image_pattern.base, &swap_xy); 169+ cairo_matrix_multiply (&m, &swap_xy, &m); 170+ } 171 status = _cairo_surface_paint (opaque_surface, 172 CAIRO_OPERATOR_OVER, 173 &image_pattern.base, 174 NULL); 175 _cairo_pattern_fini (&image_pattern.base); 176 if (status) 177 goto CLEANUP_OPAQUE_IMAGE; 178 179@@ -706,23 +733,16 @@ static cairo_status_t 180 bi.bmiHeader.biXPelsPerMeter = PELS_72DPI; 181 bi.bmiHeader.biYPelsPerMeter = PELS_72DPI; 182 bi.bmiHeader.biPlanes = 1; 183 bi.bmiHeader.biBitCount = 32; 184 bi.bmiHeader.biCompression = use_mime ? mime_type : BI_RGB; 185 bi.bmiHeader.biClrUsed = 0; 186 bi.bmiHeader.biClrImportant = 0; 187 188- m = pattern->base.matrix; 189- status = cairo_matrix_invert (&m); 190- /* _cairo_pattern_set_matrix guarantees invertibility */ 191- assert (status == CAIRO_STATUS_SUCCESS); 192- 193- cairo_matrix_multiply (&m, &m, &surface->gdi_ctm); 194- cairo_matrix_multiply(&m, &m, &surface->ctm); 195 SaveDC (surface->dc); 196 _cairo_matrix_to_win32_xform (&m, &xform); 197 198 if (! SetWorldTransform (surface->dc, &xform)) { 199 status = _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint_image_pattern"); 200 goto CLEANUP_OPAQUE_IMAGE; 201 } 202 203@@ -1260,16 +1280,17 @@ static cairo_int_status_t 204 DWORD pen_width; 205 DWORD *dash_array; 206 HGDIOBJ obj; 207 unsigned int i; 208 cairo_solid_pattern_t clear; 209 cairo_matrix_t mat; 210 double scale; 211 double scaled_width; 212+ double major, minor; 213 214 status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); 215 if (status) 216 return status; 217 218 if (op == CAIRO_OPERATOR_CLEAR) { 219 _cairo_win32_printing_surface_init_clear_color (surface, &clear); 220 source = (cairo_pattern_t*) &clear; 221@@ -1350,22 +1371,40 @@ static cairo_int_status_t 222 if (status) 223 return status; 224 225 /* 226 * Switch to user space to set line parameters 227 */ 228 SaveDC (surface->dc); 229 230- _cairo_matrix_to_win32_xform (&mat, &xform); 231- xform.eDx = 0.0f; 232- xform.eDy = 0.0f; 233+ /* Some printers don't handle transformed strokes. Avoid the transform 234+ * if not required for the pen shape. Use the SVD here to find the major 235+ * and minor scales then check if they differ by more than 1 device unit. 236+ * If the difference is smaller, then just treat the scaling as uniform. 237+ * This check ignores rotations as the pen shape is symmetric before 238+ * transformation. 239+ */ 240+ _cairo_matrix_transformed_circle_axes (&mat, scale, &major, &minor); 241+ if (fabs (major - minor) > 1) { 242+ /* Check if the matrix swaps the X and Y axes such that the diagonal 243+ * is nearly zero. This was observed to cause problems with XPS export. 244+ */ 245+ if (fabs (mat.xx) < 1e-6 && fabs (mat.yy) < 1e-6) { 246+ /* swap the X and Y axes to undo the axis swap in the matrix */ 247+ cairo_matrix_t swap_xy = { 0, 1, 1, 0, 0, 0 }; 248+ cairo_matrix_multiply (&mat, &swap_xy, &mat); 249+ } 250+ _cairo_matrix_to_win32_xform (&mat, &xform); 251+ xform.eDx = 0.0f; 252+ xform.eDy = 0.0f; 253 254- if (!ModifyWorldTransform (surface->dc, &xform, MWT_LEFTMULTIPLY)) 255- return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SetWorldTransform"); 256+ if (!ModifyWorldTransform (surface->dc, &xform, MWT_LEFTMULTIPLY)) 257+ return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SetWorldTransform"); 258+ } 259 260 if (source->type == CAIRO_PATTERN_TYPE_SOLID) { 261 StrokePath (surface->dc); 262 } else { 263 if (!WidenPath (surface->dc)) 264 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:WidenPath"); 265 if (!SelectClipPath (surface->dc, RGN_AND)) 266 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectClipPath"); 267diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h 268--- a/gfx/cairo/cairo/src/cairoint.h 269+++ b/gfx/cairo/cairo/src/cairoint.h 270@@ -2115,16 +2115,22 @@ cairo_private cairo_bool_t 271 int *itx, int *ity); 272 273 cairo_private cairo_bool_t 274 _cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix); 275 276 cairo_private cairo_bool_t 277 _cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix) cairo_pure; 278 279+cairo_private void 280+_cairo_matrix_transformed_circle_axes (const cairo_matrix_t *matrix, 281+ double radius, 282+ double *major, 283+ double *minor); 284+ 285 cairo_private double 286 _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix, 287 double radius) cairo_pure; 288 289 cairo_private void 290 _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, 291 pixman_transform_t *pixman_transform, 292 double xc, 293