From: Robin Dunn Date: Sat, 27 Aug 2011 23:26:53 +0000 (+0000) Subject: * Implement dynamic loading of the Cairo DLL on Windows similar to how it was X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/932d0768aa4ef14b363c1f5989e7c425771ce1ff * Implement dynamic loading of the Cairo DLL on Windows similar to how it was done for GDI+. * Enable the use of the wxCairoContext on MSW. * Enable creating a wxGCDC from an exisiting wxGraphicsContext. * Since it's possible for a DLL that is using wx to not be on the PATH nor in the same location as the .exe, change the wxDynamicLibrary::RawLoad method to explicitly look first in the same place as the main wx-using binary. This way it will find DLLs that are in the same folder as the wx-using binary even if that would not be in the normal DLL search path. * Change wxDCImpl and wxDC::GetLogicalScale to be const methods. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68935 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/build/tools/build-wxwidgets.py b/build/tools/build-wxwidgets.py index 548bb10456..a3d370d20a 100755 --- a/build/tools/build-wxwidgets.py +++ b/build/tools/build-wxwidgets.py @@ -174,6 +174,7 @@ def main(scriptName, args): "mac_framework" : (False, "Install the Mac build as a framework"), "mac_framework_prefix" : (defFwPrefix, "Prefix where the framework should be installed. Default: %s" % defFwPrefix), + "cairo" : (False, "Enable dynamicly loading the Cairo lib for wxGraphicsContext on MSW"), "no_config" : (False, "Turn off configure step on autoconf builds"), "config_only" : (False, "Only run the configure step and then exit"), "rebake" : (False, "Regenerate Bakefile and autoconf files"), @@ -182,7 +183,6 @@ def main(scriptName, args): "cocoa" : (False, "Build the old Mac Cooca port."), "osx_cocoa" : (False, "Build the new Cocoa port"), "shared" : (False, "Build wx as a dynamic library"), - "cairo" : (False, "Build support for wxCairoContext (always true on GTK+)"), "extra_make" : ("", "Extra args to pass on [n]make's command line."), "features" : ("", "A comma-separated list of wxUSE_XYZ defines on Win, or a list of configure flags on unix."), "verbose" : (False, "Print commands as they are run, (to aid with debugging this script)"), @@ -343,6 +343,8 @@ def main(scriptName, args): flags["wxUSE_UNICODE_MSLU"] = "1" if options.cairo: + if not os.environ.get("CAIRO_ROOT"): + print "WARNING: Expected CAIRO_ROOT set in the environment!" flags["wxUSE_CAIRO"] = "1" if options.wxpython: @@ -361,7 +363,7 @@ def main(scriptName, args): if VERSION >= (2,9): flags["wxUSE_UIACTIONSIMULATOR"] = "1" - + mswIncludeDir = os.path.join(wxRootDir, "include", "wx", "msw") setup0File = os.path.join(mswIncludeDir, "setup0.h") @@ -399,8 +401,11 @@ def main(scriptName, args): if options.shared: args.append("SHARED=1") + if options.cairo: - args.append("USE_CAIRO=1") + args.append( + "CPPFLAGS=/I%s" % + os.path.join(os.environ.get("CAIRO_ROOT", ""), 'include\\cairo')) wxBuilder = builder.MSVCBuilder() diff --git a/include/wx/cairo.h b/include/wx/cairo.h index 88d570586b..42cc0d532c 100644 --- a/include/wx/cairo.h +++ b/include/wx/cairo.h @@ -16,130 +16,13 @@ #include "wx/dynlib.h" #include - -class wxCairoLibrary +extern "C" { -public: - // return the pointer to the global instance of this class or NULL if we - // failed to load/initialize it - static wxCairoLibrary *Get(); - - - // for internal use only - static void CleanUp(); - -private: - // the single wxCairoLibrary instance or NULL - static wxCairoLibrary *ms_lib; - - wxCairoLibrary(); - ~wxCairoLibrary(); - - bool IsOk(); - bool InitializeMethods(); - - wxDynamicLibrary m_libCairo; - wxDynamicLibrary m_libPangoCairo; - - // true if we successfully loaded the libraries and can use them - // - // note that this field must have this name as it's used by wxDL_XXX macros - bool m_ok; - -public: - wxDL_VOIDMETHOD_DEFINE( cairo_arc, - (cairo_t *cr, double xc, double yc, double radius, double angle1, double angle2), (cr, xc, yc, radius, angle1, angle2) ) - wxDL_VOIDMETHOD_DEFINE( cairo_arc_negative, - (cairo_t *cr, double xc, double yc, double radius, double angle1, double angle2), (cr, xc, yc, radius, angle1, angle2) ) - wxDL_VOIDMETHOD_DEFINE( cairo_clip, - (cairo_t *cr), (cr) ) - wxDL_VOIDMETHOD_DEFINE( cairo_close_path, - (cairo_t *cr), (cr) ) - wxDL_METHOD_DEFINE( cairo_t*, cairo_create, - (cairo_surface_t *target), (target), NULL) - wxDL_VOIDMETHOD_DEFINE( cairo_curve_to, - (cairo_t *cr, double x1, double y1, double x2, double y2, double x3, double y3), (cr, x1, y1, x2, y2, x3, y3) ) - wxDL_VOIDMETHOD_DEFINE( cairo_destroy, - (cairo_t *cr), (cr) ) - wxDL_VOIDMETHOD_DEFINE( cairo_fill, - (cairo_t *cr), (cr) ) - wxDL_VOIDMETHOD_DEFINE( cairo_fill_preserve, - (cairo_t *cr), (cr) ) - wxDL_METHOD_DEFINE( cairo_surface_t*, cairo_get_target, - (cairo_t *cr), (cr), NULL) - wxDL_METHOD_DEFINE( cairo_surface_t*, cairo_image_surface_create_for_data, - (unsigned char *data, cairo_format_t format, int width, int height, int stride), (data, format, width, height, stride), NULL) - wxDL_VOIDMETHOD_DEFINE( cairo_line_to, - (cairo_t *cr, double x, double y), (cr, x, y) ) - wxDL_VOIDMETHOD_DEFINE( cairo_move_to, - (cairo_t *cr, double x, double y), (cr, x, y) ) - wxDL_VOIDMETHOD_DEFINE( cairo_new_path, - (cairo_t *cr), (cr) ) - wxDL_VOIDMETHOD_DEFINE( cairo_paint, - (cairo_t *cr), (cr) ) - wxDL_VOIDMETHOD_DEFINE( cairo_pattern_add_color_stop_rgba, - (cairo_pattern_t *pattern, double offset, double red, double green, double blue, double alpha), (pattern, offset, red, green, blue, alpha) ) - wxDL_METHOD_DEFINE( cairo_pattern_t*, cairo_pattern_create_for_surface, - (cairo_surface_t *surface), (surface), NULL) - wxDL_METHOD_DEFINE( cairo_pattern_t*, cairo_pattern_create_linear, - (double x0, double y0, double x1, double y1), (x0, y0, x1, y1), NULL) - wxDL_METHOD_DEFINE( cairo_pattern_t*, cairo_pattern_create_radial, - (double cx0, double cy0, double radius0, double cx1, double cy1, double radius1), (cx0, cy0, radius0, cx1, cy1, radius1), NULL) - wxDL_VOIDMETHOD_DEFINE( cairo_pattern_destroy, - (cairo_pattern_t *pattern), (pattern) ) - wxDL_VOIDMETHOD_DEFINE( cairo_pattern_set_extend, - (cairo_pattern_t *pattern, cairo_extend_t extend), (pattern, extend) ) - wxDL_VOIDMETHOD_DEFINE( cairo_pattern_set_filter, - (cairo_pattern_t *pattern, cairo_filter_t filter), (pattern, filter) ) - wxDL_VOIDMETHOD_DEFINE( cairo_rectangle, - (cairo_t *cr, double x, double y, double width, double height), (cr, x, y, width, height) ) - wxDL_METHOD_DEFINE( cairo_t*, cairo_reference, - (cairo_t *cr), (cr), NULL ) - wxDL_VOIDMETHOD_DEFINE( cairo_reset_clip, - (cairo_t *cr), (cr) ) - wxDL_VOIDMETHOD_DEFINE( cairo_restore, - (cairo_t *cr), (cr) ) - wxDL_VOIDMETHOD_DEFINE( cairo_rotate, - (cairo_t *cr, double angle), (cr, angle) ) - wxDL_VOIDMETHOD_DEFINE( cairo_save, - (cairo_t *cr), (cr) ) - wxDL_VOIDMETHOD_DEFINE( cairo_scale, - (cairo_t *cr, double sx, double sy), (cr, sx, sy) ) - wxDL_VOIDMETHOD_DEFINE( cairo_set_dash, - (cairo_t *cr, const double *dashes, int num_dashes, double offset), (cr, dashes, num_dashes, offset) ) - wxDL_VOIDMETHOD_DEFINE( cairo_set_fill_rule, - (cairo_t *cr, cairo_fill_rule_t fill_rule), (cr, fill_rule) ) - wxDL_VOIDMETHOD_DEFINE( cairo_set_line_cap, - (cairo_t *cr, cairo_line_cap_t line_cap), (cr, line_cap) ) - wxDL_VOIDMETHOD_DEFINE( cairo_set_line_join, - (cairo_t *cr, cairo_line_join_t line_join), (cr, line_join) ) - wxDL_VOIDMETHOD_DEFINE( cairo_set_line_width, - (cairo_t *cr, double width), (cr, width) ) - wxDL_VOIDMETHOD_DEFINE( cairo_set_operator, - (cairo_t *cr, cairo_operator_t op), (cr, op) ) - wxDL_VOIDMETHOD_DEFINE( cairo_set_source, - (cairo_t *cr, cairo_pattern_t *source), (cr, source) ) - wxDL_VOIDMETHOD_DEFINE( cairo_set_source_rgba, - (cairo_t *cr, double red, double green, double blue, double alpha), (cr, red, green, blue, alpha) ) - wxDL_VOIDMETHOD_DEFINE( cairo_stroke, - (cairo_t *cr), (cr) ) - wxDL_VOIDMETHOD_DEFINE( cairo_stroke_preserve, - (cairo_t *cr), (cr) ) - wxDL_METHOD_DEFINE( cairo_surface_t*, cairo_surface_create_similar, - (cairo_surface_t *other, cairo_content_t content, int width, int height), (other, content, width, height), NULL) - wxDL_VOIDMETHOD_DEFINE( cairo_surface_destroy, - (cairo_surface_t *surface), (surface) ) - wxDL_VOIDMETHOD_DEFINE( cairo_translate, - (cairo_t *cr, double tx, double ty), (cr, tx, ty) ) + +bool wxCairoInit(); +void wxCairoCleanUp(); -#if wxUSE_PANGO - wxDL_VOIDMETHOD_DEFINE( pango_cairo_update_layout, - (cairo_t *cr, PangoLayout *layout), (cr, layout) ) - wxDL_VOIDMETHOD_DEFINE( pango_cairo_show_layout, - (cairo_t *cr, PangoLayout *layout), (cr, layout) ) -#endif - wxDECLARE_NO_COPY_CLASS(wxCairoLibrary); -}; +} #endif // wxUSE_CAIRO diff --git a/include/wx/dc.h b/include/wx/dc.h index 9f32103d85..b519785afa 100644 --- a/include/wx/dc.h +++ b/include/wx/dc.h @@ -475,7 +475,7 @@ public: } virtual void SetLogicalScale(double x, double y); - virtual void GetLogicalScale(double *x, double *y) + virtual void GetLogicalScale(double *x, double *y) const { if ( x ) *x = m_logicalScaleX; if ( y ) *y = m_logicalScaleY; @@ -1020,7 +1020,7 @@ public: void SetLogicalScale(double x, double y) { m_pimpl->SetLogicalScale( x, y ); } - void GetLogicalScale(double *x, double *y) + void GetLogicalScale(double *x, double *y) const { m_pimpl->GetLogicalScale( x, y ); } void SetLogicalOrigin(wxCoord x, wxCoord y) diff --git a/include/wx/dcgraph.h b/include/wx/dcgraph.h index 38ebbb61cc..99ecc11fca 100644 --- a/include/wx/dcgraph.h +++ b/include/wx/dcgraph.h @@ -32,6 +32,8 @@ public: #if defined(__WXMSW__) && wxUSE_ENH_METAFILE wxGCDC( const wxEnhMetaFileDC& dc ); #endif + wxGCDC(wxGraphicsContext* context); + wxGCDC(); virtual ~wxGCDC(); diff --git a/src/common/cairo.cpp b/src/common/cairo.cpp index ad2ae52e1a..b27bdd92c3 100644 --- a/src/common/cairo.cpp +++ b/src/common/cairo.cpp @@ -16,27 +16,280 @@ #pragma hdrstop #endif +// keep cairo.h from defining dllimport as we're defining the symbols inside +// the wx dll in order to load them dynamically. +#define cairo_public + #include "wx/cairo.h" +#include "wx/dynlib.h" #if wxUSE_CAIRO +#ifdef __WXMAC__ +#include "wx/osx/private.h" +#include +#endif + #ifndef WX_PRECOMP #include "wx/module.h" #include "wx/log.h" #endif +#define wxCAIRO_METHOD_TYPE(name) \ + wxCairo##name##_t + +#define wxCAIRO_STATIC_METHOD_DEFINE(rettype, name, args, argnames, defret) \ + static wxCAIRO_METHOD_TYPE(name) name; + +#define wxCAIRO_STATIC_VOIDMETHOD_DEFINE(name, args, argnames) \ + wxCAIRO_STATIC_METHOD_DEFINE(void, name, args, argnames, NULL) + +#define wxFOR_ALL_CAIRO_VOIDMETHODS(m) \ + m( cairo_append_path, \ + (cairo_t *cr, const cairo_path_t *path), (cr, path) ) \ + m( cairo_arc, \ + (cairo_t *cr, double xc, double yc, double radius, double angle1, double angle2), (cr, xc, yc, radius, angle1, angle2) ) \ + m( cairo_arc_negative, \ + (cairo_t *cr, double xc, double yc, double radius, double angle1, double angle2), (cr, xc, yc, radius, angle1, angle2) ) \ + m( cairo_clip, \ + (cairo_t *cr), (cr) ) \ + m( cairo_close_path, \ + (cairo_t *cr), (cr) ) \ + m( cairo_curve_to, \ + (cairo_t *cr, double x1, double y1, double x2, double y2, double x3, double y3), (cr, x1, y1, x2, y2, x3, y3) ) \ + m( cairo_destroy, \ + (cairo_t *cr), (cr) ) \ + m( cairo_fill, \ + (cairo_t *cr), (cr) ) \ + m( cairo_fill_preserve, \ + (cairo_t *cr), (cr) ) \ + m( cairo_font_extents, \ + (cairo_t *cr, cairo_font_extents_t *extents), (cr, extents) ) \ + m( cairo_font_face_destroy, \ + (cairo_font_face_t *font_face), (font_face) ) \ + m( cairo_get_current_point, \ + (cairo_t *cr, double *x, double *y), (cr, x, y) ) \ + m( cairo_get_matrix, \ + (cairo_t *cr, cairo_matrix_t *matrix), (cr, matrix) ) \ + m( cairo_line_to, \ + (cairo_t *cr, double x, double y), (cr, x, y) ) \ + m( cairo_matrix_init, \ + (cairo_matrix_t *matrix, double xx, double yx, double xy, double yy, double x0, double y0), (matrix, xx, yx, xy, yy, x0, y0) ) \ + m( cairo_matrix_multiply, \ + (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b), (result, a, b) ) \ + m( cairo_matrix_rotate, \ + (cairo_matrix_t *matrix, double radians), (matrix, radians) ) \ + m( cairo_matrix_scale, \ + (cairo_matrix_t *matrix, double sx, double sy), (matrix, sx, sy) ) \ + m( cairo_matrix_transform_distance, \ + (const cairo_matrix_t *matrix, double *dx, double *dy), (matrix, dx, dy) ) \ + m( cairo_matrix_transform_point, \ + (const cairo_matrix_t *matrix, double *x, double *y), (matrix, x, y) ) \ + m( cairo_matrix_translate, \ + (cairo_matrix_t *matrix, double tx, double ty), (matrix, tx, ty) ) \ + m( cairo_move_to, \ + (cairo_t *cr, double x, double y), (cr, x, y) ) \ + m( cairo_new_path, \ + (cairo_t *cr), (cr) ) \ + m( cairo_paint, \ + (cairo_t *cr), (cr) ) \ + m( cairo_paint_with_alpha, \ + (cairo_t *cr, double alpha), (cr, alpha) ) \ + m( cairo_path_destroy, \ + (cairo_path_t *path), (path) ) \ + m( cairo_pattern_add_color_stop_rgba, \ + (cairo_pattern_t *pattern, double offset, double red, double green, double blue, double alpha), (pattern, offset, red, green, blue, alpha) ) \ + m( cairo_pattern_destroy, \ + (cairo_pattern_t *pattern), (pattern) ) \ + m( cairo_pattern_set_extend, \ + (cairo_pattern_t *pattern, cairo_extend_t extend), (pattern, extend) ) \ + m( cairo_pattern_set_filter, \ + (cairo_pattern_t *pattern, cairo_filter_t filter), (pattern, filter) ) \ + m( cairo_pop_group_to_source, \ + (cairo_t *cr), (cr) ) \ + m( cairo_push_group, \ + (cairo_t *cr), (cr) ) \ + m( cairo_rectangle, \ + (cairo_t *cr, double x, double y, double width, double height), (cr, x, y, width, height) ) \ + m( cairo_reset_clip, \ + (cairo_t *cr), (cr) ) \ + m( cairo_restore, \ + (cairo_t *cr), (cr) ) \ + m( cairo_rotate, \ + (cairo_t *cr, double angle), (cr, angle) ) \ + m( cairo_save, \ + (cairo_t *cr), (cr) ) \ + m( cairo_scale, \ + (cairo_t *cr, double sx, double sy), (cr, sx, sy) ) \ + m( cairo_select_font_face, \ + (cairo_t *cr, const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight), (cr, family, slant, weight) ) \ + m( cairo_set_antialias, \ + (cairo_t *cr, cairo_antialias_t antialias), (cr, antialias) ) \ + m( cairo_set_dash, \ + (cairo_t *cr, const double *dashes, int num_dashes, double offset), (cr, dashes, num_dashes, offset) ) \ + m( cairo_set_fill_rule, \ + (cairo_t *cr, cairo_fill_rule_t fill_rule), (cr, fill_rule) ) \ + m( cairo_set_font_face, \ + (cairo_t *cr, cairo_font_face_t *font_face), (cr, font_face) ) \ + m( cairo_set_font_size, \ + (cairo_t *cr, double size), (cr, size) ) \ + m( cairo_set_line_cap, \ + (cairo_t *cr, cairo_line_cap_t line_cap), (cr, line_cap) ) \ + m( cairo_set_line_join, \ + (cairo_t *cr, cairo_line_join_t line_join), (cr, line_join) ) \ + m( cairo_set_line_width, \ + (cairo_t *cr, double width), (cr, width) ) \ + m( cairo_set_matrix, \ + (cairo_t *cr, const cairo_matrix_t *matrix), (cr, matrix) ) \ + m( cairo_set_operator, \ + (cairo_t *cr, cairo_operator_t op), (cr, op) ) \ + m( cairo_set_source, \ + (cairo_t *cr, cairo_pattern_t *source), (cr, source) ) \ + m( cairo_set_source_rgba, \ + (cairo_t *cr, double red, double green, double blue, double alpha), (cr, red, green, blue, alpha) ) \ + m( cairo_show_text, \ + (cairo_t *cr, const char *utf8), (cr, utf8) ) \ + m( cairo_stroke, \ + (cairo_t *cr), (cr) ) \ + m( cairo_stroke_extents, \ + (cairo_t *cr, double *x1, double *y1, double *x2, double *y2), (cr, x1, y1, x2, y2) ) \ + m( cairo_stroke_preserve, \ + (cairo_t *cr), (cr) ) \ + m( cairo_surface_destroy, \ + (cairo_surface_t *surface), (surface) ) \ + m( cairo_text_extents, \ + (cairo_t *cr, const char *utf8, cairo_text_extents_t *extents), (cr, utf8, extents) ) \ + m( cairo_transform, \ + (cairo_t *cr, const cairo_matrix_t *matrix), (cr, matrix) ) \ + m( cairo_translate, \ + (cairo_t *cr, double tx, double ty), (cr, tx, ty) ) \ + +#ifdef __WXMAC__ +#define wxCAIRO_PLATFORM_METHODS(m) \ + m( cairo_font_face_t*, cairo_quartz_font_face_create_for_cgfont, \ + (CGFontRef font), (font), NULL ) \ + m( cairo_surface_t*, cairo_quartz_surface_create_for_cg_context, \ + (CGContextRef cgContext, unsigned int width, unsigned int height), (cgContext, width, height), NULL ) +#elif defined(__WXMSW__) +#define wxCAIRO_PLATFORM_METHODS(m) \ + m( cairo_surface_t*, cairo_win32_surface_create, \ + (HDC hdc), (hdc), NULL ) \ + m( cairo_surface_t*, cairo_win32_printing_surface_create, \ + (HDC hdc), (hdc), NULL ) +#else +#define wxCAIRO_PLATFORM_METHODS(m) +#endif + +#define wxFOR_ALL_CAIRO_METHODS(m) \ + m( cairo_path_t*, cairo_copy_path, \ + (cairo_t *cr), (cr), NULL ) \ + m( cairo_t*, cairo_create, \ + (cairo_surface_t *target), (target), NULL) \ + m( cairo_surface_t*, cairo_get_target, \ + (cairo_t *cr), (cr), NULL) \ + m( cairo_surface_t*, cairo_image_surface_create, \ + (cairo_format_t format, int width, int height), (format, width, height), NULL ) \ + m( cairo_surface_t*, cairo_image_surface_create_for_data, \ + (unsigned char *data, cairo_format_t format, int width, int height, int stride), (data, format, width, height, stride), NULL) \ + m( cairo_bool_t, cairo_in_fill, \ + (cairo_t *cr, double x, double y), (cr, x, y), false ) \ + m( cairo_status_t, cairo_matrix_invert, \ + (cairo_matrix_t *matrix), (matrix), NULL) \ + m( cairo_pattern_t*, cairo_pattern_create_for_surface, \ + (cairo_surface_t *surface), (surface), NULL) \ + m( cairo_pattern_t*, cairo_pattern_create_linear, \ + (double x0, double y0, double x1, double y1), (x0, y0, x1, y1), NULL) \ + m( cairo_pattern_t*, cairo_pattern_create_radial, \ + (double cx0, double cy0, double radius0, double cx1, double cy1, double radius1), (cx0, cy0, radius0, cx1, cy1, radius1), NULL) \ + m( cairo_status_t, cairo_pattern_status, \ + (cairo_pattern_t *pattern), (pattern), 4) \ + m( cairo_t*, cairo_reference, \ + (cairo_t *cr), (cr), NULL ) \ + m( cairo_surface_t*, cairo_surface_create_similar, \ + (cairo_surface_t *other, cairo_content_t content, int width, int height), (other, content, width, height), NULL) \ + wxCAIRO_PLATFORM_METHODS(m) + +#if wxUSE_PANGO +#define wxFOR_ALL_PANGO_CAIRO_VOIDMETHODS(m) \ + m( pango_cairo_update_layout, \ + (cairo_t *cr, PangoLayout *layout), (cr, layout) ) \ + m( pango_cairo_show_layout, \ + (cairo_t *cr, PangoLayout *layout), (cr, layout) ) +#endif -wxCairoLibrary *wxCairoLibrary::ms_lib = NULL; +#define wxCAIRO_DECLARE_TYPE(rettype, name, args, argnames, defret) \ + typedef rettype (*wxCAIRO_METHOD_TYPE(name)) args ; \ + wxCAIRO_METHOD_TYPE(name) wxDL_METHOD_NAME(name); + +#define wxCAIRO_DECLARE_VOIDTYPE(name, args, argnames) \ + wxCAIRO_DECLARE_TYPE(void, name, args, argnames, NULL) + +wxFOR_ALL_CAIRO_VOIDMETHODS(wxCAIRO_DECLARE_VOIDTYPE) +wxFOR_ALL_CAIRO_METHODS(wxCAIRO_DECLARE_TYPE) + +class wxCairo +{ +public: + static bool Initialize(); + + // for internal use only + static void CleanUp(); + +private: + // the single wxCairo instance or NULL + static wxCairo *ms_lib; + + wxCairo(); + ~wxCairo(); + + bool IsOk(); + + wxDynamicLibrary m_libCairo; + wxDynamicLibrary m_libPangoCairo; + + // true if we successfully loaded the libraries and can use them + // + // note that this field must have this name as it's used by wxDL_XXX macros + bool m_ok; + +public: + + wxFOR_ALL_CAIRO_VOIDMETHODS(wxCAIRO_STATIC_VOIDMETHOD_DEFINE) + wxFOR_ALL_CAIRO_METHODS(wxCAIRO_STATIC_METHOD_DEFINE) +#if wxUSE_PANGO // untested, uncomment to test compilation. + //wxFOR_ALL_PANGO_METHODS(wxDL_STATIC_METHOD_DEFINE) +#endif + + wxDECLARE_NO_COPY_CLASS(wxCairo); +}; + +#define wxINIT_CAIRO_VOIDFUNC(name, params, args) \ + wxCAIRO_METHOD_TYPE(name) wxCairo::name = NULL; + +#define wxINIT_CAIRO_FUNC(rettype, name, params, args, defret) \ + wxCAIRO_METHOD_TYPE(name) wxCairo::name = NULL; + +wxFOR_ALL_CAIRO_VOIDMETHODS(wxINIT_CAIRO_VOIDFUNC) +wxFOR_ALL_CAIRO_METHODS(wxINIT_CAIRO_FUNC) + +#undef wxINIT_CAIRO_FUNC + +wxCairo *wxCairo::ms_lib = NULL; //---------------------------------------------------------------------------- // wxCairoLibrary //---------------------------------------------------------------------------- -wxCairoLibrary::wxCairoLibrary() +wxCairo::wxCairo() { wxLogNull log; - m_libCairo.Load("libcairo.so.2"); +#ifdef __WXMSW__ + wxString cairoDllStr("libcairo-2.dll"); +#else + wxString cairoDllStr("libcairo.so.2"); +#endif + m_libCairo.Load(cairoDllStr); m_ok = m_libCairo.IsLoaded(); if ( !m_ok ) return; @@ -51,18 +304,35 @@ wxCairoLibrary::wxCairoLibrary() } #endif - m_ok = InitializeMethods(); + +#define wxDO_LOAD_FUNC(name, nameStr) \ + name = (wxCAIRO_METHOD_TYPE(name))m_libCairo.RawGetSymbol(nameStr); \ + if ( !name ) \ + return; + +#define wxLOAD_CAIRO_VOIDFUNC(name, params, args) \ + wxDO_LOAD_FUNC(name, wxSTRINGIZE_T(name)) + +#define wxLOAD_CAIRO_FUNC(rettype, name, params, args, defret) \ + wxDO_LOAD_FUNC(name, wxSTRINGIZE_T(name)) + +wxFOR_ALL_CAIRO_VOIDMETHODS(wxLOAD_CAIRO_VOIDFUNC) +wxFOR_ALL_CAIRO_METHODS(wxLOAD_CAIRO_FUNC) + +#undef wxLOAD_CAIRO_FUNC + + m_ok = true; } -wxCairoLibrary::~wxCairoLibrary() +wxCairo::~wxCairo() { } -/* static */ wxCairoLibrary* wxCairoLibrary::Get() +/* static */ bool wxCairo::Initialize() { if ( !ms_lib ) { - ms_lib = new wxCairoLibrary(); + ms_lib = new wxCairo(); if ( !ms_lib->IsOk() ) { delete ms_lib; @@ -70,10 +340,10 @@ wxCairoLibrary::~wxCairoLibrary() } } - return ms_lib; + return ms_lib != NULL; } -/* static */ void wxCairoLibrary::CleanUp() +/* static */ void wxCairo::CleanUp() { if (ms_lib) { @@ -82,63 +352,48 @@ wxCairoLibrary::~wxCairoLibrary() } } -bool wxCairoLibrary::IsOk() +bool wxCairo::IsOk() { return m_ok; } -bool wxCairoLibrary::InitializeMethods() +// ============================================================================ +// implementation of the functions themselves +// ============================================================================ + +extern "C" { - wxDL_METHOD_LOAD(m_libCairo, cairo_arc); - wxDL_METHOD_LOAD(m_libCairo, cairo_arc_negative); - wxDL_METHOD_LOAD(m_libCairo, cairo_clip); - wxDL_METHOD_LOAD(m_libCairo, cairo_close_path); - wxDL_METHOD_LOAD(m_libCairo, cairo_create); - wxDL_METHOD_LOAD(m_libCairo, cairo_curve_to); - wxDL_METHOD_LOAD(m_libCairo, cairo_destroy); - wxDL_METHOD_LOAD(m_libCairo, cairo_fill); - wxDL_METHOD_LOAD(m_libCairo, cairo_fill_preserve); - wxDL_METHOD_LOAD(m_libCairo, cairo_get_target); - wxDL_METHOD_LOAD(m_libCairo, cairo_image_surface_create_for_data); - wxDL_METHOD_LOAD(m_libCairo, cairo_line_to); - wxDL_METHOD_LOAD(m_libCairo, cairo_move_to); - wxDL_METHOD_LOAD(m_libCairo, cairo_new_path); - wxDL_METHOD_LOAD(m_libCairo, cairo_paint); - wxDL_METHOD_LOAD(m_libCairo, cairo_pattern_add_color_stop_rgba); - wxDL_METHOD_LOAD(m_libCairo, cairo_pattern_create_for_surface); - wxDL_METHOD_LOAD(m_libCairo, cairo_pattern_create_linear); - wxDL_METHOD_LOAD(m_libCairo, cairo_pattern_create_radial); - wxDL_METHOD_LOAD(m_libCairo, cairo_pattern_destroy); - wxDL_METHOD_LOAD(m_libCairo, cairo_pattern_set_extend); - wxDL_METHOD_LOAD(m_libCairo, cairo_pattern_set_filter); - wxDL_METHOD_LOAD(m_libCairo, cairo_rectangle); - wxDL_METHOD_LOAD(m_libCairo, cairo_reset_clip); - wxDL_METHOD_LOAD(m_libCairo, cairo_restore); - wxDL_METHOD_LOAD(m_libCairo, cairo_rotate); - wxDL_METHOD_LOAD(m_libCairo, cairo_save); - wxDL_METHOD_LOAD(m_libCairo, cairo_scale); - wxDL_METHOD_LOAD(m_libCairo, cairo_set_dash); - wxDL_METHOD_LOAD(m_libCairo, cairo_set_fill_rule); - wxDL_METHOD_LOAD(m_libCairo, cairo_set_line_cap); - wxDL_METHOD_LOAD(m_libCairo, cairo_set_line_join); - wxDL_METHOD_LOAD(m_libCairo, cairo_set_line_width); - wxDL_METHOD_LOAD(m_libCairo, cairo_set_operator); - wxDL_METHOD_LOAD(m_libCairo, cairo_set_source); - wxDL_METHOD_LOAD(m_libCairo, cairo_set_source_rgba); - wxDL_METHOD_LOAD(m_libCairo, cairo_stroke); - wxDL_METHOD_LOAD(m_libCairo, cairo_stroke_preserve); - wxDL_METHOD_LOAD(m_libCairo, cairo_surface_create_similar); - wxDL_METHOD_LOAD(m_libCairo, cairo_surface_destroy); - wxDL_METHOD_LOAD(m_libCairo, cairo_translate); -#if wxUSE_PANGO - wxDL_METHOD_LOAD(m_libPangoCairo, pango_cairo_update_layout); - wxDL_METHOD_LOAD(m_libPangoCairo, pango_cairo_show_layout); -#endif +bool wxCairoInit() +{ + return wxCairo::Initialize(); +} - return true; +void wxCairoCleanUp() +{ + wxCairo::CleanUp(); } +#define wxIMPL_CAIRO_FUNC(rettype, name, params, args, defret) \ + rettype name params \ + { \ + wxASSERT_MSG(wxCairo::Initialize(), "Cairo not initialized"); \ + return wxCairo::name args; \ + } + +#define wxIMPL_CAIRO_VOIDFUNC(name, params, args) \ + wxIMPL_CAIRO_FUNC(void, name, params, args, NULL) + +// we currently link directly to Cairo on GTK since it is usually available there, +// so don't use our cairo_xyz wrapper functions until the decision is made to +// always load Cairo dynamically there. +#ifndef __WXGTK__ +wxFOR_ALL_CAIRO_VOIDMETHODS(wxIMPL_CAIRO_VOIDFUNC) +wxFOR_ALL_CAIRO_METHODS(wxIMPL_CAIRO_FUNC) +#endif + +} // extern "C" + //---------------------------------------------------------------------------- // wxCairoModule //---------------------------------------------------------------------------- @@ -151,7 +406,7 @@ public: virtual void OnExit(); private: - DECLARE_DYNAMIC_CLASS(wxCairotModule) + DECLARE_DYNAMIC_CLASS(wxCairoModule) }; bool wxCairoModule::OnInit() @@ -161,7 +416,7 @@ bool wxCairoModule::OnInit() void wxCairoModule::OnExit() { - wxCairoLibrary::CleanUp(); + wxCairo::CleanUp(); } IMPLEMENT_DYNAMIC_CLASS(wxCairoModule, wxModule) diff --git a/src/common/dcgraph.cpp b/src/common/dcgraph.cpp index 1f7295a12e..812ca0e4ed 100644 --- a/src/common/dcgraph.cpp +++ b/src/common/dcgraph.cpp @@ -121,6 +121,12 @@ wxGCDC::wxGCDC(const wxEnhMetaFileDC& dc) } #endif +wxGCDC::wxGCDC(wxGraphicsContext* context) : + wxDC( new wxGCDCImpl( this ) ) +{ + SetGraphicsContext(context); +} + wxGCDC::wxGCDC() : wxDC( new wxGCDCImpl( this ) ) { diff --git a/src/generic/graphicc.cpp b/src/generic/graphicc.cpp index 7fb9f85f38..597fbe5a7e 100644 --- a/src/generic/graphicc.cpp +++ b/src/generic/graphicc.cpp @@ -21,6 +21,10 @@ #if wxUSE_CAIRO +// keep cairo.h from defining dllimport as we're defining the symbols inside +// the wx dll in order to load them dynamically. +#define cairo_public + #include "wx/cairo.h" #ifndef WX_PRECOMP @@ -1089,7 +1093,13 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm // Create a surface object and copy the bitmap pixel data to it. if the // image has alpha (or a mask represented as alpha) then we'll use a // different format and iterator than if it doesn't... - if (bmpSource.HasAlpha() || bmpSource.GetMask()) + if (bmpSource.HasAlpha() || (bmpSource.GetMask() +#ifdef __WXMSW__ + // this check is needed under wxMSW, but adding this condition to wxGTK + // causes an assert when getting alpha pixel data, not sure about Mac. + && bmpSource.GetDepth() == 32 +#endif + )) { m_surface = cairo_image_surface_create_for_data( m_buffer, CAIRO_FORMAT_ARGB32, bw, bh, bw*4); @@ -1190,10 +1200,20 @@ public : wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxPrinterDC& dc ) : wxGraphicsContext(renderer) { +#ifdef __WXMSW__ + // wxMSW contexts always use MM_ANISOTROPIC, which messes up + // text rendering when printing using Cairo. Switch it to MM_TEXT + // map mode to avoid this problem. + HDC hdc = (HDC)dc.GetHDC(); + ::SetMapMode(hdc, MM_TEXT); + m_mswSurface = cairo_win32_printing_surface_create(hdc); + Init( cairo_create(m_mswSurface) ); +#endif + #ifdef __WXGTK20__ const wxDCImpl *impl = dc.GetImpl(); Init( (cairo_t*) impl->GetCairoContext() ); - +#endif wxSize sz = dc.GetSize(); m_width = sz.x; m_height = sz.y; @@ -1203,11 +1223,21 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxPrinterDC& double sx,sy; dc.GetUserScale( &sx, &sy ); + +// TODO: Determine if these fixes are needed on other platforms too. +// On MSW, without this the printer context will not respect wxDC SetMapMode calls. +// For example, using dc.SetMapMode(wxMM_POINTS) can let us share printer and screen +// drawing code +#ifdef __WXMSW__ + double lsx,lsy; + dc.GetLogicalScale( &lsx, &lsy ); + sx *= lsx; + sy *= lsy; +#endif cairo_scale( m_context, sx, sy ); org = dc.GetLogicalOrigin(); cairo_translate( m_context, -org.x, -org.y ); -#endif } wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc ) @@ -1220,6 +1250,11 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& m_enableOffset = true; +#ifdef __WXMSW__ + m_mswSurface = cairo_win32_surface_create((HDC)dc.GetHDC()); + Init( cairo_create(m_mswSurface) ); +#endif + #ifdef __WXGTK20__ wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl(); Init( gdk_cairo_create( impldc->GetGDKWindow() ) ); @@ -1258,6 +1293,11 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC& m_height = height; m_enableOffset = true; + +#ifdef __WXMSW__ + m_mswSurface = cairo_win32_surface_create((HDC)dc.GetHDC()); + Init( cairo_create(m_mswSurface) ); +#endif #ifdef __WXGTK20__ wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl(); @@ -1837,7 +1877,13 @@ public : // create a subimage from a native image representation virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h ); +protected : + bool EnsureIsLoaded(); + void Load(); + void Unload(); + friend class wxCairoModule; private : + int m_loaded; DECLARE_DYNAMIC_CLASS_NO_COPY(wxCairoRenderer) } ; @@ -1852,18 +1898,46 @@ static wxCairoRenderer gs_cairoGraphicsRenderer; extern wxGraphicsRenderer* gCairoRenderer; wxGraphicsRenderer* gCairoRenderer = &gs_cairoGraphicsRenderer; +bool wxCairoRenderer::EnsureIsLoaded() +{ +#ifndef __WXGTK__ + Load(); + return wxCairoInit(); +#else + return true; +#endif +} + +void wxCairoRenderer::Load() +{ + wxCairoInit(); +} + +void wxCairoRenderer::Unload() +{ + wxCairoCleanUp(); +} + +// call EnsureIsLoaded() and return returnOnFail value if it fails +#define ENSURE_LOADED_OR_RETURN(returnOnFail) \ + if ( !EnsureIsLoaded() ) \ + return (returnOnFail) + wxGraphicsContext * wxCairoRenderer::CreateContext( const wxWindowDC& dc) { + ENSURE_LOADED_OR_RETURN(NULL); return new wxCairoContext(this,dc); } wxGraphicsContext * wxCairoRenderer::CreateContext( const wxMemoryDC& dc) { + ENSURE_LOADED_OR_RETURN(NULL); return new wxCairoContext(this,dc); } wxGraphicsContext * wxCairoRenderer::CreateContext( const wxPrinterDC& dc) { + ENSURE_LOADED_OR_RETURN(NULL); #ifdef __WXGTK20__ const wxDCImpl *impl = dc.GetImpl(); cairo_t* context = (cairo_t*) impl->GetCairoContext(); @@ -1871,13 +1945,14 @@ wxGraphicsContext * wxCairoRenderer::CreateContext( const wxPrinterDC& dc) return new wxCairoContext(this,dc); else #endif - return NULL; + return new wxCairoContext(this,dc); } #ifdef __WXMSW__ #if wxUSE_ENH_METAFILE -wxGraphicsContext * wxCairoRenderer::CreateContext( const wxEnhMetaFileDC& dc) +wxGraphicsContext * wxCairoRenderer::CreateContext( const wxEnhMetaFileDC& WXUNUSED(dc) ) { + ENSURE_LOADED_OR_RETURN(NULL); return NULL; } #endif @@ -1885,6 +1960,7 @@ wxGraphicsContext * wxCairoRenderer::CreateContext( const wxEnhMetaFileDC& dc) wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeContext( void * context ) { + ENSURE_LOADED_OR_RETURN(NULL); #ifdef __WXMSW__ return new wxCairoContext(this,(HDC)context); #else @@ -1895,15 +1971,18 @@ wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeContext( void * cont wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeWindow( void * window ) { + ENSURE_LOADED_OR_RETURN(NULL); #ifdef __WXGTK__ return new wxCairoContext(this,(GdkDrawable*)window); #else + wxUnusedVar(window); return NULL; #endif } wxGraphicsContext * wxCairoRenderer::CreateMeasuringContext() { + ENSURE_LOADED_OR_RETURN(NULL); #ifdef __WXGTK__ return CreateContextFromNativeWindow(gdk_get_default_root_window()); #endif @@ -1913,6 +1992,7 @@ wxGraphicsContext * wxCairoRenderer::CreateMeasuringContext() wxGraphicsContext * wxCairoRenderer::CreateContext( wxWindow* window ) { + ENSURE_LOADED_OR_RETURN(NULL); return new wxCairoContext(this, window ); } @@ -1920,6 +2000,7 @@ wxGraphicsContext * wxCairoRenderer::CreateContext( wxWindow* window ) wxGraphicsPath wxCairoRenderer::CreatePath() { + ENSURE_LOADED_OR_RETURN(wxNullGraphicsPath); wxGraphicsPath path; path.SetRefData( new wxCairoPathData(this) ); return path; @@ -1932,6 +2013,7 @@ wxGraphicsMatrix wxCairoRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble wxDouble tx, wxDouble ty) { + ENSURE_LOADED_OR_RETURN(wxNullGraphicsMatrix); wxGraphicsMatrix m; wxCairoMatrixData* data = new wxCairoMatrixData( this ); data->Set( a,b,c,d,tx,ty ) ; @@ -1941,6 +2023,7 @@ wxGraphicsMatrix wxCairoRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble wxGraphicsPen wxCairoRenderer::CreatePen(const wxPen& pen) { + ENSURE_LOADED_OR_RETURN(wxNullGraphicsPen); if ( !pen.IsOk() || pen.GetStyle() == wxPENSTYLE_TRANSPARENT ) return wxNullGraphicsPen; else @@ -1953,6 +2036,7 @@ wxGraphicsPen wxCairoRenderer::CreatePen(const wxPen& pen) wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush ) { + ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush); if ( !brush.IsOk() || brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT ) return wxNullGraphicsBrush; else @@ -1968,6 +2052,7 @@ wxCairoRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxGraphicsGradientStops& stops) { + ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush); wxGraphicsBrush p; wxCairoBrushData* d = new wxCairoBrushData( this ); d->CreateLinearGradientBrush(x1, y1, x2, y2, stops); @@ -1980,6 +2065,7 @@ wxCairoRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble r, const wxGraphicsGradientStops& stops) { + ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush); wxGraphicsBrush p; wxCairoBrushData* d = new wxCairoBrushData( this ); d->CreateRadialGradientBrush(xo, yo, xc, yc, r, stops); @@ -1990,6 +2076,7 @@ wxCairoRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, // sets the font wxGraphicsFont wxCairoRenderer::CreateFont( const wxFont &font , const wxColour &col ) { + ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont); if ( font.IsOk() ) { wxGraphicsFont p; @@ -2002,6 +2089,7 @@ wxGraphicsFont wxCairoRenderer::CreateFont( const wxFont &font , const wxColour wxGraphicsBitmap wxCairoRenderer::CreateBitmap( const wxBitmap& bmp ) { + ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap); if ( bmp.IsOk() ) { wxGraphicsBitmap p; @@ -2014,6 +2102,7 @@ wxGraphicsBitmap wxCairoRenderer::CreateBitmap( const wxBitmap& bmp ) wxGraphicsBitmap wxCairoRenderer::CreateBitmapFromNativeBitmap( void* bitmap ) { + ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap); if ( bitmap != NULL ) { wxGraphicsBitmap p; @@ -2031,6 +2120,7 @@ wxCairoRenderer::CreateSubBitmap(const wxGraphicsBitmap& WXUNUSED(bitmap), wxDouble WXUNUSED(w), wxDouble WXUNUSED(h)) { + ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap); wxFAIL_MSG("wxCairoRenderer::CreateSubBitmap is not implemented."); return wxNullGraphicsBitmap; } diff --git a/src/msw/dlmsw.cpp b/src/msw/dlmsw.cpp index cdff7387ab..33a55b8ce8 100644 --- a/src/msw/dlmsw.cpp +++ b/src/msw/dlmsw.cpp @@ -27,6 +27,7 @@ #include "wx/msw/private.h" #include "wx/msw/debughlp.h" +#include "wx/filename.h" const wxString wxDynamicLibrary::ms_dllext(wxT(".dll")); @@ -224,13 +225,37 @@ wxDllType wxDynamicLibrary::GetProgramHandle() // loading/unloading DLLs // ---------------------------------------------------------------------------- +#ifndef MAX_PATH + #define MAX_PATH 260 // from VC++ headers +#endif + /* static */ wxDllType wxDynamicLibrary::RawLoad(const wxString& libname, int flags) { - return flags & wxDL_GET_LOADED - ? ::GetModuleHandle(libname.t_str()) - : ::LoadLibrary(libname.t_str()); + if (flags & wxDL_GET_LOADED) + return ::GetModuleHandle(libname.t_str()); + + // Explicitly look in the same path as where the main wx HINSTANCE module + // is located (usually the executable or the DLL that uses wx). Normally + // this is automatically part of the default search path but in some cases + // it may not be, such as when the wxPython extension modules need to load + // a DLL, but the intperpreter executable is located elsewhere. Doing + // this allows us to always be able to dynamically load a DLL that is + // located at the same place as the wx modules. + wxString modpath, path; + ::GetModuleFileName(wxGetInstance(), + wxStringBuffer(modpath, MAX_PATH+1), + MAX_PATH); + + wxFileName::SplitPath(modpath, &path, NULL, NULL); + ::SetDllDirectory(path.t_str()); + + wxDllType handle = ::LoadLibrary(libname.t_str()); + + // reset the search path + ::SetDllDirectory(NULL); + return handle; } /* static */ diff --git a/src/msw/graphics.cpp b/src/msw/graphics.cpp index 0bc8226142..88d5fb5594 100644 --- a/src/msw/graphics.cpp +++ b/src/msw/graphics.cpp @@ -2127,6 +2127,14 @@ WXHDC wxGCDC::AcquireHDC() if ( !gc ) return NULL; +#if wxUSE_CAIRO + // we can't get the HDC if it is not a GDI+ context + wxGraphicsRenderer* r1 = gc->GetRenderer(); + wxGraphicsRenderer* r2 = wxGraphicsRenderer::GetCairoRenderer(); + if (r1 == r2) + return NULL; +#endif + Graphics * const g = static_cast(gc->GetNativeContext()); return g ? g->GetHDC() : NULL; } @@ -2139,6 +2147,14 @@ void wxGCDC::ReleaseHDC(WXHDC hdc) wxGraphicsContext * const gc = GetGraphicsContext(); wxCHECK_RET( gc, "can't release HDC because there is no wxGraphicsContext" ); +#if wxUSE_CAIRO + // we can't get the HDC if it is not a GDI+ context + wxGraphicsRenderer* r1 = gc->GetRenderer(); + wxGraphicsRenderer* r2 = wxGraphicsRenderer::GetCairoRenderer(); + if (r1 == r2) + return; +#endif + Graphics * const g = static_cast(gc->GetNativeContext()); wxCHECK_RET( g, "can't release HDC because there is no Graphics" );