Upload Tizen2.0 source
[framework/graphics/cairo.git] / src / cairo-win32-surface.c
1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* Cairo - a vector graphics library with display and print output
3  *
4  * Copyright © 2005 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it either under the terms of the GNU Lesser General Public
8  * License version 2.1 as published by the Free Software Foundation
9  * (the "LGPL") or, at your option, under the terms of the Mozilla
10  * Public License Version 1.1 (the "MPL"). If you do not alter this
11  * notice, a recipient may use your version of this file under either
12  * the MPL or the LGPL.
13  *
14  * You should have received a copy of the LGPL along with this library
15  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17  * You should have received a copy of the MPL along with this library
18  * in the file COPYING-MPL-1.1
19  *
20  * The contents of this file are subject to the Mozilla Public License
21  * Version 1.1 (the "License"); you may not use this file except in
22  * compliance with the License. You may obtain a copy of the License at
23  * http://www.mozilla.org/MPL/
24  *
25  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27  * the specific language governing rights and limitations.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is Red Hat, Inc.
32  *
33  * Contributor(s):
34  *      Owen Taylor <otaylor@redhat.com>
35  *      Stuart Parmenter <stuart@mozilla.com>
36  *      Vladimir Vukicevic <vladimir@pobox.com>
37  */
38
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
47
48 #include "cairoint.h"
49
50 #include "cairo-clip-private.h"
51 #include "cairo-composite-rectangles-private.h"
52 #include "cairo-default-context-private.h"
53 #include "cairo-error-private.h"
54 #include "cairo-image-surface-private.h"
55 #include "cairo-paginated-private.h"
56 #include "cairo-pattern-private.h"
57 #include "cairo-win32-private.h"
58 #include "cairo-scaled-font-subsets-private.h"
59 #include "cairo-surface-fallback-private.h"
60 #include "cairo-surface-backend-private.h"
61
62 #include <wchar.h>
63 #include <windows.h>
64
65 #if defined(__MINGW32__) && !defined(ETO_PDY)
66 # define ETO_PDY 0x2000
67 #endif
68
69 #undef DEBUG_COMPOSITE
70
71 /* for older SDKs */
72 #ifndef SHADEBLENDCAPS
73 #define SHADEBLENDCAPS  120
74 #endif
75 #ifndef SB_NONE
76 #define SB_NONE         0x00000000
77 #endif
78
79 #define PELS_72DPI  ((LONG)(72. / 0.0254))
80
81 /**
82  * SECTION:cairo-win32
83  * @Title: Win32 Surfaces
84  * @Short_Description: Microsoft Windows surface support
85  * @See_Also: #cairo_surface_t
86  *
87  * The Microsoft Windows surface is used to render cairo graphics to
88  * Microsoft Windows windows, bitmaps, and printing device contexts.
89  *
90  * The surface returned by cairo_win32_printing_surface_create() is of surface
91  * type %CAIRO_SURFACE_TYPE_WIN32_PRINTING and is a multi-page vector surface
92  * type.
93  *
94  * The surface returned by the other win32 constructors is of surface type
95  * %CAIRO_SURFACE_TYPE_WIN32 and is a raster surface type.
96  */
97
98 /**
99  * CAIRO_HAS_WIN32_SURFACE:
100  *
101  * Defined if the Microsoft Windows surface backend is available.
102  * This macro can be used to conditionally compile backend-specific code.
103  */
104
105 static const cairo_surface_backend_t cairo_win32_surface_backend;
106
107 /**
108  * _cairo_win32_print_gdi_error:
109  * @context: context string to display along with the error
110  *
111  * Helper function to dump out a human readable form of the
112  * current error code.
113  *
114  * Return value: A cairo status code for the error code
115  **/
116 cairo_status_t
117 _cairo_win32_print_gdi_error (const char *context)
118 {
119     void *lpMsgBuf;
120     DWORD last_error = GetLastError ();
121
122     if (!FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
123                          FORMAT_MESSAGE_FROM_SYSTEM,
124                          NULL,
125                          last_error,
126                          MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
127                          (LPWSTR) &lpMsgBuf,
128                          0, NULL)) {
129         fprintf (stderr, "%s: Unknown GDI error", context);
130     } else {
131         fprintf (stderr, "%s: %S", context, (wchar_t *)lpMsgBuf);
132
133         LocalFree (lpMsgBuf);
134     }
135
136     fflush (stderr);
137
138     /* We should switch off of last_status, but we'd either return
139      * CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there
140      * is no CAIRO_STATUS_UNKNOWN_ERROR.
141      */
142
143     return _cairo_error (CAIRO_STATUS_NO_MEMORY);
144 }
145
146 uint32_t
147 _cairo_win32_flags_for_dc (HDC dc)
148 {
149     uint32_t flags = 0;
150
151     if (GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
152         flags |= CAIRO_WIN32_SURFACE_IS_DISPLAY;
153
154         /* These will always be possible, but the actual GetDeviceCaps
155          * calls will return whether they're accelerated or not.
156          * We may want to use our own (pixman) routines sometimes
157          * if they're eventually faster, but for now have GDI do
158          * everything.
159          */
160         flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT;
161         flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND;
162         flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT;
163         flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB;
164     } else {
165         int cap;
166
167         cap = GetDeviceCaps(dc, SHADEBLENDCAPS);
168         if (cap != SB_NONE)
169             flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND;
170
171         cap = GetDeviceCaps(dc, RASTERCAPS);
172         if (cap & RC_BITBLT)
173             flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT;
174         if (cap & RC_STRETCHBLT)
175             flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT;
176         if (cap & RC_STRETCHDIB)
177             flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB;
178     }
179
180     return flags;
181 }
182
183 static cairo_status_t
184 _create_dc_and_bitmap (cairo_win32_surface_t *surface,
185                        HDC                    original_dc,
186                        cairo_format_t         format,
187                        int                    width,
188                        int                    height,
189                        unsigned char        **bits_out,
190                        int                   *rowstride_out)
191 {
192     cairo_status_t status;
193
194     BITMAPINFO *bitmap_info = NULL;
195     struct {
196         BITMAPINFOHEADER bmiHeader;
197         RGBQUAD bmiColors[2];
198     } bmi_stack;
199     void *bits;
200
201     int num_palette = 0;        /* Quiet GCC */
202     int i;
203
204     surface->dc = NULL;
205     surface->bitmap = NULL;
206     surface->is_dib = FALSE;
207
208     switch (format) {
209     default:
210     case CAIRO_FORMAT_INVALID:
211         return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
212     case CAIRO_FORMAT_ARGB32:
213     case CAIRO_FORMAT_RGB24:
214         num_palette = 0;
215         break;
216
217     case CAIRO_FORMAT_A8:
218         num_palette = 256;
219         break;
220
221     case CAIRO_FORMAT_A1:
222         num_palette = 2;
223         break;
224     }
225
226     if (num_palette > 2) {
227         bitmap_info = _cairo_malloc_ab_plus_c (num_palette, sizeof(RGBQUAD), sizeof(BITMAPINFOHEADER));
228         if (!bitmap_info)
229             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
230     } else {
231         bitmap_info = (BITMAPINFO *)&bmi_stack;
232     }
233
234     bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
235     bitmap_info->bmiHeader.biWidth = width == 0 ? 1 : width;
236     bitmap_info->bmiHeader.biHeight = height == 0 ? -1 : - height; /* top-down */
237     bitmap_info->bmiHeader.biSizeImage = 0;
238     bitmap_info->bmiHeader.biXPelsPerMeter = PELS_72DPI; /* unused here */
239     bitmap_info->bmiHeader.biYPelsPerMeter = PELS_72DPI; /* unused here */
240     bitmap_info->bmiHeader.biPlanes = 1;
241
242     switch (format) {
243     /* We can't create real RGB24 bitmaps because something seems to
244      * break if we do, especially if we don't set up an image
245      * fallback.  It could be a bug with using a 24bpp pixman image
246      * (and creating one with masks).  So treat them like 32bpp.
247      * Note: This causes problems when using BitBlt/AlphaBlend/etc!
248      * see end of file.
249      */
250     case CAIRO_FORMAT_RGB24:
251     case CAIRO_FORMAT_ARGB32:
252         bitmap_info->bmiHeader.biBitCount = 32;
253         bitmap_info->bmiHeader.biCompression = BI_RGB;
254         bitmap_info->bmiHeader.biClrUsed = 0;   /* unused */
255         bitmap_info->bmiHeader.biClrImportant = 0;
256         break;
257
258     case CAIRO_FORMAT_A8:
259         bitmap_info->bmiHeader.biBitCount = 8;
260         bitmap_info->bmiHeader.biCompression = BI_RGB;
261         bitmap_info->bmiHeader.biClrUsed = 256;
262         bitmap_info->bmiHeader.biClrImportant = 0;
263
264         for (i = 0; i < 256; i++) {
265             bitmap_info->bmiColors[i].rgbBlue = i;
266             bitmap_info->bmiColors[i].rgbGreen = i;
267             bitmap_info->bmiColors[i].rgbRed = i;
268             bitmap_info->bmiColors[i].rgbReserved = 0;
269         }
270
271         break;
272
273     case CAIRO_FORMAT_A1:
274         bitmap_info->bmiHeader.biBitCount = 1;
275         bitmap_info->bmiHeader.biCompression = BI_RGB;
276         bitmap_info->bmiHeader.biClrUsed = 2;
277         bitmap_info->bmiHeader.biClrImportant = 0;
278
279         for (i = 0; i < 2; i++) {
280             bitmap_info->bmiColors[i].rgbBlue = i * 255;
281             bitmap_info->bmiColors[i].rgbGreen = i * 255;
282             bitmap_info->bmiColors[i].rgbRed = i * 255;
283             bitmap_info->bmiColors[i].rgbReserved = 0;
284         }
285
286         break;
287     }
288
289     surface->dc = CreateCompatibleDC (original_dc);
290     if (!surface->dc)
291         goto FAIL;
292
293     surface->bitmap = CreateDIBSection (surface->dc,
294                                         bitmap_info,
295                                         DIB_RGB_COLORS,
296                                         &bits,
297                                         NULL, 0);
298     if (!surface->bitmap)
299         goto FAIL;
300
301     surface->is_dib = TRUE;
302
303     GdiFlush();
304
305     surface->saved_dc_bitmap = SelectObject (surface->dc,
306                                              surface->bitmap);
307     if (!surface->saved_dc_bitmap)
308         goto FAIL;
309
310     if (bitmap_info && num_palette > 2)
311         free (bitmap_info);
312
313     if (bits_out)
314         *bits_out = bits;
315
316     if (rowstride_out) {
317         /* Windows bitmaps are padded to 32-bit (dword) boundaries */
318         switch (format) {
319         case CAIRO_FORMAT_ARGB32:
320         case CAIRO_FORMAT_RGB24:
321             *rowstride_out = 4 * width;
322             break;
323
324         case CAIRO_FORMAT_A8:
325             *rowstride_out = (width + 3) & ~3;
326             break;
327
328         case CAIRO_FORMAT_A1:
329             *rowstride_out = ((width + 31) & ~31) / 8;
330             break;
331         }
332     }
333
334     surface->flags = _cairo_win32_flags_for_dc (surface->dc);
335
336     return CAIRO_STATUS_SUCCESS;
337
338  FAIL:
339     status = _cairo_win32_print_gdi_error ("_create_dc_and_bitmap");
340
341     if (bitmap_info && num_palette > 2)
342         free (bitmap_info);
343
344     if (surface->saved_dc_bitmap) {
345         SelectObject (surface->dc, surface->saved_dc_bitmap);
346         surface->saved_dc_bitmap = NULL;
347     }
348
349     if (surface->bitmap) {
350         DeleteObject (surface->bitmap);
351         surface->bitmap = NULL;
352     }
353
354     if (surface->dc) {
355         DeleteDC (surface->dc);
356         surface->dc = NULL;
357     }
358
359     return status;
360 }
361
362 static cairo_surface_t *
363 _cairo_win32_surface_create_for_dc (HDC             original_dc,
364                                     cairo_format_t  format,
365                                     int             width,
366                                     int             height)
367 {
368     cairo_status_t status;
369     cairo_win32_surface_t *surface;
370     unsigned char *bits;
371     int rowstride;
372
373     if (! CAIRO_FORMAT_VALID (format))
374         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
375
376     surface = malloc (sizeof (cairo_win32_surface_t));
377     if (surface == NULL)
378         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
379
380     surface->clip_region = NULL;
381
382     status = _create_dc_and_bitmap (surface, original_dc, format,
383                                     width, height,
384                                     &bits, &rowstride);
385     if (status)
386         goto FAIL;
387
388     surface->image = cairo_image_surface_create_for_data (bits, format,
389                                                           width, height, rowstride);
390     status = surface->image->status;
391     if (status)
392         goto FAIL;
393
394     surface->format = format;
395
396     surface->clip_rect.x = 0;
397     surface->clip_rect.y = 0;
398     surface->clip_rect.width = width;
399     surface->clip_rect.height = height;
400
401     surface->initial_clip_rgn = NULL;
402     surface->had_simple_clip = FALSE;
403
404     surface->extents = surface->clip_rect;
405     surface->font_subsets = NULL;
406
407     _cairo_surface_init (&surface->base,
408                          &cairo_win32_surface_backend,
409                          NULL, /* device */
410                          _cairo_content_from_format (format));
411
412     return &surface->base;
413
414  FAIL:
415     if (surface->bitmap) {
416         SelectObject (surface->dc, surface->saved_dc_bitmap);
417         DeleteObject (surface->bitmap);
418         DeleteDC (surface->dc);
419     }
420     free (surface);
421
422     return _cairo_surface_create_in_error (status);
423 }
424
425 static cairo_surface_t *
426 _cairo_win32_surface_create_similar_internal (void          *abstract_src,
427                                               cairo_content_t content,
428                                               int            width,
429                                               int            height,
430                                               cairo_bool_t   force_dib)
431 {
432     cairo_win32_surface_t *src = abstract_src;
433     cairo_format_t format = _cairo_format_from_content (content);
434     cairo_surface_t *new_surf = NULL;
435
436     /* We force a DIB always if:
437      * - we need alpha; or
438      * - the parent is a DIB; or
439      * - the parent is for printing (because we don't care about the bit depth at that point)
440      *
441      * We also might end up with a DIB even if a DDB is requested if DDB creation failed
442      * due to out of memory.
443      */
444     if (src->is_dib ||
445         (content & CAIRO_CONTENT_ALPHA) ||
446         src->base.backend->type == CAIRO_SURFACE_TYPE_WIN32_PRINTING)
447     {
448         force_dib = TRUE;
449     }
450
451     if (!force_dib) {
452         /* try to create a ddb */
453         new_surf = cairo_win32_surface_create_with_ddb (src->dc, CAIRO_FORMAT_RGB24, width, height);
454
455         if (new_surf->status != CAIRO_STATUS_SUCCESS)
456             new_surf = NULL;
457     }
458
459     if (new_surf == NULL) {
460         new_surf = _cairo_win32_surface_create_for_dc (src->dc, format, width, height);
461     }
462
463     return new_surf;
464 }
465
466 cairo_surface_t *
467 _cairo_win32_surface_create_similar (void           *abstract_src,
468                                      cairo_content_t content,
469                                      int             width,
470                                      int             height)
471 {
472     return _cairo_win32_surface_create_similar_internal (abstract_src, content, width, height, FALSE);
473 }
474
475 cairo_status_t
476 _cairo_win32_surface_finish (void *abstract_surface)
477 {
478     cairo_win32_surface_t *surface = abstract_surface;
479
480     if (surface->image)
481         cairo_surface_destroy (surface->image);
482
483     /* If we created the Bitmap and DC, destroy them */
484     if (surface->bitmap) {
485         SelectObject (surface->dc, surface->saved_dc_bitmap);
486         DeleteObject (surface->bitmap);
487         DeleteDC (surface->dc);
488     } else {
489         _cairo_win32_restore_initial_clip (surface);
490     }
491
492     if (surface->initial_clip_rgn)
493         DeleteObject (surface->initial_clip_rgn);
494
495     if (surface->font_subsets != NULL)
496         _cairo_scaled_font_subsets_destroy (surface->font_subsets);
497
498     return CAIRO_STATUS_SUCCESS;
499 }
500
501 static cairo_status_t
502 _cairo_win32_surface_get_subimage (cairo_win32_surface_t  *surface,
503                                    int                     x,
504                                    int                     y,
505                                    int                     width,
506                                    int                     height,
507                                    cairo_win32_surface_t **local_out)
508 {
509     cairo_win32_surface_t *local;
510     cairo_int_status_t status;
511     cairo_content_t content = _cairo_content_from_format (surface->format);
512
513     local =
514         (cairo_win32_surface_t *) _cairo_win32_surface_create_similar_internal
515         (surface, content, width, height, TRUE);
516     if (local == NULL)
517         return CAIRO_INT_STATUS_UNSUPPORTED;
518     if (local->base.status)
519         return local->base.status;
520
521     status = CAIRO_INT_STATUS_UNSUPPORTED;
522
523     /* Only BitBlt if the source surface supports it. */
524     if ((surface->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT) &&
525         BitBlt (local->dc,
526                 0, 0,
527                 width, height,
528                 surface->dc,
529                 x, y,
530                 SRCCOPY))
531     {
532         status = CAIRO_STATUS_SUCCESS;
533     }
534
535     if (status) {
536         /* If we failed here, most likely the source or dest doesn't
537          * support BitBlt/AlphaBlend (e.g. a printer).
538          * You can't reliably get bits from a printer DC, so just fill in
539          * the surface as white (common case for printing).
540          */
541
542         RECT r;
543         r.left = r.top = 0;
544         r.right = width;
545         r.bottom = height;
546         FillRect(local->dc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
547     }
548
549     *local_out = local;
550
551     return CAIRO_STATUS_SUCCESS;
552 }
553
554 static cairo_surface_t *
555 _cairo_win32_surface_map_to_image (void                    *abstract_surface,
556                                    const cairo_rectangle_int_t   *extents)
557 {
558     cairo_win32_surface_t *surface = abstract_surface;
559     cairo_win32_surface_t *local = NULL;
560     cairo_status_t status;
561
562     if (surface->image) {
563         GdiFlush();
564         return _cairo_surface_create_for_rectangle_int (surface->image,
565                                                         extents);
566     }
567
568     status = _cairo_win32_surface_get_subimage (abstract_surface,
569                                                 extents->x,
570                                                 extents->y,
571                                                 extents->width,
572                                                 extents->height,
573                                                 &local);
574     if (unlikely (status))
575         return _cairo_surface_create_in_error (status);
576
577     status = cairo_surface_set_user_data (local->image,
578                                           (const cairo_user_data_key_t *)surface->image,
579                                           local, NULL);
580     if (unlikely (status)) {
581         cairo_surface_destroy (&local->base);
582         return _cairo_surface_create_in_error (status);
583     }
584
585     cairo_surface_set_device_offset (local->image, -extents->x, -extents->y);
586     return local->image;
587 }
588
589 static cairo_int_status_t
590 _cairo_win32_surface_unmap_image (void                    *abstract_surface,
591                                   cairo_image_surface_t   *image)
592 {
593     cairo_win32_surface_t *surface = abstract_surface;
594     cairo_win32_surface_t *local;
595
596     local = cairo_surface_get_user_data (&image->base,
597                                          (const cairo_user_data_key_t *) surface->image);
598     if (!local)
599         return CAIRO_INT_STATUS_SUCCESS;
600
601     if (!BitBlt (surface->dc,
602                  image->base.device_transform.x0,
603                  image->base.device_transform.y0,
604                  image->width, image->height,
605                  local->dc,
606                  0, 0,
607                  SRCCOPY))
608         _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image");
609
610     return CAIRO_STATUS_SUCCESS;
611 }
612
613 static cairo_status_t
614 _cairo_win32_surface_acquire_source_image (void                    *abstract_surface,
615                                            cairo_image_surface_t  **image_out,
616                                            void                   **image_extra)
617 {
618     cairo_win32_surface_t *surface = abstract_surface;
619     cairo_win32_surface_t *local;
620     cairo_status_t status;
621
622     if (surface->image) {
623         *image_out = (cairo_image_surface_t *)surface->image;
624         *image_extra = NULL;
625         return CAIRO_STATUS_SUCCESS;
626     }
627
628     status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0,
629                                                 surface->extents.width,
630                                                 surface->extents.height, &local);
631     if (status)
632         return status;
633
634     *image_out = (cairo_image_surface_t *)local->image;
635     *image_extra = local;
636     return CAIRO_STATUS_SUCCESS;
637 }
638
639 static void
640 _cairo_win32_surface_release_source_image (void                   *abstract_surface,
641                                            cairo_image_surface_t  *image,
642                                            void                   *image_extra)
643 {
644     cairo_win32_surface_t *local = image_extra;
645
646     if (local)
647         cairo_surface_destroy ((cairo_surface_t *)local);
648 }
649
650 cairo_status_t
651 _cairo_win32_surface_set_clip_region (void           *abstract_surface,
652                                       cairo_region_t *region)
653 {
654     cairo_win32_surface_t *surface = abstract_surface;
655     cairo_status_t status = CAIRO_STATUS_SUCCESS;
656
657     if (surface->clip_region == region)
658         return CAIRO_STATUS_SUCCESS;
659
660     cairo_region_destroy (surface->clip_region);
661     surface->clip_region = cairo_region_reference (region);
662
663     /* The semantics we want is that any clip set by cairo combines
664      * is intersected with the clip on device context that the
665      * surface was created for. To implement this, we need to
666      * save the original clip when first setting a clip on surface.
667      */
668
669     /* Clear any clip set by cairo, return to the original first */
670     status = _cairo_win32_restore_initial_clip (surface);
671
672     /* Then combine any new region with it */
673     if (region) {
674         cairo_rectangle_int_t extents;
675         int num_rects;
676         RGNDATA *data;
677         size_t data_size;
678         RECT *rects;
679         int i;
680         HRGN gdi_region;
681
682         /* Create a GDI region for the cairo region */
683
684         cairo_region_get_extents (region, &extents);
685         num_rects = cairo_region_num_rectangles (region);
686         /* XXX see notes in _cairo_win32_save_initial_clip --
687          * this code will interact badly with a HDC which had an initial
688          * world transform -- we should probably manually transform the
689          * region rects, because SelectClipRgn takes device units, not
690          * logical units (unlike IntersectClipRect).
691          */
692
693         data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT);
694         data = malloc (data_size);
695         if (!data)
696             return _cairo_error(CAIRO_STATUS_NO_MEMORY);
697         rects = (RECT *)data->Buffer;
698
699         data->rdh.dwSize = sizeof (RGNDATAHEADER);
700         data->rdh.iType = RDH_RECTANGLES;
701         data->rdh.nCount = num_rects;
702         data->rdh.nRgnSize = num_rects * sizeof (RECT);
703         data->rdh.rcBound.left = extents.x;
704         data->rdh.rcBound.top = extents.y;
705         data->rdh.rcBound.right = extents.x + extents.width;
706         data->rdh.rcBound.bottom = extents.y + extents.height;
707
708         for (i = 0; i < num_rects; i++) {
709             cairo_rectangle_int_t rect;
710
711             cairo_region_get_rectangle (region, i, &rect);
712
713             rects[i].left   = rect.x;
714             rects[i].top    = rect.y;
715             rects[i].right  = rect.x + rect.width;
716             rects[i].bottom = rect.y + rect.height;
717         }
718
719         gdi_region = ExtCreateRegion (NULL, data_size, data);
720         free (data);
721
722         if (!gdi_region)
723             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
724
725         /* AND the new region into our DC */
726         if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
727             status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
728
729         DeleteObject (gdi_region);
730     }
731
732     return status;
733 }
734
735 #if !defined(AC_SRC_OVER)
736 #define AC_SRC_OVER                 0x00
737 #pragma pack(1)
738 typedef struct {
739     BYTE   BlendOp;
740     BYTE   BlendFlags;
741     BYTE   SourceConstantAlpha;
742     BYTE   AlphaFormat;
743 }BLENDFUNCTION;
744 #pragma pack()
745 #endif
746
747 /* for compatibility with VC++ 6 */
748 #ifndef AC_SRC_ALPHA
749 #define AC_SRC_ALPHA                0x01
750 #endif
751
752 typedef BOOL (WINAPI *cairo_alpha_blend_func_t) (HDC hdcDest,
753                                                  int nXOriginDest,
754                                                  int nYOriginDest,
755                                                  int nWidthDest,
756                                                  int hHeightDest,
757                                                  HDC hdcSrc,
758                                                  int nXOriginSrc,
759                                                  int nYOriginSrc,
760                                                  int nWidthSrc,
761                                                  int nHeightSrc,
762                                                  BLENDFUNCTION blendFunction);
763
764 static cairo_int_status_t
765 _composite_alpha_blend (cairo_win32_surface_t *dst,
766                         cairo_win32_surface_t *src,
767                         int                    alpha,
768                         int                    src_x,
769                         int                    src_y,
770                         int                    src_w,
771                         int                    src_h,
772                         int                    dst_x,
773                         int                    dst_y,
774                         int                    dst_w,
775                         int                    dst_h)
776 {
777     static unsigned alpha_blend_checked = FALSE;
778     static cairo_alpha_blend_func_t alpha_blend = NULL;
779
780     BLENDFUNCTION blend_function;
781
782     /* Check for AlphaBlend dynamically to allow compiling on
783      * MSVC 6 and use on older windows versions
784      */
785     if (!alpha_blend_checked) {
786         OSVERSIONINFO os;
787
788         os.dwOSVersionInfoSize = sizeof (os);
789         GetVersionEx (&os);
790
791         /* If running on Win98, disable using AlphaBlend()
792          * to avoid Win98 AlphaBlend() bug */
793         if (VER_PLATFORM_WIN32_WINDOWS != os.dwPlatformId ||
794             os.dwMajorVersion != 4 || os.dwMinorVersion != 10)
795         {
796             HMODULE msimg32_dll = LoadLibraryW (L"msimg32");
797
798             if (msimg32_dll != NULL)
799                 alpha_blend = (cairo_alpha_blend_func_t)GetProcAddress (msimg32_dll,
800                                                                         "AlphaBlend");
801         }
802
803         alpha_blend_checked = TRUE;
804     }
805
806     if (alpha_blend == NULL)
807         return CAIRO_INT_STATUS_UNSUPPORTED;
808     if (!(dst->flags & CAIRO_WIN32_SURFACE_CAN_ALPHABLEND))
809         return CAIRO_INT_STATUS_UNSUPPORTED;
810     if (src->format == CAIRO_FORMAT_RGB24 && dst->format == CAIRO_FORMAT_ARGB32)
811         return CAIRO_INT_STATUS_UNSUPPORTED;
812
813     blend_function.BlendOp = AC_SRC_OVER;
814     blend_function.BlendFlags = 0;
815     blend_function.SourceConstantAlpha = alpha;
816     blend_function.AlphaFormat = (src->format == CAIRO_FORMAT_ARGB32) ? AC_SRC_ALPHA : 0;
817
818     if (!alpha_blend (dst->dc,
819                       dst_x, dst_y,
820                       dst_w, dst_h,
821                       src->dc,
822                       src_x, src_y,
823                       src_w, src_h,
824                       blend_function))
825         return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(AlphaBlend)");
826
827     return CAIRO_STATUS_SUCCESS;
828 }
829
830 static cairo_int_status_t
831 _cairo_win32_surface_composite_inner (cairo_win32_surface_t *src,
832                                       cairo_image_surface_t *src_image,
833                                       cairo_win32_surface_t *dst,
834                                       cairo_rectangle_int_t src_extents,
835                                       cairo_rectangle_int_t src_r,
836                                       cairo_rectangle_int_t dst_r,
837                                       int alpha,
838                                       cairo_bool_t needs_alpha,
839                                       cairo_bool_t needs_scale)
840 {
841     /* Then do BitBlt, StretchDIBits, StretchBlt, AlphaBlend, or MaskBlt */
842     if (src_image) {
843         if (needs_alpha || needs_scale)
844             return CAIRO_INT_STATUS_UNSUPPORTED;
845
846         if (dst->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHBLT) {
847             BITMAPINFO bi;
848             bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
849             bi.bmiHeader.biWidth = src_image->width;
850             bi.bmiHeader.biHeight = - src_image->height;
851             bi.bmiHeader.biSizeImage = 0;
852             bi.bmiHeader.biXPelsPerMeter = PELS_72DPI;
853             bi.bmiHeader.biYPelsPerMeter = PELS_72DPI;
854             bi.bmiHeader.biPlanes = 1;
855             bi.bmiHeader.biBitCount = 32;
856             bi.bmiHeader.biCompression = BI_RGB;
857             bi.bmiHeader.biClrUsed = 0;
858             bi.bmiHeader.biClrImportant = 0;
859
860             /* StretchDIBits is broken with top-down dibs; you need to do some
861              * special munging to make the coordinate space work (basically,
862              * need to address everything based on the bottom left, instead of top left,
863              * and need to tell it to flip the resulting image.
864              *
865              * See http://blog.vlad1.com/archives/2006/10/26/134/ and comments.
866              */
867             if (!StretchDIBits (dst->dc,
868                                 /* dst x,y,w,h */
869                                 dst_r.x, dst_r.y + dst_r.height - 1,
870                                 dst_r.width, - (int) dst_r.height,
871                                 /* src x,y,w,h */
872                                 src_r.x, src_extents.height - src_r.y + 1,
873                                 src_r.width, - (int) src_r.height,
874                                 src_image->data,
875                                 &bi,
876                                 DIB_RGB_COLORS,
877                                 SRCCOPY))
878                 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(StretchDIBits)");
879         }
880     } else if (!needs_alpha) {
881         /* BitBlt or StretchBlt? */
882         if (!needs_scale && (dst->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT)) {
883             if (!BitBlt (dst->dc,
884                          dst_r.x, dst_r.y,
885                          dst_r.width, dst_r.height,
886                          src->dc,
887                          src_r.x, src_r.y,
888                          SRCCOPY))
889                 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(BitBlt)");
890         } else if (dst->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHBLT) {
891             /* StretchBlt? */
892             /* XXX check if we want HALFTONE, based on the src filter */
893             BOOL success;
894             int oldmode = SetStretchBltMode(dst->dc, HALFTONE);
895             success = StretchBlt(dst->dc,
896                                  dst_r.x, dst_r.y,
897                                  dst_r.width, dst_r.height,
898                                  src->dc,
899                                  src_r.x, src_r.y,
900                                  src_r.width, src_r.height,
901                                  SRCCOPY);
902             SetStretchBltMode(dst->dc, oldmode);
903
904             if (!success)
905                 return _cairo_win32_print_gdi_error ("StretchBlt");
906         }
907     } else if (needs_alpha && !needs_scale) {
908         return _composite_alpha_blend (dst, src, alpha,
909                                        src_r.x, src_r.y, src_r.width, src_r.height,
910                                        dst_r.x, dst_r.y, dst_r.width, dst_r.height);
911     }
912
913     return CAIRO_STATUS_SUCCESS;
914 }
915
916 /* from pixman-private.h */
917 #define MOD(a,b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b))
918
919 static cairo_int_status_t
920 _cairo_win32_surface_composite (cairo_operator_t        op,
921                                 const cairo_pattern_t   *pattern,
922                                 const cairo_pattern_t   *mask_pattern,
923                                 void                    *abstract_dst,
924                                 int                     src_x,
925                                 int                     src_y,
926                                 int                     mask_x,
927                                 int                     mask_y,
928                                 int                     dst_x,
929                                 int                     dst_y,
930                                 unsigned int            width,
931                                 unsigned int            height,
932                                 cairo_region_t         *clip_region)
933 {
934     cairo_win32_surface_t *dst = abstract_dst;
935     cairo_win32_surface_t *src;
936     cairo_surface_pattern_t *src_surface_pattern;
937     int alpha;
938     double scalex, scaley;
939     cairo_fixed_t x0_fixed, y0_fixed;
940     cairo_int_status_t status;
941
942     cairo_bool_t needs_alpha, needs_scale, needs_repeat;
943     cairo_image_surface_t *src_image = NULL;
944
945     cairo_format_t src_format;
946     cairo_rectangle_int_t src_extents;
947
948     cairo_rectangle_int_t src_r = { src_x, src_y, width, height };
949     cairo_rectangle_int_t dst_r = { dst_x, dst_y, width, height };
950
951 #ifdef DEBUG_COMPOSITE
952     fprintf (stderr, "+++ composite: %d %p %p %p [%d %d] [%d %d] [%d %d] %dx%d\n",
953              op, pattern, mask_pattern, abstract_dst, src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height);
954 #endif
955
956     /* If the destination can't do any of these, then
957      * we may as well give up, since this is what we'll
958      * look to for optimization.
959      */
960     if ((dst->flags & (CAIRO_WIN32_SURFACE_CAN_BITBLT |
961                        CAIRO_WIN32_SURFACE_CAN_ALPHABLEND |
962                        CAIRO_WIN32_SURFACE_CAN_STRETCHBLT |
963                        CAIRO_WIN32_SURFACE_CAN_STRETCHDIB))
964         == 0)
965     {
966         goto UNSUPPORTED;
967     }
968
969     if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
970         goto UNSUPPORTED;
971
972     if (pattern->extend != CAIRO_EXTEND_NONE &&
973         pattern->extend != CAIRO_EXTEND_REPEAT)
974         goto UNSUPPORTED;
975
976     if (mask_pattern) {
977         /* FIXME: When we fully support RENDER style 4-channel
978          * masks we need to check r/g/b != 1.0.
979          */
980         if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID)
981             return CAIRO_INT_STATUS_UNSUPPORTED;
982
983         alpha = ((cairo_solid_pattern_t *)mask_pattern)->color.alpha_short >> 8;
984     } else {
985         alpha = 255;
986     }
987
988     src_surface_pattern = (cairo_surface_pattern_t *)pattern;
989     src = (cairo_win32_surface_t *)src_surface_pattern->surface;
990
991     if (src->base.type == CAIRO_SURFACE_TYPE_IMAGE &&
992         dst->flags & (CAIRO_WIN32_SURFACE_CAN_STRETCHDIB))
993     {
994         /* In some very limited cases, we can use StretchDIBits to draw
995          * an image surface directly:
996          *  - source is CAIRO_FORMAT_ARGB32
997          *  - dest is CAIRO_FORMAT_ARGB32
998          *  - alpha is 255
999          *  - operator is SOURCE or OVER
1000          *  - image stride is 4*width
1001          */
1002         src_image = (cairo_image_surface_t*) src;
1003
1004         if (src_image->format != CAIRO_FORMAT_RGB24 ||
1005             dst->format != CAIRO_FORMAT_RGB24 ||
1006             alpha != 255 ||
1007             (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) ||
1008             src_image->stride != (src_image->width * 4))
1009         {
1010             goto UNSUPPORTED;
1011         }
1012
1013         src_format = src_image->format;
1014         src_extents.x = 0;
1015         src_extents.y = 0;
1016         src_extents.width = src_image->width;
1017         src_extents.height = src_image->height;
1018     } else if (src->base.backend != dst->base.backend) {
1019         goto UNSUPPORTED;
1020     } else {
1021         src_format = src->format;
1022         src_extents = src->extents;
1023     }
1024
1025
1026 #ifdef DEBUG_COMPOSITE
1027     fprintf (stderr, "Before check: src size: (%d %d) xy [%d %d] -> dst [%d %d %d %d] {srcmat %f %f %f %f}\n",
1028              src_extents.width, src_extents.height,
1029              src_x, src_y,
1030              dst_x, dst_y, width, height,
1031              pattern->matrix.x0, pattern->matrix.y0, pattern->matrix.xx, pattern->matrix.yy);
1032 #endif
1033
1034     /* We can only use GDI functions if the source and destination rectangles
1035      * are on integer pixel boundaries.  Figure that out here.
1036      */
1037     x0_fixed = _cairo_fixed_from_double(pattern->matrix.x0 / pattern->matrix.xx);
1038     y0_fixed = _cairo_fixed_from_double(pattern->matrix.y0 / pattern->matrix.yy);
1039
1040     if (pattern->matrix.yx != 0.0 ||
1041         pattern->matrix.xy != 0.0 ||
1042         !_cairo_fixed_is_integer(x0_fixed) ||
1043         !_cairo_fixed_is_integer(y0_fixed))
1044     {
1045         goto UNSUPPORTED;
1046     }
1047
1048     scalex = pattern->matrix.xx;
1049     scaley = pattern->matrix.yy;
1050
1051     src_r.x += _cairo_fixed_integer_part(x0_fixed);
1052     src_r.y += _cairo_fixed_integer_part(y0_fixed);
1053
1054     /* Success, right? */
1055     if (scalex == 0.0 || scaley == 0.0)
1056         return CAIRO_STATUS_SUCCESS;
1057
1058     if (scalex != 1.0 || scaley != 1.0)
1059         goto UNSUPPORTED;
1060
1061     /* If the src coordinates are outside of the source surface bounds,
1062      * we have to fix them up, because this is an error for the GDI
1063      * functions.
1064      */
1065
1066 #ifdef DEBUG_COMPOSITE
1067     fprintf (stderr, "before: [%d %d %d %d] -> [%d %d %d %d]\n",
1068              src_r.x, src_r.y, src_r.width, src_r.height,
1069              dst_r.x, dst_r.y, dst_r.width, dst_r.height);
1070     fflush (stderr);
1071 #endif
1072
1073     /* If the src rectangle doesn't wholly lie within the src extents,
1074      * fudge things.  We really need to do fixup on the unpainted
1075      * region -- e.g. the SOURCE operator is broken for areas outside
1076      * of the extents, because it won't clear that area to transparent
1077      * black.
1078      */
1079
1080     if (pattern->extend != CAIRO_EXTEND_REPEAT) {
1081         needs_repeat = FALSE;
1082
1083         /* If the src rect and the extents of the source image don't overlap at all,
1084          * we can't do anything useful here.
1085          */
1086         if (src_r.x > src_extents.width || src_r.y > src_extents.height ||
1087             (src_r.x + src_r.width) < 0 || (src_r.y + src_r.height) < 0)
1088         {
1089             if (op == CAIRO_OPERATOR_OVER)
1090                 return CAIRO_STATUS_SUCCESS;
1091             goto UNSUPPORTED;
1092         }
1093
1094         if (src_r.x < 0) {
1095             src_r.width += src_r.x;
1096             src_r.x = 0;
1097
1098             dst_r.width += src_r.x;
1099             dst_r.x -= src_r.x;
1100         }
1101
1102         if (src_r.y < 0) {
1103             src_r.height += src_r.y;
1104             src_r.y = 0;
1105
1106             dst_r.height += dst_r.y;
1107             dst_r.y -= src_r.y;
1108         }
1109
1110         if (src_r.x + src_r.width > src_extents.width) {
1111             src_r.width = src_extents.width - src_r.x;
1112             dst_r.width = src_r.width;
1113         }
1114
1115         if (src_r.y + src_r.height > src_extents.height) {
1116             src_r.height = src_extents.height - src_r.y;
1117             dst_r.height = src_r.height;
1118         }
1119     } else {
1120         needs_repeat = TRUE;
1121     }
1122
1123     /*
1124      * Operations that we can do:
1125      *
1126      *  RGB OVER  RGB -> BitBlt (same as SOURCE)
1127      *  RGB OVER ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA)
1128      * ARGB OVER ARGB -> AlphaBlend, with AC_SRC_ALPHA
1129      * ARGB OVER  RGB -> AlphaBlend, with AC_SRC_ALPHA; we'll have junk in the dst A byte
1130      * 
1131      *  RGB OVER  RGB + mask -> AlphaBlend, no AC_SRC_ALPHA
1132      *  RGB OVER ARGB + mask -> UNSUPPORTED
1133      * ARGB OVER ARGB + mask -> AlphaBlend, with AC_SRC_ALPHA
1134      * ARGB OVER  RGB + mask -> AlphaBlend, with AC_SRC_ALPHA; junk in the dst A byte
1135      * 
1136      *  RGB SOURCE  RGB -> BitBlt
1137      *  RGB SOURCE ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA)
1138      * ARGB SOURCE ARGB -> BitBlt
1139      * ARGB SOURCE  RGB -> BitBlt
1140      * 
1141      *  RGB SOURCE  RGB + mask -> unsupported
1142      *  RGB SOURCE ARGB + mask -> unsupported
1143      * ARGB SOURCE ARGB + mask -> unsupported
1144      * ARGB SOURCE  RGB + mask -> unsupported
1145      */
1146
1147     /*
1148      * Figure out what action to take.
1149      */
1150     if (op == CAIRO_OPERATOR_OVER) {
1151         if (alpha == 0)
1152             return CAIRO_STATUS_SUCCESS;
1153
1154         if (src_format == dst->format) {
1155             if (alpha == 255 && src_format == CAIRO_FORMAT_RGB24) {
1156                 needs_alpha = FALSE;
1157             } else {
1158                 needs_alpha = TRUE;
1159             }
1160         } else if (src_format == CAIRO_FORMAT_ARGB32 &&
1161                    dst->format == CAIRO_FORMAT_RGB24)
1162         {
1163             needs_alpha = TRUE;
1164         } else {
1165             goto UNSUPPORTED;
1166         }
1167     } else if (alpha == 255 && op == CAIRO_OPERATOR_SOURCE) {
1168         if ((src_format == dst->format) ||
1169             (src_format == CAIRO_FORMAT_ARGB32 && dst->format == CAIRO_FORMAT_RGB24))
1170         {
1171             needs_alpha = FALSE;
1172         } else {
1173             goto UNSUPPORTED;
1174         }
1175     } else {
1176         goto UNSUPPORTED;
1177     }
1178
1179     if (scalex == 1.0 && scaley == 1.0) {
1180         needs_scale = FALSE;
1181     } else {
1182         /* Should never be reached until we turn StretchBlt back on */
1183         needs_scale = TRUE;
1184     }
1185
1186 #ifdef DEBUG_COMPOSITE
1187     fprintf (stderr, "action: [%d %d %d %d] -> [%d %d %d %d]\n",
1188              src_r.x, src_r.y, src_r.width, src_r.height,
1189              dst_r.x, dst_r.y, dst_r.width, dst_r.height);
1190     fflush (stderr);
1191 #endif
1192
1193     status = _cairo_win32_surface_set_clip_region (dst, clip_region);
1194     if (status)
1195         return status;
1196
1197     /* If we need to repeat, we turn the repeated blit into
1198      * a bunch of piece-by-piece blits.
1199      */
1200     if (needs_repeat) {
1201         cairo_rectangle_int_t piece_src_r, piece_dst_r;
1202         uint32_t rendered_width = 0, rendered_height = 0;
1203         uint32_t to_render_height, to_render_width;
1204         int32_t piece_x, piece_y;
1205         int32_t src_start_x = MOD(src_r.x, src_extents.width);
1206         int32_t src_start_y = MOD(src_r.y, src_extents.height);
1207
1208         if (needs_scale)
1209             goto UNSUPPORTED;
1210
1211         /* If both the src and dest have an image, we may as well fall
1212          * back, because it will be faster than our separate blits.
1213          * Our blit code will be fastest when the src is a DDB and the
1214          * destination is a DDB.
1215          */
1216         if ((src_image || src->image) && dst->image)
1217             goto UNSUPPORTED;
1218
1219         /* If the src is not a bitmap but an on-screen (or unknown)
1220          * DC, chances are that fallback will be faster.
1221          */
1222         if (src->bitmap == NULL)
1223             goto UNSUPPORTED;
1224
1225         /* If we can use PatBlt, just do so */
1226         if (!src_image && !needs_alpha)
1227         {
1228             HBRUSH brush;
1229             HGDIOBJ old_brush;
1230             POINT old_brush_origin;
1231
1232             /* Set up the brush with our bitmap */
1233             brush = CreatePatternBrush (src->bitmap);
1234
1235             /* SetBrushOrgEx sets the coordinates in the destination DC of where the
1236              * pattern should start.
1237              */
1238             SetBrushOrgEx (dst->dc, dst_r.x - src_start_x,
1239                            dst_r.y - src_start_y, &old_brush_origin);
1240
1241             old_brush = SelectObject (dst->dc, brush);
1242
1243             PatBlt (dst->dc, dst_r.x, dst_r.y, dst_r.width, dst_r.height, PATCOPY);
1244
1245             /* Restore the old brush and pen */
1246             SetBrushOrgEx (dst->dc, old_brush_origin.x, old_brush_origin.y, NULL);
1247             SelectObject (dst->dc, old_brush);
1248             DeleteObject (brush);
1249
1250             return CAIRO_STATUS_SUCCESS;
1251         }
1252
1253         /* If we were not able to use PatBlt, then manually expand out the blit */
1254
1255         /* Arbitrary factor; we think that going through
1256          * fallback will be faster if we have to do more
1257          * than this amount of blits in either direction.
1258          */
1259         if (dst_r.width / src_extents.width > 5 ||
1260             dst_r.height / src_extents.height > 5)
1261             goto UNSUPPORTED;
1262
1263         for (rendered_height = 0;
1264              rendered_height < dst_r.height;
1265              rendered_height += to_render_height)
1266         {
1267             piece_y = (src_start_y + rendered_height) % src_extents.height;
1268             to_render_height = src_extents.height - piece_y;
1269
1270             if (rendered_height + to_render_height > dst_r.height)
1271                 to_render_height = dst_r.height - rendered_height;
1272
1273             for (rendered_width = 0;
1274                  rendered_width < dst_r.width;
1275                  rendered_width += to_render_width)
1276             {
1277                 piece_x = (src_start_x + rendered_width) % src_extents.width;
1278                 to_render_width = src_extents.width - piece_x;
1279
1280                 if (rendered_width + to_render_width > dst_r.width)
1281                     to_render_width = dst_r.width - rendered_width;
1282
1283                 piece_src_r.x = piece_x;
1284                 piece_src_r.y = piece_y;
1285                 piece_src_r.width = to_render_width;
1286                 piece_src_r.height = to_render_height;
1287
1288                 piece_dst_r.x = dst_r.x + rendered_width;
1289                 piece_dst_r.y = dst_r.y + rendered_height;
1290                 piece_dst_r.width = to_render_width;
1291                 piece_dst_r.height = to_render_height;
1292
1293                 status = _cairo_win32_surface_composite_inner (src, src_image, dst,
1294                                                                src_extents, piece_src_r, piece_dst_r,
1295                                                                alpha, needs_alpha, needs_scale);
1296                 if (status != CAIRO_STATUS_SUCCESS) {
1297                     /* Uh oh.  If something failed, and it's the first
1298                      * piece, then we can jump to UNSUPPORTED. 
1299                      * Otherwise, this is bad times, because part of the
1300                      * rendering was already done. */
1301                     if (rendered_width == 0 &&
1302                         rendered_height == 0)
1303                     {
1304                         goto UNSUPPORTED;
1305                     }
1306
1307                     return status;
1308                 }
1309             }
1310         }
1311     } else {
1312         status = _cairo_win32_surface_composite_inner (src, src_image, dst,
1313                                                        src_extents, src_r, dst_r,
1314                                                        alpha, needs_alpha, needs_scale);
1315     }
1316
1317     if (status == CAIRO_STATUS_SUCCESS)
1318         return status;
1319
1320 UNSUPPORTED:
1321     /* Fall back to image surface directly, if this is a DIB surface */
1322     if (dst->image) {
1323         GdiFlush();
1324
1325 #if 0
1326         return dst->image->backend->composite (op, pattern, mask_pattern,
1327                                                dst->image,
1328                                                src_x, src_y,
1329                                                mask_x, mask_y,
1330                                                dst_x, dst_y,
1331                                                width, height,
1332                                                clip_region);
1333 #endif
1334     }
1335
1336     return CAIRO_INT_STATUS_UNSUPPORTED;
1337 }
1338
1339 /* This big function tells us how to optimize operators for the
1340  * case of solid destination and constant-alpha source
1341  *
1342  * Note: This function needs revisiting if we add support for
1343  *       super-luminescent colors (a == 0, r,g,b > 0)
1344  */
1345 static enum { DO_CLEAR, DO_SOURCE, DO_NOTHING, DO_UNSUPPORTED }
1346 categorize_solid_dest_operator (cairo_operator_t op,
1347                                 unsigned short   alpha)
1348 {
1349     enum { SOURCE_TRANSPARENT, SOURCE_LIGHT, SOURCE_SOLID, SOURCE_OTHER } source;
1350
1351     if (alpha >= 0xff00)
1352         source = SOURCE_SOLID;
1353     else if (alpha < 0x100)
1354         source = SOURCE_TRANSPARENT;
1355     else
1356         source = SOURCE_OTHER;
1357
1358     switch (op) {
1359     case CAIRO_OPERATOR_CLEAR:    /* 0                 0 */
1360     case CAIRO_OPERATOR_OUT:      /* 1 - Ab            0 */
1361         return DO_CLEAR;
1362         break;
1363
1364     case CAIRO_OPERATOR_SOURCE:   /* 1                 0 */
1365     case CAIRO_OPERATOR_IN:       /* Ab                0 */
1366         return DO_SOURCE;
1367         break;
1368
1369     case CAIRO_OPERATOR_OVER:     /* 1            1 - Aa */
1370     case CAIRO_OPERATOR_ATOP:     /* Ab           1 - Aa */
1371         if (source == SOURCE_SOLID)
1372             return DO_SOURCE;
1373         else if (source == SOURCE_TRANSPARENT)
1374             return DO_NOTHING;
1375         else
1376             return DO_UNSUPPORTED;
1377         break;
1378
1379     case CAIRO_OPERATOR_DEST_OUT: /* 0            1 - Aa */
1380     case CAIRO_OPERATOR_XOR:      /* 1 - Ab       1 - Aa */
1381         if (source == SOURCE_SOLID)
1382             return DO_CLEAR;
1383         else if (source == SOURCE_TRANSPARENT)
1384             return DO_NOTHING;
1385         else
1386             return DO_UNSUPPORTED;
1387         break;
1388
1389     case CAIRO_OPERATOR_DEST:     /* 0                 1 */
1390     case CAIRO_OPERATOR_DEST_OVER:/* 1 - Ab            1 */
1391     case CAIRO_OPERATOR_SATURATE: /* min(1,(1-Ab)/Aa)  1 */
1392         return DO_NOTHING;
1393         break;
1394
1395     case CAIRO_OPERATOR_DEST_IN:  /* 0                Aa */
1396     case CAIRO_OPERATOR_DEST_ATOP:/* 1 - Ab           Aa */
1397         if (source == SOURCE_SOLID)
1398             return DO_NOTHING;
1399         else if (source == SOURCE_TRANSPARENT)
1400             return DO_CLEAR;
1401         else
1402             return DO_UNSUPPORTED;
1403         break;
1404
1405     case CAIRO_OPERATOR_ADD:      /* 1                1 */
1406         if (source == SOURCE_TRANSPARENT)
1407             return DO_NOTHING;
1408         else
1409             return DO_UNSUPPORTED;
1410         break;
1411
1412     case CAIRO_OPERATOR_MULTIPLY:
1413     case CAIRO_OPERATOR_SCREEN:
1414     case CAIRO_OPERATOR_OVERLAY:
1415     case CAIRO_OPERATOR_DARKEN:
1416     case CAIRO_OPERATOR_LIGHTEN:
1417     case CAIRO_OPERATOR_COLOR_DODGE:
1418     case CAIRO_OPERATOR_COLOR_BURN:
1419     case CAIRO_OPERATOR_HARD_LIGHT:
1420     case CAIRO_OPERATOR_SOFT_LIGHT:
1421     case CAIRO_OPERATOR_DIFFERENCE:
1422     case CAIRO_OPERATOR_EXCLUSION:
1423     case CAIRO_OPERATOR_HSL_HUE:
1424     case CAIRO_OPERATOR_HSL_SATURATION:
1425     case CAIRO_OPERATOR_HSL_COLOR:
1426     case CAIRO_OPERATOR_HSL_LUMINOSITY:
1427         return DO_UNSUPPORTED;
1428
1429     default:
1430         ASSERT_NOT_REACHED;
1431         return DO_UNSUPPORTED;
1432     }
1433 }
1434
1435 static cairo_int_status_t
1436 _cairo_win32_surface_fill_rectangles (void                      *abstract_surface,
1437                                       cairo_operator_t          op,
1438                                       const cairo_color_t       *color,
1439                                       cairo_rectangle_int_t     *rects,
1440                                       int                       num_rects)
1441 {
1442     cairo_win32_surface_t *surface = abstract_surface;
1443     cairo_status_t status;
1444     COLORREF new_color;
1445     HBRUSH new_brush;
1446     int i;
1447
1448     /* XXXperf If it's not RGB24, we need to do a little more checking
1449      * to figure out when we can use GDI.  We don't have that checking
1450      * anywhere at the moment, so just bail and use the fallback
1451      * paths. */
1452     if (surface->format != CAIRO_FORMAT_RGB24)
1453         return CAIRO_INT_STATUS_UNSUPPORTED;
1454
1455     status = _cairo_win32_surface_set_clip_region (surface, NULL);
1456     if (status)
1457         return status;
1458
1459     /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all
1460      * surfaces with alpha.)
1461      */
1462     switch (categorize_solid_dest_operator (op, color->alpha_short)) {
1463     case DO_CLEAR:
1464         new_color = RGB (0, 0, 0);
1465         break;
1466     case DO_SOURCE:
1467         new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8);
1468         break;
1469     case DO_NOTHING:
1470         return CAIRO_STATUS_SUCCESS;
1471     case DO_UNSUPPORTED:
1472     default:
1473         return CAIRO_INT_STATUS_UNSUPPORTED;
1474     }
1475
1476     new_brush = CreateSolidBrush (new_color);
1477     if (!new_brush)
1478         return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1479
1480     for (i = 0; i < num_rects; i++) {
1481         RECT rect;
1482
1483         rect.left = rects[i].x;
1484         rect.top = rects[i].y;
1485         rect.right = rects[i].x + rects[i].width;
1486         rect.bottom = rects[i].y + rects[i].height;
1487
1488         if (!FillRect (surface->dc, &rect, new_brush))
1489             goto FAIL;
1490     }
1491
1492     DeleteObject (new_brush);
1493
1494     return CAIRO_STATUS_SUCCESS;
1495
1496  FAIL:
1497     status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1498
1499     DeleteObject (new_brush);
1500
1501     return status;
1502 }
1503
1504 cairo_bool_t
1505 _cairo_win32_surface_get_extents (void                    *abstract_surface,
1506                                   cairo_rectangle_int_t   *rectangle)
1507 {
1508     cairo_win32_surface_t *surface = abstract_surface;
1509
1510     *rectangle = surface->extents;
1511     return TRUE;
1512 }
1513
1514 static cairo_status_t
1515 _cairo_win32_surface_flush (void *abstract_surface)
1516 {
1517     return _cairo_win32_surface_set_clip_region (abstract_surface, NULL);
1518 }
1519
1520 #define STACK_GLYPH_SIZE 256
1521
1522 cairo_int_status_t
1523 _cairo_win32_surface_show_glyphs_internal (void                  *surface,
1524                                            cairo_operator_t       op,
1525                                            const cairo_pattern_t *source,
1526                                            cairo_glyph_t         *glyphs,
1527                                            int                    num_glyphs,
1528                                            cairo_scaled_font_t   *scaled_font,
1529                                            const cairo_clip_t    *clip,
1530                                            cairo_bool_t           glyph_indexing)
1531 {
1532 #if CAIRO_HAS_WIN32_FONT
1533     cairo_win32_surface_t *dst = surface;
1534
1535     WORD glyph_buf_stack[STACK_GLYPH_SIZE];
1536     WORD *glyph_buf = glyph_buf_stack;
1537     int dxy_buf_stack[2 * STACK_GLYPH_SIZE];
1538     int *dxy_buf = dxy_buf_stack;
1539
1540     BOOL win_result = 0;
1541     int i, j;
1542
1543     cairo_solid_pattern_t *solid_pattern;
1544     COLORREF color;
1545
1546     cairo_matrix_t device_to_logical;
1547
1548     int start_x, start_y;
1549     double user_x, user_y;
1550     int logical_x, logical_y;
1551     unsigned int glyph_index_option;
1552
1553     /* We can only handle win32 fonts */
1554     if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_WIN32)
1555         return CAIRO_INT_STATUS_UNSUPPORTED;
1556
1557     /* We can only handle opaque solid color sources */
1558     if (!_cairo_pattern_is_opaque_solid(source))
1559         return CAIRO_INT_STATUS_UNSUPPORTED;
1560
1561     /* We can only handle operator SOURCE or OVER with the destination
1562      * having no alpha */
1563     if ((op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) ||
1564         (dst->format != CAIRO_FORMAT_RGB24))
1565         return CAIRO_INT_STATUS_UNSUPPORTED;
1566
1567     /* If we have a fallback mask clip set on the dst, we have
1568      * to go through the fallback path, but only if we're not
1569      * doing this for printing */
1570     if (clip != NULL) {
1571         if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) == 0) {
1572             if (! _cairo_clip_is_region (clip))
1573                 return CAIRO_INT_STATUS_UNSUPPORTED;
1574
1575             _cairo_win32_surface_set_clip_region (surface,
1576                                                   _cairo_clip_get_region (clip));
1577         }
1578     }
1579
1580     solid_pattern = (cairo_solid_pattern_t *)source;
1581     color = RGB(((int)solid_pattern->color.red_short) >> 8,
1582                 ((int)solid_pattern->color.green_short) >> 8,
1583                 ((int)solid_pattern->color.blue_short) >> 8);
1584
1585     cairo_win32_scaled_font_get_device_to_logical(scaled_font, &device_to_logical);
1586
1587     SaveDC(dst->dc);
1588
1589     cairo_win32_scaled_font_select_font(scaled_font, dst->dc);
1590     SetTextColor(dst->dc, color);
1591     SetTextAlign(dst->dc, TA_BASELINE | TA_LEFT);
1592     SetBkMode(dst->dc, TRANSPARENT);
1593
1594     if (num_glyphs > STACK_GLYPH_SIZE) {
1595         glyph_buf = (WORD *) _cairo_malloc_ab (num_glyphs, sizeof(WORD));
1596         dxy_buf = (int *) _cairo_malloc_abc (num_glyphs, sizeof(int), 2);
1597     }
1598
1599     /* It is vital that dx values for dxy_buf are calculated from the delta of
1600      * _logical_ x coordinates (not user x coordinates) or else the sum of all
1601      * previous dx values may start to diverge from the current glyph's x
1602      * coordinate due to accumulated rounding error. As a result strings could
1603      * be painted shorter or longer than expected. */
1604
1605     user_x = glyphs[0].x;
1606     user_y = glyphs[0].y;
1607
1608     cairo_matrix_transform_point(&device_to_logical,
1609                                  &user_x, &user_y);
1610
1611     logical_x = _cairo_lround (user_x);
1612     logical_y = _cairo_lround (user_y);
1613
1614     start_x = logical_x;
1615     start_y = logical_y;
1616
1617     for (i = 0, j = 0; i < num_glyphs; ++i, j = 2 * i) {
1618         glyph_buf[i] = (WORD) glyphs[i].index;
1619         if (i == num_glyphs - 1) {
1620             dxy_buf[j] = 0;
1621             dxy_buf[j+1] = 0;
1622         } else {
1623             double next_user_x = glyphs[i+1].x;
1624             double next_user_y = glyphs[i+1].y;
1625             int next_logical_x, next_logical_y;
1626
1627             cairo_matrix_transform_point(&device_to_logical,
1628                                          &next_user_x, &next_user_y);
1629
1630             next_logical_x = _cairo_lround (next_user_x);
1631             next_logical_y = _cairo_lround (next_user_y);
1632
1633             dxy_buf[j] = _cairo_lround (next_logical_x - logical_x);
1634             dxy_buf[j+1] = _cairo_lround (next_logical_y - logical_y);
1635
1636             logical_x = next_logical_x;
1637             logical_y = next_logical_y;
1638         }
1639     }
1640
1641     if (glyph_indexing)
1642         glyph_index_option = ETO_GLYPH_INDEX;
1643     else
1644         glyph_index_option = 0;
1645
1646     win_result = ExtTextOutW(dst->dc,
1647                              start_x,
1648                              start_y,
1649                              glyph_index_option | ETO_PDY,
1650                              NULL,
1651                              glyph_buf,
1652                              num_glyphs,
1653                              dxy_buf);
1654     if (!win_result) {
1655         _cairo_win32_print_gdi_error("_cairo_win32_surface_show_glyphs(ExtTextOutW failed)");
1656     }
1657
1658     RestoreDC(dst->dc, -1);
1659
1660     if (glyph_buf != glyph_buf_stack) {
1661         free(glyph_buf);
1662         free(dxy_buf);
1663     }
1664     return (win_result) ? CAIRO_STATUS_SUCCESS : CAIRO_INT_STATUS_UNSUPPORTED;
1665 #else
1666     return CAIRO_INT_STATUS_UNSUPPORTED;
1667 #endif
1668 }
1669
1670 #undef STACK_GLYPH_SIZE
1671
1672 cairo_int_status_t
1673 _cairo_win32_surface_show_glyphs (void                  *surface,
1674                                   cairo_operator_t       op,
1675                                   const cairo_pattern_t *source,
1676                                   cairo_glyph_t         *glyphs,
1677                                   int                    num_glyphs,
1678                                   cairo_scaled_font_t   *scaled_font,
1679                                   const cairo_clip_t    *clip)
1680 {
1681     return _cairo_win32_surface_show_glyphs_internal (surface,
1682                                                       op,
1683                                                       source,
1684                                                       glyphs,
1685                                                       num_glyphs,
1686                                                       scaled_font,
1687                                                       clip,
1688                                                       TRUE);
1689 }
1690
1691
1692 /**
1693  * cairo_win32_surface_create:
1694  * @hdc: the DC to create a surface for
1695  *
1696  * Creates a cairo surface that targets the given DC.  The DC will be
1697  * queried for its initial clip extents, and this will be used as the
1698  * size of the cairo surface.  The resulting surface will always be of
1699  * format %CAIRO_FORMAT_RGB24; should you need another surface format,
1700  * you will need to create one through
1701  * cairo_win32_surface_create_with_dib().
1702  *
1703  * Return value: the newly created surface
1704  **/
1705 cairo_surface_t *
1706 cairo_win32_surface_create (HDC hdc)
1707 {
1708     cairo_win32_surface_t *surface;
1709
1710     cairo_format_t format;
1711     RECT rect;
1712
1713     /* Assume that everything coming in as a HDC is RGB24 */
1714     format = CAIRO_FORMAT_RGB24;
1715
1716     surface = malloc (sizeof (cairo_win32_surface_t));
1717     if (surface == NULL)
1718         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1719
1720     if (_cairo_win32_save_initial_clip (hdc, surface) != CAIRO_STATUS_SUCCESS) {
1721         free (surface);
1722         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1723     }
1724
1725     surface->clip_region = NULL;
1726     surface->image = NULL;
1727     surface->format = format;
1728
1729     surface->dc = hdc;
1730     surface->bitmap = NULL;
1731     surface->is_dib = FALSE;
1732     surface->saved_dc_bitmap = NULL;
1733     surface->brush = NULL;
1734     surface->old_brush = NULL;
1735     surface->font_subsets = NULL;
1736
1737     GetClipBox(hdc, &rect);
1738     surface->extents.x = rect.left;
1739     surface->extents.y = rect.top;
1740     surface->extents.width = rect.right - rect.left;
1741     surface->extents.height = rect.bottom - rect.top;
1742
1743     surface->flags = _cairo_win32_flags_for_dc (surface->dc);
1744
1745     _cairo_surface_init (&surface->base,
1746                          &cairo_win32_surface_backend,
1747                          NULL, /* device */
1748                          _cairo_content_from_format (format));
1749
1750     return (cairo_surface_t *)surface;
1751 }
1752
1753 /**
1754  * cairo_win32_surface_create_with_dib:
1755  * @format: format of pixels in the surface to create
1756  * @width: width of the surface, in pixels
1757  * @height: height of the surface, in pixels
1758  *
1759  * Creates a device-independent-bitmap surface not associated with
1760  * any particular existing surface or device context. The created
1761  * bitmap will be uninitialized.
1762  *
1763  * Return value: the newly created surface
1764  *
1765  * Since: 1.2
1766  **/
1767 cairo_surface_t *
1768 cairo_win32_surface_create_with_dib (cairo_format_t format,
1769                                      int            width,
1770                                      int            height)
1771 {
1772     return _cairo_win32_surface_create_for_dc (NULL, format, width, height);
1773 }
1774
1775 /**
1776  * cairo_win32_surface_create_with_ddb:
1777  * @hdc: a DC compatible with the surface to create
1778  * @format: format of pixels in the surface to create
1779  * @width: width of the surface, in pixels
1780  * @height: height of the surface, in pixels
1781  *
1782  * Creates a device-dependent-bitmap surface not associated with
1783  * any particular existing surface or device context. The created
1784  * bitmap will be uninitialized.
1785  *
1786  * Return value: the newly created surface
1787  *
1788  * Since: 1.4
1789  **/
1790 cairo_surface_t *
1791 cairo_win32_surface_create_with_ddb (HDC hdc,
1792                                      cairo_format_t format,
1793                                      int width,
1794                                      int height)
1795 {
1796     cairo_win32_surface_t *new_surf;
1797     HBITMAP ddb;
1798     HDC screen_dc, ddb_dc;
1799     HBITMAP saved_dc_bitmap;
1800
1801     if (format != CAIRO_FORMAT_RGB24)
1802         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
1803 /* XXX handle these eventually
1804         format != CAIRO_FORMAT_A8 ||
1805         format != CAIRO_FORMAT_A1)
1806 */
1807
1808     if (!hdc) {
1809         screen_dc = GetDC (NULL);
1810         hdc = screen_dc;
1811     } else {
1812         screen_dc = NULL;
1813     }
1814
1815     ddb_dc = CreateCompatibleDC (hdc);
1816     if (ddb_dc == NULL) {
1817         new_surf = (cairo_win32_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1818         goto FINISH;
1819     }
1820
1821     ddb = CreateCompatibleBitmap (hdc, width, height);
1822     if (ddb == NULL) {
1823         DeleteDC (ddb_dc);
1824
1825         /* Note that if an app actually does hit this out of memory
1826          * condition, it's going to have lots of other issues, as
1827          * video memory is probably exhausted.  However, it can often
1828          * continue using DIBs instead of DDBs.
1829          */
1830         new_surf = (cairo_win32_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1831         goto FINISH;
1832     }
1833
1834     saved_dc_bitmap = SelectObject (ddb_dc, ddb);
1835
1836     new_surf = (cairo_win32_surface_t*) cairo_win32_surface_create (ddb_dc);
1837     new_surf->bitmap = ddb;
1838     new_surf->saved_dc_bitmap = saved_dc_bitmap;
1839     new_surf->is_dib = FALSE;
1840
1841 FINISH:
1842     if (screen_dc)
1843         ReleaseDC (NULL, screen_dc);
1844
1845     return (cairo_surface_t*) new_surf;
1846 }
1847
1848 /**
1849  * _cairo_surface_is_win32:
1850  * @surface: a #cairo_surface_t
1851  *
1852  * Checks if a surface is a win32 surface.  This will
1853  * return False if this is a win32 printing surface; use
1854  * _cairo_surface_is_win32_printing() to check for that.
1855  *
1856  * Return value: True if the surface is an win32 surface
1857  **/
1858 int
1859 _cairo_surface_is_win32 (cairo_surface_t *surface)
1860 {
1861     return surface->backend == &cairo_win32_surface_backend;
1862 }
1863
1864 /**
1865  * cairo_win32_surface_get_dc
1866  * @surface: a #cairo_surface_t
1867  *
1868  * Returns the HDC associated with this surface, or %NULL if none.
1869  * Also returns %NULL if the surface is not a win32 surface.
1870  *
1871  * A call to cairo_surface_flush() is required before using the HDC to
1872  * ensure that all pending drawing operations are finished and to
1873  * restore any temporary modification cairo has made to its state. A
1874  * call to cairo_surface_mark_dirty() is required after the state or
1875  * the content of the HDC has been modified.
1876  *
1877  * Return value: HDC or %NULL if no HDC available.
1878  *
1879  * Since: 1.2
1880  **/
1881 HDC
1882 cairo_win32_surface_get_dc (cairo_surface_t *surface)
1883 {
1884     cairo_win32_surface_t *winsurf;
1885
1886     if (_cairo_surface_is_win32 (surface)){
1887         winsurf = (cairo_win32_surface_t *) surface;
1888
1889         return winsurf->dc;
1890     }
1891
1892     if (_cairo_surface_is_paginated (surface)) {
1893         cairo_surface_t *target;
1894
1895         target = _cairo_paginated_surface_get_target (surface);
1896
1897         if (_cairo_surface_is_win32_printing (target)) {
1898             winsurf = (cairo_win32_surface_t *) target;
1899
1900             return winsurf->dc;
1901         }
1902     }
1903
1904     return NULL;
1905 }
1906
1907 /**
1908  * cairo_win32_surface_get_image
1909  * @surface: a #cairo_surface_t
1910  *
1911  * Returns a #cairo_surface_t image surface that refers to the same bits
1912  * as the DIB of the Win32 surface.  If the passed-in win32 surface
1913  * is not a DIB surface, %NULL is returned.
1914  *
1915  * Return value: a #cairo_surface_t (owned by the win32 #cairo_surface_t),
1916  * or %NULL if the win32 surface is not a DIB.
1917  *
1918  * Since: 1.4
1919  */
1920 cairo_surface_t *
1921 cairo_win32_surface_get_image (cairo_surface_t *surface)
1922 {
1923     if (!_cairo_surface_is_win32(surface))
1924         return NULL;
1925
1926     return ((cairo_win32_surface_t*)surface)->image;
1927 }
1928
1929 static const cairo_surface_backend_t cairo_win32_surface_backend = {
1930     CAIRO_SURFACE_TYPE_WIN32,
1931     _cairo_win32_surface_finish,
1932
1933     _cairo_default_context_create,
1934
1935     _cairo_win32_surface_create_similar,
1936     NULL,
1937     _cairo_win32_surface_map_to_image,
1938     _cairo_win32_surface_unmap_image,
1939
1940     _cairo_win32_surface_acquire_source_image,
1941     _cairo_win32_surface_release_source_image,
1942     NULL,  /* snapshot */
1943
1944     NULL, /* copy_page */
1945     NULL, /* show_page */
1946
1947     _cairo_win32_surface_get_extents,
1948     NULL, /* get_font_options */
1949
1950     _cairo_win32_surface_flush,
1951     NULL, /* mark_dirty_rectangle */
1952
1953     NULL, /* paint */
1954     NULL, /* mask */
1955     NULL, /* stroke */
1956     NULL, /* fill */
1957     NULL, /* fill/stroke */
1958     _cairo_win32_surface_show_glyphs,
1959 };
1960
1961 /* Notes:
1962  *
1963  * Win32 alpha-understanding functions
1964  *
1965  * BitBlt - will copy full 32 bits from a 32bpp DIB to result
1966  *          (so it's safe to use for ARGB32->ARGB32 SOURCE blits)
1967  *          (but not safe going RGB24->ARGB32, if RGB24 is also represented
1968  *           as a 32bpp DIB, since the alpha isn't discarded!)
1969  *
1970  * AlphaBlend - if both the source and dest have alpha, even if AC_SRC_ALPHA isn't set,
1971  *              it will still copy over the src alpha, because the SCA value (255) will be
1972  *              multiplied by all the src components.
1973  */
1974
1975
1976 cairo_int_status_t
1977 _cairo_win32_save_initial_clip (HDC hdc, cairo_win32_surface_t *surface)
1978 {
1979     RECT rect;
1980     int clipBoxType;
1981     int gm;
1982     XFORM saved_xform;
1983
1984     /* GetClipBox/GetClipRgn and friends interact badly with a world transform
1985      * set.  GetClipBox returns values in logical (transformed) coordinates;
1986      * it's unclear what GetClipRgn returns, because the region is empty in the
1987      * case of a SIMPLEREGION clip, but I assume device (untransformed) coordinates.
1988      * Similarly, IntersectClipRect works in logical units, whereas SelectClipRgn
1989      * works in device units.
1990      *
1991      * So, avoid the whole mess and get rid of the world transform
1992      * while we store our initial data and when we restore initial coordinates.
1993      *
1994      * XXX we may need to modify x/y by the ViewportOrg or WindowOrg
1995      * here in GM_COMPATIBLE; unclear.
1996      */
1997     gm = GetGraphicsMode (hdc);
1998     if (gm == GM_ADVANCED) {
1999         GetWorldTransform (hdc, &saved_xform);
2000         ModifyWorldTransform (hdc, NULL, MWT_IDENTITY);
2001     }
2002
2003     clipBoxType = GetClipBox (hdc, &rect);
2004     if (clipBoxType == ERROR) {
2005         _cairo_win32_print_gdi_error ("cairo_win32_surface_create");
2006         SetGraphicsMode (hdc, gm);
2007         /* XXX: Can we make a more reasonable guess at the error cause here? */
2008         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2009     }
2010
2011     surface->clip_rect.x = rect.left;
2012     surface->clip_rect.y = rect.top;
2013     surface->clip_rect.width = rect.right - rect.left;
2014     surface->clip_rect.height = rect.bottom - rect.top;
2015
2016     surface->initial_clip_rgn = NULL;
2017     surface->had_simple_clip = FALSE;
2018
2019     if (clipBoxType == COMPLEXREGION) {
2020         surface->initial_clip_rgn = CreateRectRgn (0, 0, 0, 0);
2021         if (GetClipRgn (hdc, surface->initial_clip_rgn) <= 0) {
2022             DeleteObject(surface->initial_clip_rgn);
2023             surface->initial_clip_rgn = NULL;
2024         }
2025     } else if (clipBoxType == SIMPLEREGION) {
2026         surface->had_simple_clip = TRUE;
2027     }
2028
2029     if (gm == GM_ADVANCED)
2030         SetWorldTransform (hdc, &saved_xform);
2031
2032     return CAIRO_STATUS_SUCCESS;
2033 }
2034
2035 cairo_int_status_t
2036 _cairo_win32_restore_initial_clip (cairo_win32_surface_t *surface)
2037 {
2038     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
2039
2040     XFORM saved_xform;
2041     int gm = GetGraphicsMode (surface->dc);
2042     if (gm == GM_ADVANCED) {
2043         GetWorldTransform (surface->dc, &saved_xform);
2044         ModifyWorldTransform (surface->dc, NULL, MWT_IDENTITY);
2045     }
2046
2047     /* initial_clip_rgn will either be a real region or NULL (which means reset to no clip region) */
2048     SelectClipRgn (surface->dc, surface->initial_clip_rgn);
2049
2050     if (surface->had_simple_clip) {
2051         /* then if we had a simple clip, intersect */
2052         IntersectClipRect (surface->dc,
2053                            surface->clip_rect.x,
2054                            surface->clip_rect.y,
2055                            surface->clip_rect.x + surface->clip_rect.width,
2056                            surface->clip_rect.y + surface->clip_rect.height);
2057     }
2058
2059     if (gm == GM_ADVANCED)
2060         SetWorldTransform (surface->dc, &saved_xform);
2061
2062     return status;
2063 }
2064
2065 void
2066 _cairo_win32_debug_dump_hrgn (HRGN rgn, char *header)
2067 {
2068     RGNDATA *rd;
2069     unsigned int z;
2070
2071     if (header)
2072         fprintf (stderr, "%s\n", header);
2073
2074     if (rgn == NULL) {
2075         fprintf (stderr, " NULL\n");
2076     }
2077
2078     z = GetRegionData(rgn, 0, NULL);
2079     rd = (RGNDATA*) malloc(z);
2080     z = GetRegionData(rgn, z, rd);
2081
2082     fprintf (stderr, " %ld rects, bounds: %ld %ld %ld %ld\n",
2083              rd->rdh.nCount,
2084              rd->rdh.rcBound.left,
2085              rd->rdh.rcBound.top,
2086              rd->rdh.rcBound.right - rd->rdh.rcBound.left,
2087              rd->rdh.rcBound.bottom - rd->rdh.rcBound.top);
2088
2089     for (z = 0; z < rd->rdh.nCount; z++) {
2090         RECT r = ((RECT*)rd->Buffer)[z];
2091         fprintf (stderr, " [%d]: [%ld %ld %ld %ld]\n",
2092                  z, r.left, r.top, r.right - r.left, r.bottom - r.top);
2093     }
2094
2095     free(rd);
2096     fflush (stderr);
2097 }