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
,
440 cairo_surface_t
**clone_out
)
442 cairo_content_t src_content
;
443 cairo_surface_t
*new_surface
;
444 cairo_status_t status
;
445 cairo_surface_pattern_t pattern
;
447 src_content
= cairo_surface_get_content(src
);
449 _cairo_win32_surface_create_similar_internal (abstract_surface
,
453 if (new_surface
== NULL
)
454 return CAIRO_INT_STATUS_UNSUPPORTED
;
456 status
= new_surface
->status
;
460 _cairo_pattern_init_for_surface (&pattern
, src
);
462 status
= _cairo_surface_composite (CAIRO_OPERATOR_SOURCE
,
471 _cairo_pattern_fini (&pattern
.base
);
473 if (status
== CAIRO_STATUS_SUCCESS
) {
474 *clone_offset_x
= src_x
;
475 *clone_offset_y
= src_y
;
476 *clone_out
= new_surface
;
478 cairo_surface_destroy (new_surface
);
485 _cairo_win32_surface_finish (void *abstract_surface
)
487 cairo_win32_surface_t
*surface
= abstract_surface
;
490 cairo_surface_destroy (surface
->image
);
492 /* If we created the Bitmap and DC, destroy them */
493 if (surface
->bitmap
) {
494 SelectObject (surface
->dc
, surface
->saved_dc_bitmap
);
495 DeleteObject (surface
->bitmap
);
496 DeleteDC (surface
->dc
);
498 _cairo_win32_restore_initial_clip (surface
);
501 if (surface
->initial_clip_rgn
)
502 DeleteObject (surface
->initial_clip_rgn
);
504 if (surface
->font_subsets
!= NULL
)
505 _cairo_scaled_font_subsets_destroy (surface
->font_subsets
);
507 return CAIRO_STATUS_SUCCESS
;
510 static cairo_status_t
511 _cairo_win32_surface_get_subimage (cairo_win32_surface_t
*surface
,
516 cairo_win32_surface_t
**local_out
)
518 cairo_win32_surface_t
*local
;
519 cairo_int_status_t status
;
520 cairo_content_t content
= _cairo_content_from_format (surface
->format
);
523 (cairo_win32_surface_t
*) _cairo_win32_surface_create_similar_internal
524 (surface
, content
, width
, height
, TRUE
);
526 return CAIRO_INT_STATUS_UNSUPPORTED
;
527 if (local
->base
.status
)
528 return local
->base
.status
;
530 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
532 /* Only BitBlt if the source surface supports it. */
533 if ((surface
->flags
& CAIRO_WIN32_SURFACE_CAN_BITBLT
) &&
541 status
= CAIRO_STATUS_SUCCESS
;
545 /* If we failed here, most likely the source or dest doesn't
546 * support BitBlt/AlphaBlend (e.g. a printer).
547 * You can't reliably get bits from a printer DC, so just fill in
548 * the surface as white (common case for printing).
555 FillRect(local
->dc
, &r
, (HBRUSH
)GetStockObject(WHITE_BRUSH
));
560 return CAIRO_STATUS_SUCCESS
;
563 static cairo_status_t
564 _cairo_win32_surface_acquire_source_image (void *abstract_surface
,
565 cairo_image_surface_t
**image_out
,
568 cairo_win32_surface_t
*surface
= abstract_surface
;
569 cairo_win32_surface_t
*local
= NULL
;
570 cairo_status_t status
;
572 if (surface
->image
) {
573 *image_out
= (cairo_image_surface_t
*)surface
->image
;
576 return CAIRO_STATUS_SUCCESS
;
579 status
= _cairo_win32_surface_get_subimage (abstract_surface
, 0, 0,
580 surface
->extents
.width
,
581 surface
->extents
.height
, &local
);
585 *image_out
= (cairo_image_surface_t
*)local
->image
;
586 *image_extra
= local
;
588 return CAIRO_STATUS_SUCCESS
;
592 _cairo_win32_surface_release_source_image (void *abstract_surface
,
593 cairo_image_surface_t
*image
,
596 cairo_win32_surface_t
*local
= image_extra
;
599 cairo_surface_destroy ((cairo_surface_t
*)local
);
602 static cairo_status_t
603 _cairo_win32_surface_acquire_dest_image (void *abstract_surface
,
604 cairo_rectangle_int_t
*interest_rect
,
605 cairo_image_surface_t
**image_out
,
606 cairo_rectangle_int_t
*image_rect
,
609 cairo_win32_surface_t
*surface
= abstract_surface
;
610 cairo_win32_surface_t
*local
= NULL
;
611 cairo_status_t status
;
615 if (surface
->image
) {
620 image_rect
->width
= surface
->extents
.width
;
621 image_rect
->height
= surface
->extents
.height
;
623 *image_out
= (cairo_image_surface_t
*)surface
->image
;
626 return CAIRO_STATUS_SUCCESS
;
629 if (GetClipBox (surface
->dc
, &clip_box
) == ERROR
)
630 return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
635 y2
= clip_box
.bottom
;
637 if (interest_rect
->x
> x1
)
638 x1
= interest_rect
->x
;
639 if (interest_rect
->y
> y1
)
640 y1
= interest_rect
->y
;
641 if ((int) (interest_rect
->x
+ interest_rect
->width
) < x2
)
642 x2
= interest_rect
->x
+ interest_rect
->width
;
643 if ((int) (interest_rect
->y
+ interest_rect
->height
) < y2
)
644 y2
= interest_rect
->y
+ interest_rect
->height
;
646 if (x1
>= x2
|| y1
>= y2
) {
650 return CAIRO_STATUS_SUCCESS
;
653 status
= _cairo_win32_surface_get_subimage (abstract_surface
,
654 x1
, y1
, x2
- x1
, y2
- y1
,
659 *image_out
= (cairo_image_surface_t
*)local
->image
;
660 *image_extra
= local
;
664 image_rect
->width
= x2
- x1
;
665 image_rect
->height
= y2
- y1
;
667 return CAIRO_STATUS_SUCCESS
;
671 _cairo_win32_surface_release_dest_image (void *abstract_surface
,
672 cairo_rectangle_int_t
*interest_rect
,
673 cairo_image_surface_t
*image
,
674 cairo_rectangle_int_t
*image_rect
,
677 cairo_win32_surface_t
*surface
= abstract_surface
;
678 cairo_win32_surface_t
*local
= image_extra
;
683 if (!BitBlt (surface
->dc
,
684 image_rect
->x
, image_rect
->y
,
685 image_rect
->width
, image_rect
->height
,
689 _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image");
691 cairo_surface_destroy ((cairo_surface_t
*)local
);
694 #if !defined(AC_SRC_OVER)
695 #define AC_SRC_OVER 0x00
700 BYTE SourceConstantAlpha
;
706 /* for compatibility with VC++ 6 */
708 #define AC_SRC_ALPHA 0x01
711 typedef BOOL (WINAPI
*cairo_alpha_blend_func_t
) (HDC hdcDest
,
721 BLENDFUNCTION blendFunction
);
723 static cairo_int_status_t
724 _composite_alpha_blend (cairo_win32_surface_t
*dst
,
725 cairo_win32_surface_t
*src
,
736 static unsigned alpha_blend_checked
= FALSE
;
737 static cairo_alpha_blend_func_t alpha_blend
= NULL
;
739 BLENDFUNCTION blend_function
;
741 /* Check for AlphaBlend dynamically to allow compiling on
742 * MSVC 6 and use on older windows versions
744 if (!alpha_blend_checked
) {
747 os
.dwOSVersionInfoSize
= sizeof (os
);
750 /* If running on Win98, disable using AlphaBlend()
751 * to avoid Win98 AlphaBlend() bug */
752 if (VER_PLATFORM_WIN32_WINDOWS
!= os
.dwPlatformId
||
753 os
.dwMajorVersion
!= 4 || os
.dwMinorVersion
!= 10)
755 HMODULE msimg32_dll
= LoadLibraryW (L
"msimg32");
757 if (msimg32_dll
!= NULL
)
758 alpha_blend
= (cairo_alpha_blend_func_t
)GetProcAddress (msimg32_dll
,
762 alpha_blend_checked
= TRUE
;
765 if (alpha_blend
== NULL
)
766 return CAIRO_INT_STATUS_UNSUPPORTED
;
767 if (!(dst
->flags
& CAIRO_WIN32_SURFACE_CAN_ALPHABLEND
))
768 return CAIRO_INT_STATUS_UNSUPPORTED
;
769 if (src
->format
== CAIRO_FORMAT_RGB24
&& dst
->format
== CAIRO_FORMAT_ARGB32
)
770 return CAIRO_INT_STATUS_UNSUPPORTED
;
772 blend_function
.BlendOp
= AC_SRC_OVER
;
773 blend_function
.BlendFlags
= 0;
774 blend_function
.SourceConstantAlpha
= alpha
;
775 blend_function
.AlphaFormat
= (src
->format
== CAIRO_FORMAT_ARGB32
) ? AC_SRC_ALPHA
: 0;
777 if (!alpha_blend (dst
->dc
,
784 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(AlphaBlend)");
786 return CAIRO_STATUS_SUCCESS
;
789 static cairo_int_status_t
790 _cairo_win32_surface_composite_inner (cairo_win32_surface_t
*src
,
791 cairo_image_surface_t
*src_image
,
792 cairo_win32_surface_t
*dst
,
793 cairo_rectangle_int_t src_extents
,
794 cairo_rectangle_int_t src_r
,
795 cairo_rectangle_int_t dst_r
,
797 cairo_bool_t needs_alpha
,
798 cairo_bool_t needs_scale
)
800 /* Then do BitBlt, StretchDIBits, StretchBlt, AlphaBlend, or MaskBlt */
802 if (needs_alpha
|| needs_scale
)
803 return CAIRO_INT_STATUS_UNSUPPORTED
;
805 if (dst
->flags
& CAIRO_WIN32_SURFACE_CAN_STRETCHBLT
) {
807 bi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
808 bi
.bmiHeader
.biWidth
= src_image
->width
;
809 bi
.bmiHeader
.biHeight
= - src_image
->height
;
810 bi
.bmiHeader
.biSizeImage
= 0;
811 bi
.bmiHeader
.biXPelsPerMeter
= PELS_72DPI
;
812 bi
.bmiHeader
.biYPelsPerMeter
= PELS_72DPI
;
813 bi
.bmiHeader
.biPlanes
= 1;
814 bi
.bmiHeader
.biBitCount
= 32;
815 bi
.bmiHeader
.biCompression
= BI_RGB
;
816 bi
.bmiHeader
.biClrUsed
= 0;
817 bi
.bmiHeader
.biClrImportant
= 0;
819 /* StretchDIBits is broken with top-down dibs; you need to do some
820 * special munging to make the coordinate space work (basically,
821 * need to address everything based on the bottom left, instead of top left,
822 * and need to tell it to flip the resulting image.
824 * See http://blog.vlad1.com/archives/2006/10/26/134/ and comments.
826 if (!StretchDIBits (dst
->dc
,
828 dst_r
.x
, dst_r
.y
+ dst_r
.height
- 1,
829 dst_r
.width
, - (int) dst_r
.height
,
831 src_r
.x
, src_extents
.height
- src_r
.y
+ 1,
832 src_r
.width
, - (int) src_r
.height
,
837 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(StretchDIBits)");
839 } else if (!needs_alpha
) {
840 /* BitBlt or StretchBlt? */
841 if (!needs_scale
&& (dst
->flags
& CAIRO_WIN32_SURFACE_CAN_BITBLT
)) {
842 if (!BitBlt (dst
->dc
,
844 dst_r
.width
, dst_r
.height
,
848 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(BitBlt)");
849 } else if (dst
->flags
& CAIRO_WIN32_SURFACE_CAN_STRETCHBLT
) {
851 /* XXX check if we want HALFTONE, based on the src filter */
853 int oldmode
= SetStretchBltMode(dst
->dc
, HALFTONE
);
854 success
= StretchBlt(dst
->dc
,
856 dst_r
.width
, dst_r
.height
,
859 src_r
.width
, src_r
.height
,
861 SetStretchBltMode(dst
->dc
, oldmode
);
864 return _cairo_win32_print_gdi_error ("StretchBlt");
866 } else if (needs_alpha
&& !needs_scale
) {
867 return _composite_alpha_blend (dst
, src
, alpha
,
868 src_r
.x
, src_r
.y
, src_r
.width
, src_r
.height
,
869 dst_r
.x
, dst_r
.y
, dst_r
.width
, dst_r
.height
);
872 return CAIRO_STATUS_SUCCESS
;
875 static cairo_int_status_t
876 _cairo_win32_surface_composite (cairo_operator_t op
,
877 cairo_pattern_t
*pattern
,
878 cairo_pattern_t
*mask_pattern
,
889 cairo_win32_surface_t
*dst
= abstract_dst
;
890 cairo_win32_surface_t
*src
;
891 cairo_surface_pattern_t
*src_surface_pattern
;
893 double scalex
, scaley
;
894 cairo_fixed_t x0_fixed
, y0_fixed
;
895 cairo_int_status_t status
;
897 cairo_bool_t needs_alpha
, needs_scale
, needs_repeat
;
898 cairo_image_surface_t
*src_image
= NULL
;
900 cairo_format_t src_format
;
901 cairo_rectangle_int_t src_extents
;
903 cairo_rectangle_int_t src_r
= { src_x
, src_y
, width
, height
};
904 cairo_rectangle_int_t dst_r
= { dst_x
, dst_y
, width
, height
};
906 #ifdef DEBUG_COMPOSITE
907 fprintf (stderr
, "+++ composite: %d %p %p %p [%d %d] [%d %d] [%d %d] %dx%d\n",
908 op
, pattern
, mask_pattern
, abstract_dst
, src_x
, src_y
, mask_x
, mask_y
, dst_x
, dst_y
, width
, height
);
911 /* If the destination can't do any of these, then
912 * we may as well give up, since this is what we'll
913 * look to for optimization.
915 if ((dst
->flags
& (CAIRO_WIN32_SURFACE_CAN_BITBLT
|
916 CAIRO_WIN32_SURFACE_CAN_ALPHABLEND
|
917 CAIRO_WIN32_SURFACE_CAN_STRETCHBLT
|
918 CAIRO_WIN32_SURFACE_CAN_STRETCHDIB
))
924 if (pattern
->type
!= CAIRO_PATTERN_TYPE_SURFACE
)
927 if (pattern
->extend
!= CAIRO_EXTEND_NONE
&&
928 pattern
->extend
!= CAIRO_EXTEND_REPEAT
)
932 /* FIXME: When we fully support RENDER style 4-channel
933 * masks we need to check r/g/b != 1.0.
935 if (mask_pattern
->type
!= CAIRO_PATTERN_TYPE_SOLID
)
936 return CAIRO_INT_STATUS_UNSUPPORTED
;
938 alpha
= ((cairo_solid_pattern_t
*)mask_pattern
)->color
.alpha_short
>> 8;
943 src_surface_pattern
= (cairo_surface_pattern_t
*)pattern
;
944 src
= (cairo_win32_surface_t
*)src_surface_pattern
->surface
;
946 if (src
->base
.type
== CAIRO_SURFACE_TYPE_IMAGE
&&
947 dst
->flags
& (CAIRO_WIN32_SURFACE_CAN_STRETCHDIB
))
949 /* In some very limited cases, we can use StretchDIBits to draw
950 * an image surface directly:
951 * - source is CAIRO_FORMAT_ARGB32
952 * - dest is CAIRO_FORMAT_ARGB32
954 * - operator is SOURCE or OVER
955 * - image stride is 4*width
957 src_image
= (cairo_image_surface_t
*) src
;
959 if (src_image
->format
!= CAIRO_FORMAT_RGB24
||
960 dst
->format
!= CAIRO_FORMAT_RGB24
||
962 (op
!= CAIRO_OPERATOR_SOURCE
&& op
!= CAIRO_OPERATOR_OVER
) ||
963 src_image
->stride
!= (src_image
->width
* 4))
968 src_format
= src_image
->format
;
971 src_extents
.width
= src_image
->width
;
972 src_extents
.height
= src_image
->height
;
973 } else if (src
->base
.backend
!= dst
->base
.backend
) {
976 src_format
= src
->format
;
977 src_extents
= src
->extents
;
981 #ifdef DEBUG_COMPOSITE
982 fprintf (stderr
, "Before check: src size: (%d %d) xy [%d %d] -> dst [%d %d %d %d] {srcmat %f %f %f %f}\n",
983 src_extents
.width
, src_extents
.height
,
985 dst_x
, dst_y
, width
, height
,
986 pattern
->matrix
.x0
, pattern
->matrix
.y0
, pattern
->matrix
.xx
, pattern
->matrix
.yy
);
989 /* We can only use GDI functions if the source and destination rectangles
990 * are on integer pixel boundaries. Figure that out here.
992 x0_fixed
= _cairo_fixed_from_double(pattern
->matrix
.x0
/ pattern
->matrix
.xx
);
993 y0_fixed
= _cairo_fixed_from_double(pattern
->matrix
.y0
/ pattern
->matrix
.yy
);
995 if (pattern
->matrix
.yx
!= 0.0 ||
996 pattern
->matrix
.xy
!= 0.0 ||
997 !_cairo_fixed_is_integer(x0_fixed
) ||
998 !_cairo_fixed_is_integer(y0_fixed
))
1003 scalex
= pattern
->matrix
.xx
;
1004 scaley
= pattern
->matrix
.yy
;
1006 src_r
.x
+= _cairo_fixed_integer_part(x0_fixed
);
1007 src_r
.y
+= _cairo_fixed_integer_part(y0_fixed
);
1009 /* Success, right? */
1010 if (scalex
== 0.0 || scaley
== 0.0)
1011 return CAIRO_STATUS_SUCCESS
;
1013 if (scalex
!= 1.0 || scaley
!= 1.0)
1016 /* If the src coordinates are outside of the source surface bounds,
1017 * we have to fix them up, because this is an error for the GDI
1021 #ifdef DEBUG_COMPOSITE
1022 fprintf (stderr
, "before: [%d %d %d %d] -> [%d %d %d %d]\n",
1023 src_r
.x
, src_r
.y
, src_r
.width
, src_r
.height
,
1024 dst_r
.x
, dst_r
.y
, dst_r
.width
, dst_r
.height
);
1028 /* If the src recangle doesn't wholly lie within the src extents,
1029 * fudge things. We really need to do fixup on the unpainted
1030 * region -- e.g. the SOURCE operator is broken for areas outside
1031 * of the extents, because it won't clear that area to transparent
1035 if (pattern
->extend
!= CAIRO_EXTEND_REPEAT
) {
1036 needs_repeat
= FALSE
;
1038 /* If the src rect and the extents of the source image don't overlap at all,
1039 * we can't do anything useful here.
1041 if (src_r
.x
> src_extents
.width
|| src_r
.y
> src_extents
.height
||
1042 (src_r
.x
+ src_r
.width
) < 0 || (src_r
.y
+ src_r
.height
) < 0)
1044 if (op
== CAIRO_OPERATOR_OVER
)
1045 return CAIRO_STATUS_SUCCESS
;
1050 src_r
.width
+= src_r
.x
;
1053 dst_r
.width
+= src_r
.x
;
1058 src_r
.height
+= src_r
.y
;
1061 dst_r
.height
+= dst_r
.y
;
1065 if (src_r
.x
+ src_r
.width
> src_extents
.width
) {
1066 src_r
.width
= src_extents
.width
- src_r
.x
;
1067 dst_r
.width
= src_r
.width
;
1070 if (src_r
.y
+ src_r
.height
> src_extents
.height
) {
1071 src_r
.height
= src_extents
.height
- src_r
.y
;
1072 dst_r
.height
= src_r
.height
;
1075 needs_repeat
= TRUE
;
1079 * Operations that we can do:
1081 * RGB OVER RGB -> BitBlt (same as SOURCE)
1082 * RGB OVER ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA)
1083 * ARGB OVER ARGB -> AlphaBlend, with AC_SRC_ALPHA
1084 * ARGB OVER RGB -> AlphaBlend, with AC_SRC_ALPHA; we'll have junk in the dst A byte
1086 * RGB OVER RGB + mask -> AlphaBlend, no AC_SRC_ALPHA
1087 * RGB OVER ARGB + mask -> UNSUPPORTED
1088 * ARGB OVER ARGB + mask -> AlphaBlend, with AC_SRC_ALPHA
1089 * ARGB OVER RGB + mask -> AlphaBlend, with AC_SRC_ALPHA; junk in the dst A byte
1091 * RGB SOURCE RGB -> BitBlt
1092 * RGB SOURCE ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA)
1093 * ARGB SOURCE ARGB -> BitBlt
1094 * ARGB SOURCE RGB -> BitBlt
1096 * RGB SOURCE RGB + mask -> unsupported
1097 * RGB SOURCE ARGB + mask -> unsupported
1098 * ARGB SOURCE ARGB + mask -> unsupported
1099 * ARGB SOURCE RGB + mask -> unsupported
1103 * Figure out what action to take.
1105 if (op
== CAIRO_OPERATOR_OVER
) {
1107 return CAIRO_STATUS_SUCCESS
;
1109 if (src_format
== dst
->format
) {
1110 if (alpha
== 255 && src_format
== CAIRO_FORMAT_RGB24
) {
1111 needs_alpha
= FALSE
;
1115 } else if (src_format
== CAIRO_FORMAT_ARGB32
&&
1116 dst
->format
== CAIRO_FORMAT_RGB24
)
1122 } else if (alpha
== 255 && op
== CAIRO_OPERATOR_SOURCE
) {
1123 if ((src_format
== dst
->format
) ||
1124 (src_format
== CAIRO_FORMAT_ARGB32
&& dst
->format
== CAIRO_FORMAT_RGB24
))
1126 needs_alpha
= FALSE
;
1134 if (scalex
== 1.0 && scaley
== 1.0) {
1135 needs_scale
= FALSE
;
1137 /* Should never be reached until we turn StretchBlt back on */
1141 #ifdef DEBUG_COMPOSITE
1142 fprintf (stderr
, "action: [%d %d %d %d] -> [%d %d %d %d]\n",
1143 src_r
.x
, src_r
.y
, src_r
.width
, src_r
.height
,
1144 dst_r
.x
, dst_r
.y
, dst_r
.width
, dst_r
.height
);
1148 /* If we need to repeat, we turn the repeated blit into
1149 * a bunch of piece-by-piece blits.
1152 cairo_rectangle_int_t piece_src_r
, piece_dst_r
;
1153 uint32_t rendered_width
= 0, rendered_height
= 0;
1154 uint32_t to_render_height
, to_render_width
;
1155 int32_t piece_x
, piece_y
;
1156 int32_t src_start_x
= src_r
.x
% src_extents
.width
;
1157 int32_t src_start_y
= src_r
.y
% src_extents
.height
;
1162 /* If both the src and dest have an image, we may as well fall
1163 * back, because it will be faster than our separate blits.
1164 * Our blit code will be fastest when the src is a DDB and the
1165 * destination is a DDB.
1167 if ((src_image
|| src
->image
) && dst
->image
)
1170 /* If the src is not a bitmap but an on-screen (or unknown)
1171 * DC, chances are that fallback will be faster.
1173 if (src
->bitmap
== NULL
)
1176 /* If we can use PatBlt, just do so */
1177 if (!src_image
&& !needs_alpha
)
1181 POINT old_brush_origin
;
1183 /* Set up the brush with our bitmap */
1184 brush
= CreatePatternBrush (src
->bitmap
);
1186 /* SetBrushOrgEx sets the coordinates in the destination DC of where the
1187 * pattern should start.
1189 SetBrushOrgEx (dst
->dc
, dst_r
.x
- src_start_x
,
1190 dst_r
.y
- src_start_y
, &old_brush_origin
);
1192 old_brush
= SelectObject (dst
->dc
, brush
);
1194 PatBlt (dst
->dc
, dst_r
.x
, dst_r
.y
, dst_r
.width
, dst_r
.height
, PATCOPY
);
1196 /* Restore the old brush and pen */
1197 SetBrushOrgEx (dst
->dc
, old_brush_origin
.x
, old_brush_origin
.y
, NULL
);
1198 SelectObject (dst
->dc
, old_brush
);
1199 DeleteObject (brush
);
1201 return CAIRO_STATUS_SUCCESS
;
1204 /* If we were not able to use PatBlt, then manually expand out the blit */
1206 /* Arbitrary factor; we think that going through
1207 * fallback will be faster if we have to do more
1208 * than this amount of blits in either direction.
1210 if (dst_r
.width
/ src_extents
.width
> 5 ||
1211 dst_r
.height
/ src_extents
.height
> 5)
1214 for (rendered_height
= 0;
1215 rendered_height
< dst_r
.height
;
1216 rendered_height
+= to_render_height
)
1218 piece_y
= (src_start_y
+ rendered_height
) % src_extents
.height
;
1219 to_render_height
= src_extents
.height
- piece_y
;
1221 if (rendered_height
+ to_render_height
> dst_r
.height
)
1222 to_render_height
= dst_r
.height
- rendered_height
;
1224 for (rendered_width
= 0;
1225 rendered_width
< dst_r
.width
;
1226 rendered_width
+= to_render_width
)
1228 piece_x
= (src_start_x
+ rendered_width
) % src_extents
.width
;
1229 to_render_width
= src_extents
.width
- piece_x
;
1231 if (rendered_width
+ to_render_width
> dst_r
.width
)
1232 to_render_width
= dst_r
.width
- rendered_width
;
1234 piece_src_r
.x
= piece_x
;
1235 piece_src_r
.y
= piece_y
;
1236 piece_src_r
.width
= to_render_width
;
1237 piece_src_r
.height
= to_render_height
;
1239 piece_dst_r
.x
= dst_r
.x
+ rendered_width
;
1240 piece_dst_r
.y
= dst_r
.y
+ rendered_height
;
1241 piece_dst_r
.width
= to_render_width
;
1242 piece_dst_r
.height
= to_render_height
;
1244 status
= _cairo_win32_surface_composite_inner (src
, src_image
, dst
,
1245 src_extents
, piece_src_r
, piece_dst_r
,
1246 alpha
, needs_alpha
, needs_scale
);
1247 if (status
!= CAIRO_STATUS_SUCCESS
) {
1248 /* Uh oh. If something failed, and it's the first
1249 * piece, then we can jump to UNSUPPORTED.
1250 * Otherwise, this is bad times, because part of the
1251 * rendering was already done. */
1252 if (rendered_width
== 0 &&
1253 rendered_height
== 0)
1263 status
= _cairo_win32_surface_composite_inner (src
, src_image
, dst
,
1264 src_extents
, src_r
, dst_r
,
1265 alpha
, needs_alpha
, needs_scale
);
1268 if (status
== CAIRO_STATUS_SUCCESS
)
1272 /* Fall back to image surface directly, if this is a DIB surface */
1276 return dst
->image
->backend
->composite (op
, pattern
, mask_pattern
,
1284 return CAIRO_INT_STATUS_UNSUPPORTED
;
1287 /* This big function tells us how to optimize operators for the
1288 * case of solid destination and constant-alpha source
1290 * Note: This function needs revisiting if we add support for
1291 * super-luminescent colors (a == 0, r,g,b > 0)
1293 static enum { DO_CLEAR
, DO_SOURCE
, DO_NOTHING
, DO_UNSUPPORTED
}
1294 categorize_solid_dest_operator (cairo_operator_t op
,
1295 unsigned short alpha
)
1297 enum { SOURCE_TRANSPARENT
, SOURCE_LIGHT
, SOURCE_SOLID
, SOURCE_OTHER
} source
;
1299 if (alpha
>= 0xff00)
1300 source
= SOURCE_SOLID
;
1301 else if (alpha
< 0x100)
1302 source
= SOURCE_TRANSPARENT
;
1304 source
= SOURCE_OTHER
;
1307 case CAIRO_OPERATOR_CLEAR
: /* 0 0 */
1308 case CAIRO_OPERATOR_OUT
: /* 1 - Ab 0 */
1312 case CAIRO_OPERATOR_SOURCE
: /* 1 0 */
1313 case CAIRO_OPERATOR_IN
: /* Ab 0 */
1317 case CAIRO_OPERATOR_OVER
: /* 1 1 - Aa */
1318 case CAIRO_OPERATOR_ATOP
: /* Ab 1 - Aa */
1319 if (source
== SOURCE_SOLID
)
1321 else if (source
== SOURCE_TRANSPARENT
)
1324 return DO_UNSUPPORTED
;
1327 case CAIRO_OPERATOR_DEST_OUT
: /* 0 1 - Aa */
1328 case CAIRO_OPERATOR_XOR
: /* 1 - Ab 1 - Aa */
1329 if (source
== SOURCE_SOLID
)
1331 else if (source
== SOURCE_TRANSPARENT
)
1334 return DO_UNSUPPORTED
;
1337 case CAIRO_OPERATOR_DEST
: /* 0 1 */
1338 case CAIRO_OPERATOR_DEST_OVER
:/* 1 - Ab 1 */
1339 case CAIRO_OPERATOR_SATURATE
: /* min(1,(1-Ab)/Aa) 1 */
1343 case CAIRO_OPERATOR_DEST_IN
: /* 0 Aa */
1344 case CAIRO_OPERATOR_DEST_ATOP
:/* 1 - Ab Aa */
1345 if (source
== SOURCE_SOLID
)
1347 else if (source
== SOURCE_TRANSPARENT
)
1350 return DO_UNSUPPORTED
;
1353 case CAIRO_OPERATOR_ADD
: /* 1 1 */
1354 if (source
== SOURCE_TRANSPARENT
)
1357 return DO_UNSUPPORTED
;
1362 return DO_UNSUPPORTED
;
1365 static cairo_int_status_t
1366 _cairo_win32_surface_fill_rectangles (void *abstract_surface
,
1367 cairo_operator_t op
,
1368 const cairo_color_t
*color
,
1369 cairo_rectangle_int_t
*rects
,
1372 cairo_win32_surface_t
*surface
= abstract_surface
;
1373 cairo_status_t status
;
1378 /* XXXperf If it's not RGB24, we need to do a little more checking
1379 * to figure out when we can use GDI. We don't have that checking
1380 * anywhere at the moment, so just bail and use the fallback
1382 if (surface
->format
!= CAIRO_FORMAT_RGB24
)
1383 return CAIRO_INT_STATUS_UNSUPPORTED
;
1385 /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all
1386 * surfaces with alpha.)
1388 switch (categorize_solid_dest_operator (op
, color
->alpha_short
)) {
1390 new_color
= RGB (0, 0, 0);
1393 new_color
= RGB (color
->red_short
>> 8, color
->green_short
>> 8, color
->blue_short
>> 8);
1396 return CAIRO_STATUS_SUCCESS
;
1397 case DO_UNSUPPORTED
:
1399 return CAIRO_INT_STATUS_UNSUPPORTED
;
1402 new_brush
= CreateSolidBrush (new_color
);
1404 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1406 for (i
= 0; i
< num_rects
; i
++) {
1409 rect
.left
= rects
[i
].x
;
1410 rect
.top
= rects
[i
].y
;
1411 rect
.right
= rects
[i
].x
+ rects
[i
].width
;
1412 rect
.bottom
= rects
[i
].y
+ rects
[i
].height
;
1414 if (!FillRect (surface
->dc
, &rect
, new_brush
))
1418 DeleteObject (new_brush
);
1420 return CAIRO_STATUS_SUCCESS
;
1423 status
= _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1425 DeleteObject (new_brush
);
1430 static cairo_int_status_t
1431 _cairo_win32_surface_set_clip_region (void *abstract_surface
,
1432 cairo_region_t
*region
)
1434 cairo_win32_surface_t
*surface
= abstract_surface
;
1435 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
1437 /* If we are in-memory, then we set the clip on the image surface
1438 * as well as on the underlying GDI surface.
1440 if (surface
->image
) {
1441 unsigned int serial
;
1443 serial
= _cairo_surface_allocate_clip_serial (surface
->image
);
1444 status
= _cairo_surface_set_clip_region (surface
->image
, region
, serial
);
1449 /* The semantics we want is that any clip set by cairo combines
1450 * is intersected with the clip on device context that the
1451 * surface was created for. To implement this, we need to
1452 * save the original clip when first setting a clip on surface.
1455 /* Clear any clip set by cairo, return to the original first */
1456 status
= _cairo_win32_restore_initial_clip (surface
);
1458 /* Then combine any new region with it */
1460 cairo_rectangle_int_t extents
;
1461 cairo_box_int_t
*boxes
;
1469 /* Create a GDI region for the cairo region */
1471 _cairo_region_get_extents (region
, &extents
);
1472 status
= _cairo_region_get_boxes (region
, &num_boxes
, &boxes
);
1476 if (num_boxes
== 1 &&
1477 boxes
[0].p1
.x
== 0 &&
1478 boxes
[0].p1
.y
== 0 &&
1479 boxes
[0].p2
.x
== surface
->extents
.width
&&
1480 boxes
[0].p2
.y
== surface
->extents
.height
)
1484 SelectClipRgn (surface
->dc
, NULL
);
1485 IntersectClipRect (surface
->dc
,
1491 _cairo_region_boxes_fini (region
, boxes
);
1493 /* XXX see notes in _cairo_win32_save_initial_clip --
1494 * this code will interact badly with a HDC which had an initial
1495 * world transform -- we should probably manually transform the
1496 * region rects, because SelectClipRgn takes device units, not
1497 * logical units (unlike IntersectClipRect).
1500 data_size
= sizeof (RGNDATAHEADER
) + num_boxes
* sizeof (RECT
);
1501 data
= malloc (data_size
);
1503 _cairo_region_boxes_fini (region
, boxes
);
1504 return _cairo_error(CAIRO_STATUS_NO_MEMORY
);
1506 rects
= (RECT
*)data
->Buffer
;
1508 data
->rdh
.dwSize
= sizeof (RGNDATAHEADER
);
1509 data
->rdh
.iType
= RDH_RECTANGLES
;
1510 data
->rdh
.nCount
= num_boxes
;
1511 data
->rdh
.nRgnSize
= num_boxes
* sizeof (RECT
);
1512 data
->rdh
.rcBound
.left
= extents
.x
;
1513 data
->rdh
.rcBound
.top
= extents
.y
;
1514 data
->rdh
.rcBound
.right
= extents
.x
+ extents
.width
;
1515 data
->rdh
.rcBound
.bottom
= extents
.y
+ extents
.height
;
1517 for (i
= 0; i
< num_boxes
; i
++) {
1518 rects
[i
].left
= boxes
[i
].p1
.x
;
1519 rects
[i
].top
= boxes
[i
].p1
.y
;
1520 rects
[i
].right
= boxes
[i
].p2
.x
;
1521 rects
[i
].bottom
= boxes
[i
].p2
.y
;
1524 _cairo_region_boxes_fini (region
, boxes
);
1526 gdi_region
= ExtCreateRegion (NULL
, data_size
, data
);
1530 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1532 /* AND the new region into our DC */
1533 if (ExtSelectClipRgn (surface
->dc
, gdi_region
, RGN_AND
) == ERROR
)
1534 status
= _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
1536 DeleteObject (gdi_region
);
1544 _cairo_win32_surface_get_extents (void *abstract_surface
,
1545 cairo_rectangle_int_t
*rectangle
)
1547 cairo_win32_surface_t
*surface
= abstract_surface
;
1549 *rectangle
= surface
->extents
;
1551 return CAIRO_STATUS_SUCCESS
;
1554 static cairo_status_t
1555 _cairo_win32_surface_flush (void *abstract_surface
)
1557 return _cairo_surface_reset_clip (abstract_surface
);
1560 #define STACK_GLYPH_SIZE 256
1563 _cairo_win32_surface_show_glyphs (void *surface
,
1564 cairo_operator_t op
,
1565 cairo_pattern_t
*source
,
1566 cairo_glyph_t
*glyphs
,
1568 cairo_scaled_font_t
*scaled_font
,
1569 int *remaining_glyphs
)
1571 #if CAIRO_HAS_WIN32_FONT
1572 cairo_win32_surface_t
*dst
= surface
;
1574 WORD glyph_buf_stack
[STACK_GLYPH_SIZE
];
1575 WORD
*glyph_buf
= glyph_buf_stack
;
1576 int dxy_buf_stack
[2 * STACK_GLYPH_SIZE
];
1577 int *dxy_buf
= dxy_buf_stack
;
1579 BOOL win_result
= 0;
1582 cairo_solid_pattern_t
*solid_pattern
;
1585 cairo_matrix_t device_to_logical
;
1587 int start_x
, start_y
;
1588 double user_x
, user_y
;
1589 int logical_x
, logical_y
;
1590 unsigned int glyph_index_option
;
1592 /* We can only handle win32 fonts */
1593 if (cairo_scaled_font_get_type (scaled_font
) != CAIRO_FONT_TYPE_WIN32
)
1594 return CAIRO_INT_STATUS_UNSUPPORTED
;
1596 /* We can only handle opaque solid color sources */
1597 if (!_cairo_pattern_is_opaque_solid(source
))
1598 return CAIRO_INT_STATUS_UNSUPPORTED
;
1600 /* We can only handle operator SOURCE or OVER with the destination
1601 * having no alpha */
1602 if ((op
!= CAIRO_OPERATOR_SOURCE
&& op
!= CAIRO_OPERATOR_OVER
) ||
1603 (dst
->format
!= CAIRO_FORMAT_RGB24
))
1604 return CAIRO_INT_STATUS_UNSUPPORTED
;
1606 /* If we have a fallback mask clip set on the dst, we have
1607 * to go through the fallback path, but only if we're not
1608 * doing this for printing */
1609 if (dst
->base
.clip
&&
1610 !(dst
->flags
& CAIRO_WIN32_SURFACE_FOR_PRINTING
) &&
1611 (dst
->base
.clip
->mode
!= CAIRO_CLIP_MODE_REGION
||
1612 dst
->base
.clip
->surface
!= NULL
))
1613 return CAIRO_INT_STATUS_UNSUPPORTED
;
1615 solid_pattern
= (cairo_solid_pattern_t
*)source
;
1616 color
= RGB(((int)solid_pattern
->color
.red_short
) >> 8,
1617 ((int)solid_pattern
->color
.green_short
) >> 8,
1618 ((int)solid_pattern
->color
.blue_short
) >> 8);
1620 cairo_win32_scaled_font_get_device_to_logical(scaled_font
, &device_to_logical
);
1624 cairo_win32_scaled_font_select_font(scaled_font
, dst
->dc
);
1625 SetTextColor(dst
->dc
, color
);
1626 SetTextAlign(dst
->dc
, TA_BASELINE
| TA_LEFT
);
1627 SetBkMode(dst
->dc
, TRANSPARENT
);
1629 if (num_glyphs
> STACK_GLYPH_SIZE
) {
1630 glyph_buf
= (WORD
*) _cairo_malloc_ab (num_glyphs
, sizeof(WORD
));
1631 dxy_buf
= (int *) _cairo_malloc_abc (num_glyphs
, sizeof(int), 2);
1634 /* It is vital that dx values for dxy_buf are calculated from the delta of
1635 * _logical_ x coordinates (not user x coordinates) or else the sum of all
1636 * previous dx values may start to diverge from the current glyph's x
1637 * coordinate due to accumulated rounding error. As a result strings could
1638 * be painted shorter or longer than expected. */
1640 user_x
= glyphs
[0].x
;
1641 user_y
= glyphs
[0].y
;
1643 cairo_matrix_transform_point(&device_to_logical
,
1646 logical_x
= _cairo_lround (user_x
);
1647 logical_y
= _cairo_lround (user_y
);
1649 start_x
= logical_x
;
1650 start_y
= logical_y
;
1652 for (i
= 0, j
= 0; i
< num_glyphs
; ++i
, j
= 2 * i
) {
1653 glyph_buf
[i
] = (WORD
) glyphs
[i
].index
;
1654 if (i
== num_glyphs
- 1) {
1658 double next_user_x
= glyphs
[i
+1].x
;
1659 double next_user_y
= glyphs
[i
+1].y
;
1660 int next_logical_x
, next_logical_y
;
1662 cairo_matrix_transform_point(&device_to_logical
,
1663 &next_user_x
, &next_user_y
);
1665 next_logical_x
= _cairo_lround (next_user_x
);
1666 next_logical_y
= _cairo_lround (next_user_y
);
1668 dxy_buf
[j
] = _cairo_lround (next_logical_x
- logical_x
);
1669 dxy_buf
[j
+1] = _cairo_lround (next_logical_y
- logical_y
);
1671 logical_x
= next_logical_x
;
1672 logical_y
= next_logical_y
;
1676 /* Using glyph indices for a Type 1 font does not work on a
1677 * printer DC. The win32 printing surface will convert the the
1678 * glyph indices of Type 1 fonts to the unicode values.
1680 if ((dst
->flags
& CAIRO_WIN32_SURFACE_FOR_PRINTING
) &&
1681 _cairo_win32_scaled_font_is_type1 (scaled_font
))
1683 glyph_index_option
= 0;
1687 glyph_index_option
= ETO_GLYPH_INDEX
;
1690 win_result
= ExtTextOutW(dst
->dc
,
1693 glyph_index_option
| ETO_PDY
,
1699 _cairo_win32_print_gdi_error("_cairo_win32_surface_show_glyphs(ExtTextOutW failed)");
1702 RestoreDC(dst
->dc
, -1);
1704 if (glyph_buf
!= glyph_buf_stack
) {
1708 return (win_result
) ? CAIRO_STATUS_SUCCESS
: CAIRO_INT_STATUS_UNSUPPORTED
;
1710 return CAIRO_INT_STATUS_UNSUPPORTED
;
1714 #undef STACK_GLYPH_SIZE
1717 * cairo_win32_surface_create:
1718 * @hdc: the DC to create a surface for
1720 * Creates a cairo surface that targets the given DC. The DC will be
1721 * queried for its initial clip extents, and this will be used as the
1722 * size of the cairo surface. The resulting surface will always be of
1723 * format %CAIRO_FORMAT_RGB24; should you need another surface format,
1724 * you will need to create one through
1725 * cairo_win32_surface_create_with_dib().
1727 * Return value: the newly created surface
1730 cairo_win32_surface_create (HDC hdc
)
1732 cairo_win32_surface_t
*surface
;
1734 cairo_format_t format
;
1737 /* Assume that everything coming in as a HDC is RGB24 */
1738 format
= CAIRO_FORMAT_RGB24
;
1740 surface
= malloc (sizeof (cairo_win32_surface_t
));
1741 if (surface
== NULL
)
1742 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1744 if (_cairo_win32_save_initial_clip (hdc
, surface
) != CAIRO_STATUS_SUCCESS
) {
1746 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1749 surface
->image
= NULL
;
1750 surface
->format
= format
;
1753 surface
->bitmap
= NULL
;
1754 surface
->is_dib
= FALSE
;
1755 surface
->saved_dc_bitmap
= NULL
;
1756 surface
->brush
= NULL
;
1757 surface
->old_brush
= NULL
;
1758 surface
->font_subsets
= NULL
;
1760 GetClipBox(hdc
, &rect
);
1761 surface
->extents
.x
= rect
.left
;
1762 surface
->extents
.y
= rect
.top
;
1763 surface
->extents
.width
= rect
.right
- rect
.left
;
1764 surface
->extents
.height
= rect
.bottom
- rect
.top
;
1766 surface
->flags
= _cairo_win32_flags_for_dc (surface
->dc
);
1768 _cairo_surface_init (&surface
->base
, &cairo_win32_surface_backend
,
1769 _cairo_content_from_format (format
));
1771 return (cairo_surface_t
*)surface
;
1775 * cairo_win32_surface_create_with_dib:
1776 * @format: format of pixels in the surface to create
1777 * @width: width of the surface, in pixels
1778 * @height: height of the surface, in pixels
1780 * Creates a device-independent-bitmap surface not associated with
1781 * any particular existing surface or device context. The created
1782 * bitmap will be uninitialized.
1784 * Return value: the newly created surface
1789 cairo_win32_surface_create_with_dib (cairo_format_t format
,
1793 return _cairo_win32_surface_create_for_dc (NULL
, format
, width
, height
);
1797 * cairo_win32_surface_create_with_ddb:
1798 * @hdc: the DC to create a surface for
1799 * @format: format of pixels in the surface to create
1800 * @width: width of the surface, in pixels
1801 * @height: height of the surface, in pixels
1803 * Creates a device-independent-bitmap surface not associated with
1804 * any particular existing surface or device context. The created
1805 * bitmap will be uninitialized.
1807 * Return value: the newly created surface
1812 cairo_win32_surface_create_with_ddb (HDC hdc
,
1813 cairo_format_t format
,
1817 cairo_win32_surface_t
*new_surf
;
1819 HDC screen_dc
, ddb_dc
;
1820 HBITMAP saved_dc_bitmap
;
1822 if (format
!= CAIRO_FORMAT_RGB24
)
1823 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT
));
1824 /* XXX handle these eventually
1825 format != CAIRO_FORMAT_A8 ||
1826 format != CAIRO_FORMAT_A1)
1830 screen_dc
= GetDC (NULL
);
1836 ddb_dc
= CreateCompatibleDC (hdc
);
1837 if (ddb_dc
== NULL
) {
1838 new_surf
= (cairo_win32_surface_t
*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1842 ddb
= CreateCompatibleBitmap (hdc
, width
, height
);
1846 /* Note that if an app actually does hit this out of memory
1847 * condition, it's going to have lots of other issues, as
1848 * video memory is probably exhausted. However, it can often
1849 * continue using DIBs instead of DDBs.
1851 new_surf
= (cairo_win32_surface_t
*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1855 saved_dc_bitmap
= SelectObject (ddb_dc
, ddb
);
1857 new_surf
= (cairo_win32_surface_t
*) cairo_win32_surface_create (ddb_dc
);
1858 new_surf
->bitmap
= ddb
;
1859 new_surf
->saved_dc_bitmap
= saved_dc_bitmap
;
1860 new_surf
->is_dib
= FALSE
;
1864 ReleaseDC (NULL
, screen_dc
);
1866 return (cairo_surface_t
*) new_surf
;
1870 * _cairo_surface_is_win32:
1871 * @surface: a #cairo_surface_t
1873 * Checks if a surface is a win32 surface. This will
1874 * return False if this is a win32 printing surface; use
1875 * _cairo_surface_is_win32_printing() to check for that.
1877 * Return value: True if the surface is an win32 surface
1880 _cairo_surface_is_win32 (cairo_surface_t
*surface
)
1882 return surface
->backend
== &cairo_win32_surface_backend
;
1886 * cairo_win32_surface_get_dc
1887 * @surface: a #cairo_surface_t
1889 * Returns the HDC associated with this surface, or %NULL if none.
1890 * Also returns %NULL if the surface is not a win32 surface.
1892 * Return value: HDC or %NULL if no HDC available.
1897 cairo_win32_surface_get_dc (cairo_surface_t
*surface
)
1899 cairo_win32_surface_t
*winsurf
;
1901 if (_cairo_surface_is_win32 (surface
)){
1902 winsurf
= (cairo_win32_surface_t
*) surface
;
1907 if (_cairo_surface_is_paginated (surface
)) {
1908 cairo_surface_t
*target
;
1910 target
= _cairo_paginated_surface_get_target (surface
);
1912 if (_cairo_surface_is_win32_printing (target
)) {
1913 winsurf
= (cairo_win32_surface_t
*) target
;
1923 * cairo_win32_surface_get_image
1924 * @surface: a #cairo_surface_t
1926 * Returns a #cairo_surface_t image surface that refers to the same bits
1927 * as the DIB of the Win32 surface. If the passed-in win32 surface
1928 * is not a DIB surface, %NULL is returned.
1930 * Return value: a #cairo_surface_t (owned by the win32 #cairo_surface_t),
1931 * or %NULL if the win32 surface is not a DIB.
1936 cairo_win32_surface_get_image (cairo_surface_t
*surface
)
1938 if (!_cairo_surface_is_win32(surface
))
1941 return ((cairo_win32_surface_t
*)surface
)->image
;
1945 _cairo_win32_surface_is_similar (void *surface_a
,
1947 cairo_content_t content
)
1949 cairo_win32_surface_t
*a
= surface_a
;
1950 cairo_win32_surface_t
*b
= surface_b
;
1952 return a
->dc
== b
->dc
;
1955 static cairo_status_t
1956 _cairo_win32_surface_reset (void *abstract_surface
)
1958 cairo_win32_surface_t
*surface
= abstract_surface
;
1959 cairo_status_t status
;
1961 status
= _cairo_win32_surface_set_clip_region (surface
, NULL
);
1965 return CAIRO_STATUS_SUCCESS
;
1968 static const cairo_surface_backend_t cairo_win32_surface_backend
= {
1969 CAIRO_SURFACE_TYPE_WIN32
,
1970 _cairo_win32_surface_create_similar
,
1971 _cairo_win32_surface_finish
,
1972 _cairo_win32_surface_acquire_source_image
,
1973 _cairo_win32_surface_release_source_image
,
1974 _cairo_win32_surface_acquire_dest_image
,
1975 _cairo_win32_surface_release_dest_image
,
1976 _cairo_win32_surface_clone_similar
,
1977 _cairo_win32_surface_composite
,
1978 _cairo_win32_surface_fill_rectangles
,
1979 NULL
, /* composite_trapezoids */
1980 NULL
, /* copy_page */
1981 NULL
, /* show_page */
1982 _cairo_win32_surface_set_clip_region
,
1983 NULL
, /* intersect_clip_path */
1984 _cairo_win32_surface_get_extents
,
1985 NULL
, /* old_show_glyphs */
1986 NULL
, /* get_font_options */
1987 _cairo_win32_surface_flush
,
1988 NULL
, /* mark_dirty_rectangle */
1989 NULL
, /* scaled_font_fini */
1990 NULL
, /* scaled_glyph_fini */
1996 _cairo_win32_surface_show_glyphs
,
1998 NULL
, /* snapshot */
1999 _cairo_win32_surface_is_similar
,
2001 _cairo_win32_surface_reset
2006 * Win32 alpha-understanding functions
2008 * BitBlt - will copy full 32 bits from a 32bpp DIB to result
2009 * (so it's safe to use for ARGB32->ARGB32 SOURCE blits)
2010 * (but not safe going RGB24->ARGB32, if RGB24 is also represented
2011 * as a 32bpp DIB, since the alpha isn't discarded!)
2013 * AlphaBlend - if both the source and dest have alpha, even if AC_SRC_ALPHA isn't set,
2014 * it will still copy over the src alpha, because the SCA value (255) will be
2015 * multiplied by all the src components.
2020 _cairo_win32_save_initial_clip (HDC hdc
, cairo_win32_surface_t
*surface
)
2027 /* GetClipBox/GetClipRgn and friends interact badly with a world transform
2028 * set. GetClipBox returns values in logical (transformed) coordinates;
2029 * it's unclear what GetClipRgn returns, because the region is empty in the
2030 * case of a SIMPLEREGION clip, but I assume device (untransformed) coordinates.
2031 * Similarily, IntersectClipRect works in logical units, whereas SelectClipRgn
2032 * works in device units.
2034 * So, avoid the whole mess and get rid of the world transform
2035 * while we store our initial data and when we restore initial coordinates.
2037 * XXX we may need to modify x/y by the ViewportOrg or WindowOrg
2038 * here in GM_COMPATIBLE; unclear.
2040 gm
= GetGraphicsMode (hdc
);
2041 if (gm
== GM_ADVANCED
) {
2042 GetWorldTransform (hdc
, &saved_xform
);
2043 ModifyWorldTransform (hdc
, NULL
, MWT_IDENTITY
);
2046 clipBoxType
= GetClipBox (hdc
, &rect
);
2047 if (clipBoxType
== ERROR
) {
2048 _cairo_win32_print_gdi_error ("cairo_win32_surface_create");
2049 SetGraphicsMode (hdc
, gm
);
2050 /* XXX: Can we make a more reasonable guess at the error cause here? */
2051 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
2054 surface
->clip_rect
.x
= rect
.left
;
2055 surface
->clip_rect
.y
= rect
.top
;
2056 surface
->clip_rect
.width
= rect
.right
- rect
.left
;
2057 surface
->clip_rect
.height
= rect
.bottom
- rect
.top
;
2059 surface
->initial_clip_rgn
= NULL
;
2060 surface
->had_simple_clip
= FALSE
;
2062 if (clipBoxType
== COMPLEXREGION
) {
2063 surface
->initial_clip_rgn
= CreateRectRgn (0, 0, 0, 0);
2064 if (GetClipRgn (hdc
, surface
->initial_clip_rgn
) <= 0) {
2065 DeleteObject(surface
->initial_clip_rgn
);
2066 surface
->initial_clip_rgn
= NULL
;
2068 } else if (clipBoxType
== SIMPLEREGION
) {
2069 surface
->had_simple_clip
= TRUE
;
2072 if (gm
== GM_ADVANCED
)
2073 SetWorldTransform (hdc
, &saved_xform
);
2075 return CAIRO_STATUS_SUCCESS
;
2079 _cairo_win32_restore_initial_clip (cairo_win32_surface_t
*surface
)
2081 cairo_int_status_t status
= CAIRO_STATUS_SUCCESS
;
2084 int gm
= GetGraphicsMode (surface
->dc
);
2085 if (gm
== GM_ADVANCED
) {
2086 GetWorldTransform (surface
->dc
, &saved_xform
);
2087 ModifyWorldTransform (surface
->dc
, NULL
, MWT_IDENTITY
);
2090 /* initial_clip_rgn will either be a real region or NULL (which means reset to no clip region) */
2091 SelectClipRgn (surface
->dc
, surface
->initial_clip_rgn
);
2093 if (surface
->had_simple_clip
) {
2094 /* then if we had a simple clip, intersect */
2095 IntersectClipRect (surface
->dc
,
2096 surface
->clip_rect
.x
,
2097 surface
->clip_rect
.y
,
2098 surface
->clip_rect
.x
+ surface
->clip_rect
.width
,
2099 surface
->clip_rect
.y
+ surface
->clip_rect
.height
);
2102 if (gm
== GM_ADVANCED
)
2103 SetWorldTransform (surface
->dc
, &saved_xform
);
2109 _cairo_win32_debug_dump_hrgn (HRGN rgn
, char *header
)
2115 fprintf (stderr
, "%s\n", header
);
2118 fprintf (stderr
, " NULL\n");
2121 z
= GetRegionData(rgn
, 0, NULL
);
2122 rd
= (RGNDATA
*) malloc(z
);
2123 z
= GetRegionData(rgn
, z
, rd
);
2125 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
);
2127 for (z
= 0; z
< rd
->rdh
.nCount
; z
++) {
2128 RECT r
= ((RECT
*)rd
->Buffer
)[z
];
2129 fprintf (stderr
, " [%d]: [%d %d %d %d]\n", z
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
);