1///////////////////////////////////////////////////////////////////////////// 2// Name: src/mac/carbon/metafile.cpp 3// Purpose: wxMetaFile, wxMetaFileDC etc. These classes are optional. 4// Author: Stefan Csomor 5// Modified by: 6// Created: 04/01/98 7// RCS-ID: $Id: metafile.cpp 49303 2007-10-21 18:12:25Z SC $ 8// Copyright: (c) Stefan Csomor 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11// 12// Currently, the only purpose for making a metafile 13// is to put it on the clipboard. 14 15 16#include "wx/wxprec.h" 17 18#if wxUSE_METAFILE 19 20#ifndef WX_PRECOMP 21 #include "wx/utils.h" 22 #include "wx/app.h" 23#endif 24 25#include "wx/metafile.h" 26#include "wx/clipbrd.h" 27#include "wx/mac/uma.h" 28#include "wx/graphics.h" 29 30#include <stdio.h> 31#include <string.h> 32 33IMPLEMENT_DYNAMIC_CLASS(wxMetafile, wxObject) 34IMPLEMENT_ABSTRACT_CLASS(wxMetafileDC, wxDC) 35 36#define M_METAFILEREFDATA( a ) ((wxMetafileRefData*)(a).GetRefData()) 37 38class wxMetafileRefData: public wxGDIRefData 39{ 40public: 41#if wxMAC_USE_CORE_GRAPHICS 42 // creates a metafile from memory, assumes ownership 43 wxMetafileRefData(CFDataRef data); 44#else 45 // creates a metafile from memory, assumes ownership 46 wxMetafileRefData(PicHandle data); 47#endif 48 // prepares a recording metafile 49 wxMetafileRefData( int width, int height); 50 // prepares a metafile to be read from a file (if filename is not empty) 51 wxMetafileRefData( const wxString& filename); 52 virtual ~wxMetafileRefData(); 53 54 void Init(); 55 56 int GetWidth() const { return m_width; } 57 int GetHeight() const { return m_height; } 58 59#if wxMAC_USE_CORE_GRAPHICS 60 CGPDFDocumentRef GetPDFDocument() const { return m_pdfDoc; } 61 void UpdateDocumentFromData() ; 62 63 const wxCFDataRef& GetData() const { return m_data; } 64 CGContextRef GetContext() const { return m_context; } 65#else 66 PicHandle GetHandle() const { return m_metafile; } 67#endif 68 // ends the recording 69 void Close(); 70private: 71#if wxMAC_USE_CORE_GRAPHICS 72 wxCFDataRef m_data; 73 wxCFRef<CGPDFDocumentRef> m_pdfDoc; 74 CGContextRef m_context; 75#else 76 PicHandle m_metafile; 77#endif 78 int m_width ; 79 int m_height ; 80}; 81 82#if !wxMAC_USE_CORE_GRAPHICS 83wxMetafileRefData::wxMetafileRefData(PicHandle pict) 84{ 85 Init(); 86 m_metafile = pict; 87 88 Rect r; 89 wxMacGetPictureBounds( m_metafile, &r ); 90 m_width = r.right - r.left; 91 m_height = r.bottom - r.top; 92} 93#else 94wxMetafileRefData::wxMetafileRefData(CFDataRef data) : 95 m_data(data) 96{ 97 Init(); 98 UpdateDocumentFromData(); 99} 100#endif 101 102wxMetafileRefData::wxMetafileRefData( const wxString& filename ) 103{ 104 Init(); 105#if wxMAC_USE_CORE_GRAPHICS 106 if ( !filename.empty() ) 107 { 108 wxCFRef<CFMutableStringRef> cfMutableString(CFStringCreateMutableCopy(NULL, 0, wxMacCFStringHolder(filename))); 109 CFStringNormalize(cfMutableString,kCFStringNormalizationFormD); 110 wxCFRef<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfMutableString , kCFURLPOSIXPathStyle, false)); 111 m_pdfDoc.reset(CGPDFDocumentCreateWithURL(url)); 112 } 113#else 114 wxASSERT_MSG( filename.empty(), wxT("no file-based metafile support yet") ); 115 m_metafile = NULL; 116#endif 117} 118 119 120wxMetafileRefData::wxMetafileRefData( int width, int height) 121{ 122 Init(); 123 124 m_width = width; 125 m_height = height; 126#if wxMAC_USE_CORE_GRAPHICS 127 CGRect r = CGRectMake( 0 , 0 , width , height ); 128 129 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0); 130 m_data.reset(data); 131 CGDataConsumerRef dataConsumer = UMACGDataConsumerCreateWithCFData(data); 132 m_context = CGPDFContextCreate( dataConsumer, (width != 0 && height != 0) ? &r : NULL , NULL ); 133 CGDataConsumerRelease( dataConsumer ); 134 if ( m_context ) 135 { 136#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 137 if ( &CGPDFContextBeginPage != NULL ) 138 CGPDFContextBeginPage(m_context, NULL); 139 else 140#endif 141 CGContextBeginPage(m_context, &r); 142 143 CGColorSpaceRef genericColorSpace = wxMacGetGenericRGBColorSpace(); 144 145 CGContextSetFillColorSpace( m_context, genericColorSpace ); 146 CGContextSetStrokeColorSpace( m_context, genericColorSpace ); 147 148 CGContextTranslateCTM( m_context , 0 , height ) ; 149 CGContextScaleCTM( m_context , 1 , -1 ) ; 150 } 151#else 152 Rect r = { 0, 0, height, width }; 153 m_metafile = OpenPicture( &r ) ; 154#endif 155} 156 157wxMetafileRefData::~wxMetafileRefData() 158{ 159#if! wxMAC_USE_CORE_GRAPHICS 160 if (m_metafile) 161 { 162 KillPicture( (PicHandle)m_metafile ); 163 m_metafile = NULL; 164 } 165#endif 166} 167 168void wxMetafileRefData::Init() 169{ 170#if wxMAC_USE_CORE_GRAPHICS 171 m_context = NULL; 172#else 173 m_metafile = NULL; 174#endif 175 m_width = -1; 176 m_height = -1; 177} 178 179void wxMetafileRefData::Close() 180{ 181#if wxMAC_USE_CORE_GRAPHICS 182#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 183 if ( &CGPDFContextEndPage != NULL ) 184 CGPDFContextEndPage(m_context); 185 else 186#endif 187 CGContextEndPage(m_context); 188 189 CGContextRelease(m_context); 190 m_context = NULL; 191 192 UpdateDocumentFromData(); 193#else 194 ClosePicture(); 195#endif 196} 197 198#if wxMAC_USE_CORE_GRAPHICS 199void wxMetafileRefData::UpdateDocumentFromData() 200{ 201 wxCFRef<CGDataProviderRef> provider(UMACGDataProviderCreateWithCFData(m_data)); 202 m_pdfDoc.reset(CGPDFDocumentCreateWithProvider(provider)); 203 if ( m_pdfDoc != NULL ) 204 { 205 CGPDFPageRef page = CGPDFDocumentGetPage( m_pdfDoc, 1 ); 206 CGRect rect = CGPDFPageGetBoxRect ( page, kCGPDFMediaBox); 207 m_width = rect.size.width; 208 m_height = rect.size.height; 209 } 210} 211#endif 212 213wxMetaFile::wxMetaFile(const wxString& file) 214{ 215 m_refData = new wxMetafileRefData(file); 216} 217 218wxMetaFile::~wxMetaFile() 219{ 220} 221 222bool wxMetaFile::IsOk() const 223{ 224#if wxMAC_USE_CORE_GRAPHICS 225 return (M_METAFILEDATA && (M_METAFILEDATA->GetData() != NULL)); 226#else 227 return (M_METAFILEDATA && (M_METAFILEDATA->GetHandle() != NULL)); 228#endif 229} 230 231WXHMETAFILE wxMetaFile::GetHMETAFILE() const 232{ 233#if wxMAC_USE_CORE_GRAPHICS 234 return (WXHMETAFILE) (CFDataRef) M_METAFILEDATA->GetData(); 235#else 236 return (WXHMETAFILE) M_METAFILEDATA->GetHandle(); 237#endif 238} 239 240bool wxMetaFile::SetClipboard(int width, int height) 241{ 242 bool success = true; 243 244#if wxUSE_DRAG_AND_DROP 245 if (m_refData == NULL) 246 return false; 247 248 bool alreadyOpen = wxTheClipboard->IsOpened(); 249 if (!alreadyOpen) 250 { 251 wxTheClipboard->Open(); 252 wxTheClipboard->Clear(); 253 } 254 255 wxDataObject *data = new wxMetafileDataObject( *this ); 256 success = wxTheClipboard->SetData( data ); 257 if (!alreadyOpen) 258 wxTheClipboard->Close(); 259#endif 260 261 return success; 262} 263 264void wxMetafile::SetHMETAFILE(WXHMETAFILE mf) 265{ 266 UnRef(); 267 268#if wxMAC_USE_CORE_GRAPHICS 269 m_refData = new wxMetafileRefData((CFDataRef)mf); 270#else 271 m_refData = new wxMetafileRefData((PicHandle)mf); 272#endif 273} 274 275void wxMetafile::SetPICT(void* pictHandle) 276{ 277 UnRef(); 278 279#if wxMAC_USE_CORE_GRAPHICS 280 Handle picHandle = (Handle) pictHandle; 281 HLock(picHandle); 282 CFDataRef data = CFDataCreateWithBytesNoCopy( kCFAllocatorDefault, (const UInt8*) *picHandle, GetHandleSize(picHandle), kCFAllocatorNull); 283 wxCFRef<CGDataProviderRef> provider(UMACGDataProviderCreateWithCFData(data)); 284 QDPictRef pictRef = QDPictCreateWithProvider(provider); 285 CGRect rect = QDPictGetBounds(pictRef); 286 m_refData = new wxMetafileRefData( rect.size.width, rect.size.height ); 287 QDPictDrawToCGContext( ((wxMetafileRefData*) m_refData)->GetContext(), rect, pictRef ); 288 CFRelease( data ); 289 QDPictRelease( pictRef ); 290 ((wxMetafileRefData*) m_refData)->Close(); 291#else 292 m_refData = new wxMetafileRefData((PicHandle)pictHandle); 293#endif 294} 295 296bool wxMetaFile::Play(wxDC *dc) 297{ 298 if (!m_refData) 299 return false; 300 301 if (!dc->Ok()) 302 return false; 303 304 { 305#if wxMAC_USE_CORE_GRAPHICS 306 CGContextRef cg = (CGContextRef) dc->GetGraphicsContext()->GetNativeContext(); 307 CGPDFDocumentRef doc = M_METAFILEDATA->GetPDFDocument(); 308 CGPDFPageRef page = CGPDFDocumentGetPage( doc, 1 ); 309 wxMacCGContextStateSaver save(cg); 310 CGContextDrawPDFPage( cg, page ); 311// CGContextTranslateCTM( cg, 0, bounds.size.width ); 312// CGContextScaleCTM( cg, 1, -1 ); 313 #else 314 PicHandle pict = (PicHandle)GetHMETAFILE(); 315 wxMacPortSetter helper( dc ); 316 Rect picFrame; 317 DrawPicture( pict, wxMacGetPictureBounds( pict, &picFrame ) ); 318#endif 319 } 320 321 return true; 322} 323 324wxSize wxMetaFile::GetSize() const 325{ 326 wxSize dataSize = wxDefaultSize; 327 328 if (Ok()) 329 { 330 dataSize.x = M_METAFILEDATA->GetWidth(); 331 dataSize.y = M_METAFILEDATA->GetHeight(); 332 } 333 334 return dataSize; 335} 336 337// Metafile device context 338 339// New constructor that takes origin and extent. If you use this, don't 340// give origin/extent arguments to wxMakeMetaFilePlaceable. 341 342wxMetaFileDC::wxMetaFileDC( 343 const wxString& filename, 344 int width, int height, 345 const wxString& WXUNUSED(description) ) 346{ 347 wxASSERT_MSG( width != 0 || height != 0, wxT("no arbitration of metafile size supported") ); 348 wxASSERT_MSG( filename.empty(), wxT("no file based metafile support yet")); 349 350 m_metaFile = new wxMetaFile( filename ); 351 wxMetafileRefData* metafiledata = new wxMetafileRefData(width, height); 352 m_metaFile->UnRef(); 353 m_metaFile->SetRefData( metafiledata ); 354#if wxMAC_USE_CORE_GRAPHICS 355 SetGraphicsContext( wxGraphicsContext::CreateFromNative(metafiledata->GetContext())); 356 m_ok = (m_graphicContext != NULL) ; 357#else 358 Rect r = { 0, 0, height, width }; 359 RectRgn( (RgnHandle)m_macBoundaryClipRgn, &r ); 360 CopyRgn( (RgnHandle)m_macBoundaryClipRgn, (RgnHandle)m_macCurrentClipRgn ); 361 ::GetPort( (GrafPtr*)&m_macPort ); 362 m_ok = true; 363#endif 364 365 SetMapMode( wxMM_TEXT ); 366} 367 368wxMetaFileDC::~wxMetaFileDC() 369{ 370} 371 372void wxMetaFileDC::DoGetSize(int *width, int *height) const 373{ 374 wxCHECK_RET( m_metaFile, wxT("GetSize() doesn't work without a metafile") ); 375 376 wxSize sz = m_metaFile->GetSize(); 377 if (width) 378 (*width) = sz.x; 379 if (height) 380 (*height) = sz.y; 381} 382 383wxMetaFile *wxMetaFileDC::Close() 384{ 385#if wxMAC_USE_CORE_GRAPHICS 386 delete m_graphicContext; 387 m_graphicContext = NULL; 388 m_ok = false; 389#endif 390 391 M_METAFILEREFDATA(*m_metaFile)->Close(); 392 393 return m_metaFile; 394} 395 396#if wxUSE_DATAOBJ 397size_t wxMetafileDataObject::GetDataSize() const 398{ 399#if wxMAC_USE_CORE_GRAPHICS 400 CFIndex length = 0; 401 wxMetafileRefData* refData = M_METAFILEREFDATA(m_metafile); 402 if ( refData ) 403 length = refData->GetData().GetLength(); 404 return length; 405#else 406 return GetHandleSize( (Handle) (*((wxMetafile*)&m_metafile)).GetHMETAFILE() ); 407#endif 408} 409 410bool wxMetafileDataObject::GetDataHere(void *buf) const 411{ 412 bool result = false; 413#if wxMAC_USE_CORE_GRAPHICS 414 wxMetafileRefData* refData = M_METAFILEREFDATA(m_metafile); 415 if ( refData ) 416 { 417 CFIndex length = refData->GetData().GetLength(); 418 if ( length > 0 ) 419 { 420 result = true ; 421 refData->GetData().GetBytes(CFRangeMake(0,length), (UInt8 *) buf); 422 } 423 } 424#else 425 Handle pictH = (Handle)(*((wxMetafile*)&m_metafile)).GetHMETAFILE(); 426 result = (pictH != NULL); 427 428 if (result) 429 memcpy( buf, *pictH, GetHandleSize( pictH ) ); 430 431#endif 432 return result; 433} 434 435bool wxMetafileDataObject::SetData(size_t len, const void *buf) 436{ 437#if wxMAC_USE_CORE_GRAPHICS 438 wxMetafileRefData* metafiledata = new wxMetafileRefData(wxCFRefFromGet(wxCFDataRef((UInt8*)buf, len).get())); 439 m_metafile.UnRef(); 440 m_metafile.SetRefData( metafiledata ); 441#else 442 Handle handle = NewHandle( len ); 443 SetHandleSize( handle, len ); 444 memcpy( *handle, buf, len ); 445 m_metafile.SetHMETAFILE( (WXHMETAFILE) handle ); 446#endif 447 return true; 448} 449#endif 450 451#endif 452