Bug 1691109 [wpt PR 27513] - Increase timeout duration for wpt/fetch/api/basic/keepal...
[gecko.git] / gfx / cairo / win32-printing-axis-swap.patch
blob87a1a91e41c4c2d4aef18bda41bf30182062e911
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
7 workaround for Windows printer drivers that can't handle swapped X and Y axes
9 diff --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)).
17 For another derivation of the same result, using Singular Value Decomposition,
18 see doc/tutorial/src/singular.c.
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)
34 - double a, b, c, d, f, g, h, i, j;
35 + double a, b, c, d, f, g, h, i, j, k;
37 _cairo_matrix_get_affine (matrix,
38 &a, &b,
39 &c, &d,
40 NULL, NULL);
42 i = a*a + b*b;
43 j = c*c + d*d;
44 + k = a*c + b*d;
46 f = 0.5 * (i + j);
47 g = 0.5 * (i - j);
48 - h = a*c + b*d;
49 + h = hypot (g, k);
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);
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)
68 + double major;
70 + _cairo_matrix_transformed_circle_axes (matrix, radius, &major, NULL);
72 + return major;
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)
81 diff --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;
95 /* If we can't use StretchDIBits with this surface, we can't do anything
96 * here.
98 if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB))
99 return CAIRO_INT_STATUS_UNSUPPORTED;
101 if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
102 @@ -658,39 +659,65 @@ static cairo_status_t
103 &mime_size,
104 &mime_info);
106 if (_cairo_status_is_error (status))
107 return status;
109 use_mime = (status == CAIRO_STATUS_SUCCESS);
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;
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;
131 + if (axis_swap) {
132 + width = image->height;
133 + height = image->width;
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;
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;
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);
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;
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;
188 - m = pattern->base.matrix;
189 - status = cairo_matrix_invert (&m);
190 - /* _cairo_pattern_set_matrix guarantees invertibility */
191 - assert (status == CAIRO_STATUS_SUCCESS);
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);
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;
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;
214 status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
215 if (status)
216 return status;
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;
226 * Switch to user space to set line parameters
228 SaveDC (surface->dc);
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);
250 + _cairo_matrix_to_win32_xform (&mat, &xform);
251 + xform.eDx = 0.0f;
252 + xform.eDy = 0.0f;
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");
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");
267 diff --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);
273 cairo_private cairo_bool_t
274 _cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix);
276 cairo_private cairo_bool_t
277 _cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix) cairo_pure;
279 +cairo_private void
280 +_cairo_matrix_transformed_circle_axes (const cairo_matrix_t *matrix,
281 + double radius,
282 + double *major,
283 + double *minor);
285 cairo_private double
286 _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
287 double radius) cairo_pure;
289 cairo_private void
290 _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
291 pixman_transform_t *pixman_transform,
292 double xc,