1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/osx/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 // Copyright:   (c) Stefan Csomor
8 // Licence:       wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 //
11 // Currently, the only purpose for making a metafile
12 // is to put it on the clipboard.
13 
14 
15 #include "wx/wxprec.h"
16 
17 #if wxUSE_METAFILE
18 
19 #ifndef WX_PRECOMP
20     #include "wx/utils.h"
21     #include "wx/app.h"
22 #endif
23 
24 #include "wx/metafile.h"
25 #include "wx/clipbrd.h"
26 #include "wx/osx/private.h"
27 #include "wx/graphics.h"
28 #include "wx/osx/metafile.h"
29 
30 #include <stdio.h>
31 #include <string.h>
32 
33 IMPLEMENT_DYNAMIC_CLASS(wxMetafile, wxObject)
34 IMPLEMENT_ABSTRACT_CLASS(wxMetafileDC, wxDC)
35 IMPLEMENT_ABSTRACT_CLASS(wxMetafileDCImpl, wxGCDCImpl)
36 
37 #define M_METAFILEREFDATA( a ) ((wxMetafileRefData*)(a).GetRefData())
38 
39 class wxMetafileRefData : public wxGDIRefData
40 {
41 public:
42     // default ctor needed for CreateGDIRefData(), must be initialized later
wxMetafileRefData()43     wxMetafileRefData() { Init(); }
44 
45     // creates a metafile from memory, assumes ownership
46     wxMetafileRefData(CFDataRef data);
47 
48     // prepares a recording metafile
49     wxMetafileRefData( int width, int height);
50 
51     // prepares a metafile to be read from a file (if filename is not empty)
52     wxMetafileRefData( const wxString& filename);
53 
54     virtual ~wxMetafileRefData();
55 
IsOk() const56     virtual bool IsOk() const { return m_data != NULL; }
57 
58     void Init();
59 
GetWidth() const60     int GetWidth() const { return m_width; }
GetHeight() const61     int GetHeight() const { return m_height; }
62 
GetPDFDocument() const63     CGPDFDocumentRef GetPDFDocument() const { return m_pdfDoc; }
64     void UpdateDocumentFromData() ;
65 
GetData() const66     const wxCFDataRef& GetData() const { return m_data; }
GetContext() const67     CGContextRef GetContext() const { return m_context; }
68 
69     // ends the recording
70     void Close();
71 private:
72     wxCFDataRef m_data;
73     wxCFRef<CGPDFDocumentRef> m_pdfDoc;
74     CGContextRef m_context;
75 
76     int m_width ;
77     int m_height ;
78 
79 
80     // Our m_pdfDoc field can't be easily (deep) copied and so we don't define a
81     // copy ctor.
82     wxDECLARE_NO_COPY_CLASS(wxMetafileRefData);
83 };
84 
wxMetafileRefData(CFDataRef data)85 wxMetafileRefData::wxMetafileRefData(CFDataRef data) :
86     m_data(data)
87 {
88     Init();
89     UpdateDocumentFromData();
90 }
91 
wxMetafileRefData(const wxString & filename)92 wxMetafileRefData::wxMetafileRefData( const wxString& filename )
93 {
94     Init();
95 
96     if ( !filename.empty() )
97     {
98         wxCFRef<CFMutableStringRef> cfMutableString(CFStringCreateMutableCopy(NULL, 0, wxCFStringRef(filename)));
99         CFStringNormalize(cfMutableString,kCFStringNormalizationFormD);
100         wxCFRef<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfMutableString , kCFURLPOSIXPathStyle, false));
101         m_pdfDoc.reset(CGPDFDocumentCreateWithURL(url));
102     }
103 }
104 
105 
wxMetafileRefData(int width,int height)106 wxMetafileRefData::wxMetafileRefData( int width, int height)
107 {
108     Init();
109 
110     m_width = width;
111     m_height = height;
112 
113     CGRect r = CGRectMake( 0 , 0 , width  , height );
114 
115     CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
116     m_data.reset(data);
117     CGDataConsumerRef dataConsumer = wxMacCGDataConsumerCreateWithCFData(data);
118     m_context = CGPDFContextCreate( dataConsumer, (width != 0 && height != 0) ? &r : NULL , NULL );
119     CGDataConsumerRelease( dataConsumer );
120     if ( m_context )
121     {
122         CGPDFContextBeginPage(m_context, NULL);
123 
124         CGColorSpaceRef genericColorSpace  = wxMacGetGenericRGBColorSpace();
125 
126         CGContextSetFillColorSpace( m_context, genericColorSpace );
127         CGContextSetStrokeColorSpace( m_context, genericColorSpace );
128 
129         CGContextTranslateCTM( m_context , 0 ,  height ) ;
130         CGContextScaleCTM( m_context , 1 , -1 ) ;
131     }
132 }
133 
~wxMetafileRefData()134 wxMetafileRefData::~wxMetafileRefData()
135 {
136 }
137 
Init()138 void wxMetafileRefData::Init()
139 {
140     m_context = NULL;
141     m_width = -1;
142     m_height = -1;
143 }
144 
Close()145 void wxMetafileRefData::Close()
146 {
147     CGPDFContextEndPage(m_context);
148 
149     CGContextRelease(m_context);
150     m_context = NULL;
151 
152     UpdateDocumentFromData();
153 }
154 
UpdateDocumentFromData()155 void wxMetafileRefData::UpdateDocumentFromData()
156 {
157     wxCFRef<CGDataProviderRef> provider(wxMacCGDataProviderCreateWithCFData(m_data));
158     m_pdfDoc.reset(CGPDFDocumentCreateWithProvider(provider));
159     if ( m_pdfDoc != NULL )
160     {
161         CGPDFPageRef page = CGPDFDocumentGetPage( m_pdfDoc, 1 );
162         CGRect rect = CGPDFPageGetBoxRect ( page, kCGPDFMediaBox);
163         m_width = static_cast<int>(rect.size.width);
164         m_height = static_cast<int>(rect.size.height);
165     }
166 }
167 
wxMetaFile(const wxString & file)168 wxMetaFile::wxMetaFile(const wxString& file)
169 {
170     m_refData = new wxMetafileRefData(file);
171 }
172 
~wxMetaFile()173 wxMetaFile::~wxMetaFile()
174 {
175 }
176 
CreateGDIRefData() const177 wxGDIRefData *wxMetaFile::CreateGDIRefData() const
178 {
179     return new wxMetafileRefData;
180 }
181 
182 wxGDIRefData *
CloneGDIRefData(const wxGDIRefData * WXUNUSED (data)) const183 wxMetaFile::CloneGDIRefData(const wxGDIRefData * WXUNUSED(data)) const
184 {
185     wxFAIL_MSG( wxS("Cloning metafiles is not implemented in wxCarbon.") );
186 
187     return new wxMetafileRefData;
188 }
189 
GetHMETAFILE() const190 WXHMETAFILE wxMetaFile::GetHMETAFILE() const
191 {
192     return (WXHMETAFILE) (CFDataRef) M_METAFILEDATA->GetData();
193 }
194 
SetClipboard(int WXUNUSED (width),int WXUNUSED (height))195 bool wxMetaFile::SetClipboard(int WXUNUSED(width), int WXUNUSED(height))
196 {
197     bool success = true;
198 
199 #if wxUSE_DRAG_AND_DROP
200     if (m_refData == NULL)
201         return false;
202 
203     bool alreadyOpen = wxTheClipboard->IsOpened();
204     if (!alreadyOpen)
205     {
206         wxTheClipboard->Open();
207         wxTheClipboard->Clear();
208     }
209 
210     wxDataObject *data = new wxMetafileDataObject( *this );
211     success = wxTheClipboard->SetData( data );
212     if (!alreadyOpen)
213         wxTheClipboard->Close();
214 #endif
215 
216     return success;
217 }
218 
SetHMETAFILE(WXHMETAFILE mf)219 void wxMetafile::SetHMETAFILE(WXHMETAFILE mf)
220 {
221     UnRef();
222 
223     m_refData = new wxMetafileRefData((CFDataRef)mf);
224 }
225 
Play(wxDC * dc)226 bool wxMetaFile::Play(wxDC *dc)
227 {
228     if (!m_refData)
229         return false;
230 
231     if (!dc->IsOk())
232         return false;
233 
234     {
235         wxDCImpl *impl = dc->GetImpl();
236         wxGCDCImpl *gc_impl = wxDynamicCast(impl, wxGCDCImpl);
237         if (gc_impl)
238         {
239             CGContextRef cg = (CGContextRef) (gc_impl->GetGraphicsContext()->GetNativeContext());
240             CGPDFDocumentRef doc = M_METAFILEDATA->GetPDFDocument();
241             CGPDFPageRef page = CGPDFDocumentGetPage( doc, 1 );
242             wxMacCGContextStateSaver save(cg);
243             CGContextDrawPDFPage( cg, page );
244         }
245 //        CGContextTranslateCTM( cg, 0, bounds.size.width );
246 //        CGContextScaleCTM( cg, 1, -1 );
247     }
248 
249     return true;
250 }
251 
GetSize() const252 wxSize wxMetaFile::GetSize() const
253 {
254     wxSize dataSize = wxDefaultSize;
255 
256     if (IsOk())
257     {
258         dataSize.x = M_METAFILEDATA->GetWidth();
259         dataSize.y = M_METAFILEDATA->GetHeight();
260     }
261 
262     return dataSize;
263 }
264 
265 // Metafile device context
266 
267 // New constructor that takes origin and extent. If you use this, don't
268 // give origin/extent arguments to wxMakeMetaFilePlaceable.
269 
wxMetafileDCImpl(wxDC * owner,const wxString & filename,int width,int height,const wxString & WXUNUSED (description))270 wxMetafileDCImpl::wxMetafileDCImpl(
271     wxDC *owner,
272     const wxString& filename,
273     int width, int height,
274     const wxString& WXUNUSED(description) ) :
275     wxGCDCImpl( owner )
276 {
277     wxASSERT_MSG( width != 0 || height != 0, wxT("no arbitration of metafile size supported") );
278     wxASSERT_MSG( filename.empty(), wxT("no file based metafile support yet"));
279 
280     m_metaFile = new wxMetaFile( filename );
281     wxMetafileRefData* metafiledata = new wxMetafileRefData(width, height);
282     m_metaFile->UnRef();
283     m_metaFile->SetRefData( metafiledata );
284 
285     SetGraphicsContext( wxGraphicsContext::CreateFromNative(metafiledata->GetContext()));
286     m_ok = (m_graphicContext != NULL) ;
287 
288     SetMapMode( wxMM_TEXT );
289 }
290 
~wxMetafileDCImpl()291 wxMetafileDCImpl::~wxMetafileDCImpl()
292 {
293 }
294 
DoGetSize(int * width,int * height) const295 void wxMetafileDCImpl::DoGetSize(int *width, int *height) const
296 {
297     wxCHECK_RET( m_metaFile, wxT("GetSize() doesn't work without a metafile") );
298 
299     wxSize sz = m_metaFile->GetSize();
300     if (width)
301         (*width) = sz.x;
302     if (height)
303         (*height) = sz.y;
304 }
305 
Close()306 wxMetaFile *wxMetafileDCImpl::Close()
307 {
308     wxDELETE(m_graphicContext);
309     m_ok = false;
310 
311     M_METAFILEREFDATA(*m_metaFile)->Close();
312 
313     return m_metaFile;
314 }
315 
316 #if wxUSE_DATAOBJ
GetDataSize() const317 size_t wxMetafileDataObject::GetDataSize() const
318 {
319     CFIndex length = 0;
320     wxMetafileRefData* refData = M_METAFILEREFDATA(m_metafile);
321     if ( refData )
322         length = refData->GetData().GetLength();
323     return length;
324 }
325 
GetDataHere(void * buf) const326 bool wxMetafileDataObject::GetDataHere(void *buf) const
327 {
328     bool result = false;
329 
330     wxMetafileRefData* refData = M_METAFILEREFDATA(m_metafile);
331     if ( refData )
332     {
333         CFIndex length = refData->GetData().GetLength();
334         if ( length > 0 )
335         {
336             result = true ;
337             refData->GetData().GetBytes(CFRangeMake(0,length), (UInt8 *) buf);
338         }
339     }
340     return result;
341 }
342 
SetData(size_t len,const void * buf)343 bool wxMetafileDataObject::SetData(size_t len, const void *buf)
344 {
345     wxMetafileRefData* metafiledata = new wxMetafileRefData(wxCFRefFromGet(wxCFDataRef((UInt8*)buf, len).get()));
346     m_metafile.UnRef();
347     m_metafile.SetRefData( metafiledata );
348     return true;
349 }
350 #endif
351 
352 #endif
353