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
4 * Copyright © 2007 Adrian Johnson
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
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/
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.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Adrian Johnson.
34 * Adrian Johnson <ajohnson@redneon.com>
35 * Vladimir Vukicevic <vladimir@pobox.com>
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
43 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
44 # define _WIN32_WINNT 0x0500
49 #include "cairo-paginated-private.h"
51 #include "cairo-clip-private.h"
52 #include "cairo-win32-private.h"
53 #include "cairo-meta-surface-private.h"
54 #include "cairo-scaled-font-subsets-private.h"
58 #if !defined(POSTSCRIPT_IDENTIFY)
59 # define POSTSCRIPT_IDENTIFY 0x1015
62 #if !defined(PSIDENT_GDICENTRIC)
63 # define PSIDENT_GDICENTRIC 0x0000
66 #if !defined(GET_PS_FEATURESETTING)
67 # define GET_PS_FEATURESETTING 0x1019
70 #if !defined(FEATURESETTING_PSLEVEL)
71 # define FEATURESETTING_PSLEVEL 0x0002
74 #if !defined(GRADIENT_FILL_RECT_H)
75 # define GRADIENT_FILL_RECT_H 0x00
78 #define PELS_72DPI ((LONG)(72. / 0.0254))
80 static const cairo_surface_backend_t cairo_win32_printing_surface_backend
;
81 static const cairo_paginated_surface_backend_t cairo_win32_surface_paginated_backend
;
84 _cairo_win32_printing_surface_init_ps_mode (cairo_win32_surface_t
*surface
)
87 INT ps_feature
, ps_level
;
89 word
= PSIDENT_GDICENTRIC
;
90 if (ExtEscape (surface
->dc
, POSTSCRIPT_IDENTIFY
, sizeof(DWORD
), (char *)&word
, 0, (char *)NULL
) <= 0)
93 ps_feature
= FEATURESETTING_PSLEVEL
;
94 if (ExtEscape (surface
->dc
, GET_PS_FEATURESETTING
, sizeof(INT
),
95 (char *)&ps_feature
, sizeof(INT
), (char *)&ps_level
) <= 0)
99 surface
->flags
|= CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT
;
102 static cairo_int_status_t
103 analyze_surface_pattern_transparency (cairo_surface_pattern_t
*pattern
)
105 cairo_image_surface_t
*image
;
107 cairo_int_status_t status
;
110 status
= _cairo_surface_acquire_source_image (pattern
->surface
,
116 if (image
->base
.status
)
117 return image
->base
.status
;
119 if (image
->format
== CAIRO_FORMAT_RGB24
) {
120 status
= CAIRO_STATUS_SUCCESS
;
124 if (image
->format
!= CAIRO_FORMAT_ARGB32
) {
125 /* If the surface does not support the image format, assume
126 * that it does have alpha. The image will be converted to
127 * rgb24 when the surface blends the image into the page
128 * color to remove the transparency. */
129 status
= CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
;
133 for (y
= 0; y
< image
->height
; y
++) {
135 uint32_t *pixel
= (uint32_t *) (image
->data
+ y
* image
->stride
);
137 for (x
= 0; x
< image
->width
; x
++, pixel
++) {
138 a
= (*pixel
& 0xff000000) >> 24;
140 status
= CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
;
145 status
= CAIRO_STATUS_SUCCESS
;
148 _cairo_surface_release_source_image (pattern
->surface
, image
, image_extra
);
154 surface_pattern_supported (const cairo_surface_pattern_t
*pattern
)
156 cairo_extend_t extend
;
158 if (_cairo_surface_is_meta (pattern
->surface
))
161 if (cairo_surface_get_type (pattern
->surface
) != CAIRO_SURFACE_TYPE_WIN32
&&
162 pattern
->surface
->backend
->acquire_source_image
== NULL
)
167 extend
= cairo_pattern_get_extend ((cairo_pattern_t
*)&pattern
->base
);
169 case CAIRO_EXTEND_NONE
:
170 case CAIRO_EXTEND_REPEAT
:
171 case CAIRO_EXTEND_REFLECT
:
172 /* There's no point returning FALSE for EXTEND_PAD, as the image
173 * surface does not currently implement it either */
174 case CAIRO_EXTEND_PAD
:
183 pattern_supported (cairo_win32_surface_t
*surface
, const cairo_pattern_t
*pattern
)
185 if (pattern
->type
== CAIRO_PATTERN_TYPE_SOLID
)
188 if (pattern
->type
== CAIRO_PATTERN_TYPE_SURFACE
)
189 return surface_pattern_supported ((const cairo_surface_pattern_t
*) pattern
);
191 if (pattern
->type
== CAIRO_PATTERN_TYPE_LINEAR
)
192 return surface
->flags
& CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT
;
197 static cairo_int_status_t
198 _cairo_win32_printing_surface_analyze_operation (cairo_win32_surface_t
*surface
,
200 const cairo_pattern_t
*pattern
)
202 if (! pattern_supported (surface
, pattern
))
203 return CAIRO_INT_STATUS_UNSUPPORTED
;
205 if (!(op
== CAIRO_OPERATOR_SOURCE
||
206 op
== CAIRO_OPERATOR_OVER
||
207 op
== CAIRO_OPERATOR_CLEAR
))
208 return CAIRO_INT_STATUS_UNSUPPORTED
;
210 if (pattern
->type
== CAIRO_PATTERN_TYPE_SURFACE
) {
211 cairo_surface_pattern_t
*surface_pattern
= (cairo_surface_pattern_t
*) pattern
;
213 if ( _cairo_surface_is_meta (surface_pattern
->surface
))
214 return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN
;
217 if (op
== CAIRO_OPERATOR_SOURCE
||
218 op
== CAIRO_OPERATOR_CLEAR
)
219 return CAIRO_STATUS_SUCCESS
;
221 /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
222 * the pattern contains transparency, we return
223 * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
224 * surface. If the analysis surface determines that there is
225 * anything drawn under this operation, a fallback image will be
226 * used. Otherwise the operation will be replayed during the
227 * render stage and we blend the transarency into the white
228 * background to convert the pattern to opaque.
231 if (pattern
->type
== CAIRO_PATTERN_TYPE_SURFACE
) {
232 cairo_surface_pattern_t
*surface_pattern
= (cairo_surface_pattern_t
*) pattern
;
234 return analyze_surface_pattern_transparency (surface_pattern
);
237 if (_cairo_pattern_is_opaque (pattern
))
238 return CAIRO_STATUS_SUCCESS
;
240 return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
;
244 _cairo_win32_printing_surface_operation_supported (cairo_win32_surface_t
*surface
,
246 const cairo_pattern_t
*pattern
)
248 if (_cairo_win32_printing_surface_analyze_operation (surface
, op
, pattern
) != CAIRO_INT_STATUS_UNSUPPORTED
)
255 _cairo_win32_printing_surface_init_clear_color (cairo_win32_surface_t
*surface
,
256 cairo_solid_pattern_t
*color
)
258 if (surface
->content
== CAIRO_CONTENT_COLOR_ALPHA
)
259 _cairo_pattern_init_solid (color
, CAIRO_COLOR_WHITE
, CAIRO_CONTENT_COLOR
);
261 _cairo_pattern_init_solid (color
, CAIRO_COLOR_BLACK
, CAIRO_CONTENT_COLOR
);
265 _cairo_win32_printing_surface_flatten_transparency (cairo_win32_surface_t
*surface
,
266 const cairo_color_t
*color
)
269 BYTE red
, green
, blue
;
271 red
= color
->red_short
>> 8;
272 green
= color
->green_short
>> 8;
273 blue
= color
->blue_short
>> 8;
275 if (!CAIRO_COLOR_IS_OPAQUE(color
)) {
276 if (surface
->content
== CAIRO_CONTENT_COLOR_ALPHA
) {
277 /* Blend into white */
278 uint8_t one_minus_alpha
= 255 - (color
->alpha_short
>> 8);
280 red
= (color
->red_short
>> 8) + one_minus_alpha
;
281 green
= (color
->green_short
>> 8) + one_minus_alpha
;
282 blue
= (color
->blue_short
>> 8) + one_minus_alpha
;
284 /* Blend into black */
285 red
= (color
->red_short
>> 8);
286 green
= (color
->green_short
>> 8);
287 blue
= (color
->blue_short
>> 8);
290 c
= RGB (red
, green
, blue
);
295 static cairo_status_t
296 _cairo_win32_printing_surface_select_solid_brush (cairo_win32_surface_t
*surface
,
297 cairo_pattern_t
*source
)
299 cairo_solid_pattern_t
*pattern
= (cairo_solid_pattern_t
*) source
;
302 color
= _cairo_win32_printing_surface_flatten_transparency (surface
,
304 surface
->brush
= CreateSolidBrush (color
);
306 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_select_solid_brush(CreateSolidBrush)");
307 surface
->old_brush
= SelectObject (surface
->dc
, surface
->brush
);
309 return CAIRO_STATUS_SUCCESS
;
313 _cairo_win32_printing_surface_done_solid_brush (cairo_win32_surface_t
*surface
)
315 if (surface
->old_brush
) {
316 SelectObject (surface
->dc
, surface
->old_brush
);
317 DeleteObject (surface
->brush
);
318 surface
->old_brush
= NULL
;
322 static cairo_status_t
323 _cairo_win32_printing_surface_get_ctm_clip_box (cairo_win32_surface_t
*surface
,
328 _cairo_matrix_to_win32_xform (&surface
->ctm
, &xform
);
329 if (!SetWorldTransform (surface
->dc
, &xform
))
330 return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:SetWorldTransform");
331 GetClipBox (surface
->dc
, clip
);
332 if (!ModifyWorldTransform (surface
->dc
, &xform
, MWT_IDENTITY
))
333 return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:ModifyWorldTransform");
335 return CAIRO_STATUS_SUCCESS
;
338 static cairo_status_t
339 _cairo_win32_printing_surface_paint_solid_pattern (cairo_win32_surface_t
*surface
,
340 cairo_pattern_t
*pattern
)
343 cairo_status_t status
;
345 GetClipBox (surface
->dc
, &clip
);
346 status
= _cairo_win32_printing_surface_select_solid_brush (surface
, pattern
);
350 FillRect (surface
->dc
, &clip
, surface
->brush
);
351 _cairo_win32_printing_surface_done_solid_brush (surface
);
356 static cairo_status_t
357 _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t
*surface
,
358 cairo_surface_pattern_t
*pattern
)
360 cairo_content_t old_content
;
361 cairo_matrix_t old_ctm
;
362 cairo_bool_t old_has_ctm
;
363 cairo_rectangle_int_t meta_extents
;
364 cairo_status_t status
;
365 cairo_extend_t extend
;
368 int x_tile
, y_tile
, left
, right
, top
, bottom
;
370 cairo_surface_t
*meta_surface
= pattern
->surface
;
372 extend
= cairo_pattern_get_extend (&pattern
->base
);
374 p2d
= pattern
->base
.matrix
;
375 status
= cairo_matrix_invert (&p2d
);
376 /* _cairo_pattern_set_matrix guarantees invertibility */
377 assert (status
== CAIRO_STATUS_SUCCESS
);
379 old_ctm
= surface
->ctm
;
380 old_has_ctm
= surface
->has_ctm
;
381 cairo_matrix_multiply (&p2d
, &p2d
, &surface
->ctm
);
383 SaveDC (surface
->dc
);
384 _cairo_matrix_to_win32_xform (&p2d
, &xform
);
386 status
= _cairo_surface_get_extents (meta_surface
, &meta_extents
);
390 status
= _cairo_win32_printing_surface_get_ctm_clip_box (surface
, &clip
);
394 if (extend
== CAIRO_EXTEND_REPEAT
|| extend
== CAIRO_EXTEND_REFLECT
) {
395 left
= (int) floor((double)clip
.left
/meta_extents
.width
);
396 right
= (int) ceil((double)clip
.right
/meta_extents
.width
);
397 top
= (int) floor((double)clip
.top
/meta_extents
.height
);
398 bottom
= (int) ceil((double)clip
.bottom
/meta_extents
.height
);
406 old_content
= surface
->content
;
407 if (cairo_surface_get_content (meta_surface
) == CAIRO_CONTENT_COLOR
) {
408 cairo_pattern_t
*source
;
409 cairo_solid_pattern_t black
;
411 surface
->content
= CAIRO_CONTENT_COLOR
;
412 _cairo_pattern_init_solid (&black
, CAIRO_COLOR_BLACK
, CAIRO_CONTENT_COLOR
);
413 source
= (cairo_pattern_t
*) &black
;
414 _cairo_win32_printing_surface_paint_solid_pattern (surface
, source
);
417 for (y_tile
= top
; y_tile
< bottom
; y_tile
++) {
418 for (x_tile
= left
; x_tile
< right
; x_tile
++) {
422 SaveDC (surface
->dc
);
424 cairo_matrix_translate (&m
,
425 x_tile
*meta_extents
.width
,
426 y_tile
*meta_extents
.height
);
427 if (extend
== CAIRO_EXTEND_REFLECT
) {
429 cairo_matrix_translate (&m
, meta_extents
.width
, 0);
430 cairo_matrix_scale (&m
, -1, 1);
433 cairo_matrix_translate (&m
, 0, meta_extents
.height
);
434 cairo_matrix_scale (&m
, 1, -1);
438 surface
->has_ctm
= !_cairo_matrix_is_identity (&surface
->ctm
);
440 /* Set clip path around bbox of the pattern. */
441 BeginPath (surface
->dc
);
445 cairo_matrix_transform_point (&surface
->ctm
, &x
, &y
);
446 MoveToEx (surface
->dc
, (int) x
, (int) y
, NULL
);
448 x
= meta_extents
.width
;
450 cairo_matrix_transform_point (&surface
->ctm
, &x
, &y
);
451 LineTo (surface
->dc
, (int) x
, (int) y
);
453 x
= meta_extents
.width
;
454 y
= meta_extents
.height
;
455 cairo_matrix_transform_point (&surface
->ctm
, &x
, &y
);
456 LineTo (surface
->dc
, (int) x
, (int) y
);
459 y
= meta_extents
.height
;
460 cairo_matrix_transform_point (&surface
->ctm
, &x
, &y
);
461 LineTo (surface
->dc
, (int) x
, (int) y
);
463 CloseFigure (surface
->dc
);
464 EndPath (surface
->dc
);
465 SelectClipPath (surface
->dc
, RGN_AND
);
467 SaveDC (surface
->dc
); /* Allow clip path to be reset during replay */
468 status
= _cairo_meta_surface_replay_region (meta_surface
, &surface
->base
,
469 CAIRO_META_REGION_NATIVE
);
470 assert (status
!= CAIRO_INT_STATUS_UNSUPPORTED
);
471 /* Restore both the clip save and our earlier path SaveDC */
472 RestoreDC (surface
->dc
, -2);
479 surface
->content
= old_content
;
480 surface
->ctm
= old_ctm
;
481 surface
->has_ctm
= old_has_ctm
;
482 RestoreDC (surface
->dc
, -1);
487 static cairo_status_t
488 _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t
*surface
,
489 cairo_surface_pattern_t
*pattern
)
491 cairo_status_t status
;
492 cairo_extend_t extend
;
493 cairo_surface_attributes_t pat_attr
;
494 cairo_image_surface_t
*image
;
496 cairo_surface_t
*opaque_surface
;
497 cairo_image_surface_t
*opaque_image
= NULL
;
502 int x_tile
, y_tile
, left
, right
, top
, bottom
;
504 const cairo_color_t
*background_color
;
506 /* If we can't use StretchDIBits with this surface, we can't do anything
509 if (!(surface
->flags
& CAIRO_WIN32_SURFACE_CAN_STRETCHDIB
))
510 return CAIRO_INT_STATUS_UNSUPPORTED
;
512 if (surface
->content
== CAIRO_CONTENT_COLOR_ALPHA
)
513 background_color
= CAIRO_COLOR_WHITE
;
515 background_color
= CAIRO_COLOR_BLACK
;
517 extend
= cairo_pattern_get_extend (&pattern
->base
);
519 status
= _cairo_surface_acquire_source_image (pattern
->surface
,
520 &image
, &image_extra
);
524 if (image
->base
.status
) {
525 status
= image
->base
.status
;
529 if (image
->width
== 0 || image
->height
== 0) {
530 status
= CAIRO_STATUS_SUCCESS
;
534 if (image
->format
!= CAIRO_FORMAT_RGB24
) {
535 cairo_surface_pattern_t opaque_pattern
;
537 opaque_surface
= cairo_image_surface_create (CAIRO_FORMAT_RGB24
,
540 if (opaque_surface
->status
) {
541 status
= opaque_surface
->status
;
542 goto CLEANUP_OPAQUE_IMAGE
;
545 _cairo_pattern_init_for_surface (&opaque_pattern
, &image
->base
);
547 status
= _cairo_surface_fill_rectangle (opaque_surface
,
548 CAIRO_OPERATOR_SOURCE
,
551 image
->width
, image
->height
);
553 _cairo_pattern_fini (&opaque_pattern
.base
);
554 goto CLEANUP_OPAQUE_IMAGE
;
557 status
= _cairo_surface_composite (CAIRO_OPERATOR_OVER
,
558 &opaque_pattern
.base
,
567 _cairo_pattern_fini (&opaque_pattern
.base
);
568 goto CLEANUP_OPAQUE_IMAGE
;
571 _cairo_pattern_fini (&opaque_pattern
.base
);
572 opaque_image
= (cairo_image_surface_t
*) opaque_surface
;
574 opaque_surface
= &image
->base
;
575 opaque_image
= image
;
578 bi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
579 bi
.bmiHeader
.biWidth
= opaque_image
->width
;
580 bi
.bmiHeader
.biHeight
= -opaque_image
->height
;
581 bi
.bmiHeader
.biSizeImage
= 0;
582 bi
.bmiHeader
.biXPelsPerMeter
= PELS_72DPI
;
583 bi
.bmiHeader
.biYPelsPerMeter
= PELS_72DPI
;
584 bi
.bmiHeader
.biPlanes
= 1;
585 bi
.bmiHeader
.biBitCount
= 32;
586 bi
.bmiHeader
.biCompression
= BI_RGB
;
587 bi
.bmiHeader
.biClrUsed
= 0;
588 bi
.bmiHeader
.biClrImportant
= 0;
590 m
= pattern
->base
.matrix
;
591 status
= cairo_matrix_invert (&m
);
592 /* _cairo_pattern_set_matrix guarantees invertibility */
593 assert (status
== CAIRO_STATUS_SUCCESS
);
595 cairo_matrix_multiply (&m
, &m
, &surface
->ctm
);
596 SaveDC (surface
->dc
);
597 _cairo_matrix_to_win32_xform (&m
, &xform
);
599 if (! SetWorldTransform (surface
->dc
, &xform
)) {
600 status
= _cairo_win32_print_gdi_error ("_win32_scaled_font_set_world_transform");
601 goto CLEANUP_OPAQUE_IMAGE
;
604 oldmode
= SetStretchBltMode(surface
->dc
, HALFTONE
);
606 GetClipBox (surface
->dc
, &clip
);
607 if (extend
== CAIRO_EXTEND_REPEAT
|| extend
== CAIRO_EXTEND_REFLECT
) {
608 left
= (int) floor((double)clip
.left
/opaque_image
->width
);
609 right
= (int) ceil((double)clip
.right
/opaque_image
->width
);
610 top
= (int) floor((double)clip
.top
/opaque_image
->height
);
611 bottom
= (int) ceil((double)clip
.bottom
/opaque_image
->height
);
619 for (y_tile
= top
; y_tile
< bottom
; y_tile
++) {
620 for (x_tile
= left
; x_tile
< right
; x_tile
++) {
621 if (!StretchDIBits (surface
->dc
,
622 x_tile
*opaque_image
->width
,
623 y_tile
*opaque_image
->height
,
625 opaque_image
->height
,
629 opaque_image
->height
,
635 status
= _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint(StretchDIBits)");
636 goto CLEANUP_OPAQUE_IMAGE
;
640 SetStretchBltMode(surface
->dc
, oldmode
);
641 RestoreDC (surface
->dc
, -1);
643 CLEANUP_OPAQUE_IMAGE
:
644 if (opaque_image
!= image
)
645 cairo_surface_destroy (opaque_surface
);
647 _cairo_surface_release_source_image (pattern
->surface
, image
, image_extra
);
652 static cairo_status_t
653 _cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t
*surface
,
654 cairo_surface_pattern_t
*pattern
)
656 if (_cairo_surface_is_meta (pattern
->surface
)) {
657 return _cairo_win32_printing_surface_paint_meta_pattern (surface
,
660 return _cairo_win32_printing_surface_paint_image_pattern (surface
,
666 vertex_set_color (TRIVERTEX
*vert
, cairo_color_t
*color
)
668 /* MSDN says that the range here is 0x0000 .. 0xff00;
669 * that may well be a typo, but just chop the low bits
671 vert
->Alpha
= 0xff00;
672 vert
->Red
= color
->red_short
& 0xff00;
673 vert
->Green
= color
->green_short
& 0xff00;
674 vert
->Blue
= color
->blue_short
& 0xff00;
677 static cairo_int_status_t
678 _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t
*surface
,
679 cairo_linear_pattern_t
*pattern
)
686 cairo_matrix_t mat
, rot
;
687 double p1x
, p1y
, p2x
, p2y
, xd
, yd
, d
, sn
, cs
;
688 cairo_extend_t extend
;
689 int range_start
, range_stop
, num_ranges
, num_rects
, stop
;
690 int total_verts
, total_rects
;
691 cairo_status_t status
;
693 extend
= cairo_pattern_get_extend (&pattern
->base
.base
);
694 SaveDC (surface
->dc
);
696 mat
= pattern
->base
.base
.matrix
;
697 status
= cairo_matrix_invert (&mat
);
698 /* _cairo_pattern_set_matrix guarantees invertibility */
699 assert (status
== CAIRO_STATUS_SUCCESS
);
701 cairo_matrix_multiply (&mat
, &surface
->ctm
, &mat
);
703 p1x
= _cairo_fixed_to_double (pattern
->p1
.x
);
704 p1y
= _cairo_fixed_to_double (pattern
->p1
.y
);
705 p2x
= _cairo_fixed_to_double (pattern
->p2
.x
);
706 p2y
= _cairo_fixed_to_double (pattern
->p2
.y
);
707 cairo_matrix_translate (&mat
, p1x
, p1y
);
711 d
= sqrt (xd
*xd
+ yd
*yd
);
714 cairo_matrix_init (&rot
,
718 cairo_matrix_multiply (&mat
, &rot
, &mat
);
720 _cairo_matrix_to_win32_xform (&mat
, &xform
);
722 if (!SetWorldTransform (surface
->dc
, &xform
))
723 return _cairo_win32_print_gdi_error ("_win32_printing_surface_paint_linear_pattern:SetWorldTransform2");
725 GetClipBox (surface
->dc
, &clip
);
727 if (extend
== CAIRO_EXTEND_REPEAT
|| extend
== CAIRO_EXTEND_REFLECT
) {
728 range_start
= (int) floor(clip
.left
/d
);
729 range_stop
= (int) ceil(clip
.right
/d
);
734 num_ranges
= range_stop
- range_start
;
735 num_stops
= pattern
->base
.n_stops
;
736 num_rects
= num_stops
- 1;
738 /* Add an extra four points and two rectangles for EXTEND_PAD */
739 vert
= malloc (sizeof (TRIVERTEX
) * (num_rects
*2*num_ranges
+ 4));
740 rect
= malloc (sizeof (GRADIENT_RECT
) * (num_rects
*num_ranges
+ 2));
742 for (i
= 0; i
< num_ranges
*num_rects
; i
++) {
743 vert
[i
*2].y
= (LONG
) clip
.top
;
744 if (i
%num_rects
== 0) {
746 if (extend
== CAIRO_EXTEND_REFLECT
&& (range_start
+(i
/num_rects
))%2)
748 vert
[i
*2].x
= (LONG
)(d
*(range_start
+ i
/num_rects
));
749 vertex_set_color (&vert
[i
*2], &pattern
->base
.stops
[stop
].color
);
751 vert
[i
*2].x
= vert
[i
*2-1].x
;
752 vert
[i
*2].Red
= vert
[i
*2-1].Red
;
753 vert
[i
*2].Green
= vert
[i
*2-1].Green
;
754 vert
[i
*2].Blue
= vert
[i
*2-1].Blue
;
755 vert
[i
*2].Alpha
= vert
[i
*2-1].Alpha
;
758 stop
= i
%num_rects
+ 1;
759 vert
[i
*2+1].x
= (LONG
)(d
*(range_start
+ i
/num_rects
+ pattern
->base
.stops
[stop
].offset
));
760 vert
[i
*2+1].y
= (LONG
) clip
.bottom
;
761 if (extend
== CAIRO_EXTEND_REFLECT
&& (range_start
+(i
/num_rects
))%2)
762 stop
= num_rects
- stop
;
763 vertex_set_color (&vert
[i
*2+1], &pattern
->base
.stops
[stop
].color
);
765 rect
[i
].UpperLeft
= i
*2;
766 rect
[i
].LowerRight
= i
*2 + 1;
768 total_verts
= 2*num_ranges
*num_rects
;
769 total_rects
= num_ranges
*num_rects
;
771 if (extend
== CAIRO_EXTEND_PAD
) {
772 vert
[i
*2].x
= vert
[i
*2-1].x
;
773 vert
[i
*2].y
= (LONG
) clip
.top
;
774 vert
[i
*2].Red
= vert
[i
*2-1].Red
;
775 vert
[i
*2].Green
= vert
[i
*2-1].Green
;
776 vert
[i
*2].Blue
= vert
[i
*2-1].Blue
;
777 vert
[i
*2].Alpha
= 0xff00;
778 vert
[i
*2+1].x
= clip
.right
;
779 vert
[i
*2+1].y
= (LONG
) clip
.bottom
;
780 vert
[i
*2+1].Red
= vert
[i
*2-1].Red
;
781 vert
[i
*2+1].Green
= vert
[i
*2-1].Green
;
782 vert
[i
*2+1].Blue
= vert
[i
*2-1].Blue
;
783 vert
[i
*2+1].Alpha
= 0xff00;
784 rect
[i
].UpperLeft
= i
*2;
785 rect
[i
].LowerRight
= i
*2 + 1;
789 vert
[i
*2].x
= clip
.left
;
790 vert
[i
*2].y
= (LONG
) clip
.top
;
791 vert
[i
*2].Red
= vert
[0].Red
;
792 vert
[i
*2].Green
= vert
[0].Green
;
793 vert
[i
*2].Blue
= vert
[0].Blue
;
794 vert
[i
*2].Alpha
= 0xff00;
795 vert
[i
*2+1].x
= vert
[0].x
;
796 vert
[i
*2+1].y
= (LONG
) clip
.bottom
;
797 vert
[i
*2+1].Red
= vert
[0].Red
;
798 vert
[i
*2+1].Green
= vert
[0].Green
;
799 vert
[i
*2+1].Blue
= vert
[0].Blue
;
800 vert
[i
*2+1].Alpha
= 0xff00;
801 rect
[i
].UpperLeft
= i
*2;
802 rect
[i
].LowerRight
= i
*2 + 1;
808 if (!GradientFill (surface
->dc
,
811 GRADIENT_FILL_RECT_H
))
812 return _cairo_win32_print_gdi_error ("_win32_printing_surface_paint_linear_pattern:GradientFill");
816 RestoreDC (surface
->dc
, -1);
821 static cairo_int_status_t
822 _cairo_win32_printing_surface_paint_pattern (cairo_win32_surface_t
*surface
,
823 cairo_pattern_t
*pattern
)
825 cairo_status_t status
;
827 switch (pattern
->type
) {
828 case CAIRO_PATTERN_TYPE_SOLID
:
829 status
= _cairo_win32_printing_surface_paint_solid_pattern (surface
, pattern
);
834 case CAIRO_PATTERN_TYPE_SURFACE
:
835 status
= _cairo_win32_printing_surface_paint_surface_pattern (surface
,
836 (cairo_surface_pattern_t
*) pattern
);
841 case CAIRO_PATTERN_TYPE_LINEAR
:
842 status
= _cairo_win32_printing_surface_paint_linear_pattern (surface
, (cairo_linear_pattern_t
*) pattern
);
847 case CAIRO_PATTERN_TYPE_RADIAL
:
848 return CAIRO_INT_STATUS_UNSUPPORTED
;
852 return CAIRO_STATUS_SUCCESS
;
855 typedef struct _win32_print_path_info
{
856 cairo_win32_surface_t
*surface
;
859 static cairo_status_t
860 _cairo_win32_printing_surface_path_move_to (void *closure
, cairo_point_t
*point
)
862 win32_path_info_t
*path_info
= closure
;
864 if (path_info
->surface
->has_ctm
) {
867 x
= _cairo_fixed_to_double (point
->x
);
868 y
= _cairo_fixed_to_double (point
->y
);
869 cairo_matrix_transform_point (&path_info
->surface
->ctm
, &x
, &y
);
870 MoveToEx (path_info
->surface
->dc
, (int) x
, (int) y
, NULL
);
872 MoveToEx (path_info
->surface
->dc
,
873 _cairo_fixed_integer_part (point
->x
),
874 _cairo_fixed_integer_part (point
->y
),
878 return CAIRO_STATUS_SUCCESS
;
881 static cairo_status_t
882 _cairo_win32_printing_surface_path_line_to (void *closure
, cairo_point_t
*point
)
884 win32_path_info_t
*path_info
= closure
;
886 path_info
->surface
->path_empty
= FALSE
;
887 if (path_info
->surface
->has_ctm
) {
890 x
= _cairo_fixed_to_double (point
->x
);
891 y
= _cairo_fixed_to_double (point
->y
);
892 cairo_matrix_transform_point (&path_info
->surface
->ctm
, &x
, &y
);
893 LineTo (path_info
->surface
->dc
, (int) x
, (int) y
);
895 LineTo (path_info
->surface
->dc
,
896 _cairo_fixed_integer_part (point
->x
),
897 _cairo_fixed_integer_part (point
->y
));
900 return CAIRO_STATUS_SUCCESS
;
903 static cairo_status_t
904 _cairo_win32_printing_surface_path_curve_to (void *closure
,
909 win32_path_info_t
*path_info
= closure
;
912 path_info
->surface
->path_empty
= FALSE
;
913 if (path_info
->surface
->has_ctm
) {
916 x
= _cairo_fixed_to_double (b
->x
);
917 y
= _cairo_fixed_to_double (b
->y
);
918 cairo_matrix_transform_point (&path_info
->surface
->ctm
, &x
, &y
);
919 points
[0].x
= (LONG
) x
;
920 points
[0].y
= (LONG
) y
;
922 x
= _cairo_fixed_to_double (c
->x
);
923 y
= _cairo_fixed_to_double (c
->y
);
924 cairo_matrix_transform_point (&path_info
->surface
->ctm
, &x
, &y
);
925 points
[1].x
= (LONG
) x
;
926 points
[1].y
= (LONG
) y
;
928 x
= _cairo_fixed_to_double (d
->x
);
929 y
= _cairo_fixed_to_double (d
->y
);
930 cairo_matrix_transform_point (&path_info
->surface
->ctm
, &x
, &y
);
931 points
[2].x
= (LONG
) x
;
932 points
[2].y
= (LONG
) y
;
934 points
[0].x
= _cairo_fixed_integer_part (b
->x
);
935 points
[0].y
= _cairo_fixed_integer_part (b
->y
);
936 points
[1].x
= _cairo_fixed_integer_part (c
->x
);
937 points
[1].y
= _cairo_fixed_integer_part (c
->y
);
938 points
[2].x
= _cairo_fixed_integer_part (d
->x
);
939 points
[2].y
= _cairo_fixed_integer_part (d
->y
);
941 PolyBezierTo (path_info
->surface
->dc
, points
, 3);
943 return CAIRO_STATUS_SUCCESS
;
946 static cairo_status_t
947 _cairo_win32_printing_surface_path_close_path (void *closure
)
949 win32_path_info_t
*path_info
= closure
;
951 CloseFigure (path_info
->surface
->dc
);
953 return CAIRO_STATUS_SUCCESS
;
956 static cairo_status_t
957 _cairo_win32_printing_surface_emit_path (cairo_win32_surface_t
*surface
,
958 cairo_path_fixed_t
*path
)
960 win32_path_info_t path_info
;
961 cairo_status_t status
;
963 path_info
.surface
= surface
;
964 status
= _cairo_path_fixed_interpret (path
,
965 CAIRO_DIRECTION_FORWARD
,
966 _cairo_win32_printing_surface_path_move_to
,
967 _cairo_win32_printing_surface_path_line_to
,
968 _cairo_win32_printing_surface_path_curve_to
,
969 _cairo_win32_printing_surface_path_close_path
,
974 static cairo_int_status_t
975 _cairo_win32_printing_surface_show_page (void *abstract_surface
)
977 cairo_win32_surface_t
*surface
= abstract_surface
;
979 /* Undo both SaveDC's that we did in start_page */
980 RestoreDC (surface
->dc
, -2);
982 return CAIRO_STATUS_SUCCESS
;
985 static cairo_int_status_t
986 _cairo_win32_printing_surface_intersect_clip_path (void *abstract_surface
,
987 cairo_path_fixed_t
*path
,
988 cairo_fill_rule_t fill_rule
,
990 cairo_antialias_t antialias
)
992 cairo_win32_surface_t
*surface
= abstract_surface
;
993 cairo_status_t status
;
995 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
)
996 return CAIRO_STATUS_SUCCESS
;
999 RestoreDC (surface
->dc
, -1);
1000 SaveDC (surface
->dc
);
1002 return CAIRO_STATUS_SUCCESS
;
1005 BeginPath (surface
->dc
);
1006 status
= _cairo_win32_printing_surface_emit_path (surface
, path
);
1007 EndPath (surface
->dc
);
1009 switch (fill_rule
) {
1010 case CAIRO_FILL_RULE_WINDING
:
1011 SetPolyFillMode (surface
->dc
, WINDING
);
1013 case CAIRO_FILL_RULE_EVEN_ODD
:
1014 SetPolyFillMode (surface
->dc
, ALTERNATE
);
1020 SelectClipPath (surface
->dc
, RGN_AND
);
1026 _cairo_win32_printing_surface_get_font_options (void *abstract_surface
,
1027 cairo_font_options_t
*options
)
1029 _cairo_font_options_init_default (options
);
1031 cairo_font_options_set_hint_style (options
, CAIRO_HINT_STYLE_NONE
);
1032 cairo_font_options_set_hint_metrics (options
, CAIRO_HINT_METRICS_OFF
);
1033 cairo_font_options_set_antialias (options
, CAIRO_ANTIALIAS_GRAY
);
1036 static cairo_int_status_t
1037 _cairo_win32_printing_surface_paint (void *abstract_surface
,
1038 cairo_operator_t op
,
1039 cairo_pattern_t
*source
)
1041 cairo_win32_surface_t
*surface
= abstract_surface
;
1042 cairo_solid_pattern_t clear
;
1044 if (op
== CAIRO_OPERATOR_CLEAR
) {
1045 _cairo_win32_printing_surface_init_clear_color (surface
, &clear
);
1046 source
= (cairo_pattern_t
*) &clear
;
1047 op
= CAIRO_OPERATOR_SOURCE
;
1050 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
)
1051 return _cairo_win32_printing_surface_analyze_operation (surface
, op
, source
);
1053 assert (_cairo_win32_printing_surface_operation_supported (surface
, op
, source
));
1055 return _cairo_win32_printing_surface_paint_pattern (surface
, source
);
1059 _cairo_win32_line_cap (cairo_line_cap_t cap
)
1062 case CAIRO_LINE_CAP_BUTT
:
1063 return PS_ENDCAP_FLAT
;
1064 case CAIRO_LINE_CAP_ROUND
:
1065 return PS_ENDCAP_ROUND
;
1066 case CAIRO_LINE_CAP_SQUARE
:
1067 return PS_ENDCAP_SQUARE
;
1075 _cairo_win32_line_join (cairo_line_join_t join
)
1078 case CAIRO_LINE_JOIN_MITER
:
1079 return PS_JOIN_MITER
;
1080 case CAIRO_LINE_JOIN_ROUND
:
1081 return PS_JOIN_ROUND
;
1082 case CAIRO_LINE_JOIN_BEVEL
:
1083 return PS_JOIN_BEVEL
;
1091 _cairo_matrix_factor_out_scale (cairo_matrix_t
*m
, double *scale
)
1096 if (fabs (m
->xy
) > s
)
1098 if (fabs (m
->yx
) > s
)
1100 if (fabs (m
->yy
) > s
)
1104 cairo_matrix_scale (m
, s
, s
);
1107 static cairo_int_status_t
1108 _cairo_win32_printing_surface_stroke (void *abstract_surface
,
1109 cairo_operator_t op
,
1110 cairo_pattern_t
*source
,
1111 cairo_path_fixed_t
*path
,
1112 cairo_stroke_style_t
*style
,
1113 cairo_matrix_t
*stroke_ctm
,
1114 cairo_matrix_t
*stroke_ctm_inverse
,
1116 cairo_antialias_t antialias
)
1118 cairo_win32_surface_t
*surface
= abstract_surface
;
1119 cairo_int_status_t status
;
1128 cairo_solid_pattern_t clear
;
1132 if (op
== CAIRO_OPERATOR_CLEAR
) {
1133 _cairo_win32_printing_surface_init_clear_color (surface
, &clear
);
1134 source
= (cairo_pattern_t
*) &clear
;
1135 op
= CAIRO_OPERATOR_SOURCE
;
1138 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
) {
1139 /* Win32 does not support a dash offset. */
1140 if (style
->num_dashes
> 0 && style
->dash_offset
!= 0.0)
1141 return CAIRO_INT_STATUS_UNSUPPORTED
;
1143 return _cairo_win32_printing_surface_analyze_operation (surface
, op
, source
);
1146 assert (_cairo_win32_printing_surface_operation_supported (surface
, op
, source
));
1147 assert (!(style
->num_dashes
> 0 && style
->dash_offset
!= 0.0));
1149 cairo_matrix_multiply (&mat
, stroke_ctm
, &surface
->ctm
);
1150 _cairo_matrix_factor_out_scale (&mat
, &scale
);
1152 pen_style
= PS_GEOMETRIC
;
1154 if (style
->num_dashes
) {
1155 pen_style
|= PS_USERSTYLE
;
1156 dash_array
= calloc (sizeof (DWORD
), style
->num_dashes
);
1157 for (i
= 0; i
< style
->num_dashes
; i
++) {
1158 dash_array
[i
] = (DWORD
) (scale
* style
->dash
[i
]);
1161 pen_style
|= PS_SOLID
;
1164 SetMiterLimit (surface
->dc
, (FLOAT
) (style
->miter_limit
), NULL
);
1165 if (source
->type
== CAIRO_PATTERN_TYPE_SOLID
) {
1166 cairo_solid_pattern_t
*solid
= (cairo_solid_pattern_t
*) source
;
1169 color
= _cairo_win32_printing_surface_flatten_transparency (surface
,
1172 /* Color not used as the pen will only be used by WidenPath() */
1173 color
= RGB (0,0,0);
1175 brush
.lbStyle
= BS_SOLID
;
1176 brush
.lbColor
= color
;
1178 pen_style
|= _cairo_win32_line_cap (style
->line_cap
);
1179 pen_style
|= _cairo_win32_line_join (style
->line_join
);
1180 pen
= ExtCreatePen(pen_style
,
1181 scale
* style
->line_width
,
1186 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:ExtCreatePen");
1187 obj
= SelectObject (surface
->dc
, pen
);
1189 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectObject");
1191 BeginPath (surface
->dc
);
1192 status
= _cairo_win32_printing_surface_emit_path (surface
, path
);
1193 EndPath (surface
->dc
);
1198 * Switch to user space to set line parameters
1200 SaveDC (surface
->dc
);
1202 _cairo_matrix_to_win32_xform (&mat
, &xform
);
1206 if (!SetWorldTransform (surface
->dc
, &xform
))
1207 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SetWorldTransform");
1209 if (source
->type
== CAIRO_PATTERN_TYPE_SOLID
) {
1210 StrokePath (surface
->dc
);
1212 if (!WidenPath (surface
->dc
))
1213 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:WidenPath");
1214 if (!SelectClipPath (surface
->dc
, RGN_AND
))
1215 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectClipPath");
1217 /* Return to device space to paint the pattern */
1218 if (!ModifyWorldTransform (surface
->dc
, &xform
, MWT_IDENTITY
))
1219 return _cairo_win32_print_gdi_error ("_win32_surface_stroke:ModifyWorldTransform");
1220 status
= _cairo_win32_printing_surface_paint_pattern (surface
, source
);
1222 RestoreDC (surface
->dc
, -1);
1230 static cairo_int_status_t
1231 _cairo_win32_printing_surface_fill (void *abstract_surface
,
1232 cairo_operator_t op
,
1233 cairo_pattern_t
*source
,
1234 cairo_path_fixed_t
*path
,
1235 cairo_fill_rule_t fill_rule
,
1237 cairo_antialias_t antialias
)
1239 cairo_win32_surface_t
*surface
= abstract_surface
;
1240 cairo_int_status_t status
;
1241 cairo_solid_pattern_t clear
;
1243 if (op
== CAIRO_OPERATOR_CLEAR
) {
1244 _cairo_win32_printing_surface_init_clear_color (surface
, &clear
);
1245 source
= (cairo_pattern_t
*) &clear
;
1246 op
= CAIRO_OPERATOR_SOURCE
;
1249 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
)
1250 return _cairo_win32_printing_surface_analyze_operation (surface
, op
, source
);
1252 assert (_cairo_win32_printing_surface_operation_supported (surface
, op
, source
));
1254 surface
->path_empty
= TRUE
;
1255 BeginPath (surface
->dc
);
1256 status
= _cairo_win32_printing_surface_emit_path (surface
, path
);
1257 EndPath (surface
->dc
);
1259 switch (fill_rule
) {
1260 case CAIRO_FILL_RULE_WINDING
:
1261 SetPolyFillMode (surface
->dc
, WINDING
);
1263 case CAIRO_FILL_RULE_EVEN_ODD
:
1264 SetPolyFillMode (surface
->dc
, ALTERNATE
);
1270 if (source
->type
== CAIRO_PATTERN_TYPE_SOLID
) {
1271 status
= _cairo_win32_printing_surface_select_solid_brush (surface
, source
);
1275 FillPath (surface
->dc
);
1276 _cairo_win32_printing_surface_done_solid_brush (surface
);
1277 } else if (surface
->path_empty
== FALSE
) {
1278 SaveDC (surface
->dc
);
1279 SelectClipPath (surface
->dc
, RGN_AND
);
1280 status
= _cairo_win32_printing_surface_paint_pattern (surface
, source
);
1281 RestoreDC (surface
->dc
, -1);
1289 static cairo_int_status_t
1290 _cairo_win32_printing_surface_show_glyphs (void *abstract_surface
,
1291 cairo_operator_t op
,
1292 cairo_pattern_t
*source
,
1293 cairo_glyph_t
*glyphs
,
1295 cairo_scaled_font_t
*scaled_font
,
1296 int *remaining_glyphs
)
1298 cairo_win32_surface_t
*surface
= abstract_surface
;
1299 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
1300 cairo_scaled_glyph_t
*scaled_glyph
;
1301 cairo_pattern_t
*opaque
= NULL
;
1303 cairo_matrix_t old_ctm
;
1304 cairo_bool_t old_has_ctm
;
1305 cairo_solid_pattern_t clear
;
1307 if (op
== CAIRO_OPERATOR_CLEAR
) {
1308 _cairo_win32_printing_surface_init_clear_color (surface
, &clear
);
1309 source
= (cairo_pattern_t
*) &clear
;
1310 op
= CAIRO_OPERATOR_SOURCE
;
1313 if (surface
->paginated_mode
== CAIRO_PAGINATED_MODE_ANALYZE
) {
1314 /* When printing bitmap fonts to a printer DC, Windows may
1315 * substitute an outline font for bitmap font. As the win32
1316 * font backend always uses a screen DC when obtaining the
1317 * font metrics the metrics of the substituted font will not
1318 * match the metrics that the win32 font backend returns.
1320 * If we are printing a bitmap font, use fallback images to
1321 * ensure the font is not substituted.
1323 if (cairo_scaled_font_get_type (scaled_font
) == CAIRO_FONT_TYPE_WIN32
) {
1324 if (_cairo_win32_scaled_font_is_bitmap (scaled_font
))
1325 return CAIRO_INT_STATUS_UNSUPPORTED
;
1327 return _cairo_win32_printing_surface_analyze_operation (surface
, op
, source
);
1330 /* For non win32 fonts we need to check that each glyph has a
1331 * path available. If a path is not available,
1332 * _cairo_scaled_glyph_lookup() will return
1333 * CAIRO_INT_STATUS_UNSUPPORTED and a fallback image will be
1336 for (i
= 0; i
< num_glyphs
; i
++) {
1337 status
= _cairo_scaled_glyph_lookup (scaled_font
,
1339 CAIRO_SCALED_GLYPH_INFO_PATH
,
1345 return _cairo_win32_printing_surface_analyze_operation (surface
, op
, source
);
1348 if (source
->type
== CAIRO_PATTERN_TYPE_SOLID
) {
1349 cairo_solid_pattern_t
*solid
= (cairo_solid_pattern_t
*) source
;
1352 color
= _cairo_win32_printing_surface_flatten_transparency (surface
,
1354 opaque
= cairo_pattern_create_rgb (GetRValue (color
) / 255.0,
1355 GetGValue (color
) / 255.0,
1356 GetBValue (color
) / 255.0);
1358 return opaque
->status
;
1362 if (cairo_scaled_font_get_type (scaled_font
) == CAIRO_FONT_TYPE_WIN32
&&
1363 source
->type
== CAIRO_PATTERN_TYPE_SOLID
)
1366 cairo_glyph_t
*type1_glyphs
= NULL
;
1367 cairo_scaled_font_subsets_glyph_t subset_glyph
;
1369 /* Calling ExtTextOutW() with ETO_GLYPH_INDEX and a Type 1
1370 * font on a printer DC prints garbled text. The text displays
1371 * correctly on a display DC. When using a printer
1372 * DC, ExtTextOutW() only works with characters and not glyph
1375 * For Type 1 fonts the glyph indices are converted back to
1376 * unicode characters before calling _cairo_win32_surface_show_glyphs().
1378 * As _cairo_win32_scaled_font_index_to_ucs4() is a slow
1379 * operation, the font subsetting function
1380 * _cairo_scaled_font_subsets_map_glyph() is used to obtain
1381 * the unicode value because it caches the reverse mapping in
1384 if (_cairo_win32_scaled_font_is_type1 (scaled_font
)) {
1385 type1_glyphs
= _cairo_malloc_ab (num_glyphs
, sizeof (cairo_glyph_t
));
1386 if (type1_glyphs
== NULL
)
1387 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1389 memcpy (type1_glyphs
, glyphs
, num_glyphs
* sizeof (cairo_glyph_t
));
1390 for (i
= 0; i
< num_glyphs
; i
++) {
1391 status
= _cairo_scaled_font_subsets_map_glyph (surface
->font_subsets
,
1393 type1_glyphs
[i
].index
,
1399 type1_glyphs
[i
].index
= subset_glyph
.unicode
;
1401 glyphs
= type1_glyphs
;
1404 if (surface
->has_ctm
) {
1405 for (i
= 0; i
< num_glyphs
; i
++)
1406 cairo_matrix_transform_point (&surface
->ctm
, &glyphs
[i
].x
, &glyphs
[i
].y
);
1407 cairo_matrix_multiply (&ctm
, &scaled_font
->ctm
, &surface
->ctm
);
1408 scaled_font
= cairo_scaled_font_create (scaled_font
->font_face
,
1409 &scaled_font
->font_matrix
,
1411 &scaled_font
->options
);
1413 status
= _cairo_win32_surface_show_glyphs (surface
, op
,
1415 num_glyphs
, scaled_font
,
1417 if (surface
->has_ctm
)
1418 cairo_scaled_font_destroy (scaled_font
);
1420 if (type1_glyphs
!= NULL
)
1421 free (type1_glyphs
);
1426 SaveDC (surface
->dc
);
1427 old_ctm
= surface
->ctm
;
1428 old_has_ctm
= surface
->has_ctm
;
1429 surface
->has_ctm
= TRUE
;
1430 surface
->path_empty
= TRUE
;
1431 BeginPath (surface
->dc
);
1432 for (i
= 0; i
< num_glyphs
; i
++) {
1433 status
= _cairo_scaled_glyph_lookup (scaled_font
,
1435 CAIRO_SCALED_GLYPH_INFO_PATH
,
1439 surface
->ctm
= old_ctm
;
1440 cairo_matrix_translate (&surface
->ctm
, glyphs
[i
].x
, glyphs
[i
].y
);
1441 status
= _cairo_win32_printing_surface_emit_path (surface
, scaled_glyph
->path
);
1443 EndPath (surface
->dc
);
1444 surface
->ctm
= old_ctm
;
1445 surface
->has_ctm
= old_has_ctm
;
1446 if (status
== CAIRO_STATUS_SUCCESS
&& surface
->path_empty
== FALSE
) {
1447 if (source
->type
== CAIRO_PATTERN_TYPE_SOLID
) {
1448 status
= _cairo_win32_printing_surface_select_solid_brush (surface
, source
);
1452 SetPolyFillMode (surface
->dc
, WINDING
);
1453 FillPath (surface
->dc
);
1454 _cairo_win32_printing_surface_done_solid_brush (surface
);
1456 SelectClipPath (surface
->dc
, RGN_AND
);
1457 status
= _cairo_win32_printing_surface_paint_pattern (surface
, source
);
1460 RestoreDC (surface
->dc
, -1);
1463 cairo_pattern_destroy (opaque
);
1468 static cairo_surface_t
*
1469 _cairo_win32_printing_surface_create_similar (void *abstract_surface
,
1470 cairo_content_t content
,
1474 return _cairo_meta_surface_create (content
, width
, height
);
1477 static cairo_int_status_t
1478 _cairo_win32_printing_surface_start_page (void *abstract_surface
)
1480 cairo_win32_surface_t
*surface
= abstract_surface
;
1482 double x_res
, y_res
;
1483 cairo_matrix_t inverse_ctm
;
1484 cairo_status_t status
;
1486 SaveDC (surface
->dc
); /* Save application context first, before doing MWT */
1488 SetGraphicsMode (surface
->dc
, GM_ADVANCED
);
1489 GetWorldTransform(surface
->dc
, &xform
);
1490 surface
->ctm
.xx
= xform
.eM11
;
1491 surface
->ctm
.xy
= xform
.eM21
;
1492 surface
->ctm
.yx
= xform
.eM12
;
1493 surface
->ctm
.yy
= xform
.eM22
;
1494 surface
->ctm
.x0
= xform
.eDx
;
1495 surface
->ctm
.y0
= xform
.eDy
;
1496 surface
->has_ctm
= !_cairo_matrix_is_identity (&surface
->ctm
);
1498 inverse_ctm
= surface
->ctm
;
1499 status
= cairo_matrix_invert (&inverse_ctm
);
1503 x_res
= (double) GetDeviceCaps(surface
->dc
, LOGPIXELSX
);
1504 y_res
= (double) GetDeviceCaps(surface
->dc
, LOGPIXELSY
);
1505 cairo_matrix_transform_distance (&inverse_ctm
, &x_res
, &y_res
);
1506 _cairo_surface_set_resolution (&surface
->base
, x_res
, y_res
);
1508 if (!ModifyWorldTransform (surface
->dc
, NULL
, MWT_IDENTITY
))
1509 return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_start_page:ModifyWorldTransform");
1511 SaveDC (surface
->dc
); /* Then save Cairo's known-good clip state, so the clip path can be reset */
1513 return CAIRO_STATUS_SUCCESS
;
1517 _cairo_win32_printing_surface_set_paginated_mode (void *abstract_surface
,
1518 cairo_paginated_mode_t paginated_mode
)
1520 cairo_win32_surface_t
*surface
= abstract_surface
;
1522 surface
->paginated_mode
= paginated_mode
;
1526 _cairo_win32_printing_surface_supports_fine_grained_fallbacks (void *abstract_surface
)
1532 * cairo_win32_printing_surface_create:
1533 * @hdc: the DC to create a surface for
1535 * Creates a cairo surface that targets the given DC. The DC will be
1536 * queried for its initial clip extents, and this will be used as the
1537 * size of the cairo surface. The DC should be a printing DC;
1538 * antialiasing will be ignored, and GDI will be used as much as
1539 * possible to draw to the surface.
1541 * The returned surface will be wrapped using the paginated surface to
1542 * provide correct complex rendering behaviour; show_page() and
1543 * associated methods must be used for correct output.
1545 * Return value: the newly created surface
1550 cairo_win32_printing_surface_create (HDC hdc
)
1552 cairo_win32_surface_t
*surface
;
1553 cairo_surface_t
*paginated
;
1556 surface
= malloc (sizeof (cairo_win32_surface_t
));
1557 if (surface
== NULL
)
1558 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1560 if (_cairo_win32_save_initial_clip (hdc
, surface
) != CAIRO_STATUS_SUCCESS
) {
1562 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1565 surface
->image
= NULL
;
1566 surface
->format
= CAIRO_FORMAT_RGB24
;
1567 surface
->content
= CAIRO_CONTENT_COLOR_ALPHA
;
1570 surface
->bitmap
= NULL
;
1571 surface
->is_dib
= FALSE
;
1572 surface
->saved_dc_bitmap
= NULL
;
1573 surface
->brush
= NULL
;
1574 surface
->old_brush
= NULL
;
1575 surface
->font_subsets
= _cairo_scaled_font_subsets_create_scaled ();
1576 if (surface
->font_subsets
== NULL
) {
1578 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1581 GetClipBox(hdc
, &rect
);
1582 surface
->extents
.x
= rect
.left
;
1583 surface
->extents
.y
= rect
.top
;
1584 surface
->extents
.width
= rect
.right
- rect
.left
;
1585 surface
->extents
.height
= rect
.bottom
- rect
.top
;
1587 surface
->flags
= _cairo_win32_flags_for_dc (surface
->dc
);
1588 surface
->flags
|= CAIRO_WIN32_SURFACE_FOR_PRINTING
;
1590 _cairo_win32_printing_surface_init_ps_mode (surface
);
1591 _cairo_surface_init (&surface
->base
, &cairo_win32_printing_surface_backend
,
1592 CAIRO_CONTENT_COLOR_ALPHA
);
1594 paginated
= _cairo_paginated_surface_create (&surface
->base
,
1595 CAIRO_CONTENT_COLOR_ALPHA
,
1596 surface
->extents
.width
,
1597 surface
->extents
.height
,
1598 &cairo_win32_surface_paginated_backend
);
1600 /* paginated keeps the only reference to surface now, drop ours */
1601 cairo_surface_destroy (&surface
->base
);
1607 _cairo_surface_is_win32_printing (cairo_surface_t
*surface
)
1609 return surface
->backend
== &cairo_win32_printing_surface_backend
;
1612 static const cairo_surface_backend_t cairo_win32_printing_surface_backend
= {
1613 CAIRO_SURFACE_TYPE_WIN32_PRINTING
,
1614 _cairo_win32_printing_surface_create_similar
,
1615 _cairo_win32_surface_finish
,
1616 NULL
, /* acquire_source_image */
1617 NULL
, /* release_source_image */
1618 NULL
, /* acquire_dest_image */
1619 NULL
, /* release_dest_image */
1620 _cairo_win32_surface_clone_similar
,
1621 NULL
, /* composite */
1622 NULL
, /* fill_rectangles */
1623 NULL
, /* composite_trapezoids */
1624 NULL
, /* copy_page */
1625 _cairo_win32_printing_surface_show_page
,
1626 NULL
, /* set_clip_region */
1627 _cairo_win32_printing_surface_intersect_clip_path
,
1628 _cairo_win32_surface_get_extents
,
1629 NULL
, /* old_show_glyphs */
1630 _cairo_win32_printing_surface_get_font_options
,
1632 NULL
, /* mark_dirty_rectangle */
1633 NULL
, /* scaled_font_fini */
1634 NULL
, /* scaled_glyph_fini */
1636 _cairo_win32_printing_surface_paint
,
1638 _cairo_win32_printing_surface_stroke
,
1639 _cairo_win32_printing_surface_fill
,
1640 _cairo_win32_printing_surface_show_glyphs
,
1641 NULL
, /* snapshot */
1642 NULL
, /* is_similar */
1644 NULL
, /* fill_stroke */
1647 static const cairo_paginated_surface_backend_t cairo_win32_surface_paginated_backend
= {
1648 _cairo_win32_printing_surface_start_page
,
1649 _cairo_win32_printing_surface_set_paginated_mode
,
1650 NULL
, /* set_bounding_box */
1651 NULL
, /* _cairo_win32_printing_surface_has_fallback_images, */
1652 _cairo_win32_printing_surface_supports_fine_grained_fallbacks
,