1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* Cairo - a vector graphics library with display and print output
3 *
4 * Copyright © 2007, 2008 Adrian Johnson
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
13 *
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
19 *
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
24 *
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
28 *
29 * The Original Code is the cairo graphics library.
30 *
31 * The Initial Developer of the Original Code is Adrian Johnson.
32 *
33 * Contributor(s):
34 * Adrian Johnson <ajohnson@redneon.com>
35 * Vladimir Vukicevic <vladimir@pobox.com>
36 */
37
38 #define WIN32_LEAN_AND_MEAN
39 /* We require Windows 2000 features such as ETO_PDY */
40 #if !defined(WINVER) || (WINVER < 0x0500)
41 # define WINVER 0x0500
42 #endif
43 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
44 # define _WIN32_WINNT 0x0500
45 #endif
46
47 #include "cairoint.h"
48
49 #include "cairo-error-private.h"
50 #include "cairo-paginated-private.h"
51
52 #include "cairo-clip-private.h"
53 #include "cairo-win32-private.h"
54 #include "cairo-recording-surface-private.h"
55 #include "cairo-scaled-font-subsets-private.h"
56 #include "cairo-image-info-private.h"
57 #include "cairo-surface-clipper-private.h"
58
59 #include <windows.h>
60
61 #if !defined(POSTSCRIPT_IDENTIFY)
62 # define POSTSCRIPT_IDENTIFY 0x1015
63 #endif
64
65 #if !defined(PSIDENT_GDICENTRIC)
66 # define PSIDENT_GDICENTRIC 0x0000
67 #endif
68
69 #if !defined(GET_PS_FEATURESETTING)
70 # define GET_PS_FEATURESETTING 0x1019
71 #endif
72
73 #if !defined(FEATURESETTING_PSLEVEL)
74 # define FEATURESETTING_PSLEVEL 0x0002
75 #endif
76
77 #if !defined(GRADIENT_FILL_RECT_H)
78 # define GRADIENT_FILL_RECT_H 0x00
79 #endif
80
81 #if !defined(CHECKJPEGFORMAT)
82 # define CHECKJPEGFORMAT 0x1017
83 #endif
84
85 #if !defined(CHECKPNGFORMAT)
86 # define CHECKPNGFORMAT 0x1018
87 #endif
88
89 #define PELS_72DPI ((LONG)(72. / 0.0254))
90
91 static const cairo_surface_backend_t cairo_win32_printing_surface_backend;
92 static const cairo_paginated_surface_backend_t cairo_win32_surface_paginated_backend;
93
94 static void
_cairo_win32_printing_surface_init_ps_mode(cairo_win32_surface_t * surface)95 _cairo_win32_printing_surface_init_ps_mode (cairo_win32_surface_t *surface)
96 {
97 DWORD word;
98 INT ps_feature, ps_level;
99
100 word = PSIDENT_GDICENTRIC;
101 if (ExtEscape (surface->dc, POSTSCRIPT_IDENTIFY, sizeof(DWORD), (char *)&word, 0, (char *)NULL) <= 0)
102 return;
103
104 ps_feature = FEATURESETTING_PSLEVEL;
105 if (ExtEscape (surface->dc, GET_PS_FEATURESETTING, sizeof(INT),
106 (char *)&ps_feature, sizeof(INT), (char *)&ps_level) <= 0)
107 return;
108
109 if (ps_level >= 3)
110 surface->flags |= CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT;
111 }
112
113 static void
_cairo_win32_printing_surface_init_image_support(cairo_win32_surface_t * surface)114 _cairo_win32_printing_surface_init_image_support (cairo_win32_surface_t *surface)
115 {
116 DWORD word;
117
118 word = CHECKJPEGFORMAT;
119 if (ExtEscape(surface->dc, QUERYESCSUPPORT, sizeof(word), (char *)&word, 0, (char *)NULL) > 0)
120 surface->flags |= CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG;
121
122 word = CHECKPNGFORMAT;
123 if (ExtEscape(surface->dc, QUERYESCSUPPORT, sizeof(word), (char *)&word, 0, (char *)NULL) > 0)
124 surface->flags |= CAIRO_WIN32_SURFACE_CAN_CHECK_PNG;
125 }
126
127 /* When creating an EMF file, ExtTextOut with ETO_GLYPH_INDEX does not
128 * work unless the GDI function GdiInitializeLanguagePack() has been
129 * called.
130 *
131 * http://m-a-tech.blogspot.com/2009/04/emf-buffer-idiocracy.html
132 *
133 * The only information I could find on the how to use this
134 * undocumented function is the use in:
135 *
136 * http://src.chromium.org/viewvc/chrome/trunk/src/chrome/renderer/render_process.cc?view=markup
137 *
138 * to solve the same problem. The above code first checks if LPK.DLL
139 * is already loaded. If it is not it calls
140 * GdiInitializeLanguagePack() using the prototype
141 * BOOL GdiInitializeLanguagePack (int)
142 * and argument 0.
143 */
144 static void
_cairo_win32_printing_surface_init_language_pack(cairo_win32_surface_t * surface)145 _cairo_win32_printing_surface_init_language_pack (cairo_win32_surface_t *surface)
146 {
147 typedef BOOL (WINAPI *gdi_init_lang_pack_func_t)(int);
148 gdi_init_lang_pack_func_t gdi_init_lang_pack;
149 HMODULE module;
150
151 if (GetModuleHandleW (L"LPK.DLL"))
152 return;
153
154 module = GetModuleHandleW (L"GDI32.DLL");
155 if (module) {
156 gdi_init_lang_pack = (gdi_init_lang_pack_func_t)
157 GetProcAddress (module, "GdiInitializeLanguagePack");
158 if (gdi_init_lang_pack)
159 gdi_init_lang_pack (0);
160 }
161 }
162
163 static cairo_int_status_t
analyze_surface_pattern_transparency(cairo_surface_pattern_t * pattern)164 analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern)
165 {
166 cairo_image_surface_t *image;
167 void *image_extra;
168 cairo_int_status_t status;
169 cairo_image_transparency_t transparency;
170
171 status = _cairo_surface_acquire_source_image (pattern->surface,
172 &image,
173 &image_extra);
174 if (status)
175 return status;
176
177 transparency = _cairo_image_analyze_transparency (image);
178 switch (transparency) {
179 case CAIRO_IMAGE_UNKNOWN:
180 ASSERT_NOT_REACHED;
181 case CAIRO_IMAGE_IS_OPAQUE:
182 status = CAIRO_STATUS_SUCCESS;
183 break;
184
185 case CAIRO_IMAGE_HAS_BILEVEL_ALPHA:
186 case CAIRO_IMAGE_HAS_ALPHA:
187 status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
188 break;
189 }
190
191 _cairo_surface_release_source_image (pattern->surface, image, image_extra);
192
193 return status;
194 }
195
196 static cairo_bool_t
surface_pattern_supported(const cairo_surface_pattern_t * pattern)197 surface_pattern_supported (const cairo_surface_pattern_t *pattern)
198 {
199 if (_cairo_surface_is_recording (pattern->surface))
200 return TRUE;
201
202 if (cairo_surface_get_type (pattern->surface) != CAIRO_SURFACE_TYPE_WIN32 &&
203 pattern->surface->backend->acquire_source_image == NULL)
204 {
205 return FALSE;
206 }
207
208 return TRUE;
209 }
210
211 static cairo_bool_t
pattern_supported(cairo_win32_surface_t * surface,const cairo_pattern_t * pattern)212 pattern_supported (cairo_win32_surface_t *surface, const cairo_pattern_t *pattern)
213 {
214 if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
215 return TRUE;
216
217 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
218 return surface_pattern_supported ((const cairo_surface_pattern_t *) pattern);
219
220 if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR)
221 return surface->flags & CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT;
222
223 return FALSE;
224 }
225
226 static cairo_int_status_t
_cairo_win32_printing_surface_analyze_operation(cairo_win32_surface_t * surface,cairo_operator_t op,const cairo_pattern_t * pattern)227 _cairo_win32_printing_surface_analyze_operation (cairo_win32_surface_t *surface,
228 cairo_operator_t op,
229 const cairo_pattern_t *pattern)
230 {
231 if (! pattern_supported (surface, pattern))
232 return CAIRO_INT_STATUS_UNSUPPORTED;
233
234 if (!(op == CAIRO_OPERATOR_SOURCE ||
235 op == CAIRO_OPERATOR_OVER ||
236 op == CAIRO_OPERATOR_CLEAR))
237 return CAIRO_INT_STATUS_UNSUPPORTED;
238
239 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
240 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
241
242 if ( _cairo_surface_is_recording (surface_pattern->surface))
243 return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
244 }
245
246 if (op == CAIRO_OPERATOR_SOURCE ||
247 op == CAIRO_OPERATOR_CLEAR)
248 return CAIRO_STATUS_SUCCESS;
249
250 /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
251 * the pattern contains transparency, we return
252 * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
253 * surface. If the analysis surface determines that there is
254 * anything drawn under this operation, a fallback image will be
255 * used. Otherwise the operation will be replayed during the
256 * render stage and we blend the transarency into the white
257 * background to convert the pattern to opaque.
258 */
259
260 if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
261 cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
262
263 return analyze_surface_pattern_transparency (surface_pattern);
264 }
265
266 if (_cairo_pattern_is_opaque (pattern, NULL))
267 return CAIRO_STATUS_SUCCESS;
268 else
269 return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
270 }
271
272 static cairo_bool_t
_cairo_win32_printing_surface_operation_supported(cairo_win32_surface_t * surface,cairo_operator_t op,const cairo_pattern_t * pattern)273 _cairo_win32_printing_surface_operation_supported (cairo_win32_surface_t *surface,
274 cairo_operator_t op,
275 const cairo_pattern_t *pattern)
276 {
277 if (_cairo_win32_printing_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED)
278 return TRUE;
279 else
280 return FALSE;
281 }
282
283 static void
_cairo_win32_printing_surface_init_clear_color(cairo_win32_surface_t * surface,cairo_solid_pattern_t * color)284 _cairo_win32_printing_surface_init_clear_color (cairo_win32_surface_t *surface,
285 cairo_solid_pattern_t *color)
286 {
287 if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
288 _cairo_pattern_init_solid (color, CAIRO_COLOR_WHITE);
289 else
290 _cairo_pattern_init_solid (color, CAIRO_COLOR_BLACK);
291 }
292
293 static COLORREF
_cairo_win32_printing_surface_flatten_transparency(cairo_win32_surface_t * surface,const cairo_color_t * color)294 _cairo_win32_printing_surface_flatten_transparency (cairo_win32_surface_t *surface,
295 const cairo_color_t *color)
296 {
297 COLORREF c;
298 BYTE red, green, blue;
299
300 red = color->red_short >> 8;
301 green = color->green_short >> 8;
302 blue = color->blue_short >> 8;
303
304 if (!CAIRO_COLOR_IS_OPAQUE(color)) {
305 if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
306 /* Blend into white */
307 uint8_t one_minus_alpha = 255 - (color->alpha_short >> 8);
308
309 red = (color->red_short >> 8) + one_minus_alpha;
310 green = (color->green_short >> 8) + one_minus_alpha;
311 blue = (color->blue_short >> 8) + one_minus_alpha;
312 } else {
313 /* Blend into black */
314 red = (color->red_short >> 8);
315 green = (color->green_short >> 8);
316 blue = (color->blue_short >> 8);
317 }
318 }
319 c = RGB (red, green, blue);
320
321 return c;
322 }
323
324 static cairo_status_t
_cairo_win32_printing_surface_select_solid_brush(cairo_win32_surface_t * surface,const cairo_pattern_t * source)325 _cairo_win32_printing_surface_select_solid_brush (cairo_win32_surface_t *surface,
326 const cairo_pattern_t *source)
327 {
328 cairo_solid_pattern_t *pattern = (cairo_solid_pattern_t *) source;
329 COLORREF color;
330
331 color = _cairo_win32_printing_surface_flatten_transparency (surface,
332 &pattern->color);
333 surface->brush = CreateSolidBrush (color);
334 if (!surface->brush)
335 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_select_solid_brush(CreateSolidBrush)");
336 surface->old_brush = SelectObject (surface->dc, surface->brush);
337
338 return CAIRO_STATUS_SUCCESS;
339 }
340
341 static void
_cairo_win32_printing_surface_done_solid_brush(cairo_win32_surface_t * surface)342 _cairo_win32_printing_surface_done_solid_brush (cairo_win32_surface_t *surface)
343 {
344 if (surface->old_brush) {
345 SelectObject (surface->dc, surface->old_brush);
346 DeleteObject (surface->brush);
347 surface->old_brush = NULL;
348 }
349 }
350
351 static cairo_status_t
_cairo_win32_printing_surface_get_ctm_clip_box(cairo_win32_surface_t * surface,RECT * clip)352 _cairo_win32_printing_surface_get_ctm_clip_box (cairo_win32_surface_t *surface,
353 RECT *clip)
354 {
355 XFORM xform;
356
357 _cairo_matrix_to_win32_xform (&surface->ctm, &xform);
358 if (!ModifyWorldTransform (surface->dc, &xform, MWT_LEFTMULTIPLY))
359 return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:ModifyWorldTransform");
360 GetClipBox (surface->dc, clip);
361
362 _cairo_matrix_to_win32_xform (&surface->gdi_ctm, &xform);
363 if (!SetWorldTransform (surface->dc, &xform))
364 return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:SetWorldTransform");
365
366 return CAIRO_STATUS_SUCCESS;
367 }
368
369 static cairo_status_t
_cairo_win32_printing_surface_paint_solid_pattern(cairo_win32_surface_t * surface,const cairo_pattern_t * pattern)370 _cairo_win32_printing_surface_paint_solid_pattern (cairo_win32_surface_t *surface,
371 const cairo_pattern_t *pattern)
372 {
373 RECT clip;
374 cairo_status_t status;
375
376 GetClipBox (surface->dc, &clip);
377 status = _cairo_win32_printing_surface_select_solid_brush (surface, pattern);
378 if (status)
379 return status;
380
381 FillRect (surface->dc, &clip, surface->brush);
382 _cairo_win32_printing_surface_done_solid_brush (surface);
383
384 return CAIRO_STATUS_SUCCESS;
385 }
386
387 static cairo_status_t
_cairo_win32_printing_surface_paint_recording_pattern(cairo_win32_surface_t * surface,cairo_surface_pattern_t * pattern)388 _cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_surface_t *surface,
389 cairo_surface_pattern_t *pattern)
390 {
391 cairo_content_t old_content;
392 cairo_matrix_t old_ctm;
393 cairo_bool_t old_has_ctm;
394 cairo_rectangle_int_t recording_extents;
395 cairo_status_t status;
396 cairo_extend_t extend;
397 cairo_matrix_t p2d;
398 XFORM xform;
399 int x_tile, y_tile, left, right, top, bottom;
400 RECT clip;
401 cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) pattern->surface;
402 cairo_box_t bbox;
403
404 extend = cairo_pattern_get_extend (&pattern->base);
405
406 p2d = pattern->base.matrix;
407 status = cairo_matrix_invert (&p2d);
408 /* _cairo_pattern_set_matrix guarantees invertibility */
409 assert (status == CAIRO_STATUS_SUCCESS);
410
411 old_ctm = surface->ctm;
412 old_has_ctm = surface->has_ctm;
413 cairo_matrix_multiply (&p2d, &p2d, &surface->ctm);
414 surface->ctm = p2d;
415 SaveDC (surface->dc);
416 _cairo_matrix_to_win32_xform (&p2d, &xform);
417
418 status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
419 if (status)
420 return status;
421
422 _cairo_box_round_to_rectangle (&bbox, &recording_extents);
423
424 status = _cairo_win32_printing_surface_get_ctm_clip_box (surface, &clip);
425 if (status)
426 return status;
427
428 if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) {
429 left = floor (clip.left / _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x));
430 right = ceil (clip.right / _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x));
431 top = floor (clip.top / _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y));
432 bottom = ceil (clip.bottom / _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y));
433 } else {
434 left = 0;
435 right = 1;
436 top = 0;
437 bottom = 1;
438 }
439
440 old_content = surface->content;
441 if (recording_surface->base.content == CAIRO_CONTENT_COLOR) {
442 surface->content = CAIRO_CONTENT_COLOR;
443 status = _cairo_win32_printing_surface_paint_solid_pattern (surface,
444 &_cairo_pattern_black.base);
445 if (status)
446 return status;
447 }
448
449 for (y_tile = top; y_tile < bottom; y_tile++) {
450 for (x_tile = left; x_tile < right; x_tile++) {
451 cairo_matrix_t m;
452 double x, y;
453
454 SaveDC (surface->dc);
455 m = p2d;
456 cairo_matrix_translate (&m,
457 x_tile*recording_extents.width,
458 y_tile*recording_extents.height);
459 if (extend == CAIRO_EXTEND_REFLECT) {
460 if (x_tile % 2) {
461 cairo_matrix_translate (&m, recording_extents.width, 0);
462 cairo_matrix_scale (&m, -1, 1);
463 }
464 if (y_tile % 2) {
465 cairo_matrix_translate (&m, 0, recording_extents.height);
466 cairo_matrix_scale (&m, 1, -1);
467 }
468 }
469 surface->ctm = m;
470 surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
471
472 /* Set clip path around bbox of the pattern. */
473 BeginPath (surface->dc);
474
475 x = 0;
476 y = 0;
477 cairo_matrix_transform_point (&surface->ctm, &x, &y);
478 MoveToEx (surface->dc, (int) x, (int) y, NULL);
479
480 x = recording_extents.width;
481 y = 0;
482 cairo_matrix_transform_point (&surface->ctm, &x, &y);
483 LineTo (surface->dc, (int) x, (int) y);
484
485 x = recording_extents.width;
486 y = recording_extents.height;
487 cairo_matrix_transform_point (&surface->ctm, &x, &y);
488 LineTo (surface->dc, (int) x, (int) y);
489
490 x = 0;
491 y = recording_extents.height;
492 cairo_matrix_transform_point (&surface->ctm, &x, &y);
493 LineTo (surface->dc, (int) x, (int) y);
494
495 CloseFigure (surface->dc);
496 EndPath (surface->dc);
497 SelectClipPath (surface->dc, RGN_AND);
498
499 SaveDC (surface->dc); /* Allow clip path to be reset during replay */
500 status = _cairo_recording_surface_replay_region (&recording_surface->base, NULL,
501 &surface->base,
502 CAIRO_RECORDING_REGION_NATIVE);
503 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
504 /* Restore both the clip save and our earlier path SaveDC */
505 RestoreDC (surface->dc, -2);
506
507 if (status)
508 return status;
509 }
510 }
511
512 surface->content = old_content;
513 surface->ctm = old_ctm;
514 surface->has_ctm = old_has_ctm;
515 RestoreDC (surface->dc, -1);
516
517 return status;
518 }
519
520 static cairo_int_status_t
_cairo_win32_printing_surface_check_jpeg(cairo_win32_surface_t * surface,cairo_surface_t * source,const unsigned char ** data,unsigned long * length,cairo_image_info_t * info)521 _cairo_win32_printing_surface_check_jpeg (cairo_win32_surface_t *surface,
522 cairo_surface_t *source,
523 const unsigned char **data,
524 unsigned long *length,
525 cairo_image_info_t *info)
526 {
527 const unsigned char *mime_data;
528 unsigned long mime_data_length;
529 cairo_int_status_t status;
530 DWORD result;
531
532 if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG))
533 return CAIRO_INT_STATUS_UNSUPPORTED;
534
535 cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
536 &mime_data, &mime_data_length);
537 if (mime_data == NULL)
538 return CAIRO_INT_STATUS_UNSUPPORTED;
539
540 status = _cairo_image_info_get_jpeg_info (info, mime_data, mime_data_length);
541 if (status)
542 return status;
543
544 result = 0;
545 if (ExtEscape(surface->dc, CHECKJPEGFORMAT, mime_data_length, (char *) mime_data,
546 sizeof(result), (char *) &result) <= 0)
547 return CAIRO_INT_STATUS_UNSUPPORTED;
548
549 if (result != 1)
550 return CAIRO_INT_STATUS_UNSUPPORTED;
551
552 *data = mime_data;
553 *length = mime_data_length;
554
555 return CAIRO_STATUS_SUCCESS;
556 }
557
558 static cairo_int_status_t
_cairo_win32_printing_surface_check_png(cairo_win32_surface_t * surface,cairo_surface_t * source,const unsigned char ** data,unsigned long * length,cairo_image_info_t * info)559 _cairo_win32_printing_surface_check_png (cairo_win32_surface_t *surface,
560 cairo_surface_t *source,
561 const unsigned char **data,
562 unsigned long *length,
563 cairo_image_info_t *info)
564 {
565 const unsigned char *mime_data;
566 unsigned long mime_data_length;
567
568 cairo_int_status_t status;
569 DWORD result;
570
571 if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_CHECK_PNG))
572 return CAIRO_INT_STATUS_UNSUPPORTED;
573
574 cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_PNG,
575 &mime_data, &mime_data_length);
576 if (mime_data == NULL)
577 return CAIRO_INT_STATUS_UNSUPPORTED;
578
579 status = _cairo_image_info_get_png_info (info, mime_data, mime_data_length);
580 if (status)
581 return status;
582
583 result = 0;
584 if (ExtEscape(surface->dc, CHECKPNGFORMAT, mime_data_length, (char *) mime_data,
585 sizeof(result), (char *) &result) <= 0)
586 return CAIRO_INT_STATUS_UNSUPPORTED;
587
588 if (result != 1)
589 return CAIRO_INT_STATUS_UNSUPPORTED;
590
591 *data = mime_data;
592 *length = mime_data_length;
593
594 return CAIRO_STATUS_SUCCESS;
595 }
596
597 static cairo_status_t
_cairo_win32_printing_surface_paint_image_pattern(cairo_win32_surface_t * surface,cairo_surface_pattern_t * pattern)598 _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surface,
599 cairo_surface_pattern_t *pattern)
600 {
601 cairo_status_t status;
602 cairo_extend_t extend;
603 cairo_image_surface_t *image;
604 void *image_extra;
605 cairo_image_surface_t *opaque_image = NULL;
606 BITMAPINFO bi;
607 cairo_matrix_t m;
608 int oldmode;
609 XFORM xform;
610 int x_tile, y_tile, left, right, top, bottom;
611 RECT clip;
612 const cairo_color_t *background_color;
613 const unsigned char *mime_data;
614 unsigned long mime_size;
615 cairo_image_info_t mime_info;
616 cairo_bool_t use_mime;
617 DWORD mime_type;
618 cairo_bool_t axis_swap;
619
620 /* If we can't use StretchDIBits with this surface, we can't do anything
621 * here.
622 */
623 if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB))
624 return CAIRO_INT_STATUS_UNSUPPORTED;
625
626 if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
627 background_color = CAIRO_COLOR_WHITE;
628 else
629 background_color = CAIRO_COLOR_BLACK;
630
631 extend = cairo_pattern_get_extend (&pattern->base);
632
633 status = _cairo_surface_acquire_source_image (pattern->surface,
634 &image, &image_extra);
635 if (status)
636 return status;
637
638 if (image->base.status) {
639 status = image->base.status;
640 goto CLEANUP_IMAGE;
641 }
642
643 if (image->width == 0 || image->height == 0) {
644 status = CAIRO_STATUS_SUCCESS;
645 goto CLEANUP_IMAGE;
646 }
647
648 mime_type = BI_JPEG;
649 status = _cairo_win32_printing_surface_check_jpeg (surface,
650 pattern->surface,
651 &mime_data,
652 &mime_size,
653 &mime_info);
654 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
655 mime_type = BI_PNG;
656 status = _cairo_win32_printing_surface_check_png (surface,
657 pattern->surface,
658 &mime_data,
659 &mime_size,
660 &mime_info);
661 }
662 if (_cairo_status_is_error (status))
663 return status;
664
665 use_mime = (status == CAIRO_STATUS_SUCCESS);
666
667 m = pattern->base.matrix;
668 status = cairo_matrix_invert (&m);
669 /* _cairo_pattern_set_matrix guarantees invertibility */
670 assert (status == CAIRO_STATUS_SUCCESS);
671 cairo_matrix_multiply (&m, &m, &surface->ctm);
672 cairo_matrix_multiply (&m, &m, &surface->gdi_ctm);
673 /* Check if the matrix swaps the X and Y axes by checking if the diagonal
674 * is effectively zero. This can happen, for example, if it was composed
675 * with a rotation such as a landscape transform. Some printing devices
676 * don't support such transforms in StretchDIBits.
677 */
678 axis_swap = fabs (m.xx*image->width) < 1 && fabs (m.yy*image->height) < 1;
679
680 if (!use_mime && (image->format != CAIRO_FORMAT_RGB24 || axis_swap)) {
681 cairo_surface_t *opaque_surface;
682 cairo_surface_pattern_t image_pattern;
683 cairo_solid_pattern_t background_pattern;
684 int width = image->width, height = image->height;
685
686 if (axis_swap) {
687 width = image->height;
688 height = image->width;
689 }
690 opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
691 width,
692 height);
693 if (opaque_surface->status) {
694 status = opaque_surface->status;
695 goto CLEANUP_OPAQUE_IMAGE;
696 }
697
698 if (image->format != CAIRO_FORMAT_RGB24) {
699 _cairo_pattern_init_solid (&background_pattern,
700 background_color);
701 status = _cairo_surface_paint (opaque_surface,
702 CAIRO_OPERATOR_SOURCE,
703 &background_pattern.base,
704 NULL);
705 if (status)
706 goto CLEANUP_OPAQUE_IMAGE;
707 }
708
709 _cairo_pattern_init_for_surface (&image_pattern, &image->base);
710 if (axis_swap) {
711 /* swap the X and Y axes to undo the axis swap in the matrix */
712 cairo_matrix_t swap_xy = { 0, 1, 1, 0, 0, 0 };
713 cairo_pattern_set_matrix (&image_pattern.base, &swap_xy);
714 cairo_matrix_multiply (&m, &swap_xy, &m);
715 }
716 status = _cairo_surface_paint (opaque_surface,
717 CAIRO_OPERATOR_OVER,
718 &image_pattern.base,
719 NULL);
720 _cairo_pattern_fini (&image_pattern.base);
721 if (status)
722 goto CLEANUP_OPAQUE_IMAGE;
723
724 opaque_image = (cairo_image_surface_t *) opaque_surface;
725 } else {
726 opaque_image = image;
727 }
728
729 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
730 bi.bmiHeader.biWidth = use_mime ? mime_info.width : opaque_image->width;
731 bi.bmiHeader.biHeight = use_mime ? - mime_info.height : -opaque_image->height;
732 bi.bmiHeader.biSizeImage = use_mime ? mime_size : 0;
733 bi.bmiHeader.biXPelsPerMeter = PELS_72DPI;
734 bi.bmiHeader.biYPelsPerMeter = PELS_72DPI;
735 bi.bmiHeader.biPlanes = 1;
736 bi.bmiHeader.biBitCount = 32;
737 bi.bmiHeader.biCompression = use_mime ? mime_type : BI_RGB;
738 bi.bmiHeader.biClrUsed = 0;
739 bi.bmiHeader.biClrImportant = 0;
740
741 SaveDC (surface->dc);
742 _cairo_matrix_to_win32_xform (&m, &xform);
743
744 if (! SetWorldTransform (surface->dc, &xform)) {
745 status = _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint_image_pattern");
746 goto CLEANUP_OPAQUE_IMAGE;
747 }
748
749 oldmode = SetStretchBltMode(surface->dc, HALFTONE);
750
751 GetClipBox (surface->dc, &clip);
752 if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) {
753 left = floor ( clip.left / (double) opaque_image->width);
754 right = ceil (clip.right / (double) opaque_image->width);
755 top = floor (clip.top / (double) opaque_image->height);
756 bottom = ceil (clip.bottom / (double) opaque_image->height);
757 } else {
758 left = 0;
759 right = 1;
760 top = 0;
761 bottom = 1;
762 }
763
764 for (y_tile = top; y_tile < bottom; y_tile++) {
765 for (x_tile = left; x_tile < right; x_tile++) {
766 if (!StretchDIBits (surface->dc,
767 x_tile*opaque_image->width,
768 y_tile*opaque_image->height,
769 opaque_image->width,
770 opaque_image->height,
771 0,
772 0,
773 use_mime ? mime_info.width : opaque_image->width,
774 use_mime ? mime_info.height : opaque_image->height,
775 use_mime ? mime_data : opaque_image->data,
776 &bi,
777 DIB_RGB_COLORS,
778 SRCCOPY))
779 {
780 status = _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint(StretchDIBits)");
781 goto CLEANUP_OPAQUE_IMAGE;
782 }
783 }
784 }
785 SetStretchBltMode(surface->dc, oldmode);
786 RestoreDC (surface->dc, -1);
787
788 CLEANUP_OPAQUE_IMAGE:
789 if (opaque_image != image)
790 cairo_surface_destroy (&opaque_image->base);
791 CLEANUP_IMAGE:
792 _cairo_surface_release_source_image (pattern->surface, image, image_extra);
793
794 return status;
795 }
796
797 static cairo_status_t
_cairo_win32_printing_surface_paint_surface_pattern(cairo_win32_surface_t * surface,cairo_surface_pattern_t * pattern)798 _cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t *surface,
799 cairo_surface_pattern_t *pattern)
800 {
801 if (_cairo_surface_is_recording (pattern->surface)) {
802 return _cairo_win32_printing_surface_paint_recording_pattern (surface,
803 pattern);
804 } else {
805 return _cairo_win32_printing_surface_paint_image_pattern (surface,
806 pattern);
807 }
808 }
809
810 static void
vertex_set_color(TRIVERTEX * vert,cairo_color_stop_t * color)811 vertex_set_color (TRIVERTEX *vert, cairo_color_stop_t *color)
812 {
813 /* MSDN says that the range here is 0x0000 .. 0xff00;
814 * that may well be a typo, but just chop the low bits
815 * here. */
816 vert->Alpha = 0xff00;
817 vert->Red = color->red_short & 0xff00;
818 vert->Green = color->green_short & 0xff00;
819 vert->Blue = color->blue_short & 0xff00;
820 }
821
822 static cairo_int_status_t
_cairo_win32_printing_surface_paint_linear_pattern(cairo_win32_surface_t * surface,cairo_linear_pattern_t * pattern)823 _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surface,
824 cairo_linear_pattern_t *pattern)
825 {
826 TRIVERTEX *vert;
827 GRADIENT_RECT *rect;
828 RECT clip;
829 XFORM xform;
830 int i, num_stops;
831 cairo_matrix_t mat, rot;
832 double p1x, p1y, p2x, p2y, xd, yd, d, sn, cs;
833 cairo_extend_t extend;
834 int range_start, range_stop, num_ranges, num_rects, stop;
835 int total_verts, total_rects;
836 cairo_status_t status;
837
838 extend = cairo_pattern_get_extend (&pattern->base.base);
839 SaveDC (surface->dc);
840
841 mat = pattern->base.base.matrix;
842 status = cairo_matrix_invert (&mat);
843 /* _cairo_pattern_set_matrix guarantees invertibility */
844 assert (status == CAIRO_STATUS_SUCCESS);
845
846 cairo_matrix_multiply (&mat, &surface->ctm, &mat);
847
848 p1x = _cairo_fixed_to_double (pattern->p1.x);
849 p1y = _cairo_fixed_to_double (pattern->p1.y);
850 p2x = _cairo_fixed_to_double (pattern->p2.x);
851 p2y = _cairo_fixed_to_double (pattern->p2.y);
852 cairo_matrix_translate (&mat, p1x, p1y);
853
854 xd = p2x - p1x;
855 yd = p2y - p1y;
856 d = sqrt (xd*xd + yd*yd);
857 sn = yd/d;
858 cs = xd/d;
859 cairo_matrix_init (&rot,
860 cs, sn,
861 -sn, cs,
862 0, 0);
863 cairo_matrix_multiply (&mat, &rot, &mat);
864
865 _cairo_matrix_to_win32_xform (&mat, &xform);
866
867 if (!SetWorldTransform (surface->dc, &xform))
868 return _cairo_win32_print_gdi_error ("_win32_printing_surface_paint_linear_pattern:SetWorldTransform2");
869
870 GetClipBox (surface->dc, &clip);
871
872 if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) {
873 range_start = floor (clip.left / d);
874 range_stop = ceil (clip.right / d);
875 } else {
876 range_start = 0;
877 range_stop = 1;
878 }
879 num_ranges = range_stop - range_start;
880 num_stops = pattern->base.n_stops;
881 num_rects = num_stops - 1;
882
883 /* Add an extra four points and two rectangles for EXTEND_PAD */
884 vert = malloc (sizeof (TRIVERTEX) * (num_rects*2*num_ranges + 4));
885 rect = malloc (sizeof (GRADIENT_RECT) * (num_rects*num_ranges + 2));
886
887 for (i = 0; i < num_ranges*num_rects; i++) {
888 vert[i*2].y = (LONG) clip.top;
889 if (i%num_rects == 0) {
890 stop = 0;
891 if (extend == CAIRO_EXTEND_REFLECT && (range_start+(i/num_rects))%2)
892 stop = num_rects;
893 vert[i*2].x = (LONG)(d*(range_start + i/num_rects));
894 vertex_set_color (&vert[i*2], &pattern->base.stops[stop].color);
895 } else {
896 vert[i*2].x = vert[i*2-1].x;
897 vert[i*2].Red = vert[i*2-1].Red;
898 vert[i*2].Green = vert[i*2-1].Green;
899 vert[i*2].Blue = vert[i*2-1].Blue;
900 vert[i*2].Alpha = vert[i*2-1].Alpha;
901 }
902
903 stop = i%num_rects + 1;
904 vert[i*2+1].x = (LONG)(d*(range_start + i/num_rects + pattern->base.stops[stop].offset));
905 vert[i*2+1].y = (LONG) clip.bottom;
906 if (extend == CAIRO_EXTEND_REFLECT && (range_start+(i/num_rects))%2)
907 stop = num_rects - stop;
908 vertex_set_color (&vert[i*2+1], &pattern->base.stops[stop].color);
909
910 rect[i].UpperLeft = i*2;
911 rect[i].LowerRight = i*2 + 1;
912 }
913 total_verts = 2*num_ranges*num_rects;
914 total_rects = num_ranges*num_rects;
915
916 if (extend == CAIRO_EXTEND_PAD) {
917 vert[i*2].x = vert[i*2-1].x;
918 vert[i*2].y = (LONG) clip.top;
919 vert[i*2].Red = vert[i*2-1].Red;
920 vert[i*2].Green = vert[i*2-1].Green;
921 vert[i*2].Blue = vert[i*2-1].Blue;
922 vert[i*2].Alpha = 0xff00;
923 vert[i*2+1].x = clip.right;
924 vert[i*2+1].y = (LONG) clip.bottom;
925 vert[i*2+1].Red = vert[i*2-1].Red;
926 vert[i*2+1].Green = vert[i*2-1].Green;
927 vert[i*2+1].Blue = vert[i*2-1].Blue;
928 vert[i*2+1].Alpha = 0xff00;
929 rect[i].UpperLeft = i*2;
930 rect[i].LowerRight = i*2 + 1;
931
932 i++;
933
934 vert[i*2].x = clip.left;
935 vert[i*2].y = (LONG) clip.top;
936 vert[i*2].Red = vert[0].Red;
937 vert[i*2].Green = vert[0].Green;
938 vert[i*2].Blue = vert[0].Blue;
939 vert[i*2].Alpha = 0xff00;
940 vert[i*2+1].x = vert[0].x;
941 vert[i*2+1].y = (LONG) clip.bottom;
942 vert[i*2+1].Red = vert[0].Red;
943 vert[i*2+1].Green = vert[0].Green;
944 vert[i*2+1].Blue = vert[0].Blue;
945 vert[i*2+1].Alpha = 0xff00;
946 rect[i].UpperLeft = i*2;
947 rect[i].LowerRight = i*2 + 1;
948
949 total_verts += 4;
950 total_rects += 2;
951 }
952
953 if (!GradientFill (surface->dc,
954 vert, total_verts,
955 rect, total_rects,
956 GRADIENT_FILL_RECT_H))
957 return _cairo_win32_print_gdi_error ("_win32_printing_surface_paint_linear_pattern:GradientFill");
958
959 free (rect);
960 free (vert);
961 RestoreDC (surface->dc, -1);
962
963 return 0;
964 }
965
966 static cairo_int_status_t
_cairo_win32_printing_surface_paint_pattern(cairo_win32_surface_t * surface,const cairo_pattern_t * pattern)967 _cairo_win32_printing_surface_paint_pattern (cairo_win32_surface_t *surface,
968 const cairo_pattern_t *pattern)
969 {
970 cairo_status_t status;
971
972 switch (pattern->type) {
973 case CAIRO_PATTERN_TYPE_SOLID:
974 status = _cairo_win32_printing_surface_paint_solid_pattern (surface, pattern);
975 if (status)
976 return status;
977 break;
978
979 case CAIRO_PATTERN_TYPE_SURFACE:
980 status = _cairo_win32_printing_surface_paint_surface_pattern (surface,
981 (cairo_surface_pattern_t *) pattern);
982 if (status)
983 return status;
984 break;
985
986 case CAIRO_PATTERN_TYPE_LINEAR:
987 status = _cairo_win32_printing_surface_paint_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
988 if (status)
989 return status;
990 break;
991
992 case CAIRO_PATTERN_TYPE_RADIAL:
993 return CAIRO_INT_STATUS_UNSUPPORTED;
994 break;
995 }
996
997 return CAIRO_STATUS_SUCCESS;
998 }
999
1000 typedef struct _win32_print_path_info {
1001 cairo_win32_surface_t *surface;
1002 } win32_path_info_t;
1003
1004 static cairo_status_t
_cairo_win32_printing_surface_path_move_to(void * closure,const cairo_point_t * point)1005 _cairo_win32_printing_surface_path_move_to (void *closure,
1006 const cairo_point_t *point)
1007 {
1008 win32_path_info_t *path_info = closure;
1009
1010 if (path_info->surface->has_ctm) {
1011 double x, y;
1012
1013 x = _cairo_fixed_to_double (point->x);
1014 y = _cairo_fixed_to_double (point->y);
1015 cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
1016 MoveToEx (path_info->surface->dc, (int) x, (int) y, NULL);
1017 } else {
1018 MoveToEx (path_info->surface->dc,
1019 _cairo_fixed_integer_part (point->x),
1020 _cairo_fixed_integer_part (point->y),
1021 NULL);
1022 }
1023
1024 return CAIRO_STATUS_SUCCESS;
1025 }
1026
1027 static cairo_status_t
_cairo_win32_printing_surface_path_line_to(void * closure,const cairo_point_t * point)1028 _cairo_win32_printing_surface_path_line_to (void *closure,
1029 const cairo_point_t *point)
1030 {
1031 win32_path_info_t *path_info = closure;
1032
1033 path_info->surface->path_empty = FALSE;
1034 if (path_info->surface->has_ctm) {
1035 double x, y;
1036
1037 x = _cairo_fixed_to_double (point->x);
1038 y = _cairo_fixed_to_double (point->y);
1039 cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
1040 LineTo (path_info->surface->dc, (int) x, (int) y);
1041 } else {
1042 LineTo (path_info->surface->dc,
1043 _cairo_fixed_integer_part (point->x),
1044 _cairo_fixed_integer_part (point->y));
1045 }
1046
1047 return CAIRO_STATUS_SUCCESS;
1048 }
1049
1050 static cairo_status_t
_cairo_win32_printing_surface_path_curve_to(void * closure,const cairo_point_t * b,const cairo_point_t * c,const cairo_point_t * d)1051 _cairo_win32_printing_surface_path_curve_to (void *closure,
1052 const cairo_point_t *b,
1053 const cairo_point_t *c,
1054 const cairo_point_t *d)
1055 {
1056 win32_path_info_t *path_info = closure;
1057 POINT points[3];
1058
1059 path_info->surface->path_empty = FALSE;
1060 if (path_info->surface->has_ctm) {
1061 double x, y;
1062
1063 x = _cairo_fixed_to_double (b->x);
1064 y = _cairo_fixed_to_double (b->y);
1065 cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
1066 points[0].x = (LONG) x;
1067 points[0].y = (LONG) y;
1068
1069 x = _cairo_fixed_to_double (c->x);
1070 y = _cairo_fixed_to_double (c->y);
1071 cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
1072 points[1].x = (LONG) x;
1073 points[1].y = (LONG) y;
1074
1075 x = _cairo_fixed_to_double (d->x);
1076 y = _cairo_fixed_to_double (d->y);
1077 cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
1078 points[2].x = (LONG) x;
1079 points[2].y = (LONG) y;
1080 } else {
1081 points[0].x = _cairo_fixed_integer_part (b->x);
1082 points[0].y = _cairo_fixed_integer_part (b->y);
1083 points[1].x = _cairo_fixed_integer_part (c->x);
1084 points[1].y = _cairo_fixed_integer_part (c->y);
1085 points[2].x = _cairo_fixed_integer_part (d->x);
1086 points[2].y = _cairo_fixed_integer_part (d->y);
1087 }
1088 PolyBezierTo (path_info->surface->dc, points, 3);
1089
1090 return CAIRO_STATUS_SUCCESS;
1091 }
1092
1093 static cairo_status_t
_cairo_win32_printing_surface_path_close_path(void * closure)1094 _cairo_win32_printing_surface_path_close_path (void *closure)
1095 {
1096 win32_path_info_t *path_info = closure;
1097
1098 CloseFigure (path_info->surface->dc);
1099
1100 return CAIRO_STATUS_SUCCESS;
1101 }
1102
1103 static cairo_status_t
_cairo_win32_printing_surface_emit_path(cairo_win32_surface_t * surface,cairo_path_fixed_t * path)1104 _cairo_win32_printing_surface_emit_path (cairo_win32_surface_t *surface,
1105 cairo_path_fixed_t *path)
1106 {
1107 win32_path_info_t path_info;
1108
1109 path_info.surface = surface;
1110 return _cairo_path_fixed_interpret (path,
1111 CAIRO_DIRECTION_FORWARD,
1112 _cairo_win32_printing_surface_path_move_to,
1113 _cairo_win32_printing_surface_path_line_to,
1114 _cairo_win32_printing_surface_path_curve_to,
1115 _cairo_win32_printing_surface_path_close_path,
1116 &path_info);
1117 }
1118
1119 static cairo_int_status_t
_cairo_win32_printing_surface_show_page(void * abstract_surface)1120 _cairo_win32_printing_surface_show_page (void *abstract_surface)
1121 {
1122 cairo_win32_surface_t *surface = abstract_surface;
1123
1124 /* Undo both SaveDC's that we did in start_page */
1125 RestoreDC (surface->dc, -2);
1126
1127 return CAIRO_STATUS_SUCCESS;
1128 }
1129
1130 static cairo_status_t
_cairo_win32_printing_surface_clipper_intersect_clip_path(cairo_surface_clipper_t * clipper,cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias)1131 _cairo_win32_printing_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
1132 cairo_path_fixed_t *path,
1133 cairo_fill_rule_t fill_rule,
1134 double tolerance,
1135 cairo_antialias_t antialias)
1136 {
1137 cairo_win32_surface_t *surface = cairo_container_of (clipper,
1138 cairo_win32_surface_t,
1139 clipper);
1140 cairo_status_t status;
1141
1142 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
1143 return CAIRO_STATUS_SUCCESS;
1144
1145 if (path == NULL) {
1146 RestoreDC (surface->dc, -1);
1147 SaveDC (surface->dc);
1148
1149 return CAIRO_STATUS_SUCCESS;
1150 }
1151
1152 BeginPath (surface->dc);
1153 status = _cairo_win32_printing_surface_emit_path (surface, path);
1154 EndPath (surface->dc);
1155
1156 switch (fill_rule) {
1157 case CAIRO_FILL_RULE_WINDING:
1158 SetPolyFillMode (surface->dc, WINDING);
1159 break;
1160 case CAIRO_FILL_RULE_EVEN_ODD:
1161 SetPolyFillMode (surface->dc, ALTERNATE);
1162 break;
1163 default:
1164 ASSERT_NOT_REACHED;
1165 }
1166
1167 SelectClipPath (surface->dc, RGN_AND);
1168
1169 return status;
1170 }
1171
1172 static void
_cairo_win32_printing_surface_get_font_options(void * abstract_surface,cairo_font_options_t * options)1173 _cairo_win32_printing_surface_get_font_options (void *abstract_surface,
1174 cairo_font_options_t *options)
1175 {
1176 _cairo_font_options_init_default (options);
1177
1178 cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
1179 cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
1180 cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
1181 _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
1182 }
1183
1184 static cairo_int_status_t
_cairo_win32_printing_surface_paint(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_clip_t * clip)1185 _cairo_win32_printing_surface_paint (void *abstract_surface,
1186 cairo_operator_t op,
1187 const cairo_pattern_t *source,
1188 cairo_clip_t *clip)
1189 {
1190 cairo_win32_surface_t *surface = abstract_surface;
1191 cairo_solid_pattern_t clear;
1192 cairo_status_t status;
1193
1194 status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
1195 if (status)
1196 return status;
1197
1198 if (op == CAIRO_OPERATOR_CLEAR) {
1199 _cairo_win32_printing_surface_init_clear_color (surface, &clear);
1200 source = (cairo_pattern_t*) &clear;
1201 op = CAIRO_OPERATOR_SOURCE;
1202 }
1203
1204 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
1205 return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
1206
1207 assert (_cairo_win32_printing_surface_operation_supported (surface, op, source));
1208
1209 return _cairo_win32_printing_surface_paint_pattern (surface, source);
1210 }
1211
1212 static int
_cairo_win32_line_cap(cairo_line_cap_t cap)1213 _cairo_win32_line_cap (cairo_line_cap_t cap)
1214 {
1215 switch (cap) {
1216 case CAIRO_LINE_CAP_BUTT:
1217 return PS_ENDCAP_FLAT;
1218 case CAIRO_LINE_CAP_ROUND:
1219 return PS_ENDCAP_ROUND;
1220 case CAIRO_LINE_CAP_SQUARE:
1221 return PS_ENDCAP_SQUARE;
1222 default:
1223 ASSERT_NOT_REACHED;
1224 return 0;
1225 }
1226 }
1227
1228 static int
_cairo_win32_line_join(cairo_line_join_t join)1229 _cairo_win32_line_join (cairo_line_join_t join)
1230 {
1231 switch (join) {
1232 case CAIRO_LINE_JOIN_MITER:
1233 return PS_JOIN_MITER;
1234 case CAIRO_LINE_JOIN_ROUND:
1235 return PS_JOIN_ROUND;
1236 case CAIRO_LINE_JOIN_BEVEL:
1237 return PS_JOIN_BEVEL;
1238 default:
1239 ASSERT_NOT_REACHED;
1240 return 0;
1241 }
1242 }
1243
1244 static void
_cairo_matrix_factor_out_scale(cairo_matrix_t * m,double * scale)1245 _cairo_matrix_factor_out_scale (cairo_matrix_t *m, double *scale)
1246 {
1247 double s;
1248
1249 s = fabs (m->xx);
1250 if (fabs (m->xy) > s)
1251 s = fabs (m->xy);
1252 if (fabs (m->yx) > s)
1253 s = fabs (m->yx);
1254 if (fabs (m->yy) > s)
1255 s = fabs (m->yy);
1256 *scale = s;
1257 s = 1.0/s;
1258 cairo_matrix_scale (m, s, s);
1259 }
1260
1261 static cairo_int_status_t
_cairo_win32_printing_surface_stroke(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,const cairo_stroke_style_t * style,const cairo_matrix_t * stroke_ctm,const cairo_matrix_t * stroke_ctm_inverse,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)1262 _cairo_win32_printing_surface_stroke (void *abstract_surface,
1263 cairo_operator_t op,
1264 const cairo_pattern_t *source,
1265 cairo_path_fixed_t *path,
1266 const cairo_stroke_style_t *style,
1267 const cairo_matrix_t *stroke_ctm,
1268 const cairo_matrix_t *stroke_ctm_inverse,
1269 double tolerance,
1270 cairo_antialias_t antialias,
1271 cairo_clip_t *clip)
1272 {
1273 cairo_win32_surface_t *surface = abstract_surface;
1274 cairo_int_status_t status;
1275 HPEN pen;
1276 LOGBRUSH brush;
1277 COLORREF color;
1278 XFORM xform;
1279 DWORD pen_style;
1280 DWORD pen_width;
1281 DWORD *dash_array;
1282 HGDIOBJ obj;
1283 unsigned int i;
1284 cairo_solid_pattern_t clear;
1285 cairo_matrix_t mat;
1286 double scale;
1287 double scaled_width;
1288 double major, minor;
1289
1290 status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
1291 if (status)
1292 return status;
1293
1294 if (op == CAIRO_OPERATOR_CLEAR) {
1295 _cairo_win32_printing_surface_init_clear_color (surface, &clear);
1296 source = (cairo_pattern_t*) &clear;
1297 op = CAIRO_OPERATOR_SOURCE;
1298 }
1299
1300 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
1301 /* Win32 does not support a dash offset. */
1302 if (style->num_dashes > 0 && style->dash_offset != 0.0)
1303 return CAIRO_INT_STATUS_UNSUPPORTED;
1304
1305 return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
1306 }
1307
1308 assert (_cairo_win32_printing_surface_operation_supported (surface, op, source));
1309 assert (!(style->num_dashes > 0 && style->dash_offset != 0.0));
1310
1311 cairo_matrix_multiply (&mat, stroke_ctm, &surface->ctm);
1312 _cairo_matrix_factor_out_scale (&mat, &scale);
1313
1314 pen_style = PS_GEOMETRIC;
1315 dash_array = NULL;
1316 if (style->num_dashes) {
1317 pen_style |= PS_USERSTYLE;
1318 dash_array = calloc (sizeof (DWORD), style->num_dashes);
1319 for (i = 0; i < style->num_dashes; i++) {
1320 DWORD dashes = (DWORD) (scale * style->dash[i]);
1321 /* zero dash-lengths cause ExtCreatePen to fail. Make the dashes
1322 * longer if necessary.
1323 */
1324 dash_array[i] = MAX(1, dashes);
1325 }
1326 } else {
1327 pen_style |= PS_SOLID;
1328 }
1329
1330 SetMiterLimit (surface->dc, (FLOAT) (style->miter_limit), NULL);
1331 if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
1332 cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
1333
1334
1335 color = _cairo_win32_printing_surface_flatten_transparency (surface,
1336 &solid->color);
1337 } else {
1338 /* Color not used as the pen will only be used by WidenPath() */
1339 color = RGB (0,0,0);
1340 }
1341 brush.lbStyle = BS_SOLID;
1342 brush.lbColor = color;
1343 brush.lbHatch = 0;
1344 pen_style |= _cairo_win32_line_cap (style->line_cap);
1345 pen_style |= _cairo_win32_line_join (style->line_join);
1346 scaled_width = scale * style->line_width;
1347 if (scaled_width == 0.0)
1348 return status;
1349 pen_width = (DWORD)scaled_width;
1350 if (pen_width == 0) {
1351 /* ExtCreatePen will fail if passed zero width. We have to choose
1352 * between drawing something too wide, or drawing nothing at all.
1353 * Let's draw something.
1354 */
1355 pen_width = 1;
1356 }
1357 pen = ExtCreatePen(pen_style,
1358 pen_width,
1359 &brush,
1360 style->num_dashes,
1361 dash_array);
1362 if (pen == NULL)
1363 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:ExtCreatePen");
1364 obj = SelectObject (surface->dc, pen);
1365 if (obj == NULL)
1366 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectObject");
1367
1368 BeginPath (surface->dc);
1369 status = _cairo_win32_printing_surface_emit_path (surface, path);
1370 EndPath (surface->dc);
1371 if (status)
1372 return status;
1373
1374 /*
1375 * Switch to user space to set line parameters
1376 */
1377 SaveDC (surface->dc);
1378
1379 /* Some printers don't handle transformed strokes. Avoid the transform
1380 * if not required for the pen shape. Use the SVD here to find the major
1381 * and minor scales then check if they differ by more than 1 device unit.
1382 * If the difference is smaller, then just treat the scaling as uniform.
1383 * This check ignores rotations as the pen shape is symmetric before
1384 * transformation.
1385 */
1386 _cairo_matrix_transformed_circle_axes (&mat, scale, &major, &minor);
1387 if (fabs (major - minor) > 1) {
1388 /* Check if the matrix swaps the X and Y axes such that the diagonal
1389 * is nearly zero. This was observed to cause problems with XPS export.
1390 */
1391 if (fabs (mat.xx) < 1e-6 && fabs (mat.yy) < 1e-6) {
1392 /* swap the X and Y axes to undo the axis swap in the matrix */
1393 cairo_matrix_t swap_xy = { 0, 1, 1, 0, 0, 0 };
1394 cairo_matrix_multiply (&mat, &swap_xy, &mat);
1395 }
1396 _cairo_matrix_to_win32_xform (&mat, &xform);
1397 xform.eDx = 0.0f;
1398 xform.eDy = 0.0f;
1399
1400 if (!ModifyWorldTransform (surface->dc, &xform, MWT_LEFTMULTIPLY))
1401 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SetWorldTransform");
1402 }
1403
1404 if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
1405 StrokePath (surface->dc);
1406 } else {
1407 if (!WidenPath (surface->dc))
1408 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:WidenPath");
1409 if (!SelectClipPath (surface->dc, RGN_AND))
1410 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectClipPath");
1411
1412 /* Return to device space to paint the pattern */
1413 _cairo_matrix_to_win32_xform (&surface->gdi_ctm, &xform);
1414 if (!SetWorldTransform (surface->dc, &xform))
1415 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:ModifyWorldTransform");
1416 status = _cairo_win32_printing_surface_paint_pattern (surface, source);
1417 }
1418 RestoreDC (surface->dc, -1);
1419 DeleteObject (pen);
1420 if (dash_array)
1421 free (dash_array);
1422
1423 return status;
1424 }
1425
1426 static cairo_int_status_t
_cairo_win32_printing_surface_fill(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)1427 _cairo_win32_printing_surface_fill (void *abstract_surface,
1428 cairo_operator_t op,
1429 const cairo_pattern_t *source,
1430 cairo_path_fixed_t *path,
1431 cairo_fill_rule_t fill_rule,
1432 double tolerance,
1433 cairo_antialias_t antialias,
1434 cairo_clip_t *clip)
1435 {
1436 cairo_win32_surface_t *surface = abstract_surface;
1437 cairo_int_status_t status;
1438 cairo_solid_pattern_t clear;
1439
1440 status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
1441 if (status)
1442 return status;
1443
1444 if (op == CAIRO_OPERATOR_CLEAR) {
1445 _cairo_win32_printing_surface_init_clear_color (surface, &clear);
1446 source = (cairo_pattern_t*) &clear;
1447 op = CAIRO_OPERATOR_SOURCE;
1448 }
1449
1450 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
1451 return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
1452
1453 assert (_cairo_win32_printing_surface_operation_supported (surface, op, source));
1454
1455 surface->path_empty = TRUE;
1456 BeginPath (surface->dc);
1457 status = _cairo_win32_printing_surface_emit_path (surface, path);
1458 EndPath (surface->dc);
1459
1460 switch (fill_rule) {
1461 case CAIRO_FILL_RULE_WINDING:
1462 SetPolyFillMode (surface->dc, WINDING);
1463 break;
1464 case CAIRO_FILL_RULE_EVEN_ODD:
1465 SetPolyFillMode (surface->dc, ALTERNATE);
1466 break;
1467 default:
1468 ASSERT_NOT_REACHED;
1469 }
1470
1471 if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
1472 status = _cairo_win32_printing_surface_select_solid_brush (surface, source);
1473 if (status)
1474 return status;
1475
1476 FillPath (surface->dc);
1477 _cairo_win32_printing_surface_done_solid_brush (surface);
1478 } else if (surface->path_empty == FALSE) {
1479 SaveDC (surface->dc);
1480 SelectClipPath (surface->dc, RGN_AND);
1481 status = _cairo_win32_printing_surface_paint_pattern (surface, source);
1482 RestoreDC (surface->dc, -1);
1483 }
1484
1485 fflush(stderr);
1486
1487 return status;
1488 }
1489
1490 static cairo_int_status_t
_cairo_win32_printing_surface_emit_win32_glyphs(cairo_win32_surface_t * surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_glyph_t * glyphs,int num_glyphs,cairo_scaled_font_t * scaled_font,cairo_clip_t * clip,int * remaining_glyphs)1491 _cairo_win32_printing_surface_emit_win32_glyphs (cairo_win32_surface_t *surface,
1492 cairo_operator_t op,
1493 const cairo_pattern_t *source,
1494 cairo_glyph_t *glyphs,
1495 int num_glyphs,
1496 cairo_scaled_font_t *scaled_font,
1497 cairo_clip_t *clip,
1498 int *remaining_glyphs)
1499 {
1500 cairo_matrix_t ctm;
1501 cairo_glyph_t *unicode_glyphs;
1502 cairo_scaled_font_subsets_glyph_t subset_glyph;
1503 int i, first;
1504 cairo_bool_t sequence_is_unicode;
1505 cairo_status_t status = CAIRO_STATUS_SUCCESS;
1506
1507 /* Where possible reverse the glyph indices back to unicode
1508 * characters. Strings of glyphs that could not be reversed to
1509 * unicode will be printed with ETO_GLYPH_INDEX.
1510 *
1511 * As _cairo_win32_scaled_font_index_to_ucs4() is a slow
1512 * operation, the font subsetting function
1513 * _cairo_scaled_font_subsets_map_glyph() is used to obtain
1514 * the unicode value because it caches the reverse mapping in
1515 * the subsets.
1516 */
1517
1518 if (surface->has_ctm) {
1519 for (i = 0; i < num_glyphs; i++)
1520 cairo_matrix_transform_point (&surface->ctm, &glyphs[i].x, &glyphs[i].y);
1521 cairo_matrix_multiply (&ctm, &scaled_font->ctm, &surface->ctm);
1522 scaled_font = cairo_scaled_font_create (scaled_font->font_face,
1523 &scaled_font->font_matrix,
1524 &ctm,
1525 &scaled_font->options);
1526 }
1527
1528 unicode_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
1529 if (unicode_glyphs == NULL)
1530 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1531
1532 memcpy (unicode_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
1533 for (i = 0; i < num_glyphs; i++) {
1534 status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
1535 scaled_font,
1536 glyphs[i].index,
1537 NULL, 0,
1538 &subset_glyph);
1539 if (status)
1540 goto fail;
1541
1542 unicode_glyphs[i].index = subset_glyph.unicode;
1543 }
1544
1545 i = 0;
1546 first = 0;
1547 sequence_is_unicode = unicode_glyphs[0].index <= 0xffff;
1548 while (i < num_glyphs) {
1549 if (i == num_glyphs - 1 ||
1550 ((unicode_glyphs[i + 1].index < 0xffff) != sequence_is_unicode))
1551 {
1552 status = _cairo_win32_surface_show_glyphs_internal (
1553 surface,
1554 op,
1555 source,
1556 sequence_is_unicode ? &unicode_glyphs[first] : &glyphs[first],
1557 i - first + 1,
1558 scaled_font,
1559 clip,
1560 remaining_glyphs,
1561 ! sequence_is_unicode);
1562 first = i + 1;
1563 if (i < num_glyphs - 1)
1564 sequence_is_unicode = unicode_glyphs[i + 1].index <= 0xffff;
1565 }
1566 i++;
1567 }
1568
1569 fail:
1570 if (surface->has_ctm)
1571 cairo_scaled_font_destroy (scaled_font);
1572
1573 free (unicode_glyphs);
1574
1575 return status;
1576 }
1577
1578 static cairo_int_status_t
_cairo_win32_printing_surface_show_glyphs(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_glyph_t * glyphs,int num_glyphs,cairo_scaled_font_t * scaled_font,cairo_clip_t * clip,int * remaining_glyphs)1579 _cairo_win32_printing_surface_show_glyphs (void *abstract_surface,
1580 cairo_operator_t op,
1581 const cairo_pattern_t *source,
1582 cairo_glyph_t *glyphs,
1583 int num_glyphs,
1584 cairo_scaled_font_t *scaled_font,
1585 cairo_clip_t *clip,
1586 int *remaining_glyphs)
1587 {
1588 cairo_win32_surface_t *surface = abstract_surface;
1589 cairo_status_t status = CAIRO_STATUS_SUCCESS;
1590 cairo_scaled_glyph_t *scaled_glyph;
1591 cairo_pattern_t *opaque = NULL;
1592 int i;
1593 cairo_matrix_t old_ctm;
1594 cairo_bool_t old_has_ctm;
1595 cairo_solid_pattern_t clear;
1596 cairo_scaled_font_t *local_scaled_font = NULL;
1597
1598 status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
1599 if (status)
1600 return status;
1601
1602 if (op == CAIRO_OPERATOR_CLEAR) {
1603 _cairo_win32_printing_surface_init_clear_color (surface, &clear);
1604 source = (cairo_pattern_t*) &clear;
1605 op = CAIRO_OPERATOR_SOURCE;
1606 }
1607
1608 if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
1609 /* When printing bitmap fonts to a printer DC, Windows may
1610 * substitute an outline font for bitmap font. As the win32
1611 * font backend always uses a screen DC when obtaining the
1612 * font metrics the metrics of the substituted font will not
1613 * match the metrics that the win32 font backend returns.
1614 *
1615 * If we are printing a bitmap font, use fallback images to
1616 * ensure the font is not substituted.
1617 */
1618 #if CAIRO_HAS_WIN32_FONT
1619 if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32) {
1620 if (_cairo_win32_scaled_font_is_bitmap (scaled_font))
1621 return CAIRO_INT_STATUS_UNSUPPORTED;
1622 else
1623 return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
1624 }
1625 #endif
1626
1627 #if CAIRO_HAS_DWRITE_FONT
1628 if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_DWRITE) {
1629 return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
1630 }
1631 #endif
1632
1633 /* For non win32 fonts we need to check that each glyph has a
1634 * path available. If a path is not available,
1635 * _cairo_scaled_glyph_lookup() will return
1636 * CAIRO_INT_STATUS_UNSUPPORTED and a fallback image will be
1637 * used.
1638 */
1639 for (i = 0; i < num_glyphs; i++) {
1640 status = _cairo_scaled_glyph_lookup (scaled_font,
1641 glyphs[i].index,
1642 CAIRO_SCALED_GLYPH_INFO_PATH,
1643 &scaled_glyph);
1644 if (status)
1645 return status;
1646 }
1647
1648 return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
1649 }
1650
1651 if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
1652 cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
1653 COLORREF color;
1654
1655 color = _cairo_win32_printing_surface_flatten_transparency (surface,
1656 &solid->color);
1657 opaque = cairo_pattern_create_rgb (GetRValue (color) / 255.0,
1658 GetGValue (color) / 255.0,
1659 GetBValue (color) / 255.0);
1660 if (opaque->status)
1661 return opaque->status;
1662 source = opaque;
1663 }
1664
1665 #if CAIRO_HAS_DWRITE_FONT
1666 /* For a printer, the dwrite path is not desirable as it goes through the
1667 * bitmap-blitting GDI interop route. Better to create a win32 (GDI) font
1668 * so that ExtTextOut can be used, giving the printer driver the chance
1669 * to do the right thing with the text.
1670 */
1671 if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_DWRITE) {
1672 status = _cairo_dwrite_scaled_font_create_win32_scaled_font (scaled_font, &local_scaled_font);
1673 if (status == CAIRO_STATUS_SUCCESS) {
1674 scaled_font = local_scaled_font;
1675 } else {
1676 /* Reset status; we'll fall back to drawing glyphs as paths */
1677 status = CAIRO_STATUS_SUCCESS;
1678 }
1679 }
1680 #endif
1681
1682 #if CAIRO_HAS_WIN32_FONT
1683 if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32 &&
1684 source->type == CAIRO_PATTERN_TYPE_SOLID)
1685 {
1686 status = _cairo_win32_printing_surface_emit_win32_glyphs (surface,
1687 op,
1688 source,
1689 glyphs,
1690 num_glyphs,
1691 scaled_font,
1692 clip,
1693 remaining_glyphs);
1694 goto FINISH;
1695 }
1696 #endif
1697
1698 SaveDC (surface->dc);
1699 old_ctm = surface->ctm;
1700 old_has_ctm = surface->has_ctm;
1701 surface->has_ctm = TRUE;
1702 surface->path_empty = TRUE;
1703 BeginPath (surface->dc);
1704 for (i = 0; i < num_glyphs; i++) {
1705 status = _cairo_scaled_glyph_lookup (scaled_font,
1706 glyphs[i].index,
1707 CAIRO_SCALED_GLYPH_INFO_PATH,
1708 &scaled_glyph);
1709 if (status)
1710 break;
1711 surface->ctm = old_ctm;
1712 cairo_matrix_translate (&surface->ctm, glyphs[i].x, glyphs[i].y);
1713 status = _cairo_win32_printing_surface_emit_path (surface, scaled_glyph->path);
1714 }
1715 EndPath (surface->dc);
1716 surface->ctm = old_ctm;
1717 surface->has_ctm = old_has_ctm;
1718 if (status == CAIRO_STATUS_SUCCESS && surface->path_empty == FALSE) {
1719 if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
1720 status = _cairo_win32_printing_surface_select_solid_brush (surface, source);
1721 if (status)
1722 goto FINISH;
1723
1724 SetPolyFillMode (surface->dc, WINDING);
1725 FillPath (surface->dc);
1726 _cairo_win32_printing_surface_done_solid_brush (surface);
1727 } else {
1728 SelectClipPath (surface->dc, RGN_AND);
1729 status = _cairo_win32_printing_surface_paint_pattern (surface, source);
1730 }
1731 }
1732 RestoreDC (surface->dc, -1);
1733
1734 if (opaque)
1735 cairo_pattern_destroy (opaque);
1736
1737 FINISH:
1738 if (local_scaled_font)
1739 cairo_scaled_font_destroy (local_scaled_font);
1740
1741 return status;
1742 }
1743
1744 static cairo_surface_t *
_cairo_win32_printing_surface_create_similar(void * abstract_surface,cairo_content_t content,int width,int height)1745 _cairo_win32_printing_surface_create_similar (void *abstract_surface,
1746 cairo_content_t content,
1747 int width,
1748 int height)
1749 {
1750 cairo_rectangle_t extents;
1751
1752 extents.x = extents.y = 0;
1753 extents.width = width;
1754 extents.height = height;
1755 return cairo_recording_surface_create (content, &extents);
1756 }
1757
1758 static cairo_int_status_t
_cairo_win32_printing_surface_start_page(void * abstract_surface)1759 _cairo_win32_printing_surface_start_page (void *abstract_surface)
1760 {
1761 cairo_win32_surface_t *surface = abstract_surface;
1762 XFORM xform;
1763 double x_res, y_res;
1764 cairo_matrix_t inverse_ctm;
1765 cairo_status_t status;
1766
1767 SaveDC (surface->dc); /* Save application context first, before doing MWT */
1768
1769 /* As the logical coordinates used by GDI functions (eg LineTo)
1770 * are integers we need to do some additional work to prevent
1771 * rounding errors. For example the obvious way to paint a recording
1772 * pattern is to:
1773 *
1774 * SaveDC()
1775 * transform the device context DC by the pattern to device matrix
1776 * replay the recording surface
1777 * RestoreDC()
1778 *
1779 * The problem here is that if the pattern to device matrix is
1780 * [100 0 0 100 0 0], coordinates in the recording pattern such as
1781 * (1.56, 2.23) which correspond to (156, 223) in device space
1782 * will be rounded to (100, 200) due to (1.56, 2.23) being
1783 * truncated to integers.
1784 *
1785 * This is solved by saving the current GDI CTM in surface->ctm,
1786 * switch the GDI CTM to identity, and transforming all
1787 * coordinates by surface->ctm before passing them to GDI. When
1788 * painting a recording pattern, surface->ctm is transformed by the
1789 * pattern to device matrix.
1790 *
1791 * For printing device contexts where 1 unit is 1 dpi, switching
1792 * the GDI CTM to identity maximises the possible resolution of
1793 * coordinates.
1794 *
1795 * If the device context is an EMF file, using an identity
1796 * transform often provides insufficent resolution. The workaround
1797 * is to set the GDI CTM to a scale < 1 eg [1.0/16 0 0 1/0/16 0 0]
1798 * and scale the cairo CTM by [16 0 0 16 0 0]. The
1799 * SetWorldTransform function call to scale the GDI CTM by 1.0/16
1800 * will be recorded in the EMF followed by all the graphics
1801 * functions by their coordinateds multiplied by 16.
1802 *
1803 * To support allowing the user to set a GDI CTM with scale < 1,
1804 * we avoid switching to an identity CTM if the CTM xx and yy is < 1.
1805 */
1806 SetGraphicsMode (surface->dc, GM_ADVANCED);
1807 GetWorldTransform(surface->dc, &xform);
1808 if (xform.eM11 < 1 && xform.eM22 < 1) {
1809 cairo_matrix_init_identity (&surface->ctm);
1810 surface->gdi_ctm.xx = xform.eM11;
1811 surface->gdi_ctm.xy = xform.eM21;
1812 surface->gdi_ctm.yx = xform.eM12;
1813 surface->gdi_ctm.yy = xform.eM22;
1814 surface->gdi_ctm.x0 = xform.eDx;
1815 surface->gdi_ctm.y0 = xform.eDy;
1816 } else {
1817 surface->ctm.xx = xform.eM11;
1818 surface->ctm.xy = xform.eM21;
1819 surface->ctm.yx = xform.eM12;
1820 surface->ctm.yy = xform.eM22;
1821 surface->ctm.x0 = xform.eDx;
1822 surface->ctm.y0 = xform.eDy;
1823 cairo_matrix_init_identity (&surface->gdi_ctm);
1824 if (!ModifyWorldTransform (surface->dc, NULL, MWT_IDENTITY))
1825 return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_start_page:ModifyWorldTransform");
1826 }
1827
1828 surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
1829 surface->has_gdi_ctm = !_cairo_matrix_is_identity (&surface->gdi_ctm);
1830 inverse_ctm = surface->ctm;
1831 status = cairo_matrix_invert (&inverse_ctm);
1832 if (status)
1833 return status;
1834
1835 x_res = GetDeviceCaps (surface->dc, LOGPIXELSX);
1836 y_res = GetDeviceCaps (surface->dc, LOGPIXELSY);
1837 cairo_matrix_transform_distance (&inverse_ctm, &x_res, &y_res);
1838 _cairo_surface_set_resolution (&surface->base, x_res, y_res);
1839
1840 SaveDC (surface->dc); /* Then save Cairo's known-good clip state, so the clip path can be reset */
1841
1842 return CAIRO_STATUS_SUCCESS;
1843 }
1844
1845 static void
_cairo_win32_printing_surface_set_paginated_mode(void * abstract_surface,cairo_paginated_mode_t paginated_mode)1846 _cairo_win32_printing_surface_set_paginated_mode (void *abstract_surface,
1847 cairo_paginated_mode_t paginated_mode)
1848 {
1849 cairo_win32_surface_t *surface = abstract_surface;
1850
1851 surface->paginated_mode = paginated_mode;
1852 }
1853
1854 static cairo_bool_t
_cairo_win32_printing_surface_supports_fine_grained_fallbacks(void * abstract_surface)1855 _cairo_win32_printing_surface_supports_fine_grained_fallbacks (void *abstract_surface)
1856 {
1857 return TRUE;
1858 }
1859
1860 /**
1861 * cairo_win32_printing_surface_create:
1862 * @hdc: the DC to create a surface for
1863 *
1864 * Creates a cairo surface that targets the given DC. The DC will be
1865 * queried for its initial clip extents, and this will be used as the
1866 * size of the cairo surface. The DC should be a printing DC;
1867 * antialiasing will be ignored, and GDI will be used as much as
1868 * possible to draw to the surface.
1869 *
1870 * The returned surface will be wrapped using the paginated surface to
1871 * provide correct complex rendering behaviour; show_page() and
1872 * associated methods must be used for correct output.
1873 *
1874 * Return value: the newly created surface
1875 *
1876 * Since: 1.6
1877 **/
1878 cairo_surface_t *
cairo_win32_printing_surface_create(HDC hdc)1879 cairo_win32_printing_surface_create (HDC hdc)
1880 {
1881 cairo_win32_surface_t *surface;
1882 cairo_surface_t *paginated;
1883 RECT rect;
1884
1885 surface = malloc (sizeof (cairo_win32_surface_t));
1886 if (surface == NULL)
1887 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1888
1889 if (_cairo_win32_save_initial_clip (hdc, surface) != CAIRO_STATUS_SUCCESS) {
1890 free (surface);
1891 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1892 }
1893
1894 _cairo_surface_clipper_init (&surface->clipper,
1895 _cairo_win32_printing_surface_clipper_intersect_clip_path);
1896
1897 surface->image = NULL;
1898 surface->format = CAIRO_FORMAT_RGB24;
1899 surface->content = CAIRO_CONTENT_COLOR_ALPHA;
1900 surface->d3d9surface = NULL;
1901
1902 surface->dc = hdc;
1903 surface->bitmap = NULL;
1904 surface->is_dib = FALSE;
1905 surface->saved_dc_bitmap = NULL;
1906 surface->brush = NULL;
1907 surface->old_brush = NULL;
1908 surface->font_subsets = _cairo_scaled_font_subsets_create_scaled ();
1909 if (surface->font_subsets == NULL) {
1910 free (surface);
1911 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1912 }
1913
1914 GetClipBox(hdc, &rect);
1915 surface->extents.x = rect.left;
1916 surface->extents.y = rect.top;
1917 surface->extents.width = rect.right - rect.left;
1918 surface->extents.height = rect.bottom - rect.top;
1919
1920 surface->flags = _cairo_win32_flags_for_dc (surface->dc);
1921 surface->flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING;
1922
1923 _cairo_win32_printing_surface_init_ps_mode (surface);
1924 _cairo_win32_printing_surface_init_image_support (surface);
1925 _cairo_win32_printing_surface_init_language_pack (surface);
1926 _cairo_surface_init (&surface->base,
1927 &cairo_win32_printing_surface_backend,
1928 NULL, /* device */
1929 CAIRO_CONTENT_COLOR_ALPHA);
1930
1931 paginated = _cairo_paginated_surface_create (&surface->base,
1932 CAIRO_CONTENT_COLOR_ALPHA,
1933 &cairo_win32_surface_paginated_backend);
1934
1935 /* paginated keeps the only reference to surface now, drop ours */
1936 cairo_surface_destroy (&surface->base);
1937
1938 return paginated;
1939 }
1940
1941 cairo_bool_t
_cairo_surface_is_win32_printing(cairo_surface_t * surface)1942 _cairo_surface_is_win32_printing (cairo_surface_t *surface)
1943 {
1944 return surface->backend == &cairo_win32_printing_surface_backend;
1945 }
1946
1947 static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
1948 CAIRO_SURFACE_TYPE_WIN32_PRINTING,
1949 _cairo_win32_printing_surface_create_similar,
1950 _cairo_win32_surface_finish,
1951 NULL, /* acquire_source_image */
1952 NULL, /* release_source_image */
1953 NULL, /* acquire_dest_image */
1954 NULL, /* release_dest_image */
1955 NULL, /* clone_similar */
1956 NULL, /* composite */
1957 NULL, /* fill_rectangles */
1958 NULL, /* composite_trapezoids */
1959 NULL, /* create_span_renderer */
1960 NULL, /* check_span_renderer */
1961 NULL, /* copy_page */
1962 _cairo_win32_printing_surface_show_page,
1963 _cairo_win32_surface_get_extents,
1964 NULL, /* old_show_glyphs */
1965 _cairo_win32_printing_surface_get_font_options,
1966 NULL, /* flush */
1967 NULL, /* mark_dirty_rectangle */
1968 NULL, /* scaled_font_fini */
1969 NULL, /* scaled_glyph_fini */
1970
1971 _cairo_win32_printing_surface_paint,
1972 NULL, /* mask */
1973 _cairo_win32_printing_surface_stroke,
1974 _cairo_win32_printing_surface_fill,
1975 _cairo_win32_printing_surface_show_glyphs,
1976 NULL, /* snapshot */
1977 NULL, /* is_similar */
1978 NULL, /* fill_stroke */
1979 };
1980
1981 static const cairo_paginated_surface_backend_t cairo_win32_surface_paginated_backend = {
1982 _cairo_win32_printing_surface_start_page,
1983 _cairo_win32_printing_surface_set_paginated_mode,
1984 NULL, /* set_bounding_box */
1985 NULL, /* _cairo_win32_printing_surface_has_fallback_images, */
1986 _cairo_win32_printing_surface_supports_fine_grained_fallbacks,
1987 };
1988