1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/enhmeta.cpp
3 // Purpose:     implementation of wxEnhMetaFileXXX classes
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     13.01.00
7 // RCS-ID:      $Id: enhmeta.cpp 60850 2009-06-01 10:16:13Z JS $
8 // Copyright:   (c) 2000 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence:     wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11 
12 // ============================================================================
13 // declarations
14 // ============================================================================
15 
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19 
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22 
23 #ifdef __BORLANDC__
24     #pragma hdrstop
25 #endif
26 
27 #if wxUSE_ENH_METAFILE
28 
29 #ifndef WX_PRECOMP
30     #include "wx/string.h"
31     #include "wx/log.h"
32     #include "wx/intl.h"
33 #endif //WX_PRECOMP
34 
35 #include "wx/metafile.h"
36 #include "wx/clipbrd.h"
37 
38 #include "wx/msw/private.h"
39 
40 // ----------------------------------------------------------------------------
41 // wxWin macros
42 // ----------------------------------------------------------------------------
43 
IMPLEMENT_DYNAMIC_CLASS(wxEnhMetaFile,wxObject)44 IMPLEMENT_DYNAMIC_CLASS(wxEnhMetaFile, wxObject)
45 IMPLEMENT_ABSTRACT_CLASS(wxEnhMetaFileDC, wxDC)
46 
47 // ----------------------------------------------------------------------------
48 // macros
49 // ----------------------------------------------------------------------------
50 
51 #define GetEMF()            ((HENHMETAFILE)m_hMF)
52 #define GetEMFOf(mf)        ((HENHMETAFILE)((mf).m_hMF))
53 
54 // ----------------------------------------------------------------------------
55 // private functions
56 // ----------------------------------------------------------------------------
57 
58 // we must pass NULL if the string is empty to metafile functions
59 static inline const wxChar *GetMetaFileName(const wxString& fn)
60     { return !fn ? (wxChar *)NULL : fn.c_str(); }
61 
62 // ============================================================================
63 // implementation
64 // ============================================================================
65 
66 // ----------------------------------------------------------------------------
67 // wxEnhMetaFile
68 // ----------------------------------------------------------------------------
69 
Init()70 void wxEnhMetaFile::Init()
71 {
72     if ( m_filename.empty() )
73     {
74         m_hMF = 0;
75     }
76     else // have valid file name, load metafile from it
77     {
78         m_hMF = (WXHANDLE)::GetEnhMetaFile(m_filename);
79         if ( !m_hMF )
80             wxLogSysError(_("Failed to load metafile from file \"%s\"."),
81                           m_filename.c_str());
82     }
83 }
84 
Assign(const wxEnhMetaFile & mf)85 void wxEnhMetaFile::Assign(const wxEnhMetaFile& mf)
86 {
87     if ( &mf == this )
88         return;
89 
90     if ( mf.m_hMF )
91     {
92         m_hMF = (WXHANDLE)::CopyEnhMetaFile(GetEMFOf(mf),
93                                             GetMetaFileName(m_filename));
94         if ( !m_hMF )
95         {
96             wxLogLastError(_T("CopyEnhMetaFile"));
97         }
98     }
99     else
100     {
101         m_hMF = 0;
102     }
103 }
104 
Free()105 void wxEnhMetaFile::Free()
106 {
107     if ( m_hMF )
108     {
109         if ( !::DeleteEnhMetaFile(GetEMF()) )
110         {
111             wxLogLastError(_T("DeleteEnhMetaFile"));
112         }
113     }
114 }
115 
Play(wxDC * dc,wxRect * rectBound)116 bool wxEnhMetaFile::Play(wxDC *dc, wxRect *rectBound)
117 {
118     wxCHECK_MSG( Ok(), false, _T("can't play invalid enhanced metafile") );
119     wxCHECK_MSG( dc, false, _T("invalid wxDC in wxEnhMetaFile::Play") );
120 
121     RECT rect;
122     if ( rectBound )
123     {
124         rect.top = rectBound->y;
125         rect.left = rectBound->x;
126         rect.right = rectBound->x + rectBound->width;
127         rect.bottom = rectBound->y + rectBound->height;
128     }
129     else
130     {
131         wxSize size = GetSize();
132 
133         rect.top =
134         rect.left = 0;
135         rect.right = size.x;
136         rect.bottom = size.y;
137     }
138 
139     if ( !::PlayEnhMetaFile(GetHdcOf(*dc), GetEMF(), &rect) )
140     {
141         wxLogLastError(_T("PlayEnhMetaFile"));
142 
143         return false;
144     }
145 
146     return true;
147 }
148 
GetSize() const149 wxSize wxEnhMetaFile::GetSize() const
150 {
151     wxSize size = wxDefaultSize;
152 
153     if ( Ok() )
154     {
155         ENHMETAHEADER hdr;
156         if ( !::GetEnhMetaFileHeader(GetEMF(), sizeof(hdr), &hdr) )
157         {
158             wxLogLastError(_T("GetEnhMetaFileHeader"));
159         }
160         else
161         {
162             // the width and height are in HIMETRIC (0.01mm) units, transform
163             // them to pixels
164             LONG w = hdr.rclFrame.right,
165                  h = hdr.rclFrame.bottom;
166 
167             HIMETRICToPixel(&w, &h);
168 
169             size.x = w;
170             size.y = h;
171         }
172     }
173 
174     return size;
175 }
176 
SetClipboard(int WXUNUSED (width),int WXUNUSED (height))177 bool wxEnhMetaFile::SetClipboard(int WXUNUSED(width), int WXUNUSED(height))
178 {
179 #if wxUSE_DRAG_AND_DROP && wxUSE_CLIPBOARD
180     wxCHECK_MSG( m_hMF, false, _T("can't copy invalid metafile to clipboard") );
181 
182     return wxTheClipboard->AddData(new wxEnhMetaFileDataObject(*this));
183 #else // !wxUSE_DRAG_AND_DROP
184     wxFAIL_MSG(_T("not implemented"));
185     return false;
186 #endif // wxUSE_DRAG_AND_DROP/!wxUSE_DRAG_AND_DROP
187 }
188 
189 // ----------------------------------------------------------------------------
190 // wxEnhMetaFileDC
191 // ----------------------------------------------------------------------------
192 
wxEnhMetaFileDC(const wxString & filename,int width,int height,const wxString & description)193 wxEnhMetaFileDC::wxEnhMetaFileDC(const wxString& filename,
194                                  int width, int height,
195                                  const wxString& description)
196 {
197     m_width = width;
198     m_height = height;
199 
200     RECT rect;
201     RECT *pRect;
202     if ( width && height )
203     {
204         rect.top =
205         rect.left = 0;
206         rect.right = width;
207         rect.bottom = height;
208 
209         // CreateEnhMetaFile() wants them in HIMETRIC
210         PixelToHIMETRIC(&rect.right, &rect.bottom);
211 
212         pRect = &rect;
213     }
214     else
215     {
216         // GDI will try to find out the size for us (not recommended)
217         pRect = (LPRECT)NULL;
218     }
219 
220     ScreenHDC hdcRef;
221     m_hDC = (WXHDC)::CreateEnhMetaFile(hdcRef, GetMetaFileName(filename),
222                                        pRect, description);
223     if ( !m_hDC )
224     {
225         wxLogLastError(_T("CreateEnhMetaFile"));
226     }
227 }
228 
229 #if wxUSE_ENH_METAFILE_FROM_DC
230 
PixelToHIMETRIC(LONG * x,LONG * y,HDC hdcRef)231 void PixelToHIMETRIC(LONG *x, LONG *y, HDC hdcRef)
232 {
233     int iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE),
234         iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE),
235         iWidthPels = GetDeviceCaps(hdcRef, HORZRES),
236         iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
237 
238     *x *= (iWidthMM * 100);
239     *x /= iWidthPels;
240     *y *= (iHeightMM * 100);
241     *y /= iHeightPels;
242 }
243 
HIMETRICToPixel(LONG * x,LONG * y,HDC hdcRef)244 void HIMETRICToPixel(LONG *x, LONG *y, HDC hdcRef)
245 {
246     int iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE),
247         iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE),
248         iWidthPels = GetDeviceCaps(hdcRef, HORZRES),
249         iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
250 
251     *x *= iWidthPels;
252     *x /= (iWidthMM * 100);
253     *y *= iHeightPels;
254     *y /= (iHeightMM * 100);
255 }
256 
wxEnhMetaFileDC(const wxDC & referenceDC,const wxString & filename,int width,int height,const wxString & description)257 wxEnhMetaFileDC::wxEnhMetaFileDC(const wxDC& referenceDC,
258                                  const wxString& filename,
259                                  int width, int height,
260                                  const wxString& description)
261 {
262     m_width = width;
263     m_height = height;
264     HDC hdcRef = GetHdcOf(referenceDC);
265 
266     RECT rect;
267     RECT *pRect;
268     if ( width && height )
269     {
270         rect.top =
271         rect.left = 0;
272         rect.right = width;
273         rect.bottom = height;
274 
275         // CreateEnhMetaFile() wants them in HIMETRIC
276         PixelToHIMETRIC(&rect.right, &rect.bottom, hdcRef);
277 
278         pRect = &rect;
279     }
280     else
281     {
282         // GDI will try to find out the size for us (not recommended)
283         pRect = (LPRECT)NULL;
284     }
285 
286     m_hDC = (WXHDC)::CreateEnhMetaFile(hdcRef, GetMetaFileName(filename),
287                                        pRect, description.wx_str());
288     if ( !m_hDC )
289     {
290         wxLogLastError(_T("CreateEnhMetaFile"));
291     }
292 }
293 
294 #endif
295 
DoGetSize(int * width,int * height) const296 void wxEnhMetaFileDC::DoGetSize(int *width, int *height) const
297 {
298     if ( width )
299         *width = m_width;
300     if ( height )
301         *height = m_height;
302 }
303 
Close()304 wxEnhMetaFile *wxEnhMetaFileDC::Close()
305 {
306     wxCHECK_MSG( Ok(), NULL, _T("invalid wxEnhMetaFileDC") );
307 
308     HENHMETAFILE hMF = ::CloseEnhMetaFile(GetHdc());
309     if ( !hMF )
310     {
311         wxLogLastError(_T("CloseEnhMetaFile"));
312 
313         return NULL;
314     }
315 
316     wxEnhMetaFile *mf = new wxEnhMetaFile;
317     mf->SetHENHMETAFILE((WXHANDLE)hMF);
318     return mf;
319 }
320 
~wxEnhMetaFileDC()321 wxEnhMetaFileDC::~wxEnhMetaFileDC()
322 {
323     // avoid freeing it in the base class dtor
324     m_hDC = 0;
325 }
326 
327 #if wxUSE_DRAG_AND_DROP
328 
329 // ----------------------------------------------------------------------------
330 // wxEnhMetaFileDataObject
331 // ----------------------------------------------------------------------------
332 
333 wxDataFormat
GetPreferredFormat(Direction WXUNUSED (dir)) const334 wxEnhMetaFileDataObject::GetPreferredFormat(Direction WXUNUSED(dir)) const
335 {
336     return wxDF_ENHMETAFILE;
337 }
338 
GetFormatCount(Direction WXUNUSED (dir)) const339 size_t wxEnhMetaFileDataObject::GetFormatCount(Direction WXUNUSED(dir)) const
340 {
341     // wxDF_ENHMETAFILE and wxDF_METAFILE
342     return 2;
343 }
344 
GetAllFormats(wxDataFormat * formats,Direction WXUNUSED (dir)) const345 void wxEnhMetaFileDataObject::GetAllFormats(wxDataFormat *formats,
346                                             Direction WXUNUSED(dir)) const
347 {
348     formats[0] = wxDF_ENHMETAFILE;
349     formats[1] = wxDF_METAFILE;
350 }
351 
GetDataSize(const wxDataFormat & format) const352 size_t wxEnhMetaFileDataObject::GetDataSize(const wxDataFormat& format) const
353 {
354     if ( format == wxDF_ENHMETAFILE )
355     {
356         // we pass data by handle and not HGLOBAL
357         return 0u;
358     }
359     else
360     {
361         wxASSERT_MSG( format == wxDF_METAFILE, _T("unsupported format") );
362 
363         return sizeof(METAFILEPICT);
364     }
365 }
366 
GetDataHere(const wxDataFormat & format,void * buf) const367 bool wxEnhMetaFileDataObject::GetDataHere(const wxDataFormat& format, void *buf) const
368 {
369     wxCHECK_MSG( m_metafile.Ok(), false, _T("copying invalid enh metafile") );
370 
371     HENHMETAFILE hEMF = (HENHMETAFILE)m_metafile.GetHENHMETAFILE();
372 
373     if ( format == wxDF_ENHMETAFILE )
374     {
375         HENHMETAFILE hEMFCopy = ::CopyEnhMetaFile(hEMF, NULL);
376         if ( !hEMFCopy )
377         {
378             wxLogLastError(_T("CopyEnhMetaFile"));
379 
380             return false;
381         }
382 
383         *(HENHMETAFILE *)buf = hEMFCopy;
384     }
385     else
386     {
387         wxASSERT_MSG( format == wxDF_METAFILE, _T("unsupported format") );
388 
389         // convert to WMF
390 
391         ScreenHDC hdc;
392 
393         // first get the buffer size and alloc memory
394         size_t size = ::GetWinMetaFileBits(hEMF, 0, NULL, MM_ANISOTROPIC, hdc);
395         wxCHECK_MSG( size, false, _T("GetWinMetaFileBits() failed") );
396 
397         BYTE *bits = (BYTE *)malloc(size);
398 
399         // then get the enh metafile bits
400         if ( !::GetWinMetaFileBits(hEMF, size, bits, MM_ANISOTROPIC, hdc) )
401         {
402             wxLogLastError(_T("GetWinMetaFileBits"));
403 
404             free(bits);
405 
406             return false;
407         }
408 
409         // and finally convert them to the WMF
410         HMETAFILE hMF = ::SetMetaFileBitsEx(size, bits);
411         free(bits);
412         if ( !hMF )
413         {
414             wxLogLastError(_T("SetMetaFileBitsEx"));
415 
416             return false;
417         }
418 
419         METAFILEPICT *mfpict = (METAFILEPICT *)buf;
420 
421         wxSize sizeMF = m_metafile.GetSize();
422         mfpict->hMF  = hMF;
423         mfpict->mm   = MM_ANISOTROPIC;
424         mfpict->xExt = sizeMF.x;
425         mfpict->yExt = sizeMF.y;
426 
427         PixelToHIMETRIC(&mfpict->xExt, &mfpict->yExt);
428     }
429 
430     return true;
431 }
432 
SetData(const wxDataFormat & format,size_t WXUNUSED (len),const void * buf)433 bool wxEnhMetaFileDataObject::SetData(const wxDataFormat& format,
434                                       size_t WXUNUSED(len),
435                                       const void *buf)
436 {
437     HENHMETAFILE hEMF;
438 
439     if ( format == wxDF_ENHMETAFILE )
440     {
441         hEMF = *(HENHMETAFILE *)buf;
442 
443         wxCHECK_MSG( hEMF, false, _T("pasting invalid enh metafile") );
444     }
445     else
446     {
447         wxASSERT_MSG( format == wxDF_METAFILE, _T("unsupported format") );
448 
449         // convert from WMF
450         const METAFILEPICT *mfpict = (const METAFILEPICT *)buf;
451 
452         // first get the buffer size
453         size_t size = ::GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
454         wxCHECK_MSG( size, false, _T("GetMetaFileBitsEx() failed") );
455 
456         // then get metafile bits
457         BYTE *bits = (BYTE *)malloc(size);
458         if ( !::GetMetaFileBitsEx(mfpict->hMF, size, bits) )
459         {
460             wxLogLastError(_T("GetMetaFileBitsEx"));
461 
462             free(bits);
463 
464             return false;
465         }
466 
467         ScreenHDC hdcRef;
468 
469         // and finally create an enhanced metafile from them
470         hEMF = ::SetWinMetaFileBits(size, bits, hdcRef, mfpict);
471         free(bits);
472         if ( !hEMF )
473         {
474             wxLogLastError(_T("SetWinMetaFileBits"));
475 
476             return false;
477         }
478     }
479 
480     m_metafile.SetHENHMETAFILE((WXHANDLE)hEMF);
481 
482     return true;
483 }
484 
485 // ----------------------------------------------------------------------------
486 // wxEnhMetaFileSimpleDataObject
487 // ----------------------------------------------------------------------------
488 
GetDataSize() const489 size_t wxEnhMetaFileSimpleDataObject::GetDataSize() const
490 {
491     // we pass data by handle and not HGLOBAL
492     return 0u;
493 }
494 
GetDataHere(void * buf) const495 bool wxEnhMetaFileSimpleDataObject::GetDataHere(void *buf) const
496 {
497     wxCHECK_MSG( m_metafile.Ok(), false, _T("copying invalid enh metafile") );
498 
499     HENHMETAFILE hEMF = (HENHMETAFILE)m_metafile.GetHENHMETAFILE();
500 
501     HENHMETAFILE hEMFCopy = ::CopyEnhMetaFile(hEMF, NULL);
502     if ( !hEMFCopy )
503     {
504         wxLogLastError(_T("CopyEnhMetaFile"));
505 
506         return false;
507     }
508 
509     *(HENHMETAFILE *)buf = hEMFCopy;
510     return true;
511 }
512 
SetData(size_t WXUNUSED (len),const void * buf)513 bool wxEnhMetaFileSimpleDataObject::SetData(size_t WXUNUSED(len),
514                                             const void *buf)
515 {
516     HENHMETAFILE hEMF = *(HENHMETAFILE *)buf;
517 
518     wxCHECK_MSG( hEMF, false, _T("pasting invalid enh metafile") );
519     m_metafile.SetHENHMETAFILE((WXHANDLE)hEMF);
520 
521     return true;
522 }
523 
524 
525 #endif // wxUSE_DRAG_AND_DROP
526 
527 #endif // wxUSE_ENH_METAFILE
528