]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/metafile.cpp
Use fallback when passing -1 for point size (as allowed by other ports)
[wxWidgets.git] / src / mac / carbon / metafile.cpp
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$
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 #include "wx/mac/carbon/metafile.h"
30
31 #include <stdio.h>
32 #include <string.h>
33
34 IMPLEMENT_DYNAMIC_CLASS(wxMetafile, wxObject)
35 IMPLEMENT_ABSTRACT_CLASS(wxMetafileDC, wxDC)
36 IMPLEMENT_ABSTRACT_CLASS(wxMetafileDCImpl, wxGCDCImpl)
37
38 #define M_METAFILEREFDATA( a ) ((wxMetafileRefData*)(a).GetRefData())
39
40 class wxMetafileRefData : public wxGDIRefData
41 {
42 public:
43 // default ctor needed for CreateGDIRefData(), must be initialized later
44 wxMetafileRefData() { Init(); }
45
46 // creates a metafile from memory, assumes ownership
47 wxMetafileRefData(CFDataRef data);
48
49 // prepares a recording metafile
50 wxMetafileRefData( int width, int height);
51
52 // prepares a metafile to be read from a file (if filename is not empty)
53 wxMetafileRefData( const wxString& filename);
54
55 virtual ~wxMetafileRefData();
56
57 virtual bool IsOk() const { return m_data != NULL; }
58
59 void Init();
60
61 int GetWidth() const { return m_width; }
62 int GetHeight() const { return m_height; }
63
64 CGPDFDocumentRef GetPDFDocument() const { return m_pdfDoc; }
65 void UpdateDocumentFromData() ;
66
67 const wxCFDataRef& GetData() const { return m_data; }
68 CGContextRef GetContext() const { return m_context; }
69
70 // ends the recording
71 void Close();
72 private:
73 wxCFDataRef m_data;
74 wxCFRef<CGPDFDocumentRef> m_pdfDoc;
75 CGContextRef m_context;
76
77 int m_width ;
78 int m_height ;
79 };
80
81 wxMetafileRefData::wxMetafileRefData(CFDataRef data) :
82 m_data(data)
83 {
84 Init();
85 UpdateDocumentFromData();
86 }
87
88 wxMetafileRefData::wxMetafileRefData( const wxString& filename )
89 {
90 Init();
91
92 if ( !filename.empty() )
93 {
94 wxCFRef<CFMutableStringRef> cfMutableString(CFStringCreateMutableCopy(NULL, 0, wxCFStringRef(filename)));
95 CFStringNormalize(cfMutableString,kCFStringNormalizationFormD);
96 wxCFRef<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfMutableString , kCFURLPOSIXPathStyle, false));
97 m_pdfDoc.reset(CGPDFDocumentCreateWithURL(url));
98 }
99 }
100
101
102 wxMetafileRefData::wxMetafileRefData( int width, int height)
103 {
104 Init();
105
106 m_width = width;
107 m_height = height;
108
109 CGRect r = CGRectMake( 0 , 0 , width , height );
110
111 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
112 m_data.reset(data);
113 CGDataConsumerRef dataConsumer = wxMacCGDataConsumerCreateWithCFData(data);
114 m_context = CGPDFContextCreate( dataConsumer, (width != 0 && height != 0) ? &r : NULL , NULL );
115 CGDataConsumerRelease( dataConsumer );
116 if ( m_context )
117 {
118 CGPDFContextBeginPage(m_context, NULL);
119
120 CGColorSpaceRef genericColorSpace = wxMacGetGenericRGBColorSpace();
121
122 CGContextSetFillColorSpace( m_context, genericColorSpace );
123 CGContextSetStrokeColorSpace( m_context, genericColorSpace );
124
125 CGContextTranslateCTM( m_context , 0 , height ) ;
126 CGContextScaleCTM( m_context , 1 , -1 ) ;
127 }
128 }
129
130 wxMetafileRefData::~wxMetafileRefData()
131 {
132 }
133
134 void wxMetafileRefData::Init()
135 {
136 m_context = NULL;
137 m_width = -1;
138 m_height = -1;
139 }
140
141 void wxMetafileRefData::Close()
142 {
143 CGPDFContextEndPage(m_context);
144
145 CGContextRelease(m_context);
146 m_context = NULL;
147
148 UpdateDocumentFromData();
149 }
150
151 void wxMetafileRefData::UpdateDocumentFromData()
152 {
153 wxCFRef<CGDataProviderRef> provider(wxMacCGDataProviderCreateWithCFData(m_data));
154 m_pdfDoc.reset(CGPDFDocumentCreateWithProvider(provider));
155 if ( m_pdfDoc != NULL )
156 {
157 CGPDFPageRef page = CGPDFDocumentGetPage( m_pdfDoc, 1 );
158 CGRect rect = CGPDFPageGetBoxRect ( page, kCGPDFMediaBox);
159 m_width = wx_static_cast(int, rect.size.width);
160 m_height = wx_static_cast(int, rect.size.height);
161 }
162 }
163
164 wxMetaFile::wxMetaFile(const wxString& file)
165 {
166 m_refData = new wxMetafileRefData(file);
167 }
168
169 wxMetaFile::~wxMetaFile()
170 {
171 }
172
173 wxGDIRefData *wxMetaFile::CreateGDIRefData() const
174 {
175 return new wxMetafileRefData;
176 }
177
178 wxGDIRefData *wxMetaFile::CloneGDIRefData(const wxGDIRefData *data) const
179 {
180 return new wxMetafileRefData(*wx_static_cast(const wxMetafileRefData *, data));
181 }
182
183 WXHMETAFILE wxMetaFile::GetHMETAFILE() const
184 {
185 return (WXHMETAFILE) (CFDataRef) M_METAFILEDATA->GetData();
186 }
187
188 bool wxMetaFile::SetClipboard(int WXUNUSED(width), int WXUNUSED(height))
189 {
190 bool success = true;
191
192 #if wxUSE_DRAG_AND_DROP
193 if (m_refData == NULL)
194 return false;
195
196 bool alreadyOpen = wxTheClipboard->IsOpened();
197 if (!alreadyOpen)
198 {
199 wxTheClipboard->Open();
200 wxTheClipboard->Clear();
201 }
202
203 wxDataObject *data = new wxMetafileDataObject( *this );
204 success = wxTheClipboard->SetData( data );
205 if (!alreadyOpen)
206 wxTheClipboard->Close();
207 #endif
208
209 return success;
210 }
211
212 void wxMetafile::SetHMETAFILE(WXHMETAFILE mf)
213 {
214 UnRef();
215
216 m_refData = new wxMetafileRefData((CFDataRef)mf);
217 }
218
219 #ifndef __LP64__
220 void wxMetafile::SetPICT(void* pictHandle)
221 {
222 UnRef();
223
224 Handle picHandle = (Handle) pictHandle;
225 HLock(picHandle);
226 CFDataRef data = CFDataCreateWithBytesNoCopy( kCFAllocatorDefault, (const UInt8*) *picHandle, GetHandleSize(picHandle), kCFAllocatorNull);
227 wxCFRef<CGDataProviderRef> provider(wxMacCGDataProviderCreateWithCFData(data));
228 QDPictRef pictRef = QDPictCreateWithProvider(provider);
229 CGRect rect = QDPictGetBounds(pictRef);
230 m_refData = new wxMetafileRefData(wx_static_cast(int, rect.size.width),
231 wx_static_cast(int, rect.size.height));
232 QDPictDrawToCGContext( ((wxMetafileRefData*) m_refData)->GetContext(), rect, pictRef );
233 CFRelease( data );
234 QDPictRelease( pictRef );
235 ((wxMetafileRefData*) m_refData)->Close();
236 }
237 #endif
238
239 bool wxMetaFile::Play(wxDC *dc)
240 {
241 if (!m_refData)
242 return false;
243
244 if (!dc->IsOk())
245 return false;
246
247 {
248 wxDCImpl *impl = dc->GetImpl();
249 wxGCDCImpl *gc_impl = wxDynamicCast(impl, wxGCDCImpl);
250 if (gc_impl)
251 {
252 CGContextRef cg = (CGContextRef) (gc_impl->GetGraphicsContext()->GetNativeContext());
253 CGPDFDocumentRef doc = M_METAFILEDATA->GetPDFDocument();
254 CGPDFPageRef page = CGPDFDocumentGetPage( doc, 1 );
255 wxMacCGContextStateSaver save(cg);
256 CGContextDrawPDFPage( cg, page );
257 }
258 // CGContextTranslateCTM( cg, 0, bounds.size.width );
259 // CGContextScaleCTM( cg, 1, -1 );
260 }
261
262 return true;
263 }
264
265 wxSize wxMetaFile::GetSize() const
266 {
267 wxSize dataSize = wxDefaultSize;
268
269 if (Ok())
270 {
271 dataSize.x = M_METAFILEDATA->GetWidth();
272 dataSize.y = M_METAFILEDATA->GetHeight();
273 }
274
275 return dataSize;
276 }
277
278 // Metafile device context
279
280 // New constructor that takes origin and extent. If you use this, don't
281 // give origin/extent arguments to wxMakeMetaFilePlaceable.
282
283 wxMetafileDCImpl::wxMetafileDCImpl(
284 wxDC *owner,
285 const wxString& filename,
286 int width, int height,
287 const wxString& WXUNUSED(description) ) :
288 wxGCDCImpl( owner )
289 {
290 wxASSERT_MSG( width != 0 || height != 0, wxT("no arbitration of metafile size supported") );
291 wxASSERT_MSG( filename.empty(), wxT("no file based metafile support yet"));
292
293 m_metaFile = new wxMetaFile( filename );
294 wxMetafileRefData* metafiledata = new wxMetafileRefData(width, height);
295 m_metaFile->UnRef();
296 m_metaFile->SetRefData( metafiledata );
297
298 SetGraphicsContext( wxGraphicsContext::CreateFromNative(metafiledata->GetContext()));
299 m_ok = (m_graphicContext != NULL) ;
300
301 SetMapMode( wxMM_TEXT );
302 }
303
304 wxMetafileDCImpl::~wxMetafileDCImpl()
305 {
306 }
307
308 void wxMetafileDCImpl::DoGetSize(int *width, int *height) const
309 {
310 wxCHECK_RET( m_metaFile, wxT("GetSize() doesn't work without a metafile") );
311
312 wxSize sz = m_metaFile->GetSize();
313 if (width)
314 (*width) = sz.x;
315 if (height)
316 (*height) = sz.y;
317 }
318
319 wxMetaFile *wxMetafileDCImpl::Close()
320 {
321 delete m_graphicContext;
322 m_graphicContext = NULL;
323 m_ok = false;
324
325 M_METAFILEREFDATA(*m_metaFile)->Close();
326
327 return m_metaFile;
328 }
329
330 #if wxUSE_DATAOBJ
331 size_t wxMetafileDataObject::GetDataSize() const
332 {
333 CFIndex length = 0;
334 wxMetafileRefData* refData = M_METAFILEREFDATA(m_metafile);
335 if ( refData )
336 length = refData->GetData().GetLength();
337 return length;
338 }
339
340 bool wxMetafileDataObject::GetDataHere(void *buf) const
341 {
342 bool result = false;
343
344 wxMetafileRefData* refData = M_METAFILEREFDATA(m_metafile);
345 if ( refData )
346 {
347 CFIndex length = refData->GetData().GetLength();
348 if ( length > 0 )
349 {
350 result = true ;
351 refData->GetData().GetBytes(CFRangeMake(0,length), (UInt8 *) buf);
352 }
353 }
354 return result;
355 }
356
357 bool wxMetafileDataObject::SetData(size_t len, const void *buf)
358 {
359 wxMetafileRefData* metafiledata = new wxMetafileRefData(wxCFRefFromGet(wxCFDataRef((UInt8*)buf, len).get()));
360 m_metafile.UnRef();
361 m_metafile.SetRefData( metafiledata );
362 return true;
363 }
364 #endif
365
366 #endif