Update ooo320-m1
[ooovba.git] / vcl / aqua / source / gdi / salbmp.cxx
blobd42389e9a4e876e562fd382f512b5637bd62d0a5
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: salbmp.cxx,v $
10 * $Revision: 1.36 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include "tools/color.hxx"
35 #include "salbmp.h"
36 #include "vcl/bitmap.hxx" // for BitmapSystemData
37 #include "vcl/salbtype.hxx"
38 #include "vcl/bmpfast.hxx"
40 #include "basebmp/scanlineformats.hxx"
41 #include "basebmp/color.hxx"
42 #include "basegfx/vector/b2ivector.hxx"
44 #include <boost/bind.hpp>
46 #include "salinst.h"
48 // =======================================================================
50 static bool isValidBitCount( sal_uInt16 nBitCount )
52 return (nBitCount == 1) || (nBitCount == 4) || (nBitCount == 8) || (nBitCount == 16) || (nBitCount == 24) || (nBitCount == 32);
55 // =======================================================================
57 AquaSalBitmap::AquaSalBitmap()
58 : mxGraphicContext( NULL )
59 , mxCachedImage( NULL )
60 , mnBits(0)
61 , mnWidth(0)
62 , mnHeight(0)
63 , mnBytesPerRow(0)
67 // ------------------------------------------------------------------
69 AquaSalBitmap::~AquaSalBitmap()
71 Destroy();
74 // ------------------------------------------------------------------
76 bool AquaSalBitmap::Create( CGLayerRef xLayer, int nBitmapBits,
77 int nX, int nY, int nWidth, int nHeight, bool /*bMirrorVert*/ )
79 DBG_ASSERT( xLayer, "AquaSalBitmap::Create() from non-layered context" );
81 // sanitize input parameters
82 if( nX < 0 )
83 nWidth += nX, nX = 0;
84 if( nY < 0 )
85 nHeight += nY, nY = 0;
86 const CGSize aLayerSize = CGLayerGetSize( xLayer );
87 if( nWidth >= (int)aLayerSize.width - nX )
88 nWidth = (int)aLayerSize.width - nX;
89 if( nHeight >= (int)aLayerSize.height - nY )
90 nHeight = (int)aLayerSize.height - nY;
91 if( (nWidth < 0) || (nHeight < 0) )
92 nWidth = nHeight = 0;
94 // initialize properties
95 mnWidth = nWidth;
96 mnHeight = nHeight;
97 mnBits = nBitmapBits ? nBitmapBits : 32;
99 // initialize drawing context
100 CreateContext();
102 // copy layer content into the bitmap buffer
103 const CGPoint aSrcPoint = { -nX, -nY };
104 ::CGContextDrawLayerAtPoint( mxGraphicContext, aSrcPoint, xLayer );
105 return true;
108 // ------------------------------------------------------------------
110 bool AquaSalBitmap::Create( const Size& rSize, USHORT nBits, const BitmapPalette& rBitmapPalette )
112 if( !isValidBitCount( nBits ) )
113 return false;
114 maPalette = rBitmapPalette;
115 mnBits = nBits;
116 mnWidth = rSize.Width();
117 mnHeight = rSize.Height();
118 return AllocateUserData();
121 // ------------------------------------------------------------------
123 bool AquaSalBitmap::Create( const SalBitmap& rSalBmp )
125 return Create( rSalBmp, rSalBmp.GetBitCount() );
128 // ------------------------------------------------------------------
130 bool AquaSalBitmap::Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics )
132 return Create( rSalBmp, pGraphics ? pGraphics->GetBitCount() : rSalBmp.GetBitCount() );
135 // ------------------------------------------------------------------
137 bool AquaSalBitmap::Create( const SalBitmap& rSalBmp, USHORT nNewBitCount )
139 const AquaSalBitmap& rSourceBitmap = static_cast<const AquaSalBitmap&>(rSalBmp);
141 if( isValidBitCount( nNewBitCount ) && rSourceBitmap.maUserBuffer.get() )
143 mnBits = nNewBitCount;
144 mnWidth = rSourceBitmap.mnWidth;
145 mnHeight = rSourceBitmap.mnHeight;
146 maPalette = rSourceBitmap.maPalette;
148 if( AllocateUserData() )
150 ConvertBitmapData( mnWidth, mnHeight, mnBits, mnBytesPerRow, maPalette, maUserBuffer.get(), rSourceBitmap.mnBits, rSourceBitmap.mnBytesPerRow, rSourceBitmap.maPalette, rSourceBitmap.maUserBuffer.get() );
151 return true;
154 return false;
157 // ------------------------------------------------------------------
159 bool AquaSalBitmap::Create( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas > /*xBitmapCanvas*/, Size& /*rSize*/, bool /*bMask*/ )
161 return false;
164 // ------------------------------------------------------------------
166 void AquaSalBitmap::Destroy()
168 DestroyContext();
169 maUserBuffer.reset();
172 // ------------------------------------------------------------------
174 void AquaSalBitmap::DestroyContext()
176 CGImageRelease( mxCachedImage );
177 mxCachedImage = NULL;
179 if( mxGraphicContext )
181 CGContextRelease( mxGraphicContext );
182 mxGraphicContext = NULL;
183 maContextBuffer.reset();
187 // ------------------------------------------------------------------
189 bool AquaSalBitmap::CreateContext()
191 DestroyContext();
193 // prepare graphics context
194 // convert image from user input if available
195 const bool bSkipConversion = !maUserBuffer;
196 if( bSkipConversion )
197 AllocateUserData();
199 // default to RGBA color space
200 CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
201 CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
203 // convert data into something accepted by CGBitmapContextCreate()
204 size_t bitsPerComponent = (mnBits == 16) ? 5 : 8;
205 sal_uInt32 nContextBytesPerRow = mnBytesPerRow;
206 if( (mnBits == 16) || (mnBits == 32) )
208 // no conversion needed for truecolor
209 maContextBuffer = maUserBuffer;
211 else if( (mnBits == 8) && maPalette.IsGreyPalette() )
213 // no conversion needed for grayscale
214 maContextBuffer = maUserBuffer;
215 aCGColorSpace = GetSalData()->mxGraySpace;
216 aCGBmpInfo = kCGImageAlphaNone;
217 bitsPerComponent = mnBits;
219 // TODO: is special handling for 1bit input buffers worth it?
220 else
222 // convert user data to 32 bit
223 nContextBytesPerRow = mnWidth << 2;
226 maContextBuffer.reset( new sal_uInt8[ mnHeight * nContextBytesPerRow ] );
228 if( !bSkipConversion )
229 ConvertBitmapData( mnWidth, mnHeight,
230 32, nContextBytesPerRow, maPalette, maContextBuffer.get(),
231 mnBits, mnBytesPerRow, maPalette, maUserBuffer.get() );
233 catch( std::bad_alloc )
235 mxGraphicContext = 0;
239 if( maContextBuffer.get() )
241 mxGraphicContext = ::CGBitmapContextCreate( maContextBuffer.get(), mnWidth, mnHeight,
242 bitsPerComponent, nContextBytesPerRow, aCGColorSpace, aCGBmpInfo );
245 if( !mxGraphicContext )
246 maContextBuffer.reset();
248 return mxGraphicContext != NULL;
251 // ------------------------------------------------------------------
253 bool AquaSalBitmap::AllocateUserData()
255 Destroy();
257 if( mnWidth && mnHeight )
259 mnBytesPerRow = 0;
261 switch( mnBits )
263 case 1: mnBytesPerRow = (mnWidth + 7) >> 3; break;
264 case 4: mnBytesPerRow = (mnWidth + 1) >> 1; break;
265 case 8: mnBytesPerRow = mnWidth; break;
266 case 16: mnBytesPerRow = mnWidth << 1; break;
267 case 24: mnBytesPerRow = (mnWidth << 1) + mnWidth; break;
268 case 32: mnBytesPerRow = mnWidth << 2; break;
269 default:
270 DBG_ERROR("vcl::AquaSalBitmap::AllocateUserData(), illegal bitcount!");
276 if( mnBytesPerRow )
277 maUserBuffer.reset( new sal_uInt8[mnBytesPerRow * mnHeight] );
279 catch( const std::bad_alloc& )
281 DBG_ERROR( "vcl::AquaSalBitmap::AllocateUserData: bad alloc" );
282 maUserBuffer.reset( NULL );
283 mnBytesPerRow = 0;
286 return maUserBuffer.get() != 0;
289 // ------------------------------------------------------------------
291 class ImplPixelFormat
293 protected:
294 sal_uInt8* pData;
295 public:
296 static ImplPixelFormat* GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette );
298 virtual void StartLine( sal_uInt8* pLine ) { pData = pLine; }
299 virtual void SkipPixel( sal_uInt32 nPixel ) = 0;
300 virtual ColorData ReadPixel() = 0;
301 virtual void WritePixel( ColorData nColor ) = 0;
304 class ImplPixelFormat32 : public ImplPixelFormat
305 // currently ARGB-format for 32bit depth
307 public:
308 virtual void SkipPixel( sal_uInt32 nPixel )
310 pData += nPixel << 2;
312 virtual ColorData ReadPixel()
314 const ColorData c = RGB_COLORDATA( pData[1], pData[2], pData[3] );
315 pData += 4;
316 return c;
318 virtual void WritePixel( ColorData nColor )
320 *pData++ = 0;
321 *pData++ = COLORDATA_RED( nColor );
322 *pData++ = COLORDATA_GREEN( nColor );
323 *pData++ = COLORDATA_BLUE( nColor );
327 class ImplPixelFormat24 : public ImplPixelFormat
328 // currently BGR-format for 24bit depth
330 public:
331 virtual void SkipPixel( sal_uInt32 nPixel )
333 pData += (nPixel << 1) + nPixel;
335 virtual ColorData ReadPixel()
337 const ColorData c = RGB_COLORDATA( pData[2], pData[1], pData[0] );
338 pData += 3;
339 return c;
341 virtual void WritePixel( ColorData nColor )
343 *pData++ = COLORDATA_BLUE( nColor );
344 *pData++ = COLORDATA_GREEN( nColor );
345 *pData++ = COLORDATA_RED( nColor );
349 class ImplPixelFormat16 : public ImplPixelFormat
350 // currently R5G6B5-format for 16bit depth
352 protected:
353 sal_uInt16* pData16;
354 public:
356 virtual void StartLine( sal_uInt8* pLine )
358 pData16 = (sal_uInt16*)pLine;
360 virtual void SkipPixel( sal_uInt32 nPixel )
362 pData += nPixel;
364 virtual ColorData ReadPixel()
366 const ColorData c = RGB_COLORDATA( (*pData & 0x7c00) >> 7, (*pData & 0x03e0) >> 2 , (*pData & 0x001f) << 3 );
367 pData++;
368 return c;
370 virtual void WritePixel( ColorData nColor )
372 *pData++ = ((COLORDATA_RED( nColor ) & 0xf8 ) << 7 ) ||
373 ((COLORDATA_GREEN( nColor ) & 0xf8 ) << 2 ) ||
374 ((COLORDATA_BLUE( nColor ) & 0xf8 ) >> 3 );
378 class ImplPixelFormat8 : public ImplPixelFormat
380 private:
381 const BitmapPalette& mrPalette;
383 public:
384 ImplPixelFormat8( const BitmapPalette& rPalette )
385 : mrPalette( rPalette )
388 virtual void SkipPixel( sal_uInt32 nPixel )
390 pData += nPixel;
392 virtual ColorData ReadPixel()
394 return mrPalette[ *pData++ ].operator Color().GetColor();
396 virtual void WritePixel( ColorData nColor )
398 const BitmapColor aColor( COLORDATA_RED( nColor ), COLORDATA_GREEN( nColor ), COLORDATA_BLUE( nColor ) );
399 *pData++ = static_cast< sal_uInt8 >( mrPalette.GetBestIndex( aColor ) );
403 class ImplPixelFormat4 : public ImplPixelFormat
405 private:
406 const BitmapPalette& mrPalette;
407 sal_uInt32 mnX;
408 sal_uInt32 mnShift;
410 public:
411 ImplPixelFormat4( const BitmapPalette& rPalette )
412 : mrPalette( rPalette )
415 virtual void SkipPixel( sal_uInt32 nPixel )
417 mnX += nPixel;
418 if( (nPixel & 1) )
419 mnShift ^= 4;
421 virtual void StartLine( sal_uInt8* pLine )
423 pData = pLine;
424 mnX = 0;
425 mnShift = 4;
427 virtual ColorData ReadPixel()
429 const BitmapColor& rColor = mrPalette[( pData[mnX >> 1] >> mnShift) & 0x0f];
430 mnX++;
431 mnShift ^= 4;
432 return rColor.operator Color().GetColor();
434 virtual void WritePixel( ColorData nColor )
436 const BitmapColor aColor( COLORDATA_RED( nColor ), COLORDATA_GREEN( nColor ), COLORDATA_BLUE( nColor ) );
437 pData[mnX>>1] &= (0xf0 >> mnShift);
438 pData[mnX>>1] |= (static_cast< sal_uInt8 >( mrPalette.GetBestIndex( aColor ) ) & 0x0f);
439 mnX++;
440 mnShift ^= 4;
444 class ImplPixelFormat1 : public ImplPixelFormat
446 private:
447 const BitmapPalette& mrPalette;
448 sal_uInt32 mnX;
450 public:
451 ImplPixelFormat1( const BitmapPalette& rPalette )
452 : mrPalette( rPalette )
455 virtual void SkipPixel( sal_uInt32 nPixel )
457 mnX += nPixel;
459 virtual void StartLine( sal_uInt8* pLine )
461 pData = pLine;
462 mnX = 0;
464 virtual ColorData ReadPixel()
466 const BitmapColor& rColor = mrPalette[ (pData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1];
467 mnX++;
468 return rColor.operator Color().GetColor();
470 virtual void WritePixel( ColorData nColor )
472 const BitmapColor aColor( COLORDATA_RED( nColor ), COLORDATA_GREEN( nColor ), COLORDATA_BLUE( nColor ) );
473 if( mrPalette.GetBestIndex( aColor ) & 1 )
474 pData[ mnX >> 3 ] |= 1 << ( 7 - ( mnX & 7 ) );
475 else
476 pData[ mnX >> 3 ] &= ~( 1 << ( 7 - ( mnX & 7 ) ) );
477 mnX++;
481 ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette )
483 switch( nBits )
485 case 1: return new ImplPixelFormat1( rPalette );
486 case 4: return new ImplPixelFormat4( rPalette );
487 case 8: return new ImplPixelFormat8( rPalette );
488 case 16: return new ImplPixelFormat16;
489 case 24: return new ImplPixelFormat24;
490 case 32: return new ImplPixelFormat32;
493 return 0;
496 void AquaSalBitmap::ConvertBitmapData( sal_uInt32 nWidth, sal_uInt32 nHeight,
497 sal_uInt16 nDestBits, sal_uInt32 nDestBytesPerRow, const BitmapPalette& rDestPalette, sal_uInt8* pDestData,
498 sal_uInt16 nSrcBits, sal_uInt32 nSrcBytesPerRow, const BitmapPalette& rSrcPalette, sal_uInt8* pSrcData )
501 if( (nDestBytesPerRow == nSrcBytesPerRow) && (nDestBits == nSrcBits) && ((nSrcBits != 8) || (rDestPalette.operator==( rSrcPalette ))) )
503 // simple case, same format, so just copy
504 memcpy( pDestData, pSrcData, nHeight * nDestBytesPerRow );
505 return;
508 // try accelerated conversion if possible
509 // TODO: are other truecolor conversions except BGR->ARGB worth it?
510 bool bConverted = false;
511 if( (nSrcBits == 24) && (nDestBits == 32) )
513 // TODO: extend bmpfast.cxx with a method that can be directly used here
514 BitmapBuffer aSrcBuf;
515 aSrcBuf.mnFormat = BMP_FORMAT_24BIT_TC_BGR;
516 aSrcBuf.mpBits = pSrcData;
517 aSrcBuf.mnBitCount = nSrcBits;
518 aSrcBuf.mnScanlineSize = nSrcBytesPerRow;
519 BitmapBuffer aDstBuf;
520 aDstBuf.mnFormat = BMP_FORMAT_32BIT_TC_ARGB;
521 aDstBuf.mpBits = pDestData;
522 aSrcBuf.mnBitCount = nDestBits;
523 aDstBuf.mnScanlineSize = nDestBytesPerRow;
525 aSrcBuf.mnWidth = aDstBuf.mnWidth = nWidth;
526 aSrcBuf.mnHeight = aDstBuf.mnHeight = nHeight;
528 SalTwoRect aTwoRects;
529 aTwoRects.mnSrcX = aTwoRects.mnDestX = 0;
530 aTwoRects.mnSrcY = aTwoRects.mnDestY = 0;
531 aTwoRects.mnSrcWidth = aTwoRects.mnDestWidth = mnWidth;
532 aTwoRects.mnSrcHeight = aTwoRects.mnDestHeight = mnHeight;
533 bConverted = ::ImplFastBitmapConversion( aDstBuf, aSrcBuf, aTwoRects );
536 if( !bConverted )
538 // TODO: this implementation is for clarety, not for speed
540 ImplPixelFormat* pD = ImplPixelFormat::GetFormat( nDestBits, rDestPalette );
541 ImplPixelFormat* pS = ImplPixelFormat::GetFormat( nSrcBits, rSrcPalette );
543 if( pD && pS )
545 sal_uInt32 nY = nHeight;
546 while( nY-- )
548 pD->StartLine( pDestData );
549 pS->StartLine( pSrcData );
551 sal_uInt32 nX = nWidth;
552 while( nX-- )
553 pD->WritePixel( pS->ReadPixel() );
555 pSrcData += nSrcBytesPerRow;
556 pDestData += nDestBytesPerRow;
559 delete pS;
560 delete pD;
564 // ------------------------------------------------------------------
566 Size AquaSalBitmap::GetSize() const
568 return Size( mnWidth, mnHeight );
571 // ------------------------------------------------------------------
573 USHORT AquaSalBitmap::GetBitCount() const
575 return mnBits;
578 // ------------------------------------------------------------------
580 static struct pal_entry
582 BYTE mnRed;
583 BYTE mnGreen;
584 BYTE mnBlue;
586 const aImplSalSysPalEntryAry[ 16 ] =
588 { 0, 0, 0 },
589 { 0, 0, 0x80 },
590 { 0, 0x80, 0 },
591 { 0, 0x80, 0x80 },
592 { 0x80, 0, 0 },
593 { 0x80, 0, 0x80 },
594 { 0x80, 0x80, 0 },
595 { 0x80, 0x80, 0x80 },
596 { 0xC0, 0xC0, 0xC0 },
597 { 0, 0, 0xFF },
598 { 0, 0xFF, 0 },
599 { 0, 0xFF, 0xFF },
600 { 0xFF, 0, 0 },
601 { 0xFF, 0, 0xFF },
602 { 0xFF, 0xFF, 0 },
603 { 0xFF, 0xFF, 0xFF }
606 const BitmapPalette& GetDefaultPalette( int mnBits, bool bMonochrome )
608 if( bMonochrome )
609 return Bitmap::GetGreyPalette( 1U << mnBits );
611 // at this point we should provide some kind of default palette
612 // since all other platforms do so, too.
613 static bool bDefPalInit = false;
614 static BitmapPalette aDefPalette256;
615 static BitmapPalette aDefPalette16;
616 static BitmapPalette aDefPalette2;
617 if( ! bDefPalInit )
619 bDefPalInit = true;
620 aDefPalette256.SetEntryCount( 256 );
621 aDefPalette16.SetEntryCount( 16 );
622 aDefPalette2.SetEntryCount( 2 );
624 // Standard colors
625 unsigned int i;
626 for( i = 0; i < 16; i++ )
628 aDefPalette16[i] =
629 aDefPalette256[i] = BitmapColor( aImplSalSysPalEntryAry[i].mnRed,
630 aImplSalSysPalEntryAry[i].mnGreen,
631 aImplSalSysPalEntryAry[i].mnBlue );
634 aDefPalette2[0] = BitmapColor( 0, 0, 0 );
635 aDefPalette2[1] = BitmapColor( 0xff, 0xff, 0xff );
637 // own palette (6/6/6)
638 const int DITHER_PAL_STEPS = 6;
639 const BYTE DITHER_PAL_DELTA = 51;
640 int nB, nG, nR;
641 BYTE nRed, nGreen, nBlue;
642 for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
644 for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
646 for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
648 aDefPalette256[ i ] = BitmapColor( nRed, nGreen, nBlue );
649 i++;
655 // now fill in appropriate palette
656 switch( mnBits )
658 case 1: return aDefPalette2;
659 case 4: return aDefPalette16;
660 case 8: return aDefPalette256;
661 default: break;
664 const static BitmapPalette aEmptyPalette;
665 return aEmptyPalette;
668 BitmapBuffer* AquaSalBitmap::AcquireBuffer( bool bReadOnly )
670 if( !maUserBuffer.get() )
671 // || maContextBuffer.get() && (maUserBuffer.get() != maContextBuffer.get()) )
673 fprintf(stderr,"ASB::Acq(%dx%d,d=%d)\n",mnWidth,mnHeight,mnBits);
674 // TODO: AllocateUserData();
675 return NULL;
678 BitmapBuffer* pBuffer = new BitmapBuffer;
679 pBuffer->mnWidth = mnWidth;
680 pBuffer->mnHeight = mnHeight;
681 pBuffer->maPalette = maPalette;
682 pBuffer->mnScanlineSize = mnBytesPerRow;
683 pBuffer->mpBits = maUserBuffer.get();
684 pBuffer->mnBitCount = mnBits;
685 switch( mnBits )
687 case 1: pBuffer->mnFormat = BMP_FORMAT_1BIT_MSB_PAL; break;
688 case 4: pBuffer->mnFormat = BMP_FORMAT_4BIT_MSN_PAL; break;
689 case 8: pBuffer->mnFormat = BMP_FORMAT_8BIT_PAL; break;
690 case 16: pBuffer->mnFormat = BMP_FORMAT_16BIT_TC_MSB_MASK;
691 pBuffer->maColorMask = ColorMask( k16BitRedColorMask, k16BitGreenColorMask, k16BitBlueColorMask );
692 break;
693 case 24: pBuffer->mnFormat = BMP_FORMAT_24BIT_TC_BGR; break;
694 case 32: pBuffer->mnFormat = BMP_FORMAT_32BIT_TC_ARGB;
695 pBuffer->maColorMask = ColorMask( k32BitRedColorMask, k32BitGreenColorMask, k32BitBlueColorMask );
696 break;
698 pBuffer->mnFormat |= BMP_FORMAT_BOTTOM_UP;
700 // some BitmapBuffer users depend on a complete palette
701 if( (mnBits <= 8) && !maPalette )
702 pBuffer->maPalette = GetDefaultPalette( mnBits, true );
704 return pBuffer;
707 // ------------------------------------------------------------------
709 void AquaSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
711 // invalidate graphic context if we have different data
712 if( !bReadOnly )
714 maPalette = pBuffer->maPalette;
715 if( mxGraphicContext )
716 DestroyContext();
719 delete pBuffer;
722 // ------------------------------------------------------------------
724 CGImageRef AquaSalBitmap::CreateCroppedImage( int nX, int nY, int nNewWidth, int nNewHeight ) const
726 if( !mxCachedImage )
728 if( !mxGraphicContext )
729 if( !const_cast<AquaSalBitmap*>(this)->CreateContext() )
730 return NULL;
732 mxCachedImage = CGBitmapContextCreateImage( mxGraphicContext );
735 CGImageRef xCroppedImage = NULL;
736 // short circuit if there is nothing to crop
737 if( !nX && !nY && (mnWidth == nNewWidth) && (mnHeight == nNewHeight) )
739 xCroppedImage = mxCachedImage;
740 CFRetain( xCroppedImage );
742 else
744 nY = mnHeight - (nY + nNewHeight); // adjust for y-mirrored context
745 const CGRect aCropRect = {{nX, nY}, {nNewWidth, nNewHeight}};
746 xCroppedImage = CGImageCreateWithImageInRect( mxCachedImage, aCropRect );
749 return xCroppedImage;
752 // ------------------------------------------------------------------
754 static void CFRTLFree(void* /*info*/, const void* data, size_t /*size*/)
756 rtl_freeMemory( const_cast<void*>(data) );
759 CGImageRef AquaSalBitmap::CreateWithMask( const AquaSalBitmap& rMask,
760 int nX, int nY, int nWidth, int nHeight ) const
762 CGImageRef xImage( CreateCroppedImage( nX, nY, nWidth, nHeight ) );
763 if( !xImage )
764 return NULL;
766 CGImageRef xMask = rMask.CreateCroppedImage( nX, nY, nWidth, nHeight );
767 if( !xMask )
768 return xImage;
770 // CGImageCreateWithMask() only likes masks or greyscale images => convert if needed
771 // TODO: isolate in an extra method?
772 if( !CGImageIsMask(xMask) || (CGImageGetColorSpace(xMask) != GetSalData()->mxGraySpace) )
774 const CGRect xImageRect=CGRectMake( 0, 0, nWidth, nHeight );//the rect has no offset
776 // create the alpha mask image fitting our image
777 // TODO: is caching the full mask or the subimage mask worth it?
778 int nMaskBytesPerRow = ((nWidth + 3) & ~3);
779 void* pMaskMem = rtl_allocateMemory( nMaskBytesPerRow * nHeight );
780 CGContextRef xMaskContext = CGBitmapContextCreate( pMaskMem,
781 nWidth, nHeight, 8, nMaskBytesPerRow, GetSalData()->mxGraySpace, kCGImageAlphaNone );
782 CGContextDrawImage( xMaskContext, xImageRect, xMask );
783 CFRelease( xMask );
784 CGDataProviderRef xDataProvider( CGDataProviderCreateWithData( NULL,
785 pMaskMem, nHeight * nMaskBytesPerRow, &CFRTLFree ) );
786 static const float* pDecode = NULL;
787 xMask = CGImageMaskCreate( nWidth, nHeight, 8, 8, nMaskBytesPerRow, xDataProvider, pDecode, false );
788 CFRelease( xDataProvider );
789 CFRelease( xMaskContext );
792 if( !xMask )
793 return xImage;
795 // combine image and alpha mask
796 CGImageRef xMaskedImage = CGImageCreateWithMask( xImage, xMask );
797 CFRelease( xMask );
798 CFRelease( xImage );
799 return xMaskedImage;
802 // ------------------------------------------------------------------
804 /** creates an image from the given rectangle, replacing all black pixels with nMaskColor and make all other full transparent */
805 CGImageRef AquaSalBitmap::CreateColorMask( int nX, int nY, int nWidth, int nHeight, SalColor nMaskColor ) const
807 CGImageRef xMask = 0;
808 if( maUserBuffer.get() && (nX + nWidth <= mnWidth) && (nY + nHeight <= mnHeight) )
810 const sal_uInt32 nDestBytesPerRow = nWidth << 2;
811 sal_uInt32* pMaskBuffer = static_cast<sal_uInt32*>( rtl_allocateMemory( nHeight * nDestBytesPerRow ) );
812 sal_uInt32* pDest = pMaskBuffer;
814 ImplPixelFormat* pSourcePixels = ImplPixelFormat::GetFormat( mnBits, maPalette );
816 if( pMaskBuffer && pSourcePixels )
818 sal_uInt32 nColor;
819 reinterpret_cast<sal_uInt8*>(&nColor)[0] = 0xff;
820 reinterpret_cast<sal_uInt8*>(&nColor)[1] = SALCOLOR_RED( nMaskColor );
821 reinterpret_cast<sal_uInt8*>(&nColor)[2] = SALCOLOR_GREEN( nMaskColor );
822 reinterpret_cast<sal_uInt8*>(&nColor)[3] = SALCOLOR_BLUE( nMaskColor );
824 sal_uInt8* pSource = maUserBuffer.get();
825 if( nY )
826 pSource += nY * mnBytesPerRow;
828 int y = nHeight;
829 while( y-- )
831 pSourcePixels->StartLine( pSource );
832 pSourcePixels->SkipPixel(nX);
833 sal_uInt32 x = nWidth;
834 while( x-- )
836 *pDest++ = ( pSourcePixels->ReadPixel() == 0 ) ? nColor : 0;
838 pSource += mnBytesPerRow;
841 CGDataProviderRef xDataProvider( CGDataProviderCreateWithData(NULL, pMaskBuffer, nHeight * nDestBytesPerRow, &CFRTLFree) );
842 xMask = CGImageCreate(nWidth, nHeight, 8, 32, nDestBytesPerRow, GetSalData()->mxRGBSpace, kCGImageAlphaPremultipliedFirst, xDataProvider, NULL, true, kCGRenderingIntentDefault);
843 CFRelease(xDataProvider);
845 else
847 free(pMaskBuffer);
850 delete pSourcePixels;
852 return xMask;
855 // =======================================================================
857 /** AquaSalBitmap::GetSystemData Get platform native image data from existing image
859 * @param rData struct BitmapSystemData, defined in vcl/inc/bitmap.hxx
860 * @return true if successful
862 bool AquaSalBitmap::GetSystemData( BitmapSystemData& rData )
864 bool bRet = false;
866 if( !mxGraphicContext )
867 CreateContext();
869 if ( mxGraphicContext )
871 bRet = true;
873 #ifdef CAIRO
874 if ((CGBitmapContextGetBitsPerPixel(mxGraphicContext) == 32) &&
875 (CGBitmapContextGetBitmapInfo(mxGraphicContext) & kCGBitmapByteOrderMask) != kCGBitmapByteOrder32Host) {
877 * We need to hack things because VCL does not use kCGBitmapByteOrder32Host, while Cairo requires it.
879 OSL_TRACE("AquaSalBitmap::%s(): kCGBitmapByteOrder32Host not found => inserting it.",__func__);
881 CGImageRef xImage = CGBitmapContextCreateImage (mxGraphicContext);
883 // re-create the context with single change: include kCGBitmapByteOrder32Host flag.
884 CGContextRef mxGraphicContextNew = CGBitmapContextCreate( CGBitmapContextGetData(mxGraphicContext),
885 CGBitmapContextGetWidth(mxGraphicContext),
886 CGBitmapContextGetHeight(mxGraphicContext),
887 CGBitmapContextGetBitsPerComponent(mxGraphicContext),
888 CGBitmapContextGetBytesPerRow(mxGraphicContext),
889 CGBitmapContextGetColorSpace(mxGraphicContext),
890 CGBitmapContextGetBitmapInfo(mxGraphicContext) | kCGBitmapByteOrder32Host);
891 CFRelease(mxGraphicContext);
893 // Needs to be flipped
894 CGContextSaveGState( mxGraphicContextNew );
895 CGContextTranslateCTM (mxGraphicContextNew, 0, CGBitmapContextGetHeight(mxGraphicContextNew));
896 CGContextScaleCTM (mxGraphicContextNew, 1.0, -1.0);
898 CGContextDrawImage(mxGraphicContextNew, CGRectMake( 0, 0, CGImageGetWidth(xImage), CGImageGetHeight(xImage)), xImage);
900 // Flip back
901 CGContextRestoreGState( mxGraphicContextNew );
903 CGImageRelease( xImage );
904 mxGraphicContext = mxGraphicContextNew;
906 #endif
908 rData.rImageContext = (void *) mxGraphicContext;
909 rData.mnWidth = mnWidth;
910 rData.mnHeight = mnHeight;
913 return bRet;