1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/dcbufcmn.cpp
3 // Purpose:     Buffered DC implementation
4 // Author:      Ron Lee, Jaakko Salli
5 // Modified by:
6 // Created:     Sep-20-2006
7 // Copyright:   (c) wxWidgets team
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 #ifdef __BORLANDC__
23     #pragma hdrstop
24 #endif
25 
26 #include "wx/dcbuffer.h"
27 
28 #ifndef WX_PRECOMP
29     #include "wx/module.h"
30 #endif
31 
32 // ============================================================================
33 // implementation
34 // ============================================================================
35 
36 IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC,wxMemoryDC)
37 IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC,wxBufferedDC)
38 
39 // ----------------------------------------------------------------------------
40 // wxSharedDCBufferManager: helper class maintaining backing store bitmap
41 // ----------------------------------------------------------------------------
42 
43 class wxSharedDCBufferManager : public wxModule
44 {
45 public:
wxSharedDCBufferManager()46     wxSharedDCBufferManager() { }
47 
OnInit()48     virtual bool OnInit() { return true; }
OnExit()49     virtual void OnExit() { wxDELETE(ms_buffer); }
50 
GetBuffer(int w,int h)51     static wxBitmap* GetBuffer(int w, int h)
52     {
53         if ( ms_usingSharedBuffer )
54             return new wxBitmap(w, h);
55 
56         if ( !ms_buffer ||
57                 w > ms_buffer->GetWidth() ||
58                     h > ms_buffer->GetHeight() )
59         {
60             delete ms_buffer;
61 
62             // we must always return a valid bitmap but creating a bitmap of
63             // size 0 would fail, so create a 1*1 bitmap in this case
64             if ( !w )
65                 w = 1;
66             if ( !h )
67                 h = 1;
68 
69             ms_buffer = new wxBitmap(w, h);
70         }
71 
72         ms_usingSharedBuffer = true;
73         return ms_buffer;
74     }
75 
ReleaseBuffer(wxBitmap * buffer)76     static void ReleaseBuffer(wxBitmap* buffer)
77     {
78         if ( buffer == ms_buffer )
79         {
80             wxASSERT_MSG( ms_usingSharedBuffer, wxT("shared buffer already released") );
81             ms_usingSharedBuffer = false;
82         }
83         else
84         {
85             delete buffer;
86         }
87     }
88 
89 private:
90     static wxBitmap *ms_buffer;
91     static bool ms_usingSharedBuffer;
92 
93     DECLARE_DYNAMIC_CLASS(wxSharedDCBufferManager)
94 };
95 
96 wxBitmap* wxSharedDCBufferManager::ms_buffer = NULL;
97 bool wxSharedDCBufferManager::ms_usingSharedBuffer = false;
98 
IMPLEMENT_DYNAMIC_CLASS(wxSharedDCBufferManager,wxModule)99 IMPLEMENT_DYNAMIC_CLASS(wxSharedDCBufferManager, wxModule)
100 
101 // ============================================================================
102 // wxBufferedDC
103 // ============================================================================
104 
105 void wxBufferedDC::UseBuffer(wxCoord w, wxCoord h)
106 {
107     wxCHECK_RET( w >= -1 && h >= -1, "Invalid buffer size" );
108 
109     if ( !m_buffer || !m_buffer->IsOk() )
110     {
111         if ( w == -1 || h == -1 )
112             m_dc->GetSize(&w, &h);
113 
114         m_buffer = wxSharedDCBufferManager::GetBuffer(w, h);
115         m_style |= wxBUFFER_USES_SHARED_BUFFER;
116         m_area.Set(w,h);
117     }
118     else
119         m_area = m_buffer->GetSize();
120 
121     SelectObject(*m_buffer);
122 
123     // now that the DC is valid we can inherit the attributes (fonts, colours,
124     // layout direction, ...) from the original DC
125     if ( m_dc && m_dc->IsOk() )
126         CopyAttributes(*m_dc);
127 }
128 
UnMask()129 void wxBufferedDC::UnMask()
130 {
131     wxCHECK_RET( m_dc, wxT("no underlying wxDC?") );
132     wxASSERT_MSG( m_buffer && m_buffer->IsOk(), wxT("invalid backing store") );
133 
134     wxCoord x = 0,
135             y = 0;
136 
137     // Ensure the scale matches the device
138     SetUserScale(1.0, 1.0);
139 
140     if ( m_style & wxBUFFER_CLIENT_AREA )
141         GetDeviceOrigin(&x, &y);
142 
143     // It's possible that the buffer may be bigger than the area that needs to
144     // be drawn (the client size of the window is smaller than the bitmap, or
145     // a shared bitmap has been reused for a smaller area, etc.) so avoid
146     // blitting too much if possible, but only use the real DC size if the
147     // wxBUFFER_VIRTUAL_AREA style is not set.
148     int width = m_area.GetWidth(),
149         height = m_area.GetHeight();
150 
151     if (!(m_style & wxBUFFER_VIRTUAL_AREA))
152     {
153         int widthDC,
154             heightDC;
155         m_dc->GetSize(&widthDC, &heightDC);
156         width = wxMin(width, widthDC);
157         height = wxMin(height, heightDC);
158     }
159 
160     const wxPoint origin = GetLogicalOrigin();
161     m_dc->Blit(-origin.x, -origin.y, width, height, this, -x, -y);
162     m_dc = NULL;
163 
164     if ( m_style & wxBUFFER_USES_SHARED_BUFFER )
165         wxSharedDCBufferManager::ReleaseBuffer(m_buffer);
166 }
167