Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  cairo-win32-display-surface.c   Sprache: C

 
/* -*- 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>
 */


#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:
    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;

    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:
    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;

    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:
 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;

 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) {
 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;
    }

    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) {
/* 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;
    }

    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;
}

Messung V0.5
C=97 H=92 G=94

¤ Dauer der Verarbeitung: 0.38 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge