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.
5 * Copyright © 2012 Intel Corporation
7 * This library is free software; you can redistribute it and/or
8 * modify it either under the terms of the GNU Lesser General Public
9 * License version 2.1 as published by the Free Software Foundation
10 * (the "LGPL") or, at your option, under the terms of the Mozilla
11 * Public License Version 1.1 (the "MPL"). If you do not alter this
12 * notice, a recipient may use your version of this file under either
13 * the MPL or the LGPL.
15 * You should have received a copy of the LGPL along with this library
16 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18 * You should have received a copy of the MPL along with this library
19 * in the file COPYING-MPL-1.1
21 * The contents of this file are subject to the Mozilla Public License
22 * Version 1.1 (the "License"); you may not use this file except in
23 * compliance with the License. You may obtain a copy of the License at
24 * http://www.mozilla.org/MPL/
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 * the specific language governing rights and limitations.
30 * The Original Code is the cairo graphics library.
32 * The Initial Developer of the Original Code is Red Hat, Inc.
35 * Owen Taylor <otaylor@redhat.com>
36 * Stuart Parmenter <stuart@mozilla.com>
37 * Vladimir Vukicevic <vladimir@pobox.com>
40 #define WIN32_LEAN_AND_MEAN
41 /* We require Windows 2000 features such as ETO_PDY */
42 #if !defined(WINVER) || (WINVER < 0x0500)
43 # define WINVER 0x0500
45 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
46 # define _WIN32_WINNT 0x0500
51 #include "cairo-clip-private.h"
52 #include "cairo-composite-rectangles-private.h"
53 #include "cairo-compositor-private.h"
54 #include "cairo-damage-private.h"
55 #include "cairo-default-context-private.h"
56 #include "cairo-error-private.h"
57 #include "cairo-image-surface-inline.h"
58 #include "cairo-paginated-private.h"
59 #include "cairo-pattern-private.h"
60 #include "cairo-win32-private.h"
61 #include "cairo-scaled-font-subsets-private.h"
62 #include "cairo-surface-fallback-private.h"
63 #include "cairo-surface-backend-private.h"
68 #if defined(__MINGW32__) && !defined(ETO_PDY)
69 # define ETO_PDY 0x2000
72 #define PELS_72DPI ((LONG)(72. / 0.0254))
76 * @Title: Win32 Surfaces
77 * @Short_Description: Microsoft Windows surface support
78 * @See_Also: #cairo_surface_t
80 * The Microsoft Windows surface is used to render cairo graphics to
81 * Microsoft Windows windows, bitmaps, and printing device contexts.
83 * The surface returned by cairo_win32_printing_surface_create() is of surface
84 * type %CAIRO_SURFACE_TYPE_WIN32_PRINTING and is a multi-page vector surface
87 * The surface returned by the other win32 constructors is of surface type
88 * %CAIRO_SURFACE_TYPE_WIN32 and is a raster surface type.
92 * CAIRO_HAS_WIN32_SURFACE:
94 * Defined if the Microsoft Windows surface backend is available.
95 * This macro can be used to conditionally compile backend-specific code.
100 static const cairo_surface_backend_t cairo_win32_display_surface_backend;
102 static cairo_status_t
103 _create_dc_and_bitmap (cairo_win32_display_surface_t *surface,
105 cairo_format_t format,
108 unsigned char **bits_out,
111 cairo_status_t status;
113 BITMAPINFO *bitmap_info = NULL;
115 BITMAPINFOHEADER bmiHeader;
116 RGBQUAD bmiColors[2];
120 int num_palette = 0; /* Quiet GCC */
123 surface->win32.dc = NULL;
124 surface->bitmap = NULL;
125 surface->is_dib = FALSE;
129 case CAIRO_FORMAT_INVALID:
130 case CAIRO_FORMAT_RGB16_565:
131 case CAIRO_FORMAT_RGB30:
132 return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
133 case CAIRO_FORMAT_ARGB32:
134 case CAIRO_FORMAT_RGB24:
138 case CAIRO_FORMAT_A8:
142 case CAIRO_FORMAT_A1:
147 if (num_palette > 2) {
148 bitmap_info = _cairo_malloc_ab_plus_c (num_palette, sizeof(RGBQUAD), sizeof(BITMAPINFOHEADER));
150 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
152 bitmap_info = (BITMAPINFO *)&bmi_stack;
155 bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
156 bitmap_info->bmiHeader.biWidth = width == 0 ? 1 : width;
157 bitmap_info->bmiHeader.biHeight = height == 0 ? -1 : - height; /* top-down */
158 bitmap_info->bmiHeader.biSizeImage = 0;
159 bitmap_info->bmiHeader.biXPelsPerMeter = PELS_72DPI; /* unused here */
160 bitmap_info->bmiHeader.biYPelsPerMeter = PELS_72DPI; /* unused here */
161 bitmap_info->bmiHeader.biPlanes = 1;
164 case CAIRO_FORMAT_INVALID:
165 case CAIRO_FORMAT_RGB16_565:
166 case CAIRO_FORMAT_RGB30:
168 /* We can't create real RGB24 bitmaps because something seems to
169 * break if we do, especially if we don't set up an image
170 * fallback. It could be a bug with using a 24bpp pixman image
171 * (and creating one with masks). So treat them like 32bpp.
172 * Note: This causes problems when using BitBlt/AlphaBlend/etc!
175 case CAIRO_FORMAT_RGB24:
176 case CAIRO_FORMAT_ARGB32:
177 bitmap_info->bmiHeader.biBitCount = 32;
178 bitmap_info->bmiHeader.biCompression = BI_RGB;
179 bitmap_info->bmiHeader.biClrUsed = 0; /* unused */
180 bitmap_info->bmiHeader.biClrImportant = 0;
183 case CAIRO_FORMAT_A8:
184 bitmap_info->bmiHeader.biBitCount = 8;
185 bitmap_info->bmiHeader.biCompression = BI_RGB;
186 bitmap_info->bmiHeader.biClrUsed = 256;
187 bitmap_info->bmiHeader.biClrImportant = 0;
189 for (i = 0; i < 256; i++) {
190 bitmap_info->bmiColors[i].rgbBlue = i;
191 bitmap_info->bmiColors[i].rgbGreen = i;
192 bitmap_info->bmiColors[i].rgbRed = i;
193 bitmap_info->bmiColors[i].rgbReserved = 0;
197 case CAIRO_FORMAT_A1:
198 bitmap_info->bmiHeader.biBitCount = 1;
199 bitmap_info->bmiHeader.biCompression = BI_RGB;
200 bitmap_info->bmiHeader.biClrUsed = 2;
201 bitmap_info->bmiHeader.biClrImportant = 0;
203 for (i = 0; i < 2; i++) {
204 bitmap_info->bmiColors[i].rgbBlue = i * 255;
205 bitmap_info->bmiColors[i].rgbGreen = i * 255;
206 bitmap_info->bmiColors[i].rgbRed = i * 255;
207 bitmap_info->bmiColors[i].rgbReserved = 0;
212 surface->win32.dc = CreateCompatibleDC (original_dc);
213 if (!surface->win32.dc)
216 surface->bitmap = CreateDIBSection (surface->win32.dc,
221 if (!surface->bitmap)
224 surface->is_dib = TRUE;
228 surface->saved_dc_bitmap = SelectObject (surface->win32.dc,
230 if (!surface->saved_dc_bitmap)
233 if (bitmap_info && num_palette > 2)
240 /* Windows bitmaps are padded to 32-bit (dword) boundaries */
242 case CAIRO_FORMAT_INVALID:
243 case CAIRO_FORMAT_RGB16_565:
244 case CAIRO_FORMAT_RGB30:
246 case CAIRO_FORMAT_ARGB32:
247 case CAIRO_FORMAT_RGB24:
248 *rowstride_out = 4 * width;
251 case CAIRO_FORMAT_A8:
252 *rowstride_out = (width + 3) & ~3;
255 case CAIRO_FORMAT_A1:
256 *rowstride_out = ((width + 31) & ~31) / 8;
261 surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc);
263 return CAIRO_STATUS_SUCCESS;
266 status = _cairo_win32_print_gdi_error (__FUNCTION__);
268 if (bitmap_info && num_palette > 2)
271 if (surface->saved_dc_bitmap) {
272 SelectObject (surface->win32.dc, surface->saved_dc_bitmap);
273 surface->saved_dc_bitmap = NULL;
276 if (surface->bitmap) {
277 DeleteObject (surface->bitmap);
278 surface->bitmap = NULL;
281 if (surface->win32.dc) {
282 DeleteDC (surface->win32.dc);
283 surface->win32.dc = NULL;
289 static cairo_surface_t *
290 _cairo_win32_display_surface_create_for_dc (HDC original_dc,
291 cairo_format_t format,
295 cairo_status_t status;
296 cairo_device_t *device;
297 cairo_win32_display_surface_t *surface;
301 surface = malloc (sizeof (*surface));
303 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
305 surface->fallback = NULL;
307 status = _create_dc_and_bitmap (surface, original_dc, format,
313 surface->image = cairo_image_surface_create_for_data (bits, format,
314 width, height, rowstride);
315 status = surface->image->status;
319 _cairo_image_surface_set_parent (to_image_surface(surface->image),
320 &surface->win32.base);
322 surface->win32.format = format;
324 surface->win32.extents.x = 0;
325 surface->win32.extents.y = 0;
326 surface->win32.extents.width = width;
327 surface->win32.extents.height = height;
329 surface->initial_clip_rgn = NULL;
330 surface->had_simple_clip = FALSE;
332 device = _cairo_win32_device_get ();
334 _cairo_surface_init (&surface->win32.base,
335 &cairo_win32_display_surface_backend,
337 _cairo_content_from_format (format));
339 cairo_device_destroy (device);
341 return &surface->win32.base;
344 if (surface->bitmap) {
345 SelectObject (surface->win32.dc, surface->saved_dc_bitmap);
346 DeleteObject (surface->bitmap);
347 DeleteDC (surface->win32.dc);
351 return _cairo_surface_create_in_error (status);
354 static cairo_surface_t *
355 _cairo_win32_display_surface_create_similar (void *abstract_src,
356 cairo_content_t content,
360 cairo_win32_display_surface_t *src = abstract_src;
361 cairo_format_t format = _cairo_format_from_content (content);
362 cairo_surface_t *new_surf = NULL;
364 /* We force a DIB always if:
365 * - we need alpha; or
366 * - the parent is a DIB; or
367 * - the parent is for printing (because we don't care about the
368 * bit depth at that point)
370 * We also might end up with a DIB even if a DDB is requested if
371 * DDB creation failed due to out of memory.
373 if (!(src->is_dib || content & CAIRO_CONTENT_ALPHA)) {
374 /* try to create a ddb */
375 new_surf = cairo_win32_surface_create_with_ddb (src->win32.dc, CAIRO_FORMAT_RGB24, width, height);
377 if (new_surf->status)
381 if (new_surf == NULL) {
382 new_surf = _cairo_win32_display_surface_create_for_dc (src->win32.dc, format, width, height);
388 static cairo_surface_t *
389 _cairo_win32_display_surface_create_similar_image (void *abstract_other,
390 cairo_format_t format,
394 cairo_win32_display_surface_t *surface = abstract_other;
396 surface = (cairo_win32_display_surface_t *)
397 _cairo_win32_display_surface_create_for_dc (surface->win32.dc,
398 format, width, height);
399 if (surface->win32.base.status)
400 return &surface->win32.base;
402 return surface->image;
405 static cairo_status_t
406 _cairo_win32_display_surface_finish (void *abstract_surface)
408 cairo_win32_display_surface_t *surface = abstract_surface;
410 if (surface->image) {
411 /* Unhook ourselves first to avoid the double-unref from the image */
412 to_image_surface(surface->image)->parent = NULL;
413 cairo_surface_finish (surface->image);
414 cairo_surface_destroy (surface->image);
417 /* If we created the Bitmap and DC, destroy them */
418 if (surface->bitmap) {
419 SelectObject (surface->win32.dc, surface->saved_dc_bitmap);
420 DeleteObject (surface->bitmap);
421 DeleteDC (surface->win32.dc);
424 if (surface->initial_clip_rgn)
425 DeleteObject (surface->initial_clip_rgn);
427 return CAIRO_STATUS_SUCCESS;
430 static cairo_surface_t *
431 _cairo_win32_display_surface_map_to_image (void *abstract_surface,
432 const cairo_rectangle_int_t *extents)
434 cairo_win32_display_surface_t *surface = abstract_surface;
435 cairo_status_t status;
437 TRACE ((stderr, "%s (surface=%d)\n",
438 __FUNCTION__, surface->win32.base.unique_id));
443 if (surface->fallback == NULL) {
445 _cairo_win32_display_surface_create_for_dc (surface->win32.dc,
446 surface->win32.format,
447 surface->win32.extents.width,
448 surface->win32.extents.height);
449 if (unlikely (status = surface->fallback->status))
452 if (!BitBlt (to_win32_surface(surface->fallback)->dc,
454 surface->win32.extents.width,
455 surface->win32.extents.height,
459 status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
464 surface = to_win32_display_surface (surface->fallback);
467 return _cairo_image_surface_map_to_image (surface->image, extents);
470 cairo_surface_destroy (surface->fallback);
471 surface->fallback = NULL;
473 return _cairo_surface_create_in_error (status);
476 static cairo_int_status_t
477 _cairo_win32_display_surface_unmap_image (void *abstract_surface,
478 cairo_image_surface_t *image)
480 cairo_win32_display_surface_t *surface = abstract_surface;
482 /* Delay the download until the next flush, which means we also need
483 * to make sure our sources rare flushed.
485 TRACE ((stderr, "%s (surface=%d)\n",
486 __FUNCTION__, to_win32_surface(surface)->base.unique_id));
488 if (surface->fallback) {
489 cairo_rectangle_int_t r;
491 r.x = image->base.device_transform_inverse.x0;
492 r.y = image->base.device_transform_inverse.y0;
493 r.width = image->width;
494 r.height = image->height;
496 TRACE ((stderr, "%s: adding damage (%d,%d)x(%d,%d)\n",
497 __FUNCTION__, r.x, r.y, r.width, r.height));
498 surface->fallback->damage =
499 _cairo_damage_add_rectangle (surface->fallback->damage, &r);
502 return CAIRO_INT_STATUS_SUCCESS;
505 static cairo_status_t
506 _cairo_win32_display_surface_flush (void *abstract_surface)
508 cairo_win32_display_surface_t *surface = abstract_surface;
509 cairo_status_t status = CAIRO_STATUS_SUCCESS;
511 TRACE ((stderr, "%s (surface=%d)\n",
512 __FUNCTION__, surface->win32.base.unique_id));
513 if (surface->fallback == NULL)
514 return CAIRO_STATUS_SUCCESS;
516 if (surface->fallback->damage) {
517 cairo_win32_display_surface_t *fallback;
518 cairo_damage_t *damage;
520 damage = _cairo_damage_reduce (surface->fallback->damage);
521 surface->fallback->damage = NULL;
523 fallback = to_win32_display_surface (surface->fallback);
524 assert (fallback->image);
526 TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__,
527 damage->region ? cairo_region_num_rectangles (damage->region) : 0));
529 if (damage->status) {
530 if (!BitBlt (surface->win32.dc,
532 surface->win32.extents.width,
533 surface->win32.extents.height,
537 status = _cairo_win32_print_gdi_error (__FUNCTION__);
538 } else if (damage->region) {
539 int n = cairo_region_num_rectangles (damage->region), i;
540 for (i = 0; i < n; i++) {
541 cairo_rectangle_int_t rect;
543 cairo_region_get_rectangle (damage->region, i, &rect);
544 TRACE ((stderr, "%s: damage (%d,%d)x(%d,%d)\n", __FUNCTION__,
546 rect.width, rect.height));
547 if (!BitBlt (surface->win32.dc,
549 rect.width, rect.height,
553 status = _cairo_win32_print_gdi_error (__FUNCTION__);
558 _cairo_damage_destroy (damage);
560 cairo_surface_destroy (surface->fallback);
561 surface->fallback = NULL;
567 static cairo_status_t
568 _cairo_win32_display_surface_mark_dirty (void *abstract_surface,
569 int x, int y, int width, int height)
571 _cairo_win32_display_surface_discard_fallback (abstract_surface);
572 return CAIRO_STATUS_SUCCESS;
575 static cairo_int_status_t
576 _cairo_win32_save_initial_clip (HDC hdc, cairo_win32_display_surface_t *surface)
583 /* GetClipBox/GetClipRgn and friends interact badly with a world transform
584 * set. GetClipBox returns values in logical (transformed) coordinates;
585 * it's unclear what GetClipRgn returns, because the region is empty in the
586 * case of a SIMPLEREGION clip, but I assume device (untransformed) coordinates.
587 * Similarly, IntersectClipRect works in logical units, whereas SelectClipRgn
588 * works in device units.
590 * So, avoid the whole mess and get rid of the world transform
591 * while we store our initial data and when we restore initial coordinates.
593 * XXX we may need to modify x/y by the ViewportOrg or WindowOrg
594 * here in GM_COMPATIBLE; unclear.
596 gm = GetGraphicsMode (hdc);
597 if (gm == GM_ADVANCED) {
598 GetWorldTransform (hdc, &saved_xform);
599 ModifyWorldTransform (hdc, NULL, MWT_IDENTITY);
602 clipBoxType = GetClipBox (hdc, &rect);
603 if (clipBoxType == ERROR) {
604 _cairo_win32_print_gdi_error (__FUNCTION__);
605 SetGraphicsMode (hdc, gm);
606 /* XXX: Can we make a more reasonable guess at the error cause here? */
607 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
610 surface->win32.extents.x = rect.left;
611 surface->win32.extents.y = rect.top;
612 surface->win32.extents.width = rect.right - rect.left;
613 surface->win32.extents.height = rect.bottom - rect.top;
615 surface->initial_clip_rgn = NULL;
616 surface->had_simple_clip = FALSE;
618 if (clipBoxType == COMPLEXREGION) {
619 surface->initial_clip_rgn = CreateRectRgn (0, 0, 0, 0);
620 if (GetClipRgn (hdc, surface->initial_clip_rgn) <= 0) {
621 DeleteObject(surface->initial_clip_rgn);
622 surface->initial_clip_rgn = NULL;
624 } else if (clipBoxType == SIMPLEREGION) {
625 surface->had_simple_clip = TRUE;
628 if (gm == GM_ADVANCED)
629 SetWorldTransform (hdc, &saved_xform);
631 return CAIRO_STATUS_SUCCESS;
635 _cairo_win32_display_surface_set_clip (cairo_win32_display_surface_t *surface,
639 cairo_rectangle_int_t extents;
646 cairo_status_t status;
647 cairo_region_t *region;
649 /* The semantics we want is that any clip set by cairo combines
650 * is intersected with the clip on device context that the
651 * surface was created for. To implement this, we need to
652 * save the original clip when first setting a clip on surface.
655 assert (_cairo_clip_is_region (clip));
656 region = _cairo_clip_get_region (clip);
658 return CAIRO_STATUS_SUCCESS;
660 cairo_region_get_extents (region, &extents);
661 num_rects = cairo_region_num_rectangles (region);
663 /* XXX see notes in _cairo_win32_save_initial_clip --
664 * this code will interact badly with a HDC which had an initial
665 * world transform -- we should probably manually transform the
666 * region rects, because SelectClipRgn takes device units, not
667 * logical units (unlike IntersectClipRect).
670 data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT);
671 if (data_size > sizeof (stack)) {
672 data = malloc (data_size);
674 return _cairo_error(CAIRO_STATUS_NO_MEMORY);
676 data = (RGNDATA *)stack;
678 data->rdh.dwSize = sizeof (RGNDATAHEADER);
679 data->rdh.iType = RDH_RECTANGLES;
680 data->rdh.nCount = num_rects;
681 data->rdh.nRgnSize = num_rects * sizeof (RECT);
682 data->rdh.rcBound.left = extents.x;
683 data->rdh.rcBound.top = extents.y;
684 data->rdh.rcBound.right = extents.x + extents.width;
685 data->rdh.rcBound.bottom = extents.y + extents.height;
687 rects = (RECT *)data->Buffer;
688 for (i = 0; i < num_rects; i++) {
689 cairo_rectangle_int_t rect;
691 cairo_region_get_rectangle (region, i, &rect);
693 rects[i].left = rect.x;
694 rects[i].top = rect.y;
695 rects[i].right = rect.x + rect.width;
696 rects[i].bottom = rect.y + rect.height;
699 gdi_region = ExtCreateRegion (NULL, data_size, data);
700 if ((char *)data != stack)
704 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
706 /* AND the new region into our DC */
707 status = CAIRO_STATUS_SUCCESS;
708 if (ExtSelectClipRgn (surface->win32.dc, gdi_region, RGN_AND) == ERROR)
709 status = _cairo_win32_print_gdi_error (__FUNCTION__);
711 DeleteObject (gdi_region);
717 _cairo_win32_display_surface_unset_clip (cairo_win32_display_surface_t *surface)
720 int gm = GetGraphicsMode (surface->win32.dc);
721 if (gm == GM_ADVANCED) {
722 GetWorldTransform (surface->win32.dc, &saved_xform);
723 ModifyWorldTransform (surface->win32.dc, NULL, MWT_IDENTITY);
726 /* initial_clip_rgn will either be a real region or NULL (which means reset to no clip region) */
727 SelectClipRgn (surface->win32.dc, surface->initial_clip_rgn);
729 if (surface->had_simple_clip) {
730 /* then if we had a simple clip, intersect */
731 IntersectClipRect (surface->win32.dc,
732 surface->win32.extents.x,
733 surface->win32.extents.y,
734 surface->win32.extents.x + surface->win32.extents.width,
735 surface->win32.extents.y + surface->win32.extents.height);
738 if (gm == GM_ADVANCED)
739 SetWorldTransform (surface->win32.dc, &saved_xform);
743 _cairo_win32_display_surface_discard_fallback (cairo_win32_display_surface_t *surface)
745 if (surface->fallback) {
746 TRACE ((stderr, "%s (surface=%d)\n",
747 __FUNCTION__, surface->win32.base.unique_id));
749 cairo_surface_destroy (surface->fallback);
750 surface->fallback = NULL;
754 static cairo_int_status_t
755 _cairo_win32_display_surface_paint (void *surface,
757 const cairo_pattern_t *source,
758 const cairo_clip_t *clip)
760 cairo_win32_device_t *device = to_win32_device_from_surface (surface);
762 TRACE ((stderr, "%s (surface=%d)\n",
763 __FUNCTION__, to_win32_surface(surface)->base.unique_id));
766 (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_CLEAR))
767 _cairo_win32_display_surface_discard_fallback (surface);
769 return _cairo_compositor_paint (device->compositor,
770 surface, op, source, clip);
773 static cairo_int_status_t
774 _cairo_win32_display_surface_mask (void *surface,
776 const cairo_pattern_t *source,
777 const cairo_pattern_t *mask,
778 const cairo_clip_t *clip)
780 cairo_win32_device_t *device = to_win32_device_from_surface (surface);
782 TRACE ((stderr, "%s (surface=%d)\n",
783 __FUNCTION__, to_win32_surface(surface)->base.unique_id));
785 if (clip == NULL && op == CAIRO_OPERATOR_SOURCE)
786 _cairo_win32_display_surface_discard_fallback (surface);
788 return _cairo_compositor_mask (device->compositor,
789 surface, op, source, mask, clip);
792 static cairo_int_status_t
793 _cairo_win32_display_surface_stroke (void *surface,
795 const cairo_pattern_t *source,
796 const cairo_path_fixed_t *path,
797 const cairo_stroke_style_t *style,
798 const cairo_matrix_t *ctm,
799 const cairo_matrix_t *ctm_inverse,
801 cairo_antialias_t antialias,
802 const cairo_clip_t *clip)
804 cairo_win32_device_t *device = to_win32_device_from_surface (surface);
806 TRACE ((stderr, "%s (surface=%d)\n",
807 __FUNCTION__, to_win32_surface(surface)->base.unique_id));
809 return _cairo_compositor_stroke (device->compositor, surface,
811 style, ctm, ctm_inverse,
812 tolerance, antialias, clip);
815 static cairo_int_status_t
816 _cairo_win32_display_surface_fill (void *surface,
818 const cairo_pattern_t *source,
819 const cairo_path_fixed_t *path,
820 cairo_fill_rule_t fill_rule,
822 cairo_antialias_t antialias,
823 const cairo_clip_t *clip)
825 cairo_win32_device_t *device = to_win32_device_from_surface (surface);
827 TRACE ((stderr, "%s (surface=%d)\n",
828 __FUNCTION__, to_win32_surface(surface)->base.unique_id));
830 return _cairo_compositor_fill (device->compositor, surface,
832 fill_rule, tolerance, antialias,
836 static cairo_int_status_t
837 _cairo_win32_display_surface_glyphs (void *surface,
839 const cairo_pattern_t *source,
840 cairo_glyph_t *glyphs,
842 cairo_scaled_font_t *scaled_font,
843 const cairo_clip_t *clip)
845 cairo_win32_device_t *device = to_win32_device_from_surface (surface);
847 TRACE ((stderr, "%s (surface=%d)\n",
848 __FUNCTION__, to_win32_surface(surface)->base.unique_id));
850 return _cairo_compositor_glyphs (device->compositor, surface,
852 glyphs, num_glyphs, scaled_font,
856 static const cairo_surface_backend_t cairo_win32_display_surface_backend = {
857 CAIRO_SURFACE_TYPE_WIN32,
858 _cairo_win32_display_surface_finish,
860 _cairo_default_context_create,
862 _cairo_win32_display_surface_create_similar,
863 _cairo_win32_display_surface_create_similar_image,
864 _cairo_win32_display_surface_map_to_image,
865 _cairo_win32_display_surface_unmap_image,
867 _cairo_surface_default_source,
868 _cairo_surface_default_acquire_source_image,
869 _cairo_surface_default_release_source_image,
872 NULL, /* copy_page */
873 NULL, /* show_page */
875 _cairo_win32_surface_get_extents,
876 NULL, /* get_font_options */
878 _cairo_win32_display_surface_flush,
879 _cairo_win32_display_surface_mark_dirty,
881 _cairo_win32_display_surface_paint,
882 _cairo_win32_display_surface_mask,
883 _cairo_win32_display_surface_stroke,
884 _cairo_win32_display_surface_fill,
885 NULL, /* fill/stroke */
886 _cairo_win32_display_surface_glyphs,
891 * Win32 alpha-understanding functions
893 * BitBlt - will copy full 32 bits from a 32bpp DIB to result
894 * (so it's safe to use for ARGB32->ARGB32 SOURCE blits)
895 * (but not safe going RGB24->ARGB32, if RGB24 is also represented
896 * as a 32bpp DIB, since the alpha isn't discarded!)
898 * AlphaBlend - if both the source and dest have alpha, even if AC_SRC_ALPHA isn't set,
899 * it will still copy over the src alpha, because the SCA value (255) will be
900 * multiplied by all the src components.
904 * cairo_win32_surface_create:
905 * @hdc: the DC to create a surface for
907 * Creates a cairo surface that targets the given DC. The DC will be
908 * queried for its initial clip extents, and this will be used as the
909 * size of the cairo surface. The resulting surface will always be of
910 * format %CAIRO_FORMAT_RGB24; should you need another surface format,
911 * you will need to create one through
912 * cairo_win32_surface_create_with_dib().
914 * Return value: the newly created surface
919 cairo_win32_surface_create (HDC hdc)
921 cairo_win32_display_surface_t *surface;
923 cairo_format_t format;
924 cairo_status_t status;
925 cairo_device_t *device;
927 /* Assume that everything coming in as a HDC is RGB24 */
928 format = CAIRO_FORMAT_RGB24;
930 surface = malloc (sizeof (*surface));
932 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
934 status = _cairo_win32_save_initial_clip (hdc, surface);
937 return _cairo_surface_create_in_error (status);
940 surface->image = NULL;
941 surface->fallback = NULL;
942 surface->win32.format = format;
944 surface->win32.dc = hdc;
945 surface->bitmap = NULL;
946 surface->is_dib = FALSE;
947 surface->saved_dc_bitmap = NULL;
949 surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc);
951 device = _cairo_win32_device_get ();
953 _cairo_surface_init (&surface->win32.base,
954 &cairo_win32_display_surface_backend,
956 _cairo_content_from_format (format));
958 cairo_device_destroy (device);
960 return &surface->win32.base;
964 * cairo_win32_surface_create_with_dib:
965 * @format: format of pixels in the surface to create
966 * @width: width of the surface, in pixels
967 * @height: height of the surface, in pixels
969 * Creates a device-independent-bitmap surface not associated with
970 * any particular existing surface or device context. The created
971 * bitmap will be uninitialized.
973 * Return value: the newly created surface
978 cairo_win32_surface_create_with_dib (cairo_format_t format,
982 if (! CAIRO_FORMAT_VALID (format))
983 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
985 return _cairo_win32_display_surface_create_for_dc (NULL, format, width, height);
989 * cairo_win32_surface_create_with_ddb:
990 * @hdc: a DC compatible with the surface to create
991 * @format: format of pixels in the surface to create
992 * @width: width of the surface, in pixels
993 * @height: height of the surface, in pixels
995 * Creates a device-dependent-bitmap surface not associated with
996 * any particular existing surface or device context. The created
997 * bitmap will be uninitialized.
999 * Return value: the newly created surface
1004 cairo_win32_surface_create_with_ddb (HDC hdc,
1005 cairo_format_t format,
1009 cairo_win32_display_surface_t *new_surf;
1011 HDC screen_dc, ddb_dc;
1012 HBITMAP saved_dc_bitmap;
1014 if (format != CAIRO_FORMAT_RGB24)
1015 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
1016 /* XXX handle these eventually
1017 format != CAIRO_FORMAT_A8 ||
1018 format != CAIRO_FORMAT_A1)
1022 screen_dc = GetDC (NULL);
1028 ddb_dc = CreateCompatibleDC (hdc);
1029 if (ddb_dc == NULL) {
1030 new_surf = (cairo_win32_display_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1034 ddb = CreateCompatibleBitmap (hdc, width, height);
1038 /* Note that if an app actually does hit this out of memory
1039 * condition, it's going to have lots of other issues, as
1040 * video memory is probably exhausted. However, it can often
1041 * continue using DIBs instead of DDBs.
1043 new_surf = (cairo_win32_display_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1047 saved_dc_bitmap = SelectObject (ddb_dc, ddb);
1049 new_surf = (cairo_win32_display_surface_t*) cairo_win32_surface_create (ddb_dc);
1050 new_surf->bitmap = ddb;
1051 new_surf->saved_dc_bitmap = saved_dc_bitmap;
1052 new_surf->is_dib = FALSE;
1056 ReleaseDC (NULL, screen_dc);
1058 return &new_surf->win32.base;