[cairo-commit] 5 commits - src/cairo-reference-count-private.h src/cairo-win32.h src/cairo-win32-printing-surface.c src/cairo-win32-private.h src/cairo-win32-surface.c

Vladimir Vukicevic vladimir at kemper.freedesktop.org
Tue Oct 9 14:28:33 PDT 2007


 src/cairo-reference-count-private.h |    2 
 src/cairo-win32-printing-surface.c  |   16 ---
 src/cairo-win32-private.h           |    5 -
 src/cairo-win32-surface.c           |  175 +++++++++++++++++++++---------------
 src/cairo-win32.h                   |    3 
 5 files changed, 113 insertions(+), 88 deletions(-)

New commits:
diff-tree be7d1f0f8f84ddac9e8c7dda4aa39f88806a5e39 (from 712c3cda44d7023316b93a1241e66aabde15d668)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Tue Oct 9 14:27:53 2007 -0700

    Simplify CAIRO_REFERENCE_COUNT_INVALID macro
    
    MSVC doesn't like the previous anonymous structure/cast, so simplify
    to just a bare {} structure for use as an initializer.

diff --git a/src/cairo-reference-count-private.h b/src/cairo-reference-count-private.h
index 2d1d81b..aef8a1f 100644
--- a/src/cairo-reference-count-private.h
+++ b/src/cairo-reference-count-private.h
@@ -55,7 +55,7 @@ typedef struct {
 #define CAIRO_REFERENCE_COUNT_SET_VALUE(RC, VALUE) _cairo_atomic_int_set (&(RC)->ref_count, (VALUE))
 
 #define CAIRO_REFERENCE_COUNT_INVALID_VALUE ((cairo_atomic_int_t) -1)
-#define CAIRO_REFERENCE_COUNT_INVALID ((cairo_reference_count_t) {CAIRO_REFERENCE_COUNT_INVALID_VALUE})
+#define CAIRO_REFERENCE_COUNT_INVALID {CAIRO_REFERENCE_COUNT_INVALID_VALUE}
 
 #define CAIRO_REFERENCE_COUNT_IS_INVALID(RC) (CAIRO_REFERENCE_COUNT_GET_VALUE (RC) == CAIRO_REFERENCE_COUNT_INVALID_VALUE)
 
diff-tree 712c3cda44d7023316b93a1241e66aabde15d668 (from c99d33b10e84883ade1402c3c1d1efdb4b46f66e)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Tue Oct 9 13:56:51 2007 -0700

    [win32] reduce GDI object usage
    
    Only create region objects if they're necessary; this significantly reduces
    the number of GDI objects in use by cairo surfaces.

diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 2f31697..21336de 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -358,11 +358,7 @@ _cairo_win32_surface_create_for_dc (HDC 
     surface->clip_rect.width = width;
     surface->clip_rect.height = height;
 
-    surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
-    if (GetClipRgn (surface->dc, surface->saved_clip) == 0) {
-	DeleteObject(surface->saved_clip);
-	surface->saved_clip = NULL;
-    }
+    surface->saved_clip = NULL;
 
     surface->extents = surface->clip_rect;
 
@@ -409,13 +405,9 @@ _cairo_win32_surface_create_similar_inte
 	/* otherwise, create a ddb */
 	HBITMAP ddb = CreateCompatibleBitmap (src->dc, width, height);
 	HDC ddb_dc = CreateCompatibleDC (src->dc);
-	HRGN crgn = CreateRectRgn (0, 0, width, height);
 	HBITMAP saved_dc_bitmap;
 
 	saved_dc_bitmap = SelectObject (ddb_dc, ddb);
-	SelectClipRgn (ddb_dc, crgn);
-
-	DeleteObject (crgn);
 
 	new_surf = (cairo_win32_surface_t*) cairo_win32_surface_create (ddb_dc);
 	new_surf->bitmap = ddb;
@@ -486,16 +478,33 @@ _cairo_win32_surface_finish (void *abstr
     if (surface->image)
 	cairo_surface_destroy (surface->image);
 
-    if (surface->saved_clip)
-	DeleteObject (surface->saved_clip);
-
     /* 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 {
+	/* otherwise, restore the old clip region on the DC */
+	SelectClipRgn (surface->dc, surface->saved_clip);
+
+	if (surface->saved_clip == NULL) {
+	    /* We never had a clip region, so just restore the clip
+	     * to the bounds. */
+	    if (surface->clip_rect.width != 0 &&
+		surface->clip_rect.height != 0)
+	    {
+		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 (surface->saved_clip)
+	DeleteObject (surface->saved_clip);
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -1422,7 +1431,7 @@ _cairo_win32_surface_set_clip_region (vo
 				      cairo_region_t *region)
 {
     cairo_win32_surface_t *surface = abstract_surface;
-    cairo_status_t status;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
     /* If we are in-memory, then we set the clip on the image surface
      * as well as on the underlying GDI surface.
@@ -1445,12 +1454,10 @@ _cairo_win32_surface_set_clip_region (vo
 	if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR)
 	    return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region (reset)");
 
-	return CAIRO_STATUS_SUCCESS;
-
+	status = CAIRO_STATUS_SUCCESS;
     } else {
 	cairo_rectangle_int_t extents;
 	cairo_box_int_t *boxes;
-	cairo_status_t status;
 	int num_boxes;
 	RGNDATA *data;
 	size_t data_size;
@@ -1465,56 +1472,72 @@ _cairo_win32_surface_set_clip_region (vo
 	if (status)
 	    return status;
 
-	data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT);
-	data = malloc (data_size);
-	if (!data) {
-	    _cairo_region_boxes_fini (region, boxes);
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	}
-	rects = (RECT *)data->Buffer;
+	if (num_boxes == 1 && 
+	    boxes[0].p1.x == 0 &&
+	    boxes[0].p1.y == 0 &&
+	    boxes[0].p2.x == surface->extents.width &&
+	    boxes[0].p2.y == surface->extents.height)
+	{
+	    gdi_region = NULL;
 
-	data->rdh.dwSize = sizeof (RGNDATAHEADER);
-	data->rdh.iType = RDH_RECTANGLES;
-	data->rdh.nCount = num_boxes;
-	data->rdh.nRgnSize = num_boxes * 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_boxes; i++) {
-	    rects[i].left = boxes[i].p1.x;
-	    rects[i].top = boxes[i].p1.y;
-	    rects[i].right = boxes[i].p2.x;
-	    rects[i].bottom = boxes[i].p2.y;
-	}
+	    SelectClipRgn (surface->dc, NULL);
+	    IntersectClipRect (surface->dc,
+			       boxes[0].p1.x,
+			       boxes[0].p1.y,
+			       boxes[0].p2.x,
+			       boxes[0].p2.y);
 
-	_cairo_region_boxes_fini (region, boxes);
+	    _cairo_region_boxes_fini (region, boxes);
+	} else {
+	    data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT);
+	    data = malloc (data_size);
+	    if (!data) {
+		_cairo_region_boxes_fini (region, boxes);
+		return _cairo_error(CAIRO_STATUS_NO_MEMORY);
+	    }
+	    rects = (RECT *)data->Buffer;
 
-	gdi_region = ExtCreateRegion (NULL, data_size, data);
-	free (data);
+	    data->rdh.dwSize = sizeof (RGNDATAHEADER);
+	    data->rdh.iType = RDH_RECTANGLES;
+	    data->rdh.nCount = num_boxes;
+	    data->rdh.nRgnSize = num_boxes * 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_boxes; i++) {
+		rects[i].left = boxes[i].p1.x;
+		rects[i].top = boxes[i].p1.y;
+		rects[i].right = boxes[i].p2.x;
+		rects[i].bottom = boxes[i].p2.y;
+	    }
 
-	if (!gdi_region)
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    _cairo_region_boxes_fini (region, boxes);
 
-	/* Combine the new region with the original clip */
+	    gdi_region = ExtCreateRegion (NULL, data_size, data);
+	    free (data);
 
-	if (surface->saved_clip) {
-	    if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR)
-		goto FAIL;
-	}
+	    if (!gdi_region)
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-	if (SelectClipRgn (surface->dc, gdi_region) == ERROR)
-	    goto FAIL;
+	    /* Combine the new region with the original clip */
+	    if (surface->saved_clip) {
+		if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR)
+		    status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
+	    }
 
-	DeleteObject (gdi_region);
-	return CAIRO_STATUS_SUCCESS;
+	    /* Then select the new clip region into our surface if everything went ok */
+	    if (status == CAIRO_STATUS_SUCCESS) {
+		if (SelectClipRgn (surface->dc, gdi_region) == ERROR)
+		    status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
+	    }
 
-    FAIL:
-	status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
-	DeleteObject (gdi_region);
-	return status;
+	    DeleteObject (gdi_region);
+	}
     }
+
+    return status;
 }
 
 cairo_int_status_t
@@ -1693,10 +1716,12 @@ cairo_win32_surface_create (HDC hdc)
     RECT rect;
     int depth;
     cairo_format_t format;
+    int clipBoxType;
 
     /* Try to figure out the drawing bounds for the Device context
      */
-    if (GetClipBox (hdc, &rect) == ERROR) {
+    clipBoxType = GetClipBox (hdc, &rect);
+    if (clipBoxType == ERROR) {
 	_cairo_win32_print_gdi_error ("cairo_win32_surface_create");
 	/* XXX: Can we make a more reasonable guess at the error cause here? */
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -1745,16 +1770,15 @@ cairo_win32_surface_create (HDC hdc)
     surface->clip_rect.width = (uint16_t) (rect.right - rect.left);
     surface->clip_rect.height = (uint16_t) (rect.bottom - rect.top);
 
-    if (surface->clip_rect.width == 0 ||
-	surface->clip_rect.height == 0)
-    {
-	surface->saved_clip = NULL;
-    } else {
+    if (clipBoxType == COMPLEXREGION) {
 	surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
 	if (GetClipRgn (hdc, surface->saved_clip) == 0) {
+	    /* this should never happen */
 	    DeleteObject(surface->saved_clip);
 	    surface->saved_clip = NULL;
 	}
+    } else {
+	surface->saved_clip = NULL;
     }
 
     surface->extents = surface->clip_rect;
@@ -1814,7 +1838,6 @@ cairo_win32_surface_create_with_ddb (HDC
     cairo_win32_surface_t *new_surf;
     HBITMAP ddb;
     HDC screen_dc, ddb_dc;
-    HRGN crgn;
     HBITMAP saved_dc_bitmap;
 
     if (format != CAIRO_FORMAT_RGB24)
@@ -1834,7 +1857,7 @@ cairo_win32_surface_create_with_ddb (HDC
     ddb_dc = CreateCompatibleDC (hdc);
     if (ddb_dc == NULL) {
 	_cairo_win32_print_gdi_error("CreateCompatibleDC");
-	new_surf = NIL_SURFACE;
+	new_surf = (cairo_win32_surface_t*) NIL_SURFACE;
 	goto FINISH;
     }
 
@@ -1847,16 +1870,12 @@ cairo_win32_surface_create_with_ddb (HDC
 	 * video memory is probably exhausted.
 	 */
 	_cairo_win32_print_gdi_error("CreateCompatibleBitmap");
-	new_surf = NIL_SURFACE;
+	new_surf = (cairo_win32_surface_t*) NIL_SURFACE;
 	goto FINISH;
     }
 
     saved_dc_bitmap = SelectObject (ddb_dc, ddb);
 
-    crgn = CreateRectRgn (0, 0, width, height);
-    SelectClipRgn (ddb_dc, crgn);
-    DeleteObject (crgn);
-
     new_surf = (cairo_win32_surface_t*) cairo_win32_surface_create (ddb_dc);
     new_surf->bitmap = ddb;
     new_surf->saved_dc_bitmap = saved_dc_bitmap;
diff-tree c99d33b10e84883ade1402c3c1d1efdb4b46f66e (from 4dbf495515d6de933de7f567b935c5fdceed5f6f)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Tue Oct 2 10:54:44 2007 -0700

    [win32] return a nil surface, not NULL
    
    Missed an error return

diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 9a6e715..2f31697 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -1818,7 +1818,7 @@ cairo_win32_surface_create_with_ddb (HDC
     HBITMAP saved_dc_bitmap;
 
     if (format != CAIRO_FORMAT_RGB24)
-	return NULL;
+	return NIL_SURFACE;
 /* XXX handle these eventually
 	format != CAIRO_FORMAT_A8 ||
 	format != CAIRO_FORMAT_A1)
diff-tree 4dbf495515d6de933de7f567b935c5fdceed5f6f (from 61ba63f3a0947bc89310f04e9bc1694fb6451c11)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Tue Oct 2 10:48:59 2007 -0700

    [win32] report error correctly if CreateCompatibleBitmap fails
    
    These errors were being dropped on the floor, leading to
    rendering errors in out of video memory conditions.

diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 7b94325..9a6e715 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -1831,8 +1831,25 @@ cairo_win32_surface_create_with_ddb (HDC
 	screen_dc = NULL;
     }
 
-    ddb = CreateCompatibleBitmap (hdc, width, height);
     ddb_dc = CreateCompatibleDC (hdc);
+    if (ddb_dc == NULL) {
+	_cairo_win32_print_gdi_error("CreateCompatibleDC");
+	new_surf = NIL_SURFACE;
+	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.
+	 */
+	_cairo_win32_print_gdi_error("CreateCompatibleBitmap");
+	new_surf = NIL_SURFACE;
+	goto FINISH;
+    }
 
     saved_dc_bitmap = SelectObject (ddb_dc, ddb);
 
@@ -1845,6 +1862,7 @@ cairo_win32_surface_create_with_ddb (HDC
     new_surf->saved_dc_bitmap = saved_dc_bitmap;
     new_surf->is_dib = FALSE;
 
+FINISH:
     if (screen_dc)
 	ReleaseDC (NULL, screen_dc);
 
diff-tree 61ba63f3a0947bc89310f04e9bc1694fb6451c11 (from b12ed375cf7ad02a30324616e121a1e9ab8998cb)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Fri Sep 21 11:18:17 2007 -0700

    [win32] remove ignore_operators flag from win32 printing surface
    
    Remove the ignore_operators fallback-avoiding workaround; if apps
    want that same behaviour, they'll have to implement it themselves
    by taking care when calling cairo_set_operator().

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 839f3cd..fd8efc1 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -147,11 +147,10 @@ _cairo_win32_printing_surface_analyze_op
 	op == CAIRO_OPERATOR_CLEAR)
 	return CAIRO_STATUS_SUCCESS;
 
-    /* If IGNORE_OPERATORS was set, then we pretend everything is
-     * OVER/SOURCE.  Otherwise, we go to fallback.
+    /* If the operation is anything other than CLEAR, SOURCE, or
+     * OVER, we have to go to fallback.
      */
-    if (!(surface->flags & CAIRO_WIN32_SURFACE_IGNORE_OPERATORS) &&
-	op != CAIRO_OPERATOR_OVER)
+    if (op != CAIRO_OPERATOR_OVER)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
@@ -1084,8 +1083,6 @@ _cairo_win32_printing_surface_set_pagina
 /**
  * cairo_win32_printing_surface_create:
  * @hdc: the DC to create a surface for
- * @ignore_operators: whether operators other than CLEAR and OVER
- *   should be treated as SOURCE
  *
  * 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
@@ -1097,13 +1094,10 @@ _cairo_win32_printing_surface_set_pagina
  * provide correct complex renderinf behaviour; show_page() and
  * associated methods must be used for correct output.
  *
- * If ignore_operators is TRUE, the rendering may be incorrect;
- * however, the chances of hitting fallback code are much reduced.
- *
  * Return value: the newly created surface
  **/
 cairo_surface_t *
-cairo_win32_printing_surface_create (HDC hdc, cairo_bool_t ignore_operators)
+cairo_win32_printing_surface_create (HDC hdc)
 {
     cairo_win32_surface_t *surface;
     RECT rect;
@@ -1155,8 +1149,6 @@ cairo_win32_printing_surface_create (HDC
 
     surface->flags = _cairo_win32_flags_for_dc (surface->dc);
     surface->flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING;
-    if (ignore_operators)
-	surface->flags |= CAIRO_WIN32_SURFACE_IGNORE_OPERATORS;
     surface->clip_saved_dc = 0;
 
     _cairo_win32_printing_surface_init_ps_mode (surface);
diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h
index 3410b34..eddde36 100644
--- a/src/cairo-win32-private.h
+++ b/src/cairo-win32-private.h
@@ -108,11 +108,6 @@ enum {
 
     /* Whether we can use GradientFill rectangles with this surface */
     CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT = (1<<6),
-
-    /* If we should treat all operators other than CLEAR and OVER
-     * like SOURCE to avoid hitting fallback.  Ignored except
-     * for printing. */
-    CAIRO_WIN32_SURFACE_IGNORE_OPERATORS = (1<<7)
 };
 
 cairo_status_t
diff --git a/src/cairo-win32.h b/src/cairo-win32.h
index 43ddf12..933133f 100644
--- a/src/cairo-win32.h
+++ b/src/cairo-win32.h
@@ -1,3 +1,4 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2005 Red Hat, Inc
@@ -48,7 +49,7 @@ cairo_public cairo_surface_t *
 cairo_win32_surface_create (HDC hdc);
 
 cairo_public cairo_surface_t *
-cairo_win32_printing_surface_create (HDC hdc, cairo_bool_t ignore_operators);
+cairo_win32_printing_surface_create (HDC hdc);
 
 cairo_public cairo_surface_t *
 cairo_win32_surface_create_with_ddb (HDC hdc,


More information about the cairo-commit mailing list