ShaderEffect subclasses from Effect, not DependencyObject
[moon.git] / cairo / src / cairo-win32-surface.c
blob5787e2619b10ecfef2e6ee44600a81aff8c15d33
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.
33 * Contributor(s):
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
43 #endif
44 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
45 # define _WIN32_WINNT 0x0500
46 #endif
48 #include "cairoint.h"
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"
55 #include <windows.h>
57 #if defined(__MINGW32__) && !defined(ETO_PDY)
58 # define ETO_PDY 0x2000
59 #endif
61 #undef DEBUG_COMPOSITE
63 /* for older SDKs */
64 #ifndef SHADEBLENDCAPS
65 #define SHADEBLENDCAPS 120
66 #endif
67 #ifndef SB_NONE
68 #define SB_NONE 0x00000000
69 #endif
71 #define PELS_72DPI ((LONG)(72. / 0.0254))
73 static const cairo_surface_backend_t cairo_win32_surface_backend;
75 /**
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
80 * current error code.
82 * Return value: A cairo status code for the error code
83 **/
84 cairo_status_t
85 _cairo_win32_print_gdi_error (const char *context)
87 void *lpMsgBuf;
88 DWORD last_error = GetLastError ();
90 if (!FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
91 FORMAT_MESSAGE_FROM_SYSTEM,
92 NULL,
93 last_error,
94 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
95 (LPSTR) &lpMsgBuf,
96 0, NULL)) {
97 fprintf (stderr, "%s: Unknown GDI error", context);
98 } else {
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);
112 uint32_t
113 _cairo_win32_flags_for_dc (HDC dc)
115 uint32_t flags = 0;
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
124 * everything.
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;
130 } else {
131 int cap;
133 cap = GetDeviceCaps(dc, SHADEBLENDCAPS);
134 if (cap != SB_NONE)
135 flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND;
137 cap = GetDeviceCaps(dc, RASTERCAPS);
138 if (cap & RC_BITBLT)
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;
146 return flags;
149 static cairo_status_t
150 _create_dc_and_bitmap (cairo_win32_surface_t *surface,
151 HDC original_dc,
152 cairo_format_t format,
153 int width,
154 int height,
155 unsigned char **bits_out,
156 int *rowstride_out)
158 cairo_status_t status;
160 BITMAPINFO *bitmap_info = NULL;
161 struct {
162 BITMAPINFOHEADER bmiHeader;
163 RGBQUAD bmiColors[2];
164 } bmi_stack;
165 void *bits;
167 int num_palette = 0; /* Quiet GCC */
168 int i;
170 surface->dc = NULL;
171 surface->bitmap = NULL;
172 surface->is_dib = FALSE;
174 switch (format) {
175 case CAIRO_FORMAT_ARGB32:
176 case CAIRO_FORMAT_RGB24:
177 num_palette = 0;
178 break;
180 case CAIRO_FORMAT_A8:
181 num_palette = 256;
182 break;
184 case CAIRO_FORMAT_A1:
185 num_palette = 2;
186 break;
189 if (num_palette > 2) {
190 bitmap_info = _cairo_malloc_ab_plus_c (num_palette, sizeof(RGBQUAD), sizeof(BITMAPINFOHEADER));
191 if (!bitmap_info)
192 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
193 } else {
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;
205 switch (format) {
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!
211 * see end of file.
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;
219 break;
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;
234 break;
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;
249 break;
252 surface->dc = CreateCompatibleDC (original_dc);
253 if (!surface->dc)
254 goto FAIL;
256 surface->bitmap = CreateDIBSection (surface->dc,
257 bitmap_info,
258 DIB_RGB_COLORS,
259 &bits,
260 NULL, 0);
261 if (!surface->bitmap)
262 goto FAIL;
264 surface->is_dib = TRUE;
266 GdiFlush();
268 surface->saved_dc_bitmap = SelectObject (surface->dc,
269 surface->bitmap);
270 if (!surface->saved_dc_bitmap)
271 goto FAIL;
273 if (bitmap_info && num_palette > 2)
274 free (bitmap_info);
276 if (bits_out)
277 *bits_out = bits;
279 if (rowstride_out) {
280 /* Windows bitmaps are padded to 32-bit (dword) boundaries */
281 switch (format) {
282 case CAIRO_FORMAT_ARGB32:
283 case CAIRO_FORMAT_RGB24:
284 *rowstride_out = 4 * width;
285 break;
287 case CAIRO_FORMAT_A8:
288 *rowstride_out = (width + 3) & ~3;
289 break;
291 case CAIRO_FORMAT_A1:
292 *rowstride_out = ((width + 31) & ~31) / 8;
293 break;
297 surface->flags = _cairo_win32_flags_for_dc (surface->dc);
299 return CAIRO_STATUS_SUCCESS;
301 FAIL:
302 status = _cairo_win32_print_gdi_error ("_create_dc_and_bitmap");
304 if (bitmap_info && num_palette > 2)
305 free (bitmap_info);
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;
317 if (surface->dc) {
318 DeleteDC (surface->dc);
319 surface->dc = NULL;
322 return status;
325 static cairo_surface_t *
326 _cairo_win32_surface_create_for_dc (HDC original_dc,
327 cairo_format_t format,
328 int width,
329 int height)
331 cairo_status_t status;
332 cairo_win32_surface_t *surface;
333 unsigned char *bits;
334 int rowstride;
336 surface = malloc (sizeof (cairo_win32_surface_t));
337 if (surface == NULL)
338 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
340 status = _create_dc_and_bitmap (surface, original_dc, format,
341 width, height,
342 &bits, &rowstride);
343 if (status)
344 goto FAIL;
346 surface->image = cairo_image_surface_create_for_data (bits, format,
347 width, height, rowstride);
348 status = surface->image->status;
349 if (status)
350 goto FAIL;
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;
370 FAIL:
371 if (surface->bitmap) {
372 SelectObject (surface->dc, surface->saved_dc_bitmap);
373 DeleteObject (surface->bitmap);
374 DeleteDC (surface->dc);
376 free (surface);
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,
384 int width,
385 int height,
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.
400 if (src->is_dib ||
401 (content & CAIRO_CONTENT_ALPHA) ||
402 src->base.backend->type == CAIRO_SURFACE_TYPE_WIN32_PRINTING)
404 force_dib = TRUE;
407 if (!force_dib) {
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)
412 new_surf = NULL;
415 if (new_surf == NULL) {
416 new_surf = _cairo_win32_surface_create_for_dc (src->dc, format, width, height);
419 return new_surf;
422 cairo_surface_t *
423 _cairo_win32_surface_create_similar (void *abstract_src,
424 cairo_content_t content,
425 int width,
426 int height)
428 return _cairo_win32_surface_create_similar_internal (abstract_src, content, width, height, FALSE);
431 cairo_status_t
432 _cairo_win32_surface_clone_similar (void *abstract_surface,
433 cairo_surface_t *src,
434 int src_x,
435 int src_y,
436 int width,
437 int height,
438 int *clone_offset_x,
439 int *clone_offset_y,
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);
448 new_surface =
449 _cairo_win32_surface_create_similar_internal (abstract_surface,
450 src_content,
451 width, height,
452 FALSE);
453 if (new_surface == NULL)
454 return CAIRO_INT_STATUS_UNSUPPORTED;
456 status = new_surface->status;
457 if (status)
458 return status;
460 _cairo_pattern_init_for_surface (&pattern, src);
462 status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
463 &pattern.base,
464 NULL,
465 new_surface,
466 src_x, src_y,
467 0, 0,
468 0, 0,
469 width, height);
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;
477 } else
478 cairo_surface_destroy (new_surface);
480 return status;
484 cairo_status_t
485 _cairo_win32_surface_finish (void *abstract_surface)
487 cairo_win32_surface_t *surface = abstract_surface;
489 if (surface->image)
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);
497 } else {
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,
512 int x,
513 int y,
514 int width,
515 int height,
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);
522 local =
523 (cairo_win32_surface_t *) _cairo_win32_surface_create_similar_internal
524 (surface, content, width, height, TRUE);
525 if (local == NULL)
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) &&
534 BitBlt (local->dc,
535 0, 0,
536 width, height,
537 surface->dc,
538 x, y,
539 SRCCOPY))
541 status = CAIRO_STATUS_SUCCESS;
544 if (status) {
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).
551 RECT r;
552 r.left = r.top = 0;
553 r.right = width;
554 r.bottom = height;
555 FillRect(local->dc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
558 *local_out = local;
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,
566 void **image_extra)
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;
574 *image_extra = NULL;
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);
582 if (status)
583 return status;
585 *image_out = (cairo_image_surface_t *)local->image;
586 *image_extra = local;
588 return CAIRO_STATUS_SUCCESS;
591 static void
592 _cairo_win32_surface_release_source_image (void *abstract_surface,
593 cairo_image_surface_t *image,
594 void *image_extra)
596 cairo_win32_surface_t *local = image_extra;
598 if (local)
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,
607 void **image_extra)
609 cairo_win32_surface_t *surface = abstract_surface;
610 cairo_win32_surface_t *local = NULL;
611 cairo_status_t status;
612 RECT clip_box;
613 int x1, y1, x2, y2;
615 if (surface->image) {
616 GdiFlush();
618 image_rect->x = 0;
619 image_rect->y = 0;
620 image_rect->width = surface->extents.width;
621 image_rect->height = surface->extents.height;
623 *image_out = (cairo_image_surface_t *)surface->image;
624 *image_extra = NULL;
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");
632 x1 = clip_box.left;
633 x2 = clip_box.right;
634 y1 = clip_box.top;
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) {
647 *image_out = NULL;
648 *image_extra = NULL;
650 return CAIRO_STATUS_SUCCESS;
653 status = _cairo_win32_surface_get_subimage (abstract_surface,
654 x1, y1, x2 - x1, y2 - y1,
655 &local);
656 if (status)
657 return status;
659 *image_out = (cairo_image_surface_t *)local->image;
660 *image_extra = local;
662 image_rect->x = x1;
663 image_rect->y = y1;
664 image_rect->width = x2 - x1;
665 image_rect->height = y2 - y1;
667 return CAIRO_STATUS_SUCCESS;
670 static void
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,
675 void *image_extra)
677 cairo_win32_surface_t *surface = abstract_surface;
678 cairo_win32_surface_t *local = image_extra;
680 if (!local)
681 return;
683 if (!BitBlt (surface->dc,
684 image_rect->x, image_rect->y,
685 image_rect->width, image_rect->height,
686 local->dc,
687 0, 0,
688 SRCCOPY))
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
696 #pragma pack(1)
697 typedef struct {
698 BYTE BlendOp;
699 BYTE BlendFlags;
700 BYTE SourceConstantAlpha;
701 BYTE AlphaFormat;
702 }BLENDFUNCTION;
703 #pragma pack()
704 #endif
706 /* for compatibility with VC++ 6 */
707 #ifndef AC_SRC_ALPHA
708 #define AC_SRC_ALPHA 0x01
709 #endif
711 typedef BOOL (WINAPI *cairo_alpha_blend_func_t) (HDC hdcDest,
712 int nXOriginDest,
713 int nYOriginDest,
714 int nWidthDest,
715 int hHeightDest,
716 HDC hdcSrc,
717 int nXOriginSrc,
718 int nYOriginSrc,
719 int nWidthSrc,
720 int nHeightSrc,
721 BLENDFUNCTION blendFunction);
723 static cairo_int_status_t
724 _composite_alpha_blend (cairo_win32_surface_t *dst,
725 cairo_win32_surface_t *src,
726 int alpha,
727 int src_x,
728 int src_y,
729 int src_w,
730 int src_h,
731 int dst_x,
732 int dst_y,
733 int dst_w,
734 int dst_h)
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) {
745 OSVERSIONINFO os;
747 os.dwOSVersionInfoSize = sizeof (os);
748 GetVersionEx (&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,
759 "AlphaBlend");
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,
778 dst_x, dst_y,
779 dst_w, dst_h,
780 src->dc,
781 src_x, src_y,
782 src_w, src_h,
783 blend_function))
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,
796 int alpha,
797 cairo_bool_t needs_alpha,
798 cairo_bool_t needs_scale)
800 /* Then do BitBlt, StretchDIBits, StretchBlt, AlphaBlend, or MaskBlt */
801 if (src_image) {
802 if (needs_alpha || needs_scale)
803 return CAIRO_INT_STATUS_UNSUPPORTED;
805 if (dst->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHBLT) {
806 BITMAPINFO bi;
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,
827 /* dst x,y,w,h */
828 dst_r.x, dst_r.y + dst_r.height - 1,
829 dst_r.width, - (int) dst_r.height,
830 /* src x,y,w,h */
831 src_r.x, src_extents.height - src_r.y + 1,
832 src_r.width, - (int) src_r.height,
833 src_image->data,
834 &bi,
835 DIB_RGB_COLORS,
836 SRCCOPY))
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,
843 dst_r.x, dst_r.y,
844 dst_r.width, dst_r.height,
845 src->dc,
846 src_r.x, src_r.y,
847 SRCCOPY))
848 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(BitBlt)");
849 } else if (dst->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHBLT) {
850 /* StretchBlt? */
851 /* XXX check if we want HALFTONE, based on the src filter */
852 BOOL success;
853 int oldmode = SetStretchBltMode(dst->dc, HALFTONE);
854 success = StretchBlt(dst->dc,
855 dst_r.x, dst_r.y,
856 dst_r.width, dst_r.height,
857 src->dc,
858 src_r.x, src_r.y,
859 src_r.width, src_r.height,
860 SRCCOPY);
861 SetStretchBltMode(dst->dc, oldmode);
863 if (!success)
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,
879 void *abstract_dst,
880 int src_x,
881 int src_y,
882 int mask_x,
883 int mask_y,
884 int dst_x,
885 int dst_y,
886 unsigned int width,
887 unsigned int height)
889 cairo_win32_surface_t *dst = abstract_dst;
890 cairo_win32_surface_t *src;
891 cairo_surface_pattern_t *src_surface_pattern;
892 int alpha;
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);
909 #endif
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))
919 == 0)
921 goto UNSUPPORTED;
924 if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
925 goto UNSUPPORTED;
927 if (pattern->extend != CAIRO_EXTEND_NONE &&
928 pattern->extend != CAIRO_EXTEND_REPEAT)
929 goto UNSUPPORTED;
931 if (mask_pattern) {
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;
939 } else {
940 alpha = 255;
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
953 * - alpha is 255
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 ||
961 alpha != 255 ||
962 (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) ||
963 src_image->stride != (src_image->width * 4))
965 goto UNSUPPORTED;
968 src_format = src_image->format;
969 src_extents.x = 0;
970 src_extents.y = 0;
971 src_extents.width = src_image->width;
972 src_extents.height = src_image->height;
973 } else if (src->base.backend != dst->base.backend) {
974 goto UNSUPPORTED;
975 } else {
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,
984 src_x, src_y,
985 dst_x, dst_y, width, height,
986 pattern->matrix.x0, pattern->matrix.y0, pattern->matrix.xx, pattern->matrix.yy);
987 #endif
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))
1000 goto UNSUPPORTED;
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)
1014 goto UNSUPPORTED;
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
1018 * functions.
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);
1025 fflush (stderr);
1026 #endif
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
1032 * black.
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;
1046 goto UNSUPPORTED;
1049 if (src_r.x < 0) {
1050 src_r.width += src_r.x;
1051 src_r.x = 0;
1053 dst_r.width += src_r.x;
1054 dst_r.x -= src_r.x;
1057 if (src_r.y < 0) {
1058 src_r.height += src_r.y;
1059 src_r.y = 0;
1061 dst_r.height += dst_r.y;
1062 dst_r.y -= src_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;
1074 } else {
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) {
1106 if (alpha == 0)
1107 return CAIRO_STATUS_SUCCESS;
1109 if (src_format == dst->format) {
1110 if (alpha == 255 && src_format == CAIRO_FORMAT_RGB24) {
1111 needs_alpha = FALSE;
1112 } else {
1113 needs_alpha = TRUE;
1115 } else if (src_format == CAIRO_FORMAT_ARGB32 &&
1116 dst->format == CAIRO_FORMAT_RGB24)
1118 needs_alpha = TRUE;
1119 } else {
1120 goto UNSUPPORTED;
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;
1127 } else {
1128 goto UNSUPPORTED;
1130 } else {
1131 goto UNSUPPORTED;
1134 if (scalex == 1.0 && scaley == 1.0) {
1135 needs_scale = FALSE;
1136 } else {
1137 /* Should never be reached until we turn StretchBlt back on */
1138 needs_scale = TRUE;
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);
1145 fflush (stderr);
1146 #endif
1148 /* If we need to repeat, we turn the repeated blit into
1149 * a bunch of piece-by-piece blits.
1151 if (needs_repeat) {
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;
1159 if (needs_scale)
1160 goto UNSUPPORTED;
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)
1168 goto UNSUPPORTED;
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)
1174 goto UNSUPPORTED;
1176 /* If we can use PatBlt, just do so */
1177 if (!src_image && !needs_alpha)
1179 HBRUSH brush;
1180 HGDIOBJ old_brush;
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)
1212 goto UNSUPPORTED;
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)
1255 goto UNSUPPORTED;
1258 return status;
1262 } else {
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)
1269 return status;
1271 UNSUPPORTED:
1272 /* Fall back to image surface directly, if this is a DIB surface */
1273 if (dst->image) {
1274 GdiFlush();
1276 return dst->image->backend->composite (op, pattern, mask_pattern,
1277 dst->image,
1278 src_x, src_y,
1279 mask_x, mask_y,
1280 dst_x, dst_y,
1281 width, height);
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;
1303 else
1304 source = SOURCE_OTHER;
1306 switch (op) {
1307 case CAIRO_OPERATOR_CLEAR: /* 0 0 */
1308 case CAIRO_OPERATOR_OUT: /* 1 - Ab 0 */
1309 return DO_CLEAR;
1310 break;
1312 case CAIRO_OPERATOR_SOURCE: /* 1 0 */
1313 case CAIRO_OPERATOR_IN: /* Ab 0 */
1314 return DO_SOURCE;
1315 break;
1317 case CAIRO_OPERATOR_OVER: /* 1 1 - Aa */
1318 case CAIRO_OPERATOR_ATOP: /* Ab 1 - Aa */
1319 if (source == SOURCE_SOLID)
1320 return DO_SOURCE;
1321 else if (source == SOURCE_TRANSPARENT)
1322 return DO_NOTHING;
1323 else
1324 return DO_UNSUPPORTED;
1325 break;
1327 case CAIRO_OPERATOR_DEST_OUT: /* 0 1 - Aa */
1328 case CAIRO_OPERATOR_XOR: /* 1 - Ab 1 - Aa */
1329 if (source == SOURCE_SOLID)
1330 return DO_CLEAR;
1331 else if (source == SOURCE_TRANSPARENT)
1332 return DO_NOTHING;
1333 else
1334 return DO_UNSUPPORTED;
1335 break;
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 */
1340 return DO_NOTHING;
1341 break;
1343 case CAIRO_OPERATOR_DEST_IN: /* 0 Aa */
1344 case CAIRO_OPERATOR_DEST_ATOP:/* 1 - Ab Aa */
1345 if (source == SOURCE_SOLID)
1346 return DO_NOTHING;
1347 else if (source == SOURCE_TRANSPARENT)
1348 return DO_CLEAR;
1349 else
1350 return DO_UNSUPPORTED;
1351 break;
1353 case CAIRO_OPERATOR_ADD: /* 1 1 */
1354 if (source == SOURCE_TRANSPARENT)
1355 return DO_NOTHING;
1356 else
1357 return DO_UNSUPPORTED;
1358 break;
1361 ASSERT_NOT_REACHED;
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,
1370 int num_rects)
1372 cairo_win32_surface_t *surface = abstract_surface;
1373 cairo_status_t status;
1374 COLORREF new_color;
1375 HBRUSH new_brush;
1376 int i;
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
1381 * paths. */
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)) {
1389 case DO_CLEAR:
1390 new_color = RGB (0, 0, 0);
1391 break;
1392 case DO_SOURCE:
1393 new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8);
1394 break;
1395 case DO_NOTHING:
1396 return CAIRO_STATUS_SUCCESS;
1397 case DO_UNSUPPORTED:
1398 default:
1399 return CAIRO_INT_STATUS_UNSUPPORTED;
1402 new_brush = CreateSolidBrush (new_color);
1403 if (!new_brush)
1404 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1406 for (i = 0; i < num_rects; i++) {
1407 RECT rect;
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))
1415 goto FAIL;
1418 DeleteObject (new_brush);
1420 return CAIRO_STATUS_SUCCESS;
1422 FAIL:
1423 status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1425 DeleteObject (new_brush);
1427 return status;
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);
1445 if (status)
1446 return status;
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 */
1459 if (region) {
1460 cairo_rectangle_int_t extents;
1461 cairo_box_int_t *boxes;
1462 int num_boxes;
1463 RGNDATA *data;
1464 size_t data_size;
1465 RECT *rects;
1466 int i;
1467 HRGN gdi_region;
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);
1473 if (status)
1474 return status;
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)
1482 gdi_region = NULL;
1484 SelectClipRgn (surface->dc, NULL);
1485 IntersectClipRect (surface->dc,
1486 boxes[0].p1.x,
1487 boxes[0].p1.y,
1488 boxes[0].p2.x,
1489 boxes[0].p2.y);
1491 _cairo_region_boxes_fini (region, boxes);
1492 } else {
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);
1502 if (!data) {
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);
1527 free (data);
1529 if (!gdi_region)
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);
1540 return status;
1543 cairo_int_status_t
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
1562 cairo_int_status_t
1563 _cairo_win32_surface_show_glyphs (void *surface,
1564 cairo_operator_t op,
1565 cairo_pattern_t *source,
1566 cairo_glyph_t *glyphs,
1567 int num_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;
1580 int i, j;
1582 cairo_solid_pattern_t *solid_pattern;
1583 COLORREF color;
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);
1622 SaveDC(dst->dc);
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,
1644 &user_x, &user_y);
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) {
1655 dxy_buf[j] = 0;
1656 dxy_buf[j+1] = 0;
1657 } else {
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;
1685 else
1687 glyph_index_option = ETO_GLYPH_INDEX;
1690 win_result = ExtTextOutW(dst->dc,
1691 start_x,
1692 start_y,
1693 glyph_index_option | ETO_PDY,
1694 NULL,
1695 glyph_buf,
1696 num_glyphs,
1697 dxy_buf);
1698 if (!win_result) {
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) {
1705 free(glyph_buf);
1706 free(dxy_buf);
1708 return (win_result) ? CAIRO_STATUS_SUCCESS : CAIRO_INT_STATUS_UNSUPPORTED;
1709 #else
1710 return CAIRO_INT_STATUS_UNSUPPORTED;
1711 #endif
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
1729 cairo_surface_t *
1730 cairo_win32_surface_create (HDC hdc)
1732 cairo_win32_surface_t *surface;
1734 cairo_format_t format;
1735 RECT rect;
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) {
1745 free (surface);
1746 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1749 surface->image = NULL;
1750 surface->format = format;
1752 surface->dc = hdc;
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
1786 * Since: 1.2
1788 cairo_surface_t *
1789 cairo_win32_surface_create_with_dib (cairo_format_t format,
1790 int width,
1791 int height)
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
1809 * Since: 1.4
1811 cairo_surface_t *
1812 cairo_win32_surface_create_with_ddb (HDC hdc,
1813 cairo_format_t format,
1814 int width,
1815 int height)
1817 cairo_win32_surface_t *new_surf;
1818 HBITMAP ddb;
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)
1829 if (!hdc) {
1830 screen_dc = GetDC (NULL);
1831 hdc = screen_dc;
1832 } else {
1833 screen_dc = 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));
1839 goto FINISH;
1842 ddb = CreateCompatibleBitmap (hdc, width, height);
1843 if (ddb == NULL) {
1844 DeleteDC (ddb_dc);
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));
1852 goto FINISH;
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;
1862 FINISH:
1863 if (screen_dc)
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.
1894 * Since: 1.2
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;
1904 return winsurf->dc;
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;
1915 return winsurf->dc;
1919 return NULL;
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.
1933 * Since: 1.4
1935 cairo_surface_t *
1936 cairo_win32_surface_get_image (cairo_surface_t *surface)
1938 if (!_cairo_surface_is_win32(surface))
1939 return NULL;
1941 return ((cairo_win32_surface_t*)surface)->image;
1944 static cairo_bool_t
1945 _cairo_win32_surface_is_similar (void *surface_a,
1946 void *surface_b,
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);
1962 if (status)
1963 return status;
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 */
1992 NULL, /* paint */
1993 NULL, /* mask */
1994 NULL, /* stroke */
1995 NULL, /* fill */
1996 _cairo_win32_surface_show_glyphs,
1998 NULL, /* snapshot */
1999 _cairo_win32_surface_is_similar,
2001 _cairo_win32_surface_reset
2004 /* Notes:
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.
2019 cairo_int_status_t
2020 _cairo_win32_save_initial_clip (HDC hdc, cairo_win32_surface_t *surface)
2022 RECT rect;
2023 int clipBoxType;
2024 int gm;
2025 XFORM saved_xform;
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;
2078 cairo_int_status_t
2079 _cairo_win32_restore_initial_clip (cairo_win32_surface_t *surface)
2081 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
2083 XFORM saved_xform;
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);
2105 return status;
2108 void
2109 _cairo_win32_debug_dump_hrgn (HRGN rgn, char *header)
2111 RGNDATA *rd;
2112 int z;
2114 if (header)
2115 fprintf (stderr, "%s\n", header);
2117 if (rgn == NULL) {
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);
2132 free(rd);
2133 fflush (stderr);