PageRenderTime 33ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/ExtLibs/wxWidgets/src/msw/metafile.cpp

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