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., 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
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Red Hat, Inc.
34 * Owen Taylor <otaylor@redhat.com>
35 * Stuart Parmenter <stuart@mozilla.com>
36 * Vladimir Vukicevic <vladimir@pobox.com>
39 #define WIN32_LEAN_AND_MEAN
40 /* We require Windows 2000 features such as ETO_PDY */
41 #if !defined(WINVER) || (WINVER < 0x0500)
42 # define WINVER 0x0500
44 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
45 # define _WIN32_WINNT 0x0500
50 #include "cairo-clip-private.h"
51 #include "cairo-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"
65 #if defined(__MINGW32__) && !defined(ETO_PDY)
66 # define ETO_PDY 0x2000
69 #undef DEBUG_COMPOSITE
72 #ifndef SHADEBLENDCAPS
73 #define SHADEBLENDCAPS 120
76 #define SB_NONE 0x00000000
79 #define PELS_72DPI ((LONG)(72. / 0.0254))
83 * @Title: Win32 Surfaces
84 * @Short_Description: Microsoft Windows surface support
85 * @See_Also: #cairo_surface_t
87 * The Microsoft Windows surface is used to render cairo graphics to
88 * Microsoft Windows windows, bitmaps, and printing device contexts.
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
94 * The surface returned by the other win32 constructors is of surface type
95 * %CAIRO_SURFACE_TYPE_WIN32 and is a raster surface type.
99 * CAIRO_HAS_WIN32_SURFACE:
101 * Defined if the Microsoft Windows surface backend is available.
102 * This macro can be used to conditionally compile backend-specific code.
105 static const cairo_surface_backend_t cairo_win32_surface_backend;
108 * _cairo_win32_print_gdi_error:
109 * @context: context string to display along with the error
111 * Helper function to dump out a human readable form of the
112 * current error code.
114 * Return value: A cairo status code for the error code
117 _cairo_win32_print_gdi_error (const char *context)
120 DWORD last_error = GetLastError ();
122 if (!FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
123 FORMAT_MESSAGE_FROM_SYSTEM,
126 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
129 fprintf (stderr, "%s: Unknown GDI error", context);
131 fprintf (stderr, "%s: %S", context, (wchar_t *)lpMsgBuf);
133 LocalFree (lpMsgBuf);
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.
143 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
147 _cairo_win32_flags_for_dc (HDC dc)
151 if (GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
152 flags |= CAIRO_WIN32_SURFACE_IS_DISPLAY;
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
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;
167 cap = GetDeviceCaps(dc, SHADEBLENDCAPS);
169 flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND;
171 cap = GetDeviceCaps(dc, RASTERCAPS);
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;
183 static cairo_status_t
184 _create_dc_and_bitmap (cairo_win32_surface_t *surface,
186 cairo_format_t format,
189 unsigned char **bits_out,
192 cairo_status_t status;
194 BITMAPINFO *bitmap_info = NULL;
196 BITMAPINFOHEADER bmiHeader;
197 RGBQUAD bmiColors[2];
201 int num_palette = 0; /* Quiet GCC */
205 surface->bitmap = NULL;
206 surface->is_dib = FALSE;
210 case CAIRO_FORMAT_INVALID:
211 return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
212 case CAIRO_FORMAT_ARGB32:
213 case CAIRO_FORMAT_RGB24:
217 case CAIRO_FORMAT_A8:
221 case CAIRO_FORMAT_A1:
226 if (num_palette > 2) {
227 bitmap_info = _cairo_malloc_ab_plus_c (num_palette, sizeof(RGBQUAD), sizeof(BITMAPINFOHEADER));
229 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
231 bitmap_info = (BITMAPINFO *)&bmi_stack;
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;
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!
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;
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;
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;
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;
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;
289 surface->dc = CreateCompatibleDC (original_dc);
293 surface->bitmap = CreateDIBSection (surface->dc,
298 if (!surface->bitmap)
301 surface->is_dib = TRUE;
305 surface->saved_dc_bitmap = SelectObject (surface->dc,
307 if (!surface->saved_dc_bitmap)
310 if (bitmap_info && num_palette > 2)
317 /* Windows bitmaps are padded to 32-bit (dword) boundaries */
319 case CAIRO_FORMAT_ARGB32:
320 case CAIRO_FORMAT_RGB24:
321 *rowstride_out = 4 * width;
324 case CAIRO_FORMAT_A8:
325 *rowstride_out = (width + 3) & ~3;
328 case CAIRO_FORMAT_A1:
329 *rowstride_out = ((width + 31) & ~31) / 8;
334 surface->flags = _cairo_win32_flags_for_dc (surface->dc);
336 return CAIRO_STATUS_SUCCESS;
339 status = _cairo_win32_print_gdi_error ("_create_dc_and_bitmap");
341 if (bitmap_info && num_palette > 2)
344 if (surface->saved_dc_bitmap) {
345 SelectObject (surface->dc, surface->saved_dc_bitmap);
346 surface->saved_dc_bitmap = NULL;
349 if (surface->bitmap) {
350 DeleteObject (surface->bitmap);
351 surface->bitmap = NULL;
355 DeleteDC (surface->dc);
362 static cairo_surface_t *
363 _cairo_win32_surface_create_for_dc (HDC original_dc,
364 cairo_format_t format,
368 cairo_status_t status;
369 cairo_win32_surface_t *surface;
373 if (! CAIRO_FORMAT_VALID (format))
374 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
376 surface = malloc (sizeof (cairo_win32_surface_t));
378 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
380 surface->clip_region = NULL;
382 status = _create_dc_and_bitmap (surface, original_dc, format,
388 surface->image = cairo_image_surface_create_for_data (bits, format,
389 width, height, rowstride);
390 status = surface->image->status;
394 surface->format = format;
396 surface->clip_rect.x = 0;
397 surface->clip_rect.y = 0;
398 surface->clip_rect.width = width;
399 surface->clip_rect.height = height;
401 surface->initial_clip_rgn = NULL;
402 surface->had_simple_clip = FALSE;
404 surface->extents = surface->clip_rect;
405 surface->font_subsets = NULL;
407 _cairo_surface_init (&surface->base,
408 &cairo_win32_surface_backend,
410 _cairo_content_from_format (format));
412 return &surface->base;
415 if (surface->bitmap) {
416 SelectObject (surface->dc, surface->saved_dc_bitmap);
417 DeleteObject (surface->bitmap);
418 DeleteDC (surface->dc);
422 return _cairo_surface_create_in_error (status);
425 static cairo_surface_t *
426 _cairo_win32_surface_create_similar_internal (void *abstract_src,
427 cairo_content_t content,
430 cairo_bool_t force_dib)
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;
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)
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.
445 (content & CAIRO_CONTENT_ALPHA) ||
446 src->base.backend->type == CAIRO_SURFACE_TYPE_WIN32_PRINTING)
452 /* try to create a ddb */
453 new_surf = cairo_win32_surface_create_with_ddb (src->dc, CAIRO_FORMAT_RGB24, width, height);
455 if (new_surf->status != CAIRO_STATUS_SUCCESS)
459 if (new_surf == NULL) {
460 new_surf = _cairo_win32_surface_create_for_dc (src->dc, format, width, height);
467 _cairo_win32_surface_create_similar (void *abstract_src,
468 cairo_content_t content,
472 return _cairo_win32_surface_create_similar_internal (abstract_src, content, width, height, FALSE);
476 _cairo_win32_surface_finish (void *abstract_surface)
478 cairo_win32_surface_t *surface = abstract_surface;
481 cairo_surface_destroy (surface->image);
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);
489 _cairo_win32_restore_initial_clip (surface);
492 if (surface->initial_clip_rgn)
493 DeleteObject (surface->initial_clip_rgn);
495 if (surface->font_subsets != NULL)
496 _cairo_scaled_font_subsets_destroy (surface->font_subsets);
498 return CAIRO_STATUS_SUCCESS;
501 static cairo_status_t
502 _cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
507 cairo_win32_surface_t **local_out)
509 cairo_win32_surface_t *local;
510 cairo_int_status_t status;
511 cairo_content_t content = _cairo_content_from_format (surface->format);
514 (cairo_win32_surface_t *) _cairo_win32_surface_create_similar_internal
515 (surface, content, width, height, TRUE);
517 return CAIRO_INT_STATUS_UNSUPPORTED;
518 if (local->base.status)
519 return local->base.status;
521 status = CAIRO_INT_STATUS_UNSUPPORTED;
523 /* Only BitBlt if the source surface supports it. */
524 if ((surface->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT) &&
532 status = CAIRO_STATUS_SUCCESS;
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).
546 FillRect(local->dc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
551 return CAIRO_STATUS_SUCCESS;
554 static cairo_surface_t *
555 _cairo_win32_surface_map_to_image (void *abstract_surface,
556 const cairo_rectangle_int_t *extents)
558 cairo_win32_surface_t *surface = abstract_surface;
559 cairo_win32_surface_t *local = NULL;
560 cairo_status_t status;
562 if (surface->image) {
564 return _cairo_surface_create_for_rectangle_int (surface->image,
568 status = _cairo_win32_surface_get_subimage (abstract_surface,
574 if (unlikely (status))
575 return _cairo_surface_create_in_error (status);
577 status = cairo_surface_set_user_data (local->image,
578 (const cairo_user_data_key_t *)surface->image,
580 if (unlikely (status)) {
581 cairo_surface_destroy (&local->base);
582 return _cairo_surface_create_in_error (status);
585 cairo_surface_set_device_offset (local->image, -extents->x, -extents->y);
589 static cairo_int_status_t
590 _cairo_win32_surface_unmap_image (void *abstract_surface,
591 cairo_image_surface_t *image)
593 cairo_win32_surface_t *surface = abstract_surface;
594 cairo_win32_surface_t *local;
596 local = cairo_surface_get_user_data (&image->base,
597 (const cairo_user_data_key_t *) surface->image);
599 return CAIRO_INT_STATUS_SUCCESS;
601 if (!BitBlt (surface->dc,
602 image->base.device_transform.x0,
603 image->base.device_transform.y0,
604 image->width, image->height,
608 _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image");
610 return CAIRO_STATUS_SUCCESS;
613 static cairo_status_t
614 _cairo_win32_surface_acquire_source_image (void *abstract_surface,
615 cairo_image_surface_t **image_out,
618 cairo_win32_surface_t *surface = abstract_surface;
619 cairo_win32_surface_t *local;
620 cairo_status_t status;
622 if (surface->image) {
623 *image_out = (cairo_image_surface_t *)surface->image;
625 return CAIRO_STATUS_SUCCESS;
628 status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0,
629 surface->extents.width,
630 surface->extents.height, &local);
634 *image_out = (cairo_image_surface_t *)local->image;
635 *image_extra = local;
636 return CAIRO_STATUS_SUCCESS;
640 _cairo_win32_surface_release_source_image (void *abstract_surface,
641 cairo_image_surface_t *image,
644 cairo_win32_surface_t *local = image_extra;
647 cairo_surface_destroy ((cairo_surface_t *)local);
651 _cairo_win32_surface_set_clip_region (void *abstract_surface,
652 cairo_region_t *region)
654 cairo_win32_surface_t *surface = abstract_surface;
655 cairo_status_t status = CAIRO_STATUS_SUCCESS;
657 if (surface->clip_region == region)
658 return CAIRO_STATUS_SUCCESS;
660 cairo_region_destroy (surface->clip_region);
661 surface->clip_region = cairo_region_reference (region);
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.
669 /* Clear any clip set by cairo, return to the original first */
670 status = _cairo_win32_restore_initial_clip (surface);
672 /* Then combine any new region with it */
674 cairo_rectangle_int_t extents;
682 /* Create a GDI region for the cairo region */
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).
693 data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT);
694 data = malloc (data_size);
696 return _cairo_error(CAIRO_STATUS_NO_MEMORY);
697 rects = (RECT *)data->Buffer;
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;
708 for (i = 0; i < num_rects; i++) {
709 cairo_rectangle_int_t rect;
711 cairo_region_get_rectangle (region, i, &rect);
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;
719 gdi_region = ExtCreateRegion (NULL, data_size, data);
723 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
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");
729 DeleteObject (gdi_region);
735 #if !defined(AC_SRC_OVER)
736 #define AC_SRC_OVER 0x00
741 BYTE SourceConstantAlpha;
747 /* for compatibility with VC++ 6 */
749 #define AC_SRC_ALPHA 0x01
752 typedef BOOL (WINAPI *cairo_alpha_blend_func_t) (HDC hdcDest,
762 BLENDFUNCTION blendFunction);
764 static cairo_int_status_t
765 _composite_alpha_blend (cairo_win32_surface_t *dst,
766 cairo_win32_surface_t *src,
777 static unsigned alpha_blend_checked = FALSE;
778 static cairo_alpha_blend_func_t alpha_blend = NULL;
780 BLENDFUNCTION blend_function;
782 /* Check for AlphaBlend dynamically to allow compiling on
783 * MSVC 6 and use on older windows versions
785 if (!alpha_blend_checked) {
788 os.dwOSVersionInfoSize = sizeof (os);
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)
796 HMODULE msimg32_dll = LoadLibraryW (L"msimg32");
798 if (msimg32_dll != NULL)
799 alpha_blend = (cairo_alpha_blend_func_t)GetProcAddress (msimg32_dll,
803 alpha_blend_checked = TRUE;
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;
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;
818 if (!alpha_blend (dst->dc,
825 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(AlphaBlend)");
827 return CAIRO_STATUS_SUCCESS;
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,
838 cairo_bool_t needs_alpha,
839 cairo_bool_t needs_scale)
841 /* Then do BitBlt, StretchDIBits, StretchBlt, AlphaBlend, or MaskBlt */
843 if (needs_alpha || needs_scale)
844 return CAIRO_INT_STATUS_UNSUPPORTED;
846 if (dst->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHBLT) {
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;
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.
865 * See http://blog.vlad1.com/archives/2006/10/26/134/ and comments.
867 if (!StretchDIBits (dst->dc,
869 dst_r.x, dst_r.y + dst_r.height - 1,
870 dst_r.width, - (int) dst_r.height,
872 src_r.x, src_extents.height - src_r.y + 1,
873 src_r.width, - (int) src_r.height,
878 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(StretchDIBits)");
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,
885 dst_r.width, dst_r.height,
889 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(BitBlt)");
890 } else if (dst->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHBLT) {
892 /* XXX check if we want HALFTONE, based on the src filter */
894 int oldmode = SetStretchBltMode(dst->dc, HALFTONE);
895 success = StretchBlt(dst->dc,
897 dst_r.width, dst_r.height,
900 src_r.width, src_r.height,
902 SetStretchBltMode(dst->dc, oldmode);
905 return _cairo_win32_print_gdi_error ("StretchBlt");
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);
913 return CAIRO_STATUS_SUCCESS;
916 /* from pixman-private.h */
917 #define MOD(a,b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b))
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,
932 cairo_region_t *clip_region)
934 cairo_win32_surface_t *dst = abstract_dst;
935 cairo_win32_surface_t *src;
936 cairo_surface_pattern_t *src_surface_pattern;
938 double scalex, scaley;
939 cairo_fixed_t x0_fixed, y0_fixed;
940 cairo_int_status_t status;
942 cairo_bool_t needs_alpha, needs_scale, needs_repeat;
943 cairo_image_surface_t *src_image = NULL;
945 cairo_format_t src_format;
946 cairo_rectangle_int_t src_extents;
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 };
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);
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.
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))
969 if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
972 if (pattern->extend != CAIRO_EXTEND_NONE &&
973 pattern->extend != CAIRO_EXTEND_REPEAT)
977 /* FIXME: When we fully support RENDER style 4-channel
978 * masks we need to check r/g/b != 1.0.
980 if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID)
981 return CAIRO_INT_STATUS_UNSUPPORTED;
983 alpha = ((cairo_solid_pattern_t *)mask_pattern)->color.alpha_short >> 8;
988 src_surface_pattern = (cairo_surface_pattern_t *)pattern;
989 src = (cairo_win32_surface_t *)src_surface_pattern->surface;
991 if (src->base.type == CAIRO_SURFACE_TYPE_IMAGE &&
992 dst->flags & (CAIRO_WIN32_SURFACE_CAN_STRETCHDIB))
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
999 * - operator is SOURCE or OVER
1000 * - image stride is 4*width
1002 src_image = (cairo_image_surface_t*) src;
1004 if (src_image->format != CAIRO_FORMAT_RGB24 ||
1005 dst->format != CAIRO_FORMAT_RGB24 ||
1007 (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) ||
1008 src_image->stride != (src_image->width * 4))
1013 src_format = src_image->format;
1016 src_extents.width = src_image->width;
1017 src_extents.height = src_image->height;
1018 } else if (src->base.backend != dst->base.backend) {
1021 src_format = src->format;
1022 src_extents = src->extents;
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,
1030 dst_x, dst_y, width, height,
1031 pattern->matrix.x0, pattern->matrix.y0, pattern->matrix.xx, pattern->matrix.yy);
1034 /* We can only use GDI functions if the source and destination rectangles
1035 * are on integer pixel boundaries. Figure that out here.
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);
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))
1048 scalex = pattern->matrix.xx;
1049 scaley = pattern->matrix.yy;
1051 src_r.x += _cairo_fixed_integer_part(x0_fixed);
1052 src_r.y += _cairo_fixed_integer_part(y0_fixed);
1054 /* Success, right? */
1055 if (scalex == 0.0 || scaley == 0.0)
1056 return CAIRO_STATUS_SUCCESS;
1058 if (scalex != 1.0 || scaley != 1.0)
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
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);
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
1080 if (pattern->extend != CAIRO_EXTEND_REPEAT) {
1081 needs_repeat = FALSE;
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.
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)
1089 if (op == CAIRO_OPERATOR_OVER)
1090 return CAIRO_STATUS_SUCCESS;
1095 src_r.width += src_r.x;
1098 dst_r.width += src_r.x;
1103 src_r.height += src_r.y;
1106 dst_r.height += dst_r.y;
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;
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;
1120 needs_repeat = TRUE;
1124 * Operations that we can do:
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
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
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
1141 * RGB SOURCE RGB + mask -> unsupported
1142 * RGB SOURCE ARGB + mask -> unsupported
1143 * ARGB SOURCE ARGB + mask -> unsupported
1144 * ARGB SOURCE RGB + mask -> unsupported
1148 * Figure out what action to take.
1150 if (op == CAIRO_OPERATOR_OVER) {
1152 return CAIRO_STATUS_SUCCESS;
1154 if (src_format == dst->format) {
1155 if (alpha == 255 && src_format == CAIRO_FORMAT_RGB24) {
1156 needs_alpha = FALSE;
1160 } else if (src_format == CAIRO_FORMAT_ARGB32 &&
1161 dst->format == CAIRO_FORMAT_RGB24)
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))
1171 needs_alpha = FALSE;
1179 if (scalex == 1.0 && scaley == 1.0) {
1180 needs_scale = FALSE;
1182 /* Should never be reached until we turn StretchBlt back on */
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);
1193 status = _cairo_win32_surface_set_clip_region (dst, clip_region);
1197 /* If we need to repeat, we turn the repeated blit into
1198 * a bunch of piece-by-piece blits.
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);
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.
1216 if ((src_image || src->image) && dst->image)
1219 /* If the src is not a bitmap but an on-screen (or unknown)
1220 * DC, chances are that fallback will be faster.
1222 if (src->bitmap == NULL)
1225 /* If we can use PatBlt, just do so */
1226 if (!src_image && !needs_alpha)
1230 POINT old_brush_origin;
1232 /* Set up the brush with our bitmap */
1233 brush = CreatePatternBrush (src->bitmap);
1235 /* SetBrushOrgEx sets the coordinates in the destination DC of where the
1236 * pattern should start.
1238 SetBrushOrgEx (dst->dc, dst_r.x - src_start_x,
1239 dst_r.y - src_start_y, &old_brush_origin);
1241 old_brush = SelectObject (dst->dc, brush);
1243 PatBlt (dst->dc, dst_r.x, dst_r.y, dst_r.width, dst_r.height, PATCOPY);
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);
1250 return CAIRO_STATUS_SUCCESS;
1253 /* If we were not able to use PatBlt, then manually expand out the blit */
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.
1259 if (dst_r.width / src_extents.width > 5 ||
1260 dst_r.height / src_extents.height > 5)
1263 for (rendered_height = 0;
1264 rendered_height < dst_r.height;
1265 rendered_height += to_render_height)
1267 piece_y = (src_start_y + rendered_height) % src_extents.height;
1268 to_render_height = src_extents.height - piece_y;
1270 if (rendered_height + to_render_height > dst_r.height)
1271 to_render_height = dst_r.height - rendered_height;
1273 for (rendered_width = 0;
1274 rendered_width < dst_r.width;
1275 rendered_width += to_render_width)
1277 piece_x = (src_start_x + rendered_width) % src_extents.width;
1278 to_render_width = src_extents.width - piece_x;
1280 if (rendered_width + to_render_width > dst_r.width)
1281 to_render_width = dst_r.width - rendered_width;
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;
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;
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)
1312 status = _cairo_win32_surface_composite_inner (src, src_image, dst,
1313 src_extents, src_r, dst_r,
1314 alpha, needs_alpha, needs_scale);
1317 if (status == CAIRO_STATUS_SUCCESS)
1321 /* Fall back to image surface directly, if this is a DIB surface */
1326 return dst->image->backend->composite (op, pattern, mask_pattern,
1336 return CAIRO_INT_STATUS_UNSUPPORTED;
1339 /* This big function tells us how to optimize operators for the
1340 * case of solid destination and constant-alpha source
1342 * Note: This function needs revisiting if we add support for
1343 * super-luminescent colors (a == 0, r,g,b > 0)
1345 static enum { DO_CLEAR, DO_SOURCE, DO_NOTHING, DO_UNSUPPORTED }
1346 categorize_solid_dest_operator (cairo_operator_t op,
1347 unsigned short alpha)
1349 enum { SOURCE_TRANSPARENT, SOURCE_LIGHT, SOURCE_SOLID, SOURCE_OTHER } source;
1351 if (alpha >= 0xff00)
1352 source = SOURCE_SOLID;
1353 else if (alpha < 0x100)
1354 source = SOURCE_TRANSPARENT;
1356 source = SOURCE_OTHER;
1359 case CAIRO_OPERATOR_CLEAR: /* 0 0 */
1360 case CAIRO_OPERATOR_OUT: /* 1 - Ab 0 */
1364 case CAIRO_OPERATOR_SOURCE: /* 1 0 */
1365 case CAIRO_OPERATOR_IN: /* Ab 0 */
1369 case CAIRO_OPERATOR_OVER: /* 1 1 - Aa */
1370 case CAIRO_OPERATOR_ATOP: /* Ab 1 - Aa */
1371 if (source == SOURCE_SOLID)
1373 else if (source == SOURCE_TRANSPARENT)
1376 return DO_UNSUPPORTED;
1379 case CAIRO_OPERATOR_DEST_OUT: /* 0 1 - Aa */
1380 case CAIRO_OPERATOR_XOR: /* 1 - Ab 1 - Aa */
1381 if (source == SOURCE_SOLID)
1383 else if (source == SOURCE_TRANSPARENT)
1386 return DO_UNSUPPORTED;
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 */
1395 case CAIRO_OPERATOR_DEST_IN: /* 0 Aa */
1396 case CAIRO_OPERATOR_DEST_ATOP:/* 1 - Ab Aa */
1397 if (source == SOURCE_SOLID)
1399 else if (source == SOURCE_TRANSPARENT)
1402 return DO_UNSUPPORTED;
1405 case CAIRO_OPERATOR_ADD: /* 1 1 */
1406 if (source == SOURCE_TRANSPARENT)
1409 return DO_UNSUPPORTED;
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;
1431 return DO_UNSUPPORTED;
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,
1442 cairo_win32_surface_t *surface = abstract_surface;
1443 cairo_status_t status;
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
1452 if (surface->format != CAIRO_FORMAT_RGB24)
1453 return CAIRO_INT_STATUS_UNSUPPORTED;
1455 status = _cairo_win32_surface_set_clip_region (surface, NULL);
1459 /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all
1460 * surfaces with alpha.)
1462 switch (categorize_solid_dest_operator (op, color->alpha_short)) {
1464 new_color = RGB (0, 0, 0);
1467 new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8);
1470 return CAIRO_STATUS_SUCCESS;
1471 case DO_UNSUPPORTED:
1473 return CAIRO_INT_STATUS_UNSUPPORTED;
1476 new_brush = CreateSolidBrush (new_color);
1478 return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1480 for (i = 0; i < num_rects; i++) {
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;
1488 if (!FillRect (surface->dc, &rect, new_brush))
1492 DeleteObject (new_brush);
1494 return CAIRO_STATUS_SUCCESS;
1497 status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1499 DeleteObject (new_brush);
1505 _cairo_win32_surface_get_extents (void *abstract_surface,
1506 cairo_rectangle_int_t *rectangle)
1508 cairo_win32_surface_t *surface = abstract_surface;
1510 *rectangle = surface->extents;
1514 static cairo_status_t
1515 _cairo_win32_surface_flush (void *abstract_surface)
1517 return _cairo_win32_surface_set_clip_region (abstract_surface, NULL);
1520 #define STACK_GLYPH_SIZE 256
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,
1528 cairo_scaled_font_t *scaled_font,
1529 const cairo_clip_t *clip,
1530 cairo_bool_t glyph_indexing)
1532 #if CAIRO_HAS_WIN32_FONT
1533 cairo_win32_surface_t *dst = surface;
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;
1540 BOOL win_result = 0;
1543 cairo_solid_pattern_t *solid_pattern;
1546 cairo_matrix_t device_to_logical;
1548 int start_x, start_y;
1549 double user_x, user_y;
1550 int logical_x, logical_y;
1551 unsigned int glyph_index_option;
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;
1557 /* We can only handle opaque solid color sources */
1558 if (!_cairo_pattern_is_opaque_solid(source))
1559 return CAIRO_INT_STATUS_UNSUPPORTED;
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;
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 */
1571 if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) == 0) {
1572 if (! _cairo_clip_is_region (clip))
1573 return CAIRO_INT_STATUS_UNSUPPORTED;
1575 _cairo_win32_surface_set_clip_region (surface,
1576 _cairo_clip_get_region (clip));
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);
1585 cairo_win32_scaled_font_get_device_to_logical(scaled_font, &device_to_logical);
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);
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);
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. */
1605 user_x = glyphs[0].x;
1606 user_y = glyphs[0].y;
1608 cairo_matrix_transform_point(&device_to_logical,
1611 logical_x = _cairo_lround (user_x);
1612 logical_y = _cairo_lround (user_y);
1614 start_x = logical_x;
1615 start_y = logical_y;
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) {
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;
1627 cairo_matrix_transform_point(&device_to_logical,
1628 &next_user_x, &next_user_y);
1630 next_logical_x = _cairo_lround (next_user_x);
1631 next_logical_y = _cairo_lround (next_user_y);
1633 dxy_buf[j] = _cairo_lround (next_logical_x - logical_x);
1634 dxy_buf[j+1] = _cairo_lround (next_logical_y - logical_y);
1636 logical_x = next_logical_x;
1637 logical_y = next_logical_y;
1642 glyph_index_option = ETO_GLYPH_INDEX;
1644 glyph_index_option = 0;
1646 win_result = ExtTextOutW(dst->dc,
1649 glyph_index_option | ETO_PDY,
1655 _cairo_win32_print_gdi_error("_cairo_win32_surface_show_glyphs(ExtTextOutW failed)");
1658 RestoreDC(dst->dc, -1);
1660 if (glyph_buf != glyph_buf_stack) {
1664 return (win_result) ? CAIRO_STATUS_SUCCESS : CAIRO_INT_STATUS_UNSUPPORTED;
1666 return CAIRO_INT_STATUS_UNSUPPORTED;
1670 #undef STACK_GLYPH_SIZE
1673 _cairo_win32_surface_show_glyphs (void *surface,
1674 cairo_operator_t op,
1675 const cairo_pattern_t *source,
1676 cairo_glyph_t *glyphs,
1678 cairo_scaled_font_t *scaled_font,
1679 const cairo_clip_t *clip)
1681 return _cairo_win32_surface_show_glyphs_internal (surface,
1693 * cairo_win32_surface_create:
1694 * @hdc: the DC to create a surface for
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().
1703 * Return value: the newly created surface
1706 cairo_win32_surface_create (HDC hdc)
1708 cairo_win32_surface_t *surface;
1710 cairo_format_t format;
1713 /* Assume that everything coming in as a HDC is RGB24 */
1714 format = CAIRO_FORMAT_RGB24;
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));
1720 if (_cairo_win32_save_initial_clip (hdc, surface) != CAIRO_STATUS_SUCCESS) {
1722 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1725 surface->clip_region = NULL;
1726 surface->image = NULL;
1727 surface->format = format;
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;
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;
1743 surface->flags = _cairo_win32_flags_for_dc (surface->dc);
1745 _cairo_surface_init (&surface->base,
1746 &cairo_win32_surface_backend,
1748 _cairo_content_from_format (format));
1750 return (cairo_surface_t *)surface;
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
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.
1763 * Return value: the newly created surface
1768 cairo_win32_surface_create_with_dib (cairo_format_t format,
1772 return _cairo_win32_surface_create_for_dc (NULL, format, width, height);
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
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.
1786 * Return value: the newly created surface
1791 cairo_win32_surface_create_with_ddb (HDC hdc,
1792 cairo_format_t format,
1796 cairo_win32_surface_t *new_surf;
1798 HDC screen_dc, ddb_dc;
1799 HBITMAP saved_dc_bitmap;
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)
1809 screen_dc = GetDC (NULL);
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));
1821 ddb = CreateCompatibleBitmap (hdc, width, height);
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.
1830 new_surf = (cairo_win32_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1834 saved_dc_bitmap = SelectObject (ddb_dc, ddb);
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;
1843 ReleaseDC (NULL, screen_dc);
1845 return (cairo_surface_t*) new_surf;
1849 * _cairo_surface_is_win32:
1850 * @surface: a #cairo_surface_t
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.
1856 * Return value: True if the surface is an win32 surface
1859 _cairo_surface_is_win32 (cairo_surface_t *surface)
1861 return surface->backend == &cairo_win32_surface_backend;
1865 * cairo_win32_surface_get_dc
1866 * @surface: a #cairo_surface_t
1868 * Returns the HDC associated with this surface, or %NULL if none.
1869 * Also returns %NULL if the surface is not a win32 surface.
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.
1877 * Return value: HDC or %NULL if no HDC available.
1882 cairo_win32_surface_get_dc (cairo_surface_t *surface)
1884 cairo_win32_surface_t *winsurf;
1886 if (_cairo_surface_is_win32 (surface)){
1887 winsurf = (cairo_win32_surface_t *) surface;
1892 if (_cairo_surface_is_paginated (surface)) {
1893 cairo_surface_t *target;
1895 target = _cairo_paginated_surface_get_target (surface);
1897 if (_cairo_surface_is_win32_printing (target)) {
1898 winsurf = (cairo_win32_surface_t *) target;
1908 * cairo_win32_surface_get_image
1909 * @surface: a #cairo_surface_t
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.
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.
1921 cairo_win32_surface_get_image (cairo_surface_t *surface)
1923 if (!_cairo_surface_is_win32(surface))
1926 return ((cairo_win32_surface_t*)surface)->image;
1929 static const cairo_surface_backend_t cairo_win32_surface_backend = {
1930 CAIRO_SURFACE_TYPE_WIN32,
1931 _cairo_win32_surface_finish,
1933 _cairo_default_context_create,
1935 _cairo_win32_surface_create_similar,
1937 _cairo_win32_surface_map_to_image,
1938 _cairo_win32_surface_unmap_image,
1940 _cairo_win32_surface_acquire_source_image,
1941 _cairo_win32_surface_release_source_image,
1942 NULL, /* snapshot */
1944 NULL, /* copy_page */
1945 NULL, /* show_page */
1947 _cairo_win32_surface_get_extents,
1948 NULL, /* get_font_options */
1950 _cairo_win32_surface_flush,
1951 NULL, /* mark_dirty_rectangle */
1957 NULL, /* fill/stroke */
1958 _cairo_win32_surface_show_glyphs,
1963 * Win32 alpha-understanding functions
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!)
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.
1977 _cairo_win32_save_initial_clip (HDC hdc, cairo_win32_surface_t *surface)
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.
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.
1994 * XXX we may need to modify x/y by the ViewportOrg or WindowOrg
1995 * here in GM_COMPATIBLE; unclear.
1997 gm = GetGraphicsMode (hdc);
1998 if (gm == GM_ADVANCED) {
1999 GetWorldTransform (hdc, &saved_xform);
2000 ModifyWorldTransform (hdc, NULL, MWT_IDENTITY);
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);
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;
2016 surface->initial_clip_rgn = NULL;
2017 surface->had_simple_clip = FALSE;
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;
2025 } else if (clipBoxType == SIMPLEREGION) {
2026 surface->had_simple_clip = TRUE;
2029 if (gm == GM_ADVANCED)
2030 SetWorldTransform (hdc, &saved_xform);
2032 return CAIRO_STATUS_SUCCESS;
2036 _cairo_win32_restore_initial_clip (cairo_win32_surface_t *surface)
2038 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
2041 int gm = GetGraphicsMode (surface->dc);
2042 if (gm == GM_ADVANCED) {
2043 GetWorldTransform (surface->dc, &saved_xform);
2044 ModifyWorldTransform (surface->dc, NULL, MWT_IDENTITY);
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);
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);
2059 if (gm == GM_ADVANCED)
2060 SetWorldTransform (surface->dc, &saved_xform);
2066 _cairo_win32_debug_dump_hrgn (HRGN rgn, char *header)
2072 fprintf (stderr, "%s\n", header);
2075 fprintf (stderr, " NULL\n");
2078 z = GetRegionData(rgn, 0, NULL);
2079 rd = (RGNDATA*) malloc(z);
2080 z = GetRegionData(rgn, z, rd);
2082 fprintf (stderr, " %ld rects, bounds: %ld %ld %ld %ld\n",
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);
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);