/** * 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 cairo_status_t
_create_dc_and_bitmap (cairo_win32_display_surface_t *surface,
HDC original_dc,
cairo_format_t format, int width, int height, unsignedchar **bits_out, int *rowstride_out)
{
cairo_status_t status;
switch (format) { default: case CAIRO_FORMAT_INVALID: case CAIRO_FORMAT_RGB16_565: case CAIRO_FORMAT_RGB30: case CAIRO_FORMAT_RGB96F: case CAIRO_FORMAT_RGBA128F: return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); case CAIRO_FORMAT_ARGB32: case CAIRO_FORMAT_RGB24:
num_palette = 0; break;
switch (format) { case CAIRO_FORMAT_INVALID: case CAIRO_FORMAT_RGB16_565: case CAIRO_FORMAT_RGB30: case CAIRO_FORMAT_RGB96F: case CAIRO_FORMAT_RGBA128F:
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;
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->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: case CAIRO_FORMAT_RGB96F: case CAIRO_FORMAT_RGBA128F:
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;
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;
}
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);
}
/* 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));
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);
}
/* 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;
}
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;
/* 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;
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__);
/* 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);
}
/* 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) { case CAIRO_FORMAT_INVALID: case CAIRO_FORMAT_A8: case CAIRO_FORMAT_A1: case CAIRO_FORMAT_RGB16_565: case CAIRO_FORMAT_RGB30: case CAIRO_FORMAT_RGB96F: case CAIRO_FORMAT_RGBA128F: default: return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); case CAIRO_FORMAT_ARGB32: case CAIRO_FORMAT_RGB24: break;
}
/** * 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) { /* XXX handle these eventually */ case CAIRO_FORMAT_INVALID: case CAIRO_FORMAT_A8: case CAIRO_FORMAT_A1: case CAIRO_FORMAT_RGB16_565: case CAIRO_FORMAT_RGB30: case CAIRO_FORMAT_RGB96F: case CAIRO_FORMAT_RGBA128F: default: return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); case CAIRO_FORMAT_ARGB32: case CAIRO_FORMAT_RGB24: break;
}
/* 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;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.