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