From 0ae78d608a4e1ac88e82eec59835fc6df7a7fee3 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Thu, 14 Apr 2016 20:45:42 +0200 Subject: [PATCH] Restore source DC state when wxCairoContext is destroyed (wxMSW). Since raw DC (encapsulated in source wxDC) can be modified in wxCairoContext explicitly (e.g. when context is instantiated from wxPrinterDC or wxEnhMetaFileDC) or implicitly (by some Cairo functions) we have to store its state in ctor and restore it in dtor to assure consistent state of the source wxDC. --- src/common/cairo.cpp | 4 +++- src/generic/graphicc.cpp | 25 ++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/common/cairo.cpp b/src/common/cairo.cpp index 1f8b6f92cb..7eb422d12c 100644 --- a/src/common/cairo.cpp +++ b/src/common/cairo.cpp @@ -184,7 +184,9 @@ 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 ) + (HDC hdc), (hdc), NULL ) \ + m( HDC, cairo_win32_surface_get_dc, \ + (cairo_surface_t *surface), (surface), NULL ) #else #define wxCAIRO_PLATFORM_METHODS(m) #endif diff --git a/src/generic/graphicc.cpp b/src/generic/graphicc.cpp index 0570fdb36f..0e709ad777 100644 --- a/src/generic/graphicc.cpp +++ b/src/generic/graphicc.cpp @@ -509,6 +509,7 @@ protected: #ifdef __WXMSW__ cairo_surface_t* m_mswSurface; WindowHDC m_mswWindowHDC; + int m_mswStateSavedDC; #endif private: @@ -1741,6 +1742,7 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxPrinterDC& // text rendering when printing using Cairo. Switch it to MM_TEXT // map mode to avoid this problem. HDC hdc = (HDC)dc.GetHDC(); + m_mswStateSavedDC = ::SaveDC(hdc); ::SetMapMode(hdc, MM_TEXT); m_mswSurface = cairo_win32_printing_surface_create(hdc); Init( cairo_create(m_mswSurface) ); @@ -1792,7 +1794,9 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& m_enableOffset = dc.GetContentScaleFactor() <= 1; #ifdef __WXMSW__ - m_mswSurface = cairo_win32_surface_create((HDC)dc.GetHDC()); + HDC hdc = (HDC)dc.GetHDC(); + m_mswStateSavedDC = ::SaveDC(hdc); + m_mswSurface = cairo_win32_surface_create(hdc); Init( cairo_create(m_mswSurface) ); #endif @@ -1850,13 +1854,15 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC& wxASSERT_MSG(bmp.IsOk(), wxS("Should select a bitmap before creating wxCairoContext")); + HDC hdc = (HDC)dc.GetHDC(); + m_mswStateSavedDC = ::SaveDC(hdc); bool hasBitmap = false; // cairo_win32_surface_create creates a 24-bit bitmap, // so if we 32bpp bitmap, we need to create a 32-bit surface instead. if (bmp.GetDepth() < 32) { - m_mswSurface = cairo_win32_surface_create(dc.GetHDC()); + m_mswSurface = cairo_win32_surface_create(hdc); } else { @@ -1937,7 +1943,7 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC& // Fallback if we failed to create Cairo surface from 32bpp bitmap. if( !hasBitmap ) { - m_mswSurface = cairo_win32_surface_create(dc.GetHDC()); + m_mswSurface = cairo_win32_surface_create(hdc); } } @@ -2027,6 +2033,7 @@ wxCairoContext::wxCairoContext(wxGraphicsRenderer* renderer, const wxEnhMetaFile // text rendering when printing using Cairo. Switch it to MM_TEXT // map mode to avoid this problem. HDC hdc = (HDC)dc.GetHDC(); + m_mswStateSavedDC = ::SaveDC(hdc); ::SetMapMode(hdc, MM_TEXT); m_mswSurface = cairo_win32_printing_surface_create(hdc); Init( cairo_create(m_mswSurface) ); @@ -2044,6 +2051,7 @@ wxCairoContext::wxCairoContext(wxGraphicsRenderer* renderer, const wxEnhMetaFile wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, HDC handle ) : wxGraphicsContext(renderer) { + m_mswStateSavedDC = ::SaveDC(handle); m_mswSurface = cairo_win32_surface_create(handle); Init( cairo_create(m_mswSurface) ); m_width = 0; @@ -2082,6 +2090,7 @@ wxCairoContext::wxCairoContext(wxGraphicsRenderer* renderer, HWND hWnd) double scaleY = ::GetDeviceCaps((HDC)m_mswWindowHDC, LOGPIXELSY) / 96.0f; m_enableOffset = scaleY <= 1.0; + m_mswStateSavedDC = 0; m_mswSurface = cairo_win32_surface_create((HDC)m_mswWindowHDC); Init(cairo_create(m_mswSurface)); m_width = 0; @@ -2101,6 +2110,7 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context ) { #ifdef __WXMSW__ m_mswSurface = NULL; + m_mswStateSavedDC = 0; #endif // __WXMSW__ Init( context ); m_width = @@ -2135,6 +2145,7 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window) #endif #ifdef __WXMSW__ + m_mswStateSavedDC = 0; m_mswSurface = cairo_win32_surface_create((HDC)m_mswWindowHDC); Init(cairo_create(m_mswSurface)); #endif @@ -2149,6 +2160,7 @@ wxCairoContext::wxCairoContext(wxGraphicsRenderer* renderer) : { #ifdef __WXMSW__ m_mswSurface = NULL; + m_mswStateSavedDC = 0; #endif // __WXMSW__ m_context = NULL; } @@ -2163,7 +2175,14 @@ wxCairoContext::~wxCairoContext() } #ifdef __WXMSW__ if ( m_mswSurface ) + { + HDC hdc = cairo_win32_surface_get_dc(m_mswSurface); + cairo_surface_destroy(m_mswSurface); + + if ( hdc && m_mswStateSavedDC != 0 ) + ::RestoreDC(hdc, m_mswStateSavedDC); + } #endif #ifdef __WXQT__ if ( m_qtPainter != NULL )