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 // Copyright:   (c) 2000 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
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 
23 #if wxUSE_ENH_METAFILE
24 
25 #ifndef WX_PRECOMP
26     #include "wx/string.h"
27     #include "wx/log.h"
28     #include "wx/intl.h"
29 #endif //WX_PRECOMP
30 
31 #include "wx/dc.h"
32 #include "wx/msw/dc.h"
33 
34 #include "wx/metafile.h"
35 #include "wx/clipbrd.h"
36 
37 #include "wx/msw/private.h"
38 
39 // ----------------------------------------------------------------------------
40 // wxWin macros
41 // ----------------------------------------------------------------------------
42 
43 wxIMPLEMENT_DYNAMIC_CLASS(wxEnhMetaFile, wxObject);
44 
45 // ----------------------------------------------------------------------------
46 // macros
47 // ----------------------------------------------------------------------------
48 
49 #define GetEMF()            ((HENHMETAFILE)m_hMF)
50 #define GetEMFOf(mf)        ((HENHMETAFILE)((mf).m_hMF))
51 
52 // ----------------------------------------------------------------------------
53 // private functions
54 // ----------------------------------------------------------------------------
55 
56 // we must pass NULL if the string is empty to metafile functions
GetMetaFileName(const wxString & fn)57 static inline const wxChar *GetMetaFileName(const wxString& fn)
58     { return !fn ? NULL : wxMSW_CONV_LPCTSTR(fn); }
59 
60 // ============================================================================
61 // implementation
62 // ============================================================================
63 
64 // ----------------------------------------------------------------------------
65 // wxEnhMetaFile
66 // ----------------------------------------------------------------------------
67 
CreateGDIRefData() const68 wxGDIRefData *wxEnhMetaFile::CreateGDIRefData() const
69 {
70     wxFAIL_MSG( wxT("must be implemented if used") );
71 
72     return NULL;
73 }
74 
75 wxGDIRefData *
CloneGDIRefData(const wxGDIRefData * WXUNUSED (data)) const76 wxEnhMetaFile::CloneGDIRefData(const wxGDIRefData *WXUNUSED(data)) const
77 {
78     wxFAIL_MSG( wxT("must be implemented if used") );
79 
80     return NULL;
81 }
82 
Init()83 void wxEnhMetaFile::Init()
84 {
85     if ( m_filename.empty() )
86     {
87         m_hMF = 0;
88     }
89     else // have valid file name, load metafile from it
90     {
91         m_hMF = (WXHANDLE)::GetEnhMetaFile(m_filename.t_str());
92         if ( !m_hMF )
93         {
94             wxLogSysError(_("Failed to load metafile from file \"%s\"."),
95                           m_filename.c_str());
96         }
97     }
98 }
99 
Assign(const wxEnhMetaFile & mf)100 void wxEnhMetaFile::Assign(const wxEnhMetaFile& mf)
101 {
102     if ( &mf == this )
103         return;
104 
105     if ( mf.m_hMF )
106     {
107         m_hMF = (WXHANDLE)::CopyEnhMetaFile(GetEMFOf(mf),
108                                             GetMetaFileName(m_filename));
109         if ( !m_hMF )
110         {
111             wxLogLastError(wxT("CopyEnhMetaFile"));
112         }
113     }
114     else
115     {
116         m_hMF = 0;
117     }
118 }
119 
120 /* static */
Free(WXHANDLE handle)121 void wxEnhMetaFile::Free(WXHANDLE handle)
122 {
123     if ( handle )
124     {
125         if ( !::DeleteEnhMetaFile((HENHMETAFILE) handle) )
126         {
127             wxLogLastError(wxT("DeleteEnhMetaFile"));
128         }
129     }
130 }
131 
Play(wxDC * dc,wxRect * rectBound)132 bool wxEnhMetaFile::Play(wxDC *dc, wxRect *rectBound)
133 {
134     wxCHECK_MSG( IsOk(), false, wxT("can't play invalid enhanced metafile") );
135     wxCHECK_MSG( dc, false, wxT("invalid wxDC in wxEnhMetaFile::Play") );
136 
137     RECT rect;
138     if ( rectBound )
139     {
140         rect.top = rectBound->y;
141         rect.left = rectBound->x;
142         rect.right = rectBound->x + rectBound->width;
143         rect.bottom = rectBound->y + rectBound->height;
144     }
145     else
146     {
147         wxSize size = GetSize();
148 
149         rect.top =
150         rect.left = 0;
151         rect.right = size.x;
152         rect.bottom = size.y;
153     }
154 
155     wxDCImpl *impl = dc->GetImpl();
156     wxMSWDCImpl *msw_impl = wxDynamicCast( impl, wxMSWDCImpl );
157     if (!msw_impl)
158         return false;
159 
160     if ( !::PlayEnhMetaFile(GetHdcOf(*msw_impl), GetEMF(), &rect) )
161     {
162         wxLogLastError(wxT("PlayEnhMetaFile"));
163 
164         return false;
165     }
166 
167     return true;
168 }
169 
GetSize() const170 wxSize wxEnhMetaFile::GetSize() const
171 {
172     wxSize size = wxDefaultSize;
173 
174     if ( IsOk() )
175     {
176         ENHMETAHEADER hdr;
177         if ( !::GetEnhMetaFileHeader(GetEMF(), sizeof(hdr), &hdr) )
178         {
179             wxLogLastError(wxT("GetEnhMetaFileHeader"));
180         }
181         else
182         {
183             // the width and height are in HIMETRIC (0.01mm) units, transform
184             // them to pixels
185             LONG w = hdr.rclFrame.right,
186                  h = hdr.rclFrame.bottom;
187 
188             HIMETRICToPixel(&w, &h);
189 
190             size.x = w;
191             size.y = h;
192         }
193     }
194 
195     return size;
196 }
197 
SetClipboard(int WXUNUSED (width),int WXUNUSED (height))198 bool wxEnhMetaFile::SetClipboard(int WXUNUSED(width), int WXUNUSED(height))
199 {
200 #if wxUSE_DRAG_AND_DROP && wxUSE_CLIPBOARD
201     wxCHECK_MSG( m_hMF, false, wxT("can't copy invalid metafile to clipboard") );
202 
203     return wxTheClipboard->AddData(new wxEnhMetaFileDataObject(*this));
204 #else // !wxUSE_DRAG_AND_DROP
205     wxFAIL_MSG(wxT("not implemented"));
206     return false;
207 #endif // wxUSE_DRAG_AND_DROP/!wxUSE_DRAG_AND_DROP
208 }
209 
210 // ----------------------------------------------------------------------------
211 // wxEnhMetaFileDCImpl
212 // ----------------------------------------------------------------------------
213 
214 class wxEnhMetaFileDCImpl : public wxMSWDCImpl
215 {
216 public:
217     wxEnhMetaFileDCImpl( wxEnhMetaFileDC *owner,
218                          const wxString& filename, int width, int height,
219                          const wxString& description );
220     wxEnhMetaFileDCImpl( wxEnhMetaFileDC *owner,
221                          const wxDC& referenceDC,
222                          const wxString& filename, int width, int height,
223                          const wxString& description );
224     virtual ~wxEnhMetaFileDCImpl();
225 
226     // obtain a pointer to the new metafile (caller should delete it)
227     wxEnhMetaFile *Close();
228 
229 protected:
230     virtual void DoGetSize(int *width, int *height) const wxOVERRIDE;
231 
232 private:
233     void Create(HDC hdcRef,
234                 const wxString& filename, int width, int height,
235                 const wxString& description);
236 
237     // size passed to ctor and returned by DoGetSize()
238     int m_width,
239         m_height;
240 };
241 
242 
wxEnhMetaFileDCImpl(wxEnhMetaFileDC * owner,const wxString & filename,int width,int height,const wxString & description)243 wxEnhMetaFileDCImpl::wxEnhMetaFileDCImpl( wxEnhMetaFileDC* owner,
244                                  const wxString& filename,
245                                  int width, int height,
246                                  const wxString& description )
247                    : wxMSWDCImpl( owner )
248 {
249     Create(ScreenHDC(), filename, width, height, description);
250 }
251 
wxEnhMetaFileDCImpl(wxEnhMetaFileDC * owner,const wxDC & referenceDC,const wxString & filename,int width,int height,const wxString & description)252 wxEnhMetaFileDCImpl::wxEnhMetaFileDCImpl( wxEnhMetaFileDC* owner,
253                                  const wxDC& referenceDC,
254                                  const wxString& filename,
255                                  int width, int height,
256                                  const wxString& description )
257                    : wxMSWDCImpl( owner )
258 {
259     Create(GetHdcOf(referenceDC), filename, width, height, description);
260 }
261 
Create(HDC hdcRef,const wxString & filename,int width,int height,const wxString & description)262 void wxEnhMetaFileDCImpl::Create(HDC hdcRef,
263                                  const wxString& filename,
264                                  int width, int height,
265                                  const wxString& description)
266 {
267     m_width = width;
268     m_height = height;
269 
270     RECT rect;
271     RECT *pRect;
272     if ( width && height )
273     {
274         rect.top =
275         rect.left = 0;
276         rect.right = width;
277         rect.bottom = height;
278 
279         // CreateEnhMetaFile() wants them in HIMETRIC
280         PixelToHIMETRIC(&rect.right, &rect.bottom, hdcRef);
281 
282         pRect = &rect;
283     }
284     else
285     {
286         // GDI will try to find out the size for us (not recommended)
287         pRect = (LPRECT)NULL;
288     }
289 
290     m_hDC = (WXHDC)::CreateEnhMetaFile(hdcRef, GetMetaFileName(filename),
291                                        pRect, description.t_str());
292     if ( !m_hDC )
293     {
294         wxLogLastError(wxT("CreateEnhMetaFile"));
295     }
296 }
297 
DoGetSize(int * width,int * height) const298 void wxEnhMetaFileDCImpl::DoGetSize(int *width, int *height) const
299 {
300     if ( width )
301         *width = m_width;
302     if ( height )
303         *height = m_height;
304 }
305 
Close()306 wxEnhMetaFile *wxEnhMetaFileDCImpl::Close()
307 {
308     wxCHECK_MSG( IsOk(), NULL, wxT("invalid wxEnhMetaFileDC") );
309 
310     HENHMETAFILE hMF = ::CloseEnhMetaFile(GetHdc());
311     if ( !hMF )
312     {
313         wxLogLastError(wxT("CloseEnhMetaFile"));
314 
315         return NULL;
316     }
317 
318     wxEnhMetaFile *mf = new wxEnhMetaFile;
319     mf->SetHENHMETAFILE((WXHANDLE)hMF);
320     return mf;
321 }
322 
~wxEnhMetaFileDCImpl()323 wxEnhMetaFileDCImpl::~wxEnhMetaFileDCImpl()
324 {
325     // avoid freeing it in the base class dtor
326     m_hDC = 0;
327 }
328 
329 // ----------------------------------------------------------------------------
330 // wxEnhMetaFileDC
331 // ----------------------------------------------------------------------------
332 
333 wxIMPLEMENT_ABSTRACT_CLASS(wxEnhMetaFileDC, wxDC);
334 
wxEnhMetaFileDC(const wxString & filename,int width,int height,const wxString & description)335 wxEnhMetaFileDC::wxEnhMetaFileDC(const wxString& filename,
336                                  int width, int height,
337                                  const wxString& description)
338                : wxDC(new wxEnhMetaFileDCImpl(this,
339                                               filename,
340                                               width, height,
341                                               description))
342 {
343 }
344 
wxEnhMetaFileDC(const wxDC & referenceDC,const wxString & filename,int width,int height,const wxString & description)345 wxEnhMetaFileDC::wxEnhMetaFileDC(const wxDC& referenceDC,
346                                  const wxString& filename,
347                                  int width, int height,
348                                  const wxString& description)
349                : wxDC(new wxEnhMetaFileDCImpl(this,
350                                               referenceDC,
351                                               filename,
352                                               width, height,
353                                               description))
354 {
355 }
356 
Close()357 wxEnhMetaFile *wxEnhMetaFileDC::Close()
358 {
359     wxEnhMetaFileDCImpl * const
360         impl = static_cast<wxEnhMetaFileDCImpl *>(GetImpl());
361     wxCHECK_MSG( impl, NULL, wxT("no wxEnhMetaFileDC implementation") );
362 
363     return impl->Close();
364 }
365 
366 #if wxUSE_DRAG_AND_DROP
367 
368 // ----------------------------------------------------------------------------
369 // wxEnhMetaFileDataObject
370 // ----------------------------------------------------------------------------
371 
372 wxDataFormat
GetPreferredFormat(Direction WXUNUSED (dir)) const373 wxEnhMetaFileDataObject::GetPreferredFormat(Direction WXUNUSED(dir)) const
374 {
375     return wxDF_ENHMETAFILE;
376 }
377 
GetFormatCount(Direction WXUNUSED (dir)) const378 size_t wxEnhMetaFileDataObject::GetFormatCount(Direction WXUNUSED(dir)) const
379 {
380     // wxDF_ENHMETAFILE and wxDF_METAFILE
381     return 2;
382 }
383 
GetAllFormats(wxDataFormat * formats,Direction WXUNUSED (dir)) const384 void wxEnhMetaFileDataObject::GetAllFormats(wxDataFormat *formats,
385                                             Direction WXUNUSED(dir)) const
386 {
387     formats[0] = wxDF_ENHMETAFILE;
388     formats[1] = wxDF_METAFILE;
389 }
390 
GetDataSize(const wxDataFormat & format) const391 size_t wxEnhMetaFileDataObject::GetDataSize(const wxDataFormat& format) const
392 {
393     if ( format == wxDF_ENHMETAFILE )
394     {
395         // we pass data by handle and not HGLOBAL
396         return 0u;
397     }
398     else
399     {
400         wxASSERT_MSG( format == wxDF_METAFILE, wxT("unsupported format") );
401 
402         return sizeof(METAFILEPICT);
403     }
404 }
405 
GetDataHere(const wxDataFormat & format,void * buf) const406 bool wxEnhMetaFileDataObject::GetDataHere(const wxDataFormat& format, void *buf) const
407 {
408     wxCHECK_MSG( m_metafile.IsOk(), false, wxT("copying invalid enh metafile") );
409 
410     HENHMETAFILE hEMF = (HENHMETAFILE)m_metafile.GetHENHMETAFILE();
411 
412     if ( format == wxDF_ENHMETAFILE )
413     {
414         HENHMETAFILE hEMFCopy = ::CopyEnhMetaFile(hEMF, NULL);
415         if ( !hEMFCopy )
416         {
417             wxLogLastError(wxT("CopyEnhMetaFile"));
418 
419             return false;
420         }
421 
422         *(HENHMETAFILE *)buf = hEMFCopy;
423     }
424     else
425     {
426         wxASSERT_MSG( format == wxDF_METAFILE, wxT("unsupported format") );
427 
428         // convert to WMF
429 
430         ScreenHDC hdc;
431 
432         // first get the buffer size and alloc memory
433         size_t size = ::GetWinMetaFileBits(hEMF, 0, NULL, MM_ANISOTROPIC, hdc);
434         wxCHECK_MSG( size, false, wxT("GetWinMetaFileBits() failed") );
435 
436         BYTE *bits = (BYTE *)malloc(size);
437 
438         // then get the enh metafile bits
439         if ( !::GetWinMetaFileBits(hEMF, size, bits, MM_ANISOTROPIC, hdc) )
440         {
441             wxLogLastError(wxT("GetWinMetaFileBits"));
442 
443             free(bits);
444 
445             return false;
446         }
447 
448         // and finally convert them to the WMF
449         HMETAFILE hMF = ::SetMetaFileBitsEx(size, bits);
450         free(bits);
451         if ( !hMF )
452         {
453             wxLogLastError(wxT("SetMetaFileBitsEx"));
454 
455             return false;
456         }
457 
458         METAFILEPICT *mfpict = (METAFILEPICT *)buf;
459 
460         wxSize sizeMF = m_metafile.GetSize();
461         mfpict->hMF  = hMF;
462         mfpict->mm   = MM_ANISOTROPIC;
463         mfpict->xExt = sizeMF.x;
464         mfpict->yExt = sizeMF.y;
465 
466         PixelToHIMETRIC(&mfpict->xExt, &mfpict->yExt);
467     }
468 
469     return true;
470 }
471 
SetData(const wxDataFormat & format,size_t WXUNUSED (len),const void * buf)472 bool wxEnhMetaFileDataObject::SetData(const wxDataFormat& format,
473                                       size_t WXUNUSED(len),
474                                       const void *buf)
475 {
476     HENHMETAFILE hEMF;
477 
478     if ( format == wxDF_ENHMETAFILE )
479     {
480         hEMF = *static_cast<const HENHMETAFILE*>(buf);
481 
482         wxCHECK_MSG( hEMF, false, wxT("pasting invalid enh metafile") );
483     }
484     else
485     {
486         wxASSERT_MSG( format == wxDF_METAFILE, wxT("unsupported format") );
487 
488         // convert from WMF
489         const METAFILEPICT *mfpict = (const METAFILEPICT *)buf;
490 
491         // first get the buffer size
492         size_t size = ::GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
493         wxCHECK_MSG( size, false, wxT("GetMetaFileBitsEx() failed") );
494 
495         // then get metafile bits
496         BYTE *bits = (BYTE *)malloc(size);
497         if ( !::GetMetaFileBitsEx(mfpict->hMF, size, bits) )
498         {
499             wxLogLastError(wxT("GetMetaFileBitsEx"));
500 
501             free(bits);
502 
503             return false;
504         }
505 
506         ScreenHDC hdcRef;
507 
508         // and finally create an enhanced metafile from them
509         hEMF = ::SetWinMetaFileBits(size, bits, hdcRef, mfpict);
510         free(bits);
511         if ( !hEMF )
512         {
513             wxLogLastError(wxT("SetWinMetaFileBits"));
514 
515             return false;
516         }
517     }
518 
519     m_metafile.SetHENHMETAFILE((WXHANDLE)hEMF);
520 
521     return true;
522 }
523 
524 // ----------------------------------------------------------------------------
525 // wxEnhMetaFileSimpleDataObject
526 // ----------------------------------------------------------------------------
527 
GetDataSize() const528 size_t wxEnhMetaFileSimpleDataObject::GetDataSize() const
529 {
530     // we pass data by handle and not HGLOBAL
531     return 0u;
532 }
533 
GetDataHere(void * buf) const534 bool wxEnhMetaFileSimpleDataObject::GetDataHere(void *buf) const
535 {
536     wxCHECK_MSG( m_metafile.IsOk(), false, wxT("copying invalid enh metafile") );
537 
538     HENHMETAFILE hEMF = (HENHMETAFILE)m_metafile.GetHENHMETAFILE();
539 
540     HENHMETAFILE hEMFCopy = ::CopyEnhMetaFile(hEMF, NULL);
541     if ( !hEMFCopy )
542     {
543         wxLogLastError(wxT("CopyEnhMetaFile"));
544 
545         return false;
546     }
547 
548     *(HENHMETAFILE *)buf = hEMFCopy;
549     return true;
550 }
551 
SetData(size_t WXUNUSED (len),const void * buf)552 bool wxEnhMetaFileSimpleDataObject::SetData(size_t WXUNUSED(len),
553                                             const void *buf)
554 {
555     HENHMETAFILE hEMF = *static_cast<const HENHMETAFILE*>(buf);
556 
557     wxCHECK_MSG( hEMF, false, wxT("pasting invalid enh metafile") );
558     m_metafile.SetHENHMETAFILE((WXHANDLE)hEMF);
559 
560     return true;
561 }
562 
563 
564 #endif // wxUSE_DRAG_AND_DROP
565 
566 #endif // wxUSE_ENH_METAFILE
567