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

Vladimir Vukicevic vladimir at kemper.freedesktop.org
Thu Jan 24 11:31:34 PST 2008


 src/cairo-win32-printing-surface.c |   75 +++++-------
 src/cairo-win32-private.h          |   23 +++
 src/cairo-win32-surface.c          |  221 +++++++++++++++++++++++++------------
 3 files changed, 200 insertions(+), 119 deletions(-)

New commits:
commit b96c6c26c2d6b0b5f79ee569ece602338c4146b2
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Thu Jan 24 11:04:26 2008 -0800

    [win32] Print non-black/white text correctly in show_glyphs

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index cc74bcf..f7b9681 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1328,9 +1328,9 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
 
 	color = _cairo_win32_printing_surface_flatten_transparency (surface,
 								    &solid->color);
-	opaque = cairo_pattern_create_rgb (GetRValue (color),
-					   GetGValue (color),
-					   GetBValue (color));
+	opaque = cairo_pattern_create_rgb (GetRValue (color) / 255.0,
+					   GetGValue (color) / 255.0,
+					   GetBValue (color) / 255.0);
 	if (opaque->status)
 	    return opaque->status;
 	source = opaque;
commit 8e7c0db8018b258fc367da1e5502e9e13bad098c
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Thu Jan 24 11:01:55 2008 -0800

    [win32] Better tracking of initial clip
    
    There were a few corner cases that the win32 surface was failing
    at when there was an initial clip set; the win32-printing surface
    had more serious problems when painting meta surface patterns.
    This cleans up the initial DC clip tracking for both surfaces.

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index ee08d4a..cc74bcf 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -460,11 +460,14 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t   *surfa
 	    EndPath (surface->dc);
 	    SelectClipPath (surface->dc, RGN_AND);
 
+	    SaveDC (surface->dc); /* Allow clip path to be reset during replay */
 	    status = _cairo_meta_surface_replay (meta_surface, &surface->base);
+
+	    /* Restore both the clip save and our earlier path SaveDC */
+	    RestoreDC (surface->dc, -2);
+
 	    if (status)
 		return status;
-
-	    RestoreDC (surface->dc, -1);
 	}
     }
 
@@ -970,9 +973,8 @@ _cairo_win32_printing_surface_show_page (void *abstract_surface)
 {
     cairo_win32_surface_t *surface = abstract_surface;
 
-    if (surface->clip_saved_dc != 0)
-	RestoreDC (surface->dc, surface->clip_saved_dc);
-    RestoreDC (surface->dc, -1);
+    /* Undo both SaveDC's that we did in start_page */
+    RestoreDC (surface->dc, -2);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -991,10 +993,9 @@ _cairo_win32_printing_surface_intersect_clip_path (void		      *abstract_surface
 	return CAIRO_STATUS_SUCCESS;
 
     if (path == NULL) {
-	if (surface->clip_saved_dc != 0) {
-	    RestoreDC (surface->dc, surface->clip_saved_dc);
-	    surface->clip_saved_dc = 0;
-	}
+	RestoreDC (surface->dc, -1);
+	SaveDC (surface->dc);
+
 	return CAIRO_STATUS_SUCCESS;
     }
 
@@ -1013,8 +1014,6 @@ _cairo_win32_printing_surface_intersect_clip_path (void		      *abstract_surface
 	ASSERT_NOT_REACHED;
     }
 
-    if (surface->clip_saved_dc == 0)
-	surface->clip_saved_dc = SaveDC (surface->dc);
     SelectClipPath (surface->dc, RGN_AND);
 
     return status;
@@ -1417,7 +1416,8 @@ _cairo_win32_printing_surface_start_page (void *abstract_surface)
     cairo_win32_surface_t *surface = abstract_surface;
     XFORM xform;
 
-    SaveDC (surface->dc);
+    SaveDC (surface->dc); /* Save application context first, before doing MWT */
+
     SetGraphicsMode (surface->dc, GM_ADVANCED);
     GetWorldTransform(surface->dc, &xform);
     surface->ctm.xx = xform.eM11;
@@ -1430,6 +1430,8 @@ _cairo_win32_printing_surface_start_page (void *abstract_surface)
     if (!ModifyWorldTransform (surface->dc, NULL, MWT_IDENTITY))
 	return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_start_page:ModifyWorldTransform");
 
+    SaveDC (surface->dc); /* Then save Cairo's known-good clip state, so the clip path can be reset */
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -1462,21 +1464,18 @@ cairo_surface_t *
 cairo_win32_printing_surface_create (HDC hdc)
 {
     cairo_win32_surface_t *surface;
-    RECT rect;
     int xr, yr;
-
-    /* Try to figure out the drawing bounds for the Device context
-     */
-    if (GetClipBox (hdc, &rect) == ERROR) {
-	_cairo_win32_print_gdi_error ("cairo_win32_surface_create");
-	/* XXX: Can we make a more reasonable guess at the error cause here? */
-	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-    }
+    RECT rect;
 
     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->image = NULL;
     surface->format = CAIRO_FORMAT_RGB24;
     surface->content = CAIRO_CONTENT_COLOR_ALPHA;
@@ -1488,28 +1487,14 @@ cairo_win32_printing_surface_create (HDC hdc)
     surface->brush = NULL;
     surface->old_brush = NULL;
 
-    surface->clip_rect.x = (int16_t) rect.left;
-    surface->clip_rect.y = (int16_t) rect.top;
-    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 {
-	surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
-	if (GetClipRgn (hdc, surface->saved_clip) == 0) {
-	    DeleteObject(surface->saved_clip);
-	    surface->saved_clip = NULL;
-	}
-    }
-
-    surface->extents = surface->clip_rect;
+    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);
     surface->flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING;
-    surface->clip_saved_dc = 0;
 
     _cairo_win32_printing_surface_init_ps_mode (surface);
     _cairo_surface_init (&surface->base, &cairo_win32_printing_surface_backend,
@@ -1521,8 +1506,8 @@ cairo_win32_printing_surface_create (HDC hdc)
 
     return _cairo_paginated_surface_create (&surface->base,
                                             CAIRO_CONTENT_COLOR_ALPHA,
-                                            rect.right - rect.left,
-                                            rect.bottom - rect.top,
+					    surface->extents.width,
+					    surface->extents.height,
                                             &cairo_win32_surface_paginated_backend);
 }
 
diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h
index 6d30da8..704ec4e 100644
--- a/src/cairo-win32-private.h
+++ b/src/cairo-win32-private.h
@@ -71,12 +71,17 @@ typedef struct _cairo_win32_surface {
 
     cairo_surface_t *image;
 
-    cairo_rectangle_int_t clip_rect;
-
-    HRGN saved_clip;
-
     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;
+
     /* Surface DC flags */
     uint32_t flags;
 
@@ -86,7 +91,6 @@ typedef struct _cairo_win32_surface {
     cairo_bool_t path_empty;
     cairo_bool_t has_ctm;
     cairo_matrix_t ctm;
-    int clip_saved_dc;
     HBRUSH brush, old_brush;
 } cairo_win32_surface_t;
 
@@ -168,4 +172,13 @@ _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_int_status_t
+_cairo_win32_restore_initial_clip (cairo_win32_surface_t *surface);
+
+void
+_cairo_win32_debug_dump_hrgn (HRGN rgn, char *header);
+
 #endif /* CAIRO_WIN32_PRIVATE_H */
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 881532b..69c6406 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -354,7 +354,8 @@ _cairo_win32_surface_create_for_dc (HDC             original_dc,
     surface->clip_rect.width = width;
     surface->clip_rect.height = height;
 
-    surface->saved_clip = NULL;
+    surface->initial_clip_rgn = NULL;
+    surface->had_simple_clip = FALSE;
 
     surface->extents = surface->clip_rect;
 
@@ -473,26 +474,11 @@ _cairo_win32_surface_finish (void *abstract_surface)
 	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);
-	    }
-	}
+	_cairo_win32_restore_initial_clip (surface);
     }
 
-    if (surface->saved_clip)
-	DeleteObject (surface->saved_clip);
+    if (surface->initial_clip_rgn)
+	DeleteObject (surface->initial_clip_rgn);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -565,8 +551,8 @@ _cairo_win32_surface_acquire_source_image (void                    *abstract_sur
     }
 
     status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0,
-						surface->clip_rect.width,
-						surface->clip_rect.height, &local);
+						surface->extents.width,
+						surface->extents.height, &local);
     if (status)
 	return status;
 
@@ -605,8 +591,8 @@ _cairo_win32_surface_acquire_dest_image (void                    *abstract_surfa
 
 	image_rect->x = 0;
 	image_rect->y = 0;
-	image_rect->width = surface->clip_rect.width;
-	image_rect->height = surface->clip_rect.height;
+	image_rect->width = surface->extents.width;
+	image_rect->height = surface->extents.height;
 
 	*image_out = (cairo_image_surface_t *)surface->image;
 	*image_extra = NULL;
@@ -1440,13 +1426,11 @@ _cairo_win32_surface_set_clip_region (void           *abstract_surface,
      * save the original clip when first setting a clip on surface.
      */
 
-    if (region == NULL) {
-	/* Clear any clip set by cairo, return to the original */
-	if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR)
-	    return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region (reset)");
+    /* Clear any clip set by cairo, return to the original first */
+    status = _cairo_win32_restore_initial_clip (surface);
 
-	status = CAIRO_STATUS_SUCCESS;
-    } else {
+    /* Then combine any new region with it */
+    if (region) {
 	cairo_rectangle_int_t extents;
 	cairo_box_int_t *boxes;
 	int num_boxes;
@@ -1480,6 +1464,13 @@ _cairo_win32_surface_set_clip_region (void           *abstract_surface,
 
 	    _cairo_region_boxes_fini (region, boxes);
 	} else {
+	    /* 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_boxes * sizeof (RECT);
 	    data = malloc (data_size);
 	    if (!data) {
@@ -1512,17 +1503,9 @@ _cairo_win32_surface_set_clip_region (void           *abstract_surface,
 	    if (!gdi_region)
 		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-	    /* 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");
-	    }
-
-	    /* 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");
-	    }
+	    /* 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);
 	}
@@ -1704,19 +1687,10 @@ cairo_surface_t *
 cairo_win32_surface_create (HDC hdc)
 {
     cairo_win32_surface_t *surface;
-    RECT rect;
+
     int depth;
     cairo_format_t format;
-    int clipBoxType;
-
-    /* Try to figure out the drawing bounds for the Device context
-     */
-    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? */
-	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-    }
+    RECT rect;
 
     if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY) {
 	depth = GetDeviceCaps(hdc, BITSPIXEL);
@@ -1742,6 +1716,11 @@ cairo_win32_surface_create (HDC hdc)
     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->image = NULL;
     surface->format = format;
 
@@ -1752,26 +1731,13 @@ cairo_win32_surface_create (HDC hdc)
     surface->brush = NULL;
     surface->old_brush = NULL;
 
-    surface->clip_rect.x = (int16_t) rect.left;
-    surface->clip_rect.y = (int16_t) rect.top;
-    surface->clip_rect.width = (uint16_t) (rect.right - rect.left);
-    surface->clip_rect.height = (uint16_t) (rect.bottom - rect.top);
-
-    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;
+    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);
-    surface->clip_saved_dc = 0;
 
     _cairo_surface_init (&surface->base, &cairo_win32_surface_backend,
 			 _cairo_content_from_format (format));
@@ -2041,3 +2007,120 @@ DllMain (HINSTANCE hinstDLL,
 
 #endif
 
+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.
+     * Similarily, 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) == -1) {
+	    /* this should never happen */
+	    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;
+    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, " %d rects, bounds: %d %d %d %d\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]: [%d %d %d %d]\n", z, r.left, r.top, r.right - r.left, r.bottom - r.top);
+    }
+
+    free(rd);
+    fflush (stderr);
+}


More information about the cairo-commit mailing list