Changes.
[cairo/gpu.git] / src / cairo-win32-surface.c
blob6b48dba24ffdb8263a9d97113758ecb6b994d0b9
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 cairo_content_t content,
435 int src_x,
436 int src_y,
437 int width,
438 int height,
439 int *clone_offset_x,
440 int *clone_offset_y,
441 cairo_surface_t **clone_out)
443 cairo_content_t src_content;
444 cairo_surface_t *new_surface;
445 cairo_status_t status;
446 cairo_surface_pattern_t pattern;
448 src_content = src->content & content;
449 new_surface =
450 _cairo_win32_surface_create_similar_internal (abstract_surface,
451 src_content,
452 width, height,
453 FALSE);
454 if (new_surface == NULL)
455 return CAIRO_INT_STATUS_UNSUPPORTED;
457 status = new_surface->status;
458 if (status)
459 return status;
461 _cairo_pattern_init_for_surface (&pattern, src);
463 status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
464 &pattern.base,
465 NULL,
466 new_surface,
467 src_x, src_y,
468 0, 0,
469 0, 0,
470 width, height);
472 _cairo_pattern_fini (&pattern.base);
474 if (status == CAIRO_STATUS_SUCCESS) {
475 *clone_offset_x = src_x;
476 *clone_offset_y = src_y;
477 *clone_out = new_surface;
478 } else
479 cairo_surface_destroy (new_surface);
481 return status;
485 cairo_status_t
486 _cairo_win32_surface_finish (void *abstract_surface)
488 cairo_win32_surface_t *surface = abstract_surface;
490 if (surface->image)
491 cairo_surface_destroy (surface->image);
493 /* If we created the Bitmap and DC, destroy them */
494 if (surface->bitmap) {
495 SelectObject (surface->dc, surface->saved_dc_bitmap);
496 DeleteObject (surface->bitmap);
497 DeleteDC (surface->dc);
498 } else {
499 _cairo_win32_restore_initial_clip (surface);
502 if (surface->initial_clip_rgn)
503 DeleteObject (surface->initial_clip_rgn);
505 if (surface->font_subsets != NULL)
506 _cairo_scaled_font_subsets_destroy (surface->font_subsets);
508 return CAIRO_STATUS_SUCCESS;
511 static cairo_status_t
512 _cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
513 int x,
514 int y,
515 int width,
516 int height,
517 cairo_win32_surface_t **local_out)
519 cairo_win32_surface_t *local;
520 cairo_int_status_t status;
521 cairo_content_t content = _cairo_content_from_format (surface->format);
523 local =
524 (cairo_win32_surface_t *) _cairo_win32_surface_create_similar_internal
525 (surface, content, width, height, TRUE);
526 if (local == NULL)
527 return CAIRO_INT_STATUS_UNSUPPORTED;
528 if (local->base.status)
529 return local->base.status;
531 status = CAIRO_INT_STATUS_UNSUPPORTED;
533 /* Only BitBlt if the source surface supports it. */
534 if ((surface->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT) &&
535 BitBlt (local->dc,
536 0, 0,
537 width, height,
538 surface->dc,
539 x, y,
540 SRCCOPY))
542 status = CAIRO_STATUS_SUCCESS;
545 if (status) {
546 /* If we failed here, most likely the source or dest doesn't
547 * support BitBlt/AlphaBlend (e.g. a printer).
548 * You can't reliably get bits from a printer DC, so just fill in
549 * the surface as white (common case for printing).
552 RECT r;
553 r.left = r.top = 0;
554 r.right = width;
555 r.bottom = height;
556 FillRect(local->dc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
559 *local_out = local;
561 return CAIRO_STATUS_SUCCESS;
564 static cairo_status_t
565 _cairo_win32_surface_acquire_source_image (void *abstract_surface,
566 cairo_image_surface_t **image_out,
567 void **image_extra)
569 cairo_win32_surface_t *surface = abstract_surface;
570 cairo_win32_surface_t *local = NULL;
571 cairo_status_t status;
573 if (surface->image) {
574 *image_out = (cairo_image_surface_t *)surface->image;
575 *image_extra = NULL;
577 return CAIRO_STATUS_SUCCESS;
580 status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0,
581 surface->extents.width,
582 surface->extents.height, &local);
583 if (status)
584 return status;
586 *image_out = (cairo_image_surface_t *)local->image;
587 *image_extra = local;
589 return CAIRO_STATUS_SUCCESS;
592 static void
593 _cairo_win32_surface_release_source_image (void *abstract_surface,
594 cairo_image_surface_t *image,
595 void *image_extra)
597 cairo_win32_surface_t *local = image_extra;
599 if (local)
600 cairo_surface_destroy ((cairo_surface_t *)local);
603 static cairo_status_t
604 _cairo_win32_surface_acquire_dest_image (void *abstract_surface,
605 cairo_rectangle_int_t *interest_rect,
606 cairo_image_surface_t **image_out,
607 cairo_rectangle_int_t *image_rect,
608 void **image_extra)
610 cairo_win32_surface_t *surface = abstract_surface;
611 cairo_win32_surface_t *local = NULL;
612 cairo_status_t status;
613 RECT clip_box;
614 int x1, y1, x2, y2;
616 if (surface->image) {
617 GdiFlush();
619 image_rect->x = 0;
620 image_rect->y = 0;
621 image_rect->width = surface->extents.width;
622 image_rect->height = surface->extents.height;
624 *image_out = (cairo_image_surface_t *)surface->image;
625 *image_extra = NULL;
627 return CAIRO_STATUS_SUCCESS;
630 if (GetClipBox (surface->dc, &clip_box) == ERROR)
631 return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
633 x1 = clip_box.left;
634 x2 = clip_box.right;
635 y1 = clip_box.top;
636 y2 = clip_box.bottom;
638 if (interest_rect->x > x1)
639 x1 = interest_rect->x;
640 if (interest_rect->y > y1)
641 y1 = interest_rect->y;
642 if ((int) (interest_rect->x + interest_rect->width) < x2)
643 x2 = interest_rect->x + interest_rect->width;
644 if ((int) (interest_rect->y + interest_rect->height) < y2)
645 y2 = interest_rect->y + interest_rect->height;
647 if (x1 >= x2 || y1 >= y2) {
648 *image_out = NULL;
649 *image_extra = NULL;
651 return CAIRO_STATUS_SUCCESS;
654 status = _cairo_win32_surface_get_subimage (abstract_surface,
655 x1, y1, x2 - x1, y2 - y1,
656 &local);
657 if (status)
658 return status;
660 *image_out = (cairo_image_surface_t *)local->image;
661 *image_extra = local;
663 image_rect->x = x1;
664 image_rect->y = y1;
665 image_rect->width = x2 - x1;
666 image_rect->height = y2 - y1;
668 return CAIRO_STATUS_SUCCESS;
671 static void
672 _cairo_win32_surface_release_dest_image (void *abstract_surface,
673 cairo_rectangle_int_t *interest_rect,
674 cairo_image_surface_t *image,
675 cairo_rectangle_int_t *image_rect,
676 void *image_extra)
678 cairo_win32_surface_t *surface = abstract_surface;
679 cairo_win32_surface_t *local = image_extra;
681 if (!local)
682 return;
684 if (!BitBlt (surface->dc,
685 image_rect->x, image_rect->y,
686 image_rect->width, image_rect->height,
687 local->dc,
688 0, 0,
689 SRCCOPY))
690 _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image");
692 cairo_surface_destroy ((cairo_surface_t *)local);
695 #if !defined(AC_SRC_OVER)
696 #define AC_SRC_OVER 0x00
697 #pragma pack(1)
698 typedef struct {
699 BYTE BlendOp;
700 BYTE BlendFlags;
701 BYTE SourceConstantAlpha;
702 BYTE AlphaFormat;
703 }BLENDFUNCTION;
704 #pragma pack()
705 #endif
707 /* for compatibility with VC++ 6 */
708 #ifndef AC_SRC_ALPHA
709 #define AC_SRC_ALPHA 0x01
710 #endif
712 typedef BOOL (WINAPI *cairo_alpha_blend_func_t) (HDC hdcDest,
713 int nXOriginDest,
714 int nYOriginDest,
715 int nWidthDest,
716 int hHeightDest,
717 HDC hdcSrc,
718 int nXOriginSrc,
719 int nYOriginSrc,
720 int nWidthSrc,
721 int nHeightSrc,
722 BLENDFUNCTION blendFunction);
724 static cairo_int_status_t
725 _composite_alpha_blend (cairo_win32_surface_t *dst,
726 cairo_win32_surface_t *src,
727 int alpha,
728 int src_x,
729 int src_y,
730 int src_w,
731 int src_h,
732 int dst_x,
733 int dst_y,
734 int dst_w,
735 int dst_h)
737 static unsigned alpha_blend_checked = FALSE;
738 static cairo_alpha_blend_func_t alpha_blend = NULL;
740 BLENDFUNCTION blend_function;
742 /* Check for AlphaBlend dynamically to allow compiling on
743 * MSVC 6 and use on older windows versions
745 if (!alpha_blend_checked) {
746 OSVERSIONINFO os;
748 os.dwOSVersionInfoSize = sizeof (os);
749 GetVersionEx (&os);
751 /* If running on Win98, disable using AlphaBlend()
752 * to avoid Win98 AlphaBlend() bug */
753 if (VER_PLATFORM_WIN32_WINDOWS != os.dwPlatformId ||
754 os.dwMajorVersion != 4 || os.dwMinorVersion != 10)
756 HMODULE msimg32_dll = LoadLibraryW (L"msimg32");
758 if (msimg32_dll != NULL)
759 alpha_blend = (cairo_alpha_blend_func_t)GetProcAddress (msimg32_dll,
760 "AlphaBlend");
763 alpha_blend_checked = TRUE;
766 if (alpha_blend == NULL)
767 return CAIRO_INT_STATUS_UNSUPPORTED;
768 if (!(dst->flags & CAIRO_WIN32_SURFACE_CAN_ALPHABLEND))
769 return CAIRO_INT_STATUS_UNSUPPORTED;
770 if (src->format == CAIRO_FORMAT_RGB24 && dst->format == CAIRO_FORMAT_ARGB32)
771 return CAIRO_INT_STATUS_UNSUPPORTED;
773 blend_function.BlendOp = AC_SRC_OVER;
774 blend_function.BlendFlags = 0;
775 blend_function.SourceConstantAlpha = alpha;
776 blend_function.AlphaFormat = (src->format == CAIRO_FORMAT_ARGB32) ? AC_SRC_ALPHA : 0;
778 if (!alpha_blend (dst->dc,
779 dst_x, dst_y,
780 dst_w, dst_h,
781 src->dc,
782 src_x, src_y,
783 src_w, src_h,
784 blend_function))
785 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(AlphaBlend)");
787 return CAIRO_STATUS_SUCCESS;
790 static cairo_int_status_t
791 _cairo_win32_surface_composite_inner (cairo_win32_surface_t *src,
792 cairo_image_surface_t *src_image,
793 cairo_win32_surface_t *dst,
794 cairo_rectangle_int_t src_extents,
795 cairo_rectangle_int_t src_r,
796 cairo_rectangle_int_t dst_r,
797 int alpha,
798 cairo_bool_t needs_alpha,
799 cairo_bool_t needs_scale)
801 /* Then do BitBlt, StretchDIBits, StretchBlt, AlphaBlend, or MaskBlt */
802 if (src_image) {
803 if (needs_alpha || needs_scale)
804 return CAIRO_INT_STATUS_UNSUPPORTED;
806 if (dst->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHBLT) {
807 BITMAPINFO bi;
808 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
809 bi.bmiHeader.biWidth = src_image->width;
810 bi.bmiHeader.biHeight = - src_image->height;
811 bi.bmiHeader.biSizeImage = 0;
812 bi.bmiHeader.biXPelsPerMeter = PELS_72DPI;
813 bi.bmiHeader.biYPelsPerMeter = PELS_72DPI;
814 bi.bmiHeader.biPlanes = 1;
815 bi.bmiHeader.biBitCount = 32;
816 bi.bmiHeader.biCompression = BI_RGB;
817 bi.bmiHeader.biClrUsed = 0;
818 bi.bmiHeader.biClrImportant = 0;
820 /* StretchDIBits is broken with top-down dibs; you need to do some
821 * special munging to make the coordinate space work (basically,
822 * need to address everything based on the bottom left, instead of top left,
823 * and need to tell it to flip the resulting image.
825 * See http://blog.vlad1.com/archives/2006/10/26/134/ and comments.
827 if (!StretchDIBits (dst->dc,
828 /* dst x,y,w,h */
829 dst_r.x, dst_r.y + dst_r.height - 1,
830 dst_r.width, - (int) dst_r.height,
831 /* src x,y,w,h */
832 src_r.x, src_extents.height - src_r.y + 1,
833 src_r.width, - (int) src_r.height,
834 src_image->data,
835 &bi,
836 DIB_RGB_COLORS,
837 SRCCOPY))
838 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(StretchDIBits)");
840 } else if (!needs_alpha) {
841 /* BitBlt or StretchBlt? */
842 if (!needs_scale && (dst->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT)) {
843 if (!BitBlt (dst->dc,
844 dst_r.x, dst_r.y,
845 dst_r.width, dst_r.height,
846 src->dc,
847 src_r.x, src_r.y,
848 SRCCOPY))
849 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(BitBlt)");
850 } else if (dst->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHBLT) {
851 /* StretchBlt? */
852 /* XXX check if we want HALFTONE, based on the src filter */
853 BOOL success;
854 int oldmode = SetStretchBltMode(dst->dc, HALFTONE);
855 success = StretchBlt(dst->dc,
856 dst_r.x, dst_r.y,
857 dst_r.width, dst_r.height,
858 src->dc,
859 src_r.x, src_r.y,
860 src_r.width, src_r.height,
861 SRCCOPY);
862 SetStretchBltMode(dst->dc, oldmode);
864 if (!success)
865 return _cairo_win32_print_gdi_error ("StretchBlt");
867 } else if (needs_alpha && !needs_scale) {
868 return _composite_alpha_blend (dst, src, alpha,
869 src_r.x, src_r.y, src_r.width, src_r.height,
870 dst_r.x, dst_r.y, dst_r.width, dst_r.height);
873 return CAIRO_STATUS_SUCCESS;
876 /* from pixman-private.h */
877 #define MOD(a,b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b))
879 static cairo_int_status_t
880 _cairo_win32_surface_composite (cairo_operator_t op,
881 const cairo_pattern_t *pattern,
882 const cairo_pattern_t *mask_pattern,
883 void *abstract_dst,
884 int src_x,
885 int src_y,
886 int mask_x,
887 int mask_y,
888 int dst_x,
889 int dst_y,
890 unsigned int width,
891 unsigned int height)
893 cairo_win32_surface_t *dst = abstract_dst;
894 cairo_win32_surface_t *src;
895 cairo_surface_pattern_t *src_surface_pattern;
896 int alpha;
897 double scalex, scaley;
898 cairo_fixed_t x0_fixed, y0_fixed;
899 cairo_int_status_t status;
901 cairo_bool_t needs_alpha, needs_scale, needs_repeat;
902 cairo_image_surface_t *src_image = NULL;
904 cairo_format_t src_format;
905 cairo_rectangle_int_t src_extents;
907 cairo_rectangle_int_t src_r = { src_x, src_y, width, height };
908 cairo_rectangle_int_t dst_r = { dst_x, dst_y, width, height };
910 #ifdef DEBUG_COMPOSITE
911 fprintf (stderr, "+++ composite: %d %p %p %p [%d %d] [%d %d] [%d %d] %dx%d\n",
912 op, pattern, mask_pattern, abstract_dst, src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height);
913 #endif
915 /* If the destination can't do any of these, then
916 * we may as well give up, since this is what we'll
917 * look to for optimization.
919 if ((dst->flags & (CAIRO_WIN32_SURFACE_CAN_BITBLT |
920 CAIRO_WIN32_SURFACE_CAN_ALPHABLEND |
921 CAIRO_WIN32_SURFACE_CAN_STRETCHBLT |
922 CAIRO_WIN32_SURFACE_CAN_STRETCHDIB))
923 == 0)
925 goto UNSUPPORTED;
928 if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
929 goto UNSUPPORTED;
931 if (pattern->extend != CAIRO_EXTEND_NONE &&
932 pattern->extend != CAIRO_EXTEND_REPEAT)
933 goto UNSUPPORTED;
935 if (mask_pattern) {
936 /* FIXME: When we fully support RENDER style 4-channel
937 * masks we need to check r/g/b != 1.0.
939 if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID)
940 return CAIRO_INT_STATUS_UNSUPPORTED;
942 alpha = ((cairo_solid_pattern_t *)mask_pattern)->color.alpha_short >> 8;
943 } else {
944 alpha = 255;
947 src_surface_pattern = (cairo_surface_pattern_t *)pattern;
948 src = (cairo_win32_surface_t *)src_surface_pattern->surface;
950 if (src->base.type == CAIRO_SURFACE_TYPE_IMAGE &&
951 dst->flags & (CAIRO_WIN32_SURFACE_CAN_STRETCHDIB))
953 /* In some very limited cases, we can use StretchDIBits to draw
954 * an image surface directly:
955 * - source is CAIRO_FORMAT_ARGB32
956 * - dest is CAIRO_FORMAT_ARGB32
957 * - alpha is 255
958 * - operator is SOURCE or OVER
959 * - image stride is 4*width
961 src_image = (cairo_image_surface_t*) src;
963 if (src_image->format != CAIRO_FORMAT_RGB24 ||
964 dst->format != CAIRO_FORMAT_RGB24 ||
965 alpha != 255 ||
966 (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) ||
967 src_image->stride != (src_image->width * 4))
969 goto UNSUPPORTED;
972 src_format = src_image->format;
973 src_extents.x = 0;
974 src_extents.y = 0;
975 src_extents.width = src_image->width;
976 src_extents.height = src_image->height;
977 } else if (src->base.backend != dst->base.backend) {
978 goto UNSUPPORTED;
979 } else {
980 src_format = src->format;
981 src_extents = src->extents;
985 #ifdef DEBUG_COMPOSITE
986 fprintf (stderr, "Before check: src size: (%d %d) xy [%d %d] -> dst [%d %d %d %d] {srcmat %f %f %f %f}\n",
987 src_extents.width, src_extents.height,
988 src_x, src_y,
989 dst_x, dst_y, width, height,
990 pattern->matrix.x0, pattern->matrix.y0, pattern->matrix.xx, pattern->matrix.yy);
991 #endif
993 /* We can only use GDI functions if the source and destination rectangles
994 * are on integer pixel boundaries. Figure that out here.
996 x0_fixed = _cairo_fixed_from_double(pattern->matrix.x0 / pattern->matrix.xx);
997 y0_fixed = _cairo_fixed_from_double(pattern->matrix.y0 / pattern->matrix.yy);
999 if (pattern->matrix.yx != 0.0 ||
1000 pattern->matrix.xy != 0.0 ||
1001 !_cairo_fixed_is_integer(x0_fixed) ||
1002 !_cairo_fixed_is_integer(y0_fixed))
1004 goto UNSUPPORTED;
1007 scalex = pattern->matrix.xx;
1008 scaley = pattern->matrix.yy;
1010 src_r.x += _cairo_fixed_integer_part(x0_fixed);
1011 src_r.y += _cairo_fixed_integer_part(y0_fixed);
1013 /* Success, right? */
1014 if (scalex == 0.0 || scaley == 0.0)
1015 return CAIRO_STATUS_SUCCESS;
1017 if (scalex != 1.0 || scaley != 1.0)
1018 goto UNSUPPORTED;
1020 /* If the src coordinates are outside of the source surface bounds,
1021 * we have to fix them up, because this is an error for the GDI
1022 * functions.
1025 #ifdef DEBUG_COMPOSITE
1026 fprintf (stderr, "before: [%d %d %d %d] -> [%d %d %d %d]\n",
1027 src_r.x, src_r.y, src_r.width, src_r.height,
1028 dst_r.x, dst_r.y, dst_r.width, dst_r.height);
1029 fflush (stderr);
1030 #endif
1032 /* If the src recangle doesn't wholly lie within the src extents,
1033 * fudge things. We really need to do fixup on the unpainted
1034 * region -- e.g. the SOURCE operator is broken for areas outside
1035 * of the extents, because it won't clear that area to transparent
1036 * black.
1039 if (pattern->extend != CAIRO_EXTEND_REPEAT) {
1040 needs_repeat = FALSE;
1042 /* If the src rect and the extents of the source image don't overlap at all,
1043 * we can't do anything useful here.
1045 if (src_r.x > src_extents.width || src_r.y > src_extents.height ||
1046 (src_r.x + src_r.width) < 0 || (src_r.y + src_r.height) < 0)
1048 if (op == CAIRO_OPERATOR_OVER)
1049 return CAIRO_STATUS_SUCCESS;
1050 goto UNSUPPORTED;
1053 if (src_r.x < 0) {
1054 src_r.width += src_r.x;
1055 src_r.x = 0;
1057 dst_r.width += src_r.x;
1058 dst_r.x -= src_r.x;
1061 if (src_r.y < 0) {
1062 src_r.height += src_r.y;
1063 src_r.y = 0;
1065 dst_r.height += dst_r.y;
1066 dst_r.y -= src_r.y;
1069 if (src_r.x + src_r.width > src_extents.width) {
1070 src_r.width = src_extents.width - src_r.x;
1071 dst_r.width = src_r.width;
1074 if (src_r.y + src_r.height > src_extents.height) {
1075 src_r.height = src_extents.height - src_r.y;
1076 dst_r.height = src_r.height;
1078 } else {
1079 needs_repeat = TRUE;
1083 * Operations that we can do:
1085 * RGB OVER RGB -> BitBlt (same as SOURCE)
1086 * RGB OVER ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA)
1087 * ARGB OVER ARGB -> AlphaBlend, with AC_SRC_ALPHA
1088 * ARGB OVER RGB -> AlphaBlend, with AC_SRC_ALPHA; we'll have junk in the dst A byte
1090 * RGB OVER RGB + mask -> AlphaBlend, no AC_SRC_ALPHA
1091 * RGB OVER ARGB + mask -> UNSUPPORTED
1092 * ARGB OVER ARGB + mask -> AlphaBlend, with AC_SRC_ALPHA
1093 * ARGB OVER RGB + mask -> AlphaBlend, with AC_SRC_ALPHA; junk in the dst A byte
1095 * RGB SOURCE RGB -> BitBlt
1096 * RGB SOURCE ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA)
1097 * ARGB SOURCE ARGB -> BitBlt
1098 * ARGB SOURCE RGB -> BitBlt
1100 * RGB SOURCE RGB + mask -> unsupported
1101 * RGB SOURCE ARGB + mask -> unsupported
1102 * ARGB SOURCE ARGB + mask -> unsupported
1103 * ARGB SOURCE RGB + mask -> unsupported
1107 * Figure out what action to take.
1109 if (op == CAIRO_OPERATOR_OVER) {
1110 if (alpha == 0)
1111 return CAIRO_STATUS_SUCCESS;
1113 if (src_format == dst->format) {
1114 if (alpha == 255 && src_format == CAIRO_FORMAT_RGB24) {
1115 needs_alpha = FALSE;
1116 } else {
1117 needs_alpha = TRUE;
1119 } else if (src_format == CAIRO_FORMAT_ARGB32 &&
1120 dst->format == CAIRO_FORMAT_RGB24)
1122 needs_alpha = TRUE;
1123 } else {
1124 goto UNSUPPORTED;
1126 } else if (alpha == 255 && op == CAIRO_OPERATOR_SOURCE) {
1127 if ((src_format == dst->format) ||
1128 (src_format == CAIRO_FORMAT_ARGB32 && dst->format == CAIRO_FORMAT_RGB24))
1130 needs_alpha = FALSE;
1131 } else {
1132 goto UNSUPPORTED;
1134 } else {
1135 goto UNSUPPORTED;
1138 if (scalex == 1.0 && scaley == 1.0) {
1139 needs_scale = FALSE;
1140 } else {
1141 /* Should never be reached until we turn StretchBlt back on */
1142 needs_scale = TRUE;
1145 #ifdef DEBUG_COMPOSITE
1146 fprintf (stderr, "action: [%d %d %d %d] -> [%d %d %d %d]\n",
1147 src_r.x, src_r.y, src_r.width, src_r.height,
1148 dst_r.x, dst_r.y, dst_r.width, dst_r.height);
1149 fflush (stderr);
1150 #endif
1152 /* If we need to repeat, we turn the repeated blit into
1153 * a bunch of piece-by-piece blits.
1155 if (needs_repeat) {
1156 cairo_rectangle_int_t piece_src_r, piece_dst_r;
1157 uint32_t rendered_width = 0, rendered_height = 0;
1158 uint32_t to_render_height, to_render_width;
1159 int32_t piece_x, piece_y;
1160 int32_t src_start_x = MOD(src_r.x, src_extents.width);
1161 int32_t src_start_y = MOD(src_r.y, src_extents.height);
1163 if (needs_scale)
1164 goto UNSUPPORTED;
1166 /* If both the src and dest have an image, we may as well fall
1167 * back, because it will be faster than our separate blits.
1168 * Our blit code will be fastest when the src is a DDB and the
1169 * destination is a DDB.
1171 if ((src_image || src->image) && dst->image)
1172 goto UNSUPPORTED;
1174 /* If the src is not a bitmap but an on-screen (or unknown)
1175 * DC, chances are that fallback will be faster.
1177 if (src->bitmap == NULL)
1178 goto UNSUPPORTED;
1180 /* If we can use PatBlt, just do so */
1181 if (!src_image && !needs_alpha)
1183 HBRUSH brush;
1184 HGDIOBJ old_brush;
1185 POINT old_brush_origin;
1187 /* Set up the brush with our bitmap */
1188 brush = CreatePatternBrush (src->bitmap);
1190 /* SetBrushOrgEx sets the coordinates in the destination DC of where the
1191 * pattern should start.
1193 SetBrushOrgEx (dst->dc, dst_r.x - src_start_x,
1194 dst_r.y - src_start_y, &old_brush_origin);
1196 old_brush = SelectObject (dst->dc, brush);
1198 PatBlt (dst->dc, dst_r.x, dst_r.y, dst_r.width, dst_r.height, PATCOPY);
1200 /* Restore the old brush and pen */
1201 SetBrushOrgEx (dst->dc, old_brush_origin.x, old_brush_origin.y, NULL);
1202 SelectObject (dst->dc, old_brush);
1203 DeleteObject (brush);
1205 return CAIRO_STATUS_SUCCESS;
1208 /* If we were not able to use PatBlt, then manually expand out the blit */
1210 /* Arbitrary factor; we think that going through
1211 * fallback will be faster if we have to do more
1212 * than this amount of blits in either direction.
1214 if (dst_r.width / src_extents.width > 5 ||
1215 dst_r.height / src_extents.height > 5)
1216 goto UNSUPPORTED;
1218 for (rendered_height = 0;
1219 rendered_height < dst_r.height;
1220 rendered_height += to_render_height)
1222 piece_y = (src_start_y + rendered_height) % src_extents.height;
1223 to_render_height = src_extents.height - piece_y;
1225 if (rendered_height + to_render_height > dst_r.height)
1226 to_render_height = dst_r.height - rendered_height;
1228 for (rendered_width = 0;
1229 rendered_width < dst_r.width;
1230 rendered_width += to_render_width)
1232 piece_x = (src_start_x + rendered_width) % src_extents.width;
1233 to_render_width = src_extents.width - piece_x;
1235 if (rendered_width + to_render_width > dst_r.width)
1236 to_render_width = dst_r.width - rendered_width;
1238 piece_src_r.x = piece_x;
1239 piece_src_r.y = piece_y;
1240 piece_src_r.width = to_render_width;
1241 piece_src_r.height = to_render_height;
1243 piece_dst_r.x = dst_r.x + rendered_width;
1244 piece_dst_r.y = dst_r.y + rendered_height;
1245 piece_dst_r.width = to_render_width;
1246 piece_dst_r.height = to_render_height;
1248 status = _cairo_win32_surface_composite_inner (src, src_image, dst,
1249 src_extents, piece_src_r, piece_dst_r,
1250 alpha, needs_alpha, needs_scale);
1251 if (status != CAIRO_STATUS_SUCCESS) {
1252 /* Uh oh. If something failed, and it's the first
1253 * piece, then we can jump to UNSUPPORTED.
1254 * Otherwise, this is bad times, because part of the
1255 * rendering was already done. */
1256 if (rendered_width == 0 &&
1257 rendered_height == 0)
1259 goto UNSUPPORTED;
1262 return status;
1266 } else {
1267 status = _cairo_win32_surface_composite_inner (src, src_image, dst,
1268 src_extents, src_r, dst_r,
1269 alpha, needs_alpha, needs_scale);
1272 if (status == CAIRO_STATUS_SUCCESS)
1273 return status;
1275 UNSUPPORTED:
1276 /* Fall back to image surface directly, if this is a DIB surface */
1277 if (dst->image) {
1278 GdiFlush();
1280 return dst->image->backend->composite (op, pattern, mask_pattern,
1281 dst->image,
1282 src_x, src_y,
1283 mask_x, mask_y,
1284 dst_x, dst_y,
1285 width, height);
1288 return CAIRO_INT_STATUS_UNSUPPORTED;
1291 /* This big function tells us how to optimize operators for the
1292 * case of solid destination and constant-alpha source
1294 * Note: This function needs revisiting if we add support for
1295 * super-luminescent colors (a == 0, r,g,b > 0)
1297 static enum { DO_CLEAR, DO_SOURCE, DO_NOTHING, DO_UNSUPPORTED }
1298 categorize_solid_dest_operator (cairo_operator_t op,
1299 unsigned short alpha)
1301 enum { SOURCE_TRANSPARENT, SOURCE_LIGHT, SOURCE_SOLID, SOURCE_OTHER } source;
1303 if (alpha >= 0xff00)
1304 source = SOURCE_SOLID;
1305 else if (alpha < 0x100)
1306 source = SOURCE_TRANSPARENT;
1307 else
1308 source = SOURCE_OTHER;
1310 switch (op) {
1311 case CAIRO_OPERATOR_CLEAR: /* 0 0 */
1312 case CAIRO_OPERATOR_OUT: /* 1 - Ab 0 */
1313 return DO_CLEAR;
1314 break;
1316 case CAIRO_OPERATOR_SOURCE: /* 1 0 */
1317 case CAIRO_OPERATOR_IN: /* Ab 0 */
1318 return DO_SOURCE;
1319 break;
1321 case CAIRO_OPERATOR_OVER: /* 1 1 - Aa */
1322 case CAIRO_OPERATOR_ATOP: /* Ab 1 - Aa */
1323 if (source == SOURCE_SOLID)
1324 return DO_SOURCE;
1325 else if (source == SOURCE_TRANSPARENT)
1326 return DO_NOTHING;
1327 else
1328 return DO_UNSUPPORTED;
1329 break;
1331 case CAIRO_OPERATOR_DEST_OUT: /* 0 1 - Aa */
1332 case CAIRO_OPERATOR_XOR: /* 1 - Ab 1 - Aa */
1333 if (source == SOURCE_SOLID)
1334 return DO_CLEAR;
1335 else if (source == SOURCE_TRANSPARENT)
1336 return DO_NOTHING;
1337 else
1338 return DO_UNSUPPORTED;
1339 break;
1341 case CAIRO_OPERATOR_DEST: /* 0 1 */
1342 case CAIRO_OPERATOR_DEST_OVER:/* 1 - Ab 1 */
1343 case CAIRO_OPERATOR_SATURATE: /* min(1,(1-Ab)/Aa) 1 */
1344 return DO_NOTHING;
1345 break;
1347 case CAIRO_OPERATOR_DEST_IN: /* 0 Aa */
1348 case CAIRO_OPERATOR_DEST_ATOP:/* 1 - Ab Aa */
1349 if (source == SOURCE_SOLID)
1350 return DO_NOTHING;
1351 else if (source == SOURCE_TRANSPARENT)
1352 return DO_CLEAR;
1353 else
1354 return DO_UNSUPPORTED;
1355 break;
1357 case CAIRO_OPERATOR_ADD: /* 1 1 */
1358 if (source == SOURCE_TRANSPARENT)
1359 return DO_NOTHING;
1360 else
1361 return DO_UNSUPPORTED;
1362 break;
1365 ASSERT_NOT_REACHED;
1366 return DO_UNSUPPORTED;
1369 static cairo_int_status_t
1370 _cairo_win32_surface_fill_rectangles (void *abstract_surface,
1371 cairo_operator_t op,
1372 const cairo_color_t *color,
1373 cairo_rectangle_int_t *rects,
1374 int num_rects)
1376 cairo_win32_surface_t *surface = abstract_surface;
1377 cairo_status_t status;
1378 COLORREF new_color;
1379 HBRUSH new_brush;
1380 int i;
1382 /* XXXperf If it's not RGB24, we need to do a little more checking
1383 * to figure out when we can use GDI. We don't have that checking
1384 * anywhere at the moment, so just bail and use the fallback
1385 * paths. */
1386 if (surface->format != CAIRO_FORMAT_RGB24)
1387 return CAIRO_INT_STATUS_UNSUPPORTED;
1389 /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all
1390 * surfaces with alpha.)
1392 switch (categorize_solid_dest_operator (op, color->alpha_short)) {
1393 case DO_CLEAR:
1394 new_color = RGB (0, 0, 0);
1395 break;
1396 case DO_SOURCE:
1397 new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8);
1398 break;
1399 case DO_NOTHING:
1400 return CAIRO_STATUS_SUCCESS;
1401 case DO_UNSUPPORTED:
1402 default:
1403 return CAIRO_INT_STATUS_UNSUPPORTED;
1406 new_brush = CreateSolidBrush (new_color);
1407 if (!new_brush)
1408 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1410 for (i = 0; i < num_rects; i++) {
1411 RECT rect;
1413 rect.left = rects[i].x;
1414 rect.top = rects[i].y;
1415 rect.right = rects[i].x + rects[i].width;
1416 rect.bottom = rects[i].y + rects[i].height;
1418 if (!FillRect (surface->dc, &rect, new_brush))
1419 goto FAIL;
1422 DeleteObject (new_brush);
1424 return CAIRO_STATUS_SUCCESS;
1426 FAIL:
1427 status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1429 DeleteObject (new_brush);
1431 return status;
1434 static cairo_int_status_t
1435 _cairo_win32_surface_set_clip_region (void *abstract_surface,
1436 cairo_region_t *region)
1438 cairo_win32_surface_t *surface = abstract_surface;
1439 cairo_status_t status = CAIRO_STATUS_SUCCESS;
1441 /* If we are in-memory, then we set the clip on the image surface
1442 * as well as on the underlying GDI surface.
1444 if (surface->image) {
1445 unsigned int serial;
1447 serial = _cairo_surface_allocate_clip_serial (surface->image);
1448 status = _cairo_surface_set_clip_region (surface->image, region, serial);
1449 if (status)
1450 return status;
1453 /* The semantics we want is that any clip set by cairo combines
1454 * is intersected with the clip on device context that the
1455 * surface was created for. To implement this, we need to
1456 * save the original clip when first setting a clip on surface.
1459 /* Clear any clip set by cairo, return to the original first */
1460 status = _cairo_win32_restore_initial_clip (surface);
1462 /* Then combine any new region with it */
1463 if (region) {
1464 cairo_rectangle_int_t extents;
1465 int num_rects;
1466 RGNDATA *data;
1467 size_t data_size;
1468 RECT *rects;
1469 int i;
1470 HRGN gdi_region;
1471 cairo_rectangle_int_t rect0;
1473 /* Create a GDI region for the cairo region */
1475 cairo_region_get_extents (region, &extents);
1476 num_rects = cairo_region_num_rectangles (region);
1478 if (num_rects == 1)
1479 cairo_region_get_rectangle (region, 0, &rect0);
1481 if (num_rects == 1 &&
1482 rect0.x == 0 &&
1483 rect0.y == 0 &&
1484 rect0.width == surface->extents.width &&
1485 rect0.width == surface->extents.height)
1487 gdi_region = NULL;
1489 SelectClipRgn (surface->dc, NULL);
1490 IntersectClipRect (surface->dc,
1491 rect0.x,
1492 rect0.y,
1493 rect0.x + rect0.width,
1494 rect0.y + rect0.height);
1495 } else {
1496 /* XXX see notes in _cairo_win32_save_initial_clip --
1497 * this code will interact badly with a HDC which had an initial
1498 * world transform -- we should probably manually transform the
1499 * region rects, because SelectClipRgn takes device units, not
1500 * logical units (unlike IntersectClipRect).
1503 data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT);
1504 data = malloc (data_size);
1505 if (!data)
1506 return _cairo_error(CAIRO_STATUS_NO_MEMORY);
1507 rects = (RECT *)data->Buffer;
1509 data->rdh.dwSize = sizeof (RGNDATAHEADER);
1510 data->rdh.iType = RDH_RECTANGLES;
1511 data->rdh.nCount = num_rects;
1512 data->rdh.nRgnSize = num_rects * sizeof (RECT);
1513 data->rdh.rcBound.left = extents.x;
1514 data->rdh.rcBound.top = extents.y;
1515 data->rdh.rcBound.right = extents.x + extents.width;
1516 data->rdh.rcBound.bottom = extents.y + extents.height;
1518 for (i = 0; i < num_rects; i++) {
1519 cairo_rectangle_int_t rect;
1521 cairo_region_get_rectangle (region, i, &rect);
1523 rects[i].left = rect.x;
1524 rects[i].top = rect.y;
1525 rects[i].right = rect.x + rect.width;
1526 rects[i].bottom = rect.y + rect.height;
1529 gdi_region = ExtCreateRegion (NULL, data_size, data);
1530 free (data);
1532 if (!gdi_region)
1533 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1535 /* AND the new region into our DC */
1536 if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
1537 status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
1539 DeleteObject (gdi_region);
1543 return status;
1546 cairo_int_status_t
1547 _cairo_win32_surface_get_extents (void *abstract_surface,
1548 cairo_rectangle_int_t *rectangle)
1550 cairo_win32_surface_t *surface = abstract_surface;
1552 *rectangle = surface->extents;
1554 return CAIRO_STATUS_SUCCESS;
1557 static cairo_status_t
1558 _cairo_win32_surface_flush (void *abstract_surface)
1560 return _cairo_surface_reset_clip (abstract_surface);
1563 #define STACK_GLYPH_SIZE 256
1565 cairo_int_status_t
1566 _cairo_win32_surface_show_glyphs (void *surface,
1567 cairo_operator_t op,
1568 const cairo_pattern_t *source,
1569 cairo_glyph_t *glyphs,
1570 int num_glyphs,
1571 cairo_scaled_font_t *scaled_font,
1572 int *remaining_glyphs,
1573 cairo_rectangle_int_t *extents)
1575 #if CAIRO_HAS_WIN32_FONT
1576 cairo_win32_surface_t *dst = surface;
1578 WORD glyph_buf_stack[STACK_GLYPH_SIZE];
1579 WORD *glyph_buf = glyph_buf_stack;
1580 int dxy_buf_stack[2 * STACK_GLYPH_SIZE];
1581 int *dxy_buf = dxy_buf_stack;
1583 BOOL win_result = 0;
1584 int i, j;
1586 cairo_solid_pattern_t *solid_pattern;
1587 COLORREF color;
1589 cairo_matrix_t device_to_logical;
1591 int start_x, start_y;
1592 double user_x, user_y;
1593 int logical_x, logical_y;
1594 unsigned int glyph_index_option;
1596 /* We can only handle win32 fonts */
1597 if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_WIN32)
1598 return CAIRO_INT_STATUS_UNSUPPORTED;
1600 /* We can only handle opaque solid color sources */
1601 if (!_cairo_pattern_is_opaque_solid(source))
1602 return CAIRO_INT_STATUS_UNSUPPORTED;
1604 /* We can only handle operator SOURCE or OVER with the destination
1605 * having no alpha */
1606 if ((op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) ||
1607 (dst->format != CAIRO_FORMAT_RGB24))
1608 return CAIRO_INT_STATUS_UNSUPPORTED;
1610 /* If we have a fallback mask clip set on the dst, we have
1611 * to go through the fallback path, but only if we're not
1612 * doing this for printing */
1613 if (dst->base.clip &&
1614 !(dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) &&
1615 (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
1616 dst->base.clip->surface != NULL))
1617 return CAIRO_INT_STATUS_UNSUPPORTED;
1619 solid_pattern = (cairo_solid_pattern_t *)source;
1620 color = RGB(((int)solid_pattern->color.red_short) >> 8,
1621 ((int)solid_pattern->color.green_short) >> 8,
1622 ((int)solid_pattern->color.blue_short) >> 8);
1624 cairo_win32_scaled_font_get_device_to_logical(scaled_font, &device_to_logical);
1626 SaveDC(dst->dc);
1628 cairo_win32_scaled_font_select_font(scaled_font, dst->dc);
1629 SetTextColor(dst->dc, color);
1630 SetTextAlign(dst->dc, TA_BASELINE | TA_LEFT);
1631 SetBkMode(dst->dc, TRANSPARENT);
1633 if (num_glyphs > STACK_GLYPH_SIZE) {
1634 glyph_buf = (WORD *) _cairo_malloc_ab (num_glyphs, sizeof(WORD));
1635 dxy_buf = (int *) _cairo_malloc_abc (num_glyphs, sizeof(int), 2);
1638 /* It is vital that dx values for dxy_buf are calculated from the delta of
1639 * _logical_ x coordinates (not user x coordinates) or else the sum of all
1640 * previous dx values may start to diverge from the current glyph's x
1641 * coordinate due to accumulated rounding error. As a result strings could
1642 * be painted shorter or longer than expected. */
1644 user_x = glyphs[0].x;
1645 user_y = glyphs[0].y;
1647 cairo_matrix_transform_point(&device_to_logical,
1648 &user_x, &user_y);
1650 logical_x = _cairo_lround (user_x);
1651 logical_y = _cairo_lround (user_y);
1653 start_x = logical_x;
1654 start_y = logical_y;
1656 for (i = 0, j = 0; i < num_glyphs; ++i, j = 2 * i) {
1657 glyph_buf[i] = (WORD) glyphs[i].index;
1658 if (i == num_glyphs - 1) {
1659 dxy_buf[j] = 0;
1660 dxy_buf[j+1] = 0;
1661 } else {
1662 double next_user_x = glyphs[i+1].x;
1663 double next_user_y = glyphs[i+1].y;
1664 int next_logical_x, next_logical_y;
1666 cairo_matrix_transform_point(&device_to_logical,
1667 &next_user_x, &next_user_y);
1669 next_logical_x = _cairo_lround (next_user_x);
1670 next_logical_y = _cairo_lround (next_user_y);
1672 dxy_buf[j] = _cairo_lround (next_logical_x - logical_x);
1673 dxy_buf[j+1] = _cairo_lround (next_logical_y - logical_y);
1675 logical_x = next_logical_x;
1676 logical_y = next_logical_y;
1680 /* Using glyph indices for a Type 1 font does not work on a
1681 * printer DC. The win32 printing surface will convert the the
1682 * glyph indices of Type 1 fonts to the unicode values.
1684 if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) &&
1685 _cairo_win32_scaled_font_is_type1 (scaled_font))
1687 glyph_index_option = 0;
1689 else
1691 glyph_index_option = ETO_GLYPH_INDEX;
1694 win_result = ExtTextOutW(dst->dc,
1695 start_x,
1696 start_y,
1697 glyph_index_option | ETO_PDY,
1698 NULL,
1699 glyph_buf,
1700 num_glyphs,
1701 dxy_buf);
1702 if (!win_result) {
1703 _cairo_win32_print_gdi_error("_cairo_win32_surface_show_glyphs(ExtTextOutW failed)");
1706 RestoreDC(dst->dc, -1);
1708 if (glyph_buf != glyph_buf_stack) {
1709 free(glyph_buf);
1710 free(dxy_buf);
1712 return (win_result) ? CAIRO_STATUS_SUCCESS : CAIRO_INT_STATUS_UNSUPPORTED;
1713 #else
1714 return CAIRO_INT_STATUS_UNSUPPORTED;
1715 #endif
1718 #undef STACK_GLYPH_SIZE
1721 * cairo_win32_surface_create:
1722 * @hdc: the DC to create a surface for
1724 * Creates a cairo surface that targets the given DC. The DC will be
1725 * queried for its initial clip extents, and this will be used as the
1726 * size of the cairo surface. The resulting surface will always be of
1727 * format %CAIRO_FORMAT_RGB24; should you need another surface format,
1728 * you will need to create one through
1729 * cairo_win32_surface_create_with_dib().
1731 * Return value: the newly created surface
1733 cairo_surface_t *
1734 cairo_win32_surface_create (HDC hdc)
1736 cairo_win32_surface_t *surface;
1738 cairo_format_t format;
1739 RECT rect;
1741 /* Assume that everything coming in as a HDC is RGB24 */
1742 format = CAIRO_FORMAT_RGB24;
1744 surface = malloc (sizeof (cairo_win32_surface_t));
1745 if (surface == NULL)
1746 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1748 if (_cairo_win32_save_initial_clip (hdc, surface) != CAIRO_STATUS_SUCCESS) {
1749 free (surface);
1750 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1753 surface->image = NULL;
1754 surface->format = format;
1756 surface->dc = hdc;
1757 surface->bitmap = NULL;
1758 surface->is_dib = FALSE;
1759 surface->saved_dc_bitmap = NULL;
1760 surface->brush = NULL;
1761 surface->old_brush = NULL;
1762 surface->font_subsets = NULL;
1764 GetClipBox(hdc, &rect);
1765 surface->extents.x = rect.left;
1766 surface->extents.y = rect.top;
1767 surface->extents.width = rect.right - rect.left;
1768 surface->extents.height = rect.bottom - rect.top;
1770 surface->flags = _cairo_win32_flags_for_dc (surface->dc);
1772 _cairo_surface_init (&surface->base, &cairo_win32_surface_backend,
1773 _cairo_content_from_format (format));
1775 return (cairo_surface_t *)surface;
1779 * cairo_win32_surface_create_with_dib:
1780 * @format: format of pixels in the surface to create
1781 * @width: width of the surface, in pixels
1782 * @height: height of the surface, in pixels
1784 * Creates a device-independent-bitmap surface not associated with
1785 * any particular existing surface or device context. The created
1786 * bitmap will be uninitialized.
1788 * Return value: the newly created surface
1790 * Since: 1.2
1792 cairo_surface_t *
1793 cairo_win32_surface_create_with_dib (cairo_format_t format,
1794 int width,
1795 int height)
1797 return _cairo_win32_surface_create_for_dc (NULL, format, width, height);
1801 * cairo_win32_surface_create_with_ddb:
1802 * @hdc: the DC to create a surface for
1803 * @format: format of pixels in the surface to create
1804 * @width: width of the surface, in pixels
1805 * @height: height of the surface, in pixels
1807 * Creates a device-independent-bitmap surface not associated with
1808 * any particular existing surface or device context. The created
1809 * bitmap will be uninitialized.
1811 * Return value: the newly created surface
1813 * Since: 1.4
1815 cairo_surface_t *
1816 cairo_win32_surface_create_with_ddb (HDC hdc,
1817 cairo_format_t format,
1818 int width,
1819 int height)
1821 cairo_win32_surface_t *new_surf;
1822 HBITMAP ddb;
1823 HDC screen_dc, ddb_dc;
1824 HBITMAP saved_dc_bitmap;
1826 if (format != CAIRO_FORMAT_RGB24)
1827 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
1828 /* XXX handle these eventually
1829 format != CAIRO_FORMAT_A8 ||
1830 format != CAIRO_FORMAT_A1)
1833 if (!hdc) {
1834 screen_dc = GetDC (NULL);
1835 hdc = screen_dc;
1836 } else {
1837 screen_dc = NULL;
1840 ddb_dc = CreateCompatibleDC (hdc);
1841 if (ddb_dc == NULL) {
1842 new_surf = (cairo_win32_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1843 goto FINISH;
1846 ddb = CreateCompatibleBitmap (hdc, width, height);
1847 if (ddb == NULL) {
1848 DeleteDC (ddb_dc);
1850 /* Note that if an app actually does hit this out of memory
1851 * condition, it's going to have lots of other issues, as
1852 * video memory is probably exhausted. However, it can often
1853 * continue using DIBs instead of DDBs.
1855 new_surf = (cairo_win32_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1856 goto FINISH;
1859 saved_dc_bitmap = SelectObject (ddb_dc, ddb);
1861 new_surf = (cairo_win32_surface_t*) cairo_win32_surface_create (ddb_dc);
1862 new_surf->bitmap = ddb;
1863 new_surf->saved_dc_bitmap = saved_dc_bitmap;
1864 new_surf->is_dib = FALSE;
1866 FINISH:
1867 if (screen_dc)
1868 ReleaseDC (NULL, screen_dc);
1870 return (cairo_surface_t*) new_surf;
1874 * _cairo_surface_is_win32:
1875 * @surface: a #cairo_surface_t
1877 * Checks if a surface is a win32 surface. This will
1878 * return False if this is a win32 printing surface; use
1879 * _cairo_surface_is_win32_printing() to check for that.
1881 * Return value: True if the surface is an win32 surface
1884 _cairo_surface_is_win32 (cairo_surface_t *surface)
1886 return surface->backend == &cairo_win32_surface_backend;
1890 * cairo_win32_surface_get_dc
1891 * @surface: a #cairo_surface_t
1893 * Returns the HDC associated with this surface, or %NULL if none.
1894 * Also returns %NULL if the surface is not a win32 surface.
1896 * Return value: HDC or %NULL if no HDC available.
1898 * Since: 1.2
1901 cairo_win32_surface_get_dc (cairo_surface_t *surface)
1903 cairo_win32_surface_t *winsurf;
1905 if (_cairo_surface_is_win32 (surface)){
1906 winsurf = (cairo_win32_surface_t *) surface;
1908 return winsurf->dc;
1911 if (_cairo_surface_is_paginated (surface)) {
1912 cairo_surface_t *target;
1914 target = _cairo_paginated_surface_get_target (surface);
1916 if (_cairo_surface_is_win32_printing (target)) {
1917 winsurf = (cairo_win32_surface_t *) target;
1919 return winsurf->dc;
1923 return NULL;
1927 * cairo_win32_surface_get_image
1928 * @surface: a #cairo_surface_t
1930 * Returns a #cairo_surface_t image surface that refers to the same bits
1931 * as the DIB of the Win32 surface. If the passed-in win32 surface
1932 * is not a DIB surface, %NULL is returned.
1934 * Return value: a #cairo_surface_t (owned by the win32 #cairo_surface_t),
1935 * or %NULL if the win32 surface is not a DIB.
1937 * Since: 1.4
1939 cairo_surface_t *
1940 cairo_win32_surface_get_image (cairo_surface_t *surface)
1942 if (!_cairo_surface_is_win32(surface))
1943 return NULL;
1945 return ((cairo_win32_surface_t*)surface)->image;
1948 static cairo_bool_t
1949 _cairo_win32_surface_is_similar (void *surface_a,
1950 void *surface_b,
1951 cairo_content_t content)
1953 cairo_win32_surface_t *a = surface_a;
1954 cairo_win32_surface_t *b = surface_b;
1956 return a->dc == b->dc;
1959 static cairo_status_t
1960 _cairo_win32_surface_reset (void *abstract_surface)
1962 cairo_win32_surface_t *surface = abstract_surface;
1963 cairo_status_t status;
1965 status = _cairo_win32_surface_set_clip_region (surface, NULL);
1966 if (status)
1967 return status;
1969 return CAIRO_STATUS_SUCCESS;
1972 typedef struct _cairo_win32_surface_span_renderer {
1973 cairo_span_renderer_t base;
1975 cairo_operator_t op;
1976 const cairo_pattern_t *pattern;
1977 cairo_antialias_t antialias;
1979 cairo_image_surface_t *mask;
1980 cairo_win32_surface_t *dst;
1982 cairo_composite_rectangles_t composite_rectangles;
1983 } cairo_win32_surface_span_renderer_t;
1985 static cairo_status_t
1986 _cairo_win32_surface_span_renderer_render_row (
1987 void *abstract_renderer,
1988 int y,
1989 const cairo_half_open_span_t *spans,
1990 unsigned num_spans)
1992 cairo_win32_surface_span_renderer_t *renderer = abstract_renderer;
1993 _cairo_image_surface_span_render_row (y, spans, num_spans, renderer->mask, &renderer->composite_rectangles);
1994 return CAIRO_STATUS_SUCCESS;
1997 static void
1998 _cairo_win32_surface_span_renderer_destroy (void *abstract_renderer)
2000 cairo_win32_surface_span_renderer_t *renderer = abstract_renderer;
2001 if (!renderer) return;
2003 if (renderer->mask != NULL)
2004 cairo_surface_destroy (&renderer->mask->base);
2006 free (renderer);
2009 static cairo_status_t
2010 _cairo_win32_surface_span_renderer_finish (void *abstract_renderer)
2012 cairo_win32_surface_span_renderer_t *renderer = abstract_renderer;
2013 cairo_status_t status = CAIRO_STATUS_SUCCESS;
2015 if (renderer->pattern == NULL || renderer->mask == NULL)
2016 return CAIRO_STATUS_SUCCESS;
2018 status = cairo_surface_status (&renderer->mask->base);
2019 if (status == CAIRO_STATUS_SUCCESS) {
2020 cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
2021 cairo_win32_surface_t *dst = renderer->dst;
2022 cairo_pattern_t *mask_pattern = cairo_pattern_create_for_surface (&renderer->mask->base);
2023 /* composite onto the image surface directly if we can */
2024 if (dst->image) {
2025 GdiFlush(); /* XXX: I'm not sure if this needed or not */
2027 status = dst->image->backend->composite (renderer->op,
2028 renderer->pattern, mask_pattern, dst->image,
2029 rects->src.x,
2030 rects->src.y,
2031 0, 0, /* mask.x, mask.y */
2032 rects->dst.x, rects->dst.y,
2033 rects->width, rects->height);
2034 } else {
2035 /* otherwise go through the fallback_composite path which
2036 * will do the appropriate surface acquisition */
2037 status = _cairo_surface_fallback_composite (
2038 renderer->op,
2039 renderer->pattern, mask_pattern, dst,
2040 rects->src.x,
2041 rects->src.y,
2042 0, 0, /* mask.x, mask.y */
2043 rects->dst.x, rects->dst.y,
2044 rects->width, rects->height);
2046 cairo_pattern_destroy (mask_pattern);
2049 if (status != CAIRO_STATUS_SUCCESS)
2050 return _cairo_span_renderer_set_error (abstract_renderer,
2051 status);
2052 return CAIRO_STATUS_SUCCESS;
2055 static cairo_bool_t
2056 _cairo_win32_surface_check_span_renderer (cairo_operator_t op,
2057 const cairo_pattern_t *pattern,
2058 void *abstract_dst,
2059 cairo_antialias_t antialias,
2060 const cairo_composite_rectangles_t *rects)
2062 (void) op;
2063 (void) pattern;
2064 (void) abstract_dst;
2065 (void) antialias;
2066 (void) rects;
2067 return TRUE;
2070 static cairo_span_renderer_t *
2071 _cairo_win32_surface_create_span_renderer (cairo_operator_t op,
2072 const cairo_pattern_t *pattern,
2073 void *abstract_dst,
2074 cairo_antialias_t antialias,
2075 const cairo_composite_rectangles_t *rects)
2077 cairo_win32_surface_t *dst = abstract_dst;
2078 cairo_win32_surface_span_renderer_t *renderer
2079 = calloc(1, sizeof(*renderer));
2080 cairo_status_t status;
2081 int width = rects->width;
2082 int height = rects->height;
2084 if (renderer == NULL)
2085 return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
2087 renderer->base.destroy = _cairo_win32_surface_span_renderer_destroy;
2088 renderer->base.finish = _cairo_win32_surface_span_renderer_finish;
2089 renderer->base.render_row =
2090 _cairo_win32_surface_span_renderer_render_row;
2091 renderer->op = op;
2092 renderer->pattern = pattern;
2093 renderer->antialias = antialias;
2094 renderer->dst = dst;
2096 renderer->composite_rectangles = *rects;
2098 /* TODO: support rendering to A1 surfaces (or: go add span
2099 * compositing to pixman.) */
2100 renderer->mask = (cairo_image_surface_t *)
2101 cairo_image_surface_create (CAIRO_FORMAT_A8,
2102 width, height);
2104 status = cairo_surface_status (&renderer->mask->base);
2106 if (status != CAIRO_STATUS_SUCCESS) {
2107 _cairo_win32_surface_span_renderer_destroy (renderer);
2108 return _cairo_span_renderer_create_in_error (status);
2110 return &renderer->base;
2114 static const cairo_surface_backend_t cairo_win32_surface_backend = {
2115 CAIRO_SURFACE_TYPE_WIN32,
2116 _cairo_win32_surface_create_similar,
2117 _cairo_win32_surface_finish,
2118 _cairo_win32_surface_acquire_source_image,
2119 _cairo_win32_surface_release_source_image,
2120 _cairo_win32_surface_acquire_dest_image,
2121 _cairo_win32_surface_release_dest_image,
2122 _cairo_win32_surface_clone_similar,
2123 _cairo_win32_surface_composite,
2124 _cairo_win32_surface_fill_rectangles,
2125 NULL, /* composite_trapezoids */
2126 _cairo_win32_surface_create_span_renderer,
2127 _cairo_win32_surface_check_span_renderer,
2128 NULL, /* copy_page */
2129 NULL, /* show_page */
2130 _cairo_win32_surface_set_clip_region,
2131 NULL, /* intersect_clip_path */
2132 _cairo_win32_surface_get_extents,
2133 NULL, /* old_show_glyphs */
2134 NULL, /* get_font_options */
2135 _cairo_win32_surface_flush,
2136 NULL, /* mark_dirty_rectangle */
2137 NULL, /* scaled_font_fini */
2138 NULL, /* scaled_glyph_fini */
2140 NULL, /* paint */
2141 NULL, /* mask */
2142 NULL, /* stroke */
2143 NULL, /* fill */
2144 _cairo_win32_surface_show_glyphs,
2146 NULL, /* snapshot */
2147 _cairo_win32_surface_is_similar,
2149 _cairo_win32_surface_reset
2152 /* Notes:
2154 * Win32 alpha-understanding functions
2156 * BitBlt - will copy full 32 bits from a 32bpp DIB to result
2157 * (so it's safe to use for ARGB32->ARGB32 SOURCE blits)
2158 * (but not safe going RGB24->ARGB32, if RGB24 is also represented
2159 * as a 32bpp DIB, since the alpha isn't discarded!)
2161 * AlphaBlend - if both the source and dest have alpha, even if AC_SRC_ALPHA isn't set,
2162 * it will still copy over the src alpha, because the SCA value (255) will be
2163 * multiplied by all the src components.
2167 cairo_int_status_t
2168 _cairo_win32_save_initial_clip (HDC hdc, cairo_win32_surface_t *surface)
2170 RECT rect;
2171 int clipBoxType;
2172 int gm;
2173 XFORM saved_xform;
2175 /* GetClipBox/GetClipRgn and friends interact badly with a world transform
2176 * set. GetClipBox returns values in logical (transformed) coordinates;
2177 * it's unclear what GetClipRgn returns, because the region is empty in the
2178 * case of a SIMPLEREGION clip, but I assume device (untransformed) coordinates.
2179 * Similarily, IntersectClipRect works in logical units, whereas SelectClipRgn
2180 * works in device units.
2182 * So, avoid the whole mess and get rid of the world transform
2183 * while we store our initial data and when we restore initial coordinates.
2185 * XXX we may need to modify x/y by the ViewportOrg or WindowOrg
2186 * here in GM_COMPATIBLE; unclear.
2188 gm = GetGraphicsMode (hdc);
2189 if (gm == GM_ADVANCED) {
2190 GetWorldTransform (hdc, &saved_xform);
2191 ModifyWorldTransform (hdc, NULL, MWT_IDENTITY);
2194 clipBoxType = GetClipBox (hdc, &rect);
2195 if (clipBoxType == ERROR) {
2196 _cairo_win32_print_gdi_error ("cairo_win32_surface_create");
2197 SetGraphicsMode (hdc, gm);
2198 /* XXX: Can we make a more reasonable guess at the error cause here? */
2199 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2202 surface->clip_rect.x = rect.left;
2203 surface->clip_rect.y = rect.top;
2204 surface->clip_rect.width = rect.right - rect.left;
2205 surface->clip_rect.height = rect.bottom - rect.top;
2207 surface->initial_clip_rgn = NULL;
2208 surface->had_simple_clip = FALSE;
2210 if (clipBoxType == COMPLEXREGION) {
2211 surface->initial_clip_rgn = CreateRectRgn (0, 0, 0, 0);
2212 if (GetClipRgn (hdc, surface->initial_clip_rgn) <= 0) {
2213 DeleteObject(surface->initial_clip_rgn);
2214 surface->initial_clip_rgn = NULL;
2216 } else if (clipBoxType == SIMPLEREGION) {
2217 surface->had_simple_clip = TRUE;
2220 if (gm == GM_ADVANCED)
2221 SetWorldTransform (hdc, &saved_xform);
2223 return CAIRO_STATUS_SUCCESS;
2226 cairo_int_status_t
2227 _cairo_win32_restore_initial_clip (cairo_win32_surface_t *surface)
2229 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
2231 XFORM saved_xform;
2232 int gm = GetGraphicsMode (surface->dc);
2233 if (gm == GM_ADVANCED) {
2234 GetWorldTransform (surface->dc, &saved_xform);
2235 ModifyWorldTransform (surface->dc, NULL, MWT_IDENTITY);
2238 /* initial_clip_rgn will either be a real region or NULL (which means reset to no clip region) */
2239 SelectClipRgn (surface->dc, surface->initial_clip_rgn);
2241 if (surface->had_simple_clip) {
2242 /* then if we had a simple clip, intersect */
2243 IntersectClipRect (surface->dc,
2244 surface->clip_rect.x,
2245 surface->clip_rect.y,
2246 surface->clip_rect.x + surface->clip_rect.width,
2247 surface->clip_rect.y + surface->clip_rect.height);
2250 if (gm == GM_ADVANCED)
2251 SetWorldTransform (surface->dc, &saved_xform);
2253 return status;
2256 void
2257 _cairo_win32_debug_dump_hrgn (HRGN rgn, char *header)
2259 RGNDATA *rd;
2260 int z;
2262 if (header)
2263 fprintf (stderr, "%s\n", header);
2265 if (rgn == NULL) {
2266 fprintf (stderr, " NULL\n");
2269 z = GetRegionData(rgn, 0, NULL);
2270 rd = (RGNDATA*) malloc(z);
2271 z = GetRegionData(rgn, z, rd);
2273 fprintf (stderr, " %d rects, bounds: %d %d %d %d\n", rd->rdh.nCount, rd->rdh.rcBound.left, rd->rdh.rcBound.top, rd->rdh.rcBound.right - rd->rdh.rcBound.left, rd->rdh.rcBound.bottom - rd->rdh.rcBound.top);
2275 for (z = 0; z < rd->rdh.nCount; z++) {
2276 RECT r = ((RECT*)rd->Buffer)[z];
2277 fprintf (stderr, " [%d]: [%d %d %d %d]\n", z, r.left, r.top, r.right - r.left, r.bottom - r.top);
2280 free(rd);
2281 fflush (stderr);