diff options
Diffstat (limited to 'libs/cairo-1.16.0/src/win32/cairo-win32-display-surface.c')
-rw-r--r-- | libs/cairo-1.16.0/src/win32/cairo-win32-display-surface.c | 1147 |
1 files changed, 0 insertions, 1147 deletions
diff --git a/libs/cairo-1.16.0/src/win32/cairo-win32-display-surface.c b/libs/cairo-1.16.0/src/win32/cairo-win32-display-surface.c deleted file mode 100644 index 304d34a..0000000 --- a/libs/cairo-1.16.0/src/win32/cairo-win32-display-surface.c +++ /dev/null @@ -1,1147 +0,0 @@ -/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ -/* Cairo - a vector graphics library with display and print output - * - * Copyright © 2005 Red Hat, Inc. - * Copyright © 2012 Intel Corporation - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - * The Original Code is the cairo graphics library. - * - * The Initial Developer of the Original Code is Red Hat, Inc. - * - * Contributor(s): - * Owen Taylor <otaylor@redhat.com> - * Stuart Parmenter <stuart@mozilla.com> - * Vladimir Vukicevic <vladimir@pobox.com> - */ - -#define WIN32_LEAN_AND_MEAN -/* We require Windows 2000 features such as ETO_PDY */ -#if !defined(WINVER) || (WINVER < 0x0500) -# define WINVER 0x0500 -#endif -#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500) -# define _WIN32_WINNT 0x0500 -#endif - -#include "cairoint.h" - -#include "cairo-clip-private.h" -#include "cairo-composite-rectangles-private.h" -#include "cairo-compositor-private.h" -#include "cairo-damage-private.h" -#include "cairo-default-context-private.h" -#include "cairo-error-private.h" -#include "cairo-image-surface-inline.h" -#include "cairo-paginated-private.h" -#include "cairo-pattern-private.h" -#include "cairo-win32-private.h" -#include "cairo-scaled-font-subsets-private.h" -#include "cairo-surface-fallback-private.h" -#include "cairo-surface-backend-private.h" - -#include <wchar.h> -#include <windows.h> - -#if defined(__MINGW32__) && !defined(ETO_PDY) -# define ETO_PDY 0x2000 -#endif - -#define PELS_72DPI ((LONG)(72. / 0.0254)) - -/** - * SECTION:cairo-win32 - * @Title: Win32 Surfaces - * @Short_Description: Microsoft Windows surface support - * @See_Also: #cairo_surface_t - * - * The Microsoft Windows surface is used to render cairo graphics to - * Microsoft Windows windows, bitmaps, and printing device contexts. - * - * The surface returned by cairo_win32_printing_surface_create() is of surface - * type %CAIRO_SURFACE_TYPE_WIN32_PRINTING and is a multi-page vector surface - * type. - * - * The surface returned by the other win32 constructors is of surface type - * %CAIRO_SURFACE_TYPE_WIN32 and is a raster surface type. - **/ - -/** - * CAIRO_HAS_WIN32_SURFACE: - * - * Defined if the Microsoft Windows surface backend is available. - * This macro can be used to conditionally compile backend-specific code. - * - * Since: 1.0 - **/ - -static const cairo_surface_backend_t cairo_win32_display_surface_backend; - -static cairo_status_t -_create_dc_and_bitmap (cairo_win32_display_surface_t *surface, - HDC original_dc, - cairo_format_t format, - int width, - int height, - unsigned char **bits_out, - int *rowstride_out) -{ - cairo_status_t status; - - BITMAPINFO *bitmap_info = NULL; - struct { - BITMAPINFOHEADER bmiHeader; - RGBQUAD bmiColors[2]; - } bmi_stack; - void *bits; - - int num_palette = 0; /* Quiet GCC */ - int i; - - surface->win32.dc = NULL; - surface->bitmap = NULL; - surface->is_dib = FALSE; - - switch (format) { - default: - case CAIRO_FORMAT_INVALID: - case CAIRO_FORMAT_RGB16_565: - case CAIRO_FORMAT_RGB30: - return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); - case CAIRO_FORMAT_ARGB32: - case CAIRO_FORMAT_RGB24: - num_palette = 0; - break; - - case CAIRO_FORMAT_A8: - num_palette = 256; - break; - - case CAIRO_FORMAT_A1: - num_palette = 2; - break; - } - - if (num_palette > 2) { - bitmap_info = _cairo_malloc_ab_plus_c (num_palette, sizeof(RGBQUAD), sizeof(BITMAPINFOHEADER)); - if (!bitmap_info) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } else { - bitmap_info = (BITMAPINFO *)&bmi_stack; - } - - bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER); - bitmap_info->bmiHeader.biWidth = width == 0 ? 1 : width; - bitmap_info->bmiHeader.biHeight = height == 0 ? -1 : - height; /* top-down */ - bitmap_info->bmiHeader.biSizeImage = 0; - bitmap_info->bmiHeader.biXPelsPerMeter = PELS_72DPI; /* unused here */ - bitmap_info->bmiHeader.biYPelsPerMeter = PELS_72DPI; /* unused here */ - bitmap_info->bmiHeader.biPlanes = 1; - - switch (format) { - case CAIRO_FORMAT_INVALID: - case CAIRO_FORMAT_RGB16_565: - case CAIRO_FORMAT_RGB30: - ASSERT_NOT_REACHED; - /* We can't create real RGB24 bitmaps because something seems to - * break if we do, especially if we don't set up an image - * fallback. It could be a bug with using a 24bpp pixman image - * (and creating one with masks). So treat them like 32bpp. - * Note: This causes problems when using BitBlt/AlphaBlend/etc! - * see end of file. - */ - case CAIRO_FORMAT_RGB24: - case CAIRO_FORMAT_ARGB32: - bitmap_info->bmiHeader.biBitCount = 32; - bitmap_info->bmiHeader.biCompression = BI_RGB; - bitmap_info->bmiHeader.biClrUsed = 0; /* unused */ - bitmap_info->bmiHeader.biClrImportant = 0; - break; - - case CAIRO_FORMAT_A8: - bitmap_info->bmiHeader.biBitCount = 8; - bitmap_info->bmiHeader.biCompression = BI_RGB; - bitmap_info->bmiHeader.biClrUsed = 256; - bitmap_info->bmiHeader.biClrImportant = 0; - - for (i = 0; i < 256; i++) { - bitmap_info->bmiColors[i].rgbBlue = i; - bitmap_info->bmiColors[i].rgbGreen = i; - bitmap_info->bmiColors[i].rgbRed = i; - bitmap_info->bmiColors[i].rgbReserved = 0; - } - break; - - case CAIRO_FORMAT_A1: - bitmap_info->bmiHeader.biBitCount = 1; - bitmap_info->bmiHeader.biCompression = BI_RGB; - bitmap_info->bmiHeader.biClrUsed = 2; - bitmap_info->bmiHeader.biClrImportant = 0; - - for (i = 0; i < 2; i++) { - bitmap_info->bmiColors[i].rgbBlue = i * 255; - bitmap_info->bmiColors[i].rgbGreen = i * 255; - bitmap_info->bmiColors[i].rgbRed = i * 255; - bitmap_info->bmiColors[i].rgbReserved = 0; - } - break; - } - - surface->win32.dc = CreateCompatibleDC (original_dc); - if (!surface->win32.dc) - goto FAIL; - - surface->bitmap = CreateDIBSection (surface->win32.dc, - bitmap_info, - DIB_RGB_COLORS, - &bits, - NULL, 0); - if (!surface->bitmap) - goto FAIL; - - surface->is_dib = TRUE; - - GdiFlush(); - - surface->saved_dc_bitmap = SelectObject (surface->win32.dc, - surface->bitmap); - if (!surface->saved_dc_bitmap) - goto FAIL; - - if (bitmap_info && num_palette > 2) - free (bitmap_info); - - if (bits_out) - *bits_out = bits; - - if (rowstride_out) { - /* Windows bitmaps are padded to 32-bit (dword) boundaries */ - switch (format) { - case CAIRO_FORMAT_INVALID: - case CAIRO_FORMAT_RGB16_565: - case CAIRO_FORMAT_RGB30: - ASSERT_NOT_REACHED; - case CAIRO_FORMAT_ARGB32: - case CAIRO_FORMAT_RGB24: - *rowstride_out = 4 * width; - break; - - case CAIRO_FORMAT_A8: - *rowstride_out = (width + 3) & ~3; - break; - - case CAIRO_FORMAT_A1: - *rowstride_out = ((width + 31) & ~31) / 8; - break; - } - } - - surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc, format); - - return CAIRO_STATUS_SUCCESS; - - FAIL: - status = _cairo_win32_print_gdi_error (__FUNCTION__); - - if (bitmap_info && num_palette > 2) - free (bitmap_info); - - if (surface->saved_dc_bitmap) { - SelectObject (surface->win32.dc, surface->saved_dc_bitmap); - surface->saved_dc_bitmap = NULL; - } - - if (surface->bitmap) { - DeleteObject (surface->bitmap); - surface->bitmap = NULL; - } - - if (surface->win32.dc) { - DeleteDC (surface->win32.dc); - surface->win32.dc = NULL; - } - - return status; -} - -static cairo_surface_t * -_cairo_win32_display_surface_create_for_dc (HDC original_dc, - cairo_format_t format, - int width, - int height) -{ - cairo_status_t status; - cairo_device_t *device; - cairo_win32_display_surface_t *surface; - unsigned char *bits; - int rowstride; - - surface = _cairo_malloc (sizeof (*surface)); - if (surface == NULL) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - - surface->fallback = NULL; - - status = _create_dc_and_bitmap (surface, original_dc, format, - width, height, - &bits, &rowstride); - if (status) - goto FAIL; - - surface->image = cairo_image_surface_create_for_data (bits, format, - width, height, rowstride); - status = surface->image->status; - if (status) - goto FAIL; - - _cairo_image_surface_set_parent (to_image_surface(surface->image), - &surface->win32.base); - - surface->win32.format = format; - - surface->win32.extents.x = 0; - surface->win32.extents.y = 0; - surface->win32.extents.width = width; - surface->win32.extents.height = height; - surface->win32.x_ofs = 0; - surface->win32.y_ofs = 0; - - surface->initial_clip_rgn = NULL; - surface->had_simple_clip = FALSE; - - device = _cairo_win32_device_get (); - - _cairo_surface_init (&surface->win32.base, - &cairo_win32_display_surface_backend, - device, - _cairo_content_from_format (format), - FALSE); /* is_vector */ - - cairo_device_destroy (device); - - return &surface->win32.base; - - FAIL: - if (surface->bitmap) { - SelectObject (surface->win32.dc, surface->saved_dc_bitmap); - DeleteObject (surface->bitmap); - DeleteDC (surface->win32.dc); - } - free (surface); - - return _cairo_surface_create_in_error (status); -} - -static cairo_surface_t * -_cairo_win32_display_surface_create_similar (void *abstract_src, - cairo_content_t content, - int width, - int height) -{ - cairo_win32_display_surface_t *src = abstract_src; - cairo_format_t format = _cairo_format_from_content (content); - cairo_surface_t *new_surf = NULL; - - /* We force a DIB always if: - * - we need alpha; or - * - the parent is a DIB; or - * - the parent is for printing (because we don't care about the - * bit depth at that point) - * - * We also might end up with a DIB even if a DDB is requested if - * DDB creation failed due to out of memory. - */ - if (!(src->is_dib || content & CAIRO_CONTENT_ALPHA)) { - /* try to create a ddb */ - new_surf = cairo_win32_surface_create_with_ddb (src->win32.dc, CAIRO_FORMAT_RGB24, width, height); - - if (new_surf->status) - new_surf = NULL; - } - - if (new_surf == NULL) { - new_surf = _cairo_win32_display_surface_create_for_dc (src->win32.dc, format, width, height); - } - - return new_surf; -} - -static cairo_surface_t * -_cairo_win32_display_surface_create_similar_image (void *abstract_other, - cairo_format_t format, - int width, - int height) -{ - cairo_win32_display_surface_t *surface = abstract_other; - cairo_image_surface_t *image; - - surface = (cairo_win32_display_surface_t *) - _cairo_win32_display_surface_create_for_dc (surface->win32.dc, - format, width, height); - if (surface->win32.base.status) - return &surface->win32.base; - - /* And clear in order to comply with our user API semantics */ - image = (cairo_image_surface_t *) surface->image; - if (! image->base.is_clear) { - memset (image->data, 0, image->stride * height); - image->base.is_clear = TRUE; - } - - return &image->base; -} - -static cairo_status_t -_cairo_win32_display_surface_finish (void *abstract_surface) -{ - cairo_win32_display_surface_t *surface = abstract_surface; - - if (surface->image && to_image_surface(surface->image)->parent) { - assert (to_image_surface(surface->image)->parent == &surface->win32.base); - /* Unhook ourselves first to avoid the double-unref from the image */ - to_image_surface(surface->image)->parent = NULL; - cairo_surface_finish (surface->image); - cairo_surface_destroy (surface->image); - } - - /* If we created the Bitmap and DC, destroy them */ - if (surface->bitmap) { - SelectObject (surface->win32.dc, surface->saved_dc_bitmap); - DeleteObject (surface->bitmap); - DeleteDC (surface->win32.dc); - } - - _cairo_win32_display_surface_discard_fallback (surface); - - if (surface->initial_clip_rgn) - DeleteObject (surface->initial_clip_rgn); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_image_surface_t * -_cairo_win32_display_surface_map_to_image (void *abstract_surface, - const cairo_rectangle_int_t *extents) -{ - cairo_win32_display_surface_t *surface = abstract_surface; - cairo_status_t status; - - TRACE ((stderr, "%s (surface=%d)\n", - __FUNCTION__, surface->win32.base.unique_id)); - - if (surface->image) - goto done; - - if (surface->fallback == NULL) { - surface->fallback = - _cairo_win32_display_surface_create_for_dc (surface->win32.dc, - surface->win32.format, - surface->win32.extents.x + surface->win32.extents.width, - surface->win32.extents.y + surface->win32.extents.height); - if (unlikely (status = surface->fallback->status)) - goto err; - - if (!BitBlt (to_win32_surface(surface->fallback)->dc, - surface->win32.extents.x, surface->win32.extents.y, - surface->win32.extents.width, - surface->win32.extents.height, - surface->win32.dc, - surface->win32.extents.x + surface->win32.x_ofs, /* Handling multi-monitor... */ - surface->win32.extents.y + surface->win32.y_ofs, /* ... setup on Win32 */ - SRCCOPY)) { - status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR); - goto err; - } - } - - surface = to_win32_display_surface (surface->fallback); -done: - GdiFlush(); - return _cairo_surface_map_to_image (surface->image, extents); - -err: - cairo_surface_destroy (surface->fallback); - surface->fallback = NULL; - - return _cairo_image_surface_create_in_error (status); -} - -static cairo_int_status_t -_cairo_win32_display_surface_unmap_image (void *abstract_surface, - cairo_image_surface_t *image) -{ - cairo_win32_display_surface_t *surface = abstract_surface; - - /* Delay the download until the next flush, which means we also need - * to make sure our sources rare flushed. - */ - TRACE ((stderr, "%s (surface=%d)\n", - __FUNCTION__, to_win32_surface(surface)->base.unique_id)); - - if (surface->fallback) { - cairo_rectangle_int_t r; - - r.x = image->base.device_transform_inverse.x0; - r.y = image->base.device_transform_inverse.y0; - r.width = image->width; - r.height = image->height; - - TRACE ((stderr, "%s: adding damage (%d,%d)x(%d,%d)\n", - __FUNCTION__, r.x, r.y, r.width, r.height)); - surface->fallback->damage = - _cairo_damage_add_rectangle (surface->fallback->damage, &r); - surface = to_win32_display_surface (surface->fallback); - } - - return _cairo_surface_unmap_image (surface->image, image); -} - -static cairo_status_t -_cairo_win32_display_surface_flush (void *abstract_surface, unsigned flags) -{ - cairo_win32_display_surface_t *surface = abstract_surface; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - - if (flags) - return CAIRO_STATUS_SUCCESS; - - TRACE ((stderr, "%s (surface=%d)\n", - __FUNCTION__, surface->win32.base.unique_id)); - if (surface->fallback == NULL) - return CAIRO_STATUS_SUCCESS; - - if (surface->fallback->damage) { - cairo_win32_display_surface_t *fallback; - cairo_damage_t *damage; - - damage = _cairo_damage_reduce (surface->fallback->damage); - surface->fallback->damage = NULL; - - fallback = to_win32_display_surface (surface->fallback); - assert (fallback->image); - - TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__, - damage->region ? cairo_region_num_rectangles (damage->region) : 0)); - - if (damage->status) { - if (!BitBlt (surface->win32.dc, - surface->win32.extents.x + surface->win32.x_ofs, /* Handling multi-monitor... */ - surface->win32.extents.y + surface->win32.y_ofs, /* ... setup on Win32 */ - surface->win32.extents.width, - surface->win32.extents.height, - fallback->win32.dc, - surface->win32.extents.x, surface->win32.extents.y, - SRCCOPY)) - status = _cairo_win32_print_gdi_error (__FUNCTION__); - } else if (damage->region) { - int n = cairo_region_num_rectangles (damage->region), i; - for (i = 0; i < n; i++) { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (damage->region, i, &rect); - TRACE ((stderr, "%s: damage (%d,%d)x(%d,%d)\n", __FUNCTION__, - rect.x, rect.y, - rect.width, rect.height)); - if (!BitBlt (surface->win32.dc, - rect.x + surface->win32.x_ofs, /* Handling multi-monitor... */ - rect.y + surface->win32.y_ofs, /* ... setup on Win32 */ - rect.width, rect.height, - fallback->win32.dc, - rect.x, rect.y, - SRCCOPY)) { - status = _cairo_win32_print_gdi_error (__FUNCTION__); - break; - } - } - } - _cairo_damage_destroy (damage); - } else { - cairo_surface_destroy (surface->fallback); - surface->fallback = NULL; - } - - return status; -} - -static cairo_status_t -_cairo_win32_display_surface_mark_dirty (void *abstract_surface, - int x, int y, int width, int height) -{ - _cairo_win32_display_surface_discard_fallback (abstract_surface); - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_cairo_win32_save_initial_clip (HDC hdc, cairo_win32_display_surface_t *surface) -{ - RECT rect; - int clipBoxType; - int gm; - XFORM saved_xform; - - /* GetClipBox/GetClipRgn and friends interact badly with a world transform - * set. GetClipBox returns values in logical (transformed) coordinates; - * it's unclear what GetClipRgn returns, because the region is empty in the - * case of a SIMPLEREGION clip, but I assume device (untransformed) coordinates. - * Similarly, IntersectClipRect works in logical units, whereas SelectClipRgn - * works in device units. - * - * So, avoid the whole mess and get rid of the world transform - * while we store our initial data and when we restore initial coordinates. - * - * XXX we may need to modify x/y by the ViewportOrg or WindowOrg - * here in GM_COMPATIBLE; unclear. - */ - gm = GetGraphicsMode (hdc); - if (gm == GM_ADVANCED) { - GetWorldTransform (hdc, &saved_xform); - ModifyWorldTransform (hdc, NULL, MWT_IDENTITY); - } - - clipBoxType = GetClipBox (hdc, &rect); - if (clipBoxType == ERROR) { - _cairo_win32_print_gdi_error (__FUNCTION__); - SetGraphicsMode (hdc, gm); - /* XXX: Can we make a more reasonable guess at the error cause here? */ - return _cairo_error (CAIRO_STATUS_DEVICE_ERROR); - } - - surface->win32.extents.x = rect.left; - surface->win32.extents.y = rect.top; - surface->win32.extents.width = rect.right - rect.left; - surface->win32.extents.height = rect.bottom - rect.top; - - /* On multi-monitor setup, under Windows, the primary monitor always - * have origin (0,0). Any monitors that extends to the left or above - * will have coordinates in the negative range. Take this into - * account, by forcing our Win32 surface to start at extent (0,0) and - * using a device offset. Cairo does not handle extents with negative - * offsets. - */ - surface->win32.x_ofs = 0; - surface->win32.y_ofs = 0; - if ((surface->win32.extents.x < 0) || - (surface->win32.extents.y < 0)) { - /* Negative offsets occurs for (and ONLY for) the desktop DC (virtual - * desktop), when a monitor extend to the left or above the primary - * monitor. - * - * More info @ https://www.microsoft.com/msj/0697/monitor/monitor.aspx - * - * Note that any other DC, including memory DC created with - * CreateCompatibleDC(<virtual desktop DC>) will have extents in the - * positive range. This will be taken into account later when we perform - * raster operations between the DC (may have to perform offset - * translation). - */ - surface->win32.x_ofs = surface->win32.extents.x; - surface->win32.y_ofs = surface->win32.extents.y; - surface->win32.extents.x = 0; - surface->win32.extents.y = 0; - } - - surface->initial_clip_rgn = NULL; - surface->had_simple_clip = FALSE; - - if (clipBoxType == COMPLEXREGION) { - surface->initial_clip_rgn = CreateRectRgn (0, 0, 0, 0); - if (GetClipRgn (hdc, surface->initial_clip_rgn) <= 0) { - DeleteObject(surface->initial_clip_rgn); - surface->initial_clip_rgn = NULL; - } - } else if (clipBoxType == SIMPLEREGION) { - surface->had_simple_clip = TRUE; - } - - if (gm == GM_ADVANCED) - SetWorldTransform (hdc, &saved_xform); - - return CAIRO_STATUS_SUCCESS; -} - -cairo_status_t -_cairo_win32_display_surface_set_clip (cairo_win32_display_surface_t *surface, - cairo_clip_t *clip) -{ - char stack[512]; - cairo_rectangle_int_t extents; - int num_rects; - RGNDATA *data; - size_t data_size; - RECT *rects; - int i; - HRGN gdi_region; - cairo_status_t status; - cairo_region_t *region; - - /* The semantics we want is that any clip set by cairo combines - * is intersected with the clip on device context that the - * surface was created for. To implement this, we need to - * save the original clip when first setting a clip on surface. - */ - - assert (_cairo_clip_is_region (clip)); - region = _cairo_clip_get_region (clip); - if (region == NULL) - return CAIRO_STATUS_SUCCESS; - - cairo_region_get_extents (region, &extents); - num_rects = cairo_region_num_rectangles (region); - - /* XXX see notes in _cairo_win32_save_initial_clip -- - * this code will interact badly with a HDC which had an initial - * world transform -- we should probably manually transform the - * region rects, because SelectClipRgn takes device units, not - * logical units (unlike IntersectClipRect). - */ - - data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT); - if (data_size > sizeof (stack)) { - data = _cairo_malloc (data_size); - if (!data) - return _cairo_error(CAIRO_STATUS_NO_MEMORY); - } else - data = (RGNDATA *)stack; - - data->rdh.dwSize = sizeof (RGNDATAHEADER); - data->rdh.iType = RDH_RECTANGLES; - data->rdh.nCount = num_rects; - data->rdh.nRgnSize = num_rects * sizeof (RECT); - data->rdh.rcBound.left = extents.x; - data->rdh.rcBound.top = extents.y; - data->rdh.rcBound.right = extents.x + extents.width; - data->rdh.rcBound.bottom = extents.y + extents.height; - - rects = (RECT *)data->Buffer; - for (i = 0; i < num_rects; i++) { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (region, i, &rect); - - rects[i].left = rect.x; - rects[i].top = rect.y; - rects[i].right = rect.x + rect.width; - rects[i].bottom = rect.y + rect.height; - } - - gdi_region = ExtCreateRegion (NULL, data_size, data); - if ((char *)data != stack) - free (data); - - if (!gdi_region) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - /* AND the new region into our DC */ - status = CAIRO_STATUS_SUCCESS; - if (ExtSelectClipRgn (surface->win32.dc, gdi_region, RGN_AND) == ERROR) - status = _cairo_win32_print_gdi_error (__FUNCTION__); - - DeleteObject (gdi_region); - - return status; -} - -void -_cairo_win32_display_surface_unset_clip (cairo_win32_display_surface_t *surface) -{ - XFORM saved_xform; - int gm = GetGraphicsMode (surface->win32.dc); - if (gm == GM_ADVANCED) { - GetWorldTransform (surface->win32.dc, &saved_xform); - ModifyWorldTransform (surface->win32.dc, NULL, MWT_IDENTITY); - } - - /* initial_clip_rgn will either be a real region or NULL (which means reset to no clip region) */ - SelectClipRgn (surface->win32.dc, surface->initial_clip_rgn); - - if (surface->had_simple_clip) { - /* then if we had a simple clip, intersect */ - IntersectClipRect (surface->win32.dc, - surface->win32.extents.x, - surface->win32.extents.y, - surface->win32.extents.x + surface->win32.extents.width, - surface->win32.extents.y + surface->win32.extents.height); - } - - if (gm == GM_ADVANCED) - SetWorldTransform (surface->win32.dc, &saved_xform); -} - -void -_cairo_win32_display_surface_discard_fallback (cairo_win32_display_surface_t *surface) -{ - if (surface->fallback) { - TRACE ((stderr, "%s (surface=%d)\n", - __FUNCTION__, surface->win32.base.unique_id)); - - cairo_surface_finish (surface->fallback); - cairo_surface_destroy (surface->fallback); - surface->fallback = NULL; - } -} - -static cairo_int_status_t -_cairo_win32_display_surface_paint (void *surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_clip_t *clip) -{ - cairo_win32_device_t *device = to_win32_device_from_surface (surface); - - TRACE ((stderr, "%s (surface=%d)\n", - __FUNCTION__, to_win32_surface(surface)->base.unique_id)); - - if (clip == NULL && - (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_CLEAR)) - _cairo_win32_display_surface_discard_fallback (surface); - - return _cairo_compositor_paint (device->compositor, - surface, op, source, clip); -} - -static cairo_int_status_t -_cairo_win32_display_surface_mask (void *surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_pattern_t *mask, - const cairo_clip_t *clip) -{ - cairo_win32_device_t *device = to_win32_device_from_surface (surface); - - TRACE ((stderr, "%s (surface=%d)\n", - __FUNCTION__, to_win32_surface(surface)->base.unique_id)); - - if (clip == NULL && op == CAIRO_OPERATOR_SOURCE) - _cairo_win32_display_surface_discard_fallback (surface); - - return _cairo_compositor_mask (device->compositor, - surface, op, source, mask, clip); -} - -static cairo_int_status_t -_cairo_win32_display_surface_stroke (void *surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - const cairo_stroke_style_t *style, - const cairo_matrix_t *ctm, - const cairo_matrix_t *ctm_inverse, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_win32_device_t *device = to_win32_device_from_surface (surface); - - TRACE ((stderr, "%s (surface=%d)\n", - __FUNCTION__, to_win32_surface(surface)->base.unique_id)); - - return _cairo_compositor_stroke (device->compositor, surface, - op, source, path, - style, ctm, ctm_inverse, - tolerance, antialias, clip); -} - -static cairo_int_status_t -_cairo_win32_display_surface_fill (void *surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_win32_device_t *device = to_win32_device_from_surface (surface); - - TRACE ((stderr, "%s (surface=%d)\n", - __FUNCTION__, to_win32_surface(surface)->base.unique_id)); - - return _cairo_compositor_fill (device->compositor, surface, - op, source, path, - fill_rule, tolerance, antialias, - clip); -} - -static cairo_int_status_t -_cairo_win32_display_surface_glyphs (void *surface, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - const cairo_clip_t *clip) -{ - cairo_win32_device_t *device = to_win32_device_from_surface (surface); - - TRACE ((stderr, "%s (surface=%d)\n", - __FUNCTION__, to_win32_surface(surface)->base.unique_id)); - - return _cairo_compositor_glyphs (device->compositor, surface, - op, source, - glyphs, num_glyphs, scaled_font, - clip); -} - -static const cairo_surface_backend_t cairo_win32_display_surface_backend = { - CAIRO_SURFACE_TYPE_WIN32, - _cairo_win32_display_surface_finish, - - _cairo_default_context_create, - - _cairo_win32_display_surface_create_similar, - _cairo_win32_display_surface_create_similar_image, - _cairo_win32_display_surface_map_to_image, - _cairo_win32_display_surface_unmap_image, - - _cairo_surface_default_source, - _cairo_surface_default_acquire_source_image, - _cairo_surface_default_release_source_image, - NULL, /* snapshot */ - - NULL, /* copy_page */ - NULL, /* show_page */ - - _cairo_win32_surface_get_extents, - NULL, /* get_font_options */ - - _cairo_win32_display_surface_flush, - _cairo_win32_display_surface_mark_dirty, - - _cairo_win32_display_surface_paint, - _cairo_win32_display_surface_mask, - _cairo_win32_display_surface_stroke, - _cairo_win32_display_surface_fill, - NULL, /* fill/stroke */ - _cairo_win32_display_surface_glyphs, -}; - -/* Notes: - * - * Win32 alpha-understanding functions - * - * BitBlt - will copy full 32 bits from a 32bpp DIB to result - * (so it's safe to use for ARGB32->ARGB32 SOURCE blits) - * (but not safe going RGB24->ARGB32, if RGB24 is also represented - * as a 32bpp DIB, since the alpha isn't discarded!) - * - * AlphaBlend - if both the source and dest have alpha, even if AC_SRC_ALPHA isn't set, - * it will still copy over the src alpha, because the SCA value (255) will be - * multiplied by all the src components. - */ - -/** - * cairo_win32_surface_create_with_format: - * @hdc: the DC to create a surface for - * @format: format of pixels in the surface to create - * - * Creates a cairo surface that targets the given DC. The DC will be - * queried for its initial clip extents, and this will be used as the - * size of the cairo surface. - * - * Supported formats are: - * %CAIRO_FORMAT_ARGB32 - * %CAIRO_FORMAT_RGB24 - * - * Note: @format only tells cairo how to draw on the surface, not what - * the format of the surface is. Namely, cairo does not (and cannot) - * check that @hdc actually supports alpha-transparency. - * - * Return value: the newly created surface, NULL on failure - * - * Since: 1.14 - **/ -cairo_surface_t * -cairo_win32_surface_create_with_format (HDC hdc, cairo_format_t format) -{ - cairo_win32_display_surface_t *surface; - - cairo_status_t status; - cairo_device_t *device; - - switch (format) { - default: - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); - case CAIRO_FORMAT_ARGB32: - case CAIRO_FORMAT_RGB24: - break; - } - - surface = _cairo_malloc (sizeof (*surface)); - if (surface == NULL) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - - status = _cairo_win32_save_initial_clip (hdc, surface); - if (status) { - free (surface); - return _cairo_surface_create_in_error (status); - } - - surface->image = NULL; - surface->fallback = NULL; - surface->win32.format = format; - - surface->win32.dc = hdc; - surface->bitmap = NULL; - surface->is_dib = FALSE; - surface->saved_dc_bitmap = NULL; - - surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc, format); - - device = _cairo_win32_device_get (); - - _cairo_surface_init (&surface->win32.base, - &cairo_win32_display_surface_backend, - device, - _cairo_content_from_format (format), - FALSE); /* is_vector */ - - cairo_device_destroy (device); - - return &surface->win32.base; -} - -/** - * cairo_win32_surface_create: - * @hdc: the DC to create a surface for - * - * Creates a cairo surface that targets the given DC. The DC will be - * queried for its initial clip extents, and this will be used as the - * size of the cairo surface. The resulting surface will always be of - * format %CAIRO_FORMAT_RGB24; should you need another surface format, - * you will need to create one through - * cairo_win32_surface_create_with_format() or - * cairo_win32_surface_create_with_dib(). - * - * Return value: the newly created surface, NULL on failure - * - * Since: 1.0 - **/ -cairo_surface_t * -cairo_win32_surface_create (HDC hdc) -{ - return cairo_win32_surface_create_with_format (hdc, CAIRO_FORMAT_RGB24); -} - -/** - * cairo_win32_surface_create_with_dib: - * @format: format of pixels in the surface to create - * @width: width of the surface, in pixels - * @height: height of the surface, in pixels - * - * Creates a device-independent-bitmap surface not associated with - * any particular existing surface or device context. The created - * bitmap will be uninitialized. - * - * Return value: the newly created surface - * - * Since: 1.2 - **/ -cairo_surface_t * -cairo_win32_surface_create_with_dib (cairo_format_t format, - int width, - int height) -{ - if (! CAIRO_FORMAT_VALID (format)) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); - - return _cairo_win32_display_surface_create_for_dc (NULL, format, width, height); -} - -/** - * cairo_win32_surface_create_with_ddb: - * @hdc: a DC compatible with the surface to create - * @format: format of pixels in the surface to create - * @width: width of the surface, in pixels - * @height: height of the surface, in pixels - * - * Creates a device-dependent-bitmap surface not associated with - * any particular existing surface or device context. The created - * bitmap will be uninitialized. - * - * Return value: the newly created surface - * - * Since: 1.4 - **/ -cairo_surface_t * -cairo_win32_surface_create_with_ddb (HDC hdc, - cairo_format_t format, - int width, - int height) -{ - cairo_win32_display_surface_t *new_surf; - HBITMAP ddb; - HDC screen_dc, ddb_dc; - HBITMAP saved_dc_bitmap; - - switch (format) { - default: -/* XXX handle these eventually */ - case CAIRO_FORMAT_A8: - case CAIRO_FORMAT_A1: - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); - case CAIRO_FORMAT_ARGB32: - case CAIRO_FORMAT_RGB24: - break; - } - - if (!hdc) { - screen_dc = GetDC (NULL); - hdc = screen_dc; - } else { - screen_dc = NULL; - } - - ddb_dc = CreateCompatibleDC (hdc); - if (ddb_dc == NULL) { - new_surf = (cairo_win32_display_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - goto FINISH; - } - - ddb = CreateCompatibleBitmap (hdc, width, height); - if (ddb == NULL) { - DeleteDC (ddb_dc); - - /* Note that if an app actually does hit this out of memory - * condition, it's going to have lots of other issues, as - * video memory is probably exhausted. However, it can often - * continue using DIBs instead of DDBs. - */ - new_surf = (cairo_win32_display_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - goto FINISH; - } - - saved_dc_bitmap = SelectObject (ddb_dc, ddb); - - new_surf = (cairo_win32_display_surface_t*) cairo_win32_surface_create (ddb_dc); - new_surf->bitmap = ddb; - new_surf->saved_dc_bitmap = saved_dc_bitmap; - new_surf->is_dib = FALSE; - -FINISH: - if (screen_dc) - ReleaseDC (NULL, screen_dc); - - return &new_surf->win32.base; -} |