1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/os2/metafile.cpp
3 // Purpose:     wxMetaFile, wxMetaFileDC etc. These classes are optional.
4 // Author:      David Webster
5 // Modified by:
6 // Created:     10/10/99
7 // Copyright:   (c) David Webster
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13 
14 #if wxUSE_METAFILE
15 
16 #ifndef WX_PRECOMP
17     #include "wx/utils.h"
18     #include "wx/app.h"
19 #endif
20 
21 #include "wx/metafile.h"
22 #include "wx/clipbrd.h"
23 #include "wx/os2/private.h"
24 
25 #include <stdio.h>
26 #include <string.h>
27 
28 extern bool wxClipboardIsOpen;
29 
IMPLEMENT_DYNAMIC_CLASS(wxMetafile,wxObject)30 IMPLEMENT_DYNAMIC_CLASS(wxMetafile, wxObject)
31 IMPLEMENT_ABSTRACT_CLASS(wxMetafileDC, wxDC)
32 
33 /*
34  * Metafiles
35  * Currently, the only purpose for making a metafile is to put
36  * it on the clipboard.
37  */
38 
39 wxMetafileRefData::wxMetafileRefData(void)
40 {
41     m_metafile = 0;
42     m_windowsMappingMode = MM_ANISOTROPIC;
43 }
44 
~wxMetafileRefData(void)45 wxMetafileRefData::~wxMetafileRefData(void)
46 {
47     if (m_metafile)
48     {
49 // TODO: DeleteMetaFile((HMETAFILE) m_metafile);
50          m_metafile = 0;
51     }
52 }
53 
wxMetafile(const wxString & file)54 wxMetafile::wxMetafile(const wxString& file)
55 {
56     m_refData = new wxMetafileRefData;
57 
58     M_METAFILEDATA->m_windowsMappingMode = MM_ANISOTROPIC;
59     M_METAFILEDATA->m_metafile = 0;
60     if (!file.empty())
61         M_METAFILEDATA->m_metafile = (WXHANDLE)0; // TODO: GetMetaFile(file);
62 }
63 
~wxMetafile(void)64 wxMetafile::~wxMetafile(void)
65 {
66 }
67 
CreateGDIRefData() const68 wxGDIRefData *wxMetafile::CreateGDIRefData() const
69 {
70     return new wxMetafileRefData;
71 }
72 
CloneGDIRefData(const wxGDIRefData * data) const73 wxGDIRefData *wxMetafile::CloneGDIRefData(const wxGDIRefData *data) const
74 {
75     return new wxMetafileRefData(*static_cast<const wxMetafileRefData *>(data));
76 }
77 
SetClipboard(int width,int height)78 bool wxMetafile::SetClipboard(int width, int height)
79 {
80 #if !wxUSE_CLIPBOARD
81     wxUnusedVar(width);
82     wxUnusedVar(height);
83     return false;
84 #else
85     if (!m_refData)
86         return false;
87 
88     bool alreadyOpen=wxClipboardOpen();
89     if (!alreadyOpen)
90     {
91         wxOpenClipboard();
92         if (!wxEmptyClipboard()) return false;
93     }
94     bool success = wxSetClipboardData(wxDF_METAFILE, this, width,height);
95     if (!alreadyOpen) wxCloseClipboard();
96     return (bool) success;
97 #endif
98 }
99 
Play(wxDC * dc)100 bool wxMetafile::Play(wxDC *dc)
101 {
102     if (!m_refData)
103         return false;
104 
105  //   if (dc->GetHDC() && M_METAFILEDATA->m_metafile)
106  //       PlayMetaFile((HDC) dc->GetHDC(), (HMETAFILE) M_METAFILEDATA->m_metafile);
107 
108     return true;
109 }
110 
SetHMETAFILE(WXHANDLE mf)111 void wxMetafile::SetHMETAFILE(WXHANDLE mf)
112 {
113     if (m_refData)
114         m_refData = new wxMetafileRefData;
115 
116     M_METAFILEDATA->m_metafile = mf;
117 }
118 
SetWindowsMappingMode(int mm)119 void wxMetafile::SetWindowsMappingMode(int mm)
120 {
121     if (m_refData)
122         m_refData = new wxMetafileRefData;
123 
124     M_METAFILEDATA->m_windowsMappingMode = mm;
125 }
126 
127 /*
128  * Metafile device context
129  *
130  */
131 
132 // Original constructor that does not takes origin and extent. If you use this,
133 // *DO* give origin/extent arguments to wxMakeMetafilePlaceable.
wxMetafileDCImpl(wxDC * owner,const wxString & file)134 wxMetafileDCImpl::wxMetafileDCImpl(wxDC *owner, const wxString& file)
135     : wxPMDCImpl(owner)
136 {
137   m_metaFile = NULL;
138   m_minX = 10000;
139   m_minY = 10000;
140   m_maxX = -10000;
141   m_maxY = -10000;
142 //  m_title = NULL;
143 
144   if ( wxFileExists(file) )
145     wxRemoveFile(file);
146 
147   // TODO
148 /*
149   if (!file.empty())
150     m_hDC = (WXHDC) CreateMetaFile(file);
151   else
152     m_hDC = (WXHDC) CreateMetaFile(NULL);
153 */
154 
155   m_ok = (m_hDC != (WXHDC) 0) ;
156 
157   // Actual Windows mapping mode, for future reference.
158   m_windowsMappingMode = wxMM_TEXT;
159 
160   SetMapMode(wxMM_TEXT); // NOTE: does not set HDC mapmode (this is correct)
161 }
162 
163 // New constructor that takes origin and extent. If you use this, don't
164 // give origin/extent arguments to wxMakeMetafilePlaceable.
wxMetafileDCImpl(wxDC * owner,const wxString & file,int WXUNUSED (xext),int WXUNUSED (yext),int WXUNUSED (xorg),int WXUNUSED (yorg))165 wxMetafileDCImpl::wxMetafileDCImpl( wxDC *owner, const wxString& file,
166                                     int WXUNUSED(xext),
167                                     int WXUNUSED(yext),
168                                     int WXUNUSED(xorg),
169                                     int WXUNUSED(yorg) )
170     : wxPMDCImpl(owner)
171 {
172     m_minX = 10000;
173     m_minY = 10000;
174     m_maxX = -10000;
175     m_maxY = -10000;
176     if (!file.empty() && wxFileExists(file))
177         wxRemoveFile(file);
178 
179 //  m_hDC = (WXHDC) CreateMetaFile(file);
180 
181     m_ok = true;
182 
183 //  ::SetWindowOrgEx((HDC) m_hDC,xorg,yorg, NULL);
184 //  ::SetWindowExtEx((HDC) m_hDC,xext,yext, NULL);
185 
186     // Actual Windows mapping mode, for future reference.
187     m_windowsMappingMode = MM_ANISOTROPIC;
188 
189     SetMapMode(wxMM_TEXT); // NOTE: does not set HDC mapmode (this is correct)
190 }
191 
~wxMetafileDCImpl(void)192 wxMetafileDCImpl::~wxMetafileDCImpl(void)
193 {
194   m_hDC = 0;
195 }
196 
DoGetTextExtent(const wxString & WXUNUSED (string),wxCoord * WXUNUSED (x),wxCoord * WXUNUSED (y),wxCoord * WXUNUSED (descent),wxCoord * WXUNUSED (externalLeading),const wxFont * theFont) const197 void wxMetafileDCImpl::DoGetTextExtent(const wxString& WXUNUSED(string),
198                                      wxCoord *WXUNUSED(x),
199                                      wxCoord *WXUNUSED(y),
200                                      wxCoord *WXUNUSED(descent),
201                                      wxCoord *WXUNUSED(externalLeading),
202                                      const wxFont *theFont) const
203 {
204     const wxFont *fontToUse = theFont;
205     if (!fontToUse)
206         fontToUse = &m_font;
207 
208     // TODO:
209 /*
210     HDC dc = GetDC(NULL);
211 
212     SIZE sizeRect;
213     TEXTMETRIC tm;
214     GetTextExtentPoint(dc, WXSTRINGCAST string, wxStrlen(WXSTRINGCAST string), &sizeRect);
215     GetTextMetrics(dc, &tm);
216 
217     ReleaseDC(NULL, dc);
218 
219     if ( x )
220         *x = sizeRect.cx;
221     if ( y )
222         *y = sizeRect.cy;
223     if ( descent )
224         *descent = tm.tmDescent;
225     if ( externalLeading )
226         *externalLeading = tm.tmExternalLeading;
227 */
228 }
229 
Close(void)230 wxMetafile *wxMetafileDCImpl::Close(void)
231 {
232   SelectOldObjects(m_hDC);
233   HANDLE mf = 0; // TODO: CloseMetaFile((HDC) m_hDC);
234   m_hDC = 0;
235   if (mf)
236   {
237     wxMetafile *wx_mf = new wxMetafile;
238     wx_mf->SetHMETAFILE((WXHANDLE) mf);
239     wx_mf->SetWindowsMappingMode(m_windowsMappingMode);
240     return wx_mf;
241   }
242   return NULL;
243 }
244 
SetMapMode(wxMappingMode mode)245 void wxMetafileDCImpl::SetMapMode(wxMappingMode mode)
246 {
247   m_mappingMode = mode;
248 
249 //  int pixel_width = 0;
250 //  int pixel_height = 0;
251 //  int mm_width = 0;
252 //  int mm_height = 0;
253 
254   float mm2pixelsX = 10.0;
255   float mm2pixelsY = 10.0;
256 
257   switch (mode)
258   {
259     case wxMM_TWIPS:
260     {
261       m_logicalScaleX = (float)(twips2mm * mm2pixelsX);
262       m_logicalScaleY = (float)(twips2mm * mm2pixelsY);
263       break;
264     }
265     case wxMM_POINTS:
266     {
267       m_logicalScaleX = (float)(pt2mm * mm2pixelsX);
268       m_logicalScaleY = (float)(pt2mm * mm2pixelsY);
269       break;
270     }
271     case wxMM_METRIC:
272     {
273       m_logicalScaleX = mm2pixelsX;
274       m_logicalScaleY = mm2pixelsY;
275       break;
276     }
277     case wxMM_LOMETRIC:
278     {
279       m_logicalScaleX = (float)(mm2pixelsX/10.0);
280       m_logicalScaleY = (float)(mm2pixelsY/10.0);
281       break;
282     }
283     default:
284     case wxMM_TEXT:
285     {
286       m_logicalScaleX = 1.0;
287       m_logicalScaleY = 1.0;
288       break;
289     }
290   }
291   m_nWindowExtX = 100;
292   m_nWindowExtY = 100;
293 }
294 
295 #ifdef __WIN32__
296 struct RECT32
297 {
298   short left;
299   short top;
300   short right;
301   short bottom;
302 };
303 
304 struct mfPLACEABLEHEADER {
305     DWORD  key;
306     short  hmf;
307     RECT32 bbox;
308     WORD   inch;
309     DWORD  reserved;
310     WORD   checksum;
311 };
312 #else
313 struct mfPLACEABLEHEADER {
314     DWORD  key;
315     HANDLE hmf;
316     RECT   bbox;
317     WORD   inch;
318     DWORD  reserved;
319     WORD   checksum;
320 };
321 #endif
322 
323 /*
324  * Pass filename of existing non-placeable metafile, and bounding box.
325  * Adds a placeable metafile header, sets the mapping mode to anisotropic,
326  * and sets the window origin and extent to mimic the wxMM_TEXT mapping mode.
327  *
328  */
329 
wxMakeMetafilePlaceable(const wxString & filename,float scale)330 bool wxMakeMetafilePlaceable(const wxString& filename, float scale)
331 {
332   return wxMakeMetafilePlaceable(filename, 0, 0, 0, 0, scale, FALSE);
333 }
334 
wxMakeMetafilePlaceable(const wxString & WXUNUSED (filename),int WXUNUSED (x1),int WXUNUSED (y1),int WXUNUSED (x2),int WXUNUSED (y2),float WXUNUSED (scale),bool WXUNUSED (useOriginAndExtent))335 bool wxMakeMetafilePlaceable(const wxString& WXUNUSED(filename),
336                              int WXUNUSED(x1),
337                              int WXUNUSED(y1),
338                              int WXUNUSED(x2),
339                              int WXUNUSED(y2),
340                              float WXUNUSED(scale),
341                              bool WXUNUSED(useOriginAndExtent))
342 {
343 // TODO:  the OS/2 PM/MM way to do this
344 /*
345     // I'm not sure if this is the correct way of suggesting a scale
346     // to the client application, but it's the only way I can find.
347     int unitsPerInch = (int)(576/scale);
348 
349     mfPLACEABLEHEADER header;
350     header.key = 0x9AC6CDD7L;
351     header.hmf = 0;
352     header.bbox.xLeft = (int)(x1);
353     header.bbox.yTop = (int)(y1);
354     header.bbox.xRight = (int)(x2);
355     header.bbox.yBottom = (int)(y2);
356     header.inch = unitsPerInch;
357     header.reserved = 0;
358 
359     // Calculate checksum
360     WORD *p;
361     mfPLACEABLEHEADER *pMFHead = &header;
362     for (p =(WORD *)pMFHead,pMFHead -> checksum = 0; p < (WORD *)&pMFHead ->checksum; ++p)
363         pMFHead ->checksum ^= *p;
364 
365     FILE *fd = fopen(filename.fn_str(), "rb");
366     if (!fd)
367         return false;
368 
369     wxChar tempFileBuf[256];
370     wxGetTempFileName(wxT("mf"), tempFileBuf);
371     FILE *fHandle = fopen(wxConvFile.cWX2MB(tempFileBuf), "wb");
372     if (!fHandle)
373         return false;
374     fwrite((void *)&header, sizeof(unsigned char), sizeof(mfPLACEABLEHEADER), fHandle);
375 
376     // Calculate origin and extent
377     int originX = x1;
378     int originY = y1;
379     int extentX = x2 - x1;
380     int extentY = (y2 - y1);
381 
382     // Read metafile header and write
383     METAHEADER metaHeader;
384     fread((void *)&metaHeader, sizeof(unsigned char), sizeof(metaHeader), fd);
385 
386     if (useOriginAndExtent)
387         metaHeader.mtSize += 15;
388     else
389         metaHeader.mtSize += 5;
390 
391     fwrite((void *)&metaHeader, sizeof(unsigned char), sizeof(metaHeader), fHandle);
392 
393     // Write SetMapMode, SetWindowOrigin and SetWindowExt records
394     char modeBuffer[8];
395     char originBuffer[10];
396     char extentBuffer[10];
397     METARECORD *modeRecord = (METARECORD *)&modeBuffer;
398 
399     METARECORD *originRecord = (METARECORD *)&originBuffer;
400     METARECORD *extentRecord = (METARECORD *)&extentBuffer;
401 
402     modeRecord->rdSize = 4;
403     modeRecord->rdFunction = META_SETMAPMODE;
404     modeRecord->rdParm[0] = MM_ANISOTROPIC;
405 
406     originRecord->rdSize = 5;
407     originRecord->rdFunction = META_SETWINDOWORG;
408     originRecord->rdParm[0] = originY;
409     originRecord->rdParm[1] = originX;
410 
411     extentRecord->rdSize = 5;
412     extentRecord->rdFunction = META_SETWINDOWEXT;
413     extentRecord->rdParm[0] = extentY;
414     extentRecord->rdParm[1] = extentX;
415 
416     fwrite((void *)modeBuffer, sizeof(char), 8, fHandle);
417 
418     if (useOriginAndExtent)
419     {
420         fwrite((void *)originBuffer, sizeof(char), 10, fHandle);
421         fwrite((void *)extentBuffer, sizeof(char), 10, fHandle);
422     }
423 
424     int ch = -2;
425     while (ch != EOF)
426     {
427         ch = getc(fd);
428         if (ch != EOF)
429         {
430             putc(ch, fHandle);
431         }
432     }
433     fclose(fHandle);
434     fclose(fd);
435     wxRemoveFile(filename);
436     wxCopyFile(tempFileBuf, filename);
437     wxRemoveFile(tempFileBuf);
438 */
439     return true;
440 }
441 
442 #endif // wxUSE_METAFILE
443