[cairo-commit] 2 commits - src/cairo-win32-font.c src/cairo-win32.h src/cairo-win32-private.h src/cairo-win32-surface.c

Vladimir Vukicevic vladimir at kemper.freedesktop.org
Wed Sep 13 13:09:19 PDT 2006


 src/cairo-win32-font.c    |   16 +
 src/cairo-win32-private.h |   22 +
 src/cairo-win32-surface.c |  556 +++++++++++++++++++++++++++++++++++++---------
 src/cairo-win32.h         |   17 +
 4 files changed, 512 insertions(+), 99 deletions(-)

New commits:
diff-tree f1bd0b9f9815ac838f30216d810bdd4eb2b67997 (from 016653812640cddcc51d0500d62c5c65b33bdd04)
Author: Stuart Parmenter <pavlov at pavlov.net>
Date:   Tue Sep 12 16:27:40 2006 -0700

    [win32] correct win32 show_glyphs for non-y-aligned text
    
    Correctly calculate destination glyph coordinates for win32_show_glyphs.

diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
old mode 100755
new mode 100644
index d92987c..ee8cd3e
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -1673,3 +1673,19 @@ cairo_win32_scaled_font_get_metrics_fact
 {
     return 1. / ((cairo_win32_scaled_font_t *)scaled_font)->logical_scale;
 }
+
+void
+cairo_win32_scaled_font_get_logical_to_device (cairo_scaled_font_t *scaled_font,
+					       cairo_matrix_t *logical_to_device)
+{
+    cairo_win32_scaled_font_t *win_font = (cairo_win32_scaled_font_t *)scaled_font;
+    *logical_to_device = win_font->logical_to_device;
+}
+
+void
+cairo_win32_scaled_font_get_device_to_logical (cairo_scaled_font_t *scaled_font,
+					       cairo_matrix_t *device_to_logical)
+{
+    cairo_win32_scaled_font_t *win_font = (cairo_win32_scaled_font_t *)scaled_font;
+    *device_to_logical = win_font->device_to_logical;
+}
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 3b3cf25..54c8698 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -1250,6 +1250,8 @@ _cairo_win32_surface_show_glyphs (void		
     COLORREF color;
     int output_count = 0;
 
+    cairo_matrix_t device_to_logical;
+
     /* We can only handle win32 fonts */
     if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_WIN32)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1276,6 +1278,8 @@ _cairo_win32_surface_show_glyphs (void		
 		((int)solid_pattern->color.green_short) >> 8,
 		((int)solid_pattern->color.blue_short) >> 8);
 
+    cairo_win32_scaled_font_get_device_to_logical(scaled_font, &device_to_logical);
+
     SaveDC(dst->dc);
 
     cairo_win32_scaled_font_select_font(scaled_font, dst->dc);
@@ -1295,13 +1299,23 @@ _cairo_win32_surface_show_glyphs (void		
 	if (i == num_glyphs - 1)
 	    dx_buf[i] = 0;
 	else
-	    dx_buf[i] = (glyphs[i+1].x - glyphs[i].x) * WIN32_FONT_LOGICAL_SCALE;
+	    dx_buf[i] = floor(((glyphs[i+1].x - glyphs[i].x) * WIN32_FONT_LOGICAL_SCALE) + 0.5);
 
 	if (i == num_glyphs - 1 || glyphs[i].y != glyphs[i+1].y) {
 	    const int offset = (i - output_count) + 1;
+	    double user_x = glyphs[offset].x;
+	    double user_y = last_y;
+	    double logical_x, logical_y;
+
+	    cairo_matrix_transform_point(&device_to_logical,
+					 &user_x, &user_y);
+
+	    logical_x = floor(user_x + 0.5);
+	    logical_y = floor(user_y + 0.5);
+
 	    win_result = ExtTextOutW(dst->dc,
-				     glyphs[offset].x * WIN32_FONT_LOGICAL_SCALE,
-				     last_y * WIN32_FONT_LOGICAL_SCALE,
+				     logical_x,
+				     logical_y,
 				     ETO_GLYPH_INDEX,
 				     NULL,
 				     glyph_buf + offset,
@@ -1313,9 +1327,12 @@ _cairo_win32_surface_show_glyphs (void		
 	    }
 
 	    output_count = 0;
-	}
 
-	last_y = glyphs[i].y;
+	    if (i < num_glyphs - 1)
+		last_y = glyphs[i+1].y;
+	} else {
+	    last_y = glyphs[i].y;
+	}
     }
 
 FAIL:
diff --git a/src/cairo-win32.h b/src/cairo-win32.h
index 9710e9a..8719d33 100644
--- a/src/cairo-win32.h
+++ b/src/cairo-win32.h
@@ -80,6 +80,14 @@ cairo_win32_scaled_font_done_font (cairo
 cairo_public double
 cairo_win32_scaled_font_get_metrics_factor (cairo_scaled_font_t *scaled_font);
 
+cairo_public void
+cairo_win32_scaled_font_get_logical_to_device (cairo_scaled_font_t *scaled_font,
+					       cairo_matrix_t *logical_to_device);
+
+cairo_public void
+cairo_win32_scaled_font_get_device_to_logical (cairo_scaled_font_t *scaled_font,
+					       cairo_matrix_t *device_to_logical);
+
 CAIRO_END_DECLS
 
 #else  /* CAIRO_HAS_WIN32_SURFACE */
diff-tree 016653812640cddcc51d0500d62c5c65b33bdd04 (from 924bbd06f35f55886f808a7a9d3ee08e479389ad)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Tue Sep 12 16:08:40 2006 -0700

    [win32] Support for DDBs, AlphaBlend fix
    
    Add support for the win32 surface using DDBs for similar surfaces and the
    like when the orignal surface is created from a DC, or when a DDB is
    explicitly created.  A DIB is still created if alpha is required.
    
    Also fixes a case where blitting win32 RGB24 -> ARGB32 surfaces was causing
    alpha to leak into the ARGB32 surface instead of being set to fully opaque.

diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h
old mode 100755
new mode 100644
index c16c7e9..41e6e98
--- a/src/cairo-win32-private.h
+++ b/src/cairo-win32-private.h
@@ -55,8 +55,10 @@ typedef struct _cairo_win32_surface {
 
     HDC dc;
 
-    /* We create off-screen surfaces as DIBs */
+    /* We create off-screen surfaces as DIBs or DDBs, based on what we created
+     * originally*/
     HBITMAP bitmap;
+    cairo_bool_t is_dib;
 
     /* Used to save the initial 1x1 monochrome bitmap for the DC to
      * select back into the DC before deleting the DC and our
@@ -74,8 +76,26 @@ typedef struct _cairo_win32_surface {
     HRGN saved_clip;
 
     cairo_rectangle_int16_t extents;
+
+    /* Surface DC flags */
+    uint32_t flags;
 } cairo_win32_surface_t;
 
+/* Surface DC flag values */
+enum {
+    /* Whether the DC is a display DC or not */
+    CAIRO_WIN32_SURFACE_IS_DISPLAY = (1<<1),
+
+    /* Whether we can use BitBlt with this surface */
+    CAIRO_WIN32_SURFACE_CAN_BITBLT = (1<<2),
+
+    /* Whether we can use AlphaBlend with this surface */
+    CAIRO_WIN32_SURFACE_CAN_ALPHABLEND = (1<<3),
+
+    /* Whether we can use StretchBlt with this surface */
+    CAIRO_WIN32_SURFACE_CAN_STRETCHBLT = (1<<4)
+};
+
 cairo_status_t
 _cairo_win32_print_gdi_error (const char *context);
 
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
old mode 100755
new mode 100644
index 27bdcfa..3b3cf25
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -1,3 +1,4 @@
+/* -*- 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.
@@ -48,6 +49,9 @@
 #define SB_NONE         0x00000000
 #endif
 
+#define PELS_72DPI  (72. / 0.0254)
+#define NIL_SURFACE ((cairo_surface_t*)&_cairo_surface_nil)
+
 static const cairo_surface_backend_t cairo_win32_surface_backend;
 
 /**
@@ -87,6 +91,40 @@ _cairo_win32_print_gdi_error (const char
     return CAIRO_STATUS_NO_MEMORY;
 }
 
+static uint32_t
+_cairo_win32_flags_for_dc (HDC dc)
+{
+    uint32_t flags = 0;
+
+    if (GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
+	flags |= CAIRO_WIN32_SURFACE_IS_DISPLAY;
+
+	/* These will always be possible, but the actual GetDeviceCaps
+	 * calls will return whether they're accelerated or not.
+	 * We may want to use our own (pixman) routines sometimes
+	 * if they're eventually faster, but for now have GDI do
+	 * everything.
+	 */
+	flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT;
+	flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND;
+	flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT;
+    } else {
+	int cap;
+
+	cap = GetDeviceCaps(dc, SHADEBLENDCAPS);
+	if (cap != SB_NONE)
+	    flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND;
+
+	cap = GetDeviceCaps(dc, RASTERCAPS);
+	if (cap & RC_BITBLT)
+	    flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT;
+	if (cap & RC_STRETCHBLT)
+	    flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT;
+    }
+
+    return flags;
+}
+
 static cairo_status_t
 _create_dc_and_bitmap (cairo_win32_surface_t *surface,
 		       HDC                    original_dc,
@@ -110,6 +148,7 @@ _create_dc_and_bitmap (cairo_win32_surfa
 
     surface->dc = NULL;
     surface->bitmap = NULL;
+    surface->is_dib = FALSE;
 
     switch (format) {
     case CAIRO_FORMAT_ARGB32:
@@ -138,8 +177,8 @@ _create_dc_and_bitmap (cairo_win32_surfa
     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 = 72. / 0.0254; /* unused here */
-    bitmap_info->bmiHeader.biYPelsPerMeter = 72. / 0.0254; /* unused here */
+    bitmap_info->bmiHeader.biXPelsPerMeter = PELS_72DPI; /* unused here */
+    bitmap_info->bmiHeader.biYPelsPerMeter = PELS_72DPI; /* unused here */
     bitmap_info->bmiHeader.biPlanes = 1;
 
     switch (format) {
@@ -147,6 +186,8 @@ _create_dc_and_bitmap (cairo_win32_surfa
      * 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:
@@ -198,6 +239,8 @@ _create_dc_and_bitmap (cairo_win32_surfa
     if (!surface->bitmap)
 	goto FAIL;
 
+    surface->is_dib = TRUE;
+
     GdiFlush();
 
     surface->saved_dc_bitmap = SelectObject (surface->dc,
@@ -229,6 +272,8 @@ _create_dc_and_bitmap (cairo_win32_surfa
 	}
     }
 
+    surface->flags = _cairo_win32_flags_for_dc (surface->dc);
+
     return CAIRO_STATUS_SUCCESS;
 
  FAIL:
@@ -271,7 +316,7 @@ _cairo_win32_surface_create_for_dc (HDC 
     surface = malloc (sizeof (cairo_win32_surface_t));
     if (surface == NULL) {
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
-	return &_cairo_surface_nil;
+	return NIL_SURFACE;
     }
 
     status = _create_dc_and_bitmap (surface, original_dc, format,
@@ -296,8 +341,8 @@ _cairo_win32_surface_create_for_dc (HDC 
 
     surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
     if (GetClipRgn (surface->dc, surface->saved_clip) == 0) {
-        DeleteObject(surface->saved_clip);
-        surface->saved_clip = NULL;
+	DeleteObject(surface->saved_clip);
+	surface->saved_clip = NULL;
     }
 
     surface->extents = surface->clip_rect;
@@ -310,31 +355,65 @@ _cairo_win32_surface_create_for_dc (HDC 
  FAIL:
     if (surface->bitmap) {
 	SelectObject (surface->dc, surface->saved_dc_bitmap);
-  	DeleteObject (surface->bitmap);
-        DeleteDC (surface->dc);
+	DeleteObject (surface->bitmap);
+	DeleteDC (surface->dc);
     }
     if (surface)
 	free (surface);
 
     if (status == CAIRO_STATUS_NO_MEMORY) {
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
-	return &_cairo_surface_nil;
+	return NIL_SURFACE;
     } else {
 	_cairo_error (status);
-	return &_cairo_surface_nil;
+	return NIL_SURFACE;
     }
 }
 
 static cairo_surface_t *
+_cairo_win32_surface_create_similar_internal (void	    *abstract_src,
+					      cairo_content_t content,
+					      int	     width,
+					      int	     height,
+					      cairo_bool_t   force_dib)
+{
+    cairo_win32_surface_t *src = abstract_src;
+    cairo_format_t format = _cairo_format_from_content (content);
+    cairo_win32_surface_t *new_surf;
+
+    /* if the parent is a DIB or if we need alpha, then
+     * we have to create a dib */
+    if (force_dib || src->is_dib || (content & CAIRO_CONTENT_ALPHA)) {
+	new_surf = (cairo_win32_surface_t*)
+	    _cairo_win32_surface_create_for_dc (src->dc, format, width, height);
+    } else {
+	/* otherwise, create a ddb */
+	HBITMAP ddb = CreateCompatibleBitmap (src->dc, width, height);
+	HDC ddb_dc = CreateCompatibleDC (src->dc);
+	HRGN crgn = CreateRectRgn (0, 0, width, height);
+	HBITMAP saved_dc_bitmap;
+
+	saved_dc_bitmap = SelectObject (ddb_dc, ddb);
+	SelectClipRgn (ddb_dc, crgn);
+
+	DeleteObject (crgn);
+
+	new_surf = (cairo_win32_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;
+    }
+
+    return (cairo_surface_t*) new_surf;
+}
+
+static cairo_surface_t *
 _cairo_win32_surface_create_similar (void	    *abstract_src,
 				     cairo_content_t content,
 				     int	     width,
 				     int	     height)
 {
-    cairo_win32_surface_t *src = abstract_src;
-    cairo_format_t format = _cairo_format_from_content (content);
-
-    return _cairo_win32_surface_create_for_dc (src->dc, format, width, height);
+    return _cairo_win32_surface_create_similar_internal (abstract_src, content, width, height, FALSE);
 }
 
 static cairo_status_t
@@ -351,8 +430,8 @@ _cairo_win32_surface_finish (void *abstr
     /* If we created the Bitmap and DC, destroy them */
     if (surface->bitmap) {
 	SelectObject (surface->dc, surface->saved_dc_bitmap);
-  	DeleteObject (surface->bitmap);
-        DeleteDC (surface->dc);
+	DeleteObject (surface->bitmap);
+	DeleteDC (surface->dc);
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -367,24 +446,31 @@ _cairo_win32_surface_get_subimage (cairo
 				   cairo_win32_surface_t **local_out)
 {
     cairo_win32_surface_t *local;
-    cairo_status_t status;
+    cairo_int_status_t status;
     cairo_content_t content = _cairo_content_from_format (surface->format);
 
     local =
-	(cairo_win32_surface_t *) _cairo_win32_surface_create_similar (surface,
-								       content,
-								       width,
-								       height);
+	(cairo_win32_surface_t *) _cairo_win32_surface_create_similar_internal
+	(surface, content, width, height, TRUE);
     if (local->base.status)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    if (!BitBlt (local->dc,
-		 0, 0,
-		 width, height,
-		 surface->dc,
-		 x, y,
-		 SRCCOPY)) {
-	/* If we fail to BitBlt here, most likely the source is a printer.
+    status = CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if ((local->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT) &&
+	BitBlt (local->dc,
+		0, 0,
+		width, height,
+		surface->dc,
+		x, y,
+		SRCCOPY))
+    {
+	status = CAIRO_STATUS_SUCCESS;
+    }
+
+    if (status) {
+	/* If we failed here, most likely the source or dest doesn't
+	 * support BitBlt/AlphaBlend (e.g. a printer).
 	 * You can't reliably get bits from a printer DC, so just fill in
 	 * the surface as white (common case for printing).
 	 */
@@ -399,14 +485,6 @@ _cairo_win32_surface_get_subimage (cairo
     *local_out = local;
 
     return CAIRO_STATUS_SUCCESS;
-
- FAIL:
-    status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_get_subimage");
-
-    if (local)
-	cairo_surface_destroy (&local->base);
-
-    return status;
 }
 
 static cairo_status_t
@@ -575,14 +653,18 @@ _composite_alpha_blend (cairo_win32_surf
 			int                    alpha,
 			int                    src_x,
 			int                    src_y,
+			int                    src_w,
+			int                    src_h,
 			int                    dst_x,
 			int                    dst_y,
-			int                    width,
-			int                    height)
+			int                    dst_w,
+			int                    dst_h)
 {
     static unsigned alpha_blend_checked = FALSE;
     static cairo_alpha_blend_func_t alpha_blend = NULL;
 
+    int oldstretchmode;
+    BOOL success;
     BLENDFUNCTION blend_function;
 
     /* Check for AlphaBlend dynamically to allow compiling on
@@ -611,22 +693,35 @@ _composite_alpha_blend (cairo_win32_surf
 
     if (alpha_blend == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
-    if (GetDeviceCaps(dst->dc, SHADEBLENDCAPS) == SB_NONE)
+    if (!(dst->flags & CAIRO_WIN32_SURFACE_CAN_ALPHABLEND))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    if (src->format == CAIRO_FORMAT_RGB24 && dst->format == CAIRO_FORMAT_ARGB32)
+    {
+	/* Both of these are represented as 32bpp internally, and AlphaBlend
+	 * DOES NOT throw away source alpha is AC_SRC_ALPHA is not specified,
+	 * it just multiplies it by the SourceConstantAlpha, along with the
+	 * R G B components.
+	 * XXX there has to be a way to do this!
+	 */
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
     blend_function.BlendOp = AC_SRC_OVER;
     blend_function.BlendFlags = 0;
     blend_function.SourceConstantAlpha = alpha;
-    blend_function.AlphaFormat = src->format == CAIRO_FORMAT_ARGB32 ? AC_SRC_ALPHA : 0;
+    blend_function.AlphaFormat = (src->format == CAIRO_FORMAT_ARGB32) ? AC_SRC_ALPHA : 0;
 
+    /*oldstretchmode = SetStretchBltMode(dst->dc, HALFTONE);*/
     if (!alpha_blend (dst->dc,
 		      dst_x, dst_y,
-		      width, height,
+		      dst_w, dst_h,
 		      src->dc,
 		      src_x, src_y,
-		      width, height,
+		      src_w, src_h,
 		      blend_function))
 	return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
+    /*SetStretchBltMode(dst->dc, oldstretchmode);*/
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -649,11 +744,39 @@ _cairo_win32_surface_composite (cairo_op
     cairo_win32_surface_t *src;
     cairo_surface_pattern_t *src_surface_pattern;
     int alpha;
-    int integer_transform;
     int itx, ity;
+    double scalex, scaley;
+    cairo_fixed_t x0_fixed, y0_fixed;
+    int orig_dst_x = dst_x, orig_dst_y = dst_y;
+    int real_src_width, real_src_height;
+
+    int src_width, src_height;
+    int dst_width, dst_height;
+  
+    cairo_bool_t needs_alpha, needs_scale;
+    cairo_image_surface_t *src_image = NULL;
+
+#if 0
+    fprintf (stderr, "composite: %d %p %p %p [%d %d] [%d %d] [%d %d] %dx%d\n",
+	     op, pattern, mask_pattern, abstract_dst, src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height);
+#endif
+
+    /* If the destination can't do any of these, then
+     * we may as well give up, since this is what we'll
+     * look to for optimization.
+     */
+    if (dst->flags & (CAIRO_WIN32_SURFACE_CAN_BITBLT |
+		      CAIRO_WIN32_SURFACE_CAN_ALPHABLEND |
+		      CAIRO_WIN32_SURFACE_CAN_STRETCHBLT)
+	== 0)
+    {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE ||
-	pattern->extend != CAIRO_EXTEND_NONE)
+    if (pattern->extend != CAIRO_EXTEND_NONE)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     if (mask_pattern) {
@@ -665,67 +788,188 @@ _cairo_win32_surface_composite (cairo_op
 
 	alpha = ((cairo_solid_pattern_t *)mask_pattern)->color.alpha_short >> 8;
     } else {
-        alpha = 255;
+	alpha = 255;
     }
 
     src_surface_pattern = (cairo_surface_pattern_t *)pattern;
     src = (cairo_win32_surface_t *)src_surface_pattern->surface;
 
-    if (src->base.backend != dst->base.backend)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+    /* Disable this for now */
+#if 0
+    if (src->base.type == CAIRO_SURFACE_TYPE_IMAGE) {
+	src_image = (cairo_image_surface_t*) src;
 
-    integer_transform = _cairo_matrix_is_integer_translation (&pattern->matrix, &itx, &ity);
-    if (!integer_transform)
+	if (src_image->format != CAIRO_FORMAT_RGB24)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+    } else 
+#endif
+    if (src->base.backend != dst->base.backend) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
 
-    /* Fix up src coordinates; the src coords and size must be within the
-     * bounds of the source surface.
-     * XXX the region not covered should be appropriately rendered!
-     * - for OVER/SOURCE with RGB24 source -> opaque black
-     * - for SOURCE with ARGB32 source -> 100% transparent black
+#if 0
+    fprintf (stderr, "Before check: (%d %d) [%d %d] -> [%d %d %d %d] {mat %f %f %f %f}\n",
+	     src->extents.width, src->extents.height,
+	     src_x, src_y,
+	     dst_x, dst_y, width, height,
+	     pattern->matrix.x0, pattern->matrix.y0, pattern->matrix.xx, pattern->matrix.yy);
+#endif
+
+    /* We can only use GDI functions if the source and destination rectangles
+     * are on integer pixel boundaries.  Figure that out here.
      */
+    x0_fixed = _cairo_fixed_from_double(pattern->matrix.x0 / pattern->matrix.xx);
+    y0_fixed = _cairo_fixed_from_double(pattern->matrix.y0 / pattern->matrix.yy);
+
+    if (pattern->matrix.yx != 0.0 ||
+	pattern->matrix.xy != 0.0 ||
+	!_cairo_fixed_is_integer(x0_fixed) ||
+	!_cairo_fixed_is_integer(y0_fixed))
+    {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    itx = _cairo_fixed_integer_part(x0_fixed);
+    ity = _cairo_fixed_integer_part(y0_fixed);
+
+    scalex = pattern->matrix.xx;
+    scaley = pattern->matrix.yy;
+
     src_x += itx;
     src_y += ity;
 
+    if (scalex <= 0.0 || scaley <= 0.0)
+	return CAIRO_STATUS_SUCCESS;
+
+    if (scalex != 1.0 || scaley != 1.0)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    /* If the src coordinates are outside of the source surface bounds,
+     * we have to fix them up, because this is an error for the GDI
+     * functions.
+     * XXX Make sure to correctly clear out the unpainted region.
+     */
+
     if (src_x < 0) {
-        width += src_x;
-        dst_x -= src_x;
-        src_x = 0;
+	width += src_x;
+	dst_x -= src_x;
+	src_x = 0;
     }
 
     if (src_y < 0) {
-        height += src_y;
-        dst_y -= src_y;
-        src_y = 0;
+	height += src_y;
+	dst_y -= src_y;
+	src_y = 0;
     }
 
     if (src_x + width > src->extents.width)
-        width = src->extents.width - src_x;
+	dst_width = src->extents.width - src_x;
+    else
+	dst_width = width;
 
     if (src_y + height > src->extents.height)
-        height = src->extents.height - src_y;
+	dst_height = src->extents.height - src_y;
+    else
+	dst_height = height;
 
+    src_width = dst_width;
+    src_height = dst_height;
+
+    /*
+     * Figure out what action to take.
+     * XXX handle SOURCE with alpha != 255
+     */
     if (alpha == 255 &&
-	(op == CAIRO_OPERATOR_SOURCE ||
-	 (src->format == CAIRO_FORMAT_RGB24 && op == CAIRO_OPERATOR_OVER))) {
+	(dst->format == src->format) &&
+	((op == CAIRO_OPERATOR_SOURCE && (dst->format == CAIRO_FORMAT_ARGB32 ||
+					  dst->format == CAIRO_FORMAT_RGB24)) ||
+	 (op == CAIRO_OPERATOR_OVER && dst->format == CAIRO_FORMAT_RGB24)))
+    {
+	needs_alpha = FALSE;
+    } else if ((op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_SOURCE) &&
+	       (src->format == CAIRO_FORMAT_RGB24 || src->format == CAIRO_FORMAT_ARGB32) &&
+	       (dst->format == CAIRO_FORMAT_RGB24 || dst->format == CAIRO_FORMAT_ARGB32))
+    {
+	needs_alpha = TRUE;
+    } else {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+  
+    if (scalex == 1.0 && scaley == 1.0) {
+	needs_scale = FALSE;
+    } else {
+	needs_scale = TRUE;
+    }
 
-	if (!BitBlt (dst->dc,
-		     dst_x, dst_y,
-		     width, height,
-		     src->dc,
-		     src_x, src_y,
-		     SRCCOPY))
-	    return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
+#if 0
+    fprintf (stderr, "action: [%d %d %d %d] -> [%d %d %d %d]\n",
+	     src_x, src_y, src_width, src_height,
+	     dst_x, dst_y, dst_width, dst_height);
+    fflush (stderr);
+#endif
 
-	return CAIRO_STATUS_SUCCESS;
+    /* Then do BitBlt, StretchDIBits, StretchBlt, AlphaBlend, or MaskBlt */
+    if (src_image) {
+	BITMAPINFO bi;
+	bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+	bi.bmiHeader.biWidth = src_image->width;
+	bi.bmiHeader.biHeight = src_image->height;
+	bi.bmiHeader.biSizeImage = 0;
+	bi.bmiHeader.biXPelsPerMeter = PELS_72DPI;
+	bi.bmiHeader.biYPelsPerMeter = PELS_72DPI;
+	bi.bmiHeader.biPlanes = 1;
+	bi.bmiHeader.biBitCount = 32;
+	bi.bmiHeader.biCompression = BI_RGB;
+	bi.bmiHeader.biClrUsed = 0;
+	bi.bmiHeader.biClrImportant = 0;
+
+	if (!StretchDIBits (dst->dc,
+			    dst_x, dst_y, dst_width, dst_height,
+			    src_x, src_y, src_width, src_height,
+			    src_image->data,
+			    &bi,
+			    DIB_RGB_COLORS,
+			    SRCCOPY))
+	    return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(StretchDIBits)");
 
-    } else if ((src->format == CAIRO_FORMAT_RGB24 || src->format == CAIRO_FORMAT_ARGB32) &&
-	       (dst->format == CAIRO_FORMAT_RGB24 || dst->format == CAIRO_FORMAT_ARGB32) &&
-	       op == CAIRO_OPERATOR_OVER) {
-
-	return _composite_alpha_blend (dst, src, alpha,
-				       src_x, src_y,
-				       dst_x, dst_y, width, height);
+	return CAIRO_STATUS_SUCCESS;
+    } else if (!needs_alpha) {
+	/* BitBlt or StretchBlt? */
+	if (!needs_scale && (dst->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT)) {
+	    if (!BitBlt (dst->dc,
+			 dst_x, dst_y,
+			 dst_width, dst_height,
+			 src->dc,
+			 src_x, src_y,
+			 SRCCOPY))
+		return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(BitBlt)");
+
+	    return CAIRO_STATUS_SUCCESS;
+	} else if (dst->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHBLT) {
+	    /* StretchBlt? */
+	    /* XXX check if we want HALFTONE, based on the src filter */
+	    BOOL success;
+	    int oldmode = SetStretchBltMode(dst->dc, HALFTONE);
+	    success = StretchBlt(dst->dc,
+				 dst_x, dst_y,
+				 dst_width, dst_height,
+				 src->dc,
+				 src_x, src_y,
+				 src_width, src_height,
+				 SRCCOPY);
+	    SetStretchBltMode(dst->dc, oldmode);
+
+	    if (!success) {
+		_cairo_win32_print_gdi_error ("StretchBlt");
+		return CAIRO_INT_STATUS_UNSUPPORTED;
+	    }
+  
+	    return CAIRO_STATUS_SUCCESS;
+	}
+    } else if (needs_alpha && !needs_scale) {
+  	return _composite_alpha_blend (dst, src, alpha,
+				       src_x, src_y, src_width, src_height,
+				       dst_x, dst_y, dst_width, dst_height);
     }
 
     return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1114,13 +1358,13 @@ cairo_win32_surface_create (HDC hdc)
 	_cairo_win32_print_gdi_error ("cairo_win32_surface_create");
 	/* XXX: Can we make a more reasonable guess at the error cause here? */
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
-	return &_cairo_surface_nil;
+	return NIL_SURFACE;
     }
 
     if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY) {
 	depth = GetDeviceCaps(hdc, BITSPIXEL);
 	if (depth == 32)
-	    format = CAIRO_FORMAT_ARGB32;
+	    format = CAIRO_FORMAT_RGB24;
 	else if (depth == 24)
 	    format = CAIRO_FORMAT_RGB24;
 	else if (depth == 16)
@@ -1132,7 +1376,7 @@ cairo_win32_surface_create (HDC hdc)
 	else {
 	    _cairo_win32_print_gdi_error("cairo_win32_surface_create(bad BITSPIXEL)");
 	    _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    return &_cairo_surface_nil;
+	    return NIL_SURFACE;
 	}
     } else {
 	format = CAIRO_FORMAT_RGB24;
@@ -1141,7 +1385,7 @@ cairo_win32_surface_create (HDC hdc)
     surface = malloc (sizeof (cairo_win32_surface_t));
     if (surface == NULL) {
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
-	return &_cairo_surface_nil;
+	return NIL_SURFACE;
     }
 
     surface->image = NULL;
@@ -1149,6 +1393,7 @@ cairo_win32_surface_create (HDC hdc)
 
     surface->dc = hdc;
     surface->bitmap = NULL;
+    surface->is_dib = FALSE;
     surface->saved_dc_bitmap = NULL;
 
     surface->clip_rect.x = rect.left;
@@ -1157,19 +1402,21 @@ cairo_win32_surface_create (HDC hdc)
     surface->clip_rect.height = rect.bottom - rect.top;
 
     if (surface->clip_rect.width == 0 ||
-        surface->clip_rect.height == 0)
+	surface->clip_rect.height == 0)
     {
-        surface->saved_clip = NULL;
+	surface->saved_clip = NULL;
     } else {
-        surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
-        if (GetClipRgn (hdc, surface->saved_clip) == 0) {
-            DeleteObject(surface->saved_clip);
-            surface->saved_clip = NULL;
-        }
+	surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
+	if (GetClipRgn (hdc, surface->saved_clip) == 0) {
+	    DeleteObject(surface->saved_clip);
+	    surface->saved_clip = NULL;
+	}
     }
 
     surface->extents = surface->clip_rect;
 
+    surface->flags = _cairo_win32_flags_for_dc (surface->dc);
+
     _cairo_surface_init (&surface->base, &cairo_win32_surface_backend,
 			 _cairo_content_from_format (format));
 
@@ -1192,13 +1439,73 @@ cairo_win32_surface_create (HDC hdc)
  **/
 cairo_surface_t *
 cairo_win32_surface_create_with_dib (cairo_format_t format,
-                                     int	    width,
-                                     int	    height)
+				     int	    width,
+				     int	    height)
 {
     return _cairo_win32_surface_create_for_dc (NULL, format, width, height);
 }
 
 /**
+ * cairo_win32_surface_create_with_ddb:
+ * @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 unititialized.
+ *
+ * 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_surface_t *new_surf;
+    HBITMAP ddb;
+    HDC screen_dc, ddb_dc;
+    HRGN crgn;
+    HBITMAP saved_dc_bitmap;
+
+    if (format != CAIRO_FORMAT_RGB24)
+	return NULL;
+/* XXX handle these eventually
+	format != CAIRO_FORMAT_A8 ||
+	format != CAIRO_FORMAT_A1)
+*/
+
+    if (!hdc) {
+	screen_dc = GetDC (NULL);
+	hdc = screen_dc;
+    } else {
+	screen_dc = NULL;
+    }
+
+    ddb = CreateCompatibleBitmap (hdc, width, height);
+    ddb_dc = CreateCompatibleDC (hdc);
+
+    saved_dc_bitmap = SelectObject (ddb_dc, ddb);
+
+    crgn = CreateRectRgn (0, 0, width, height);
+    SelectClipRgn (ddb_dc, crgn);
+    DeleteObject (crgn);
+
+    new_surf = (cairo_win32_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;
+
+    if (screen_dc)
+	ReleaseDC (NULL, screen_dc);
+
+    return (cairo_surface_t*) new_surf;
+}
+
+/**
  * _cairo_surface_is_win32:
  * @surface: a #cairo_surface_t
  *
@@ -1239,6 +1546,28 @@ cairo_win32_surface_get_dc (cairo_surfac
     return winsurf->dc;
 }
 
+/**
+ * cario_win32_surface_get_image
+ * @surface: a #cairo_surface_t
+ *
+ * Returns a #cairo_surface_t image surface that refers to the same bits
+ * as the DIB of the Win32 surface.  If the passed-in win32 surface
+ * is not a DIB surface, NULL is returned.
+ *
+ * Return value: a #cairo_surface_t (owned by the win32 cairo_surface_t),
+ * or NULL if the win32 surface is not a DIB.
+ *
+ * Since: 1.4
+ */
+cairo_surface_t *
+cairo_win32_surface_get_image (cairo_surface_t *surface)
+{
+    if (!_cairo_surface_is_win32(surface))
+	return NULL;
+
+    return ((cairo_win32_surface_t*)surface)->image;
+}
+
 static const cairo_surface_backend_t cairo_win32_surface_backend = {
     CAIRO_SURFACE_TYPE_WIN32,
     _cairo_win32_surface_create_similar,
@@ -1289,7 +1618,7 @@ static int _cairo_win32_initialized = 0;
 void
 _cairo_win32_initialize () {
     if (_cairo_win32_initialized)
-        return;
+	return;
 
     /* every 'mutex' from CAIRO_MUTEX_DECALRE needs to be initialized here */
     InitializeCriticalSection (&cairo_toy_font_face_hash_table_mutex);
@@ -1320,3 +1649,17 @@ DllMain (HINSTANCE hinstDLL,
 }
 #endif
 #endif
+
+/* 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.
+ */
diff --git a/src/cairo-win32.h b/src/cairo-win32.h
index a5cd2f5..9710e9a 100644
--- a/src/cairo-win32.h
+++ b/src/cairo-win32.h
@@ -48,6 +48,12 @@ cairo_public cairo_surface_t *
 cairo_win32_surface_create (HDC hdc);
 
 cairo_public cairo_surface_t *
+cairo_win32_surface_create_with_ddb (HDC hdc,
+                                     cairo_format_t format,
+                                     int width,
+                                     int height);
+
+cairo_public cairo_surface_t *
 cairo_win32_surface_create_with_dib (cairo_format_t format,
                                      int width,
                                      int height);
@@ -55,6 +61,9 @@ cairo_win32_surface_create_with_dib (cai
 cairo_public HDC
 cairo_win32_surface_get_dc (cairo_surface_t *surface);
 
+cairo_public cairo_surface_t *
+cairo_win32_surface_get_image (cairo_surface_t *surface);
+
 cairo_public cairo_font_face_t *
 cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont);
 


More information about the cairo-commit mailing list