* When cloning the ref data, copy the NSBitmapImageRep instead of retaining it
[wxWidgets.git] / src / cocoa / bitmap.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/bitmap.cpp
3 // Purpose:     wxBitmap
4 // Author:      David Elliott
5 // Modified by:
6 // Created:     2003/07/19
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2003 David Elliott
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/setup.h"
13 #include "wx/utils.h"
14 #include "wx/palette.h"
15 #include "wx/bitmap.h"
16 #include "wx/icon.h"
17 #include "wx/log.h"
18 #include "wx/image.h"
19 #include "wx/xpmdecod.h"
20
21 #include "wx/cocoa/autorelease.h"
22 #include "wx/cocoa/string.h"
23
24 #import <AppKit/NSBitmapImageRep.h>
25 #import <AppKit/NSGraphics.h>
26
27 // ========================================================================
28 // wxBitmapRefData
29 // ========================================================================
30 class wxBitmapRefData: public wxGDIRefData
31 {
32     friend class wxBitmap;
33 public:
34     wxBitmapRefData();
35     wxBitmapRefData( const wxBitmapRefData& data );
36     virtual ~wxBitmapRefData();
37
38 protected:
39     int                 m_width;
40     int                 m_height;
41     int                 m_depth;
42     bool                m_ok;
43     int                 m_numColors;
44     wxPalette           m_bitmapPalette;
45     int                 m_quality;
46     WX_NSBitmapImageRep m_cocoaNSBitmapImageRep;
47     wxMask             *m_bitmapMask; // Optional mask
48 };
49
50 #define M_BITMAPDATA ((wxBitmapRefData *)m_refData)
51
52 wxBitmapRefData::wxBitmapRefData()
53 {
54     m_ok = FALSE;
55     m_width = 0;
56     m_height = 0;
57     m_depth = 0;
58     m_quality = 0;
59     m_numColors = 0;
60     m_cocoaNSBitmapImageRep = nil;
61     m_bitmapMask = NULL;
62 }
63
64 wxBitmapRefData::wxBitmapRefData( const wxBitmapRefData& data)
65 {
66     m_width = data.m_width;
67     m_height = data.m_height;
68     m_depth = data.m_depth;
69     m_ok = data.m_ok;
70     m_numColors = data.m_numColors;
71     m_bitmapPalette = data.m_bitmapPalette;
72     m_quality = data.m_quality;
73     m_cocoaNSBitmapImageRep = [data.m_cocoaNSBitmapImageRep copyWithZone:nil];
74     m_bitmapMask = data.m_bitmapMask?new wxMask(*data.m_bitmapMask):NULL;
75 }
76
77 wxBitmapRefData::~wxBitmapRefData()
78 {
79     [m_cocoaNSBitmapImageRep release];
80     m_cocoaNSBitmapImageRep = NULL;
81
82     delete m_bitmapMask;
83     m_bitmapMask = NULL;
84 }
85
86 // ========================================================================
87 // wxBitmap
88 // ========================================================================
89 IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
90
91 wxBitmap::wxBitmap()
92 {
93     m_refData = NULL;
94 }
95
96 wxBitmap::~wxBitmap()
97 {
98 }
99
100 wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits)
101 {
102     m_refData = new wxBitmapRefData;
103
104     M_BITMAPDATA->m_width = the_width ;
105     M_BITMAPDATA->m_height = the_height ;
106     M_BITMAPDATA->m_depth = no_bits ;
107     M_BITMAPDATA->m_numColors = 0;
108
109     /* TODO: create the bitmap from data */
110 }
111
112 wxBitmap::wxBitmap(int w, int h, int d)
113 {
114     (void)Create(w, h, d);
115 }
116
117 wxBitmap::wxBitmap(void *data, wxBitmapType type, int width, int height, int depth)
118 {
119     (void) Create(data, type, width, height, depth);
120 }
121
122 wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type)
123 {
124     LoadFile(filename, type);
125 }
126
127 wxObjectRefData *wxBitmap::CreateRefData() const
128 {
129     return new wxBitmapRefData;
130 }
131
132 wxObjectRefData *wxBitmap::CloneRefData(const wxObjectRefData *data) const
133 {
134     return new wxBitmapRefData(*(wxBitmapRefData*)data);
135 }
136
137 WX_NSBitmapImageRep wxBitmap::GetNSBitmapImageRep()
138 {
139     if(!M_BITMAPDATA)
140         return NULL;
141     return M_BITMAPDATA->m_cocoaNSBitmapImageRep;
142 }
143
144 void wxBitmap::SetNSBitmapImageRep(WX_NSBitmapImageRep bitmapImageRep)
145 {
146     if(!M_BITMAPDATA)
147         return;
148     // NOTE: No checking is done to make sure width/height agree
149     [bitmapImageRep retain];
150     [M_BITMAPDATA->m_cocoaNSBitmapImageRep release];
151     M_BITMAPDATA->m_cocoaNSBitmapImageRep = bitmapImageRep;
152 }
153
154 void wxBitmap::SetWidth(int w)
155 {
156     if (!M_BITMAPDATA)
157         m_refData = new wxBitmapRefData;
158
159     M_BITMAPDATA->m_width = w;
160 }
161
162 void wxBitmap::SetHeight(int h)
163 {
164     if (!M_BITMAPDATA)
165         m_refData = new wxBitmapRefData;
166
167     M_BITMAPDATA->m_height = h;
168 }
169
170 void wxBitmap::SetDepth(int d)
171 {
172     if (!M_BITMAPDATA)
173         m_refData = new wxBitmapRefData;
174
175     M_BITMAPDATA->m_depth = d;
176 }
177
178 void wxBitmap::SetQuality(int q)
179 {
180     if (!M_BITMAPDATA)
181         m_refData = new wxBitmapRefData;
182
183     M_BITMAPDATA->m_quality = q;
184 }
185
186 void wxBitmap::SetOk(bool isOk)
187 {
188     if (!M_BITMAPDATA)
189         m_refData = new wxBitmapRefData;
190
191     M_BITMAPDATA->m_ok = isOk;
192 }
193
194 void wxBitmap::SetPalette(const wxPalette& palette)
195 {
196     if (!M_BITMAPDATA)
197         m_refData = new wxBitmapRefData;
198
199     M_BITMAPDATA->m_bitmapPalette = palette ;
200 }
201
202 void wxBitmap::SetMask(wxMask *mask)
203 {
204     if (!M_BITMAPDATA)
205         m_refData = new wxBitmapRefData;
206
207     M_BITMAPDATA->m_bitmapMask = mask ;
208 }
209
210 bool wxBitmap::Ok() const
211 {
212     return m_refData && M_BITMAPDATA->m_ok;
213 }
214
215 wxPalette* wxBitmap::GetPalette() const
216 {
217     if(!m_refData)
218         return NULL;
219     return &M_BITMAPDATA->m_bitmapPalette;
220 }
221
222 wxMask* wxBitmap::GetMask() const
223 {
224     if(!m_refData)
225         return NULL;
226     return M_BITMAPDATA->m_bitmapMask;
227 }
228
229 int wxBitmap::GetDepth() const
230 {
231     if(!m_refData)
232         return 0;
233     return M_BITMAPDATA->m_depth;
234 }
235
236 int wxBitmap::GetWidth() const
237 {
238     if(!m_refData)
239         return 0;
240     return M_BITMAPDATA->m_width;
241 }
242
243 int wxBitmap::GetHeight() const
244 {
245     if(!m_refData)
246         return 0;
247     return M_BITMAPDATA->m_height;
248 }
249
250 bool wxBitmap::Create(int w, int h, int d)
251 {
252     UnRef();
253
254     m_refData = new wxBitmapRefData;
255
256     M_BITMAPDATA->m_width = w;
257     M_BITMAPDATA->m_height = h;
258     M_BITMAPDATA->m_depth = d;
259
260     /* TODO: create new bitmap */
261     M_BITMAPDATA->m_cocoaNSBitmapImageRep = [[NSBitmapImageRep alloc]
262             initWithBitmapDataPlanes: NULL
263             pixelsWide: w
264             pixelsHigh: h
265             bitsPerSample: 8
266             samplesPerPixel: 3
267             hasAlpha: NO
268             isPlanar: NO
269             colorSpaceName: NSCalibratedRGBColorSpace
270             bytesPerRow: 0
271             bitsPerPixel: 0];
272
273     wxLogDebug("M_BITMAPDATA=%p NSBitmapImageRep bitmapData=%p", M_BITMAPDATA, [M_BITMAPDATA->m_cocoaNSBitmapImageRep bitmapData]);
274     M_BITMAPDATA->m_ok = true;
275     M_BITMAPDATA->m_numColors = 0;
276     M_BITMAPDATA->m_quality = 0;
277     M_BITMAPDATA->m_bitmapMask = NULL;
278
279     return M_BITMAPDATA->m_ok;
280 }
281
282 bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type)
283 {
284     wxAutoNSAutoreleasePool pool;
285     UnRef();
286
287     m_refData = new wxBitmapRefData;
288
289     NSBitmapImageRep *imageRep = [NSBitmapImageRep
290         imageRepWithContentsOfFile:wxNSStringWithWxString(filename)];
291
292     if(imageRep)
293     {
294         M_BITMAPDATA->m_width = [imageRep pixelsWide];
295         M_BITMAPDATA->m_height = [imageRep pixelsHigh];
296         M_BITMAPDATA->m_depth = 24; // FIXME
297         M_BITMAPDATA->m_ok = true;
298         M_BITMAPDATA->m_numColors = 0;
299         M_BITMAPDATA->m_quality = 0;
300         M_BITMAPDATA->m_cocoaNSBitmapImageRep = [imageRep retain];
301         M_BITMAPDATA->m_bitmapMask = NULL;
302         return true;
303     }
304     wxImage image;
305     if(!image.LoadFile(filename,type))
306         return false;
307     if(!image.Ok())
308         return false;
309     *this = wxBitmap(image);
310     return true;
311 }
312
313 bool wxBitmap::Create(void *data, wxBitmapType type, int width, int height, int depth)
314 {
315     UnRef();
316
317     m_refData = new wxBitmapRefData;
318
319     return false;
320 }
321
322 bool wxBitmap::SaveFile(const wxString& filename, wxBitmapType type, const wxPalette *palette) const
323 {
324     return false;
325 }
326
327 bool wxBitmap::CopyFromIcon(const wxIcon& icno)
328 {
329     return false;
330 }
331
332 wxBitmap wxBitmap::GetSubBitmap(wxRect const&) const
333 {
334     return wxNullBitmap;
335 }
336
337 wxImage wxBitmap::ConvertToImage() const
338 {
339     if(!M_BITMAPDATA->m_ok)
340         return wxImage(5,5)/*wxNullImage*/;
341     return wxImage(M_BITMAPDATA->m_width,M_BITMAPDATA->m_height);
342 }
343
344 bool wxBitmap::CreateFromXpm(const char **xpm)
345 {
346 #if wxUSE_IMAGE && wxUSE_XPM
347     UnRef();
348
349     wxCHECK_MSG( xpm, false, wxT("invalid XPM data") )
350
351     wxXPMDecoder decoder;
352     wxImage img = decoder.ReadData(xpm);
353     wxCHECK_MSG( img.Ok(), false, wxT("invalid XPM data") )
354
355     *this = wxBitmap(img);
356     return true;
357 #else
358     return false;
359 #endif
360 }
361
362 bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
363 {
364     UnRef();
365
366     wxCHECK_MSG(image.Ok(), false, wxT("invalid image"));
367     wxCHECK_MSG(depth == -1 || depth == 1, false, wxT("invalid bitmap depth"));
368
369     m_refData = new wxBitmapRefData();
370
371     M_BITMAPDATA->m_width = image.GetWidth();
372     M_BITMAPDATA->m_height = image.GetHeight();
373     NSBitmapImageRep *bitmapImage = [[NSBitmapImageRep alloc]
374             initWithBitmapDataPlanes: NULL
375             pixelsWide: image.GetWidth()
376             pixelsHigh: image.GetHeight()
377             bitsPerSample: 8
378             samplesPerPixel: 3
379             hasAlpha: NO
380             isPlanar: NO
381             colorSpaceName: NSCalibratedRGBColorSpace
382             bytesPerRow: 0
383             bitsPerPixel: 0];
384
385     const int numBytes = image.GetWidth()*image.GetHeight()*3;
386     memcpy([bitmapImage bitmapData], image.GetData(), numBytes);
387     // TODO: Alpha and convert to desired depth
388     M_BITMAPDATA->m_depth = 24;
389     M_BITMAPDATA->m_ok = true;
390     M_BITMAPDATA->m_numColors = 0;
391     M_BITMAPDATA->m_quality = 0;
392     M_BITMAPDATA->m_cocoaNSBitmapImageRep = bitmapImage;
393     M_BITMAPDATA->m_bitmapMask = NULL;
394     return true;
395 }
396
397 // ========================================================================
398 // wxMask
399 // ========================================================================
400
401 IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
402
403 wxMask::wxMask()
404 {
405 /* TODO
406     m_maskBitmap = 0;
407 */
408 }
409
410 // Construct a mask from a bitmap and a colour indicating
411 // the transparent area
412 wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour)
413 {
414 /* TODO
415     m_maskBitmap = 0;
416 */
417     Create(bitmap, colour);
418 }
419
420 // Construct a mask from a bitmap and a palette index indicating
421 // the transparent area
422 wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex)
423 {
424 /* TODO
425     m_maskBitmap = 0;
426 */
427
428     Create(bitmap, paletteIndex);
429 }
430
431 // Construct a mask from a mono bitmap (copies the bitmap).
432 wxMask::wxMask(const wxBitmap& bitmap)
433 {
434 /* TODO
435     m_maskBitmap = 0;
436 */
437
438     Create(bitmap);
439 }
440
441 wxMask::~wxMask()
442 {
443 // TODO: delete mask bitmap
444 }
445
446 // Create a mask from a mono bitmap (copies the bitmap).
447 bool wxMask::Create(const wxBitmap& bitmap)
448 {
449 // TODO
450     return FALSE;
451 }
452
453 // Create a mask from a bitmap and a palette index indicating
454 // the transparent area
455 bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex)
456 {
457 // TODO
458     return FALSE;
459 }
460
461 // Create a mask from a bitmap and a colour indicating
462 // the transparent area
463 bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
464 {
465 // TODO
466     return FALSE;
467 }
468