[cairo-commit] 8 commits - src/cairo-mutex-impl-private.h src/cairo-win32-printing-surface.c src/cairo-win32-private.h src/cairo-win32-surface.c

Adrian Johnson ajohnson at kemper.freedesktop.org
Tue Sep 22 06:18:21 PDT 2009


 src/cairo-mutex-impl-private.h     |   11 ++-
 src/cairo-win32-printing-surface.c |  131 +++++++++++++++++++++++++++++++------
 src/cairo-win32-private.h          |    2 
 src/cairo-win32-surface.c          |   13 ++-
 4 files changed, 133 insertions(+), 24 deletions(-)

New commits:
commit e74cb7fa3eb9a9bcdeb298d969b70fd99ba50f3d
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue Sep 22 22:44:34 2009 +0930

    win32-printing: correct the use of the CAIRO_HAS_WIN32_FONT #ifdef
    
    it was wrapping code required for non windows fonts.

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 914b4ca..8203e6a 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1479,6 +1479,7 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
 	    else
 		return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
 	}
+#endif
 
 	/* For non win32 fonts we need to check that each glyph has a
 	 * path available. If a path is not available,
@@ -1494,7 +1495,6 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
 	    if (status)
 		return status;
 	}
-#endif
 
 	return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
     }
commit 3dd2cc8f6d84253f93affecd3022c9fe4a25d60f
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue Sep 22 22:40:53 2009 +0930

    win32-printing: fix meta surface pattern regression caused by bed2701e

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 00a84a3..914b4ca 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -418,6 +418,8 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t   *surfa
     if (status)
 	return status;
 
+    _cairo_box_round_to_rectangle (&bbox, &meta_extents);
+
     status = _cairo_win32_printing_surface_get_ctm_clip_box (surface, &clip);
     if (status)
 	return status;
commit 7658635c654b694b516e5dd44a43611d94e91abd
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue Sep 22 22:36:20 2009 +0930

    win32-printing: Allow GDI CTM with scale < 1 to be set
    
    To better support creating EMF files with the win32-printing surface,
    allow a GDI CTM with scale < 1 to be used.
    
    http://lists.cairographics.org/archives/cairo/2009-September/018110.html

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index ea5dd35..00a84a3 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -354,11 +354,13 @@ _cairo_win32_printing_surface_get_ctm_clip_box (cairo_win32_surface_t *surface,
     XFORM xform;
 
     _cairo_matrix_to_win32_xform (&surface->ctm, &xform);
+    if (!ModifyWorldTransform (surface->dc, &xform, MWT_LEFTMULTIPLY))
+	return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:ModifyWorldTransform");
+    GetClipBox (surface->dc, clip);
+
+    _cairo_matrix_to_win32_xform (&surface->gdi_ctm, &xform);
     if (!SetWorldTransform (surface->dc, &xform))
 	return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:SetWorldTransform");
-    GetClipBox (surface->dc, clip);
-    if (!ModifyWorldTransform (surface->dc, &xform, MWT_IDENTITY))
-	return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:ModifyWorldTransform");
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -716,7 +718,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t   *surf
     /* _cairo_pattern_set_matrix guarantees invertibility */
     assert (status == CAIRO_STATUS_SUCCESS);
 
-    cairo_matrix_multiply (&m, &m, &surface->ctm);
+    cairo_matrix_multiply (&m, &m, &surface->gdi_ctm);
     SaveDC (surface->dc);
     _cairo_matrix_to_win32_xform (&m, &xform);
 
@@ -1340,7 +1342,7 @@ _cairo_win32_printing_surface_stroke (void			*abstract_surface,
     xform.eDx = 0.0f;
     xform.eDy = 0.0f;
 
-    if (!SetWorldTransform (surface->dc, &xform))
+    if (!ModifyWorldTransform (surface->dc, &xform, MWT_LEFTMULTIPLY))
 	return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SetWorldTransform");
 
     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
@@ -1352,7 +1354,8 @@ _cairo_win32_printing_surface_stroke (void			*abstract_surface,
 	    return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectClipPath");
 
 	/* Return to device space to paint the pattern */
-	if (!ModifyWorldTransform (surface->dc, &xform, MWT_IDENTITY))
+	_cairo_matrix_to_win32_xform (&surface->gdi_ctm, &xform);
+	if (!SetWorldTransform (surface->dc, &xform))
 	    return _cairo_win32_print_gdi_error ("_win32_surface_stroke:ModifyWorldTransform");
 	status = _cairo_win32_printing_surface_paint_pattern (surface, source);
     }
@@ -1551,10 +1554,11 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
 	    glyphs = type1_glyphs;
 	}
 
-	if (surface->has_ctm) {
+	if (surface->has_ctm || surface->has_gdi_ctm) {
+	    cairo_matrix_multiply (&ctm, &surface->ctm, &surface->gdi_ctm);
 	    for (i = 0; i < num_glyphs; i++)
-		cairo_matrix_transform_point (&surface->ctm, &glyphs[i].x, &glyphs[i].y);
-	    cairo_matrix_multiply (&ctm, &scaled_font->ctm, &surface->ctm);
+		cairo_matrix_transform_point (&ctm, &glyphs[i].x, &glyphs[i].y);
+	    cairo_matrix_multiply (&ctm, &scaled_font->ctm, &ctm);
 	    scaled_font = cairo_scaled_font_create (scaled_font->font_face,
 						    &scaled_font->font_matrix,
 						    &ctm,
@@ -1642,16 +1646,67 @@ _cairo_win32_printing_surface_start_page (void *abstract_surface)
 
     SaveDC (surface->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
+     * rounding errors. For example the obvious way to paint a meta
+     * pattern is to:
+     *
+     *   SaveDC()
+     *   transform the device context DC by the pattern to device matrix
+     *   replay the meta surface
+     *   RestoreDC()
+     *
+     * The problem here is that if the pattern to device matrix is
+     * [100 0 0 100 0 0], coordinates in the meta pattern such as
+     * (1.56, 2.23) which correspond to (156, 223) in device space
+     * will be rounded to (100, 200) due to (1.56, 2.23) being
+     * truncated to integers.
+     *
+     * This is solved by saving the current GDI CTM in surface->ctm,
+     * switch the GDI CTM to identity, and transforming all
+     * coordinates by surface->ctm before passing them to GDI. When
+     * painting a meta pattern, surface->ctm is transformed by the
+     * pattern to device matrix.
+     *
+     * For printing device contexts where 1 unit is 1 dpi, switching
+     * the GDI CTM to identity maximises the possible resolution of
+     * coordinates.
+     *
+     * If the device context is an EMF file, using an identity
+     * transform often provides insufficent resolution. The workaround
+     * is to set the GDI CTM to a scale < 1 eg [1.0/16 0 0 1/0/16 0 0]
+     * and scale the cairo CTM by [16 0 0 16 0 0]. The
+     * SetWorldTransform function call to scale the GDI CTM by 1.0/16
+     * will be recorded in the EMF followed by all the graphics
+     * functions by their coordinateds multiplied by 16.
+     *
+     * 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);
-    surface->ctm.xx = xform.eM11;
-    surface->ctm.xy = xform.eM21;
-    surface->ctm.yx = xform.eM12;
-    surface->ctm.yy = xform.eM22;
-    surface->ctm.x0 = xform.eDx;
-    surface->ctm.y0 = xform.eDy;
-    surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
+    if (xform.eM11 < 1 && xform.eM22 < 1) {
+	cairo_matrix_init_identity (&surface->ctm);
+	surface->gdi_ctm.xx = xform.eM11;
+	surface->gdi_ctm.xy = xform.eM21;
+	surface->gdi_ctm.yx = xform.eM12;
+	surface->gdi_ctm.yy = xform.eM22;
+	surface->gdi_ctm.x0 = xform.eDx;
+	surface->gdi_ctm.y0 = xform.eDy;
+    } else {
+	surface->ctm.xx = xform.eM11;
+	surface->ctm.xy = xform.eM21;
+	surface->ctm.yx = xform.eM12;
+	surface->ctm.yy = xform.eM22;
+	surface->ctm.x0 = xform.eDx;
+	surface->ctm.y0 = xform.eDy;
+	cairo_matrix_init_identity (&surface->gdi_ctm);
+	if (!ModifyWorldTransform (surface->dc, NULL, MWT_IDENTITY))
+	    return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_start_page:ModifyWorldTransform");
+    }
 
+    surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
+    surface->has_gdi_ctm = !_cairo_matrix_is_identity (&surface->gdi_ctm);
     inverse_ctm = surface->ctm;
     status = cairo_matrix_invert (&inverse_ctm);
     if (status)
@@ -1662,9 +1717,6 @@ _cairo_win32_printing_surface_start_page (void *abstract_surface)
     cairo_matrix_transform_distance (&inverse_ctm, &x_res, &y_res);
     _cairo_surface_set_resolution (&surface->base, x_res, y_res);
 
-    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;
diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h
index c1040e8..4d0f85e 100644
--- a/src/cairo-win32-private.h
+++ b/src/cairo-win32-private.h
@@ -96,6 +96,8 @@ typedef struct _cairo_win32_surface {
     cairo_bool_t path_empty;
     cairo_bool_t has_ctm;
     cairo_matrix_t ctm;
+    cairo_bool_t has_gdi_ctm;
+    cairo_matrix_t gdi_ctm;
     HBRUSH brush, old_brush;
     cairo_scaled_font_subsets_t *font_subsets;
 } cairo_win32_surface_t;
commit 19c091670302fd23a676e680308df49a4ba06687
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue Sep 22 22:35:33 2009 +0930

    Make win32 fonts work in EMF files created by win32-printing

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index f20b5f9..ea5dd35 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -123,6 +123,42 @@ _cairo_win32_printing_surface_init_image_support (cairo_win32_surface_t *surface
 	surface->flags |= CAIRO_WIN32_SURFACE_CAN_CHECK_PNG;
 }
 
+/* When creating an EMF file, ExtTextOut with ETO_GLYPH_INDEX does not
+ * work unless the GDI function GdiInitializeLanguagePack() has been
+ * called.
+ *
+ *   http://m-a-tech.blogspot.com/2009/04/emf-buffer-idiocracy.html
+ *
+ * The only information I could find on the how to use this
+ * undocumented function is the use in:
+ *
+ * http://src.chromium.org/viewvc/chrome/trunk/src/chrome/renderer/render_process.cc?view=markup
+ *
+ * to solve the same problem. The above code first checks if LPK.DLL
+ * is already loaded. If it is not it calls
+ * GdiInitializeLanguagePack() using the prototype
+ *   BOOL GdiInitializeLanguagePack (int)
+ * and argument 0.
+ */
+static void
+_cairo_win32_printing_surface_init_language_pack (cairo_win32_surface_t *surface)
+{
+    typedef BOOL (WINAPI *gdi_init_lang_pack_func_t)(int);
+    gdi_init_lang_pack_func_t gdi_init_lang_pack;
+    HMODULE module;
+
+    if (GetModuleHandleW (L"LPK.DLL"))
+	return;
+
+    module = GetModuleHandleW (L"GDI32.DLL");
+    if (module) {
+	gdi_init_lang_pack = (gdi_init_lang_pack_func_t)
+	    GetProcAddress (module, "GdiInitializeLanguagePack");
+	if (gdi_init_lang_pack)
+	    gdi_init_lang_pack (0);
+    }
+}
+
 static cairo_int_status_t
 analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern)
 {
@@ -1713,6 +1749,7 @@ cairo_win32_printing_surface_create (HDC hdc)
 
     _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_win32_printing_surface_backend,
                          CAIRO_CONTENT_COLOR_ALPHA);
commit f01a54266d57763635f984982bec001a393d8aa2
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue Sep 22 22:34:56 2009 +0930

    Fix compiler warnings in win32-surface

diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index f6fd66b..c250668 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -2149,7 +2149,7 @@ void
 _cairo_win32_debug_dump_hrgn (HRGN rgn, char *header)
 {
     RGNDATA *rd;
-    int z;
+    unsigned int z;
 
     if (header)
 	fprintf (stderr, "%s\n", header);
@@ -2162,11 +2162,17 @@ _cairo_win32_debug_dump_hrgn (HRGN rgn, char *header)
     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);
+    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]: [%d %d %d %d]\n", z, r.left, r.top, r.right - r.left, r.bottom - r.top);
+	fprintf (stderr, " [%d]: [%ld %ld %ld %ld]\n",
+		 z, r.left, r.top, r.right - r.left, r.bottom - r.top);
     }
 
     free(rd);
commit 23663e2078e34659af43bd0e62bb1fb7a94cc71e
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue Sep 22 22:34:21 2009 +0930

    Fix compiler error on cygwin

diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 69afa17..f6fd66b 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -53,6 +53,7 @@
 #include "cairo-scaled-font-subsets-private.h"
 #include "cairo-surface-fallback-private.h"
 
+#include <wchar.h>
 #include <windows.h>
 
 #if defined(__MINGW32__) && !defined(ETO_PDY)
commit 7ecd413fab7c55918c6f3c4c272b5e8b5aa89aa7
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue Sep 22 22:33:14 2009 +0930

    Add WINVER defines to cairo-mutex-impl-privaye.h
    
    The WINVER defines should always be defined before including windows.h

diff --git a/src/cairo-mutex-impl-private.h b/src/cairo-mutex-impl-private.h
index 4aeaa86..f601db9 100644
--- a/src/cairo-mutex-impl-private.h
+++ b/src/cairo-mutex-impl-private.h
@@ -170,6 +170,15 @@
 
 #elif defined(_WIN32) /******************************************************/
 
+#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 <windows.h>
 
   typedef CRITICAL_SECTION cairo_mutex_impl_t;
commit 605ec22ab5103e16052591517f86fe558133fb8e
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue Sep 22 22:17:27 2009 +0930

    Use _WIN32 to check for win32 mutex
    
    Commit 535bcaa1 moved pthread after win32 to fix mingw build
    problems. However this breaks cygwin builds.
    
    On cygwin HAVE_WINDOWS_H is defined but _WIN32 is not. This was
    causing windows.h to be included which defines _WIN32. As a result the
    win32 code in cairo-misc.c was being compiled but the win32 declaration
    in cairint.h was not included.
    
    Fix this by using _WIN32 to enable the win32 mutex functions since
    _WIN32 is defined by mingw, visual C++, and winegcc, but not
    cygwin. On cygwin, posix functions are preferred as it is a unix
    emulation environment.

diff --git a/src/cairo-mutex-impl-private.h b/src/cairo-mutex-impl-private.h
index 8ab7600..4aeaa86 100644
--- a/src/cairo-mutex-impl-private.h
+++ b/src/cairo-mutex-impl-private.h
@@ -168,7 +168,7 @@
 # define CAIRO_MUTEX_IMPL_UNLOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
 # define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
 
-#elif defined(HAVE_WINDOWS_H) || defined(_MSC_VER) /*************************/
+#elif defined(_WIN32) /******************************************************/
 
 # include <windows.h>
 


More information about the cairo-commit mailing list