From ae3319890eacd1c8282ca6df7b263ac74abb5f8d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 12 Feb 2012 11:25:07 +0000 Subject: [PATCH] win32: Rebase on the new compositor infrastructure Try and undo all the damage that has acrued over the years by plugging into the compositor pipeline. References: https://bugs.freedesktop.org/show_bug.cgi?id=42739 References: https://bugs.freedesktop.org/show_bug.cgi?id=42821 References: https://bugs.freedesktop.org/show_bug.cgi?id=33081 Signed-off-by: Chris Wilson --- src/Makefile.sources | 6 +- src/cairo-image-compositor.c | 39 + src/cairo-image-source.c | 25 + src/cairo-image-surface-private.h | 9 + src/cairo-image-surface.c | 25 +- src/cairo-surface-backend-private.h | 10 + src/cairo-surface-private.h | 10 + src/cairo-surface.c | 20 + src/cairo-traps-compositor.c | 62 + src/cairo.h | 2 + src/cairoint.h | 6 + src/win32/cairo-win32-debug.c | 87 + src/win32/cairo-win32-device.c | 189 ++ src/win32/cairo-win32-display-surface.c | 1031 +++++++++ src/win32/cairo-win32-font.c | 23 +- src/win32/cairo-win32-gdi-compositor.c | 646 ++++++ src/win32/cairo-win32-printing-surface.c | 324 +-- src/win32/cairo-win32-private.h | 183 +- src/win32/cairo-win32-surface.c | 1960 +---------------- .../cairo-win32-system.c} | 8 - 20 files changed, 2534 insertions(+), 2131 deletions(-) create mode 100644 src/win32/cairo-win32-debug.c create mode 100644 src/win32/cairo-win32-device.c create mode 100644 src/win32/cairo-win32-display-surface.c create mode 100644 src/win32/cairo-win32-gdi-compositor.c rename src/{cairo-system.c => win32/cairo-win32-system.c} (94%) diff --git a/src/Makefile.sources b/src/Makefile.sources index 22a7b471f..19a14a7be 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -209,7 +209,6 @@ cairo_sources = \ cairo-surface-snapshot.c \ cairo-surface-subsurface.c \ cairo-surface-wrapper.c \ - cairo-system.c \ cairo-time.c \ cairo-tor-scan-converter.c \ cairo-tor22-scan-converter.c \ @@ -336,7 +335,12 @@ cairo_quartz_font_sources = cairo-quartz-font.c cairo_win32_headers = cairo-win32.h cairo_win32_private = win32/cairo-win32-private.h cairo_win32_sources = \ + win32/cairo-win32-debug.c \ + win32/cairo-win32-device.c \ + win32/cairo-win32-gdi-compositor.c \ + win32/cairo-win32-system.c \ win32/cairo-win32-surface.c \ + win32/cairo-win32-display-surface.c \ win32/cairo-win32-printing-surface.c \ $(NULL) cairo_win32_font_sources = \ diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c index 6c409e93c..7c044c4b0 100644 --- a/src/cairo-image-compositor.c +++ b/src/cairo-image-compositor.c @@ -93,6 +93,8 @@ draw_image_boxes (void *_dst, struct _cairo_boxes_chunk *chunk; int i; + TRACE ((stderr, "%s\n", __FUNCTION__)); + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { for (i = 0; i < chunk->count; i++) { cairo_box_t *b = &chunk->base[i]; @@ -279,6 +281,8 @@ fill_rectangles (void *_dst, uint32_t pixel; int i; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (fill_reduces_to_source (op, color, dst) && color_to_pixel (color, dst->pixman_format, &pixel)) { @@ -321,6 +325,8 @@ fill_boxes (void *_dst, uint32_t pixel; int i; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (fill_reduces_to_source (op, color, dst) && color_to_pixel (color, dst->pixman_format, &pixel)) { @@ -379,6 +385,9 @@ composite (void *_dst, { cairo_image_source_t *src = (cairo_image_source_t *)abstract_src; cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (mask) { pixman_image_composite32 (_pixman_operator (op), src->pixman_image, mask->pixman_image, to_pixman_image (_dst), @@ -415,6 +424,8 @@ lerp (void *_dst, cairo_image_source_t *src = (cairo_image_source_t *)abstract_src; cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask; + TRACE ((stderr, "%s\n", __FUNCTION__)); + #if PIXMAN_HAS_OP_LERP pixman_image_composite32 (PIXMAN_OP_LERP_SRC, src->pixman_image, mask->pixman_image, dst->pixman_image, @@ -424,6 +435,10 @@ lerp (void *_dst, width, height); #else /* Punch the clip out of the destination */ + TRACE ((stderr, "%s - OUT_REVERSE (mask=%d/%p, dst=%d/%p)\n", + __FUNCTION__, + mask->base.unique_id, mask->pixman_image, + dst->base.unique_id, dst->pixman_image)); pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, mask->pixman_image, NULL, dst->pixman_image, mask_x, mask_y, @@ -432,6 +447,11 @@ lerp (void *_dst, width, height); /* Now add the two results together */ + TRACE ((stderr, "%s - ADD (src=%d/%p, mask=%d/%p, dst=%d/%p)\n", + __FUNCTION__, + src->base.unique_id, src->pixman_image, + mask->base.unique_id, mask->pixman_image, + dst->base.unique_id, dst->pixman_image)); pixman_image_composite32 (PIXMAN_OP_ADD, src->pixman_image, mask->pixman_image, dst->pixman_image, src_x, src_y, @@ -464,6 +484,7 @@ composite_boxes (void *_dst, int i; /* XXX consider using a region? saves multiple prepare-composite */ + TRACE ((stderr, "%s\n", __FUNCTION__)); if (((cairo_surface_t *)_dst)->is_clear && (op == CAIRO_OPERATOR_SOURCE || @@ -612,6 +633,8 @@ composite_traps (void *_dst, pixman_image_t *mask; pixman_format_code_t format; + TRACE ((stderr, "%s\n", __FUNCTION__)); + /* Special case adding trapezoids onto a mask surface; we want to avoid * creating an intermediate temporary mask unnecessarily. * @@ -690,6 +713,8 @@ composite_tristrip (void *_dst, pixman_image_t *mask; pixman_format_code_t format; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (strip->num_points < 3) return CAIRO_STATUS_SUCCESS; @@ -745,6 +770,8 @@ composite_one_glyph (void *_dst, cairo_status_t status; int x, y; + TRACE ((stderr, "%s\n", __FUNCTION__)); + status = _cairo_scaled_glyph_lookup (info->font, info->glyphs[0].index, CAIRO_SCALED_GLYPH_INFO_SURFACE, @@ -794,6 +821,8 @@ composite_glyphs_via_mask (void *_dst, cairo_status_t status; int i; + TRACE ((stderr, "%s\n", __FUNCTION__)); + /* XXX convert the glyphs to common formats a8/a8r8g8b8 to hit * optimised paths through pixman. Should we increase the bit * depth of the target surface, we should reconsider the appropriate @@ -916,6 +945,8 @@ composite_glyphs (void *_dst, cairo_status_t status; int i; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (info->num_glyphs == 1) return composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info); @@ -1196,6 +1227,8 @@ span_renderer_init (cairo_abstract_span_renderer_t *_r, int src_x, src_y; int mask_x, mask_y; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (op == CAIRO_OPERATOR_CLEAR) { op = PIXMAN_OP_LERP_CLEAR; } else if (dst->base.is_clear && @@ -1281,6 +1314,8 @@ span_renderer_fini (cairo_abstract_span_renderer_t *_r, { cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (status == CAIRO_INT_STATUS_SUCCESS && r->base.finish) r->base.finish (r); @@ -1426,6 +1461,8 @@ span_renderer_init (cairo_abstract_span_renderer_t *_r, const cairo_pattern_t *source = &composite->source_pattern.base; cairo_operator_t op = composite->op; + TRACE ((stderr, "%s\n", __FUNCTION__)); + r->composite = composite; r->mask = NULL; r->src = NULL; @@ -1531,6 +1568,8 @@ span_renderer_fini (cairo_abstract_span_renderer_t *_r, { cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { const cairo_composite_rectangles_t *composite = r->composite; diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c index 2c9437930..58a18e349 100644 --- a/src/cairo-image-source.c +++ b/src/cairo-image-source.c @@ -71,6 +71,8 @@ _pixman_transparent_image (void) { pixman_image_t *image; + TRACE ((stderr, "%s\n", __FUNCTION__)); + image = __pixman_transparent_image; if (unlikely (image == NULL)) { pixman_color_t color; @@ -101,6 +103,8 @@ _pixman_black_image (void) { pixman_image_t *image; + TRACE ((stderr, "%s\n", __FUNCTION__)); + image = __pixman_black_image; if (unlikely (image == NULL)) { pixman_color_t color; @@ -131,6 +135,8 @@ _pixman_white_image (void) { pixman_image_t *image; + TRACE ((stderr, "%s\n", __FUNCTION__)); + image = __pixman_white_image; if (unlikely (image == NULL)) { pixman_color_t color; @@ -175,18 +181,21 @@ static int n_cached; static pixman_image_t * _pixman_transparent_image (void) { + TRACE ((stderr, "%s\n", __FUNCTION__)); return _pixman_image_for_color (CAIRO_COLOR_TRANSPARENT); } static pixman_image_t * _pixman_black_image (void) { + TRACE ((stderr, "%s\n", __FUNCTION__)); return _pixman_image_for_color (CAIRO_COLOR_BLACK); } static pixman_image_t * _pixman_white_image (void) { + TRACE ((stderr, "%s\n", __FUNCTION__)); return _pixman_image_for_color (CAIRO_COLOR_WHITE); } #endif /* !PIXMAN_HAS_ATOMIC_OPS */ @@ -294,6 +303,8 @@ _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern, unsigned int i; cairo_int_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) { pixman_stops = _cairo_malloc_ab (pattern->n_stops, sizeof(pixman_gradient_stop_t)); @@ -384,6 +395,8 @@ _pixman_image_for_mesh (const cairo_mesh_pattern_t *pattern, pixman_image_t *image; int width, height; + TRACE ((stderr, "%s\n", __FUNCTION__)); + *tx = -extents->x; *ty = -extents->y; width = extents->width; @@ -437,6 +450,8 @@ _pixel_to_solid (cairo_image_surface_t *image, int x, int y) uint32_t pixel; pixman_color_t color; + TRACE ((stderr, "%s\n", __FUNCTION__)); + switch (image->format) { default: case CAIRO_FORMAT_INVALID: @@ -607,6 +622,8 @@ _pixman_image_for_recording (cairo_image_surface_t *dst, cairo_matrix_t *m, matrix; int tx = 0, ty = 0; + TRACE ((stderr, "%s\n", __FUNCTION__)); + *ix = *iy = 0; source = _cairo_pattern_get_source (pattern, &limit); @@ -707,6 +724,8 @@ _pixman_image_for_surface (cairo_image_surface_t *dst, cairo_extend_t extend = pattern->base.extend; pixman_image_t *pixman_image; + TRACE ((stderr, "%s\n", __FUNCTION__)); + *ix = *iy = 0; pixman_image = NULL; if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) @@ -915,6 +934,8 @@ _pixman_image_for_raster (cairo_image_surface_t *dst, cairo_status_t status; cairo_surface_t *surface; + TRACE ((stderr, "%s\n", __FUNCTION__)); + *ix = *iy = 0; surface = _cairo_raster_source_pattern_acquire (&pattern->base, @@ -977,6 +998,8 @@ _pixman_image_for_pattern (cairo_image_surface_t *dst, { *tx = *ty = 0; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (pattern == NULL) return _pixman_white_image (); @@ -1034,6 +1057,8 @@ _cairo_image_source_create_for_pattern (cairo_surface_t *dst, { cairo_image_source_t *source; + TRACE ((stderr, "%s\n", __FUNCTION__)); + source = malloc (sizeof (cairo_image_source_t)); if (unlikely (source == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); diff --git a/src/cairo-image-surface-private.h b/src/cairo-image-surface-private.h index 30713a818..3951793c1 100644 --- a/src/cairo-image-surface-private.h +++ b/src/cairo-image-surface-private.h @@ -50,6 +50,7 @@ struct _cairo_image_surface { pixman_image_t *pixman_image; const cairo_compositor_t *compositor; + cairo_surface_t *parent; pixman_format_code_t pixman_format; cairo_format_t format; @@ -64,6 +65,7 @@ struct _cairo_image_surface { unsigned transparency : 2; unsigned color : 2; }; +#define to_image_surface(S) ((cairo_image_surface_t *)(S)) /* A wrapper for holding pixman images returned by create_for_pattern */ typedef struct _cairo_image_source { @@ -201,6 +203,13 @@ _pixman_image_add_tristrip (pixman_image_t *image, int dst_x, int dst_y, cairo_tristrip_t *strip); +static inline void +_cairo_image_surface_set_parent (cairo_image_surface_t *image, + cairo_surface_t *parent) +{ + image->parent = parent; +} + /** * _cairo_surface_is_image: * @surface: a #cairo_surface_t diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index fede14cd7..66f024c56 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -147,6 +147,7 @@ _cairo_image_surface_init (cairo_image_surface_t *surface, pixman_image_t *pixman_image, pixman_format_code_t pixman_format) { + surface->parent = NULL; surface->pixman_image = pixman_image; surface->pixman_format = pixman_format; @@ -714,7 +715,7 @@ _cairo_format_bits_per_pixel (cairo_format_t format) } } - static cairo_surface_t * +static cairo_surface_t * _cairo_image_surface_create_similar (void *abstract_other, cairo_content_t content, int width, @@ -722,6 +723,8 @@ _cairo_image_surface_create_similar (void *abstract_other, { cairo_image_surface_t *other = abstract_other; + TRACE ((stderr, "%s (other=%u)\n", __FUNCTION__, other->base.unique_id)); + if (! _cairo_image_surface_is_size_valid (width, height)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); @@ -872,6 +875,10 @@ _cairo_image_surface_paint (void *abstract_surface, const cairo_clip_t *clip) { cairo_image_surface_t *surface = abstract_surface; + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->base.unique_id)); + return _cairo_compositor_paint (surface->compositor, &surface->base, op, source, clip); } @@ -884,6 +891,10 @@ _cairo_image_surface_mask (void *abstract_surface, const cairo_clip_t *clip) { cairo_image_surface_t *surface = abstract_surface; + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->base.unique_id)); + return _cairo_compositor_mask (surface->compositor, &surface->base, op, source, mask, clip); } @@ -901,6 +912,10 @@ _cairo_image_surface_stroke (void *abstract_surface, const cairo_clip_t *clip) { cairo_image_surface_t *surface = abstract_surface; + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->base.unique_id)); + return _cairo_compositor_stroke (surface->compositor, &surface->base, op, source, path, style, ctm, ctm_inverse, @@ -918,6 +933,10 @@ _cairo_image_surface_fill (void *abstract_surface, const cairo_clip_t *clip) { cairo_image_surface_t *surface = abstract_surface; + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->base.unique_id)); + return _cairo_compositor_fill (surface->compositor, &surface->base, op, source, path, fill_rule, tolerance, antialias, @@ -934,6 +953,10 @@ _cairo_image_surface_glyphs (void *abstract_surface, const cairo_clip_t *clip) { cairo_image_surface_t *surface = abstract_surface; + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->base.unique_id)); + return _cairo_compositor_glyphs (surface->compositor, &surface->base, op, source, glyphs, num_glyphs, scaled_font, diff --git a/src/cairo-surface-backend-private.h b/src/cairo-surface-backend-private.h index f7bfbd7b1..fbaa91232 100644 --- a/src/cairo-surface-backend-private.h +++ b/src/cairo-surface-backend-private.h @@ -201,6 +201,16 @@ struct _cairo_surface_backend { (*get_supported_mime_types) (void *surface); }; +cairo_private cairo_status_t +_cairo_surface_default_acquire_source_image (void *surface, + cairo_image_surface_t **image_out, + void **image_extra); + +cairo_private void +_cairo_surface_default_release_source_image (void *surface, + cairo_image_surface_t *image, + void *image_extra); + cairo_private cairo_surface_t * _cairo_surface_default_source (void *surface, cairo_rectangle_int_t *extents); diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h index 657592d11..f6ebf22a2 100644 --- a/src/cairo-surface-private.h +++ b/src/cairo-surface-private.h @@ -44,6 +44,7 @@ #include "cairo-list-private.h" #include "cairo-reference-count-private.h" #include "cairo-clip-private.h" +#include "cairo-surface-backend-private.h" typedef void (*cairo_surface_func_t) (cairo_surface_t *); @@ -110,4 +111,13 @@ cairo_private cairo_surface_t * _cairo_surface_get_source (cairo_surface_t *surface, cairo_rectangle_int_t *extents); +static inline cairo_status_t +_cairo_surface_flush (cairo_surface_t *surface) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + if (surface->backend->flush) + status = surface->backend->flush (surface); + return status; +} + #endif /* CAIRO_SURFACE_PRIVATE_H */ diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 13f0909ee..78346c941 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -1713,6 +1713,17 @@ _cairo_surface_acquire_source_image (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +cairo_status_t +_cairo_surface_default_acquire_source_image (void *surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + *image_out = (cairo_image_surface_t *) + cairo_surface_map_to_image (surface, NULL); + *image_extra = NULL; + return (*image_out)->base.status; +} + /** * _cairo_surface_release_source_image: * @surface: a #cairo_surface_t @@ -1731,6 +1742,15 @@ _cairo_surface_release_source_image (cairo_surface_t *surface, surface->backend->release_source_image (surface, image, image_extra); } +void +_cairo_surface_default_release_source_image (void *surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_unmap_image (surface, &image->base); +} + + cairo_surface_t * _cairo_surface_get_source (cairo_surface_t *surface, cairo_rectangle_int_t *extents) diff --git a/src/cairo-traps-compositor.c b/src/cairo-traps-compositor.c index b4351806e..a9f8c75c3 100644 --- a/src/cairo-traps-compositor.c +++ b/src/cairo-traps-compositor.c @@ -167,6 +167,8 @@ combine_clip_as_traps (const cairo_traps_compositor_t *compositor, int src_x, src_y; cairo_int_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias); if (status) @@ -209,6 +211,8 @@ traps_get_clip_surface (const cairo_traps_compositor_t *compositor, cairo_surface_t *surface; cairo_int_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + surface = _cairo_surface_create_similar_solid (target, CAIRO_CONTENT_ALPHA, extents->width, @@ -247,6 +251,8 @@ create_composite_mask (const cairo_traps_compositor_t *compositor, int src_x, src_y; int i; + TRACE ((stderr, "%s\n", __FUNCTION__)); + surface = _cairo_surface_create_similar_solid (dst, CAIRO_CONTENT_ALPHA, extents->bounded.width, @@ -351,6 +357,8 @@ clip_and_composite_with_mask (const cairo_traps_compositor_t *compositor, cairo_surface_t *dst = extents->surface; cairo_surface_t *mask; + TRACE ((stderr, "%s\n", __FUNCTION__)); + mask = create_composite_mask (compositor, dst, draw_closure, draw_func, mask_func, extents); @@ -396,6 +404,8 @@ clip_and_composite_combine (const cairo_traps_compositor_t *compositor, cairo_surface_t *tmp, *clip; cairo_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + tmp = _cairo_surface_create_similar_scratch (dst, dst->content, extents->bounded.width, extents->bounded.height); @@ -467,6 +477,8 @@ clip_and_composite_source (const cairo_traps_compositor_t *compositor, { cairo_surface_t *mask; + TRACE ((stderr, "%s\n", __FUNCTION__)); + /* Create a surface that is mask IN clip */ mask = create_composite_mask (compositor, dst, draw_closure, draw_func, mask_func, @@ -531,6 +543,8 @@ fixup_unbounded_with_mask (const cairo_traps_compositor_t *compositor, cairo_clip_t *clip = extents->clip; cairo_surface_t *mask; + TRACE ((stderr, "%s\n", __FUNCTION__)); + /* XXX can we avoid querying the clip surface again? */ mask = traps_get_clip_surface (compositor, dst, clip, &extents->unbounded); if (unlikely (mask->status)) @@ -622,6 +636,8 @@ fixup_unbounded (const cairo_traps_compositor_t *compositor, cairo_box_t box; cairo_int_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (extents->bounded.width == extents->unbounded.width && extents->bounded.height == extents->unbounded.height) { @@ -772,6 +788,8 @@ clip_and_composite (const cairo_traps_compositor_t *compositor, cairo_region_t *clip_region = NULL; cairo_status_t status = CAIRO_STATUS_SUCCESS; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (reduce_alpha_op (extents)) { op = CAIRO_OPERATOR_ADD; source = NULL; @@ -882,6 +900,8 @@ composite_traps (const cairo_traps_compositor_t *compositor, { composite_traps_info_t *info = closure; + TRACE ((stderr, "%s\n", __FUNCTION__)); + return compositor->composite_traps (dst, op, src, src_x - dst_x, src_y - dst_y, dst_x, dst_y, @@ -907,6 +927,8 @@ composite_tristrip (const cairo_traps_compositor_t *compositor, { composite_tristrip_info_t *info = closure; + TRACE ((stderr, "%s\n", __FUNCTION__)); + return compositor->composite_tristrip (dst, op, src, src_x - dst_x, src_y - dst_y, dst_x, dst_y, @@ -985,6 +1007,8 @@ composite_aligned_boxes (const cairo_traps_compositor_t *compositor, cairo_bool_t op_is_source; cairo_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (need_clip_mask && (! extents->is_bounded || extents->op == CAIRO_OPERATOR_SOURCE)) { @@ -1107,6 +1131,8 @@ upload_boxes (const cairo_traps_compositor_t *compositor, cairo_int_status_t status; int tx, ty; + TRACE ((stderr, "%s\n", __FUNCTION__)); + src = _cairo_pattern_get_source((cairo_surface_pattern_t *)source, &limit); if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type)) @@ -1258,6 +1284,8 @@ clip_and_composite_polygon (const cairo_traps_compositor_t *compositor, cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip); cairo_int_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (polygon->num_edges == 0) { status = CAIRO_INT_STATUS_SUCCESS; @@ -1426,6 +1454,8 @@ composite_opacity_boxes (const cairo_traps_compositor_t *compositor, struct composite_opacity_info info; int i; + TRACE ((stderr, "%s\n", __FUNCTION__)); + info.compositor = compositor; info.op = op; info.dst = dst; @@ -1460,6 +1490,8 @@ composite_boxes (const cairo_traps_compositor_t *compositor, cairo_traps_t traps; cairo_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + status = _cairo_traps_init_boxes (&traps, closure); if (unlikely (status)) return status; @@ -1481,6 +1513,8 @@ clip_and_composite_boxes (const cairo_traps_compositor_t *compositor, { cairo_int_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (boxes->num_boxes == 0 && extents->is_bounded) return CAIRO_STATUS_SUCCESS; @@ -1549,6 +1583,8 @@ composite_traps_as_boxes (const cairo_traps_compositor_t *compositor, { cairo_boxes_t boxes; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (! _cairo_traps_to_boxes (&info->traps, info->antialias, &boxes)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1562,6 +1598,8 @@ clip_and_composite_traps (const cairo_traps_compositor_t *compositor, { cairo_int_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + status = trim_extents_to_traps (extents, &info->traps); if (unlikely (status != CAIRO_INT_STATUS_SUCCESS)) return status; @@ -1596,6 +1634,8 @@ clip_and_composite_tristrip (const cairo_traps_compositor_t *compositor, cairo_int_status_t status; unsigned int flags = 0; + TRACE ((stderr, "%s\n", __FUNCTION__)); + status = trim_extents_to_tristrip (extents, &info->strip); if (unlikely (status != CAIRO_INT_STATUS_SUCCESS)) return status; @@ -1630,6 +1670,8 @@ composite_mask (const cairo_traps_compositor_t *compositor, { struct composite_mask *data = closure; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (src != NULL) { compositor->composite (dst, op, src, data->mask, extents->x + src_x, extents->y + src_y, @@ -1663,6 +1705,8 @@ static void composite_box(void *closure, struct composite_box_info *info = closure; const cairo_traps_compositor_t *compositor = info->compositor; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) { cairo_surface_t *mask; cairo_color_t color; @@ -1712,6 +1756,8 @@ composite_mask_clip_boxes (const cairo_traps_compositor_t *compositor, struct composite_box_info info; int i; + TRACE ((stderr, "%s\n", __FUNCTION__)); + info.compositor = compositor; info.op = CAIRO_OPERATOR_SOURCE; info.dst = dst; @@ -1747,6 +1793,8 @@ composite_mask_clip (const cairo_traps_compositor_t *compositor, composite_traps_info_t info; cairo_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &info.antialias); if (unlikely (status)) @@ -1781,6 +1829,8 @@ _cairo_traps_compositor_paint (const cairo_compositor_t *_compositor, cairo_boxes_t boxes; cairo_int_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + status = compositor->check_composite (extents); if (unlikely (status)) return status; @@ -1799,6 +1849,8 @@ _cairo_traps_compositor_mask (const cairo_compositor_t *_compositor, const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor; cairo_int_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + status = compositor->check_composite (extents); if (unlikely (status)) return status; @@ -1820,6 +1872,8 @@ _cairo_traps_compositor_mask (const cairo_compositor_t *_compositor, &extents->mask_sample_area, &data.mask_x, &data.mask_y); + if (unlikely (data.mask->status)) + return data.mask->status; status = clip_and_composite (compositor, extents, composite_mask, @@ -1845,6 +1899,8 @@ _cairo_traps_compositor_stroke (const cairo_compositor_t *_compositor, const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor; cairo_int_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + status = compositor->check_composite (extents); if (unlikely (status)) return status; @@ -1908,6 +1964,8 @@ _cairo_traps_compositor_fill (const cairo_compositor_t *_compositor, const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor; cairo_int_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + status = compositor->check_composite (extents); if (unlikely (status)) return status; @@ -1975,6 +2033,8 @@ composite_glyphs (const cairo_traps_compositor_t *compositor, { cairo_composite_glyphs_info_t *info = closure; + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (op == CAIRO_OPERATOR_ADD && (dst->content & CAIRO_CONTENT_COLOR) == 0) info->use_mask = 0; @@ -1995,6 +2055,8 @@ _cairo_traps_compositor_glyphs (const cairo_compositor_t *_compositor, const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor; cairo_int_status_t status; + TRACE ((stderr, "%s\n", __FUNCTION__)); + status = compositor->check_composite (extents); if (unlikely (status)) return status; diff --git a/src/cairo.h b/src/cairo.h index 0a004f3d1..1c1d2d267 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -2047,6 +2047,7 @@ cairo_device_reference (cairo_device_t *device); * @CAIRO_DEVICE_TYPE_XLIB: The device is of type xlib * @CAIRO_DEVICE_TYPE_XML: The device is of type XML * @CAIRO_DEVICE_TYPE_COGL: The device is of type cogl, since 1.12 + * @CAIRO_DEVICE_TYPE_WIN32: The device is of type cogl, since 1.12 * @CAIRO_DEVICE_TYPE_INVALID: The device is invalid * * #cairo_device_type_t is used to describe the type of a given @@ -2076,6 +2077,7 @@ typedef enum _cairo_device_type { CAIRO_DEVICE_TYPE_XLIB, CAIRO_DEVICE_TYPE_XML, CAIRO_DEVICE_TYPE_COGL, + CAIRO_DEVICE_TYPE_WIN32, CAIRO_DEVICE_TYPE_INVALID = -1 } cairo_device_type_t; diff --git a/src/cairoint.h b/src/cairoint.h index d3ad9037e..6656d4b23 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1984,4 +1984,10 @@ _cairo_debug_print_traps (FILE *file, const cairo_traps_t *traps); cairo_private void _cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip); +#if 0 +#define TRACE(x) fprintf x +#else +#define TRACE(x) +#endif + #endif diff --git a/src/win32/cairo-win32-debug.c b/src/win32/cairo-win32-debug.c new file mode 100644 index 000000000..ff7aeaf1f --- /dev/null +++ b/src/win32/cairo-win32-debug.c @@ -0,0 +1,87 @@ +/* -*- 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 + * Stuart Parmenter + * Vladimir Vukicevic + */ + +#define WIN32_LEAN_AND_MEAN +/* We require Windows 2000 features such as ETO_PDY */ +#if !defined(WINVER) || (WINVER < 0x0500) +# define WINVER 0x0500 +#endif +#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500) +# define _WIN32_WINNT 0x0500 +#endif + +#include "cairoint.h" +#include "cairo-win32-private.h" + +#include +#include + +void +_cairo_win32_debug_dump_hrgn (HRGN rgn, char *header) +{ + RGNDATA *rd; + unsigned int z; + + if (header) + fprintf (stderr, "%s\n", header); + + if (rgn == NULL) { + fprintf (stderr, " NULL\n"); + } + + z = GetRegionData(rgn, 0, NULL); + rd = (RGNDATA*) malloc(z); + z = GetRegionData(rgn, z, rd); + + fprintf (stderr, " %ld rects, bounds: %ld %ld %ld %ld\n", + rd->rdh.nCount, + rd->rdh.rcBound.left, + rd->rdh.rcBound.top, + rd->rdh.rcBound.right - rd->rdh.rcBound.left, + rd->rdh.rcBound.bottom - rd->rdh.rcBound.top); + + for (z = 0; z < rd->rdh.nCount; z++) { + RECT r = ((RECT*)rd->Buffer)[z]; + fprintf (stderr, " [%d]: [%ld %ld %ld %ld]\n", + z, r.left, r.top, r.right - r.left, r.bottom - r.top); + } + + free(rd); + fflush (stderr); +} diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c new file mode 100644 index 000000000..b3ee5739a --- /dev/null +++ b/src/win32/cairo-win32-device.c @@ -0,0 +1,189 @@ +/* -*- 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 + * Stuart Parmenter + * Vladimir Vukicevic + */ + +#define WIN32_LEAN_AND_MEAN +/* We require Windows 2000 features such as ETO_PDY */ +#if !defined(WINVER) || (WINVER < 0x0500) +# define WINVER 0x0500 +#endif +#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500) +# define _WIN32_WINNT 0x0500 +#endif + +#include "cairoint.h" + +#include "cairo-atomic-private.h" +#include "cairo-device-private.h" +#include "cairo-win32-private.h" + +#include +#include + +static cairo_device_t *__cairo_win32_device; + +static cairo_status_t +_cairo_win32_device_flush (void *device) +{ + GdiFlush (); + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_win32_device_finish (void *device) +{ +} + +static void +_cairo_win32_device_destroy (void *device) +{ + free (device); +} + +static const cairo_device_backend_t _cairo_win32_device_backend = { + CAIRO_DEVICE_TYPE_WIN32, + + NULL, NULL, /* lock, unlock */ + + _cairo_win32_device_flush, + _cairo_win32_device_finish, + _cairo_win32_device_destroy, +}; + +#if 0 +D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, + D2D1::PixelFormat( + DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_IGNORE), + 0, + 0, + D2D1_RENDER_TARGET_USAGE_NONE, + D2D1_FEATURE_LEVEL_DEFAULT + ); + +hr = m_pD2DFactory->CreateDCRenderTarget(&props, &device->d2d); +#endif + +static cairo_bool_t is_win98 (void) +{ + OSVERSIONINFO os; + + os.dwOSVersionInfoSize = sizeof (os); + GetVersionEx (&os); + + return (VER_PLATFORM_WIN32_WINDOWS != os.dwPlatformId && + os.dwMajorVersion != 4 && + os.dwMinorVersion != 10); +} + +static void * +_cairo_win32_device_get_alpha_blend (cairo_win32_device_t *device) +{ + void *func = NULL; + + if (is_win98 ()) + return NULL; + + device->msimg32_dll = LoadLibraryW (L"msimg32"); + if (device->msimg32_dll) + func = GetProcAddress (device->msimg32_dll, "AlphaBlend"); + + return func; +} + +cairo_device_t * +_cairo_win32_device_get (void) +{ + cairo_win32_device_t *device; + + if (__cairo_win32_device) + return cairo_device_reference (__cairo_win32_device); + + device = malloc (sizeof (*device)); + + _cairo_device_init (&device->base, &_cairo_win32_device_backend); + + device->compositor = _cairo_win32_gdi_compositor_get (); + + device->msimg32_dll = NULL; + device->alpha_blend = _cairo_win32_device_get_alpha_blend (device); + + if (_cairo_atomic_ptr_cmpxchg ((void **)&__cairo_win32_device, NULL, device)) + return cairo_device_reference(&device->base); + + _cairo_win32_device_destroy (device); + return cairo_device_reference (__cairo_win32_device); +} + +unsigned +_cairo_win32_flags_for_dc (HDC dc) +{ + uint32_t flags = 0; + int cap; + + cap = GetDeviceCaps(dc, RASTERCAPS); + if (cap & RC_BITBLT) + flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT; + if (cap & RC_STRETCHBLT) + flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT; + if (cap & RC_STRETCHDIB) + flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB; + + 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. + */ +#if 0 + flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT; + flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND; + flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT; + flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB; +#endif + } else { + cap = GetDeviceCaps(dc, SHADEBLENDCAPS); + if (cap != SB_NONE) + flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND; + } + + return flags; +} diff --git a/src/win32/cairo-win32-display-surface.c b/src/win32/cairo-win32-display-surface.c new file mode 100644 index 000000000..1b5d47edb --- /dev/null +++ b/src/win32/cairo-win32-display-surface.c @@ -0,0 +1,1031 @@ +/* -*- 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 + * Stuart Parmenter + * Vladimir Vukicevic + */ + +#define WIN32_LEAN_AND_MEAN +/* We require Windows 2000 features such as ETO_PDY */ +#if !defined(WINVER) || (WINVER < 0x0500) +# define WINVER 0x0500 +#endif +#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500) +# define _WIN32_WINNT 0x0500 +#endif + +#include "cairoint.h" + +#include "cairo-clip-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-compositor-private.h" +#include "cairo-damage-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.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 +#include + +#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. + */ + +static const cairo_surface_backend_t cairo_win32_display_surface_backend; + +static cairo_status_t +_create_dc_and_bitmap (cairo_win32_display_surface_t *surface, + HDC original_dc, + cairo_format_t format, + int width, + int height, + unsigned char **bits_out, + int *rowstride_out) +{ + cairo_status_t status; + + BITMAPINFO *bitmap_info = NULL; + struct { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[2]; + } bmi_stack; + void *bits; + + int num_palette = 0; /* Quiet GCC */ + int i; + + surface->win32.dc = NULL; + surface->bitmap = NULL; + surface->is_dib = FALSE; + + switch (format) { + default: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB30: + return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + num_palette = 0; + break; + + case CAIRO_FORMAT_A8: + num_palette = 256; + break; + + case CAIRO_FORMAT_A1: + num_palette = 2; + break; + } + + if (num_palette > 2) { + bitmap_info = _cairo_malloc_ab_plus_c (num_palette, sizeof(RGBQUAD), sizeof(BITMAPINFOHEADER)); + if (!bitmap_info) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else { + bitmap_info = (BITMAPINFO *)&bmi_stack; + } + + bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bitmap_info->bmiHeader.biWidth = width == 0 ? 1 : width; + bitmap_info->bmiHeader.biHeight = height == 0 ? -1 : - height; /* top-down */ + bitmap_info->bmiHeader.biSizeImage = 0; + bitmap_info->bmiHeader.biXPelsPerMeter = PELS_72DPI; /* unused here */ + bitmap_info->bmiHeader.biYPelsPerMeter = PELS_72DPI; /* unused here */ + bitmap_info->bmiHeader.biPlanes = 1; + + switch (format) { + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB30: + ASSERT_NOT_REACHED; + /* We can't create real RGB24 bitmaps because something seems to + * break if we do, especially if we don't set up an image + * fallback. It could be a bug with using a 24bpp pixman image + * (and creating one with masks). So treat them like 32bpp. + * Note: This causes problems when using BitBlt/AlphaBlend/etc! + * see end of file. + */ + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_ARGB32: + bitmap_info->bmiHeader.biBitCount = 32; + bitmap_info->bmiHeader.biCompression = BI_RGB; + bitmap_info->bmiHeader.biClrUsed = 0; /* unused */ + bitmap_info->bmiHeader.biClrImportant = 0; + break; + + case CAIRO_FORMAT_A8: + bitmap_info->bmiHeader.biBitCount = 8; + bitmap_info->bmiHeader.biCompression = BI_RGB; + bitmap_info->bmiHeader.biClrUsed = 256; + bitmap_info->bmiHeader.biClrImportant = 0; + + for (i = 0; i < 256; i++) { + bitmap_info->bmiColors[i].rgbBlue = i; + bitmap_info->bmiColors[i].rgbGreen = i; + bitmap_info->bmiColors[i].rgbRed = i; + bitmap_info->bmiColors[i].rgbReserved = 0; + } + break; + + case CAIRO_FORMAT_A1: + bitmap_info->bmiHeader.biBitCount = 1; + bitmap_info->bmiHeader.biCompression = BI_RGB; + bitmap_info->bmiHeader.biClrUsed = 2; + bitmap_info->bmiHeader.biClrImportant = 0; + + for (i = 0; i < 2; i++) { + bitmap_info->bmiColors[i].rgbBlue = i * 255; + bitmap_info->bmiColors[i].rgbGreen = i * 255; + bitmap_info->bmiColors[i].rgbRed = i * 255; + bitmap_info->bmiColors[i].rgbReserved = 0; + } + break; + } + + surface->win32.dc = CreateCompatibleDC (original_dc); + if (!surface->win32.dc) + goto FAIL; + + surface->bitmap = CreateDIBSection (surface->win32.dc, + bitmap_info, + DIB_RGB_COLORS, + &bits, + NULL, 0); + if (!surface->bitmap) + goto FAIL; + + surface->is_dib = TRUE; + + GdiFlush(); + + surface->saved_dc_bitmap = SelectObject (surface->win32.dc, + surface->bitmap); + if (!surface->saved_dc_bitmap) + goto FAIL; + + if (bitmap_info && num_palette > 2) + free (bitmap_info); + + if (bits_out) + *bits_out = bits; + + if (rowstride_out) { + /* Windows bitmaps are padded to 32-bit (dword) boundaries */ + switch (format) { + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB30: + ASSERT_NOT_REACHED; + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + *rowstride_out = 4 * width; + break; + + case CAIRO_FORMAT_A8: + *rowstride_out = (width + 3) & ~3; + break; + + case CAIRO_FORMAT_A1: + *rowstride_out = ((width + 31) & ~31) / 8; + break; + } + } + + surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc); + + 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 = 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->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)); + + 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; + + 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; + + return surface->image; +} + +static cairo_status_t +_cairo_win32_display_surface_finish (void *abstract_surface) +{ + cairo_win32_display_surface_t *surface = abstract_surface; + + if (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); + } + + if (surface->initial_clip_rgn) + DeleteObject (surface->initial_clip_rgn); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_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.width, + surface->win32.extents.height); + if (unlikely (status = surface->fallback->status)) + goto err; + + if (!BitBlt (to_win32_surface(surface->fallback)->dc, + 0, 0, + surface->win32.extents.width, + surface->win32.extents.height, + surface->win32.dc, + 0, 0, + SRCCOPY)) { + status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR); + goto err; + } + } + + surface = to_win32_display_surface (surface->fallback); + if (surface->image->damage == NULL) + surface->image->damage = _cairo_damage_create (); + +done: + GdiFlush(); + return _cairo_image_surface_map_to_image (surface->image, extents); + +err: + cairo_surface_destroy (surface->fallback); + surface->fallback = NULL; + + return _cairo_surface_create_in_error (status); +} + +static cairo_int_status_t +_cairo_win32_display_surface_unmap_image (void *surface, + cairo_image_surface_t *image) +{ + /* 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)); + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_display_surface_flush (void *abstract_surface) +{ + cairo_win32_display_surface_t *surface = abstract_surface; + cairo_win32_display_surface_t *fallback; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->win32.base.unique_id)); + if (surface->fallback == NULL) + return CAIRO_STATUS_SUCCESS; + + fallback = to_win32_display_surface (surface->fallback); + assert (fallback->image); + + if (fallback->image->damage) { + cairo_damage_t *damage; + + damage = _cairo_damage_reduce (fallback->image->damage); + fallback->image->damage = NULL; + + if (damage->status) { + if (!BitBlt (surface->win32.dc, + 0, 0, + surface->win32.extents.width, + surface->win32.extents.height, + fallback->win32.dc, + 0, 0, + SRCCOPY)) + status = _cairo_win32_print_gdi_error (__FUNCTION__); + } else { + 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); + if (!BitBlt (surface->win32.dc, + rect.x, rect.y, + rect.width, rect.height, + fallback->win32.dc, + 0, 0, + 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; + + 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 = 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) +{ + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->win32.base.unique_id)); + + if (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: + * @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_dib(). + * + * Return value: the newly created surface + **/ +cairo_surface_t * +cairo_win32_surface_create (HDC hdc) +{ + cairo_win32_display_surface_t *surface; + + cairo_format_t format; + cairo_status_t status; + cairo_device_t *device; + + /* Assume that everything coming in as a HDC is RGB24 */ + format = CAIRO_FORMAT_RGB24; + + surface = 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); + + device = _cairo_win32_device_get (); + + _cairo_surface_init (&surface->win32.base, + &cairo_win32_display_surface_backend, + device, + _cairo_content_from_format (format)); + + cairo_device_destroy (device); + + return &surface->win32.base; +} + +/** + * 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; + + if (format != CAIRO_FORMAT_RGB24) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); +/* 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_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; +} diff --git a/src/win32/cairo-win32-font.c b/src/win32/cairo-win32-font.c index 73fc052d7..ed171c29e 100644 --- a/src/win32/cairo-win32-font.c +++ b/src/win32/cairo-win32-font.c @@ -236,13 +236,15 @@ _compute_transform (cairo_win32_scaled_font_t *scaled_font, if (status) return status; - scaled_font->logical_size = _cairo_lround (WIN32_FONT_LOGICAL_SCALE * - scaled_font->y_scale); - scaled_font->logical_scale = WIN32_FONT_LOGICAL_SCALE * scaled_font->y_scale; + scaled_font->logical_size = + _cairo_lround (WIN32_FONT_LOGICAL_SCALE * scaled_font->y_scale); + scaled_font->logical_scale = + WIN32_FONT_LOGICAL_SCALE * scaled_font->y_scale; } cairo_matrix_scale (&scaled_font->logical_to_device, - 1.0 / scaled_font->logical_scale, 1.0 / scaled_font->logical_scale); + 1.0 / scaled_font->logical_scale, + 1.0 / scaled_font->logical_scale); scaled_font->device_to_logical = scaled_font->logical_to_device; @@ -1049,7 +1051,6 @@ _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_f extents.y_bearing = (- extents.y_bearing - extents.height); extents.y_advance = - extents.y_advance; } - } else { /* For all other transformations, we use the design metrics * of the font. @@ -1295,6 +1296,7 @@ _draw_glyphs_on_surface (cairo_win32_surface_t *surface, return status; } +#if 0 /* Duplicate the green channel of a 4-channel mask in the alpha channel, then * invert the whole mask. */ @@ -1360,6 +1362,7 @@ _compute_a8_mask (cairo_win32_surface_t *mask_surface) return &image8->base; } +#endif static cairo_int_status_t _cairo_win32_scaled_font_glyph_init (void *abstract_font, @@ -1656,9 +1659,9 @@ _cairo_win32_scaled_font_is_synthetic (void *abstract_font) } static cairo_int_status_t -_cairo_win32_scaled_font_index_to_glyph_name (void *abstract_font, +_cairo_win32_scaled_font_index_to_glyph_name (void *abstract_font, char **glyph_names, - int num_glyph_names, + int num_glyph_names, unsigned long glyph_index, unsigned long *glyph_array_index) { @@ -1688,7 +1691,7 @@ _cairo_win32_scaled_font_index_to_glyph_name (void *abstract_font, *glyph_array_index = scaled_font->type1_notdef_index; else if (glyph_index <= scaled_font->type1_notdef_index) *glyph_array_index = glyph_index - 1; - else if (glyph_index < num_glyph_names) + else if (glyph_index < (unsigned long)num_glyph_names) *glyph_array_index = glyph_index; else return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1756,8 +1759,12 @@ _cairo_win32_scaled_font_init_glyph_surface (cairo_win32_scaled_font_t *scaled_f GdiFlush(); +#if 0 image = _compute_a8_mask (surface); status = image->status; +#else + status = CAIRO_STATUS_NO_MEMORY; +#endif if (status) goto FAIL; diff --git a/src/win32/cairo-win32-gdi-compositor.c b/src/win32/cairo-win32-gdi-compositor.c new file mode 100644 index 000000000..054d9f248 --- /dev/null +++ b/src/win32/cairo-win32-gdi-compositor.c @@ -0,0 +1,646 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * 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 University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Behdad Esfahbod + * Chris Wilson + * Karl Tomlinson , Mozilla Corporation + */ + +/* The original X drawing API was very restrictive in what it could handle, + * pixel-aligned fill/blits are all that map into Cairo's drawing model. + */ + +#include "cairoint.h" + +#include "cairo-win32-private.h" + +#include "cairo-boxes-private.h" +#include "cairo-compositor-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-pattern-private.h" +#include "cairo-region-private.h" +#include "cairo-surface-offset-private.h" + +#if !defined(AC_SRC_OVER) +#define AC_SRC_OVER 0x00 +#pragma pack(1) +typedef struct { + BYTE BlendOp; + BYTE BlendFlags; + BYTE SourceConstantAlpha; + BYTE AlphaFormat; +}BLENDFUNCTION; +#pragma pack() +#endif + +/* for compatibility with VC++ 6 */ +#ifndef AC_SRC_ALPHA +#define AC_SRC_ALPHA 0x01 +#endif + +#define PELS_72DPI ((LONG)(72. / 0.0254)) + +/* the low-level interface */ + +struct fill_box { + HDC dc; + HBRUSH brush; +}; + +static cairo_bool_t fill_box (cairo_box_t *box, void *closure) +{ + struct fill_box *fb = closure; + RECT rect; + + rect.left = _cairo_fixed_integer_part (box->p1.x); + rect.top = _cairo_fixed_integer_part (box->p1.y); + rect.right = _cairo_fixed_integer_part (box->p2.x); + rect.bottom = _cairo_fixed_integer_part (box->p2.y); + + TRACE ((stderr, "%s\n", __FUNCTION__)); + return FillRect (fb->dc, &rect, fb->brush); +} + +struct check_box { + cairo_rectangle_int_t limit; + int tx, ty; +}; + +struct copy_box { + cairo_rectangle_int_t limit; + int tx, ty; + HDC dst, src; + BLENDFUNCTION bf; + cairo_win32_alpha_blend_func_t alpha_blend; +}; + +static cairo_bool_t copy_box (cairo_box_t *box, void *closure) +{ + const struct copy_box *cb = closure; + int x = _cairo_fixed_integer_part (box->p1.x); + int y = _cairo_fixed_integer_part (box->p1.y); + int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x); + int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y); + + TRACE ((stderr, "%s\n", __FUNCTION__)); + return BitBlt (cb->dst, x, y, width, height, + cb->src, x + cb->tx, y + cb->ty, + SRCCOPY); +} + +static cairo_bool_t alpha_box (cairo_box_t *box, void *closure) +{ + const struct copy_box *cb = closure; + int x = _cairo_fixed_integer_part (box->p1.x); + int y = _cairo_fixed_integer_part (box->p1.y); + int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x); + int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y); + + TRACE ((stderr, "%s\n", __FUNCTION__)); + return cb->alpha_blend (cb->dst, x, y, width, height, + cb->src, x + cb->tx, y + cb->ty, width, height, + cb->bf); +} + +struct upload_box { + cairo_rectangle_int_t limit; + int tx, ty; + HDC dst; + BITMAPINFO bi; + void *data; +}; + +static cairo_bool_t upload_box (cairo_box_t *box, void *closure) +{ + const struct upload_box *cb = closure; + int x = _cairo_fixed_integer_part (box->p1.x); + int y = _cairo_fixed_integer_part (box->p1.y); + int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x); + int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y); + + TRACE ((stderr, "%s\n", __FUNCTION__)); + return StretchDIBits (cb->dst, x, y + height - 1, width, -height, + x + cb->tx, height - (y + cb->ty - 1), + width, -height, + cb->data, &cb->bi, + DIB_RGB_COLORS, SRCCOPY); +} + +/* the mid-level: converts boxes into drawing operations */ + +static COLORREF color_to_rgb(const cairo_color_t *c) +{ + return RGB (c->red_short >> 8, c->green_short >> 8, c->blue_short >> 8); +} + +static cairo_int_status_t +fill_boxes (cairo_win32_display_surface_t *dst, + const cairo_pattern_t *src, + cairo_boxes_t *boxes) +{ + const cairo_color_t *color = &((cairo_solid_pattern_t *) src)->color; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + struct fill_box fb; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + fb.dc = dst->win32.dc; + fb.brush = CreateSolidBrush (color_to_rgb(color)); + if (!fb.brush) + return _cairo_win32_print_gdi_error (__FUNCTION__); + + if (! _cairo_boxes_for_each_box (boxes, fill_box, &fb)) + status = CAIRO_INT_STATUS_UNSUPPORTED; + + DeleteObject (fb.brush); + + return status; +} + +static cairo_bool_t source_contains_box (cairo_box_t *box, void *closure) +{ + struct check_box *data = closure; + + /* The box is pixel-aligned so the truncation is safe. */ + return + _cairo_fixed_integer_part (box->p1.x) + data->tx >= data->limit.x && + _cairo_fixed_integer_part (box->p1.y) + data->ty >= data->limit.y && + _cairo_fixed_integer_part (box->p2.x) + data->tx <= data->limit.x + data->limit.width && + _cairo_fixed_integer_part (box->p2.y) + data->ty <= data->limit.y + data->limit.height; +} + +static cairo_status_t +copy_boxes (cairo_win32_display_surface_t *dst, + const cairo_pattern_t *source, + cairo_boxes_t *boxes) +{ + const cairo_surface_pattern_t *pattern; + struct copy_box cb; + cairo_surface_t *surface; + cairo_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + pattern = (const cairo_surface_pattern_t *) source; + surface = _cairo_surface_get_source (pattern->surface, &cb.limit); + if (surface->type == CAIRO_SURFACE_TYPE_IMAGE) { + surface = to_image_surface(surface)->parent; + if (surface == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + } + if (surface->type != CAIRO_SURFACE_TYPE_WIN32) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_matrix_is_integer_translation (&source->matrix, + &cb.tx, &cb.ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cb.dst = dst->win32.dc; + cb.src = to_win32_surface(surface)->dc; + + /* First check that the data is entirely within the image */ + if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_surface_flush (surface); + if (status) + return status; + + cb.tx += cb.limit.x; + cb.ty += cb.limit.y; + status = CAIRO_STATUS_SUCCESS; + if (! _cairo_boxes_for_each_box (boxes, copy_box, &cb)) + status = CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_win32_display_surface_discard_fallback (dst); + return status; +} + +static cairo_status_t +upload_boxes (cairo_win32_display_surface_t *dst, + const cairo_pattern_t *source, + cairo_boxes_t *boxes) +{ + const cairo_surface_pattern_t *pattern; + struct upload_box cb; + cairo_surface_t *surface; + cairo_image_surface_t *image; + void *image_extra; + cairo_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if ((dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB) == 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_matrix_is_integer_translation (&source->matrix, + &cb.tx, &cb.ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + pattern = (const cairo_surface_pattern_t *) source; + surface = _cairo_surface_get_source (pattern->surface, &cb.limit); + + /* First check that the data is entirely within the image */ + if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (surface->type != CAIRO_SURFACE_TYPE_IMAGE) { + status = _cairo_surface_acquire_source_image (surface, + &image, &image_extra); + if (status) + return status; + } else + image = to_image_surface(surface); + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (!(image->format == CAIRO_FORMAT_ARGB32 || + image->format == CAIRO_FORMAT_RGB24)) + goto err; + if (image->stride != 4*image->width) + goto err; + + cb.dst = dst->win32.dc; + cb.data = image->data; + + cb.bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + cb.bi.bmiHeader.biWidth = image->width; + cb.bi.bmiHeader.biHeight = -image->height; + cb.bi.bmiHeader.biSizeImage = 0; + cb.bi.bmiHeader.biXPelsPerMeter = PELS_72DPI; + cb.bi.bmiHeader.biYPelsPerMeter = PELS_72DPI; + cb.bi.bmiHeader.biPlanes = 1; + cb.bi.bmiHeader.biBitCount = 32; + cb.bi.bmiHeader.biCompression = BI_RGB; + cb.bi.bmiHeader.biClrUsed = 0; + cb.bi.bmiHeader.biClrImportant = 0; + + cb.tx += cb.limit.x; + cb.ty += cb.limit.y; + status = CAIRO_STATUS_SUCCESS; + if (! _cairo_boxes_for_each_box (boxes, upload_box, &cb)) + status = CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_win32_display_surface_discard_fallback (dst); +err: + if (&image->base != surface) + _cairo_surface_release_source_image (surface, image, image_extra); + + return status; +} + +static cairo_status_t +alpha_blend_boxes (cairo_win32_display_surface_t *dst, + const cairo_pattern_t *source, + cairo_boxes_t *boxes, + uint8_t alpha) +{ + const cairo_surface_pattern_t *pattern; + struct copy_box cb; + cairo_surface_t *surface; + cairo_win32_display_surface_t *src; + cairo_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (source->type != CAIRO_PATTERN_TYPE_SURFACE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + pattern = (const cairo_surface_pattern_t *) source; + surface = _cairo_surface_get_source (pattern->surface, &cb.limit); + if (surface->type == CAIRO_SURFACE_TYPE_IMAGE) { + surface = to_image_surface(surface)->parent; + if (surface == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + } + if (pattern->surface->type != CAIRO_SURFACE_TYPE_WIN32) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_matrix_is_integer_translation (&source->matrix, + &cb.tx, &cb.ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + src = to_win32_display_surface (surface); + cb.dst = dst->win32.dc; + cb.src = src->win32.dc; + + /* First check that the data is entirely within the image */ + if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_surface_flush (&src->win32.base); + if (status) + return status; + + cb.bf.BlendOp = AC_SRC_OVER; + cb.bf.BlendFlags = 0; + cb.bf.SourceConstantAlpha = alpha; + cb.bf.AlphaFormat = (src->win32.format == CAIRO_FORMAT_ARGB32) ? AC_SRC_ALPHA : 0; + cb.alpha_blend = to_win32_device(dst->win32.base.device)->alpha_blend; + + cb.tx += cb.limit.x; + cb.ty += cb.limit.y; + status = CAIRO_STATUS_SUCCESS; + if (! _cairo_boxes_for_each_box (boxes, alpha_box, &cb)) + status = CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_win32_display_surface_discard_fallback (dst); + return status; +} + +static cairo_bool_t +can_alpha_blend (cairo_win32_display_surface_t *dst) +{ + if ((dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_ALPHABLEND) == 0) + return FALSE; + + return to_win32_device(dst->win32.base.device)->alpha_blend != NULL; +} + +static cairo_status_t +draw_boxes (cairo_composite_rectangles_t *composite, + cairo_boxes_t *boxes) +{ + cairo_win32_display_surface_t *dst = to_win32_display_surface(composite->surface); + cairo_operator_t op = composite->op; + const cairo_pattern_t *src = &composite->source_pattern.base; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (boxes->num_boxes == 0 && composite->is_bounded) + return CAIRO_STATUS_SUCCESS; + + if (!boxes->is_pixel_aligned) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (op == CAIRO_OPERATOR_CLEAR) + op = CAIRO_OPERATOR_SOURCE; + + if (op == CAIRO_OPERATOR_OVER && + _cairo_pattern_is_opaque (src, &composite->bounded)) + op = CAIRO_OPERATOR_SOURCE; + + if (dst->win32.base.is_clear && op == CAIRO_OPERATOR_OVER) + op = CAIRO_OPERATOR_SOURCE; + + if (op == CAIRO_OPERATOR_SOURCE) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (src->type == CAIRO_PATTERN_TYPE_SURFACE) { + status = copy_boxes (dst, src, boxes); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + status = upload_boxes (dst, src, boxes); + } else if (src->type == CAIRO_PATTERN_TYPE_SOLID) { + status = fill_boxes (dst, src, boxes); + } + return status; + } + + if (op == CAIRO_OPERATOR_OVER && can_alpha_blend (dst)) + return alpha_blend_boxes (dst, src, boxes, 255); + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +opacity_boxes (cairo_composite_rectangles_t *composite, + cairo_boxes_t *boxes) +{ + cairo_win32_display_surface_t *dst = to_win32_display_surface(composite->surface); + cairo_operator_t op = composite->op; + const cairo_pattern_t *src = &composite->source_pattern.base; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (composite->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (boxes->num_boxes == 0 && composite->is_bounded) + return CAIRO_STATUS_SUCCESS; + + if (!boxes->is_pixel_aligned) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (op != CAIRO_OPERATOR_OVER) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (!can_alpha_blend (dst)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return alpha_blend_boxes (dst, src, boxes, + composite->mask_pattern.solid.color.alpha_short >> 8); +} + +/* high-level compositor interface */ + +static cairo_bool_t check_blit (cairo_composite_rectangles_t *composite) +{ + cairo_win32_display_surface_t *dst; + + if (composite->clip->path) + return FALSE; + + dst = to_win32_display_surface (composite->surface); + if (dst->fallback) + return FALSE; + + if (dst->win32.format != CAIRO_FORMAT_RGB24) + return FALSE; + + if (dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_BITBLT) + return TRUE; + + return dst->image == NULL; +} + +static cairo_int_status_t +_cairo_win32_gdi_compositor_paint (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *composite) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + + if (check_blit (composite)) { + cairo_boxes_t boxes; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + _cairo_clip_steal_boxes (composite->clip, &boxes); + status = draw_boxes (composite, &boxes); + _cairo_clip_unsteal_boxes (composite->clip, &boxes); + } + + return status; +} + +static cairo_int_status_t +_cairo_win32_gdi_compositor_mask (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *composite) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + + if (check_blit (composite)) { + cairo_boxes_t boxes; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + _cairo_clip_steal_boxes (composite->clip, &boxes); + status = opacity_boxes (composite, &boxes); + _cairo_clip_unsteal_boxes (composite->clip, &boxes); + } + + return status; +} + +static cairo_int_status_t +_cairo_win32_gdi_compositor_stroke (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *composite, + 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) +{ + cairo_int_status_t status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (check_blit (composite) && + _cairo_path_fixed_stroke_is_rectilinear (path)) { + cairo_boxes_t boxes; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + _cairo_boxes_init_with_clip (&boxes, composite->clip); + status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, + style, + ctm, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = draw_boxes (composite, &boxes); + _cairo_boxes_fini (&boxes); + } + + return status; +} + +static cairo_int_status_t +_cairo_win32_gdi_compositor_fill (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *composite, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_int_status_t status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (check_blit (composite) && + _cairo_path_fixed_fill_is_rectilinear (path)) { + cairo_boxes_t boxes; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + _cairo_boxes_init_with_clip (&boxes, composite->clip); + status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, + fill_rule, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = draw_boxes (composite, &boxes); + _cairo_boxes_fini (&boxes); + } + + return status; +} + +static cairo_bool_t check_glyphs (cairo_composite_rectangles_t *composite, + cairo_scaled_font_t *scaled_font) +{ + if (! _cairo_clip_is_region (composite->clip)) + return FALSE; + + if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_WIN32) + return FALSE; + + if (! _cairo_pattern_is_opaque_solid (&composite->source_pattern.base)) + return FALSE; + + return (composite->op == CAIRO_OPERATOR_CLEAR || + composite->op == CAIRO_OPERATOR_SOURCE || + composite->op == CAIRO_OPERATOR_OVER); +} + +static cairo_int_status_t +_cairo_win32_gdi_compositor_glyphs (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t*composite, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_bool_t overlap) +{ + cairo_int_status_t status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (check_blit (composite) && check_glyphs (composite, scaled_font)) { + cairo_win32_display_surface_t *dst = to_win32_display_surface (composite->surface); + + TRACE ((stderr, "%s\n", __FUNCTION__)); + status = _cairo_win32_display_surface_set_clip(dst, composite->clip); + if (status) + return status; + + status = _cairo_win32_surface_emit_glyphs (&dst->win32, + &composite->source_pattern.base, + glyphs, + num_glyphs, + scaled_font, + TRUE); + + _cairo_win32_display_surface_unset_clip (dst); + } + + return status; +} + +const cairo_compositor_t * +_cairo_win32_gdi_compositor_get (void) +{ + static cairo_compositor_t compositor; + + if (compositor.delegate == NULL) { + compositor.delegate = &_cairo_fallback_compositor; + + compositor.paint = _cairo_win32_gdi_compositor_paint; + compositor.mask = _cairo_win32_gdi_compositor_mask; + compositor.fill = _cairo_win32_gdi_compositor_fill; + compositor.stroke = _cairo_win32_gdi_compositor_stroke; + compositor.glyphs = _cairo_win32_gdi_compositor_glyphs; + } + + return &compositor; +} diff --git a/src/win32/cairo-win32-printing-surface.c b/src/win32/cairo-win32-printing-surface.c index 17a68f787..881a42ffe 100644 --- a/src/win32/cairo-win32-printing-surface.c +++ b/src/win32/cairo-win32-printing-surface.c @@ -102,36 +102,36 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend; static const cairo_paginated_surface_backend_t cairo_win32_surface_paginated_backend; static void -_cairo_win32_printing_surface_init_ps_mode (cairo_win32_surface_t *surface) +_cairo_win32_printing_surface_init_ps_mode (cairo_win32_printing_surface_t *surface) { DWORD word; INT ps_feature, ps_level; word = PSIDENT_GDICENTRIC; - if (ExtEscape (surface->dc, POSTSCRIPT_IDENTIFY, sizeof(DWORD), (char *)&word, 0, (char *)NULL) <= 0) + if (ExtEscape (surface->win32.dc, POSTSCRIPT_IDENTIFY, sizeof(DWORD), (char *)&word, 0, (char *)NULL) <= 0) return; ps_feature = FEATURESETTING_PSLEVEL; - if (ExtEscape (surface->dc, GET_PS_FEATURESETTING, sizeof(INT), + if (ExtEscape (surface->win32.dc, GET_PS_FEATURESETTING, sizeof(INT), (char *)&ps_feature, sizeof(INT), (char *)&ps_level) <= 0) return; if (ps_level >= 3) - surface->flags |= CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT; + surface->win32.flags |= CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT; } static void -_cairo_win32_printing_surface_init_image_support (cairo_win32_surface_t *surface) +_cairo_win32_printing_surface_init_image_support (cairo_win32_printing_surface_t *surface) { DWORD word; word = CHECKJPEGFORMAT; - if (ExtEscape(surface->dc, QUERYESCSUPPORT, sizeof(word), (char *)&word, 0, (char *)NULL) > 0) - surface->flags |= CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG; + if (ExtEscape(surface->win32.dc, QUERYESCSUPPORT, sizeof(word), (char *)&word, 0, (char *)NULL) > 0) + surface->win32.flags |= CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG; word = CHECKPNGFORMAT; - if (ExtEscape(surface->dc, QUERYESCSUPPORT, sizeof(word), (char *)&word, 0, (char *)NULL) > 0) - surface->flags |= CAIRO_WIN32_SURFACE_CAN_CHECK_PNG; + if (ExtEscape(surface->win32.dc, QUERYESCSUPPORT, sizeof(word), (char *)&word, 0, (char *)NULL) > 0) + surface->win32.flags |= CAIRO_WIN32_SURFACE_CAN_CHECK_PNG; } /* When creating an EMF file, ExtTextOut with ETO_GLYPH_INDEX does not @@ -152,7 +152,7 @@ _cairo_win32_printing_surface_init_image_support (cairo_win32_surface_t *surface * and argument 0. */ static void -_cairo_win32_printing_surface_init_language_pack (cairo_win32_surface_t *surface) +_cairo_win32_printing_surface_init_language_pack (cairo_win32_printing_surface_t *surface) { typedef BOOL (WINAPI *gdi_init_lang_pack_func_t)(int); gdi_init_lang_pack_func_t gdi_init_lang_pack; @@ -219,7 +219,7 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern) } static cairo_bool_t -pattern_supported (cairo_win32_surface_t *surface, const cairo_pattern_t *pattern) +pattern_supported (cairo_win32_printing_surface_t *surface, const cairo_pattern_t *pattern) { if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) return TRUE; @@ -228,13 +228,13 @@ pattern_supported (cairo_win32_surface_t *surface, const cairo_pattern_t *patter return surface_pattern_supported ((const cairo_surface_pattern_t *) pattern); if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) - return surface->flags & CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT; + return surface->win32.flags & CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT; return FALSE; } static cairo_int_status_t -_cairo_win32_printing_surface_analyze_operation (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_analyze_operation (cairo_win32_printing_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *pattern) { @@ -280,7 +280,7 @@ _cairo_win32_printing_surface_analyze_operation (cairo_win32_surface_t *surface, } static cairo_bool_t -_cairo_win32_printing_surface_operation_supported (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_operation_supported (cairo_win32_printing_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *pattern) { @@ -291,7 +291,7 @@ _cairo_win32_printing_surface_operation_supported (cairo_win32_surface_t *surfac } static void -_cairo_win32_printing_surface_init_clear_color (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_init_clear_color (cairo_win32_printing_surface_t *surface, cairo_solid_pattern_t *color) { if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) @@ -301,7 +301,7 @@ _cairo_win32_printing_surface_init_clear_color (cairo_win32_surface_t *surface, } static COLORREF -_cairo_win32_printing_surface_flatten_transparency (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_flatten_transparency (cairo_win32_printing_surface_t *surface, const cairo_color_t *color) { COLORREF c; @@ -332,7 +332,7 @@ _cairo_win32_printing_surface_flatten_transparency (cairo_win32_surface_t *surfa } static cairo_status_t -_cairo_win32_printing_surface_select_solid_brush (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_select_solid_brush (cairo_win32_printing_surface_t *surface, const cairo_pattern_t *source) { cairo_solid_pattern_t *pattern = (cairo_solid_pattern_t *) source; @@ -343,59 +343,59 @@ _cairo_win32_printing_surface_select_solid_brush (cairo_win32_surface_t *surface surface->brush = CreateSolidBrush (color); if (!surface->brush) return _cairo_win32_print_gdi_error ("_cairo_win32_surface_select_solid_brush(CreateSolidBrush)"); - surface->old_brush = SelectObject (surface->dc, surface->brush); + surface->old_brush = SelectObject (surface->win32.dc, surface->brush); return CAIRO_STATUS_SUCCESS; } static void -_cairo_win32_printing_surface_done_solid_brush (cairo_win32_surface_t *surface) +_cairo_win32_printing_surface_done_solid_brush (cairo_win32_printing_surface_t *surface) { if (surface->old_brush) { - SelectObject (surface->dc, surface->old_brush); + SelectObject (surface->win32.dc, surface->old_brush); DeleteObject (surface->brush); surface->old_brush = NULL; } } static cairo_status_t -_cairo_win32_printing_surface_get_ctm_clip_box (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_get_ctm_clip_box (cairo_win32_printing_surface_t *surface, RECT *clip) { XFORM xform; _cairo_matrix_to_win32_xform (&surface->ctm, &xform); - if (!ModifyWorldTransform (surface->dc, &xform, MWT_LEFTMULTIPLY)) + if (!ModifyWorldTransform (surface->win32.dc, &xform, MWT_LEFTMULTIPLY)) return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:ModifyWorldTransform"); - GetClipBox (surface->dc, clip); + GetClipBox (surface->win32.dc, clip); _cairo_matrix_to_win32_xform (&surface->gdi_ctm, &xform); - if (!SetWorldTransform (surface->dc, &xform)) + if (!SetWorldTransform (surface->win32.dc, &xform)) return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:SetWorldTransform"); return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_win32_printing_surface_paint_solid_pattern (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_paint_solid_pattern (cairo_win32_printing_surface_t *surface, const cairo_pattern_t *pattern) { RECT clip; cairo_status_t status; - GetClipBox (surface->dc, &clip); + GetClipBox (surface->win32.dc, &clip); status = _cairo_win32_printing_surface_select_solid_brush (surface, pattern); if (status) return status; - FillRect (surface->dc, &clip, surface->brush); + FillRect (surface->win32.dc, &clip, surface->brush); _cairo_win32_printing_surface_done_solid_brush (surface); return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_printing_surface_t *surface, cairo_surface_pattern_t *pattern) { cairo_content_t old_content; @@ -422,7 +422,7 @@ _cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_surface_t * old_has_ctm = surface->has_ctm; cairo_matrix_multiply (&p2d, &p2d, &surface->ctm); surface->ctm = p2d; - SaveDC (surface->dc); + SaveDC (surface->win32.dc); _cairo_matrix_to_win32_xform (&p2d, &xform); status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL); @@ -461,7 +461,7 @@ _cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_surface_t * cairo_matrix_t m; double x, y; - SaveDC (surface->dc); + SaveDC (surface->win32.dc); m = p2d; cairo_matrix_translate (&m, x_tile*recording_extents.width, @@ -480,39 +480,39 @@ _cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_surface_t * surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm); /* Set clip path around bbox of the pattern. */ - BeginPath (surface->dc); + BeginPath (surface->win32.dc); x = 0; y = 0; cairo_matrix_transform_point (&surface->ctm, &x, &y); - MoveToEx (surface->dc, (int) x, (int) y, NULL); + MoveToEx (surface->win32.dc, (int) x, (int) y, NULL); x = recording_extents.width; y = 0; cairo_matrix_transform_point (&surface->ctm, &x, &y); - LineTo (surface->dc, (int) x, (int) y); + LineTo (surface->win32.dc, (int) x, (int) y); x = recording_extents.width; y = recording_extents.height; cairo_matrix_transform_point (&surface->ctm, &x, &y); - LineTo (surface->dc, (int) x, (int) y); + LineTo (surface->win32.dc, (int) x, (int) y); x = 0; y = recording_extents.height; cairo_matrix_transform_point (&surface->ctm, &x, &y); - LineTo (surface->dc, (int) x, (int) y); + LineTo (surface->win32.dc, (int) x, (int) y); - CloseFigure (surface->dc); - EndPath (surface->dc); - SelectClipPath (surface->dc, RGN_AND); + CloseFigure (surface->win32.dc); + EndPath (surface->win32.dc); + SelectClipPath (surface->win32.dc, RGN_AND); - SaveDC (surface->dc); /* Allow clip path to be reset during replay */ + SaveDC (surface->win32.dc); /* Allow clip path to be reset during replay */ status = _cairo_recording_surface_replay_region (&recording_surface->base, NULL, - &surface->base, + &surface->win32.base, CAIRO_RECORDING_REGION_NATIVE); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); /* Restore both the clip save and our earlier path SaveDC */ - RestoreDC (surface->dc, -2); + RestoreDC (surface->win32.dc, -2); if (status) return status; @@ -522,13 +522,13 @@ _cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_surface_t * surface->content = old_content; surface->ctm = old_ctm; surface->has_ctm = old_has_ctm; - RestoreDC (surface->dc, -1); + RestoreDC (surface->win32.dc, -1); return status; } static cairo_int_status_t -_cairo_win32_printing_surface_check_jpeg (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_check_jpeg (cairo_win32_printing_surface_t *surface, cairo_surface_t *source, const unsigned char **data, unsigned long *length, @@ -539,7 +539,7 @@ _cairo_win32_printing_surface_check_jpeg (cairo_win32_surface_t *surface, cairo_int_status_t status; DWORD result; - if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG)) + if (!(surface->win32.flags & CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG)) return CAIRO_INT_STATUS_UNSUPPORTED; cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG, @@ -552,7 +552,7 @@ _cairo_win32_printing_surface_check_jpeg (cairo_win32_surface_t *surface, return status; result = 0; - if (ExtEscape(surface->dc, CHECKJPEGFORMAT, mime_data_length, (char *) mime_data, + if (ExtEscape(surface->win32.dc, CHECKJPEGFORMAT, mime_data_length, (char *) mime_data, sizeof(result), (char *) &result) <= 0) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -566,7 +566,7 @@ _cairo_win32_printing_surface_check_jpeg (cairo_win32_surface_t *surface, } static cairo_int_status_t -_cairo_win32_printing_surface_check_png (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_check_png (cairo_win32_printing_surface_t *surface, cairo_surface_t *source, const unsigned char **data, unsigned long *length, @@ -578,7 +578,7 @@ _cairo_win32_printing_surface_check_png (cairo_win32_surface_t *surface, cairo_int_status_t status; DWORD result; - if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_CHECK_PNG)) + if (!(surface->win32.flags & CAIRO_WIN32_SURFACE_CAN_CHECK_PNG)) return CAIRO_INT_STATUS_UNSUPPORTED; cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_PNG, @@ -591,7 +591,7 @@ _cairo_win32_printing_surface_check_png (cairo_win32_surface_t *surface, return status; result = 0; - if (ExtEscape(surface->dc, CHECKPNGFORMAT, mime_data_length, (char *) mime_data, + if (ExtEscape(surface->win32.dc, CHECKPNGFORMAT, mime_data_length, (char *) mime_data, sizeof(result), (char *) &result) <= 0) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -605,7 +605,7 @@ _cairo_win32_printing_surface_check_png (cairo_win32_surface_t *surface, } static cairo_status_t -_cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_t *surface, cairo_surface_pattern_t *pattern) { cairo_status_t status; @@ -629,7 +629,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf /* If we can't use StretchDIBits with this surface, we can't do anything * here. */ - if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB)) + if (!(surface->win32.flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB)) return CAIRO_INT_STATUS_UNSUPPORTED; if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) @@ -727,17 +727,17 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf assert (status == CAIRO_STATUS_SUCCESS); cairo_matrix_multiply (&m, &m, &surface->gdi_ctm); - SaveDC (surface->dc); + SaveDC (surface->win32.dc); _cairo_matrix_to_win32_xform (&m, &xform); - if (! SetWorldTransform (surface->dc, &xform)) { + if (! SetWorldTransform (surface->win32.dc, &xform)) { status = _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint_image_pattern"); goto CLEANUP_OPAQUE_IMAGE; } - oldmode = SetStretchBltMode(surface->dc, HALFTONE); + oldmode = SetStretchBltMode(surface->win32.dc, HALFTONE); - GetClipBox (surface->dc, &clip); + GetClipBox (surface->win32.dc, &clip); if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) { left = floor ( clip.left / (double) opaque_image->width); right = ceil (clip.right / (double) opaque_image->width); @@ -752,7 +752,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf for (y_tile = top; y_tile < bottom; y_tile++) { for (x_tile = left; x_tile < right; x_tile++) { - if (!StretchDIBits (surface->dc, + if (!StretchDIBits (surface->win32.dc, x_tile*opaque_image->width, y_tile*opaque_image->height, opaque_image->width, @@ -771,8 +771,8 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf } } } - SetStretchBltMode(surface->dc, oldmode); - RestoreDC (surface->dc, -1); + SetStretchBltMode(surface->win32.dc, oldmode); + RestoreDC (surface->win32.dc, -1); CLEANUP_OPAQUE_IMAGE: if (opaque_image != image) @@ -784,7 +784,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf } static cairo_status_t -_cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_printing_surface_t *surface, cairo_surface_pattern_t *pattern) { if (_cairo_surface_is_recording (pattern->surface)) { @@ -809,7 +809,7 @@ vertex_set_color (TRIVERTEX *vert, cairo_color_stop_t *color) } static cairo_int_status_t -_cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_printing_surface_t *surface, cairo_linear_pattern_t *pattern) { TRIVERTEX *vert; @@ -825,7 +825,7 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surfa cairo_status_t status; extend = cairo_pattern_get_extend (&pattern->base.base); - SaveDC (surface->dc); + SaveDC (surface->win32.dc); mat = pattern->base.base.matrix; status = cairo_matrix_invert (&mat); @@ -853,10 +853,10 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surfa _cairo_matrix_to_win32_xform (&mat, &xform); - if (!SetWorldTransform (surface->dc, &xform)) + if (!SetWorldTransform (surface->win32.dc, &xform)) return _cairo_win32_print_gdi_error ("_win32_printing_surface_paint_linear_pattern:SetWorldTransform2"); - GetClipBox (surface->dc, &clip); + GetClipBox (surface->win32.dc, &clip); if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) { range_start = floor (clip.left / d); @@ -939,7 +939,7 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surfa total_rects += 2; } - if (!GradientFill (surface->dc, + if (!GradientFill (surface->win32.dc, vert, total_verts, rect, total_rects, GRADIENT_FILL_RECT_H)) @@ -947,13 +947,13 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surfa free (rect); free (vert); - RestoreDC (surface->dc, -1); + RestoreDC (surface->win32.dc, -1); return 0; } static cairo_int_status_t -_cairo_win32_printing_surface_paint_pattern (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_paint_pattern (cairo_win32_printing_surface_t *surface, const cairo_pattern_t *pattern) { cairo_status_t status; @@ -990,7 +990,7 @@ _cairo_win32_printing_surface_paint_pattern (cairo_win32_surface_t *surface, } typedef struct _win32_print_path_info { - cairo_win32_surface_t *surface; + cairo_win32_printing_surface_t *surface; } win32_path_info_t; static cairo_status_t @@ -1005,9 +1005,9 @@ _cairo_win32_printing_surface_path_move_to (void *closure, x = _cairo_fixed_to_double (point->x); y = _cairo_fixed_to_double (point->y); cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y); - MoveToEx (path_info->surface->dc, (int) x, (int) y, NULL); + MoveToEx (path_info->surface->win32.dc, (int) x, (int) y, NULL); } else { - MoveToEx (path_info->surface->dc, + MoveToEx (path_info->surface->win32.dc, _cairo_fixed_integer_part (point->x), _cairo_fixed_integer_part (point->y), NULL); @@ -1029,9 +1029,9 @@ _cairo_win32_printing_surface_path_line_to (void *closure, x = _cairo_fixed_to_double (point->x); y = _cairo_fixed_to_double (point->y); cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y); - LineTo (path_info->surface->dc, (int) x, (int) y); + LineTo (path_info->surface->win32.dc, (int) x, (int) y); } else { - LineTo (path_info->surface->dc, + LineTo (path_info->surface->win32.dc, _cairo_fixed_integer_part (point->x), _cairo_fixed_integer_part (point->y)); } @@ -1077,7 +1077,7 @@ _cairo_win32_printing_surface_path_curve_to (void *closure, points[2].x = _cairo_fixed_integer_part (d->x); points[2].y = _cairo_fixed_integer_part (d->y); } - PolyBezierTo (path_info->surface->dc, points, 3); + PolyBezierTo (path_info->surface->win32.dc, points, 3); return CAIRO_STATUS_SUCCESS; } @@ -1087,13 +1087,13 @@ _cairo_win32_printing_surface_path_close_path (void *closure) { win32_path_info_t *path_info = closure; - CloseFigure (path_info->surface->dc); + CloseFigure (path_info->surface->win32.dc); return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_win32_printing_surface_emit_path (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_emit_path (cairo_win32_printing_surface_t *surface, const cairo_path_fixed_t *path) { win32_path_info_t path_info; @@ -1110,10 +1110,10 @@ _cairo_win32_printing_surface_emit_path (cairo_win32_surface_t *surface, static cairo_int_status_t _cairo_win32_printing_surface_show_page (void *abstract_surface) { - cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_printing_surface_t *surface = abstract_surface; /* Undo both SaveDC's that we did in start_page */ - RestoreDC (surface->dc, -2); + RestoreDC (surface->win32.dc, -2); return CAIRO_STATUS_SUCCESS; } @@ -1125,8 +1125,8 @@ _cairo_win32_printing_surface_clipper_intersect_clip_path (cairo_surface_clipper double tolerance, cairo_antialias_t antialias) { - cairo_win32_surface_t *surface = cairo_container_of (clipper, - cairo_win32_surface_t, + cairo_win32_printing_surface_t *surface = cairo_container_of (clipper, + cairo_win32_printing_surface_t, clipper); cairo_status_t status; @@ -1134,28 +1134,28 @@ _cairo_win32_printing_surface_clipper_intersect_clip_path (cairo_surface_clipper return CAIRO_STATUS_SUCCESS; if (path == NULL) { - RestoreDC (surface->dc, -1); - SaveDC (surface->dc); + RestoreDC (surface->win32.dc, -1); + SaveDC (surface->win32.dc); return CAIRO_STATUS_SUCCESS; } - BeginPath (surface->dc); + BeginPath (surface->win32.dc); status = _cairo_win32_printing_surface_emit_path (surface, path); - EndPath (surface->dc); + EndPath (surface->win32.dc); switch (fill_rule) { case CAIRO_FILL_RULE_WINDING: - SetPolyFillMode (surface->dc, WINDING); + SetPolyFillMode (surface->win32.dc, WINDING); break; case CAIRO_FILL_RULE_EVEN_ODD: - SetPolyFillMode (surface->dc, ALTERNATE); + SetPolyFillMode (surface->win32.dc, ALTERNATE); break; default: ASSERT_NOT_REACHED; } - SelectClipPath (surface->dc, RGN_AND); + SelectClipPath (surface->win32.dc, RGN_AND); return status; } @@ -1178,7 +1178,7 @@ _cairo_win32_printing_surface_paint (void *abstract_surface, const cairo_pattern_t *source, const cairo_clip_t *clip) { - cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_printing_surface_t *surface = abstract_surface; cairo_solid_pattern_t clear; cairo_status_t status; @@ -1261,7 +1261,7 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface, cairo_antialias_t antialias, const cairo_clip_t *clip) { - cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_printing_surface_t *surface = abstract_surface; cairo_int_status_t status; HPEN pen; LOGBRUSH brush; @@ -1311,7 +1311,7 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface, pen_style |= PS_SOLID; } - SetMiterLimit (surface->dc, (FLOAT) (style->miter_limit), NULL); + SetMiterLimit (surface->win32.dc, (FLOAT) (style->miter_limit), NULL); if (source->type == CAIRO_PATTERN_TYPE_SOLID) { cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source; @@ -1334,43 +1334,43 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface, dash_array); if (pen == NULL) return _cairo_win32_print_gdi_error ("_win32_surface_stroke:ExtCreatePen"); - obj = SelectObject (surface->dc, pen); + obj = SelectObject (surface->win32.dc, pen); if (obj == NULL) return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectObject"); - BeginPath (surface->dc); + BeginPath (surface->win32.dc); status = _cairo_win32_printing_surface_emit_path (surface, path); - EndPath (surface->dc); + EndPath (surface->win32.dc); if (status) return status; /* * Switch to user space to set line parameters */ - SaveDC (surface->dc); + SaveDC (surface->win32.dc); _cairo_matrix_to_win32_xform (&mat, &xform); xform.eDx = 0.0f; xform.eDy = 0.0f; - if (!ModifyWorldTransform (surface->dc, &xform, MWT_LEFTMULTIPLY)) + if (!ModifyWorldTransform (surface->win32.dc, &xform, MWT_LEFTMULTIPLY)) return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SetWorldTransform"); if (source->type == CAIRO_PATTERN_TYPE_SOLID) { - StrokePath (surface->dc); + StrokePath (surface->win32.dc); } else { - if (!WidenPath (surface->dc)) + if (!WidenPath (surface->win32.dc)) return _cairo_win32_print_gdi_error ("_win32_surface_stroke:WidenPath"); - if (!SelectClipPath (surface->dc, RGN_AND)) + if (!SelectClipPath (surface->win32.dc, RGN_AND)) return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectClipPath"); /* Return to device space to paint the pattern */ _cairo_matrix_to_win32_xform (&surface->gdi_ctm, &xform); - if (!SetWorldTransform (surface->dc, &xform)) + if (!SetWorldTransform (surface->win32.dc, &xform)) return _cairo_win32_print_gdi_error ("_win32_surface_stroke:ModifyWorldTransform"); status = _cairo_win32_printing_surface_paint_pattern (surface, source); } - RestoreDC (surface->dc, -1); + RestoreDC (surface->win32.dc, -1); DeleteObject (pen); free (dash_array); @@ -1387,7 +1387,7 @@ _cairo_win32_printing_surface_fill (void *abstract_surface, cairo_antialias_t antialias, const cairo_clip_t *clip) { - cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_printing_surface_t *surface = abstract_surface; cairo_int_status_t status; cairo_solid_pattern_t clear; @@ -1407,16 +1407,16 @@ _cairo_win32_printing_surface_fill (void *abstract_surface, assert (_cairo_win32_printing_surface_operation_supported (surface, op, source)); surface->path_empty = TRUE; - BeginPath (surface->dc); + BeginPath (surface->win32.dc); status = _cairo_win32_printing_surface_emit_path (surface, path); - EndPath (surface->dc); + EndPath (surface->win32.dc); switch (fill_rule) { case CAIRO_FILL_RULE_WINDING: - SetPolyFillMode (surface->dc, WINDING); + SetPolyFillMode (surface->win32.dc, WINDING); break; case CAIRO_FILL_RULE_EVEN_ODD: - SetPolyFillMode (surface->dc, ALTERNATE); + SetPolyFillMode (surface->win32.dc, ALTERNATE); break; default: ASSERT_NOT_REACHED; @@ -1427,13 +1427,13 @@ _cairo_win32_printing_surface_fill (void *abstract_surface, if (status) return status; - FillPath (surface->dc); + FillPath (surface->win32.dc); _cairo_win32_printing_surface_done_solid_brush (surface); } else if (surface->path_empty == FALSE) { - SaveDC (surface->dc); - SelectClipPath (surface->dc, RGN_AND); + SaveDC (surface->win32.dc); + SelectClipPath (surface->win32.dc, RGN_AND); status = _cairo_win32_printing_surface_paint_pattern (surface, source); - RestoreDC (surface->dc, -1); + RestoreDC (surface->win32.dc, -1); } fflush(stderr); @@ -1441,13 +1441,14 @@ _cairo_win32_printing_surface_fill (void *abstract_surface, return status; } + static cairo_int_status_t -_cairo_win32_printing_surface_emit_win32_glyphs (cairo_win32_surface_t *surface, +_cairo_win32_printing_surface_emit_win32_glyphs (cairo_win32_printing_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_glyph_t *glyphs, + cairo_glyph_t *glyphs, int num_glyphs, - cairo_scaled_font_t *scaled_font, + cairo_scaled_font_t *scaled_font, const cairo_clip_t *clip) { cairo_matrix_t ctm; @@ -1502,15 +1503,12 @@ _cairo_win32_printing_surface_emit_win32_glyphs (cairo_win32_surface_t *surface if (i == num_glyphs - 1 || ((unicode_glyphs[i + 1].index < 0xffff) != sequence_is_unicode)) { - status = _cairo_win32_surface_show_glyphs_internal ( - surface, - op, - source, - sequence_is_unicode ? &unicode_glyphs[first] : &glyphs[first], - i - first + 1, - scaled_font, - clip, - ! sequence_is_unicode); + status = _cairo_win32_surface_emit_glyphs (&surface->win32, + source, + sequence_is_unicode ? &unicode_glyphs[first] : &glyphs[first], + i - first + 1, + scaled_font, + ! sequence_is_unicode); first = i + 1; if (i < num_glyphs - 1) sequence_is_unicode = unicode_glyphs[i + 1].index <= 0xffff; @@ -1536,7 +1534,7 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac cairo_scaled_font_t *scaled_font, const cairo_clip_t *clip) { - cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_printing_surface_t *surface = abstract_surface; cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_scaled_glyph_t *scaled_glyph; cairo_pattern_t *opaque = NULL; @@ -1620,12 +1618,12 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac } #endif - SaveDC (surface->dc); + SaveDC (surface->win32.dc); old_ctm = surface->ctm; old_has_ctm = surface->has_ctm; surface->has_ctm = TRUE; surface->path_empty = TRUE; - BeginPath (surface->dc); + BeginPath (surface->win32.dc); for (i = 0; i < num_glyphs; i++) { status = _cairo_scaled_glyph_lookup (scaled_font, glyphs[i].index, @@ -1637,7 +1635,7 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac cairo_matrix_translate (&surface->ctm, glyphs[i].x, glyphs[i].y); status = _cairo_win32_printing_surface_emit_path (surface, scaled_glyph->path); } - EndPath (surface->dc); + EndPath (surface->win32.dc); surface->ctm = old_ctm; surface->has_ctm = old_has_ctm; if (status == CAIRO_STATUS_SUCCESS && surface->path_empty == FALSE) { @@ -1646,15 +1644,15 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac if (status) return status; - SetPolyFillMode (surface->dc, WINDING); - FillPath (surface->dc); + SetPolyFillMode (surface->win32.dc, WINDING); + FillPath (surface->win32.dc); _cairo_win32_printing_surface_done_solid_brush (surface); } else { - SelectClipPath (surface->dc, RGN_AND); + SelectClipPath (surface->win32.dc, RGN_AND); status = _cairo_win32_printing_surface_paint_pattern (surface, source); } } - RestoreDC (surface->dc, -1); + RestoreDC (surface->win32.dc, -1); if (opaque) cairo_pattern_destroy (opaque); @@ -1668,6 +1666,17 @@ _cairo_win32_printing_surface_get_supported_mime_types (void *abstract_surface return _cairo_win32_printing_supported_mime_types; } +static cairo_status_t +_cairo_win32_printing_surface_finish (void *abstract_surface) +{ + cairo_win32_printing_surface_t *surface = abstract_surface; + + if (surface->font_subsets != NULL) + _cairo_scaled_font_subsets_destroy (surface->font_subsets); + + return CAIRO_STATUS_SUCCESS; +} + static cairo_surface_t * _cairo_win32_printing_surface_create_similar (void *abstract_surface, cairo_content_t content, @@ -1685,13 +1694,13 @@ _cairo_win32_printing_surface_create_similar (void *abstract_surface, static cairo_int_status_t _cairo_win32_printing_surface_start_page (void *abstract_surface) { - cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_printing_surface_t *surface = abstract_surface; XFORM xform; double x_res, y_res; cairo_matrix_t inverse_ctm; cairo_status_t status; - SaveDC (surface->dc); /* Save application context first, before doing MWT */ + SaveDC (surface->win32.dc); /* Save application context first, before doing MWT */ /* As the logical coordinates used by GDI functions (eg LineTo) * are integers we need to do some additional work to prevent @@ -1730,8 +1739,8 @@ _cairo_win32_printing_surface_start_page (void *abstract_surface) * To support allowing the user to set a GDI CTM with scale < 1, * we avoid switching to an identity CTM if the CTM xx and yy is < 1. */ - SetGraphicsMode (surface->dc, GM_ADVANCED); - GetWorldTransform(surface->dc, &xform); + SetGraphicsMode (surface->win32.dc, GM_ADVANCED); + GetWorldTransform(surface->win32.dc, &xform); if (xform.eM11 < 1 && xform.eM22 < 1) { cairo_matrix_init_identity (&surface->ctm); surface->gdi_ctm.xx = xform.eM11; @@ -1748,7 +1757,7 @@ _cairo_win32_printing_surface_start_page (void *abstract_surface) surface->ctm.x0 = xform.eDx; surface->ctm.y0 = xform.eDy; cairo_matrix_init_identity (&surface->gdi_ctm); - if (!ModifyWorldTransform (surface->dc, NULL, MWT_IDENTITY)) + if (!ModifyWorldTransform (surface->win32.dc, NULL, MWT_IDENTITY)) return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_start_page:ModifyWorldTransform"); } @@ -1759,12 +1768,12 @@ _cairo_win32_printing_surface_start_page (void *abstract_surface) if (status) return status; - x_res = GetDeviceCaps (surface->dc, LOGPIXELSX); - y_res = GetDeviceCaps (surface->dc, LOGPIXELSY); + x_res = GetDeviceCaps (surface->win32.dc, LOGPIXELSX); + y_res = GetDeviceCaps (surface->win32.dc, LOGPIXELSY); cairo_matrix_transform_distance (&inverse_ctm, &x_res, &y_res); - _cairo_surface_set_resolution (&surface->base, x_res, y_res); + _cairo_surface_set_resolution (&surface->win32.base, x_res, y_res); - SaveDC (surface->dc); /* Then save Cairo's known-good clip state, so the clip path can be reset */ + SaveDC (surface->win32.dc); /* Then save Cairo's known-good clip state, so the clip path can be reset */ return CAIRO_STATUS_SUCCESS; } @@ -1773,7 +1782,7 @@ static void _cairo_win32_printing_surface_set_paginated_mode (void *abstract_surface, cairo_paginated_mode_t paginated_mode) { - cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_printing_surface_t *surface = abstract_surface; surface->paginated_mode = paginated_mode; } @@ -1805,30 +1814,29 @@ _cairo_win32_printing_surface_supports_fine_grained_fallbacks (void *abstract_su cairo_surface_t * cairo_win32_printing_surface_create (HDC hdc) { - cairo_win32_surface_t *surface; + cairo_win32_printing_surface_t *surface; cairo_surface_t *paginated; RECT rect; - surface = malloc (sizeof (cairo_win32_surface_t)); + surface = malloc (sizeof (cairo_win32_printing_surface_t)); if (surface == NULL) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); +#if 0 if (_cairo_win32_save_initial_clip (hdc, surface) != CAIRO_STATUS_SUCCESS) { free (surface); return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } +#endif _cairo_surface_clipper_init (&surface->clipper, _cairo_win32_printing_surface_clipper_intersect_clip_path); - surface->image = NULL; - surface->format = CAIRO_FORMAT_RGB24; - surface->content = CAIRO_CONTENT_COLOR_ALPHA; + surface->win32.format = CAIRO_FORMAT_RGB24; + surface->win32.base.content = CAIRO_CONTENT_COLOR_ALPHA; + + surface->win32.dc = hdc; - surface->dc = hdc; - surface->bitmap = NULL; - surface->is_dib = FALSE; - surface->saved_dc_bitmap = NULL; surface->brush = NULL; surface->old_brush = NULL; surface->font_subsets = _cairo_scaled_font_subsets_create_scaled (); @@ -1838,41 +1846,35 @@ cairo_win32_printing_surface_create (HDC hdc) } GetClipBox(hdc, &rect); - surface->extents.x = rect.left; - surface->extents.y = rect.top; - surface->extents.width = rect.right - rect.left; - surface->extents.height = rect.bottom - rect.top; + 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; - surface->flags = _cairo_win32_flags_for_dc (surface->dc); - surface->flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING; + surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc); + surface->win32.flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING; _cairo_win32_printing_surface_init_ps_mode (surface); _cairo_win32_printing_surface_init_image_support (surface); _cairo_win32_printing_surface_init_language_pack (surface); - _cairo_surface_init (&surface->base, + _cairo_surface_init (&surface->win32.base, &cairo_win32_printing_surface_backend, NULL, /* device */ CAIRO_CONTENT_COLOR_ALPHA); - paginated = _cairo_paginated_surface_create (&surface->base, + paginated = _cairo_paginated_surface_create (&surface->win32.base, CAIRO_CONTENT_COLOR_ALPHA, &cairo_win32_surface_paginated_backend); /* paginated keeps the only reference to surface now, drop ours */ - cairo_surface_destroy (&surface->base); + cairo_surface_destroy (&surface->win32.base); return paginated; } -cairo_bool_t -_cairo_surface_is_win32_printing (cairo_surface_t *surface) -{ - return surface->backend == &cairo_win32_printing_surface_backend; -} - static const cairo_surface_backend_t cairo_win32_printing_surface_backend = { CAIRO_SURFACE_TYPE_WIN32_PRINTING, - _cairo_win32_surface_finish, + _cairo_win32_printing_surface_finish, _cairo_default_context_create, diff --git a/src/win32/cairo-win32-private.h b/src/win32/cairo-win32-private.h index 07830dc25..b6c24311a 100644 --- a/src/win32/cairo-win32-private.h +++ b/src/win32/cairo-win32-private.h @@ -37,8 +37,12 @@ #define CAIRO_WIN32_PRIVATE_H #include "cairo-win32.h" + #include "cairoint.h" + +#include "cairo-device-private.h" #include "cairo-surface-clipper-private.h" +#include "cairo-surface-private.h" #ifndef SHADEBLENDCAPS #define SHADEBLENDCAPS 120 @@ -49,13 +53,59 @@ #define WIN32_FONT_LOGICAL_SCALE 32 +/* Surface DC flag values */ +enum { + /* If this is a surface created for printing or not */ + CAIRO_WIN32_SURFACE_FOR_PRINTING = (1<<0), + + /* 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), + + /* Whether we can use StretchDIBits with this surface */ + CAIRO_WIN32_SURFACE_CAN_STRETCHDIB = (1<<5), + + /* Whether we can use GradientFill rectangles with this surface */ + CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT = (1<<6), + + /* Whether we can use the CHECKJPEGFORMAT escape function */ + CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG = (1<<7), + + /* Whether we can use the CHECKJPEGFORMAT escape function */ + CAIRO_WIN32_SURFACE_CAN_CHECK_PNG = (1<<8), +}; + typedef struct _cairo_win32_surface { cairo_surface_t base; cairo_format_t format; - HDC dc; + /* Surface DC flags */ + unsigned flags; + + /* We use the x and y parts of extents for situations where + * we're not supposed to draw to the entire surface. + * For example, during a paint event a program will get + * a DC that has been clipped to the dirty region. + * A cairo surface constructed for that DC will have extents + * that match bounds of the clipped region. + */ + cairo_rectangle_int_t extents; +} cairo_win32_surface_t; +#define to_win32_surface(S) ((cairo_win32_surface_t *)(S)) + +typedef struct _cairo_win32_display_surface { + cairo_win32_surface_t win32; + /* We create off-screen surfaces as DIBs or DDBs, based on what we created * originally*/ HBITMAP bitmap; @@ -69,37 +119,19 @@ typedef struct _cairo_win32_surface { * on some versions of Windows. */ HBITMAP saved_dc_bitmap; - cairo_surface_t *image; + cairo_surface_t *fallback; - /* We use the x and y parts of extents for situations where - * we're not supposed to draw to the entire surface. - * For example, during a paint event a program will get - * a DC that has been clipped to the dirty region. - * A cairo surface constructed for that DC will have extents - * that match bounds of the clipped region. - * - * jrmuizel: I'm not sure if storing these extents instead - * of just using the size is better... */ - cairo_rectangle_int_t extents; - - /* Initial clip bits - * We need these kept around so that we maintain - * whatever clip was set on the original DC at creation - * time when cairo is asked to reset the surface clip. - */ - cairo_rectangle_int_t clip_rect; HRGN initial_clip_rgn; cairo_bool_t had_simple_clip; - cairo_region_t *clip_region; +} cairo_win32_display_surface_t; +#define to_win32_display_surface(S) ((cairo_win32_display_surface_t *)(S)) - /* For path clipping to the printing-surface */ - cairo_surface_clipper_t clipper; +typedef struct _cairo_win32_printing_surface { + cairo_win32_surface_t win32; - /* Surface DC flags */ - uint32_t flags; + cairo_surface_clipper_t clipper; - /* printing surface bits */ cairo_paginated_mode_t paginated_mode; cairo_content_t content; cairo_bool_t path_empty; @@ -109,49 +141,44 @@ typedef struct _cairo_win32_surface { cairo_matrix_t gdi_ctm; HBRUSH brush, old_brush; cairo_scaled_font_subsets_t *font_subsets; -} cairo_win32_surface_t; +} cairo_win32_printing_surface_t; +#define to_win32_printing_surface(S) ((cairo_win32_printing_surface_t *)(S)) -/* Surface DC flag values */ -enum { - /* If this is a surface created for printing or not */ - CAIRO_WIN32_SURFACE_FOR_PRINTING = (1<<0), - - /* 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), +typedef BOOL (WINAPI *cairo_win32_alpha_blend_func_t) (HDC hdcDest, + int nXOriginDest, + int nYOriginDest, + int nWidthDest, + int hHeightDest, + HDC hdcSrc, + int nXOriginSrc, + int nYOriginSrc, + int nWidthSrc, + int nHeightSrc, + BLENDFUNCTION blendFunction); - /* Whether we can use AlphaBlend with this surface */ - CAIRO_WIN32_SURFACE_CAN_ALPHABLEND = (1<<3), +typedef struct _cairo_win32_device { + cairo_device_t base; - /* Whether we can use StretchBlt with this surface */ - CAIRO_WIN32_SURFACE_CAN_STRETCHBLT = (1<<4), + HMODULE msimg32_dll; - /* Whether we can use StretchDIBits with this surface */ - CAIRO_WIN32_SURFACE_CAN_STRETCHDIB = (1<<5), + const cairo_compositor_t *compositor; - /* Whether we can use GradientFill rectangles with this surface */ - CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT = (1<<6), + cairo_win32_alpha_blend_func_t alpha_blend; +} cairo_win32_device_t; +#define to_win32_device(D) ((cairo_win32_device_t *)(D)) +#define to_win32_device_from_surface(S) to_win32_device(((cairo_surface_t *)(S))->device) - /* Whether we can use the CHECKJPEGFORMAT escape function */ - CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG = (1<<7), +cairo_private cairo_device_t * +_cairo_win32_device_get (void); - /* Whether we can use the CHECKJPEGFORMAT escape function */ - CAIRO_WIN32_SURFACE_CAN_CHECK_PNG = (1<<8), -}; +const cairo_compositor_t * +_cairo_win32_gdi_compositor_get (void); cairo_status_t _cairo_win32_print_gdi_error (const char *context); -cairo_bool_t -_cairo_surface_is_win32 (cairo_surface_t *surface); - -cairo_bool_t -_cairo_surface_is_win32_printing (cairo_surface_t *surface); - -cairo_status_t -_cairo_win32_surface_finish (void *abstract_surface); +cairo_private void +_cairo_win32_display_surface_discard_fallback (cairo_win32_display_surface_t *surface); cairo_bool_t _cairo_win32_surface_get_extents (void *abstract_surface, @@ -160,34 +187,13 @@ _cairo_win32_surface_get_extents (void *abstract_surface, uint32_t _cairo_win32_flags_for_dc (HDC dc); -cairo_status_t -_cairo_win32_surface_set_clip_region (void *abstract_surface, - cairo_region_t *region); - cairo_int_status_t -_cairo_win32_surface_show_glyphs_internal (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_bool_t glyph_indices); - -cairo_int_status_t -_cairo_win32_surface_show_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_surface_t * -_cairo_win32_surface_create_similar (void *abstract_src, - cairo_content_t content, - int width, - int height); +_cairo_win32_surface_emit_glyphs (cairo_win32_surface_t *dst, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_bool_t glyph_indexing); static inline void _cairo_matrix_to_win32_xform (const cairo_matrix_t *m, @@ -201,11 +207,12 @@ _cairo_matrix_to_win32_xform (const cairo_matrix_t *m, xform->eDy = (FLOAT) m->y0; } -cairo_int_status_t -_cairo_win32_save_initial_clip (HDC dc, cairo_win32_surface_t *surface); +cairo_status_t +_cairo_win32_display_surface_set_clip (cairo_win32_display_surface_t *surface, + cairo_clip_t *clip); -cairo_int_status_t -_cairo_win32_restore_initial_clip (cairo_win32_surface_t *surface); +void +_cairo_win32_display_surface_unset_clip (cairo_win32_display_surface_t *surface); void _cairo_win32_debug_dump_hrgn (HRGN rgn, char *header); diff --git a/src/win32/cairo-win32-surface.c b/src/win32/cairo-win32-surface.c index ec351d3f1..cec47a240 100644 --- a/src/win32/cairo-win32-surface.c +++ b/src/win32/cairo-win32-surface.c @@ -2,6 +2,7 @@ /* 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 @@ -47,8 +48,6 @@ #include "cairoint.h" -#include "cairo-clip-private.h" -#include "cairo-composite-rectangles-private.h" #include "cairo-default-context-private.h" #include "cairo-error-private.h" #include "cairo-image-surface-private.h" @@ -66,18 +65,6 @@ # define ETO_PDY 0x2000 #endif -#undef DEBUG_COMPOSITE - -/* for older SDKs */ -#ifndef SHADEBLENDCAPS -#define SHADEBLENDCAPS 120 -#endif -#ifndef SB_NONE -#define SB_NONE 0x00000000 -#endif - -#define PELS_72DPI ((LONG)(72. / 0.0254)) - /** * SECTION:cairo-win32 * @Title: Win32 Surfaces @@ -99,1406 +86,45 @@ * CAIRO_HAS_WIN32_SURFACE: * * Defined if the Microsoft Windows surface backend is available. - * This macro can be used to conditionally compile backend-specific code. - */ - -static const cairo_surface_backend_t cairo_win32_surface_backend; - -/** - * _cairo_win32_print_gdi_error: - * @context: context string to display along with the error - * - * Helper function to dump out a human readable form of the - * current error code. - * - * Return value: A cairo status code for the error code - **/ -cairo_status_t -_cairo_win32_print_gdi_error (const char *context) -{ - void *lpMsgBuf; - DWORD last_error = GetLastError (); - - if (!FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - last_error, - MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPWSTR) &lpMsgBuf, - 0, NULL)) { - fprintf (stderr, "%s: Unknown GDI error", context); - } else { - fprintf (stderr, "%s: %S", context, (wchar_t *)lpMsgBuf); - - LocalFree (lpMsgBuf); - } - - fflush (stderr); - - /* We should switch off of last_status, but we'd either return - * CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there - * is no CAIRO_STATUS_UNKNOWN_ERROR. - */ - - return _cairo_error (CAIRO_STATUS_NO_MEMORY); -} - -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; - flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB; - } 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; - if (cap & RC_STRETCHDIB) - flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB; - } - - return flags; -} - -static cairo_status_t -_create_dc_and_bitmap (cairo_win32_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->dc = NULL; - surface->bitmap = NULL; - surface->is_dib = FALSE; - - switch (format) { - default: - case CAIRO_FORMAT_INVALID: - 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) { - /* 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->dc = CreateCompatibleDC (original_dc); - if (!surface->dc) - goto FAIL; - - surface->bitmap = CreateDIBSection (surface->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->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_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->flags = _cairo_win32_flags_for_dc (surface->dc); - - return CAIRO_STATUS_SUCCESS; - - FAIL: - status = _cairo_win32_print_gdi_error ("_create_dc_and_bitmap"); - - if (bitmap_info && num_palette > 2) - free (bitmap_info); - - if (surface->saved_dc_bitmap) { - SelectObject (surface->dc, surface->saved_dc_bitmap); - surface->saved_dc_bitmap = NULL; - } - - if (surface->bitmap) { - DeleteObject (surface->bitmap); - surface->bitmap = NULL; - } - - if (surface->dc) { - DeleteDC (surface->dc); - surface->dc = NULL; - } - - return status; -} - -static cairo_surface_t * -_cairo_win32_surface_create_for_dc (HDC original_dc, - cairo_format_t format, - int width, - int height) -{ - cairo_status_t status; - cairo_win32_surface_t *surface; - unsigned char *bits; - int rowstride; - - if (! CAIRO_FORMAT_VALID (format)) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); - - surface = malloc (sizeof (cairo_win32_surface_t)); - if (surface == NULL) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - - surface->clip_region = 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; - - surface->format = format; - - surface->clip_rect.x = 0; - surface->clip_rect.y = 0; - surface->clip_rect.width = width; - surface->clip_rect.height = height; - - surface->initial_clip_rgn = NULL; - surface->had_simple_clip = FALSE; - - surface->extents = surface->clip_rect; - surface->font_subsets = NULL; - - _cairo_surface_init (&surface->base, - &cairo_win32_surface_backend, - NULL, /* device */ - _cairo_content_from_format (format)); - - return &surface->base; - - FAIL: - if (surface->bitmap) { - SelectObject (surface->dc, surface->saved_dc_bitmap); - DeleteObject (surface->bitmap); - DeleteDC (surface->dc); - } - free (surface); - - return _cairo_surface_create_in_error (status); -} - -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_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) || - src->base.backend->type == CAIRO_SURFACE_TYPE_WIN32_PRINTING) - { - force_dib = TRUE; - } - - if (!force_dib) { - /* try to create a ddb */ - new_surf = cairo_win32_surface_create_with_ddb (src->dc, CAIRO_FORMAT_RGB24, width, height); - - if (new_surf->status != CAIRO_STATUS_SUCCESS) - new_surf = NULL; - } - - if (new_surf == NULL) { - new_surf = _cairo_win32_surface_create_for_dc (src->dc, format, width, height); - } - - return new_surf; -} - -cairo_surface_t * -_cairo_win32_surface_create_similar (void *abstract_src, - cairo_content_t content, - int width, - int height) -{ - return _cairo_win32_surface_create_similar_internal (abstract_src, content, width, height, FALSE); -} - -cairo_status_t -_cairo_win32_surface_finish (void *abstract_surface) -{ - cairo_win32_surface_t *surface = abstract_surface; - - if (surface->image) - cairo_surface_destroy (surface->image); - - /* 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); - } else { - _cairo_win32_restore_initial_clip (surface); - } - - if (surface->initial_clip_rgn) - DeleteObject (surface->initial_clip_rgn); - - if (surface->font_subsets != NULL) - _cairo_scaled_font_subsets_destroy (surface->font_subsets); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface, - int x, - int y, - int width, - int height, - cairo_win32_surface_t **local_out) -{ - cairo_win32_surface_t *local; - 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_internal - (surface, content, width, height, TRUE); - if (local == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; - if (local->base.status) - return local->base.status; - - status = CAIRO_INT_STATUS_UNSUPPORTED; - - /* Only BitBlt if the source surface supports it. */ - if ((surface->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). - */ - - RECT r; - r.left = r.top = 0; - r.right = width; - r.bottom = height; - FillRect(local->dc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH)); - } - - *local_out = local; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_surface_t * -_cairo_win32_surface_map_to_image (void *abstract_surface, - const cairo_rectangle_int_t *extents) -{ - cairo_win32_surface_t *surface = abstract_surface; - cairo_win32_surface_t *local = NULL; - cairo_status_t status; - - if (surface->image) { - GdiFlush(); - return _cairo_surface_create_for_rectangle_int (surface->image, - extents); - } - - status = _cairo_win32_surface_get_subimage (abstract_surface, - extents->x, - extents->y, - extents->width, - extents->height, - &local); - if (unlikely (status)) - return _cairo_surface_create_in_error (status); - - status = cairo_surface_set_user_data (local->image, - (const cairo_user_data_key_t *)surface->image, - local, NULL); - if (unlikely (status)) { - cairo_surface_destroy (&local->base); - return _cairo_surface_create_in_error (status); - } - - cairo_surface_set_device_offset (local->image, -extents->x, -extents->y); - return local->image; -} - -static cairo_int_status_t -_cairo_win32_surface_unmap_image (void *abstract_surface, - cairo_image_surface_t *image) -{ - cairo_win32_surface_t *surface = abstract_surface; - cairo_win32_surface_t *local; - - local = cairo_surface_get_user_data (&image->base, - (const cairo_user_data_key_t *) surface->image); - if (!local) - return CAIRO_INT_STATUS_SUCCESS; - - if (!BitBlt (surface->dc, - image->base.device_transform.x0, - image->base.device_transform.y0, - image->width, image->height, - local->dc, - 0, 0, - SRCCOPY)) - _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image"); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_win32_surface_acquire_source_image (void *abstract_surface, - cairo_image_surface_t **image_out, - void **image_extra) -{ - cairo_win32_surface_t *surface = abstract_surface; - cairo_win32_surface_t *local; - cairo_status_t status; - - if (surface->image) { - *image_out = (cairo_image_surface_t *)surface->image; - *image_extra = NULL; - return CAIRO_STATUS_SUCCESS; - } - - status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0, - surface->extents.width, - surface->extents.height, &local); - if (status) - return status; - - *image_out = (cairo_image_surface_t *)local->image; - *image_extra = local; - return CAIRO_STATUS_SUCCESS; -} - -static void -_cairo_win32_surface_release_source_image (void *abstract_surface, - cairo_image_surface_t *image, - void *image_extra) -{ - cairo_win32_surface_t *local = image_extra; - - if (local) - cairo_surface_destroy ((cairo_surface_t *)local); -} - -cairo_status_t -_cairo_win32_surface_set_clip_region (void *abstract_surface, - cairo_region_t *region) -{ - cairo_win32_surface_t *surface = abstract_surface; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - - if (surface->clip_region == region) - return CAIRO_STATUS_SUCCESS; - - cairo_region_destroy (surface->clip_region); - surface->clip_region = cairo_region_reference (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. - */ - - /* Clear any clip set by cairo, return to the original first */ - status = _cairo_win32_restore_initial_clip (surface); - - /* Then combine any new region with it */ - if (region) { - cairo_rectangle_int_t extents; - int num_rects; - RGNDATA *data; - size_t data_size; - RECT *rects; - int i; - HRGN gdi_region; - - /* Create a GDI region for the cairo region */ - - 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); - data = malloc (data_size); - if (!data) - return _cairo_error(CAIRO_STATUS_NO_MEMORY); - rects = (RECT *)data->Buffer; - - 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; - - 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); - free (data); - - if (!gdi_region) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - /* AND the new region into our DC */ - if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR) - status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region"); - - DeleteObject (gdi_region); - } - - return status; -} - -#if !defined(AC_SRC_OVER) -#define AC_SRC_OVER 0x00 -#pragma pack(1) -typedef struct { - BYTE BlendOp; - BYTE BlendFlags; - BYTE SourceConstantAlpha; - BYTE AlphaFormat; -}BLENDFUNCTION; -#pragma pack() -#endif - -/* for compatibility with VC++ 6 */ -#ifndef AC_SRC_ALPHA -#define AC_SRC_ALPHA 0x01 -#endif - -typedef BOOL (WINAPI *cairo_alpha_blend_func_t) (HDC hdcDest, - int nXOriginDest, - int nYOriginDest, - int nWidthDest, - int hHeightDest, - HDC hdcSrc, - int nXOriginSrc, - int nYOriginSrc, - int nWidthSrc, - int nHeightSrc, - BLENDFUNCTION blendFunction); - -static cairo_int_status_t -_composite_alpha_blend (cairo_win32_surface_t *dst, - cairo_win32_surface_t *src, - int alpha, - int src_x, - int src_y, - int src_w, - int src_h, - int dst_x, - int dst_y, - int dst_w, - int dst_h) -{ - static unsigned alpha_blend_checked = FALSE; - static cairo_alpha_blend_func_t alpha_blend = NULL; - - BLENDFUNCTION blend_function; - - /* Check for AlphaBlend dynamically to allow compiling on - * MSVC 6 and use on older windows versions - */ - if (!alpha_blend_checked) { - OSVERSIONINFO os; - - os.dwOSVersionInfoSize = sizeof (os); - GetVersionEx (&os); - - /* If running on Win98, disable using AlphaBlend() - * to avoid Win98 AlphaBlend() bug */ - if (VER_PLATFORM_WIN32_WINDOWS != os.dwPlatformId || - os.dwMajorVersion != 4 || os.dwMinorVersion != 10) - { - HMODULE msimg32_dll = LoadLibraryW (L"msimg32"); - - if (msimg32_dll != NULL) - alpha_blend = (cairo_alpha_blend_func_t)GetProcAddress (msimg32_dll, - "AlphaBlend"); - } - - alpha_blend_checked = TRUE; - } - - if (alpha_blend == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; - if (!(dst->flags & CAIRO_WIN32_SURFACE_CAN_ALPHABLEND)) - return CAIRO_INT_STATUS_UNSUPPORTED; - if (src->format == CAIRO_FORMAT_RGB24 && dst->format == CAIRO_FORMAT_ARGB32) - 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; - - if (!alpha_blend (dst->dc, - dst_x, dst_y, - dst_w, dst_h, - src->dc, - src_x, src_y, - src_w, src_h, - blend_function)) - return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(AlphaBlend)"); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_cairo_win32_surface_composite_inner (cairo_win32_surface_t *src, - cairo_image_surface_t *src_image, - cairo_win32_surface_t *dst, - cairo_rectangle_int_t src_extents, - cairo_rectangle_int_t src_r, - cairo_rectangle_int_t dst_r, - int alpha, - cairo_bool_t needs_alpha, - cairo_bool_t needs_scale) -{ - /* Then do BitBlt, StretchDIBits, StretchBlt, AlphaBlend, or MaskBlt */ - if (src_image) { - if (needs_alpha || needs_scale) - return CAIRO_INT_STATUS_UNSUPPORTED; - - if (dst->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHBLT) { - 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; - - /* StretchDIBits is broken with top-down dibs; you need to do some - * special munging to make the coordinate space work (basically, - * need to address everything based on the bottom left, instead of top left, - * and need to tell it to flip the resulting image. - * - * See http://blog.vlad1.com/archives/2006/10/26/134/ and comments. - */ - if (!StretchDIBits (dst->dc, - /* dst x,y,w,h */ - dst_r.x, dst_r.y + dst_r.height - 1, - dst_r.width, - (int) dst_r.height, - /* src x,y,w,h */ - src_r.x, src_extents.height - src_r.y + 1, - src_r.width, - (int) src_r.height, - src_image->data, - &bi, - DIB_RGB_COLORS, - SRCCOPY)) - return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(StretchDIBits)"); - } - } else if (!needs_alpha) { - /* BitBlt or StretchBlt? */ - if (!needs_scale && (dst->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT)) { - if (!BitBlt (dst->dc, - dst_r.x, dst_r.y, - dst_r.width, dst_r.height, - src->dc, - src_r.x, src_r.y, - SRCCOPY)) - return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(BitBlt)"); - } 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_r.x, dst_r.y, - dst_r.width, dst_r.height, - src->dc, - src_r.x, src_r.y, - src_r.width, src_r.height, - SRCCOPY); - SetStretchBltMode(dst->dc, oldmode); - - if (!success) - return _cairo_win32_print_gdi_error ("StretchBlt"); - } - } else if (needs_alpha && !needs_scale) { - return _composite_alpha_blend (dst, src, alpha, - src_r.x, src_r.y, src_r.width, src_r.height, - dst_r.x, dst_r.y, dst_r.width, dst_r.height); - } - - return CAIRO_STATUS_SUCCESS; -} - -/* from pixman-private.h */ -#define MOD(a,b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b)) - -static cairo_int_status_t -_cairo_win32_surface_composite (cairo_operator_t op, - const cairo_pattern_t *pattern, - const cairo_pattern_t *mask_pattern, - void *abstract_dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height, - cairo_region_t *clip_region) -{ - cairo_win32_surface_t *dst = abstract_dst; - cairo_win32_surface_t *src; - cairo_surface_pattern_t *src_surface_pattern; - int alpha; - double scalex, scaley; - cairo_fixed_t x0_fixed, y0_fixed; - cairo_int_status_t status; - - cairo_bool_t needs_alpha, needs_scale, needs_repeat; - cairo_image_surface_t *src_image = NULL; - - cairo_format_t src_format; - cairo_rectangle_int_t src_extents; - - cairo_rectangle_int_t src_r = { src_x, src_y, width, height }; - cairo_rectangle_int_t dst_r = { dst_x, dst_y, width, height }; - -#ifdef DEBUG_COMPOSITE - 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 | - CAIRO_WIN32_SURFACE_CAN_STRETCHDIB)) - == 0) - { - goto UNSUPPORTED; - } - - if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE) - goto UNSUPPORTED; - - if (pattern->extend != CAIRO_EXTEND_NONE && - pattern->extend != CAIRO_EXTEND_REPEAT) - goto UNSUPPORTED; - - if (mask_pattern) { - /* FIXME: When we fully support RENDER style 4-channel - * masks we need to check r/g/b != 1.0. - */ - if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID) - return CAIRO_INT_STATUS_UNSUPPORTED; - - alpha = ((cairo_solid_pattern_t *)mask_pattern)->color.alpha_short >> 8; - } else { - alpha = 255; - } - - src_surface_pattern = (cairo_surface_pattern_t *)pattern; - src = (cairo_win32_surface_t *)src_surface_pattern->surface; - - if (src->base.type == CAIRO_SURFACE_TYPE_IMAGE && - dst->flags & (CAIRO_WIN32_SURFACE_CAN_STRETCHDIB)) - { - /* In some very limited cases, we can use StretchDIBits to draw - * an image surface directly: - * - source is CAIRO_FORMAT_ARGB32 - * - dest is CAIRO_FORMAT_ARGB32 - * - alpha is 255 - * - operator is SOURCE or OVER - * - image stride is 4*width - */ - src_image = (cairo_image_surface_t*) src; - - if (src_image->format != CAIRO_FORMAT_RGB24 || - dst->format != CAIRO_FORMAT_RGB24 || - alpha != 255 || - (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) || - src_image->stride != (src_image->width * 4)) - { - goto UNSUPPORTED; - } - - src_format = src_image->format; - src_extents.x = 0; - src_extents.y = 0; - src_extents.width = src_image->width; - src_extents.height = src_image->height; - } else if (src->base.backend != dst->base.backend) { - goto UNSUPPORTED; - } else { - src_format = src->format; - src_extents = src->extents; - } - - -#ifdef DEBUG_COMPOSITE - fprintf (stderr, "Before check: src size: (%d %d) xy [%d %d] -> dst [%d %d %d %d] {srcmat %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)) - { - goto UNSUPPORTED; - } - - scalex = pattern->matrix.xx; - scaley = pattern->matrix.yy; - - src_r.x += _cairo_fixed_integer_part(x0_fixed); - src_r.y += _cairo_fixed_integer_part(y0_fixed); - - /* Success, right? */ - if (scalex == 0.0 || scaley == 0.0) - return CAIRO_STATUS_SUCCESS; - - if (scalex != 1.0 || scaley != 1.0) - goto 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. - */ - -#ifdef DEBUG_COMPOSITE - fprintf (stderr, "before: [%d %d %d %d] -> [%d %d %d %d]\n", - src_r.x, src_r.y, src_r.width, src_r.height, - dst_r.x, dst_r.y, dst_r.width, dst_r.height); - fflush (stderr); -#endif - - /* If the src rectangle doesn't wholly lie within the src extents, - * fudge things. We really need to do fixup on the unpainted - * region -- e.g. the SOURCE operator is broken for areas outside - * of the extents, because it won't clear that area to transparent - * black. - */ - - if (pattern->extend != CAIRO_EXTEND_REPEAT) { - needs_repeat = FALSE; - - /* If the src rect and the extents of the source image don't overlap at all, - * we can't do anything useful here. - */ - if (src_r.x > src_extents.width || src_r.y > src_extents.height || - (src_r.x + src_r.width) < 0 || (src_r.y + src_r.height) < 0) - { - if (op == CAIRO_OPERATOR_OVER) - return CAIRO_STATUS_SUCCESS; - goto UNSUPPORTED; - } - - if (src_r.x < 0) { - src_r.width += src_r.x; - src_r.x = 0; - - dst_r.width += src_r.x; - dst_r.x -= src_r.x; - } - - if (src_r.y < 0) { - src_r.height += src_r.y; - src_r.y = 0; - - dst_r.height += dst_r.y; - dst_r.y -= src_r.y; - } - - if (src_r.x + src_r.width > src_extents.width) { - src_r.width = src_extents.width - src_r.x; - dst_r.width = src_r.width; - } - - if (src_r.y + src_r.height > src_extents.height) { - src_r.height = src_extents.height - src_r.y; - dst_r.height = src_r.height; - } - } else { - needs_repeat = TRUE; - } - - /* - * Operations that we can do: - * - * RGB OVER RGB -> BitBlt (same as SOURCE) - * RGB OVER ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA) - * ARGB OVER ARGB -> AlphaBlend, with AC_SRC_ALPHA - * ARGB OVER RGB -> AlphaBlend, with AC_SRC_ALPHA; we'll have junk in the dst A byte - * - * RGB OVER RGB + mask -> AlphaBlend, no AC_SRC_ALPHA - * RGB OVER ARGB + mask -> UNSUPPORTED - * ARGB OVER ARGB + mask -> AlphaBlend, with AC_SRC_ALPHA - * ARGB OVER RGB + mask -> AlphaBlend, with AC_SRC_ALPHA; junk in the dst A byte - * - * RGB SOURCE RGB -> BitBlt - * RGB SOURCE ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA) - * ARGB SOURCE ARGB -> BitBlt - * ARGB SOURCE RGB -> BitBlt - * - * RGB SOURCE RGB + mask -> unsupported - * RGB SOURCE ARGB + mask -> unsupported - * ARGB SOURCE ARGB + mask -> unsupported - * ARGB SOURCE RGB + mask -> unsupported - */ - - /* - * Figure out what action to take. - */ - if (op == CAIRO_OPERATOR_OVER) { - if (alpha == 0) - return CAIRO_STATUS_SUCCESS; - - if (src_format == dst->format) { - if (alpha == 255 && src_format == CAIRO_FORMAT_RGB24) { - needs_alpha = FALSE; - } else { - needs_alpha = TRUE; - } - } else if (src_format == CAIRO_FORMAT_ARGB32 && - dst->format == CAIRO_FORMAT_RGB24) - { - needs_alpha = TRUE; - } else { - goto UNSUPPORTED; - } - } else if (alpha == 255 && op == CAIRO_OPERATOR_SOURCE) { - if ((src_format == dst->format) || - (src_format == CAIRO_FORMAT_ARGB32 && dst->format == CAIRO_FORMAT_RGB24)) - { - needs_alpha = FALSE; - } else { - goto UNSUPPORTED; - } - } else { - goto UNSUPPORTED; - } - - if (scalex == 1.0 && scaley == 1.0) { - needs_scale = FALSE; - } else { - /* Should never be reached until we turn StretchBlt back on */ - needs_scale = TRUE; - } - -#ifdef DEBUG_COMPOSITE - fprintf (stderr, "action: [%d %d %d %d] -> [%d %d %d %d]\n", - src_r.x, src_r.y, src_r.width, src_r.height, - dst_r.x, dst_r.y, dst_r.width, dst_r.height); - fflush (stderr); -#endif - - status = _cairo_win32_surface_set_clip_region (dst, clip_region); - if (status) - return status; - - /* If we need to repeat, we turn the repeated blit into - * a bunch of piece-by-piece blits. - */ - if (needs_repeat) { - cairo_rectangle_int_t piece_src_r, piece_dst_r; - uint32_t rendered_width = 0, rendered_height = 0; - uint32_t to_render_height, to_render_width; - int32_t piece_x, piece_y; - int32_t src_start_x = MOD(src_r.x, src_extents.width); - int32_t src_start_y = MOD(src_r.y, src_extents.height); - - if (needs_scale) - goto UNSUPPORTED; - - /* If both the src and dest have an image, we may as well fall - * back, because it will be faster than our separate blits. - * Our blit code will be fastest when the src is a DDB and the - * destination is a DDB. - */ - if ((src_image || src->image) && dst->image) - goto UNSUPPORTED; - - /* If the src is not a bitmap but an on-screen (or unknown) - * DC, chances are that fallback will be faster. - */ - if (src->bitmap == NULL) - goto UNSUPPORTED; - - /* If we can use PatBlt, just do so */ - if (!src_image && !needs_alpha) - { - HBRUSH brush; - HGDIOBJ old_brush; - POINT old_brush_origin; - - /* Set up the brush with our bitmap */ - brush = CreatePatternBrush (src->bitmap); - - /* SetBrushOrgEx sets the coordinates in the destination DC of where the - * pattern should start. - */ - SetBrushOrgEx (dst->dc, dst_r.x - src_start_x, - dst_r.y - src_start_y, &old_brush_origin); - - old_brush = SelectObject (dst->dc, brush); - - PatBlt (dst->dc, dst_r.x, dst_r.y, dst_r.width, dst_r.height, PATCOPY); - - /* Restore the old brush and pen */ - SetBrushOrgEx (dst->dc, old_brush_origin.x, old_brush_origin.y, NULL); - SelectObject (dst->dc, old_brush); - DeleteObject (brush); - - return CAIRO_STATUS_SUCCESS; - } - - /* If we were not able to use PatBlt, then manually expand out the blit */ - - /* Arbitrary factor; we think that going through - * fallback will be faster if we have to do more - * than this amount of blits in either direction. - */ - if (dst_r.width / src_extents.width > 5 || - dst_r.height / src_extents.height > 5) - goto UNSUPPORTED; - - for (rendered_height = 0; - rendered_height < dst_r.height; - rendered_height += to_render_height) - { - piece_y = (src_start_y + rendered_height) % src_extents.height; - to_render_height = src_extents.height - piece_y; - - if (rendered_height + to_render_height > dst_r.height) - to_render_height = dst_r.height - rendered_height; - - for (rendered_width = 0; - rendered_width < dst_r.width; - rendered_width += to_render_width) - { - piece_x = (src_start_x + rendered_width) % src_extents.width; - to_render_width = src_extents.width - piece_x; - - if (rendered_width + to_render_width > dst_r.width) - to_render_width = dst_r.width - rendered_width; - - piece_src_r.x = piece_x; - piece_src_r.y = piece_y; - piece_src_r.width = to_render_width; - piece_src_r.height = to_render_height; - - piece_dst_r.x = dst_r.x + rendered_width; - piece_dst_r.y = dst_r.y + rendered_height; - piece_dst_r.width = to_render_width; - piece_dst_r.height = to_render_height; - - status = _cairo_win32_surface_composite_inner (src, src_image, dst, - src_extents, piece_src_r, piece_dst_r, - alpha, needs_alpha, needs_scale); - if (status != CAIRO_STATUS_SUCCESS) { - /* Uh oh. If something failed, and it's the first - * piece, then we can jump to UNSUPPORTED. - * Otherwise, this is bad times, because part of the - * rendering was already done. */ - if (rendered_width == 0 && - rendered_height == 0) - { - goto UNSUPPORTED; - } - - return status; - } - } - } - } else { - status = _cairo_win32_surface_composite_inner (src, src_image, dst, - src_extents, src_r, dst_r, - alpha, needs_alpha, needs_scale); - } - - if (status == CAIRO_STATUS_SUCCESS) - return status; - -UNSUPPORTED: - /* Fall back to image surface directly, if this is a DIB surface */ - if (dst->image) { - GdiFlush(); - -#if 0 - return dst->image->backend->composite (op, pattern, mask_pattern, - dst->image, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height, - clip_region); -#endif - } - - return CAIRO_INT_STATUS_UNSUPPORTED; -} - -/* This big function tells us how to optimize operators for the - * case of solid destination and constant-alpha source - * - * Note: This function needs revisiting if we add support for - * super-luminescent colors (a == 0, r,g,b > 0) - */ -static enum { DO_CLEAR, DO_SOURCE, DO_NOTHING, DO_UNSUPPORTED } -categorize_solid_dest_operator (cairo_operator_t op, - unsigned short alpha) -{ - enum { SOURCE_TRANSPARENT, SOURCE_LIGHT, SOURCE_SOLID, SOURCE_OTHER } source; - - if (alpha >= 0xff00) - source = SOURCE_SOLID; - else if (alpha < 0x100) - source = SOURCE_TRANSPARENT; - else - source = SOURCE_OTHER; - - switch (op) { - case CAIRO_OPERATOR_CLEAR: /* 0 0 */ - case CAIRO_OPERATOR_OUT: /* 1 - Ab 0 */ - return DO_CLEAR; - break; - - case CAIRO_OPERATOR_SOURCE: /* 1 0 */ - case CAIRO_OPERATOR_IN: /* Ab 0 */ - return DO_SOURCE; - break; - - case CAIRO_OPERATOR_OVER: /* 1 1 - Aa */ - case CAIRO_OPERATOR_ATOP: /* Ab 1 - Aa */ - if (source == SOURCE_SOLID) - return DO_SOURCE; - else if (source == SOURCE_TRANSPARENT) - return DO_NOTHING; - else - return DO_UNSUPPORTED; - break; - - case CAIRO_OPERATOR_DEST_OUT: /* 0 1 - Aa */ - case CAIRO_OPERATOR_XOR: /* 1 - Ab 1 - Aa */ - if (source == SOURCE_SOLID) - return DO_CLEAR; - else if (source == SOURCE_TRANSPARENT) - return DO_NOTHING; - else - return DO_UNSUPPORTED; - break; - - case CAIRO_OPERATOR_DEST: /* 0 1 */ - case CAIRO_OPERATOR_DEST_OVER:/* 1 - Ab 1 */ - case CAIRO_OPERATOR_SATURATE: /* min(1,(1-Ab)/Aa) 1 */ - return DO_NOTHING; - break; - - case CAIRO_OPERATOR_DEST_IN: /* 0 Aa */ - case CAIRO_OPERATOR_DEST_ATOP:/* 1 - Ab Aa */ - if (source == SOURCE_SOLID) - return DO_NOTHING; - else if (source == SOURCE_TRANSPARENT) - return DO_CLEAR; - else - return DO_UNSUPPORTED; - break; - - case CAIRO_OPERATOR_ADD: /* 1 1 */ - if (source == SOURCE_TRANSPARENT) - return DO_NOTHING; - else - return DO_UNSUPPORTED; - break; - - case CAIRO_OPERATOR_MULTIPLY: - case CAIRO_OPERATOR_SCREEN: - case CAIRO_OPERATOR_OVERLAY: - case CAIRO_OPERATOR_DARKEN: - case CAIRO_OPERATOR_LIGHTEN: - case CAIRO_OPERATOR_COLOR_DODGE: - case CAIRO_OPERATOR_COLOR_BURN: - case CAIRO_OPERATOR_HARD_LIGHT: - case CAIRO_OPERATOR_SOFT_LIGHT: - case CAIRO_OPERATOR_DIFFERENCE: - case CAIRO_OPERATOR_EXCLUSION: - case CAIRO_OPERATOR_HSL_HUE: - case CAIRO_OPERATOR_HSL_SATURATION: - case CAIRO_OPERATOR_HSL_COLOR: - case CAIRO_OPERATOR_HSL_LUMINOSITY: - return DO_UNSUPPORTED; - - default: - ASSERT_NOT_REACHED; - return DO_UNSUPPORTED; - } -} - -static cairo_int_status_t -_cairo_win32_surface_fill_rectangles (void *abstract_surface, - cairo_operator_t op, - const cairo_color_t *color, - cairo_rectangle_int_t *rects, - int num_rects) -{ - cairo_win32_surface_t *surface = abstract_surface; - cairo_status_t status; - COLORREF new_color; - HBRUSH new_brush; - int i; - - /* XXXperf If it's not RGB24, we need to do a little more checking - * to figure out when we can use GDI. We don't have that checking - * anywhere at the moment, so just bail and use the fallback - * paths. */ - if (surface->format != CAIRO_FORMAT_RGB24) - return CAIRO_INT_STATUS_UNSUPPORTED; - - status = _cairo_win32_surface_set_clip_region (surface, NULL); - if (status) - return status; - - /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all - * surfaces with alpha.) - */ - switch (categorize_solid_dest_operator (op, color->alpha_short)) { - case DO_CLEAR: - new_color = RGB (0, 0, 0); - break; - case DO_SOURCE: - new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8); - break; - case DO_NOTHING: - return CAIRO_STATUS_SUCCESS; - case DO_UNSUPPORTED: - default: - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - new_brush = CreateSolidBrush (new_color); - if (!new_brush) - return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles"); + * This macro can be used to conditionally compile backend-specific code. + */ - for (i = 0; i < num_rects; i++) { - RECT rect; +/** + * _cairo_win32_print_gdi_error: + * @context: context string to display along with the error + * + * Helper function to dump out a human readable form of the + * current error code. + * + * Return value: A cairo status code for the error code + **/ +cairo_status_t +_cairo_win32_print_gdi_error (const char *context) +{ + void *lpMsgBuf; + DWORD last_error = GetLastError (); - rect.left = rects[i].x; - rect.top = rects[i].y; - rect.right = rects[i].x + rects[i].width; - rect.bottom = rects[i].y + rects[i].height; + if (!FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + last_error, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR) &lpMsgBuf, + 0, NULL)) { + fprintf (stderr, "%s: Unknown GDI error", context); + } else { + fprintf (stderr, "%s: %S", context, (wchar_t *)lpMsgBuf); - if (!FillRect (surface->dc, &rect, new_brush)) - goto FAIL; + LocalFree (lpMsgBuf); } - DeleteObject (new_brush); - - return CAIRO_STATUS_SUCCESS; - - FAIL: - status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles"); - - DeleteObject (new_brush); + fflush (stderr); - return status; + /* We should switch off of last_status, but we'd either return + * CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there + * is no CAIRO_STATUS_UNKNOWN_ERROR. + */ + return _cairo_error (CAIRO_STATUS_NO_MEMORY); } cairo_bool_t @@ -1511,27 +137,71 @@ _cairo_win32_surface_get_extents (void *abstract_surface, return TRUE; } -static cairo_status_t -_cairo_win32_surface_flush (void *abstract_surface) +/** + * cairo_win32_surface_get_dc + * @surface: a #cairo_surface_t + * + * Returns the HDC associated with this surface, or %NULL if none. + * Also returns %NULL if the surface is not a win32 surface. + * + * A call to cairo_surface_flush() is required before using the HDC to + * ensure that all pending drawing operations are finished and to + * restore any temporary modification cairo has made to its state. A + * call to cairo_surface_mark_dirty() is required after the state or + * the content of the HDC has been modified. + * + * Return value: HDC or %NULL if no HDC available. + * + * Since: 1.2 + **/ +HDC +cairo_win32_surface_get_dc (cairo_surface_t *surface) { - return _cairo_win32_surface_set_clip_region (abstract_surface, NULL); + if (surface->backend->type == CAIRO_SURFACE_TYPE_WIN32) + return to_win32_surface(surface)->dc; + + if (_cairo_surface_is_paginated (surface)) { + cairo_surface_t *target = _cairo_paginated_surface_get_target (surface); + if (target->backend->type == CAIRO_SURFACE_TYPE_WIN32_PRINTING) + return to_win32_surface(target)->dc; + } + + return NULL; } -#define STACK_GLYPH_SIZE 256 +/** + * cairo_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 (surface->backend->type != CAIRO_SURFACE_TYPE_WIN32) + return NULL; + + GdiFlush(); + return to_win32_display_surface(surface)->image; +} +#define STACK_GLYPH_SIZE 256 cairo_int_status_t -_cairo_win32_surface_show_glyphs_internal (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_bool_t glyph_indexing) +_cairo_win32_surface_emit_glyphs (cairo_win32_surface_t *dst, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_bool_t glyph_indexing) { #if CAIRO_HAS_WIN32_FONT - cairo_win32_surface_t *dst = surface; - WORD glyph_buf_stack[STACK_GLYPH_SIZE]; WORD *glyph_buf = glyph_buf_stack; int dxy_buf_stack[2 * STACK_GLYPH_SIZE]; @@ -1551,31 +221,11 @@ _cairo_win32_surface_show_glyphs_internal (void *surface, unsigned int glyph_index_option; /* We can only handle win32 fonts */ - if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_WIN32) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* We can only handle opaque solid color sources */ - if (!_cairo_pattern_is_opaque_solid(source)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* We can only handle operator SOURCE or OVER with the destination - * having no alpha */ - if ((op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) || - (dst->format != CAIRO_FORMAT_RGB24)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* If we have a fallback mask clip set on the dst, we have - * to go through the fallback path, but only if we're not - * doing this for printing */ - if (clip != NULL) { - if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) == 0) { - if (! _cairo_clip_is_region (clip)) - return CAIRO_INT_STATUS_UNSUPPORTED; + assert (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32); - _cairo_win32_surface_set_clip_region (surface, - _cairo_clip_get_region (clip)); - } - } + /* We can only handle opaque solid color sources and destinations */ + assert (_cairo_pattern_is_opaque_solid(source)); + assert (dst->format == CAIRO_FORMAT_RGB24); solid_pattern = (cairo_solid_pattern_t *)source; color = RGB(((int)solid_pattern->color.red_short) >> 8, @@ -1666,422 +316,4 @@ _cairo_win32_surface_show_glyphs_internal (void *surface, return CAIRO_INT_STATUS_UNSUPPORTED; #endif } - #undef STACK_GLYPH_SIZE - -cairo_int_status_t -_cairo_win32_surface_show_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) -{ - return _cairo_win32_surface_show_glyphs_internal (surface, - op, - source, - glyphs, - num_glyphs, - scaled_font, - clip, - TRUE); -} - - -/** - * 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_dib(). - * - * Return value: the newly created surface - **/ -cairo_surface_t * -cairo_win32_surface_create (HDC hdc) -{ - cairo_win32_surface_t *surface; - - cairo_format_t format; - RECT rect; - - /* Assume that everything coming in as a HDC is RGB24 */ - format = CAIRO_FORMAT_RGB24; - - surface = malloc (sizeof (cairo_win32_surface_t)); - if (surface == NULL) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - - if (_cairo_win32_save_initial_clip (hdc, surface) != CAIRO_STATUS_SUCCESS) { - free (surface); - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - } - - surface->clip_region = NULL; - surface->image = NULL; - surface->format = format; - - surface->dc = hdc; - surface->bitmap = NULL; - surface->is_dib = FALSE; - surface->saved_dc_bitmap = NULL; - surface->brush = NULL; - surface->old_brush = NULL; - surface->font_subsets = NULL; - - GetClipBox(hdc, &rect); - surface->extents.x = rect.left; - surface->extents.y = rect.top; - surface->extents.width = rect.right - rect.left; - surface->extents.height = rect.bottom - rect.top; - - surface->flags = _cairo_win32_flags_for_dc (surface->dc); - - _cairo_surface_init (&surface->base, - &cairo_win32_surface_backend, - NULL, /* device */ - _cairo_content_from_format (format)); - - return &surface->base; -} - -/** - * 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) -{ - return _cairo_win32_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_surface_t *new_surf; - HBITMAP ddb; - HDC screen_dc, ddb_dc; - HBITMAP saved_dc_bitmap; - - if (format != CAIRO_FORMAT_RGB24) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); -/* 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_dc = CreateCompatibleDC (hdc); - if (ddb_dc == NULL) { - new_surf = (cairo_win32_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_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_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 (cairo_surface_t*) new_surf; -} - -/** - * _cairo_surface_is_win32: - * @surface: a #cairo_surface_t - * - * Checks if a surface is a win32 surface. This will - * return False if this is a win32 printing surface; use - * _cairo_surface_is_win32_printing() to check for that. - * - * Return value: True if the surface is an win32 surface - **/ -int -_cairo_surface_is_win32 (cairo_surface_t *surface) -{ - return surface->backend == &cairo_win32_surface_backend; -} - -/** - * cairo_win32_surface_get_dc - * @surface: a #cairo_surface_t - * - * Returns the HDC associated with this surface, or %NULL if none. - * Also returns %NULL if the surface is not a win32 surface. - * - * A call to cairo_surface_flush() is required before using the HDC to - * ensure that all pending drawing operations are finished and to - * restore any temporary modification cairo has made to its state. A - * call to cairo_surface_mark_dirty() is required after the state or - * the content of the HDC has been modified. - * - * Return value: HDC or %NULL if no HDC available. - * - * Since: 1.2 - **/ -HDC -cairo_win32_surface_get_dc (cairo_surface_t *surface) -{ - if (_cairo_surface_is_win32 (surface)) - return ((cairo_win32_surface_t *) target)->dc; - - if (_cairo_surface_is_paginated (surface)) { - cairo_surface_t *target = _cairo_paginated_surface_get_target (surface); - if (_cairo_surface_is_win32_printing (target)) - return ((cairo_win32_surface_t *) target)->dc; - } - - return NULL; -} - -/** - * cairo_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_finish, - - _cairo_default_context_create, - - _cairo_win32_surface_create_similar, - NULL, - _cairo_win32_surface_map_to_image, - _cairo_win32_surface_unmap_image, - - _cairo_surface_default_source, - _cairo_win32_surface_acquire_source_image, - _cairo_win32_surface_release_source_image, - NULL, /* snapshot */ - - NULL, /* copy_page */ - NULL, /* show_page */ - - _cairo_win32_surface_get_extents, - NULL, /* get_font_options */ - - _cairo_win32_surface_flush, - NULL, /* mark_dirty_rectangle */ - - NULL, /* paint */ - NULL, /* mask */ - NULL, /* stroke */ - NULL, /* fill */ - NULL, /* fill/stroke */ - _cairo_win32_surface_show_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_int_status_t -_cairo_win32_save_initial_clip (HDC hdc, cairo_win32_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 ("cairo_win32_surface_create"); - SetGraphicsMode (hdc, gm); - /* XXX: Can we make a more reasonable guess at the error cause here? */ - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - - surface->clip_rect.x = rect.left; - surface->clip_rect.y = rect.top; - surface->clip_rect.width = rect.right - rect.left; - surface->clip_rect.height = rect.bottom - rect.top; - - 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_int_status_t -_cairo_win32_restore_initial_clip (cairo_win32_surface_t *surface) -{ - cairo_int_status_t status = CAIRO_STATUS_SUCCESS; - - XFORM saved_xform; - int gm = GetGraphicsMode (surface->dc); - if (gm == GM_ADVANCED) { - GetWorldTransform (surface->dc, &saved_xform); - ModifyWorldTransform (surface->dc, NULL, MWT_IDENTITY); - } - - /* initial_clip_rgn will either be a real region or NULL (which means reset to no clip region) */ - SelectClipRgn (surface->dc, surface->initial_clip_rgn); - - if (surface->had_simple_clip) { - /* then if we had a simple clip, intersect */ - IntersectClipRect (surface->dc, - surface->clip_rect.x, - surface->clip_rect.y, - surface->clip_rect.x + surface->clip_rect.width, - surface->clip_rect.y + surface->clip_rect.height); - } - - if (gm == GM_ADVANCED) - SetWorldTransform (surface->dc, &saved_xform); - - return status; -} - -void -_cairo_win32_debug_dump_hrgn (HRGN rgn, char *header) -{ - RGNDATA *rd; - unsigned int z; - - if (header) - fprintf (stderr, "%s\n", header); - - if (rgn == NULL) { - fprintf (stderr, " NULL\n"); - } - - z = GetRegionData(rgn, 0, NULL); - rd = (RGNDATA*) malloc(z); - z = GetRegionData(rgn, z, rd); - - fprintf (stderr, " %ld rects, bounds: %ld %ld %ld %ld\n", - rd->rdh.nCount, - rd->rdh.rcBound.left, - rd->rdh.rcBound.top, - rd->rdh.rcBound.right - rd->rdh.rcBound.left, - rd->rdh.rcBound.bottom - rd->rdh.rcBound.top); - - for (z = 0; z < rd->rdh.nCount; z++) { - RECT r = ((RECT*)rd->Buffer)[z]; - fprintf (stderr, " [%d]: [%ld %ld %ld %ld]\n", - z, r.left, r.top, r.right - r.left, r.bottom - r.top); - } - - free(rd); - fflush (stderr); -} diff --git a/src/cairo-system.c b/src/win32/cairo-win32-system.c similarity index 94% rename from src/cairo-system.c rename to src/win32/cairo-win32-system.c index 1ff4d078f..878553009 100644 --- a/src/cairo-system.c +++ b/src/win32/cairo-win32-system.c @@ -47,8 +47,6 @@ #include "cairoint.h" - - #if CAIRO_MUTEX_IMPL_WIN32 #if !CAIRO_WIN32_STATIC_BUILD @@ -61,11 +59,6 @@ # define _WIN32_WINNT 0x0500 #endif -#include "cairo-clip-private.h" -#include "cairo-paginated-private.h" -#include "cairo-win32-private.h" -#include "cairo-scaled-font-subsets-private.h" - #include /* declare to avoid "no previous prototype for 'DllMain'" warning */ @@ -94,4 +87,3 @@ DllMain (HINSTANCE hinstDLL, #endif #endif -