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