summaryrefslogtreecommitdiff
path: root/src/cairo-win32-surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-win32-surface.c')
-rw-r--r--src/cairo-win32-surface.c221
1 files changed, 152 insertions, 69 deletions
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 881532b6..69c64069 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);
+}