From 2c45fdfc15a81eae6196f92c9768f3d895bd0819 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sat, 17 Oct 2015 18:32:57 +1030 Subject: [PATCH] win32-print: Fix the page extents As the page size can be changed between pages, set the extents in _start_page. The extents are invalidated in _show_page since the page size on the DC may be changed after this call. The only thing that uses the extents between _show_page and _start_page (and before the first _start_page) is the creation of the recording surface in the paginated surface. In this case, when the paginated surface can't get the extents, it will create an unbounded recording surface. The extents x,y is always set to 0 to prevent the replay from translating the page. --- src/win32/cairo-win32-printing-surface.c | 48 ++++++++++++++++++++---- src/win32/cairo-win32-private.h | 1 + 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/win32/cairo-win32-printing-surface.c b/src/win32/cairo-win32-printing-surface.c index cce704063..4d3b8ce05 100644 --- a/src/win32/cairo-win32-printing-surface.c +++ b/src/win32/cairo-win32-printing-surface.c @@ -1116,6 +1116,11 @@ _cairo_win32_printing_surface_show_page (void *abstract_surface) /* Undo both SaveDC's that we did in start_page */ RestoreDC (surface->win32.dc, -2); + /* Invalidate extents since the size of the next page is not known at + * this point. + */ + surface->extents_valid = FALSE; + return CAIRO_STATUS_SUCCESS; } @@ -1161,6 +1166,18 @@ _cairo_win32_printing_surface_clipper_intersect_clip_path (cairo_surface_clipper return status; } +static cairo_bool_t +_cairo_win32_printing_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_win32_printing_surface_t *surface = abstract_surface; + + if (surface->extents_valid) + *rectangle = surface->win32.extents; + + return surface->extents_valid; +} + static void _cairo_win32_printing_surface_get_font_options (void *abstract_surface, cairo_font_options_t *options) @@ -1706,6 +1723,27 @@ _cairo_win32_printing_surface_start_page (void *abstract_surface) double x_res, y_res; cairo_matrix_t inverse_ctm; cairo_status_t status; + RECT rect; + + /* Since the page size may be changed after _show_page() and before the + * next drawing command, the extents are set in _start_page() and invalidated + * in _show_page(). The paginated surface will obtain the extents immediately + * after calling _show_page() and before any drawing commands. At this point + * the next page will not have been setup on the DC so we return invalid + * extents and the paginated surface will create an unbounded recording surface. + * Prior to replay of the record surface, the paginated surface will call + * _start_page and we setup the correct extents. + * + * Note that we always set the extents x,y to 0 so prevent replay from translating + * the coordinates of objects. Windows will clip anything outside of the page clip + * area. + */ + GetClipBox(surface->win32.dc, &rect); + surface->win32.extents.x = 0; + surface->win32.extents.y = 0; + surface->win32.extents.width = rect.right; + surface->win32.extents.height = rect.bottom; + surface->extents_valid = TRUE; SaveDC (surface->win32.dc); /* Save application context first, before doing MWT */ @@ -1823,7 +1861,6 @@ cairo_win32_printing_surface_create (HDC hdc) { cairo_win32_printing_surface_t *surface; cairo_surface_t *paginated; - RECT rect; surface = malloc (sizeof (cairo_win32_printing_surface_t)); if (surface == NULL) @@ -1843,6 +1880,7 @@ cairo_win32_printing_surface_create (HDC hdc) surface->content = CAIRO_CONTENT_COLOR_ALPHA; surface->win32.dc = hdc; + surface->extents_valid = FALSE; surface->brush = NULL; surface->old_brush = NULL; @@ -1852,12 +1890,6 @@ cairo_win32_printing_surface_create (HDC hdc) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } - GetClipBox(hdc, &rect); - 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->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc); surface->win32.flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING; @@ -1898,7 +1930,7 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = { NULL, /* copy_page */ _cairo_win32_printing_surface_show_page, - _cairo_win32_surface_get_extents, + _cairo_win32_printing_surface_get_extents, _cairo_win32_printing_surface_get_font_options, NULL, /* flush */ diff --git a/src/win32/cairo-win32-private.h b/src/win32/cairo-win32-private.h index b6c24311a..6fdf96f87 100644 --- a/src/win32/cairo-win32-private.h +++ b/src/win32/cairo-win32-private.h @@ -139,6 +139,7 @@ typedef struct _cairo_win32_printing_surface { cairo_matrix_t ctm; cairo_bool_t has_gdi_ctm; cairo_matrix_t gdi_ctm; + cairo_bool_t extents_valid; HBRUSH brush, old_brush; cairo_scaled_font_subsets_t *font_subsets; } cairo_win32_printing_surface_t;