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 © 2005 Red Hat, Inc.
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 Red Hat, Inc.
34 * Owen Taylor <otaylor@redhat.com>
35 * Stuart Parmenter <stuart@mozilla.com>
36 * Vladimir Vukicevic <vladimir@pobox.com>
39 #define WIN32_LEAN_AND_MEAN
40 /* We require Windows 2000 features such as ETO_PDY */
41 #if !defined(WINVER) || (WINVER < 0x0500)
42 # define WINVER 0x0500
44 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
45 # define _WIN32_WINNT 0x0500
50 #include "cairo-clip-private.h"
51 #include "cairo-paginated-private.h"
52 #include "cairo-win32-private.h"
53 #include "cairo-scaled-font-subsets-private.h"
57 #if defined(__MINGW32__) && !defined(ETO_PDY)
58 # define ETO_PDY 0x2000
61 #undef DEBUG_COMPOSITE
64 #ifndef SHADEBLENDCAPS
65 #define SHADEBLENDCAPS 120
68 #define SB_NONE 0x00000000
71 #define PELS_72DPI ((LONG)(72. / 0.0254))
73 static const cairo_surface_backend_t cairo_win32_surface_backend
;
76 * _cairo_win32_print_gdi_error:
77 * @context: context string to display along with the error
79 * Helper function to dump out a human readable form of the
82 * Return value: A cairo status code for the error code
85 _cairo_win32_print_gdi_error (const char *context
)
88 DWORD last_error
= GetLastError ();
90 if (!FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER
|
91 FORMAT_MESSAGE_FROM_SYSTEM
,
94 MAKELANGID (LANG_NEUTRAL
, SUBLANG_DEFAULT
),
97 fprintf (stderr
, "%s: Unknown GDI error", context
);
99 fwprintf (stderr
, "%S: %s", context
, (char *)lpMsgBuf
);
101 LocalFree (lpMsgBuf
);
104 /* We should switch off of last_status, but we'd either return
105 * CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there
106 * is no CAIRO_STATUS_UNKNOWN_ERROR.
109 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
113 _cairo_win32_flags_for_dc (HDC dc
)
117 if (GetDeviceCaps(dc
, TECHNOLOGY
) == DT_RASDISPLAY
) {
118 flags
|= CAIRO_WIN32_SURFACE_IS_DISPLAY
;
120 /* These will always be possible, but the actual GetDeviceCaps
121 * calls will return whether they're accelerated or not.
122 * We may want to use our own (pixman) routines sometimes
123 * if they're eventually faster, but for now have GDI do
126 flags
|= CAIRO_WIN32_SURFACE_CAN_BITBLT
;
127 flags
|= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND
;
128 flags
|= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT
;
129 flags
|= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB
;
133 cap
= GetDeviceCaps(dc
, SHADEBLENDCAPS
);
135 flags
|= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND
;
137 cap
= GetDeviceCaps(dc
, RASTERCAPS
);
139 flags
|= CAIRO_WIN32_SURFACE_CAN_BITBLT
;
140 if (cap
& RC_STRETCHBLT
)
141 flags
|= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT
;
142 if (cap
& RC_STRETCHDIB
)
143 flags
|= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB
;
149 static cairo_status_t
150 _create_dc_and_bitmap (cairo_win32_surface_t
*surface
,
152 cairo_format_t format
,
155 unsigned char **bits_out
,
158 cairo_status_t status
;
160 BITMAPINFO
*bitmap_info
= NULL
;
162 BITMAPINFOHEADER bmiHeader
;
163 RGBQUAD bmiColors
[2];
167 int num_palette
= 0; /* Quiet GCC */
171 surface
->bitmap
= NULL
;
172 surface
->is_dib
= FALSE
;
175 case CAIRO_FORMAT_ARGB32
:
176 case CAIRO_FORMAT_RGB24
:
180 case CAIRO_FORMAT_A8
:
184 case CAIRO_FORMAT_A1
:
189 if (num_palette
> 2) {
190 bitmap_info
= _cairo_malloc_ab_plus_c (num_palette
, sizeof(RGBQUAD
), sizeof(BITMAPINFOHEADER
));
192 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
194 bitmap_info
= (BITMAPINFO
*)&bmi_stack
;
197 bitmap_info
->bmiHeader
.biSize
= sizeof (BITMAPINFOHEADER
);
198 bitmap_info
->bmiHeader
.biWidth
= width
== 0 ? 1 : width
;
199 bitmap_info
->bmiHeader
.biHeight
= height
== 0 ? -1 : - height
; /* top-down */
200 bitmap_info
->bmiHeader
.biSizeImage
= 0;
201 bitmap_info
->bmiHeader
.biXPelsPerMeter
= PELS_72DPI
; /* unused here */
202 bitmap_info
->bmiHeader
.biYPelsPerMeter
= PELS_72DPI
; /* unused here */
203 bitmap_info
->bmiHeader
.biPlanes
= 1;
206 /* We can't create real RGB24 bitmaps because something seems to
207 * break if we do, especially if we don't set up an image
208 * fallback. It could be a bug with using a 24bpp pixman image
209 * (and creating one with masks). So treat them like 32bpp.
210 * Note: This causes problems when using BitBlt/AlphaBlend/etc!
213 case CAIRO_FORMAT_RGB24
:
214 case CAIRO_FORMAT_ARGB32
:
215 bitmap_info
->bmiHeader
.biBitCount
= 32;
216 bitmap_info
->bmiHeader
.biCompression
= BI_RGB
;
217 bitmap_info
->bmiHeader
.biClrUsed
= 0; /* unused */
218 bitmap_info
->bmiHeader
.biClrImportant
= 0;
221 case CAIRO_FORMAT_A8
:
222 bitmap_info
->bmiHeader
.biBitCount
= 8;
223 bitmap_info
->bmiHeader
.biCompression
= BI_RGB
;
224 bitmap_info
->bmiHeader
.biClrUsed
= 256;
225 bitmap_info
->bmiHeader
.biClrImportant
= 0;
227 for (i
= 0; i
< 256; i
++) {
228 bitmap_info
->bmiColors
[i
].rgbBlue
= i
;
229 bitmap_info
->bmiColors
[i
].rgbGreen
= i
;
230 bitmap_info
->bmiColors
[i
].rgbRed
= i
;
231 bitmap_info
->bmiColors
[i
].rgbReserved
= 0;
236 case CAIRO_FORMAT_A1
:
237 bitmap_info
->bmiHeader
.biBitCount
= 1;
238 bitmap_info
->bmiHeader
.biCompression
= BI_RGB
;
239 bitmap_info
->bmiHeader
.biClrUsed
= 2;
240 bitmap_info
->bmiHeader
.biClrImportant
= 0;
242 for (i
= 0; i
< 2; i
++) {
243 bitmap_info
->bmiColors
[i
].rgbBlue
= i
* 255;
244 bitmap_info
->bmiColors
[i
].rgbGreen
= i
* 255;
245 bitmap_info
->bmiColors
[i
].rgbRed
= i
* 255;
246 bitmap_info
->bmiColors
[i
].rgbReserved
= 0;
252 surface
->dc
= CreateCompatibleDC (original_dc
);
256 surface
->bitmap
= CreateDIBSection (surface
->dc
,
261 if (!surface
->bitmap
)
264 surface
->is_dib
= TRUE
;
268 surface
->saved_dc_bitmap
= SelectObject (surface
->dc
,
270 if (!surface
->saved_dc_bitmap
)
273 if (bitmap_info
&& num_palette
> 2)
280 /* Windows bitmaps are padded to 32-bit (dword) boundaries */
282 case CAIRO_FORMAT_ARGB32
:
283 case CAIRO_FORMAT_RGB24
:
284 *rowstride_out
= 4 * width
;
287 case CAIRO_FORMAT_A8
:
288 *rowstride_out
= (width
+ 3) & ~3;
291 case CAIRO_FORMAT_A1
:
292 *rowstride_out
= ((width
+ 31) & ~31) / 8;
297 surface
->flags
= _cairo_win32_flags_for_dc (surface
->dc
);
299 return CAIRO_STATUS_SUCCESS
;
302 status
= _cairo_win32_print_gdi_error ("_create_dc_and_bitmap");
304 if (bitmap_info
&& num_palette
> 2)
307 if (surface
->saved_dc_bitmap
) {
308 SelectObject (surface
->dc
, surface
->saved_dc_bitmap
);
309 surface
->saved_dc_bitmap
= NULL
;
312 if (surface
->bitmap
) {
313 DeleteObject (surface
->bitmap
);
314 surface
->bitmap
= NULL
;
318 DeleteDC (surface
->dc
);
325 static cairo_surface_t
*
326 _cairo_win32_surface_create_for_dc (HDC original_dc
,
327 cairo_format_t format
,
331 cairo_status_t status
;
332 cairo_win32_surface_t
*surface
;
336 surface
= malloc (sizeof (cairo_win32_surface_t
));
338 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
340 status
= _create_dc_and_bitmap (surface
, original_dc
, format
,
346 surface
->image
= cairo_image_surface_create_for_data (bits
, format
,
347 width
, height
, rowstride
);
348 status
= surface
->image
->status
;
352 surface
->format
= format
;
354 surface
->clip_rect
.x
= 0;
355 surface
->clip_rect
.y
= 0;
356 surface
->clip_rect
.width
= width
;
357 surface
->clip_rect
.height
= height
;
359 surface
->initial_clip_rgn
= NULL
;
360 surface
->had_simple_clip
= FALSE
;
362 surface
->extents
= surface
->clip_rect
;
363 surface
->font_subsets
= NULL
;
365 _cairo_surface_init (&surface
->base
, &cairo_win32_surface_backend
,
366 _cairo_content_from_format (format
));
368 return &surface
->base
;
371 if (surface
->bitmap
) {
372 SelectObject (surface
->dc
, surface
->saved_dc_bitmap
);
373 DeleteObject (surface
->bitmap
);
374 DeleteDC (surface
->dc
);
378 return _cairo_surface_create_in_error (status
);
381 static cairo_surface_t
*
382 _cairo_win32_surface_create_similar_internal (void *abstract_src
,
383 cairo_content_t content
,
386 cairo_bool_t force_dib
)
388 cairo_win32_surface_t
*src
= abstract_src
;
389 cairo_format_t format
= _cairo_format_from_content (content
);
390 cairo_surface_t
*new_surf
= NULL
;
392 /* We force a DIB always if:
393 * - we need alpha; or
394 * - the parent is a DIB; or
395 * - the parent is for printing (because we don't care about the bit depth at that point)
397 * We also might end up with a DIB even if a DDB is requested if DDB creation failed
398 * due to out of memory.
401 (content
& CAIRO_CONTENT_ALPHA
) ||
402 src
->base
.backend
->type
== CAIRO_SURFACE_TYPE_WIN32_PRINTING
)
408 /* try to create a ddb */
409 new_surf
= cairo_win32_surface_create_with_ddb (src
->dc
, CAIRO_FORMAT_RGB24
, width
, height
);
411 if (new_surf
->status
!= CAIRO_STATUS_SUCCESS
)
415 if (new_surf
== NULL
) {
416 new_surf
= _cairo_win32_surface_create_for_dc (src
->dc
, format
, width
, height
);
423 _cairo_win32_surface_create_similar (void *abstract_src
,
424 cairo_content_t content
,
428 return _cairo_win32_surface_create_similar_internal (abstract_src
, content
, width
, height
, FALSE
);
432 _cairo_win32_surface_clone_similar (void *abstract_surface
,
433 cairo_surface_t
*src
,
434 cairo_content_t content
,
441 cairo_surface_t
**clone_out
)
443 cairo_content_t src_content
;
444 cairo_surface_t
*new_surface
;
445 cairo_status_t status
;
446 cairo_surface_pattern_t pattern
;
448 src_content
= src
->content
& content
;
450 _cairo_win32_surface_create_similar_internal (abstract_surface
,
454 if (new_surface
== NULL
)
455 return CAIRO_INT_STATUS_UNSUPPORTED
;
457 status
= new_surface
->status
;
461 _cairo_pattern_init_for_surface (&pattern
, src
);
463 status
= _cairo_surface_composite (CAIRO_OPERATOR_SOURCE
,
472 _cairo_pattern_fini (&pattern
.base
);
474 if (status
== CAIRO_STATUS_SUCCESS
) {
475 *clone_offset_x
= src_x
;
476 *clone_offset_y
= src_y
;
477 *clone_out
= new_surface
;
479 cairo_surface_destroy (new_surface
);
486 _cairo_win32_surface_finish (void *abstract_surface
)
488 cairo_win32_surface_t
*surface
= abstract_surface
;
491 cairo_surface_destroy (surface
->image
);
493 /* If we created the Bitmap and DC, destroy them */
494 if (surface
->bitmap
) {
495 SelectObject (surface
->dc
, surface
->saved_dc_bitmap
);
496 DeleteObject (surface
->bitmap
);
497 DeleteDC (surface
->dc
);
499 _cairo_win32_restore_initial_clip (surface
);
502 if (surface
->initial_clip_rgn
)
503 DeleteObject (surface
->initial_clip_rgn
);
505 if (surface
->font_subsets
!= NULL
)
506 _cairo_scaled_font_subsets_destroy (surface
->font_subsets
);
508 return CAIRO_STATUS_SUCCESS
;
511 static cairo_status_t
512 _cairo_win32_surface_get_subimage (cairo_win32_surface_t
*surface
,
517 cairo_win32_surface_t
**local_out
)
519 cairo_win32_surface_t
*local
;
520 cairo_int_status_t status
;
521 cairo_content_t content
= _cairo_content_from_format (surface
->format
);
524 (cairo_win32_surface_t
*) _cairo_win32_surface_create_similar_internal
525 (surface
, content
, width
, height
, TRUE
);
527 return CAIRO_INT_STATUS_UNSUPPORTED
;
528 if (local
->base
.status
)
529 return local
->base
.status
;
531 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
533 /* Only BitBlt if the source surface supports it. */
534 if ((surface
->flags
& CAIRO_WIN32_SURFACE_CAN_BITBLT
) &&
542 status
= CAIRO_STATUS_SUCCESS
;
546 /* If we failed here, most likely the source or dest doesn't
547 * support BitBlt/AlphaBlend (e.g. a printer).
548 * You can't reliably get bits from a printer DC, so just fill in
549 * the surface as white (common case for printing).
556 FillRect(local
->dc
, &r
, (HBRUSH
)GetStockObject(WHITE_BRUSH
));
561 return CAIRO_STATUS_SUCCESS
;
564 static cairo_status_t
565 _cairo_win32_surface_acquire_source_image (void *abstract_surface
,
566 cairo_image_surface_t
**image_out
,
569 cairo_win32_surface_t
*surface
= abstract_surface
;
570 cairo_win32_surface_t
*local
= NULL
;
571 cairo_status_t status
;
573 if (surface
->image
) {
574 *image_out
= (cairo_image_surface_t
*)surface
->image
;
577 return CAIRO_STATUS_SUCCESS
;
580 status
= _cairo_win32_surface_get_subimage (abstract_surface
, 0, 0,
581 surface
->extents
.width
,
582 surface
->extents
.height
, &local
);
586 *image_out
= (cairo_image_surface_t
*)local
->image
;
587 *image_extra
= local
;
589 return CAIRO_STATUS_SUCCESS
;
593 _cairo_win32_surface_release_source_image (void *abstract_surface
,
594 cairo_image_surface_t
*image
,
597 cairo_win32_surface_t
*local
= image_extra
;
600 cairo_surface_destroy ((cairo_surface_t
*)local
);
603 static cairo_status_t
604 _cairo_win32_surface_acquire_dest_image (void *abstract_surface
,
605 cairo_rectangle_int_t
*interest_rect
,
606 cairo_image_surface_t
**image_out
,
607 cairo_rectangle_int_t
*image_rect
,
610 cairo_win32_surface_t
*surface
= abstract_surface
;
611 cairo_win32_surface_t
*local
= NULL
;
612 cairo_status_t status
;
616 if (surface
->image
) {
621 image_rect
->width
= surface
->extents
.width
;
622 image_rect
->height
= surface
->extents
.height
;
624 *image_out
= (cairo_image_surface_t
*)surface
->image
;
627 return CAIRO_STATUS_SUCCESS
;
630 if (GetClipBox (surface
->dc
, &clip_box
) == ERROR
)
631 return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
636 y2
= clip_box
.bottom
;
638 if (interest_rect
->x
> x1
)
639 x1
= interest_rect
->x
;
640 if (interest_rect
->y
> y1
)
641 y1
= interest_rect
->y
;
642 if ((int) (interest_rect
->x
+ interest_rect
->width
) < x2
)
643 x2
= interest_rect
->x
+ interest_rect
->width
;
644 if ((int) (interest_rect
->y
+ interest_rect
->height
) < y2
)
645 y2
= interest_rect
->y
+ interest_rect
->height
;
647 if (x1
>= x2
|| y1
>= y2
) {
651 return CAIRO_STATUS_SUCCESS
;
654 status
= _cairo_win32_surface_get_subimage (abstract_surface
,
655 x1
, y1
, x2
- x1
, y2
- y1
,
660 *image_out
= (cairo_image_surface_t
*)local
->image
;
661 *image_extra
= local
;
665 image_rect
->width
= x2
- x1
;
666 image_rect
->height
= y2
- y1
;
668 return CAIRO_STATUS_SUCCESS
;
672 _cairo_win32_surface_release_dest_image (void *abstract_surface
,
673 cairo_rectangle_int_t
*interest_rect
,
674 cairo_image_surface_t
*image
,
675 cairo_rectangle_int_t
*image_rect
,
678 cairo_win32_surface_t
*surface
= abstract_surface
;
679 cairo_win32_surface_t
*local
= image_extra
;
684 if (!BitBlt (surface
->dc
,
685 image_rect
->x
, image_rect
->y
,
686 image_rect
->width
, image_rect
->height
,
690 _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image");
692 cairo_surface_destroy ((cairo_surface_t
*)local
);
695 #if !defined(AC_SRC_OVER)
696 #define AC_SRC_OVER 0x00
701 BYTE SourceConstantAlpha
;
707 /* for compatibility with VC++ 6 */
709 #define AC_SRC_ALPHA 0x01
712 typedef BOOL (WINAPI
*cairo_alpha_blend_func_t
) (HDC hdcDest
,
722 BLENDFUNCTION blendFunction
);
724 static cairo_int_status_t
725 _composite_alpha_blend (cairo_win32_surface_t
*dst
,
726 cairo_win32_surface_t
*src
,
737 static unsigned alpha_blend_checked
= FALSE
;
738 static cairo_alpha_blend_func_t alpha_blend
= NULL
;
740 BLENDFUNCTION blend_function
;
742 /* Check for AlphaBlend dynamically to allow compiling on
743 * MSVC 6 and use on older windows versions
745 if (!alpha_blend_checked
) {
748 os
.dwOSVersionInfoSize
= sizeof (os
);
751 /* If running on Win98, disable using AlphaBlend()
752 * to avoid Win98 AlphaBlend() bug */
753 if (VER_PLATFORM_WIN32_WINDOWS
!= os
.dwPlatformId
||
754 os
.dwMajorVersion
!= 4 || os
.dwMinorVersion
!= 10)
756 HMODULE msimg32_dll
= LoadLibraryW (L
"msimg32");
758 if (msimg32_dll
!= NULL
)
759 alpha_blend
= (cairo_alpha_blend_func_t
)GetProcAddress (msimg32_dll
,
763 alpha_blend_checked
= TRUE
;
766 if (alpha_blend
== NULL
)
767 return CAIRO_INT_STATUS_UNSUPPORTED
;
768 if (!(dst
->flags
& CAIRO_WIN32_SURFACE_CAN_ALPHABLEND
))
769 return CAIRO_INT_STATUS_UNSUPPORTED
;
770 if (src
->format
== CAIRO_FORMAT_RGB24
&& dst
->format
== CAIRO_FORMAT_ARGB32
)
771 return CAIRO_INT_STATUS_UNSUPPORTED
;
773 blend_function
.BlendOp
= AC_SRC_OVER
;
774 blend_function
.BlendFlags
= 0;
775 blend_function
.SourceConstantAlpha
= alpha
;
776 blend_function
.AlphaFormat
= (src
->format
== CAIRO_FORMAT_ARGB32
) ? AC_SRC_ALPHA
: 0;
778 if (!alpha_blend (dst
->dc
,
785 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(AlphaBlend)");
787 return CAIRO_STATUS_SUCCESS
;
790 static cairo_int_status_t
791 _cairo_win32_surface_composite_inner (cairo_win32_surface_t
*src
,
792 cairo_image_surface_t
*src_image
,
793 cairo_win32_surface_t
*dst
,
794 cairo_rectangle_int_t src_extents
,
795 cairo_rectangle_int_t src_r
,
796 cairo_rectangle_int_t dst_r
,
798 cairo_bool_t needs_alpha
,
799 cairo_bool_t needs_scale
)
801 /* Then do BitBlt, StretchDIBits, StretchBlt, AlphaBlend, or MaskBlt */
803 if (needs_alpha
|| needs_scale
)
804 return CAIRO_INT_STATUS_UNSUPPORTED
;
806 if (dst
->flags
& CAIRO_WIN32_SURFACE_CAN_STRETCHBLT
) {
808 bi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
809 bi
.bmiHeader
.biWidth
= src_image
->width
;
810 bi
.bmiHeader
.biHeight
= - src_image
->height
;
811 bi
.bmiHeader
.biSizeImage
= 0;
812 bi
.bmiHeader
.biXPelsPerMeter
= PELS_72DPI
;
813 bi
.bmiHeader
.biYPelsPerMeter
= PELS_72DPI
;
814 bi
.bmiHeader
.biPlanes
= 1;
815 bi
.bmiHeader
.biBitCount
= 32;
816 bi
.bmiHeader
.biCompression
= BI_RGB
;
817 bi
.bmiHeader
.biClrUsed
= 0;
818 bi
.bmiHeader
.biClrImportant
= 0;
820 /* StretchDIBits is broken with top-down dibs; you need to do some
821 * special munging to make the coordinate space work (basically,
822 * need to address everything based on the bottom left, instead of top left,
823 * and need to tell it to flip the resulting image.
825 * See http://blog.vlad1.com/archives/2006/10/26/134/ and comments.
827 if (!StretchDIBits (dst
->dc
,
829 dst_r
.x
, dst_r
.y
+ dst_r
.height
- 1,
830 dst_r
.width
, - (int) dst_r
.height
,
832 src_r
.x
, src_extents
.height
- src_r
.y
+ 1,
833 src_r
.width
, - (int) src_r
.height
,
838 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(StretchDIBits)");
840 } else if (!needs_alpha
) {
841 /* BitBlt or StretchBlt? */
842 if (!needs_scale
&& (dst
->flags
& CAIRO_WIN32_SURFACE_CAN_BITBLT
)) {
843 if (!BitBlt (dst
->dc
,
845 dst_r
.width
, dst_r
.height
,
849 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(BitBlt)");
850 } else if (dst
->flags
& CAIRO_WIN32_SURFACE_CAN_STRETCHBLT
) {
852 /* XXX check if we want HALFTONE, based on the src filter */
854 int oldmode
= SetStretchBltMode(dst
->dc
, HALFTONE
);
855 success
= StretchBlt(dst
->dc
,
857 dst_r
.width
, dst_r
.height
,
860 src_r
.width
, src_r
.height
,
862 SetStretchBltMode(dst
->dc
, oldmode
);
865 return _cairo_win32_print_gdi_error ("StretchBlt");
867 } else if (needs_alpha
&& !needs_scale
) {
868 return _composite_alpha_blend (dst
, src
, alpha
,
869 src_r
.x
, src_r
.y
, src_r
.width
, src_r
.height
,
870 dst_r
.x
, dst_r
.y
, dst_r
.width
, dst_r
.height
);
873 return CAIRO_STATUS_SUCCESS
;
876 /* from pixman-private.h */
877 #define MOD(a,b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b))
879 static cairo_int_status_t
880 _cairo_win32_surface_composite (cairo_operator_t op
,
881 const cairo_pattern_t
*pattern
,
882 const cairo_pattern_t
*mask_pattern
,
893 cairo_win32_surface_t
*dst
= abstract_dst
;
894 cairo_win32_surface_t
*src
;
895 cairo_surface_pattern_t
*src_surface_pattern
;
897 double scalex
, scaley
;
898 cairo_fixed_t x0_fixed
, y0_fixed
;
899 cairo_int_status_t status
;
901 cairo_bool_t needs_alpha
, needs_scale
, needs_repeat
;
902 cairo_image_surface_t
*src_image
= NULL
;
904 cairo_format_t src_format
;
905 cairo_rectangle_int_t src_extents
;
907 cairo_rectangle_int_t src_r
= { src_x
, src_y
, width
, height
};
908 cairo_rectangle_int_t dst_r
= { dst_x
, dst_y
, width
, height
};
910 #ifdef DEBUG_COMPOSITE
911 fprintf (stderr
, "+++ composite: %d %p %p %p [%d %d] [%d %d] [%d %d] %dx%d\n",
912 op
, pattern
, mask_pattern
, abstract_dst
, src_x
, src_y
, mask_x
, mask_y
, dst_x
, dst_y
, width
, height
);
915 /* If the destination can't do any of these, then
916 * we may as well give up, since this is what we'll
917 * look to for optimization.
919 if ((dst
->flags
& (CAIRO_WIN32_SURFACE_CAN_BITBLT
|
920 CAIRO_WIN32_SURFACE_CAN_ALPHABLEND
|
921 CAIRO_WIN32_SURFACE_CAN_STRETCHBLT
|
922 CAIRO_WIN32_SURFACE_CAN_STRETCHDIB
))
928 if (pattern
->type
!= CAIRO_PATTERN_TYPE_SURFACE
)
931 if (pattern
->extend
!= CAIRO_EXTEND_NONE
&&
932 pattern
->extend
!= CAIRO_EXTEND_REPEAT
)
936 /* FIXME: When we fully support RENDER style 4-channel
937 * masks we need to check r/g/b != 1.0.
939 if (mask_pattern
->type
!= CAIRO_PATTERN_TYPE_SOLID
)
940 return CAIRO_INT_STATUS_UNSUPPORTED
;
942 alpha
= ((cairo_solid_pattern_t
*)mask_pattern
)->color
.alpha_short
>> 8;
947 src_surface_pattern
= (cairo_surface_pattern_t
*)pattern
;
948 src
= (cairo_win32_surface_t
*)src_surface_pattern
->surface
;
950 if (src
->base
.type
== CAIRO_SURFACE_TYPE_IMAGE
&&
951 dst
->flags
& (CAIRO_WIN32_SURFACE_CAN_STRETCHDIB
))
953 /* In some very limited cases, we can use StretchDIBits to draw
954 * an image surface directly:
955 * - source is CAIRO_FORMAT_ARGB32
956 * - dest is CAIRO_FORMAT_ARGB32
958 * - operator is SOURCE or OVER
959 * - image stride is 4*width
961 src_image
= (cairo_image_surface_t
*) src
;
963 if (src_image
->format
!= CAIRO_FORMAT_RGB24
||
964 dst
->format
!= CAIRO_FORMAT_RGB24
||
966 (op
!= CAIRO_OPERATOR_SOURCE
&& op
!= CAIRO_OPERATOR_OVER
) ||
967 src_image
->stride
!= (src_image
->width
* 4))
972 src_format
= src_image
->format
;
975 src_extents
.width
= src_image
->width
;
976 src_extents
.height
= src_image
->height
;
977 } else if (src
->base
.backend
!= dst
->base
.backend
) {
980 src_format
= src
->format
;
981 src_extents
= src
->extents
;
985 #ifdef DEBUG_COMPOSITE
986 fprintf (stderr
, "Before check: src size: (%d %d) xy [%d %d] -> dst [%d %d %d %d] {srcmat %f %f %f %f}\n",
987 src_extents
.width
, src_extents
.height
,
989 dst_x
, dst_y
, width
, height
,
990 pattern
->matrix
.x0
, pattern
->matrix
.y0
, pattern
->matrix
.xx
, pattern
->matrix
.yy
);
993 /* We can only use GDI functions if the source and destination rectangles
994 * are on integer pixel boundaries. Figure that out here.
996 x0_fixed
= _cairo_fixed_from_double(pattern
->matrix
.x0
/ pattern
->matrix
.xx
);
997 y0_fixed
= _cairo_fixed_from_double(pattern
->matrix
.y0
/ pattern
->matrix
.yy
);
999 if (pattern
->matrix
.yx
!= 0.0 ||
1000 pattern
->matrix
.xy
!= 0.0 ||
1001 !_cairo_fixed_is_integer(x0_fixed
) ||
1002 !_cairo_fixed_is_integer(y0_fixed
))
1007 scalex
= pattern
->matrix
.xx
;
1008 scaley
= pattern
->matrix
.yy
;
1010 src_r
.x
+= _cairo_fixed_integer_part(x0_fixed
);
1011 src_r
.y
+= _cairo_fixed_integer_part(y0_fixed
);
1013 /* Success, right? */
1014 if (scalex
== 0.0 || scaley
== 0.0)
1015 return CAIRO_STATUS_SUCCESS
;
1017 if (scalex
!= 1.0 || scaley
!= 1.0)
1020 /* If the src coordinates are outside of the source surface bounds,
1021 * we have to fix them up, because this is an error for the GDI
1025 #ifdef DEBUG_COMPOSITE
1026 fprintf (stderr
, "before: [%d %d %d %d] -> [%d %d %d %d]\n",
1027 src_r
.x
, src_r
.y
, src_r
.width
, src_r
.height
,
1028 dst_r
.x
, dst_r
.y
, dst_r
.width
, dst_r
.height
);
1032 /* If the src recangle doesn't wholly lie within the src extents,
1033 * fudge things. We really need to do fixup on the unpainted
1034 * region -- e.g. the SOURCE operator is broken for areas outside
1035 * of the extents, because it won't clear that area to transparent
1039 if (pattern
->extend
!= CAIRO_EXTEND_REPEAT
) {
1040 needs_repeat
= FALSE
;
1042 /* If the src rect and the extents of the source image don't overlap at all,
1043 * we can't do anything useful here.
1045 if (src_r
.x
> src_extents
.width
|| src_r
.y
> src_extents
.height
||
1046 (src_r
.x
+ src_r
.width
) < 0 || (src_r
.y
+ src_r
.height
) < 0)
1048 if (op
== CAIRO_OPERATOR_OVER
)
1049 return CAIRO_STATUS_SUCCESS
;
1054 src_r
.width
+= src_r
.x
;
1057 dst_r
.width
+= src_r
.x
;
1062 src_r
.height
+= src_r
.y
;
1065 dst_r
.height
+= dst_r
.y
;
1069 if (src_r
.x
+ src_r
.width
> src_extents
.width
) {
1070 src_r
.width
= src_extents
.width
- src_r
.x
;
1071 dst_r
.width
= src_r
.width
;
1074 if (src_r
.y
+ src_r
.height
> src_extents
.height
) {
1075 src_r
.height
= src_extents
.height
- src_r
.y
;
1076 dst_r
.height
= src_r
.height
;
1079 needs_repeat
= TRUE
;
1083 * Operations that we can do:
1085 * RGB OVER RGB -> BitBlt (same as SOURCE)
1086 * RGB OVER ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA)
1087 * ARGB OVER ARGB -> AlphaBlend, with AC_SRC_ALPHA
1088 * ARGB OVER RGB -> AlphaBlend, with AC_SRC_ALPHA; we'll have junk in the dst A byte
1090 * RGB OVER RGB + mask -> AlphaBlend, no AC_SRC_ALPHA
1091 * RGB OVER ARGB + mask -> UNSUPPORTED
1092 * ARGB OVER ARGB + mask -> AlphaBlend, with AC_SRC_ALPHA
1093 * ARGB OVER RGB + mask -> AlphaBlend, with AC_SRC_ALPHA; junk in the dst A byte
1095 * RGB SOURCE RGB -> BitBlt
1096 * RGB SOURCE ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA)
1097 * ARGB SOURCE ARGB -> BitBlt
1098 * ARGB SOURCE RGB -> BitBlt
1100 * RGB SOURCE RGB + mask -> unsupported
1101 * RGB SOURCE ARGB + mask -> unsupported
1102 * ARGB SOURCE ARGB + mask -> unsupported
1103 * ARGB SOURCE RGB + mask -> unsupported
1107 * Figure out what action to take.
1109 if (op
== CAIRO_OPERATOR_OVER
) {
1111 return CAIRO_STATUS_SUCCESS
;
1113 if (src_format
== dst
->format
) {
1114 if (alpha
== 255 && src_format
== CAIRO_FORMAT_RGB24
) {
1115 needs_alpha
= FALSE
;
1119 } else if (src_format
== CAIRO_FORMAT_ARGB32
&&
1120 dst
->format
== CAIRO_FORMAT_RGB24
)
1126 } else if (alpha
== 255 && op
== CAIRO_OPERATOR_SOURCE
) {
1127 if ((src_format
== dst
->format
) ||
1128 (src_format
== CAIRO_FORMAT_ARGB32
&& dst
->format
== CAIRO_FORMAT_RGB24
))
1130 needs_alpha
= FALSE
;
1138 if (scalex
== 1.0 && scaley
== 1.0) {
1139 needs_scale
= FALSE
;
1141 /* Should never be reached until we turn StretchBlt back on */
1145 #ifdef DEBUG_COMPOSITE
1146 fprintf (stderr
, "action: [%d %d %d %d] -> [%d %d %d %d]\n",
1147 src_r
.x
, src_r
.y
, src_r
.width
, src_r
.height
,
1148 dst_r
.x
, dst_r
.y
, dst_r
.width
, dst_r
.height
);
1152 /* If we need to repeat, we turn the repeated blit into
1153 * a bunch of piece-by-piece blits.
1156 cairo_rectangle_int_t piece_src_r
, piece_dst_r
;
1157 uint32_t rendered_width
= 0, rendered_height
= 0;
1158 uint32_t to_render_height
, to_render_width
;
1159 int32_t piece_x
, piece_y
;
1160 int32_t src_start_x
= MOD(src_r
.x
, src_extents
.width
);
1161 int32_t src_start_y
= MOD(src_r
.y
, src_extents
.height
);
1166 /* If both the src and dest have an image, we may as well fall
1167 * back, because it will be faster than our separate blits.
1168 * Our blit code will be fastest when the src is a DDB and the
1169 * destination is a DDB.
1171 if ((src_image
|| src
->image
) && dst
->image
)
1174 /* If the src is not a bitmap but an on-screen (or unknown)
1175 * DC, chances are that fallback will be faster.
1177 if (src
->bitmap
== NULL
)
1180 /* If we can use PatBlt, just do so */
1181 if (!src_image
&& !needs_alpha
)
1185 POINT old_brush_origin
;
1187 /* Set up the brush with our bitmap */
1188 brush
= CreatePatternBrush (src
->bitmap
);
1190 /* SetBrushOrgEx sets the coordinates in the destination DC of where the
1191 * pattern should start.
1193 SetBrushOrgEx (dst
->dc
, dst_r
.x
- src_start_x
,
1194 dst_r
.y
- src_start_y
, &old_brush_origin
);
1196 old_brush
= SelectObject (dst
->dc
, brush
);
1198 PatBlt (dst
->dc
, dst_r
.x
, dst_r
.y
, dst_r
.width
, dst_r
.height
, PATCOPY
);
1200 /* Restore the old brush and pen */
1201 SetBrushOrgEx (dst
->dc
, old_brush_origin
.x
, old_brush_origin
.y
, NULL
);
1202 SelectObject (dst
->dc
, old_brush
);
1203 DeleteObject (brush
);
1205 return CAIRO_STATUS_SUCCESS
;
1208 /* If we were not able to use PatBlt, then manually expand out the blit */
1210 /* Arbitrary factor; we think that going through
1211 * fallback will be faster if we have to do more
1212 * than this amount of blits in either direction.
1214 if (dst_r
.width
/ src_extents
.width
> 5 ||
1215 dst_r
.height
/ src_extents
.height
> 5)
1218 for (rendered_height
= 0;
1219 rendered_height
< dst_r
.height
;
1220 rendered_height
+= to_render_height
)
1222 piece_y
= (src_start_y
+ rendered_height
) % src_extents
.height
;
1223 to_render_height
= src_extents
.height
- piece_y
;
1225 if (rendered_height
+ to_render_height
> dst_r
.height
)
1226 to_render_height
= dst_r
.height
- rendered_height
;
1228 for (rendered_width
= 0;
1229 rendered_width
< dst_r
.width
;
1230 rendered_width
+= to_render_width
)
1232 piece_x
= (src_start_x
+ rendered_width
) % src_extents
.width
;
1233 to_render_width
= src_extents
.width
- piece_x
;
1235 if (rendered_width
+ to_render_width
> dst_r
.width
)
1236 to_render_width
= dst_r
.width
- rendered_width
;
1238 piece_src_r
.x
= piece_x
;
1239 piece_src_r
.y
= piece_y
;
1240 piece_src_r
.width
= to_render_width
;
1241 piece_src_r
.height
= to_render_height
;
1243 piece_dst_r
.x
= dst_r
.x
+ rendered_width
;
1244 piece_dst_r
.y
= dst_r
.y
+ rendered_height
;
1245 piece_dst_r
.width
= to_render_width
;
1246 piece_dst_r
.height
= to_render_height
;
1248 status
= _cairo_win32_surface_composite_inner (src
, src_image
, dst
,
1249 src_extents
, piece_src_r
, piece_dst_r
,
1250 alpha
, needs_alpha
, needs_scale
);
1251 if (status
!= CAIRO_STATUS_SUCCESS
) {
1252 /* Uh oh. If something failed, and it's the first
1253 * piece, then we can jump to UNSUPPORTED.
1254 * Otherwise, this is bad times, because part of the
1255 * rendering was already done. */
1256 if (rendered_width
== 0 &&
1257 rendered_height
== 0)
1267 status
= _cairo_win32_surface_composite_inner (src
, src_image
, dst
,
1268 src_extents
, src_r
, dst_r
,
1269 alpha
, needs_alpha
, needs_scale
);
1272 if (status
== CAIRO_STATUS_SUCCESS
)
1276 /* Fall back to image surface directly, if this is a DIB surface */
1280 return dst
->image
->backend
->composite (op
, pattern
, mask_pattern
,
1288 return CAIRO_INT_STATUS_UNSUPPORTED
;
1291 /* This big function tells us how to optimize operators for the
1292 * case of solid destination and constant-alpha source
1294 * Note: This function needs revisiting if we add support for
1295 * super-luminescent colors (a == 0, r,g,b > 0)
1297 static enum { DO_CLEAR
, DO_SOURCE
, DO_NOTHING
, DO_UNSUPPORTED
}
1298 categorize_solid_dest_operator (cairo_operator_t op
,
1299 unsigned short alpha
)
1301 enum { SOURCE_TRANSPARENT
, SOURCE_LIGHT
, SOURCE_SOLID
, SOURCE_OTHER
} source
;
1303 if (alpha
>= 0xff00)
1304 source
= SOURCE_SOLID
;
1305 else if (alpha
< 0x100)
1306 source
= SOURCE_TRANSPARENT
;
1308 source
= SOURCE_OTHER
;
1311 case CAIRO_OPERATOR_CLEAR
: /* 0 0 */
1312 case CAIRO_OPERATOR_OUT
: /* 1 - Ab 0 */
1316 case CAIRO_OPERATOR_SOURCE
: /* 1 0 */
1317 case CAIRO_OPERATOR_IN
: /* Ab 0 */
1321 case CAIRO_OPERATOR_OVER
: /* 1 1 - Aa */
1322 case CAIRO_OPERATOR_ATOP
: /* Ab 1 - Aa */
1323 if (source
== SOURCE_SOLID
)
1325 else if (source
== SOURCE_TRANSPARENT
)
1328 return DO_UNSUPPORTED
;
1331 case CAIRO_OPERATOR_DEST_OUT
: /* 0 1 - Aa */
1332 case CAIRO_OPERATOR_XOR
: /* 1 - Ab 1 - Aa */
1333 if (source
== SOURCE_SOLID
)
1335 else if (source
== SOURCE_TRANSPARENT
)
1338 return DO_UNSUPPORTED
;
1341 case CAIRO_OPERATOR_DEST
: /* 0 1 */
1342 case CAIRO_OPERATOR_DEST_OVER
:/* 1 - Ab 1 */
1343 case CAIRO_OPERATOR_SATURATE
: /* min(1,(1-Ab)/Aa) 1 */
1347 case CAIRO_OPERATOR_DEST_IN
: /* 0 Aa */
1348 case CAIRO_OPERATOR_DEST_ATOP
:/* 1 - Ab Aa */
1349 if (source
== SOURCE_SOLID
)
1351 else if (source
== SOURCE_TRANSPARENT
)
1354 return DO_UNSUPPORTED
;
1357 case CAIRO_OPERATOR_ADD
: /* 1 1 */
1358 if (source
== SOURCE_TRANSPARENT
)
1361 return DO_UNSUPPORTED
;
1366 return DO_UNSUPPORTED
;
1369 static cairo_int_status_t
1370 _cairo_win32_surface_fill_rectangles (void *abstract_surface
,
1371 cairo_operator_t op
,
1372 const cairo_color_t
*color
,
1373 cairo_rectangle_int_t
*rects
,
1376 cairo_win32_surface_t
*surface
= abstract_surface
;
1377 cairo_status_t status
;
1382 /* XXXperf If it's not RGB24, we need to do a little more checking
1383 * to figure out when we can use GDI. We don't have that checking
1384 * anywhere at the moment, so just bail and use the fallback
1386 if (surface
->format
!= CAIRO_FORMAT_RGB24
)
1387 return CAIRO_INT_STATUS_UNSUPPORTED
;
1389 /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all
1390 * surfaces with alpha.)
1392 switch (categorize_solid_dest_operator (op
, color
->alpha_short
)) {
1394 new_color
= RGB (0, 0, 0);
1397 new_color
= RGB (color
->red_short
>> 8, color
->green_short
>> 8, color
->blue_short
>> 8);
1400 return CAIRO_STATUS_SUCCESS
;
1401 case DO_UNSUPPORTED
:
1403 return CAIRO_INT_STATUS_UNSUPPORTED
;
1406 new_brush
= CreateSolidBrush (new_color
);
1408 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1410 for (i
= 0; i
< num_rects
; i
++) {
1413 rect
.left
= rects
[i
].x
;
1414 rect
.top
= rects
[i
].y
;
1415 rect
.right
= rects
[i
].x
+ rects
[i
].width
;
1416 rect
.bottom
= rects
[i
].y
+ rects
[i
].height
;
1418 if (!FillRect (surface
->dc
, &rect
, new_brush
))
1422 DeleteObject (new_brush
);
1424 return CAIRO_STATUS_SUCCESS
;
1427 status
= _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1429 DeleteObject (new_brush
);
1434 static cairo_int_status_t
1435 _cairo_win32_surface_set_clip_region (void *abstract_surface
,
1436 cairo_region_t
*region
)
1438 cairo_win32_surface_t
*surface
= abstract_surface
;
1439 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
1441 /* If we are in-memory, then we set the clip on the image surface
1442 * as well as on the underlying GDI surface.
1444 if (surface
->image
) {
1445 unsigned int serial
;
1447 serial
= _cairo_surface_allocate_clip_serial (surface
->image
);
1448 status
= _cairo_surface_set_clip_region (surface
->image
, region
, serial
);
1453 /* The semantics we want is that any clip set by cairo combines
1454 * is intersected with the clip on device context that the
1455 * surface was created for. To implement this, we need to
1456 * save the original clip when first setting a clip on surface.
1459 /* Clear any clip set by cairo, return to the original first */
1460 status
= _cairo_win32_restore_initial_clip (surface
);
1462 /* Then combine any new region with it */
1464 cairo_rectangle_int_t extents
;
1471 cairo_rectangle_int_t rect0
;
1473 /* Create a GDI region for the cairo region */
1475 cairo_region_get_extents (region
, &extents
);
1476 num_rects
= cairo_region_num_rectangles (region
);
1479 cairo_region_get_rectangle (region
, 0, &rect0
);
1481 if (num_rects
== 1 &&
1484 rect0
.width
== surface
->extents
.width
&&
1485 rect0
.width
== surface
->extents
.height
)
1489 SelectClipRgn (surface
->dc
, NULL
);
1490 IntersectClipRect (surface
->dc
,
1493 rect0
.x
+ rect0
.width
,
1494 rect0
.y
+ rect0
.height
);
1496 /* XXX see notes in _cairo_win32_save_initial_clip --
1497 * this code will interact badly with a HDC which had an initial
1498 * world transform -- we should probably manually transform the
1499 * region rects, because SelectClipRgn takes device units, not
1500 * logical units (unlike IntersectClipRect).
1503 data_size
= sizeof (RGNDATAHEADER
) + num_rects
* sizeof (RECT
);
1504 data
= malloc (data_size
);
1506 return _cairo_error(CAIRO_STATUS_NO_MEMORY
);
1507 rects
= (RECT
*)data
->Buffer
;
1509 data
->rdh
.dwSize
= sizeof (RGNDATAHEADER
);
1510 data
->rdh
.iType
= RDH_RECTANGLES
;
1511 data
->rdh
.nCount
= num_rects
;
1512 data
->rdh
.nRgnSize
= num_rects
* sizeof (RECT
);
1513 data
->rdh
.rcBound
.left
= extents
.x
;
1514 data
->rdh
.rcBound
.top
= extents
.y
;
1515 data
->rdh
.rcBound
.right
= extents
.x
+ extents
.width
;
1516 data
->rdh
.rcBound
.bottom
= extents
.y
+ extents
.height
;
1518 for (i
= 0; i
< num_rects
; i
++) {
1519 cairo_rectangle_int_t rect
;
1521 cairo_region_get_rectangle (region
, i
, &rect
);
1523 rects
[i
].left
= rect
.x
;
1524 rects
[i
].top
= rect
.y
;
1525 rects
[i
].right
= rect
.x
+ rect
.width
;
1526 rects
[i
].bottom
= rect
.y
+ rect
.height
;
1529 gdi_region
= ExtCreateRegion (NULL
, data_size
, data
);
1533 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1535 /* AND the new region into our DC */
1536 if (ExtSelectClipRgn (surface
->dc
, gdi_region
, RGN_AND
) == ERROR
)
1537 status
= _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
1539 DeleteObject (gdi_region
);
1547 _cairo_win32_surface_get_extents (void *abstract_surface
,
1548 cairo_rectangle_int_t
*rectangle
)
1550 cairo_win32_surface_t
*surface
= abstract_surface
;
1552 *rectangle
= surface
->extents
;
1554 return CAIRO_STATUS_SUCCESS
;
1557 static cairo_status_t
1558 _cairo_win32_surface_flush (void *abstract_surface
)
1560 return _cairo_surface_reset_clip (abstract_surface
);
1563 #define STACK_GLYPH_SIZE 256
1566 _cairo_win32_surface_show_glyphs (void *surface
,
1567 cairo_operator_t op
,
1568 const cairo_pattern_t
*source
,
1569 cairo_glyph_t
*glyphs
,
1571 cairo_scaled_font_t
*scaled_font
,
1572 int *remaining_glyphs
,
1573 cairo_rectangle_int_t
*extents
)
1575 #if CAIRO_HAS_WIN32_FONT
1576 cairo_win32_surface_t
*dst
= surface
;
1578 WORD glyph_buf_stack
[STACK_GLYPH_SIZE
];
1579 WORD
*glyph_buf
= glyph_buf_stack
;
1580 int dxy_buf_stack
[2 * STACK_GLYPH_SIZE
];
1581 int *dxy_buf
= dxy_buf_stack
;
1583 BOOL win_result
= 0;
1586 cairo_solid_pattern_t
*solid_pattern
;
1589 cairo_matrix_t device_to_logical
;
1591 int start_x
, start_y
;
1592 double user_x
, user_y
;
1593 int logical_x
, logical_y
;
1594 unsigned int glyph_index_option
;
1596 /* We can only handle win32 fonts */
1597 if (cairo_scaled_font_get_type (scaled_font
) != CAIRO_FONT_TYPE_WIN32
)
1598 return CAIRO_INT_STATUS_UNSUPPORTED
;
1600 /* We can only handle opaque solid color sources */
1601 if (!_cairo_pattern_is_opaque_solid(source
))
1602 return CAIRO_INT_STATUS_UNSUPPORTED
;
1604 /* We can only handle operator SOURCE or OVER with the destination
1605 * having no alpha */
1606 if ((op
!= CAIRO_OPERATOR_SOURCE
&& op
!= CAIRO_OPERATOR_OVER
) ||
1607 (dst
->format
!= CAIRO_FORMAT_RGB24
))
1608 return CAIRO_INT_STATUS_UNSUPPORTED
;
1610 /* If we have a fallback mask clip set on the dst, we have
1611 * to go through the fallback path, but only if we're not
1612 * doing this for printing */
1613 if (dst
->base
.clip
&&
1614 !(dst
->flags
& CAIRO_WIN32_SURFACE_FOR_PRINTING
) &&
1615 (dst
->base
.clip
->mode
!= CAIRO_CLIP_MODE_REGION
||
1616 dst
->base
.clip
->surface
!= NULL
))
1617 return CAIRO_INT_STATUS_UNSUPPORTED
;
1619 solid_pattern
= (cairo_solid_pattern_t
*)source
;
1620 color
= RGB(((int)solid_pattern
->color
.red_short
) >> 8,
1621 ((int)solid_pattern
->color
.green_short
) >> 8,
1622 ((int)solid_pattern
->color
.blue_short
) >> 8);
1624 cairo_win32_scaled_font_get_device_to_logical(scaled_font
, &device_to_logical
);
1628 cairo_win32_scaled_font_select_font(scaled_font
, dst
->dc
);
1629 SetTextColor(dst
->dc
, color
);
1630 SetTextAlign(dst
->dc
, TA_BASELINE
| TA_LEFT
);
1631 SetBkMode(dst
->dc
, TRANSPARENT
);
1633 if (num_glyphs
> STACK_GLYPH_SIZE
) {
1634 glyph_buf
= (WORD
*) _cairo_malloc_ab (num_glyphs
, sizeof(WORD
));
1635 dxy_buf
= (int *) _cairo_malloc_abc (num_glyphs
, sizeof(int), 2);
1638 /* It is vital that dx values for dxy_buf are calculated from the delta of
1639 * _logical_ x coordinates (not user x coordinates) or else the sum of all
1640 * previous dx values may start to diverge from the current glyph's x
1641 * coordinate due to accumulated rounding error. As a result strings could
1642 * be painted shorter or longer than expected. */
1644 user_x
= glyphs
[0].x
;
1645 user_y
= glyphs
[0].y
;
1647 cairo_matrix_transform_point(&device_to_logical
,
1650 logical_x
= _cairo_lround (user_x
);
1651 logical_y
= _cairo_lround (user_y
);
1653 start_x
= logical_x
;
1654 start_y
= logical_y
;
1656 for (i
= 0, j
= 0; i
< num_glyphs
; ++i
, j
= 2 * i
) {
1657 glyph_buf
[i
] = (WORD
) glyphs
[i
].index
;
1658 if (i
== num_glyphs
- 1) {
1662 double next_user_x
= glyphs
[i
+1].x
;
1663 double next_user_y
= glyphs
[i
+1].y
;
1664 int next_logical_x
, next_logical_y
;
1666 cairo_matrix_transform_point(&device_to_logical
,
1667 &next_user_x
, &next_user_y
);
1669 next_logical_x
= _cairo_lround (next_user_x
);
1670 next_logical_y
= _cairo_lround (next_user_y
);
1672 dxy_buf
[j
] = _cairo_lround (next_logical_x
- logical_x
);
1673 dxy_buf
[j
+1] = _cairo_lround (next_logical_y
- logical_y
);
1675 logical_x
= next_logical_x
;
1676 logical_y
= next_logical_y
;
1680 /* Using glyph indices for a Type 1 font does not work on a
1681 * printer DC. The win32 printing surface will convert the the
1682 * glyph indices of Type 1 fonts to the unicode values.
1684 if ((dst
->flags
& CAIRO_WIN32_SURFACE_FOR_PRINTING
) &&
1685 _cairo_win32_scaled_font_is_type1 (scaled_font
))
1687 glyph_index_option
= 0;
1691 glyph_index_option
= ETO_GLYPH_INDEX
;
1694 win_result
= ExtTextOutW(dst
->dc
,
1697 glyph_index_option
| ETO_PDY
,
1703 _cairo_win32_print_gdi_error("_cairo_win32_surface_show_glyphs(ExtTextOutW failed)");
1706 RestoreDC(dst
->dc
, -1);
1708 if (glyph_buf
!= glyph_buf_stack
) {
1712 return (win_result
) ? CAIRO_STATUS_SUCCESS
: CAIRO_INT_STATUS_UNSUPPORTED
;
1714 return CAIRO_INT_STATUS_UNSUPPORTED
;
1718 #undef STACK_GLYPH_SIZE
1721 * cairo_win32_surface_create:
1722 * @hdc: the DC to create a surface for
1724 * Creates a cairo surface that targets the given DC. The DC will be
1725 * queried for its initial clip extents, and this will be used as the
1726 * size of the cairo surface. The resulting surface will always be of
1727 * format %CAIRO_FORMAT_RGB24; should you need another surface format,
1728 * you will need to create one through
1729 * cairo_win32_surface_create_with_dib().
1731 * Return value: the newly created surface
1734 cairo_win32_surface_create (HDC hdc
)
1736 cairo_win32_surface_t
*surface
;
1738 cairo_format_t format
;
1741 /* Assume that everything coming in as a HDC is RGB24 */
1742 format
= CAIRO_FORMAT_RGB24
;
1744 surface
= malloc (sizeof (cairo_win32_surface_t
));
1745 if (surface
== NULL
)
1746 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1748 if (_cairo_win32_save_initial_clip (hdc
, surface
) != CAIRO_STATUS_SUCCESS
) {
1750 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1753 surface
->image
= NULL
;
1754 surface
->format
= format
;
1757 surface
->bitmap
= NULL
;
1758 surface
->is_dib
= FALSE
;
1759 surface
->saved_dc_bitmap
= NULL
;
1760 surface
->brush
= NULL
;
1761 surface
->old_brush
= NULL
;
1762 surface
->font_subsets
= NULL
;
1764 GetClipBox(hdc
, &rect
);
1765 surface
->extents
.x
= rect
.left
;
1766 surface
->extents
.y
= rect
.top
;
1767 surface
->extents
.width
= rect
.right
- rect
.left
;
1768 surface
->extents
.height
= rect
.bottom
- rect
.top
;
1770 surface
->flags
= _cairo_win32_flags_for_dc (surface
->dc
);
1772 _cairo_surface_init (&surface
->base
, &cairo_win32_surface_backend
,
1773 _cairo_content_from_format (format
));
1775 return (cairo_surface_t
*)surface
;
1779 * cairo_win32_surface_create_with_dib:
1780 * @format: format of pixels in the surface to create
1781 * @width: width of the surface, in pixels
1782 * @height: height of the surface, in pixels
1784 * Creates a device-independent-bitmap surface not associated with
1785 * any particular existing surface or device context. The created
1786 * bitmap will be uninitialized.
1788 * Return value: the newly created surface
1793 cairo_win32_surface_create_with_dib (cairo_format_t format
,
1797 return _cairo_win32_surface_create_for_dc (NULL
, format
, width
, height
);
1801 * cairo_win32_surface_create_with_ddb:
1802 * @hdc: the DC to create a surface for
1803 * @format: format of pixels in the surface to create
1804 * @width: width of the surface, in pixels
1805 * @height: height of the surface, in pixels
1807 * Creates a device-independent-bitmap surface not associated with
1808 * any particular existing surface or device context. The created
1809 * bitmap will be uninitialized.
1811 * Return value: the newly created surface
1816 cairo_win32_surface_create_with_ddb (HDC hdc
,
1817 cairo_format_t format
,
1821 cairo_win32_surface_t
*new_surf
;
1823 HDC screen_dc
, ddb_dc
;
1824 HBITMAP saved_dc_bitmap
;
1826 if (format
!= CAIRO_FORMAT_RGB24
)
1827 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT
));
1828 /* XXX handle these eventually
1829 format != CAIRO_FORMAT_A8 ||
1830 format != CAIRO_FORMAT_A1)
1834 screen_dc
= GetDC (NULL
);
1840 ddb_dc
= CreateCompatibleDC (hdc
);
1841 if (ddb_dc
== NULL
) {
1842 new_surf
= (cairo_win32_surface_t
*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1846 ddb
= CreateCompatibleBitmap (hdc
, width
, height
);
1850 /* Note that if an app actually does hit this out of memory
1851 * condition, it's going to have lots of other issues, as
1852 * video memory is probably exhausted. However, it can often
1853 * continue using DIBs instead of DDBs.
1855 new_surf
= (cairo_win32_surface_t
*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1859 saved_dc_bitmap
= SelectObject (ddb_dc
, ddb
);
1861 new_surf
= (cairo_win32_surface_t
*) cairo_win32_surface_create (ddb_dc
);
1862 new_surf
->bitmap
= ddb
;
1863 new_surf
->saved_dc_bitmap
= saved_dc_bitmap
;
1864 new_surf
->is_dib
= FALSE
;
1868 ReleaseDC (NULL
, screen_dc
);
1870 return (cairo_surface_t
*) new_surf
;
1874 * _cairo_surface_is_win32:
1875 * @surface: a #cairo_surface_t
1877 * Checks if a surface is a win32 surface. This will
1878 * return False if this is a win32 printing surface; use
1879 * _cairo_surface_is_win32_printing() to check for that.
1881 * Return value: True if the surface is an win32 surface
1884 _cairo_surface_is_win32 (cairo_surface_t
*surface
)
1886 return surface
->backend
== &cairo_win32_surface_backend
;
1890 * cairo_win32_surface_get_dc
1891 * @surface: a #cairo_surface_t
1893 * Returns the HDC associated with this surface, or %NULL if none.
1894 * Also returns %NULL if the surface is not a win32 surface.
1896 * Return value: HDC or %NULL if no HDC available.
1901 cairo_win32_surface_get_dc (cairo_surface_t
*surface
)
1903 cairo_win32_surface_t
*winsurf
;
1905 if (_cairo_surface_is_win32 (surface
)){
1906 winsurf
= (cairo_win32_surface_t
*) surface
;
1911 if (_cairo_surface_is_paginated (surface
)) {
1912 cairo_surface_t
*target
;
1914 target
= _cairo_paginated_surface_get_target (surface
);
1916 if (_cairo_surface_is_win32_printing (target
)) {
1917 winsurf
= (cairo_win32_surface_t
*) target
;
1927 * cairo_win32_surface_get_image
1928 * @surface: a #cairo_surface_t
1930 * Returns a #cairo_surface_t image surface that refers to the same bits
1931 * as the DIB of the Win32 surface. If the passed-in win32 surface
1932 * is not a DIB surface, %NULL is returned.
1934 * Return value: a #cairo_surface_t (owned by the win32 #cairo_surface_t),
1935 * or %NULL if the win32 surface is not a DIB.
1940 cairo_win32_surface_get_image (cairo_surface_t
*surface
)
1942 if (!_cairo_surface_is_win32(surface
))
1945 return ((cairo_win32_surface_t
*)surface
)->image
;
1949 _cairo_win32_surface_is_similar (void *surface_a
,
1951 cairo_content_t content
)
1953 cairo_win32_surface_t
*a
= surface_a
;
1954 cairo_win32_surface_t
*b
= surface_b
;
1956 return a
->dc
== b
->dc
;
1959 static cairo_status_t
1960 _cairo_win32_surface_reset (void *abstract_surface
)
1962 cairo_win32_surface_t
*surface
= abstract_surface
;
1963 cairo_status_t status
;
1965 status
= _cairo_win32_surface_set_clip_region (surface
, NULL
);
1969 return CAIRO_STATUS_SUCCESS
;
1972 typedef struct _cairo_win32_surface_span_renderer
{
1973 cairo_span_renderer_t base
;
1975 cairo_operator_t op
;
1976 const cairo_pattern_t
*pattern
;
1977 cairo_antialias_t antialias
;
1979 cairo_image_surface_t
*mask
;
1980 cairo_win32_surface_t
*dst
;
1982 cairo_composite_rectangles_t composite_rectangles
;
1983 } cairo_win32_surface_span_renderer_t
;
1985 static cairo_status_t
1986 _cairo_win32_surface_span_renderer_render_row (
1987 void *abstract_renderer
,
1989 const cairo_half_open_span_t
*spans
,
1992 cairo_win32_surface_span_renderer_t
*renderer
= abstract_renderer
;
1993 _cairo_image_surface_span_render_row (y
, spans
, num_spans
, renderer
->mask
, &renderer
->composite_rectangles
);
1994 return CAIRO_STATUS_SUCCESS
;
1998 _cairo_win32_surface_span_renderer_destroy (void *abstract_renderer
)
2000 cairo_win32_surface_span_renderer_t
*renderer
= abstract_renderer
;
2001 if (!renderer
) return;
2003 if (renderer
->mask
!= NULL
)
2004 cairo_surface_destroy (&renderer
->mask
->base
);
2009 static cairo_status_t
2010 _cairo_win32_surface_span_renderer_finish (void *abstract_renderer
)
2012 cairo_win32_surface_span_renderer_t
*renderer
= abstract_renderer
;
2013 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
2015 if (renderer
->pattern
== NULL
|| renderer
->mask
== NULL
)
2016 return CAIRO_STATUS_SUCCESS
;
2018 status
= cairo_surface_status (&renderer
->mask
->base
);
2019 if (status
== CAIRO_STATUS_SUCCESS
) {
2020 cairo_composite_rectangles_t
*rects
= &renderer
->composite_rectangles
;
2021 cairo_win32_surface_t
*dst
= renderer
->dst
;
2022 cairo_pattern_t
*mask_pattern
= cairo_pattern_create_for_surface (&renderer
->mask
->base
);
2023 /* composite onto the image surface directly if we can */
2025 GdiFlush(); /* XXX: I'm not sure if this needed or not */
2027 status
= dst
->image
->backend
->composite (renderer
->op
,
2028 renderer
->pattern
, mask_pattern
, dst
->image
,
2031 0, 0, /* mask.x, mask.y */
2032 rects
->dst
.x
, rects
->dst
.y
,
2033 rects
->width
, rects
->height
);
2035 /* otherwise go through the fallback_composite path which
2036 * will do the appropriate surface acquisition */
2037 status
= _cairo_surface_fallback_composite (
2039 renderer
->pattern
, mask_pattern
, dst
,
2042 0, 0, /* mask.x, mask.y */
2043 rects
->dst
.x
, rects
->dst
.y
,
2044 rects
->width
, rects
->height
);
2046 cairo_pattern_destroy (mask_pattern
);
2049 if (status
!= CAIRO_STATUS_SUCCESS
)
2050 return _cairo_span_renderer_set_error (abstract_renderer
,
2052 return CAIRO_STATUS_SUCCESS
;
2056 _cairo_win32_surface_check_span_renderer (cairo_operator_t op
,
2057 const cairo_pattern_t
*pattern
,
2059 cairo_antialias_t antialias
,
2060 const cairo_composite_rectangles_t
*rects
)
2064 (void) abstract_dst
;
2070 static cairo_span_renderer_t
*
2071 _cairo_win32_surface_create_span_renderer (cairo_operator_t op
,
2072 const cairo_pattern_t
*pattern
,
2074 cairo_antialias_t antialias
,
2075 const cairo_composite_rectangles_t
*rects
)
2077 cairo_win32_surface_t
*dst
= abstract_dst
;
2078 cairo_win32_surface_span_renderer_t
*renderer
2079 = calloc(1, sizeof(*renderer
));
2080 cairo_status_t status
;
2081 int width
= rects
->width
;
2082 int height
= rects
->height
;
2084 if (renderer
== NULL
)
2085 return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY
);
2087 renderer
->base
.destroy
= _cairo_win32_surface_span_renderer_destroy
;
2088 renderer
->base
.finish
= _cairo_win32_surface_span_renderer_finish
;
2089 renderer
->base
.render_row
=
2090 _cairo_win32_surface_span_renderer_render_row
;
2092 renderer
->pattern
= pattern
;
2093 renderer
->antialias
= antialias
;
2094 renderer
->dst
= dst
;
2096 renderer
->composite_rectangles
= *rects
;
2098 /* TODO: support rendering to A1 surfaces (or: go add span
2099 * compositing to pixman.) */
2100 renderer
->mask
= (cairo_image_surface_t
*)
2101 cairo_image_surface_create (CAIRO_FORMAT_A8
,
2104 status
= cairo_surface_status (&renderer
->mask
->base
);
2106 if (status
!= CAIRO_STATUS_SUCCESS
) {
2107 _cairo_win32_surface_span_renderer_destroy (renderer
);
2108 return _cairo_span_renderer_create_in_error (status
);
2110 return &renderer
->base
;
2114 static const cairo_surface_backend_t cairo_win32_surface_backend
= {
2115 CAIRO_SURFACE_TYPE_WIN32
,
2116 _cairo_win32_surface_create_similar
,
2117 _cairo_win32_surface_finish
,
2118 _cairo_win32_surface_acquire_source_image
,
2119 _cairo_win32_surface_release_source_image
,
2120 _cairo_win32_surface_acquire_dest_image
,
2121 _cairo_win32_surface_release_dest_image
,
2122 _cairo_win32_surface_clone_similar
,
2123 _cairo_win32_surface_composite
,
2124 _cairo_win32_surface_fill_rectangles
,
2125 NULL
, /* composite_trapezoids */
2126 _cairo_win32_surface_create_span_renderer
,
2127 _cairo_win32_surface_check_span_renderer
,
2128 NULL
, /* copy_page */
2129 NULL
, /* show_page */
2130 _cairo_win32_surface_set_clip_region
,
2131 NULL
, /* intersect_clip_path */
2132 _cairo_win32_surface_get_extents
,
2133 NULL
, /* old_show_glyphs */
2134 NULL
, /* get_font_options */
2135 _cairo_win32_surface_flush
,
2136 NULL
, /* mark_dirty_rectangle */
2137 NULL
, /* scaled_font_fini */
2138 NULL
, /* scaled_glyph_fini */
2144 _cairo_win32_surface_show_glyphs
,
2146 NULL
, /* snapshot */
2147 _cairo_win32_surface_is_similar
,
2149 _cairo_win32_surface_reset
2154 * Win32 alpha-understanding functions
2156 * BitBlt - will copy full 32 bits from a 32bpp DIB to result
2157 * (so it's safe to use for ARGB32->ARGB32 SOURCE blits)
2158 * (but not safe going RGB24->ARGB32, if RGB24 is also represented
2159 * as a 32bpp DIB, since the alpha isn't discarded!)
2161 * AlphaBlend - if both the source and dest have alpha, even if AC_SRC_ALPHA isn't set,
2162 * it will still copy over the src alpha, because the SCA value (255) will be
2163 * multiplied by all the src components.
2168 _cairo_win32_save_initial_clip (HDC hdc
, cairo_win32_surface_t
*surface
)
2175 /* GetClipBox/GetClipRgn and friends interact badly with a world transform
2176 * set. GetClipBox returns values in logical (transformed) coordinates;
2177 * it's unclear what GetClipRgn returns, because the region is empty in the
2178 * case of a SIMPLEREGION clip, but I assume device (untransformed) coordinates.
2179 * Similarily, IntersectClipRect works in logical units, whereas SelectClipRgn
2180 * works in device units.
2182 * So, avoid the whole mess and get rid of the world transform
2183 * while we store our initial data and when we restore initial coordinates.
2185 * XXX we may need to modify x/y by the ViewportOrg or WindowOrg
2186 * here in GM_COMPATIBLE; unclear.
2188 gm
= GetGraphicsMode (hdc
);
2189 if (gm
== GM_ADVANCED
) {
2190 GetWorldTransform (hdc
, &saved_xform
);
2191 ModifyWorldTransform (hdc
, NULL
, MWT_IDENTITY
);
2194 clipBoxType
= GetClipBox (hdc
, &rect
);
2195 if (clipBoxType
== ERROR
) {
2196 _cairo_win32_print_gdi_error ("cairo_win32_surface_create");
2197 SetGraphicsMode (hdc
, gm
);
2198 /* XXX: Can we make a more reasonable guess at the error cause here? */
2199 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
2202 surface
->clip_rect
.x
= rect
.left
;
2203 surface
->clip_rect
.y
= rect
.top
;
2204 surface
->clip_rect
.width
= rect
.right
- rect
.left
;
2205 surface
->clip_rect
.height
= rect
.bottom
- rect
.top
;
2207 surface
->initial_clip_rgn
= NULL
;
2208 surface
->had_simple_clip
= FALSE
;
2210 if (clipBoxType
== COMPLEXREGION
) {
2211 surface
->initial_clip_rgn
= CreateRectRgn (0, 0, 0, 0);
2212 if (GetClipRgn (hdc
, surface
->initial_clip_rgn
) <= 0) {
2213 DeleteObject(surface
->initial_clip_rgn
);
2214 surface
->initial_clip_rgn
= NULL
;
2216 } else if (clipBoxType
== SIMPLEREGION
) {
2217 surface
->had_simple_clip
= TRUE
;
2220 if (gm
== GM_ADVANCED
)
2221 SetWorldTransform (hdc
, &saved_xform
);
2223 return CAIRO_STATUS_SUCCESS
;
2227 _cairo_win32_restore_initial_clip (cairo_win32_surface_t
*surface
)
2229 cairo_int_status_t status
= CAIRO_STATUS_SUCCESS
;
2232 int gm
= GetGraphicsMode (surface
->dc
);
2233 if (gm
== GM_ADVANCED
) {
2234 GetWorldTransform (surface
->dc
, &saved_xform
);
2235 ModifyWorldTransform (surface
->dc
, NULL
, MWT_IDENTITY
);
2238 /* initial_clip_rgn will either be a real region or NULL (which means reset to no clip region) */
2239 SelectClipRgn (surface
->dc
, surface
->initial_clip_rgn
);
2241 if (surface
->had_simple_clip
) {
2242 /* then if we had a simple clip, intersect */
2243 IntersectClipRect (surface
->dc
,
2244 surface
->clip_rect
.x
,
2245 surface
->clip_rect
.y
,
2246 surface
->clip_rect
.x
+ surface
->clip_rect
.width
,
2247 surface
->clip_rect
.y
+ surface
->clip_rect
.height
);
2250 if (gm
== GM_ADVANCED
)
2251 SetWorldTransform (surface
->dc
, &saved_xform
);
2257 _cairo_win32_debug_dump_hrgn (HRGN rgn
, char *header
)
2263 fprintf (stderr
, "%s\n", header
);
2266 fprintf (stderr
, " NULL\n");
2269 z
= GetRegionData(rgn
, 0, NULL
);
2270 rd
= (RGNDATA
*) malloc(z
);
2271 z
= GetRegionData(rgn
, z
, rd
);
2273 fprintf (stderr
, " %d rects, bounds: %d %d %d %d\n", rd
->rdh
.nCount
, rd
->rdh
.rcBound
.left
, rd
->rdh
.rcBound
.top
, rd
->rdh
.rcBound
.right
- rd
->rdh
.rcBound
.left
, rd
->rdh
.rcBound
.bottom
- rd
->rdh
.rcBound
.top
);
2275 for (z
= 0; z
< rd
->rdh
.nCount
; z
++) {
2276 RECT r
= ((RECT
*)rd
->Buffer
)[z
];
2277 fprintf (stderr
, " [%d]: [%d %d %d %d]\n", z
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
);