]> git.saurik.com Git - wxWidgets.git/blame - src/osx/core/bitmap.cpp
Use [DOMRange markupString] to get selection source.
[wxWidgets.git] / src / osx / core / bitmap.cpp
CommitLineData
489468fe 1/////////////////////////////////////////////////////////////////////////////
96dabe43 2// Name: src/osx/core/bitmap.cpp
489468fe
SC
3// Purpose: wxBitmap
4// Author: Stefan Csomor
5// Modified by:
6// Created: 1998-01-01
7// RCS-ID: $Id$
8// Copyright: (c) Stefan Csomor
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
14#include "wx/bitmap.h"
15
16#ifndef WX_PRECOMP
17 #include "wx/log.h"
18 #include "wx/dcmemory.h"
19 #include "wx/icon.h"
20 #include "wx/image.h"
21#endif
22
23#include "wx/metafile.h"
acc255e9
PC
24#include "wx/xpmdecod.h"
25
489468fe
SC
26#include "wx/rawbmp.h"
27
44c8e75b
SC
28#include "wx/filename.h"
29
489468fe
SC
30IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
31IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
32
b2680ced 33#if wxOSX_USE_CARBON
b96ad102 34#include "wx/osx/uma.h"
b2680ced
SC
35#else
36#include "wx/osx/private.h"
37#endif
38
489468fe
SC
39#ifndef __WXOSX_IPHONE__
40#include <QuickTime/QuickTime.h>
41#endif
42
43CGColorSpaceRef wxMacGetGenericRGBColorSpace();
44CGDataProviderRef wxMacCGDataProviderCreateWithMemoryBuffer( const wxMemoryBuffer& buf );
45
46// Implementation Notes
47// --------------------
48//
49// we are always working with a 32 bit deep pixel buffer
50// under QuickDraw its alpha parts are going to be ignored in the GWorld,
51// therefore we have a separate GWorld there for blitting the mask in
52
53// under Quartz then content is transformed into a CGImageRef representing the same data
54// which can be transferred to the GPU by the OS for fast rendering
55
56class WXDLLEXPORT wxBitmapRefData: public wxGDIRefData
57{
58 friend class WXDLLIMPEXP_FWD_CORE wxIcon;
59 friend class WXDLLIMPEXP_FWD_CORE wxCursor;
60public:
f8bfebfc 61 wxBitmapRefData(int width , int height , int depth, double logicalscale);
489468fe 62 wxBitmapRefData(int width , int height , int depth);
c944835a
SC
63 wxBitmapRefData(CGContextRef context);
64 wxBitmapRefData(CGImageRef image, double scale);
489468fe
SC
65 wxBitmapRefData();
66 wxBitmapRefData(const wxBitmapRefData &tocopy);
67
68 virtual ~wxBitmapRefData();
69
70 virtual bool IsOk() const { return m_ok; }
71
72 void Free();
73 void SetOk( bool isOk) { m_ok = isOk; }
74
75 void SetWidth( int width ) { m_width = width; }
76 void SetHeight( int height ) { m_height = height; }
77 void SetDepth( int depth ) { m_depth = depth; }
78
79 int GetWidth() const { return m_width; }
80 int GetHeight() const { return m_height; }
81 int GetDepth() const { return m_depth; }
f8bfebfc 82 double GetScaleFactor() const { return m_scaleFactor; }
489468fe
SC
83 void *GetRawAccess() const;
84 void *BeginRawAccess();
85 void EndRawAccess();
86
87 bool HasAlpha() const { return m_hasAlpha; }
88 void UseAlpha( bool useAlpha );
89
90public:
91#if wxUSE_PALETTE
92 wxPalette m_bitmapPalette;
93#endif // wxUSE_PALETTE
94
95 wxMask * m_bitmapMask; // Optional mask
96 CGImageRef CreateCGImage() const;
97
98 // returns true if the bitmap has a size that
99 // can be natively transferred into a true icon
100 // if no is returned GetIconRef will still produce
101 // an icon but it will be generated via a PICT and
102 // rescaled to 16 x 16
103 bool HasNativeSize();
104
0224c1f6 105#ifndef __WXOSX_IPHONE__
489468fe
SC
106 // caller should increase ref count if needed longer
107 // than the bitmap exists
108 IconRef GetIconRef();
489468fe
SC
109#endif
110
111 CGContextRef GetBitmapContext() const;
112
113 int GetBytesPerRow() const { return m_bytesPerRow; }
acc255e9 114 private :
489468fe 115 bool Create(int width , int height , int depth);
f8bfebfc 116 bool Create(int width , int height , int depth, double logicalScale);
c944835a
SC
117 bool Create( CGImageRef image, double scale );
118 bool Create( CGContextRef bitmapcontext);
489468fe
SC
119 void Init();
120
121 int m_width;
122 int m_height;
123 int m_bytesPerRow;
124 int m_depth;
125 bool m_hasAlpha;
126 wxMemoryBuffer m_memBuf;
127 int m_rawAccessCount;
128 bool m_ok;
129 mutable CGImageRef m_cgImageRef;
130
489468fe 131#ifndef __WXOSX_IPHONE__
0224c1f6 132 IconRef m_iconRef;
489468fe 133#endif
0224c1f6 134
489468fe 135 CGContextRef m_hBitmap;
f8bfebfc 136 double m_scaleFactor;
489468fe
SC
137};
138
139
292e5e1f 140#define wxOSX_USE_PREMULTIPLIED_ALPHA 1
489468fe
SC
141static const int kBestByteAlignement = 16;
142static const int kMaskBytesPerPixel = 1;
143
144static int GetBestBytesPerRow( int rawBytes )
145{
146 return (((rawBytes)+kBestByteAlignement-1) & ~(kBestByteAlignement-1) );
147}
148
149#if wxUSE_GUI && !defined(__WXOSX_IPHONE__)
150
151// this is used for more controls than just the wxBitmap button, also for notebooks etc
152
153void wxMacCreateBitmapButton( ControlButtonContentInfo*info , const wxBitmap& bitmap , int forceType )
154{
155 memset( info , 0 , sizeof(ControlButtonContentInfo) ) ;
a1b806b9 156 if ( bitmap.IsOk() )
489468fe
SC
157 {
158 wxBitmapRefData * bmap = bitmap.GetBitmapData() ;
159 if ( bmap == NULL )
160 return ;
161
162 if ( forceType == 0 )
163 {
164 forceType = kControlContentCGImageRef;
165 }
166
167 if ( forceType == kControlContentIconRef )
168 {
169 wxBitmap scaleBmp ;
170 wxBitmapRefData* bmp = bmap ;
171
172 if ( !bmap->HasNativeSize() )
173 {
174 // as PICT conversion will only result in a 16x16 icon, let's attempt
175 // a few scales for better results
176
177 int w = bitmap.GetWidth() ;
178 int h = bitmap.GetHeight() ;
179 int sz = wxMax( w , h ) ;
180 if ( sz == 24 || sz == 64 )
181 {
182 scaleBmp = wxBitmap( bitmap.ConvertToImage().Scale( w * 2 , h * 2 ) ) ;
183 bmp = scaleBmp.GetBitmapData() ;
184 }
185 }
186
187 info->contentType = kControlContentIconRef ;
188 info->u.iconRef = bmp->GetIconRef() ;
189 AcquireIconRef( info->u.iconRef ) ;
190 }
191 else if ( forceType == kControlContentCGImageRef )
192 {
193 info->contentType = kControlContentCGImageRef ;
194 info->u.imageRef = (CGImageRef) bmap->CreateCGImage() ;
195 }
489468fe
SC
196 }
197}
198
199CGImageRef wxMacCreateCGImageFromBitmap( const wxBitmap& bitmap )
200{
201 wxBitmapRefData * bmap = bitmap.GetBitmapData() ;
202 if ( bmap == NULL )
203 return NULL ;
204 return (CGImageRef) bmap->CreateCGImage();
205}
206
207void wxMacReleaseBitmapButton( ControlButtonContentInfo*info )
208{
209 if ( info->contentType == kControlContentIconRef )
210 {
211 ReleaseIconRef( info->u.iconRef ) ;
212 }
213 else if ( info->contentType == kControlNoContent )
214 {
215 // there's no bitmap at all, fall through silently
216 }
217 else if ( info->contentType == kControlContentPictHandle )
218 {
219 // owned by the bitmap, no release here
220 }
221 else if ( info->contentType == kControlContentCGImageRef )
222 {
223 CGImageRelease( info->u.imageRef ) ;
224 }
225 else
226 {
227 wxFAIL_MSG(wxT("Unexpected bitmap type") ) ;
228 }
229}
230
231#endif //wxUSE_BMPBUTTON
232
233#define M_BITMAPDATA ((wxBitmapRefData *)m_refData)
234
235void wxBitmapRefData::Init()
236{
237 m_width = 0 ;
238 m_height = 0 ;
239 m_depth = 0 ;
240 m_bytesPerRow = 0;
241 m_ok = false ;
242 m_bitmapMask = NULL ;
243 m_cgImageRef = NULL ;
244
245#ifndef __WXOSX_IPHONE__
246 m_iconRef = NULL ;
489468fe
SC
247#endif
248 m_hBitmap = NULL ;
249
250 m_rawAccessCount = 0 ;
251 m_hasAlpha = false;
f8bfebfc 252 m_scaleFactor = 1.0;
489468fe
SC
253}
254
ea2807a4 255wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData &tocopy) : wxGDIRefData()
489468fe
SC
256{
257 Init();
f8bfebfc 258 Create(tocopy.m_width, tocopy.m_height, tocopy.m_depth, tocopy.m_scaleFactor);
489468fe
SC
259
260 if (tocopy.m_bitmapMask)
261 m_bitmapMask = new wxMask(*tocopy.m_bitmapMask);
262 else if (tocopy.m_hasAlpha)
263 UseAlpha(true);
264
265 unsigned char* dest = (unsigned char*)GetRawAccess();
266 unsigned char* source = (unsigned char*)tocopy.GetRawAccess();
267 size_t numbytes = m_bytesPerRow * m_height;
268 memcpy( dest, source, numbytes );
269}
270
271wxBitmapRefData::wxBitmapRefData()
272{
273 Init() ;
274}
275
276wxBitmapRefData::wxBitmapRefData( int w , int h , int d )
277{
278 Init() ;
279 Create( w , h , d ) ;
280}
281
f8bfebfc
SC
282wxBitmapRefData::wxBitmapRefData(int w , int h , int d, double logicalscale)
283{
284 Init() ;
285 Create( w , h , d, logicalscale ) ;
286}
287
c944835a 288wxBitmapRefData::wxBitmapRefData(CGContextRef context)
aaa7d63c
SC
289{
290 Init();
c944835a
SC
291 Create( context );
292}
293
294wxBitmapRefData::wxBitmapRefData(CGImageRef image, double scale)
295{
296 Init();
297 Create( image, scale );
aaa7d63c
SC
298}
299// code from Technical Q&A QA1509
300
c944835a 301bool wxBitmapRefData::Create(CGImageRef image, double scale)
aaa7d63c 302{
554b2800 303 if ( image != NULL )
aaa7d63c 304 {
554b2800
SC
305 m_width = CGImageGetWidth(image);
306 m_height = CGImageGetHeight(image);
307 m_depth = 32;
308 m_hBitmap = NULL;
c944835a 309 m_scaleFactor = scale;
aaa7d63c 310
554b2800
SC
311 m_bytesPerRow = GetBestBytesPerRow( m_width * 4 ) ;
312 size_t size = m_bytesPerRow * m_height ;
313 void* data = m_memBuf.GetWriteBuf( size ) ;
314 if ( data != NULL )
315 {
316 memset( data , 0 , size ) ;
317 m_memBuf.UngetWriteBuf( size ) ;
318 CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image);
4fbb421b 319 if ( alpha == kCGImageAlphaNone || alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast )
554b2800
SC
320 {
321 m_hBitmap = CGBitmapContextCreate((char*) data, m_width, m_height, 8, m_bytesPerRow, wxMacGetGenericRGBColorSpace(), kCGImageAlphaNoneSkipFirst );
322 }
323 else
324 {
325 m_hasAlpha = true;
326 m_hBitmap = CGBitmapContextCreate((char*) data, m_width, m_height, 8, m_bytesPerRow, wxMacGetGenericRGBColorSpace(), kCGImageAlphaPremultipliedFirst );
327 }
5f35207b 328 CGRect rect = CGRectMake(0,0,m_width,m_height);
554b2800
SC
329 CGContextDrawImage(m_hBitmap, rect, image);
330
331 wxASSERT_MSG( m_hBitmap , wxT("Unable to create CGBitmapContext context") ) ;
332 CGContextTranslateCTM( m_hBitmap, 0, m_height );
c944835a 333 CGContextScaleCTM( m_hBitmap, 1*m_scaleFactor, -1*m_scaleFactor );
554b2800
SC
334 } /* data != NULL */
335 }
aaa7d63c
SC
336 m_ok = ( m_hBitmap != NULL ) ;
337
338 return m_ok ;
339
340}
341
c944835a
SC
342bool wxBitmapRefData::Create(CGContextRef context)
343{
344 if ( context != NULL && CGBitmapContextGetData(context) )
345 {
346 m_hBitmap = context;
347 m_bytesPerRow = CGBitmapContextGetBytesPerRow(context);
348 m_width = CGBitmapContextGetWidth(context);
349 m_height = CGBitmapContextGetHeight(context);
350 m_depth = CGBitmapContextGetBitsPerPixel(context) ;
351
352 // our own contexts conform to this, always.
353 wxASSERT( m_depth == 32 );
354
355 // determine content scale
356 CGRect userrect = CGRectMake(0, 0, 10, 10);
357 CGRect devicerect;
358 devicerect = CGContextConvertRectToDeviceSpace(context, userrect);
359 m_scaleFactor = devicerect.size.height / userrect.size.height;
360
361 CGImageAlphaInfo alpha = CGBitmapContextGetAlphaInfo(context);
362
363 if ( alpha == kCGImageAlphaNone || alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast )
364 {
365 // no alpha
366 }
367 else
368 {
369 m_hasAlpha = true;
370 }
371 }
372 m_ok = ( m_hBitmap != NULL ) ;
373
374 return m_ok ;
375}
376
489468fe
SC
377bool wxBitmapRefData::Create( int w , int h , int d )
378{
379 m_width = wxMax(1, w);
380 m_height = wxMax(1, h);
381 m_depth = d ;
382 m_hBitmap = NULL ;
383
795160b7
SC
384 m_bytesPerRow = GetBestBytesPerRow( m_width * 4 ) ;
385 size_t size = m_bytesPerRow * m_height ;
489468fe
SC
386 void* data = m_memBuf.GetWriteBuf( size ) ;
387 if ( data != NULL )
388 {
389 memset( data , 0 , size ) ;
390 m_memBuf.UngetWriteBuf( size ) ;
391
392 m_hBitmap = CGBitmapContextCreate((char*) data, m_width, m_height, 8, m_bytesPerRow, wxMacGetGenericRGBColorSpace(), kCGImageAlphaNoneSkipFirst );
393 wxASSERT_MSG( m_hBitmap , wxT("Unable to create CGBitmapContext context") ) ;
394 CGContextTranslateCTM( m_hBitmap, 0, m_height );
f8bfebfc 395 CGContextScaleCTM( m_hBitmap, 1*m_scaleFactor, -1*m_scaleFactor );
489468fe
SC
396 } /* data != NULL */
397 m_ok = ( m_hBitmap != NULL ) ;
398
399 return m_ok ;
400}
401
f8bfebfc
SC
402bool wxBitmapRefData::Create( int w , int h , int d, double logicalScale )
403{
404 m_scaleFactor = logicalScale;
405 return Create(w*logicalScale,h*logicalScale,d);
406}
407
489468fe
SC
408void wxBitmapRefData::UseAlpha( bool use )
409{
410 if ( m_hasAlpha == use )
411 return ;
412
413 m_hasAlpha = use ;
414
415 CGContextRelease( m_hBitmap );
416 m_hBitmap = CGBitmapContextCreate((char*) m_memBuf.GetData(), m_width, m_height, 8, m_bytesPerRow, wxMacGetGenericRGBColorSpace(), m_hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst );
417 wxASSERT_MSG( m_hBitmap , wxT("Unable to create CGBitmapContext context") ) ;
418 CGContextTranslateCTM( m_hBitmap, 0, m_height );
f8bfebfc 419 CGContextScaleCTM( m_hBitmap, 1*m_scaleFactor, -1*m_scaleFactor );
489468fe
SC
420}
421
422void *wxBitmapRefData::GetRawAccess() const
423{
424 wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ;
425 return m_memBuf.GetData() ;
426}
427
428void *wxBitmapRefData::BeginRawAccess()
429{
430 wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") ) ;
431 wxASSERT( m_rawAccessCount == 0 ) ;
432#ifndef __WXOSX_IPHONE__
359e69fe
SC
433 wxASSERT_MSG( m_iconRef == NULL ,
434 wxT("Currently, modifing bitmaps that are used in controls already is not supported") ) ;
489468fe
SC
435#endif
436 ++m_rawAccessCount ;
437
438 // we must destroy an existing cached image, as
439 // the bitmap data may change now
440 if ( m_cgImageRef )
441 {
442 CGImageRelease( m_cgImageRef ) ;
443 m_cgImageRef = NULL ;
444 }
445
446 return m_memBuf.GetData() ;
447}
448
449void wxBitmapRefData::EndRawAccess()
450{
451 wxCHECK_RET( IsOk() , wxT("invalid bitmap") ) ;
452 wxASSERT( m_rawAccessCount == 1 ) ;
453
454 --m_rawAccessCount ;
455}
456
457bool wxBitmapRefData::HasNativeSize()
458{
459 int w = GetWidth() ;
460 int h = GetHeight() ;
461 int sz = wxMax( w , h ) ;
462
463 return ( sz == 128 || sz == 48 || sz == 32 || sz == 16 );
464}
465
466#ifndef __WXOSX_IPHONE__
467IconRef wxBitmapRefData::GetIconRef()
468{
469 if ( m_iconRef == NULL )
470 {
471 // Create Icon Family Handle
472
473 IconFamilyHandle iconFamily = (IconFamilyHandle) NewHandle( 0 );
474
475 int w = GetWidth() ;
476 int h = GetHeight() ;
477 int sz = wxMax( w , h ) ;
478
479 OSType dataType = 0 ;
480 OSType maskType = 0 ;
481
0224c1f6 482 // since we don't have PICT conversion available, use
359e69fe
SC
483 // the next larger standard icon size
484 // TODO: Use NSImage
485 if (sz <= 16)
486 sz = 16;
487 else if ( sz <= 32)
488 sz = 32;
489 else if ( sz <= 48)
490 sz = 48;
491 else if ( sz <= 128)
492 sz = 128;
493 else if ( sz <= 256)
494 sz = 256;
495 else if ( sz <= 512)
496 sz = 512;
497 else if ( sz <= 1024)
498 sz = 1024;
359e69fe 499
489468fe
SC
500 switch (sz)
501 {
37d8aa5b 502#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
359e69fe
SC
503 case 1024:
504 dataType = kIconServices1024PixelDataARGB;
505 break;
37d8aa5b 506#endif
359e69fe
SC
507 case 512:
508 dataType = kIconServices512PixelDataARGB;
509 break;
510
511 case 256:
512 dataType = kIconServices256PixelDataARGB;
513 break;
514
489468fe 515 case 128:
29c829ba 516 dataType = kIconServices128PixelDataARGB ;
489468fe
SC
517 break;
518
519 case 48:
29c829ba 520 dataType = kIconServices48PixelDataARGB ;
489468fe
SC
521 break;
522
523 case 32:
29c829ba 524 dataType = kIconServices32PixelDataARGB ;
489468fe
SC
525 break;
526
527 case 16:
29c829ba 528 dataType = kIconServices16PixelDataARGB ;
489468fe
SC
529 break;
530
531 default:
532 break;
533 }
534
535 if ( dataType != 0 )
536 {
29c829ba 537 if ( maskType == 0 )
489468fe
SC
538 {
539 size_t datasize = sz * sz * 4 ;
540 Handle data = NewHandle( datasize ) ;
541 HLock( data ) ;
542 unsigned char* ptr = (unsigned char*) *data ;
543 memset( ptr, 0, datasize );
544 bool hasAlpha = HasAlpha() ;
545 wxMask *mask = m_bitmapMask ;
546 unsigned char * sourcePtr = (unsigned char*) GetRawAccess() ;
547 unsigned char * masksourcePtr = mask ? (unsigned char*) mask->GetRawAccess() : NULL ;
548
549 for ( int y = 0 ; y < h ; ++y, sourcePtr += m_bytesPerRow , masksourcePtr += mask ? mask->GetBytesPerRow() : 0 )
550 {
551 unsigned char * source = sourcePtr;
552 unsigned char * masksource = masksourcePtr;
553 unsigned char * dest = ptr + y * sz * 4 ;
554 unsigned char a, r, g, b;
555
556 for ( int x = 0 ; x < w ; ++x )
557 {
558 a = *source ++ ;
559 r = *source ++ ;
560 g = *source ++ ;
561 b = *source ++ ;
562
563 if ( mask )
564 {
565 a = 0xFF - *masksource++ ;
566 }
567 else if ( !hasAlpha )
568 a = 0xFF ;
569 else
570 {
292e5e1f 571#if wxOSX_USE_PREMULTIPLIED_ALPHA
489468fe
SC
572 // this must be non-premultiplied data
573 if ( a != 0xFF && a!= 0 )
574 {
575 r = r * 255 / a;
576 g = g * 255 / a;
577 b = b * 255 / a;
578 }
579#endif
580 }
581 *dest++ = a ;
582 *dest++ = r ;
583 *dest++ = g ;
584 *dest++ = b ;
585
586 }
587 }
588 HUnlock( data );
83c23edb 589
489468fe 590 OSStatus err = SetIconFamilyData( iconFamily, dataType , data );
83c23edb
VZ
591 if ( err != noErr )
592 {
593 wxFAIL_MSG("Error when adding bitmap");
594 }
595
489468fe
SC
596 DisposeHandle( data );
597 }
598 else
489468fe
SC
599 {
600 // setup the header properly
601
acc255e9
PC
602 Handle data = NULL ;
603 Handle maskdata = NULL ;
604 unsigned char * maskptr = NULL ;
605 unsigned char * ptr = NULL ;
489468fe
SC
606 size_t datasize, masksize ;
607
608 datasize = sz * sz * 4 ;
609 data = NewHandle( datasize ) ;
610 HLock( data ) ;
611 ptr = (unsigned char*) *data ;
612 memset( ptr , 0, datasize ) ;
613
614 masksize = sz * sz ;
615 maskdata = NewHandle( masksize ) ;
616 HLock( maskdata ) ;
617 maskptr = (unsigned char*) *maskdata ;
618 memset( maskptr , 0 , masksize ) ;
619
620 bool hasAlpha = HasAlpha() ;
621 wxMask *mask = m_bitmapMask ;
622 unsigned char * sourcePtr = (unsigned char*) GetRawAccess() ;
623 unsigned char * masksourcePtr = mask ? (unsigned char*) mask->GetRawAccess() : NULL ;
624
625 for ( int y = 0 ; y < h ; ++y, sourcePtr += m_bytesPerRow , masksourcePtr += mask ? mask->GetBytesPerRow() : 0 )
626 {
627 unsigned char * source = sourcePtr;
628 unsigned char * masksource = masksourcePtr;
629 unsigned char * dest = ptr + y * sz * 4 ;
630 unsigned char * maskdest = maskptr + y * sz ;
631 unsigned char a, r, g, b;
632
633 for ( int x = 0 ; x < w ; ++x )
634 {
635 a = *source ++ ;
636 r = *source ++ ;
637 g = *source ++ ;
638 b = *source ++ ;
639
640 *dest++ = 0 ;
641 *dest++ = r ;
642 *dest++ = g ;
643 *dest++ = b ;
644
645 if ( mask )
646 *maskdest++ = 0xFF - *masksource++ ;
647 else if ( hasAlpha )
648 *maskdest++ = a ;
649 else
650 *maskdest++ = 0xFF ;
651 }
652 }
653
654 OSStatus err = SetIconFamilyData( iconFamily, dataType , data ) ;
655 wxASSERT_MSG( err == noErr , wxT("Error when adding bitmap") ) ;
656
657 err = SetIconFamilyData( iconFamily, maskType , maskdata ) ;
658 wxASSERT_MSG( err == noErr , wxT("Error when adding mask") ) ;
659
660 HUnlock( data ) ;
661 HUnlock( maskdata ) ;
662 DisposeHandle( data ) ;
663 DisposeHandle( maskdata ) ;
664 }
665 }
489468fe
SC
666 // transform into IconRef
667
668 // cleaner version existing from 10.3 upwards
669 HLock((Handle) iconFamily);
670 OSStatus err = GetIconRefFromIconFamilyPtr( *iconFamily, GetHandleSize((Handle) iconFamily), &m_iconRef );
671 HUnlock((Handle) iconFamily);
672 DisposeHandle( (Handle) iconFamily ) ;
673
674 wxCHECK_MSG( err == noErr, NULL, wxT("Error when constructing icon ref") );
675 }
676
677 return m_iconRef ;
678}
679
489468fe
SC
680#endif
681
682CGImageRef wxBitmapRefData::CreateCGImage() const
683{
684 wxASSERT( m_ok ) ;
685 wxASSERT( m_rawAccessCount >= 0 ) ;
686 CGImageRef image ;
687 if ( m_rawAccessCount > 0 || m_cgImageRef == NULL )
688 {
689 if ( m_depth != 1 && m_bitmapMask == NULL )
690 {
0cc67fd5
SC
691#if 0
692 // in order for this code to work properly, wxMask would have to invert black and white
693 // in the native bitmap
489468fe
SC
694 if ( m_bitmapMask )
695 {
696 CGImageRef tempImage = CGBitmapContextCreateImage( m_hBitmap );
697 CGImageRef tempMask = CGBitmapContextCreateImage((CGContextRef) m_bitmapMask->GetHBITMAP() );
698 image = CGImageCreateWithMask( tempImage, tempMask );
699 CGImageRelease(tempMask);
700 CGImageRelease(tempImage);
701 }
702 else
0cc67fd5 703#endif
489468fe
SC
704 image = CGBitmapContextCreateImage( m_hBitmap );
705 }
706 else
707 {
708 size_t imageSize = m_height * m_bytesPerRow ;
709 void * dataBuffer = m_memBuf.GetData() ;
710 int w = m_width ;
711 int h = m_height ;
712 CGImageAlphaInfo alphaInfo = kCGImageAlphaNoneSkipFirst ;
713 wxMemoryBuffer membuf;
714
715 if ( m_bitmapMask )
716 {
717 alphaInfo = kCGImageAlphaFirst ;
718 unsigned char *destalphastart = (unsigned char*) membuf.GetWriteBuf( imageSize ) ;
719 memcpy( destalphastart , dataBuffer , imageSize ) ;
720 unsigned char *sourcemaskstart = (unsigned char *) m_bitmapMask->GetRawAccess() ;
721 int maskrowbytes = m_bitmapMask->GetBytesPerRow() ;
722 for ( int y = 0 ; y < h ; ++y , destalphastart += m_bytesPerRow, sourcemaskstart += maskrowbytes)
723 {
724 unsigned char *sourcemask = sourcemaskstart ;
725 unsigned char *destalpha = destalphastart ;
726 for ( int x = 0 ; x < w ; ++x , sourcemask += kMaskBytesPerPixel , destalpha += 4 )
727 {
728 *destalpha = 0xFF - *sourcemask ;
729 }
730 }
731 membuf.UngetWriteBuf( imageSize );
732 }
733 else
734 {
735 if ( m_hasAlpha )
736 {
292e5e1f 737#if wxOSX_USE_PREMULTIPLIED_ALPHA
489468fe
SC
738 alphaInfo = kCGImageAlphaPremultipliedFirst ;
739#else
740 alphaInfo = kCGImageAlphaFirst ;
741#endif
742 }
743
744 membuf = m_memBuf;
745 }
746
747 CGDataProviderRef dataProvider = NULL ;
748 if ( m_depth == 1 )
749 {
750 // TODO CHECK ALIGNMENT
751 wxMemoryBuffer maskBuf;
752 unsigned char * maskBufData = (unsigned char*) maskBuf.GetWriteBuf( m_width * m_height );
753 unsigned char * bufData = (unsigned char *) membuf.GetData() ;
754 // copy one color component
755 size_t i = 0;
756 for( int y = 0 ; y < m_height ; bufData+= m_bytesPerRow, ++y )
757 {
758 unsigned char *bufDataIter = bufData+3;
759 for ( int x = 0 ; x < m_width ; bufDataIter += 4, ++x, ++i )
760 {
761 maskBufData[i] = *bufDataIter;
762 }
763 }
764 maskBuf.UngetWriteBuf( m_width * m_height );
765
766 dataProvider =
767 wxMacCGDataProviderCreateWithMemoryBuffer( maskBuf );
768
769 image = ::CGImageMaskCreate( w, h, 8, 8, m_width , dataProvider, NULL, false );
770 }
771 else
772 {
773 CGColorSpaceRef colorSpace = wxMacGetGenericRGBColorSpace();
774 dataProvider = wxMacCGDataProviderCreateWithMemoryBuffer( membuf );
775 image =
776 ::CGImageCreate(
777 w, h, 8 , 32 , m_bytesPerRow , colorSpace, alphaInfo ,
778 dataProvider, NULL , false , kCGRenderingIntentDefault );
779 }
780 CGDataProviderRelease( dataProvider);
781 }
782 }
783 else
784 {
785 image = m_cgImageRef ;
786 CGImageRetain( image ) ;
787 }
788
789 if ( m_rawAccessCount == 0 && m_cgImageRef == NULL)
790 {
791 // we keep it for later use
792 m_cgImageRef = image ;
793 CGImageRetain( image ) ;
794 }
795
796 return image ;
797}
798
799CGContextRef wxBitmapRefData::GetBitmapContext() const
800{
801 return m_hBitmap;
802}
803
804void wxBitmapRefData::Free()
805{
806 wxASSERT_MSG( m_rawAccessCount == 0 , wxT("Bitmap still selected when destroyed") ) ;
807
808 if ( m_cgImageRef )
809 {
810 CGImageRelease( m_cgImageRef ) ;
811 m_cgImageRef = NULL ;
812 }
813#ifndef __WXOSX_IPHONE__
814 if ( m_iconRef )
815 {
816 ReleaseIconRef( m_iconRef ) ;
817 m_iconRef = NULL ;
818 }
489468fe
SC
819#endif
820 if ( m_hBitmap )
821 {
822 CGContextRelease(m_hBitmap);
823 m_hBitmap = NULL ;
824 }
825
5276b0a5 826 wxDELETE(m_bitmapMask);
489468fe
SC
827}
828
829wxBitmapRefData::~wxBitmapRefData()
830{
831 Free() ;
832}
833
732d8c74
FM
834
835
836// ----------------------------------------------------------------------------
837// wxBitmap
838// ----------------------------------------------------------------------------
839
489468fe
SC
840bool wxBitmap::CopyFromIcon(const wxIcon& icon)
841{
842 bool created = false ;
843 int w = icon.GetWidth() ;
844 int h = icon.GetHeight() ;
845
524c47aa
SC
846 Create( w , h ) ;
847#ifdef __WXOSX_CARBON__
489468fe
SC
848 if ( w == h && ( w == 16 || w == 32 || w == 48 || w == 128 ) )
849 {
850 IconFamilyHandle iconFamily = NULL ;
851 Handle imagehandle = NewHandle( 0 ) ;
852 Handle maskhandle = NewHandle( 0 ) ;
853
854 OSType maskType = 0;
855 OSType dataType = 0;
856 IconSelectorValue selector = 0 ;
857
858 switch (w)
859 {
860 case 128:
861 dataType = kThumbnail32BitData ;
862 maskType = kThumbnail8BitMask ;
863 selector = kSelectorAllAvailableData ;
864 break;
865
866 case 48:
867 dataType = kHuge32BitData ;
868 maskType = kHuge8BitMask ;
869 selector = kSelectorHuge32Bit | kSelectorHuge8BitMask ;
870 break;
871
872 case 32:
873 dataType = kLarge32BitData ;
874 maskType = kLarge8BitMask ;
875 selector = kSelectorLarge32Bit | kSelectorLarge8BitMask ;
876 break;
877
878 case 16:
879 dataType = kSmall32BitData ;
880 maskType = kSmall8BitMask ;
881 selector = kSelectorSmall32Bit | kSelectorSmall8BitMask ;
882 break;
883
884 default:
885 break;
886 }
887
888 OSStatus err = IconRefToIconFamily( MAC_WXHICON(icon.GetHICON()) , selector , &iconFamily ) ;
889
890 err = GetIconFamilyData( iconFamily , dataType , imagehandle ) ;
891 err = GetIconFamilyData( iconFamily , maskType , maskhandle ) ;
892 size_t imagehandlesize = GetHandleSize( imagehandle ) ;
893 size_t maskhandlesize = GetHandleSize( maskhandle ) ;
894
895 if ( imagehandlesize != 0 && maskhandlesize != 0 )
896 {
897 wxASSERT( GetHandleSize( imagehandle ) == w * 4 * h ) ;
898 wxASSERT( GetHandleSize( maskhandle ) == w * h ) ;
899
900 UseAlpha() ;
901
902 unsigned char *source = (unsigned char *) *imagehandle ;
903 unsigned char *sourcemask = (unsigned char *) *maskhandle ;
904 unsigned char* destination = (unsigned char*) BeginRawAccess() ;
905
906 for ( int y = 0 ; y < h ; ++y )
907 {
908 for ( int x = 0 ; x < w ; ++x )
909 {
910 unsigned char a = *sourcemask++;
911 *destination++ = a;
912 source++ ;
292e5e1f 913#if wxOSX_USE_PREMULTIPLIED_ALPHA
489468fe
SC
914 *destination++ = ( (*source++) * a + 127 ) / 255;
915 *destination++ = ( (*source++) * a + 127 ) / 255;
916 *destination++ = ( (*source++) * a + 127 ) / 255;
917#else
918 *destination++ = *source++ ;
919 *destination++ = *source++ ;
920 *destination++ = *source++ ;
921#endif
922 }
923 }
924
925 EndRawAccess() ;
926 DisposeHandle( imagehandle ) ;
927 DisposeHandle( maskhandle ) ;
928 created = true ;
929 }
930
931 DisposeHandle( (Handle) iconFamily ) ;
932 }
933#endif
934 if ( !created )
935 {
936 wxMemoryDC dc ;
937 dc.SelectObject( *this ) ;
938 dc.DrawIcon( icon , 0 , 0 ) ;
939 dc.SelectObject( wxNullBitmap ) ;
940 }
941
942 return true;
943}
944
489468fe
SC
945wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits)
946{
947 wxBitmapRefData* bitmapRefData;
948
949 m_refData = bitmapRefData = new wxBitmapRefData( the_width , the_height , no_bits ) ;
950
951 if (bitmapRefData->IsOk())
952 {
953 if ( no_bits == 1 )
954 {
784d9056
PC
955 int linesize = the_width / 8;
956 if ( the_width % 8 )
957 linesize++;
489468fe
SC
958
959 unsigned char* linestart = (unsigned char*) bits ;
960 unsigned char* destptr = (unsigned char*) BeginRawAccess() ;
961
962 for ( int y = 0 ; y < the_height ; ++y , linestart += linesize, destptr += M_BITMAPDATA->GetBytesPerRow() )
963 {
964 unsigned char* destination = destptr;
965 int index, bit, mask;
966
967 for ( int x = 0 ; x < the_width ; ++x )
968 {
969 index = x / 8 ;
970 bit = x % 8 ;
971 mask = 1 << bit ;
972
973 if ( linestart[index] & mask )
974 {
975 *destination++ = 0xFF ;
976 *destination++ = 0 ;
977 *destination++ = 0 ;
978 *destination++ = 0 ;
979 }
980 else
981 {
982 *destination++ = 0xFF ;
983 *destination++ = 0xFF ;
984 *destination++ = 0xFF ;
985 *destination++ = 0xFF ;
986 }
987 }
988 }
989
990 EndRawAccess() ;
991 }
992 else
993 {
994 wxFAIL_MSG(wxT("multicolor BITMAPs not yet implemented"));
995 }
996 } /* bitmapRefData->IsOk() */
997}
998
489468fe
SC
999wxBitmap::wxBitmap(const void* data, wxBitmapType type, int width, int height, int depth)
1000{
1001 (void) Create(data, type, width, height, depth);
1002}
1003
f8bfebfc 1004wxBitmap::wxBitmap(int width, int height, const wxDC& dc)
68d5ce90 1005{
f8bfebfc 1006 (void)Create(width, height, dc);
68d5ce90
SC
1007}
1008
489468fe
SC
1009wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type)
1010{
1011 LoadFile(filename, type);
1012}
1013
c944835a 1014wxBitmap::wxBitmap(CGImageRef image, double scale)
bf7470fe 1015{
c944835a 1016 (void) Create(image,scale);
bf7470fe
SC
1017}
1018
489468fe
SC
1019wxGDIRefData* wxBitmap::CreateGDIRefData() const
1020{
1021 return new wxBitmapRefData;
1022}
1023
1024wxGDIRefData* wxBitmap::CloneGDIRefData(const wxGDIRefData* data) const
1025{
5c33522f 1026 return new wxBitmapRefData(*static_cast<const wxBitmapRefData *>(data));
489468fe
SC
1027}
1028
1029void * wxBitmap::GetRawAccess() const
1030{
a1b806b9 1031 wxCHECK_MSG( IsOk() , NULL , wxT("invalid bitmap") ) ;
489468fe
SC
1032
1033 return M_BITMAPDATA->GetRawAccess() ;
1034}
1035
1036void * wxBitmap::BeginRawAccess()
1037{
a1b806b9 1038 wxCHECK_MSG( IsOk() , NULL , wxT("invalid bitmap") ) ;
489468fe
SC
1039
1040 return M_BITMAPDATA->BeginRawAccess() ;
1041}
1042
1043void wxBitmap::EndRawAccess()
1044{
a1b806b9 1045 wxCHECK_RET( IsOk() , wxT("invalid bitmap") ) ;
489468fe
SC
1046
1047 M_BITMAPDATA->EndRawAccess() ;
1048}
1049
1050CGImageRef wxBitmap::CreateCGImage() const
1051{
a1b806b9 1052 wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ;
489468fe
SC
1053
1054 return M_BITMAPDATA->CreateCGImage() ;
1055}
1056
1057#ifndef __WXOSX_IPHONE__
1058IconRef wxBitmap::GetIconRef() const
1059{
a1b806b9 1060 wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ;
489468fe
SC
1061
1062 return M_BITMAPDATA->GetIconRef() ;
1063}
1064
1065IconRef wxBitmap::CreateIconRef() const
1066{
1067 IconRef icon = GetIconRef();
1068 verify_noerr( AcquireIconRef(icon) );
1069 return icon;
1070}
1071#endif
1072
4bea628d 1073#if wxOSX_USE_COCOA
524c47aa 1074
72625b36
VS
1075wxBitmap::wxBitmap(WX_NSImage image)
1076{
1077 (void)Create(image);
1078}
1079
1080bool wxBitmap::Create(WX_NSImage image)
1081{
c944835a
SC
1082 return Create(wxOSXCreateBitmapContextFromNSImage(image));
1083}
1084
1085wxBitmap::wxBitmap(CGContextRef bitmapcontext)
1086{
1087 (void)Create(bitmapcontext);
1088}
1089
1090bool wxBitmap::Create(CGContextRef bitmapcontext)
1091{
1092 UnRef();
1093
1094 m_refData = new wxBitmapRefData( bitmapcontext );
1095
1096 return M_BITMAPDATA->IsOk() ;
72625b36
VS
1097}
1098
524c47aa
SC
1099WX_NSImage wxBitmap::GetNSImage() const
1100{
1101 wxCFRef< CGImageRef > cgimage(CreateCGImage());
c944835a 1102 return wxOSXGetNSImageFromCGImage( cgimage, GetScaleFactor() );
524c47aa
SC
1103}
1104
1105#endif
1106
4bea628d
SC
1107#if wxOSX_USE_IPHONE
1108
1109WX_UIImage wxBitmap::GetUIImage() const
1110{
1111 wxCFRef< CGImageRef > cgimage(CreateCGImage());
59d866ad 1112 return wxOSXGetUIImageFromCGImage( cgimage );
4bea628d
SC
1113}
1114
1115#endif
489468fe
SC
1116wxBitmap wxBitmap::GetSubBitmap(const wxRect &rect) const
1117{
a1b806b9 1118 wxCHECK_MSG( IsOk() &&
489468fe
SC
1119 (rect.x >= 0) && (rect.y >= 0) &&
1120 (rect.x+rect.width <= GetWidth()) &&
1121 (rect.y+rect.height <= GetHeight()),
1122 wxNullBitmap, wxT("invalid bitmap or bitmap region") );
1123
f8bfebfc
SC
1124 wxBitmap ret;
1125 double scale = GetScaleFactor();
1126 ret.CreateScaled( rect.width, rect.height, GetDepth(), scale );
a1b806b9 1127 wxASSERT_MSG( ret.IsOk(), wxT("GetSubBitmap error") );
489468fe 1128
f8bfebfc
SC
1129 int destwidth = rect.width*scale ;
1130 int destheight = rect.height*scale ;
489468fe
SC
1131
1132 {
1133 unsigned char *sourcedata = (unsigned char*) GetRawAccess() ;
1134 unsigned char *destdata = (unsigned char*) ret.BeginRawAccess() ;
f5fac447 1135 wxASSERT((sourcedata != NULL) && (destdata != NULL));
489468fe 1136
f5fac447 1137 if ( (sourcedata != NULL) && (destdata != NULL) )
489468fe 1138 {
f5fac447
SC
1139 int sourcelinesize = GetBitmapData()->GetBytesPerRow() ;
1140 int destlinesize = ret.GetBitmapData()->GetBytesPerRow() ;
f8bfebfc 1141 unsigned char *source = sourcedata + int(rect.x * scale * 4 + rect.y *scale * sourcelinesize) ;
f5fac447
SC
1142 unsigned char *dest = destdata ;
1143
1144 for (int yy = 0; yy < destheight; ++yy, source += sourcelinesize , dest += destlinesize)
1145 {
1146 memcpy( dest , source , destlinesize ) ;
1147 }
489468fe 1148 }
f5fac447 1149 ret.EndRawAccess() ;
489468fe
SC
1150 }
1151
489468fe
SC
1152
1153 if ( M_BITMAPDATA->m_bitmapMask )
1154 {
1155 wxMemoryBuffer maskbuf ;
1156 int rowBytes = GetBestBytesPerRow( destwidth * kMaskBytesPerPixel );
1157 size_t maskbufsize = rowBytes * destheight ;
1158
1159 int sourcelinesize = M_BITMAPDATA->m_bitmapMask->GetBytesPerRow() ;
1160 int destlinesize = rowBytes ;
1161
1162 unsigned char *source = (unsigned char *) M_BITMAPDATA->m_bitmapMask->GetRawAccess() ;
1163 unsigned char *destdata = (unsigned char * ) maskbuf.GetWriteBuf( maskbufsize ) ;
1164 wxASSERT( (source != NULL) && (destdata != NULL) ) ;
1165
f5fac447 1166 if ( (source != NULL) && (destdata != NULL) )
489468fe 1167 {
f5fac447
SC
1168 source += rect.x * kMaskBytesPerPixel + rect.y * sourcelinesize ;
1169 unsigned char *dest = destdata ;
1170
1171 for (int yy = 0; yy < destheight; ++yy, source += sourcelinesize , dest += destlinesize)
1172 {
1173 memcpy( dest , source , destlinesize ) ;
1174 }
489468fe 1175
f5fac447
SC
1176 maskbuf.UngetWriteBuf( maskbufsize ) ;
1177 }
489468fe
SC
1178 ret.SetMask( new wxMask( maskbuf , destwidth , destheight , rowBytes ) ) ;
1179 }
1180 else if ( HasAlpha() )
1181 ret.UseAlpha() ;
1182
1183 return ret;
1184}
1185
1186bool wxBitmap::Create(int w, int h, int d)
1187{
1188 UnRef();
1189
1190 if ( d < 0 )
1191 d = wxDisplayDepth() ;
1192
1193 m_refData = new wxBitmapRefData( w , h , d );
1194
1195 return M_BITMAPDATA->IsOk() ;
1196}
1197
f8bfebfc
SC
1198bool wxBitmap::Create(int w, int h, const wxDC& dc)
1199{
1200 double factor = dc.GetContentScaleFactor();
1201 return CreateScaled(w,h,wxBITMAP_SCREEN_DEPTH, factor);
1202}
1203
1204bool wxBitmap::CreateScaled(int w, int h, int d, double logicalScale)
1205{
1206 UnRef();
1207
1208 if ( d < 0 )
1209 d = wxDisplayDepth() ;
1210
1211 m_refData = new wxBitmapRefData( w , h , d, logicalScale );
1212
1213 return M_BITMAPDATA->IsOk() ;
1214}
1215
c944835a 1216bool wxBitmap::Create(CGImageRef image, double scale)
aaa7d63c
SC
1217{
1218 UnRef();
1219
c944835a 1220 m_refData = new wxBitmapRefData( image, scale );
aaa7d63c
SC
1221
1222 return M_BITMAPDATA->IsOk() ;
1223}
1224
489468fe
SC
1225bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type)
1226{
1227 UnRef();
1228
1229 wxBitmapHandler *handler = FindHandler(type);
1230
1231 if ( handler )
1232 {
1233 m_refData = new wxBitmapRefData;
1234
1235 return handler->LoadFile(this, filename, type, -1, -1);
1236 }
1237 else
1238 {
1239#if wxUSE_IMAGE
44c8e75b
SC
1240 double scale = 1.0;
1241 wxString fname = filename;
1242
1243 if ( type == wxBITMAP_TYPE_PNG )
1244 {
1245 if ( wxOSXGetMainScreenContentScaleFactor() > 1.9 )
1246 {
1247 wxFileName fn(filename);
1248 fn.MakeAbsolute();
1249 fn.SetName(fn.GetName()+"@2x");
1250
1251 if ( fn.Exists() )
1252 {
1253 fname = fn.GetFullPath();
1254 scale = 2.0;
1255 }
1256 }
1257 }
1258
1259 wxImage loadimage(fname, type);
a1b806b9 1260 if (loadimage.IsOk())
489468fe 1261 {
44c8e75b 1262 *this = wxBitmap(loadimage,-1,scale);
489468fe
SC
1263
1264 return true;
1265 }
1266#endif
1267 }
1268
1269 wxLogWarning(wxT("no bitmap handler for type %d defined."), type);
1270
1271 return false;
1272}
1273
1274bool wxBitmap::Create(const void* data, wxBitmapType type, int width, int height, int depth)
1275{
1276 UnRef();
1277
1278 m_refData = new wxBitmapRefData;
1279
1280 wxBitmapHandler *handler = FindHandler(type);
1281
1282 if ( handler == NULL )
1283 {
1284 wxLogWarning(wxT("no bitmap handler for type %d defined."), type);
1285
1286 return false;
1287 }
1288
1289 return handler->Create(this, data, type, width, height, depth);
1290}
1291
1292#if wxUSE_IMAGE
1293
44c8e75b 1294wxBitmap::wxBitmap(const wxImage& image, int depth, double scale)
489468fe 1295{
a1b806b9 1296 wxCHECK_RET( image.IsOk(), wxT("invalid image") );
489468fe
SC
1297
1298 // width and height of the device-dependent bitmap
1299 int width = image.GetWidth();
1300 int height = image.GetHeight();
1301
1302 wxBitmapRefData* bitmapRefData;
03647350 1303
44c8e75b 1304 m_refData = bitmapRefData = new wxBitmapRefData( width/scale, height/scale, depth, scale) ;
489468fe
SC
1305
1306 if ( bitmapRefData->IsOk())
1307 {
1308 // Create picture
1309
1310 bool hasAlpha = false ;
1311
1312 if ( image.HasMask() )
1313 {
1314 // takes precedence, don't mix with alpha info
1315 }
1316 else
1317 {
1318 hasAlpha = image.HasAlpha() ;
1319 }
1320
1321 if ( hasAlpha )
1322 UseAlpha() ;
1323
1324 unsigned char* destinationstart = (unsigned char*) BeginRawAccess() ;
1325 register unsigned char* data = image.GetData();
1326 if ( destinationstart != NULL && data != NULL )
1327 {
1328 const unsigned char *alpha = hasAlpha ? image.GetAlpha() : NULL ;
1329 for (int y = 0; y < height; destinationstart += M_BITMAPDATA->GetBytesPerRow(), y++)
1330 {
1331 unsigned char * destination = destinationstart;
1332 for (int x = 0; x < width; x++)
1333 {
1334 if ( hasAlpha )
1335 {
1336 const unsigned char a = *alpha++;
1337 *destination++ = a ;
1338
292e5e1f 1339 #if wxOSX_USE_PREMULTIPLIED_ALPHA
489468fe
SC
1340 *destination++ = ((*data++) * a + 127) / 255 ;
1341 *destination++ = ((*data++) * a + 127) / 255 ;
1342 *destination++ = ((*data++) * a + 127) / 255 ;
1343 #else
1344 *destination++ = *data++ ;
1345 *destination++ = *data++ ;
1346 *destination++ = *data++ ;
1347 #endif
1348 }
1349 else
1350 {
1351 *destination++ = 0xFF ;
1352 *destination++ = *data++ ;
1353 *destination++ = *data++ ;
1354 *destination++ = *data++ ;
1355 }
1356 }
1357 }
1358
1359 EndRawAccess() ;
1360 }
1361 if ( image.HasMask() )
1362 SetMask( new wxMask( *this , wxColour( image.GetMaskRed() , image.GetMaskGreen() , image.GetMaskBlue() ) ) ) ;
1363 } /* bitmapRefData->IsOk() */
1364}
1365
1366wxImage wxBitmap::ConvertToImage() const
1367{
1368 wxImage image;
1369
a1b806b9 1370 wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid bitmap") );
489468fe
SC
1371
1372 // create an wxImage object
1373 int width = GetWidth();
1374 int height = GetHeight();
1375 image.Create( width, height );
1376
1377 unsigned char *data = image.GetData();
1378 wxCHECK_MSG( data, wxNullImage, wxT("Could not allocate data for image") );
1379
1380 unsigned char* sourcestart = (unsigned char*) GetRawAccess() ;
1381
1382 bool hasAlpha = false ;
1383 bool hasMask = false ;
1384 int maskBytesPerRow = 0 ;
1385 unsigned char *alpha = NULL ;
1386 unsigned char *mask = NULL ;
1387
1388 if ( HasAlpha() )
1389 hasAlpha = true ;
1390
1391 if ( GetMask() )
1392 {
1393 hasMask = true ;
1394 mask = (unsigned char*) GetMask()->GetRawAccess() ;
1395 maskBytesPerRow = GetMask()->GetBytesPerRow() ;
1396 }
1397
1398 if ( hasAlpha )
1399 {
1400 image.SetAlpha() ;
1401 alpha = image.GetAlpha() ;
1402 }
1403
1404 int index = 0;
1405
1406 // The following masking algorithm is the same as well in msw/gtk:
1407 // the colour used as transparent one in wxImage and the one it is
1408 // replaced with when it actually occurs in the bitmap
1409 static const int MASK_RED = 1;
1410 static const int MASK_GREEN = 2;
1411 static const int MASK_BLUE = 3;
1412 static const int MASK_BLUE_REPLACEMENT = 2;
1413
1414 for (int yy = 0; yy < height; yy++ , sourcestart += M_BITMAPDATA->GetBytesPerRow() , mask += maskBytesPerRow )
1415 {
1416 unsigned char * maskp = mask ;
1417 unsigned char * source = sourcestart;
1418 unsigned char a, r, g, b;
1419 long color;
1420
1421 for (int xx = 0; xx < width; xx++)
1422 {
1423 color = *((long*) source) ;
1424#ifdef WORDS_BIGENDIAN
1425 a = ((color&0xFF000000) >> 24) ;
1426 r = ((color&0x00FF0000) >> 16) ;
1427 g = ((color&0x0000FF00) >> 8) ;
1428 b = (color&0x000000FF);
1429#else
1430 b = ((color&0xFF000000) >> 24) ;
1431 g = ((color&0x00FF0000) >> 16) ;
1432 r = ((color&0x0000FF00) >> 8) ;
1433 a = (color&0x000000FF);
1434#endif
1435 if ( hasMask )
1436 {
1437 if ( *maskp++ == 0xFF )
1438 {
1439 r = MASK_RED ;
1440 g = MASK_GREEN ;
1441 b = MASK_BLUE ;
1442 }
1443 else if ( r == MASK_RED && g == MASK_GREEN && b == MASK_BLUE )
1444 b = MASK_BLUE_REPLACEMENT ;
1445 }
1446 else if ( hasAlpha )
1447 {
1448 *alpha++ = a ;
292e5e1f 1449#if wxOSX_USE_PREMULTIPLIED_ALPHA
489468fe
SC
1450 // this must be non-premultiplied data
1451 if ( a != 0xFF && a!= 0 )
1452 {
1453 r = r * 255 / a;
1454 g = g * 255 / a;
1455 b = b * 255 / a;
1456 }
1457#endif
1458 }
1459
1460 data[index ] = r ;
1461 data[index + 1] = g ;
1462 data[index + 2] = b ;
1463
1464 index += 3;
1465 source += 4 ;
1466 }
1467 }
1468
1469 if ( hasMask )
1470 image.SetMaskColour( MASK_RED, MASK_GREEN, MASK_BLUE );
1471
1472 return image;
1473}
1474
1475#endif //wxUSE_IMAGE
1476
1477bool wxBitmap::SaveFile( const wxString& filename,
1478 wxBitmapType type, const wxPalette *palette ) const
1479{
1480 bool success = false;
1481 wxBitmapHandler *handler = FindHandler(type);
1482
1483 if ( handler )
1484 {
1485 success = handler->SaveFile(this, filename, type, palette);
1486 }
1487 else
1488 {
1489#if wxUSE_IMAGE
1490 wxImage image = ConvertToImage();
1491 success = image.SaveFile(filename, type);
1492#else
1493 wxLogWarning(wxT("no bitmap handler for type %d defined."), type);
1494#endif
1495 }
1496
1497 return success;
1498}
1499
1500int wxBitmap::GetHeight() const
1501{
a1b806b9 1502 wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
489468fe
SC
1503
1504 return M_BITMAPDATA->GetHeight();
1505}
1506
1507int wxBitmap::GetWidth() const
1508{
a1b806b9 1509 wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
489468fe
SC
1510
1511 return M_BITMAPDATA->GetWidth() ;
1512}
1513
f8bfebfc
SC
1514double wxBitmap::GetScaleFactor() const
1515{
1516 wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
1517
1518 return M_BITMAPDATA->GetScaleFactor() ;
1519}
1520
489468fe
SC
1521int wxBitmap::GetDepth() const
1522{
a1b806b9 1523 wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
489468fe
SC
1524
1525 return M_BITMAPDATA->GetDepth();
1526}
1527
1528wxMask *wxBitmap::GetMask() const
1529{
a1b806b9 1530 wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
489468fe
SC
1531
1532 return M_BITMAPDATA->m_bitmapMask;
1533}
1534
1535bool wxBitmap::HasAlpha() const
1536{
a1b806b9 1537 wxCHECK_MSG( IsOk(), false , wxT("invalid bitmap") );
489468fe
SC
1538
1539 return M_BITMAPDATA->HasAlpha() ;
1540}
1541
1542void wxBitmap::SetWidth(int w)
1543{
1544 AllocExclusive();
1545 M_BITMAPDATA->SetWidth(w);
1546}
1547
1548void wxBitmap::SetHeight(int h)
1549{
1550 AllocExclusive();
1551 M_BITMAPDATA->SetHeight(h);
1552}
1553
1554void wxBitmap::SetDepth(int d)
1555{
1556 AllocExclusive();
1557 M_BITMAPDATA->SetDepth(d);
1558}
1559
1560void wxBitmap::SetOk(bool isOk)
1561{
1562 AllocExclusive();
1563 M_BITMAPDATA->SetOk(isOk);
1564}
1565
1566#if wxUSE_PALETTE
1567wxPalette *wxBitmap::GetPalette() const
1568{
a1b806b9 1569 wxCHECK_MSG( IsOk(), NULL, wxT("Invalid bitmap GetPalette()") );
489468fe
SC
1570
1571 return &M_BITMAPDATA->m_bitmapPalette;
1572}
1573
1574void wxBitmap::SetPalette(const wxPalette& palette)
1575{
1576 AllocExclusive();
1577 M_BITMAPDATA->m_bitmapPalette = palette ;
1578}
1579#endif // wxUSE_PALETTE
1580
1581void wxBitmap::SetMask(wxMask *mask)
1582{
1583 AllocExclusive();
1584 // Remove existing mask if there is one.
1585 delete M_BITMAPDATA->m_bitmapMask;
1586
1587 M_BITMAPDATA->m_bitmapMask = mask ;
1588}
1589
1590WXHBITMAP wxBitmap::GetHBITMAP(WXHBITMAP* mask) const
1591{
1592 wxUnusedVar(mask);
1593
1594 return WXHBITMAP(M_BITMAPDATA->GetBitmapContext());
1595}
1596
1597// ----------------------------------------------------------------------------
1598// wxMask
1599// ----------------------------------------------------------------------------
1600
1601wxMask::wxMask()
1602{
1603 Init() ;
1604}
1605
ea2807a4 1606wxMask::wxMask(const wxMask &tocopy) : wxObject()
489468fe
SC
1607{
1608 Init();
1609
1610 m_bytesPerRow = tocopy.m_bytesPerRow;
1611 m_width = tocopy.m_width;
1612 m_height = tocopy.m_height;
1613
1614 size_t size = m_bytesPerRow * m_height;
1615 unsigned char* dest = (unsigned char*)m_memBuf.GetWriteBuf( size );
1616 unsigned char* source = (unsigned char*)tocopy.m_memBuf.GetData();
1617 memcpy( dest, source, size );
1618 m_memBuf.UngetWriteBuf( size ) ;
1619 RealizeNative() ;
1620}
1621
1622// Construct a mask from a bitmap and a colour indicating
1623// the transparent area
1624wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
1625{
1626 Init() ;
1627 Create( bitmap, colour );
1628}
1629
1630// Construct a mask from a mono bitmap (copies the bitmap).
1631wxMask::wxMask( const wxBitmap& bitmap )
1632{
1633 Init() ;
1634 Create( bitmap );
1635}
1636
1637// Construct a mask from a mono bitmap (copies the bitmap).
1638
1639wxMask::wxMask( const wxMemoryBuffer& data, int width , int height , int bytesPerRow )
1640{
1641 Init() ;
1642 Create( data, width , height , bytesPerRow );
1643}
1644
1645wxMask::~wxMask()
1646{
1647 if ( m_maskBitmap )
1648 {
1649 CGContextRelease( (CGContextRef) m_maskBitmap );
1650 m_maskBitmap = NULL ;
1651 }
1652}
1653
1654void wxMask::Init()
1655{
1656 m_width = m_height = m_bytesPerRow = 0 ;
1657 m_maskBitmap = NULL ;
1658}
1659
1660void *wxMask::GetRawAccess() const
1661{
1662 return m_memBuf.GetData() ;
1663}
1664
1665// The default ColorTable for k8IndexedGrayPixelFormat in Intel appears to be broken, so we'll use an non-indexed
1666// bitmap mask instead; in order to keep the code simple, the change applies to PowerPC implementations as well
1667
1668void wxMask::RealizeNative()
1669{
1670 if ( m_maskBitmap )
1671 {
1672 CGContextRelease( (CGContextRef) m_maskBitmap );
1673 m_maskBitmap = NULL ;
1674 }
1675
1676 CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
1677 // from MouseTracking sample :
1678 // Ironically, due to a bug in CGImageCreateWithMask, you cannot use
1679 // CGColorSpaceCreateWithName(kCGColorSpaceGenericGray) at this point!
1680
1681 m_maskBitmap = CGBitmapContextCreate((char*) m_memBuf.GetData(), m_width, m_height, 8, m_bytesPerRow, colorspace,
1682 kCGImageAlphaNone );
1683 CGColorSpaceRelease( colorspace );
1684 wxASSERT_MSG( m_maskBitmap , wxT("Unable to create CGBitmapContext context") ) ;
1685}
1686
1687// Create a mask from a mono bitmap (copies the bitmap).
1688
1689bool wxMask::Create(const wxMemoryBuffer& data,int width , int height , int bytesPerRow)
1690{
1691 m_memBuf = data ;
1692 m_width = width ;
1693 m_height = height ;
1694 m_bytesPerRow = bytesPerRow ;
1695
1696 wxASSERT( data.GetDataLen() == (size_t)(height * bytesPerRow) ) ;
1697
1698 RealizeNative() ;
1699
1700 return true ;
1701}
1702
1703// Create a mask from a mono bitmap (copies the bitmap).
1704bool wxMask::Create(const wxBitmap& bitmap)
1705{
1706 m_width = bitmap.GetWidth() ;
1707 m_height = bitmap.GetHeight() ;
1708 m_bytesPerRow = GetBestBytesPerRow( m_width * kMaskBytesPerPixel ) ;
1709
1710 size_t size = m_bytesPerRow * m_height ;
1711 unsigned char * destdatabase = (unsigned char*) m_memBuf.GetWriteBuf( size ) ;
1712 wxASSERT( destdatabase != NULL ) ;
974c115d
SC
1713
1714 if ( destdatabase )
489468fe 1715 {
974c115d
SC
1716 memset( destdatabase , 0 , size ) ;
1717 unsigned char * srcdata = (unsigned char*) bitmap.GetRawAccess() ;
489468fe 1718
974c115d 1719 for ( int y = 0 ; y < m_height ; ++y , destdatabase += m_bytesPerRow )
489468fe 1720 {
974c115d
SC
1721 unsigned char *destdata = destdatabase ;
1722 unsigned char r, g, b;
489468fe 1723
974c115d
SC
1724 for ( int x = 0 ; x < m_width ; ++x )
1725 {
1726 srcdata++ ;
1727 r = *srcdata++ ;
1728 g = *srcdata++ ;
1729 b = *srcdata++ ;
1730
1731 if ( ( r + g + b ) > 0x10 )
1732 *destdata++ = 0xFF ;
1733 else
1734 *destdata++ = 0x00 ;
1735 }
489468fe
SC
1736 }
1737 }
1738
1739 m_memBuf.UngetWriteBuf( size ) ;
1740 RealizeNative() ;
1741
1742 return true;
1743}
1744
1745// Create a mask from a bitmap and a colour indicating
1746// the transparent area
1747bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
1748{
1749 m_width = bitmap.GetWidth() ;
1750 m_height = bitmap.GetHeight() ;
1751 m_bytesPerRow = GetBestBytesPerRow( m_width * kMaskBytesPerPixel ) ;
1752
1753 size_t size = m_bytesPerRow * m_height ;
1754 unsigned char * destdatabase = (unsigned char*) m_memBuf.GetWriteBuf( size ) ;
1755 wxASSERT( destdatabase != NULL ) ;
f5fac447 1756 if ( destdatabase != NULL)
489468fe 1757 {
f5fac447
SC
1758 memset( destdatabase , 0 , size ) ;
1759 unsigned char * srcdatabase = (unsigned char*) bitmap.GetRawAccess() ;
1760 size_t sourceBytesRow = bitmap.GetBitmapData()->GetBytesPerRow();
489468fe 1761
f5fac447 1762 for ( int y = 0 ; y < m_height ; ++y , srcdatabase+= sourceBytesRow, destdatabase += m_bytesPerRow)
489468fe 1763 {
f5fac447
SC
1764 unsigned char *srcdata = srcdatabase ;
1765 unsigned char *destdata = destdatabase ;
1766 unsigned char r, g, b;
489468fe 1767
f5fac447
SC
1768 for ( int x = 0 ; x < m_width ; ++x )
1769 {
1770 srcdata++ ;
1771 r = *srcdata++ ;
1772 g = *srcdata++ ;
1773 b = *srcdata++ ;
1774
1775 if ( colour == wxColour( r , g , b ) )
1776 *destdata++ = 0xFF ;
1777 else
1778 *destdata++ = 0x00 ;
1779 }
489468fe
SC
1780 }
1781 }
489468fe
SC
1782 m_memBuf.UngetWriteBuf( size ) ;
1783 RealizeNative() ;
1784
1785 return true;
1786}
1787
5ca21fe7
PC
1788wxBitmap wxMask::GetBitmap() const
1789{
1790 wxBitmap bitmap(m_width, m_height, 1);
1791 unsigned char* dst = static_cast<unsigned char*>(bitmap.BeginRawAccess());
1792 const int dst_stride = bitmap.GetBitmapData()->GetBytesPerRow();
1793 const unsigned char* src = static_cast<unsigned char*>(GetRawAccess());
1794 for (int j = 0; j < m_height; j++, src += m_bytesPerRow, dst += dst_stride)
1795 {
1796 unsigned char* d = dst;
1797 for (int i = 0; i < m_width; i++)
1798 {
1799 const unsigned char byte = src[i];
1800 *d++ = 0xff;
1801 *d++ = byte;
1802 *d++ = byte;
1803 *d++ = byte;
1804 }
1805 }
1806 bitmap.EndRawAccess();
1807 return bitmap;
1808}
1809
489468fe
SC
1810WXHBITMAP wxMask::GetHBITMAP() const
1811{
1812 return m_maskBitmap ;
1813}
1814
1815// ----------------------------------------------------------------------------
1816// Standard Handlers
1817// ----------------------------------------------------------------------------
1818
aaa7d63c
SC
1819class WXDLLEXPORT wxBundleResourceHandler: public wxBitmapHandler
1820{
fb228105 1821 DECLARE_ABSTRACT_CLASS(wxBundleResourceHandler)
aaa7d63c
SC
1822
1823public:
1824 inline wxBundleResourceHandler()
1825 {
1826 };
1827
1828 virtual bool LoadFile(wxBitmap *bitmap,
1829 const wxString& name,
1830 wxBitmapType type,
1831 int desiredWidth,
1832 int desiredHeight);
1833};
1834
1835IMPLEMENT_ABSTRACT_CLASS(wxBundleResourceHandler, wxBitmapHandler);
1836
1837class WXDLLEXPORT wxPNGResourceHandler: public wxBundleResourceHandler
1838{
1839 DECLARE_DYNAMIC_CLASS(wxPNGResourceHandler)
1840
1841public:
1842 inline wxPNGResourceHandler()
1843 {
1844 SetName(wxT("PNG resource"));
1845 SetExtension("PNG");
1846 SetType(wxBITMAP_TYPE_PNG_RESOURCE);
1847 };
1848};
1849
1850IMPLEMENT_DYNAMIC_CLASS(wxPNGResourceHandler, wxBundleResourceHandler)
1851
1852class WXDLLEXPORT wxJPEGResourceHandler: public wxBundleResourceHandler
1853{
a51e79e8 1854 DECLARE_DYNAMIC_CLASS(wxJPEGResourceHandler)
aaa7d63c
SC
1855
1856public:
1857 inline wxJPEGResourceHandler()
1858 {
1859 SetName(wxT("JPEG resource"));
1860 SetExtension("JPEG");
1861 SetType(wxBITMAP_TYPE_JPEG_RESOURCE);
1862 };
1863};
1864
1865IMPLEMENT_DYNAMIC_CLASS(wxJPEGResourceHandler, wxBundleResourceHandler)
1866
1867bool wxBundleResourceHandler::LoadFile(wxBitmap *bitmap,
1868 const wxString& name,
1869 wxBitmapType WXUNUSED(type),
1870 int WXUNUSED(desiredWidth),
1871 int WXUNUSED(desiredHeight))
1872{
1873 wxString ext = GetExtension().Lower();
1874 wxCFStringRef resname(name);
e788ceb8 1875 wxCFStringRef resname2x(name+"@2x");
aaa7d63c 1876 wxCFStringRef restype(ext);
e788ceb8 1877 double scale = 1.0;
aaa7d63c 1878
e788ceb8
SC
1879 wxCFRef<CFURLRef> imageURL;
1880
e788ceb8
SC
1881 if ( wxOSXGetMainScreenContentScaleFactor() > 1.9 )
1882 {
1883 imageURL.reset(CFBundleCopyResourceURL(CFBundleGetMainBundle(), resname2x, restype, NULL));
1884 scale = 2.0;
1885 }
e788ceb8
SC
1886
1887 if ( imageURL.get() == NULL )
1888 {
1889 imageURL.reset(CFBundleCopyResourceURL(CFBundleGetMainBundle(), resname, restype, NULL));
1890 scale = 1.0;
1891 }
aaa7d63c
SC
1892
1893 if ( imageURL.get() != NULL )
1894 {
1895 // Create the data provider object
1896 wxCFRef<CGDataProviderRef> provider(CGDataProviderCreateWithURL (imageURL) );
1897 CGImageRef image = NULL;
1898
1899 if ( ext == "jpeg" )
1900 image = CGImageCreateWithJPEGDataProvider (provider, NULL, true,
1901 kCGRenderingIntentDefault);
1902 else if ( ext == "png" )
1903 image = CGImageCreateWithPNGDataProvider (provider, NULL, true,
1904 kCGRenderingIntentDefault);
1905 if ( image != NULL )
1906 {
e788ceb8 1907 bitmap->Create(image,scale);
aaa7d63c
SC
1908 CGImageRelease(image);
1909 }
1910 }
1911
1912 return false ;
1913}
1914
20e6714a
VZ
1915/* static */
1916wxBitmap wxBitmapHelpers::NewFromPNGData(const void* data, size_t size)
1917{
1918 wxCFRef<CGDataProviderRef>
1919 provider(CGDataProviderCreateWithData(NULL, data, size, NULL) );
1920 wxCFRef<CGImageRef>
1921 image(CGImageCreateWithPNGDataProvider(provider, NULL, true,
1922 kCGRenderingIntentDefault));
1923
1924 return wxBitmap(image);
1925}
1926
489468fe
SC
1927void wxBitmap::InitStandardHandlers()
1928{
aaa7d63c 1929#if wxOSX_USE_COCOA_OR_CARBON
489468fe 1930 AddHandler( new wxICONResourceHandler ) ;
b2680ced 1931#endif
aaa7d63c
SC
1932 AddHandler( new wxPNGResourceHandler );
1933 AddHandler( new wxJPEGResourceHandler );
489468fe
SC
1934}
1935
1936// ----------------------------------------------------------------------------
1937// raw bitmap access support
1938// ----------------------------------------------------------------------------
1939
1940void *wxBitmap::GetRawData(wxPixelDataBase& data, int WXUNUSED(bpp))
1941{
a1b806b9 1942 if ( !IsOk() )
489468fe
SC
1943 // no bitmap, no data (raw or otherwise)
1944 return NULL;
1945
1946 data.m_width = GetWidth() ;
1947 data.m_height = GetHeight() ;
1948 data.m_stride = GetBitmapData()->GetBytesPerRow() ;
1949
1950 return BeginRawAccess() ;
1951}
1952
1953void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(dataBase))
1954{
1955 EndRawAccess() ;
1956}
1957
1958void wxBitmap::UseAlpha()
1959{
1960 // remember that we are using alpha channel:
1961 // we'll need to create a proper mask in UngetRawData()
1962 M_BITMAPDATA->UseAlpha( true );
1963}