[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