xref: /aoo42x/main/vcl/aqua/source/gdi/salbmp.cxx (revision cd426cce)
19f62ea84SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
39f62ea84SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
49f62ea84SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
59f62ea84SAndrew Rist  * distributed with this work for additional information
69f62ea84SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
79f62ea84SAndrew Rist  * to you under the Apache License, Version 2.0 (the
89f62ea84SAndrew Rist  * "License"); you may not use this file except in compliance
99f62ea84SAndrew Rist  * with the License.  You may obtain a copy of the License at
109f62ea84SAndrew Rist  *
119f62ea84SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
129f62ea84SAndrew Rist  *
139f62ea84SAndrew Rist  * Unless required by applicable law or agreed to in writing,
149f62ea84SAndrew Rist  * software distributed under the License is distributed on an
159f62ea84SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
169f62ea84SAndrew Rist  * KIND, either express or implied.  See the License for the
179f62ea84SAndrew Rist  * specific language governing permissions and limitations
189f62ea84SAndrew Rist  * under the License.
199f62ea84SAndrew Rist  *
209f62ea84SAndrew Rist  *************************************************************/
219f62ea84SAndrew Rist 
229f62ea84SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_vcl.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include <boost/bind.hpp>
28cdf0e10cSrcweir 
29cdf0e10cSrcweir #include "basebmp/scanlineformats.hxx"
30cdf0e10cSrcweir #include "basebmp/color.hxx"
31cdf0e10cSrcweir 
32cdf0e10cSrcweir #include "basegfx/vector/b2ivector.hxx"
33cdf0e10cSrcweir 
34cdf0e10cSrcweir #include "tools/color.hxx"
35cdf0e10cSrcweir 
36cdf0e10cSrcweir #include "vcl/bitmap.hxx" // for BitmapSystemData
37cdf0e10cSrcweir #include "vcl/salbtype.hxx"
38cdf0e10cSrcweir 
39cdf0e10cSrcweir #include "aqua/salbmp.h"
40cdf0e10cSrcweir #include "aqua/salinst.h"
41cdf0e10cSrcweir 
42cdf0e10cSrcweir #include "bmpfast.hxx"
43cdf0e10cSrcweir 
44cdf0e10cSrcweir // =======================================================================
45cdf0e10cSrcweir 
46cdf0e10cSrcweir static bool isValidBitCount( sal_uInt16 nBitCount )
47cdf0e10cSrcweir {
48cdf0e10cSrcweir 	return (nBitCount == 1) || (nBitCount == 4) || (nBitCount == 8) || (nBitCount == 16) || (nBitCount == 24) || (nBitCount == 32);
49cdf0e10cSrcweir }
50cdf0e10cSrcweir 
51cdf0e10cSrcweir // =======================================================================
52cdf0e10cSrcweir 
53cdf0e10cSrcweir AquaSalBitmap::AquaSalBitmap()
54cdf0e10cSrcweir : mxGraphicContext( NULL )
55cdf0e10cSrcweir , mxCachedImage( NULL )
56cdf0e10cSrcweir , mnBits(0)
57cdf0e10cSrcweir , mnWidth(0)
58cdf0e10cSrcweir , mnHeight(0)
59cdf0e10cSrcweir , mnBytesPerRow(0)
60cdf0e10cSrcweir {
61cdf0e10cSrcweir }
62cdf0e10cSrcweir 
63cdf0e10cSrcweir // ------------------------------------------------------------------
64cdf0e10cSrcweir 
65cdf0e10cSrcweir AquaSalBitmap::~AquaSalBitmap()
66cdf0e10cSrcweir {
67cdf0e10cSrcweir 	Destroy();
68cdf0e10cSrcweir }
69cdf0e10cSrcweir 
70cdf0e10cSrcweir // ------------------------------------------------------------------
71cdf0e10cSrcweir 
72cdf0e10cSrcweir bool AquaSalBitmap::Create( CGLayerRef xLayer, int nBitmapBits,
73cdf0e10cSrcweir 	int nX, int nY, int nWidth, int nHeight, bool /*bMirrorVert*/ )
74cdf0e10cSrcweir {
75cdf0e10cSrcweir 	DBG_ASSERT( xLayer, "AquaSalBitmap::Create() from non-layered context" );
76cdf0e10cSrcweir 
77cdf0e10cSrcweir 	// sanitize input parameters
78cdf0e10cSrcweir 	if( nX < 0 )
79cdf0e10cSrcweir 		nWidth += nX, nX = 0;
80cdf0e10cSrcweir 	if( nY < 0 )
81cdf0e10cSrcweir 		nHeight += nY, nY = 0;
82cdf0e10cSrcweir 	const CGSize aLayerSize = CGLayerGetSize( xLayer );
83cdf0e10cSrcweir 	if( nWidth >= (int)aLayerSize.width - nX )
84cdf0e10cSrcweir 		nWidth = (int)aLayerSize.width - nX;
85cdf0e10cSrcweir 	if( nHeight >= (int)aLayerSize.height - nY )
86cdf0e10cSrcweir 		nHeight = (int)aLayerSize.height - nY;
87cdf0e10cSrcweir 	if( (nWidth < 0) || (nHeight < 0) )
88cdf0e10cSrcweir 		nWidth = nHeight = 0;
89cdf0e10cSrcweir 
90cdf0e10cSrcweir 	// initialize properties
91cdf0e10cSrcweir 	mnWidth  = nWidth;
92cdf0e10cSrcweir 	mnHeight = nHeight;
93cdf0e10cSrcweir 	mnBits   = nBitmapBits ? nBitmapBits : 32;
94cdf0e10cSrcweir 
95cdf0e10cSrcweir 	// initialize drawing context
96cdf0e10cSrcweir 	CreateContext();
97cdf0e10cSrcweir 
98cdf0e10cSrcweir 	// copy layer content into the bitmap buffer
99*cd426cceSHerbert Dürr 	const CGPoint aSrcPoint = CGPointMake( -nX, -nY);
100cdf0e10cSrcweir 	::CGContextDrawLayerAtPoint( mxGraphicContext, aSrcPoint, xLayer );
101cdf0e10cSrcweir 	return true;
102cdf0e10cSrcweir }
103cdf0e10cSrcweir 
104cdf0e10cSrcweir // ------------------------------------------------------------------
105cdf0e10cSrcweir 
106cdf0e10cSrcweir bool AquaSalBitmap::Create( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rBitmapPalette )
107cdf0e10cSrcweir {
108cdf0e10cSrcweir 	if( !isValidBitCount( nBits ) )
109cdf0e10cSrcweir 		return false;
110cdf0e10cSrcweir 	maPalette = rBitmapPalette;
111cdf0e10cSrcweir 	mnBits = nBits;
112cdf0e10cSrcweir     mnWidth = rSize.Width();
113cdf0e10cSrcweir 	mnHeight = rSize.Height();
114cdf0e10cSrcweir 	return AllocateUserData();
115cdf0e10cSrcweir }
116cdf0e10cSrcweir 
117cdf0e10cSrcweir // ------------------------------------------------------------------
118cdf0e10cSrcweir 
119cdf0e10cSrcweir bool AquaSalBitmap::Create( const SalBitmap& rSalBmp )
120cdf0e10cSrcweir {
121cdf0e10cSrcweir 	return Create( rSalBmp, rSalBmp.GetBitCount() );
122cdf0e10cSrcweir }
123cdf0e10cSrcweir 
124cdf0e10cSrcweir // ------------------------------------------------------------------
125cdf0e10cSrcweir 
126cdf0e10cSrcweir bool AquaSalBitmap::Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics )
127cdf0e10cSrcweir {
128cdf0e10cSrcweir 	return Create( rSalBmp, pGraphics ? pGraphics->GetBitCount() : rSalBmp.GetBitCount() );
129cdf0e10cSrcweir }
130cdf0e10cSrcweir 
131cdf0e10cSrcweir // ------------------------------------------------------------------
132cdf0e10cSrcweir 
133cdf0e10cSrcweir bool AquaSalBitmap::Create( const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount )
134cdf0e10cSrcweir {
135cdf0e10cSrcweir 	const AquaSalBitmap& rSourceBitmap = static_cast<const AquaSalBitmap&>(rSalBmp);
136cdf0e10cSrcweir 
137cdf0e10cSrcweir 	if( isValidBitCount( nNewBitCount ) && 	rSourceBitmap.maUserBuffer.get() )
138cdf0e10cSrcweir 	{
139cdf0e10cSrcweir 		mnBits = nNewBitCount;
140cdf0e10cSrcweir 		mnWidth = rSourceBitmap.mnWidth;
141cdf0e10cSrcweir 		mnHeight = rSourceBitmap.mnHeight;
142cdf0e10cSrcweir 		maPalette = rSourceBitmap.maPalette;
143cdf0e10cSrcweir 
144cdf0e10cSrcweir 		if( AllocateUserData() )
145cdf0e10cSrcweir 		{
146cdf0e10cSrcweir 			ConvertBitmapData( mnWidth, mnHeight, mnBits, mnBytesPerRow, maPalette, maUserBuffer.get(), rSourceBitmap.mnBits, rSourceBitmap.mnBytesPerRow, rSourceBitmap.maPalette, rSourceBitmap.maUserBuffer.get() );
147cdf0e10cSrcweir 			return true;
148cdf0e10cSrcweir 		}
149cdf0e10cSrcweir 	}
150cdf0e10cSrcweir 	return false;
151cdf0e10cSrcweir }
152cdf0e10cSrcweir 
153cdf0e10cSrcweir // ------------------------------------------------------------------
154cdf0e10cSrcweir 
155cdf0e10cSrcweir void AquaSalBitmap::Destroy()
156cdf0e10cSrcweir {
157cdf0e10cSrcweir 	DestroyContext();
158cdf0e10cSrcweir 	maUserBuffer.reset();
159cdf0e10cSrcweir }
160cdf0e10cSrcweir 
161cdf0e10cSrcweir // ------------------------------------------------------------------
162cdf0e10cSrcweir 
163cdf0e10cSrcweir void AquaSalBitmap::DestroyContext()
164cdf0e10cSrcweir {
165cdf0e10cSrcweir 	CGImageRelease( mxCachedImage );
166cdf0e10cSrcweir 	mxCachedImage = NULL;
167cdf0e10cSrcweir 
168cdf0e10cSrcweir 	if( mxGraphicContext )
169cdf0e10cSrcweir 	{
170cdf0e10cSrcweir 		CGContextRelease( mxGraphicContext );
171cdf0e10cSrcweir 		mxGraphicContext = NULL;
172cdf0e10cSrcweir 		maContextBuffer.reset();
173cdf0e10cSrcweir 	}
174cdf0e10cSrcweir }
175cdf0e10cSrcweir 
176cdf0e10cSrcweir // ------------------------------------------------------------------
177cdf0e10cSrcweir 
178cdf0e10cSrcweir bool AquaSalBitmap::CreateContext()
179cdf0e10cSrcweir {
180cdf0e10cSrcweir 	DestroyContext();
181cdf0e10cSrcweir 
182cdf0e10cSrcweir 	// prepare graphics context
183cdf0e10cSrcweir 	// convert image from user input if available
184cdf0e10cSrcweir 	const bool bSkipConversion = !maUserBuffer;
185cdf0e10cSrcweir 	if( bSkipConversion )
186cdf0e10cSrcweir 		AllocateUserData();
187cdf0e10cSrcweir 
188cdf0e10cSrcweir 	// default to RGBA color space
189cdf0e10cSrcweir 	CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
190cdf0e10cSrcweir     CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
191cdf0e10cSrcweir 
192cdf0e10cSrcweir     // convert data into something accepted by CGBitmapContextCreate()
193cdf0e10cSrcweir 	size_t bitsPerComponent = (mnBits == 16) ? 5 : 8;
194cdf0e10cSrcweir 	sal_uInt32 nContextBytesPerRow = mnBytesPerRow;
195cdf0e10cSrcweir 	if( (mnBits == 16) || (mnBits == 32) )
196cdf0e10cSrcweir 	{
197cdf0e10cSrcweir 		// no conversion needed for truecolor
198cdf0e10cSrcweir 		maContextBuffer = maUserBuffer;
199cdf0e10cSrcweir 	}
200cdf0e10cSrcweir 	else if( (mnBits == 8) && maPalette.IsGreyPalette() )
201cdf0e10cSrcweir 	{
202cdf0e10cSrcweir 		// no conversion needed for grayscale
203cdf0e10cSrcweir 		maContextBuffer = maUserBuffer;
204cdf0e10cSrcweir 		aCGColorSpace = GetSalData()->mxGraySpace;
205cdf0e10cSrcweir 		aCGBmpInfo = kCGImageAlphaNone;
206cdf0e10cSrcweir 		bitsPerComponent = mnBits;
207cdf0e10cSrcweir 	}
208cdf0e10cSrcweir 	// TODO: is special handling for 1bit input buffers worth it?
209cdf0e10cSrcweir 	else
210cdf0e10cSrcweir 	{
211cdf0e10cSrcweir 		// convert user data to 32 bit
212cdf0e10cSrcweir 		nContextBytesPerRow = mnWidth << 2;
213cdf0e10cSrcweir         try
214cdf0e10cSrcweir         {
215cdf0e10cSrcweir             maContextBuffer.reset( new sal_uInt8[ mnHeight * nContextBytesPerRow ] );
216cdf0e10cSrcweir 
217cdf0e10cSrcweir             if( !bSkipConversion )
218cdf0e10cSrcweir                 ConvertBitmapData( mnWidth, mnHeight,
219cdf0e10cSrcweir                                32, nContextBytesPerRow, maPalette, maContextBuffer.get(),
220cdf0e10cSrcweir                                mnBits, mnBytesPerRow, maPalette, maUserBuffer.get() );
221cdf0e10cSrcweir         }
222cdf0e10cSrcweir         catch( std::bad_alloc )
223cdf0e10cSrcweir         {
224cdf0e10cSrcweir             mxGraphicContext = 0;
225cdf0e10cSrcweir         }
226cdf0e10cSrcweir 	}
227cdf0e10cSrcweir 
228cdf0e10cSrcweir     if( maContextBuffer.get() )
229cdf0e10cSrcweir     {
230cdf0e10cSrcweir         mxGraphicContext = ::CGBitmapContextCreate( maContextBuffer.get(), mnWidth, mnHeight,
231cdf0e10cSrcweir             bitsPerComponent, nContextBytesPerRow, aCGColorSpace, aCGBmpInfo );
232cdf0e10cSrcweir     }
233cdf0e10cSrcweir 
234cdf0e10cSrcweir 	if( !mxGraphicContext )
235cdf0e10cSrcweir 		maContextBuffer.reset();
236cdf0e10cSrcweir 
237cdf0e10cSrcweir 	return mxGraphicContext != NULL;
238cdf0e10cSrcweir }
239cdf0e10cSrcweir 
240cdf0e10cSrcweir // ------------------------------------------------------------------
241cdf0e10cSrcweir 
242cdf0e10cSrcweir bool AquaSalBitmap::AllocateUserData()
243cdf0e10cSrcweir {
244cdf0e10cSrcweir 	Destroy();
245cdf0e10cSrcweir 
246cdf0e10cSrcweir 	if( mnWidth && mnHeight )
247cdf0e10cSrcweir 	{
248cdf0e10cSrcweir 		mnBytesPerRow =  0;
249cdf0e10cSrcweir 
250cdf0e10cSrcweir 		switch( mnBits )
251cdf0e10cSrcweir 		{
252cdf0e10cSrcweir 		case 1:		mnBytesPerRow = (mnWidth + 7) >> 3; break;
253cdf0e10cSrcweir 		case 4:		mnBytesPerRow = (mnWidth + 1) >> 1; break;
254cdf0e10cSrcweir 		case 8:		mnBytesPerRow = mnWidth; break;
255cdf0e10cSrcweir 		case 16:	mnBytesPerRow = mnWidth << 1; break;
256cdf0e10cSrcweir 		case 24:	mnBytesPerRow = (mnWidth << 1) + mnWidth; break;
257cdf0e10cSrcweir 		case 32:	mnBytesPerRow = mnWidth << 2; break;
258cdf0e10cSrcweir 		default:
259cdf0e10cSrcweir 			DBG_ERROR("vcl::AquaSalBitmap::AllocateUserData(), illegal bitcount!");
260cdf0e10cSrcweir 		}
261cdf0e10cSrcweir 	}
262cdf0e10cSrcweir 
263cdf0e10cSrcweir     try
264cdf0e10cSrcweir     {
265cdf0e10cSrcweir         if( mnBytesPerRow )
266cdf0e10cSrcweir             maUserBuffer.reset( new sal_uInt8[mnBytesPerRow * mnHeight] );
267cdf0e10cSrcweir     }
268cdf0e10cSrcweir     catch( const std::bad_alloc& )
269cdf0e10cSrcweir     {
270cdf0e10cSrcweir         DBG_ERROR( "vcl::AquaSalBitmap::AllocateUserData: bad alloc" );
271cdf0e10cSrcweir         maUserBuffer.reset( NULL );
272cdf0e10cSrcweir         mnBytesPerRow = 0;
273cdf0e10cSrcweir     }
274cdf0e10cSrcweir 
275cdf0e10cSrcweir 	return maUserBuffer.get() != 0;
276cdf0e10cSrcweir }
277cdf0e10cSrcweir 
278cdf0e10cSrcweir // ------------------------------------------------------------------
279cdf0e10cSrcweir 
280cdf0e10cSrcweir class ImplPixelFormat
281cdf0e10cSrcweir {
282cdf0e10cSrcweir protected:
283cdf0e10cSrcweir 	sal_uInt8* pData;
284cdf0e10cSrcweir public:
285cdf0e10cSrcweir 	static ImplPixelFormat* GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette );
286cdf0e10cSrcweir 
287cdf0e10cSrcweir 	virtual void StartLine( sal_uInt8* pLine ) { pData = pLine; }
288cdf0e10cSrcweir 	virtual void SkipPixel( sal_uInt32 nPixel ) = 0;
289cdf0e10cSrcweir 	virtual ColorData ReadPixel() = 0;
290cdf0e10cSrcweir 	virtual void WritePixel( ColorData nColor ) = 0;
291cdf0e10cSrcweir };
292cdf0e10cSrcweir 
293cdf0e10cSrcweir class ImplPixelFormat32 : public ImplPixelFormat
294cdf0e10cSrcweir // currently ARGB-format for 32bit depth
295cdf0e10cSrcweir {
296cdf0e10cSrcweir public:
297cdf0e10cSrcweir 	virtual void SkipPixel( sal_uInt32 nPixel )
298cdf0e10cSrcweir 	{
299cdf0e10cSrcweir 		pData += nPixel << 2;
300cdf0e10cSrcweir 	}
301cdf0e10cSrcweir 	virtual ColorData ReadPixel()
302cdf0e10cSrcweir 	{
303cdf0e10cSrcweir 		const ColorData c = RGB_COLORDATA( pData[1], pData[2], pData[3] );
304cdf0e10cSrcweir 		pData += 4;
305cdf0e10cSrcweir 		return c;
306cdf0e10cSrcweir 	}
307cdf0e10cSrcweir 	virtual void WritePixel( ColorData nColor )
308cdf0e10cSrcweir 	{
309cdf0e10cSrcweir 		*pData++ = 0;
310cdf0e10cSrcweir 		*pData++ = COLORDATA_RED( nColor );
311cdf0e10cSrcweir 		*pData++ = COLORDATA_GREEN( nColor );
312cdf0e10cSrcweir 		*pData++ = COLORDATA_BLUE( nColor );
313cdf0e10cSrcweir 	}
314cdf0e10cSrcweir };
315cdf0e10cSrcweir 
316cdf0e10cSrcweir class ImplPixelFormat24 : public ImplPixelFormat
317cdf0e10cSrcweir // currently BGR-format for 24bit depth
318cdf0e10cSrcweir {
319cdf0e10cSrcweir public:
320cdf0e10cSrcweir 	virtual void SkipPixel( sal_uInt32 nPixel )
321cdf0e10cSrcweir 	{
322cdf0e10cSrcweir 		pData += (nPixel << 1) + nPixel;
323cdf0e10cSrcweir 	}
324cdf0e10cSrcweir 	virtual ColorData ReadPixel()
325cdf0e10cSrcweir 	{
326cdf0e10cSrcweir 		const ColorData c = RGB_COLORDATA( pData[2], pData[1], pData[0] );
327cdf0e10cSrcweir 		pData += 3;
328cdf0e10cSrcweir 		return c;
329cdf0e10cSrcweir 	}
330cdf0e10cSrcweir 	virtual void WritePixel( ColorData nColor )
331cdf0e10cSrcweir 	{
332cdf0e10cSrcweir 		*pData++ = COLORDATA_BLUE( nColor );
333cdf0e10cSrcweir 		*pData++ = COLORDATA_GREEN( nColor );
334cdf0e10cSrcweir 		*pData++ = COLORDATA_RED( nColor );
335cdf0e10cSrcweir 	}
336cdf0e10cSrcweir };
337cdf0e10cSrcweir 
338cdf0e10cSrcweir class ImplPixelFormat16 : public ImplPixelFormat
339cdf0e10cSrcweir // currently R5G6B5-format for 16bit depth
340cdf0e10cSrcweir {
341cdf0e10cSrcweir protected:
342cdf0e10cSrcweir 	sal_uInt16* pData16;
343cdf0e10cSrcweir public:
344cdf0e10cSrcweir 
345cdf0e10cSrcweir 	virtual void StartLine( sal_uInt8* pLine )
346cdf0e10cSrcweir 	{
347cdf0e10cSrcweir 		pData16 = (sal_uInt16*)pLine;
348cdf0e10cSrcweir 	}
349cdf0e10cSrcweir 	virtual void SkipPixel( sal_uInt32 nPixel )
350cdf0e10cSrcweir 	{
351cdf0e10cSrcweir 		pData += nPixel;
352cdf0e10cSrcweir 	}
353cdf0e10cSrcweir 	virtual ColorData ReadPixel()
354cdf0e10cSrcweir 	{
355cdf0e10cSrcweir 		const ColorData c = RGB_COLORDATA( (*pData & 0x7c00) >> 7, (*pData & 0x03e0) >> 2 , (*pData & 0x001f) << 3 );
356cdf0e10cSrcweir 		pData++;
357cdf0e10cSrcweir 		return c;
358cdf0e10cSrcweir 	}
359cdf0e10cSrcweir 	virtual void WritePixel( ColorData nColor )
360cdf0e10cSrcweir 	{
361cdf0e10cSrcweir 		*pData++ =	((COLORDATA_RED( nColor ) & 0xf8 ) << 7 ) ||
362cdf0e10cSrcweir 					((COLORDATA_GREEN( nColor ) & 0xf8 ) << 2 ) ||
363cdf0e10cSrcweir 					((COLORDATA_BLUE( nColor ) & 0xf8 ) >> 3 );
364cdf0e10cSrcweir 	}
365cdf0e10cSrcweir };
366cdf0e10cSrcweir 
367cdf0e10cSrcweir class ImplPixelFormat8 : public ImplPixelFormat
368cdf0e10cSrcweir {
369cdf0e10cSrcweir private:
370cdf0e10cSrcweir 	const BitmapPalette& mrPalette;
371cdf0e10cSrcweir 
372cdf0e10cSrcweir public:
373cdf0e10cSrcweir 	ImplPixelFormat8( const BitmapPalette& rPalette )
374cdf0e10cSrcweir 	: mrPalette( rPalette )
375cdf0e10cSrcweir 	{
376cdf0e10cSrcweir 	}
377cdf0e10cSrcweir 	virtual void SkipPixel( sal_uInt32 nPixel )
378cdf0e10cSrcweir 	{
379cdf0e10cSrcweir 		pData += nPixel;
380cdf0e10cSrcweir 	}
381cdf0e10cSrcweir 	virtual ColorData ReadPixel()
382cdf0e10cSrcweir 	{
383cdf0e10cSrcweir 		return mrPalette[ *pData++ ].operator Color().GetColor();
384cdf0e10cSrcweir 	}
385cdf0e10cSrcweir 	virtual void WritePixel( ColorData nColor )
386cdf0e10cSrcweir 	{
387cdf0e10cSrcweir 		const BitmapColor aColor( COLORDATA_RED( nColor ), COLORDATA_GREEN( nColor ), COLORDATA_BLUE( nColor ) );
388cdf0e10cSrcweir 		*pData++ = static_cast< sal_uInt8 >( mrPalette.GetBestIndex( aColor ) );
389cdf0e10cSrcweir 	}
390cdf0e10cSrcweir };
391cdf0e10cSrcweir 
392cdf0e10cSrcweir class ImplPixelFormat4 : public ImplPixelFormat
393cdf0e10cSrcweir {
394cdf0e10cSrcweir private:
395cdf0e10cSrcweir 	const BitmapPalette& mrPalette;
396cdf0e10cSrcweir 	sal_uInt32 mnX;
397cdf0e10cSrcweir 	sal_uInt32 mnShift;
398cdf0e10cSrcweir 
399cdf0e10cSrcweir public:
400cdf0e10cSrcweir 	ImplPixelFormat4( const BitmapPalette& rPalette )
401cdf0e10cSrcweir 	: mrPalette( rPalette )
402cdf0e10cSrcweir 	{
403cdf0e10cSrcweir 	}
404cdf0e10cSrcweir 	virtual void SkipPixel( sal_uInt32 nPixel )
405cdf0e10cSrcweir 	{
406cdf0e10cSrcweir 		mnX += nPixel;
407cdf0e10cSrcweir 		if( (nPixel & 1) )
408cdf0e10cSrcweir 			mnShift ^= 4;
409cdf0e10cSrcweir 	}
410cdf0e10cSrcweir 	virtual void StartLine( sal_uInt8* pLine )
411cdf0e10cSrcweir 	{
412cdf0e10cSrcweir 		pData = pLine;
413cdf0e10cSrcweir 		mnX = 0;
414cdf0e10cSrcweir 		mnShift = 4;
415cdf0e10cSrcweir 	}
416cdf0e10cSrcweir 	virtual ColorData ReadPixel()
417cdf0e10cSrcweir 	{
418cdf0e10cSrcweir 		const BitmapColor& rColor = mrPalette[( pData[mnX >> 1] >> mnShift) & 0x0f];
419cdf0e10cSrcweir 		mnX++;
420cdf0e10cSrcweir 		mnShift ^= 4;
421cdf0e10cSrcweir 		return rColor.operator Color().GetColor();
422cdf0e10cSrcweir 	}
423cdf0e10cSrcweir 	virtual void WritePixel( ColorData nColor )
424cdf0e10cSrcweir 	{
425cdf0e10cSrcweir 		const BitmapColor aColor( COLORDATA_RED( nColor ), COLORDATA_GREEN( nColor ), COLORDATA_BLUE( nColor ) );
426cdf0e10cSrcweir 		pData[mnX>>1] &= (0xf0 >> mnShift);
427cdf0e10cSrcweir 		pData[mnX>>1] |= (static_cast< sal_uInt8 >( mrPalette.GetBestIndex( aColor ) ) & 0x0f);
428cdf0e10cSrcweir 		mnX++;
429cdf0e10cSrcweir 		mnShift ^= 4;
430cdf0e10cSrcweir 	}
431cdf0e10cSrcweir };
432cdf0e10cSrcweir 
433cdf0e10cSrcweir class ImplPixelFormat1 : public ImplPixelFormat
434cdf0e10cSrcweir {
435cdf0e10cSrcweir private:
436cdf0e10cSrcweir 	const BitmapPalette& mrPalette;
437cdf0e10cSrcweir 	sal_uInt32 mnX;
438cdf0e10cSrcweir 
439cdf0e10cSrcweir public:
440cdf0e10cSrcweir 	ImplPixelFormat1( const BitmapPalette& rPalette )
441cdf0e10cSrcweir 	: mrPalette( rPalette )
442cdf0e10cSrcweir 	{
443cdf0e10cSrcweir 	}
444cdf0e10cSrcweir 	virtual void SkipPixel( sal_uInt32 nPixel )
445cdf0e10cSrcweir 	{
446cdf0e10cSrcweir 		mnX += nPixel;
447cdf0e10cSrcweir 	}
448cdf0e10cSrcweir 	virtual void StartLine( sal_uInt8* pLine )
449cdf0e10cSrcweir 	{
450cdf0e10cSrcweir 		pData = pLine;
451cdf0e10cSrcweir 		mnX = 0;
452cdf0e10cSrcweir 	}
453cdf0e10cSrcweir 	virtual ColorData ReadPixel()
454cdf0e10cSrcweir 	{
455cdf0e10cSrcweir 		const BitmapColor& rColor = mrPalette[ (pData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1];
456cdf0e10cSrcweir 		mnX++;
457cdf0e10cSrcweir 		return rColor.operator Color().GetColor();
458cdf0e10cSrcweir 	}
459cdf0e10cSrcweir 	virtual void WritePixel( ColorData nColor )
460cdf0e10cSrcweir 	{
461cdf0e10cSrcweir 		const BitmapColor aColor( COLORDATA_RED( nColor ), COLORDATA_GREEN( nColor ), COLORDATA_BLUE( nColor ) );
462cdf0e10cSrcweir 		if( mrPalette.GetBestIndex( aColor ) & 1 )
463cdf0e10cSrcweir 			pData[ mnX >> 3 ] |= 1 << ( 7 - ( mnX & 7 ) );
464cdf0e10cSrcweir 		else
465cdf0e10cSrcweir 			pData[ mnX >> 3 ] &= ~( 1 << ( 7 - ( mnX & 7 ) ) );
466cdf0e10cSrcweir 		mnX++;
467cdf0e10cSrcweir 	}
468cdf0e10cSrcweir };
469cdf0e10cSrcweir 
470cdf0e10cSrcweir ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette )
471cdf0e10cSrcweir {
472cdf0e10cSrcweir 	switch( nBits )
473cdf0e10cSrcweir 	{
474cdf0e10cSrcweir 	case 1: return new ImplPixelFormat1( rPalette );
475cdf0e10cSrcweir 	case 4: return new ImplPixelFormat4( rPalette );
476cdf0e10cSrcweir 	case 8: return new ImplPixelFormat8( rPalette );
477cdf0e10cSrcweir 	case 16: return new ImplPixelFormat16;
478cdf0e10cSrcweir 	case 24: return new ImplPixelFormat24;
479cdf0e10cSrcweir 	case 32: return new ImplPixelFormat32;
480cdf0e10cSrcweir 	}
481cdf0e10cSrcweir 
482cdf0e10cSrcweir 	return 0;
483cdf0e10cSrcweir }
484cdf0e10cSrcweir 
485cdf0e10cSrcweir void AquaSalBitmap::ConvertBitmapData( sal_uInt32 nWidth, sal_uInt32 nHeight,
486cdf0e10cSrcweir 									   sal_uInt16 nDestBits, sal_uInt32 nDestBytesPerRow, const BitmapPalette& rDestPalette, sal_uInt8* pDestData,
487cdf0e10cSrcweir 									   sal_uInt16 nSrcBits, sal_uInt32 nSrcBytesPerRow, const BitmapPalette& rSrcPalette, sal_uInt8* pSrcData )
488cdf0e10cSrcweir 
489cdf0e10cSrcweir {
490cdf0e10cSrcweir 	if( (nDestBytesPerRow == nSrcBytesPerRow) && (nDestBits == nSrcBits) && ((nSrcBits != 8) || (rDestPalette.operator==( rSrcPalette ))) )
491cdf0e10cSrcweir 	{
492cdf0e10cSrcweir 		// simple case, same format, so just copy
493cdf0e10cSrcweir 		memcpy( pDestData, pSrcData, nHeight * nDestBytesPerRow );
494cdf0e10cSrcweir 		return;
495cdf0e10cSrcweir 	}
496cdf0e10cSrcweir 
497cdf0e10cSrcweir 	// try accelerated conversion if possible
498cdf0e10cSrcweir 	// TODO: are other truecolor conversions except BGR->ARGB worth it?
499cdf0e10cSrcweir 	bool bConverted = false;
500cdf0e10cSrcweir 	if( (nSrcBits == 24) && (nDestBits == 32) )
501cdf0e10cSrcweir 	{
502cdf0e10cSrcweir 		// TODO: extend bmpfast.cxx with a method that can be directly used here
503cdf0e10cSrcweir 		BitmapBuffer aSrcBuf;
504cdf0e10cSrcweir 		aSrcBuf.mnFormat = BMP_FORMAT_24BIT_TC_BGR;
505cdf0e10cSrcweir 		aSrcBuf.mpBits = pSrcData;
506cdf0e10cSrcweir 		aSrcBuf.mnBitCount = nSrcBits;
507cdf0e10cSrcweir 		aSrcBuf.mnScanlineSize = nSrcBytesPerRow;
508cdf0e10cSrcweir 		BitmapBuffer aDstBuf;
509cdf0e10cSrcweir 		aDstBuf.mnFormat = BMP_FORMAT_32BIT_TC_ARGB;
510cdf0e10cSrcweir 		aDstBuf.mpBits = pDestData;
511cdf0e10cSrcweir 		aSrcBuf.mnBitCount = nDestBits;
512cdf0e10cSrcweir 		aDstBuf.mnScanlineSize = nDestBytesPerRow;
513cdf0e10cSrcweir 
514cdf0e10cSrcweir 		aSrcBuf.mnWidth = aDstBuf.mnWidth = nWidth;
515cdf0e10cSrcweir 		aSrcBuf.mnHeight = aDstBuf.mnHeight = nHeight;
516cdf0e10cSrcweir 
517cdf0e10cSrcweir 		SalTwoRect aTwoRects;
518cdf0e10cSrcweir 		aTwoRects.mnSrcX = aTwoRects.mnDestX = 0;
519cdf0e10cSrcweir 		aTwoRects.mnSrcY = aTwoRects.mnDestY = 0;
520cdf0e10cSrcweir 		aTwoRects.mnSrcWidth = aTwoRects.mnDestWidth = mnWidth;
521cdf0e10cSrcweir 		aTwoRects.mnSrcHeight = aTwoRects.mnDestHeight = mnHeight;
522cdf0e10cSrcweir 		bConverted = ::ImplFastBitmapConversion( aDstBuf, aSrcBuf, aTwoRects );
523cdf0e10cSrcweir 	}
524cdf0e10cSrcweir 
525cdf0e10cSrcweir 	if( !bConverted )
526cdf0e10cSrcweir 	{
527cdf0e10cSrcweir 		// TODO: this implementation is for clarety, not for speed
528cdf0e10cSrcweir 
529cdf0e10cSrcweir 		ImplPixelFormat* pD = ImplPixelFormat::GetFormat( nDestBits, rDestPalette );
530cdf0e10cSrcweir 		ImplPixelFormat* pS = ImplPixelFormat::GetFormat( nSrcBits, rSrcPalette );
531cdf0e10cSrcweir 
532cdf0e10cSrcweir 		if( pD && pS )
533cdf0e10cSrcweir 		{
534cdf0e10cSrcweir 			sal_uInt32 nY = nHeight;
535cdf0e10cSrcweir 			while( nY-- )
536cdf0e10cSrcweir 			{
537cdf0e10cSrcweir 				pD->StartLine( pDestData );
538cdf0e10cSrcweir 				pS->StartLine( pSrcData );
539cdf0e10cSrcweir 
540cdf0e10cSrcweir 				sal_uInt32 nX = nWidth;
541cdf0e10cSrcweir 				while( nX-- )
542cdf0e10cSrcweir 					pD->WritePixel( pS->ReadPixel() );
543cdf0e10cSrcweir 
544cdf0e10cSrcweir 				pSrcData += nSrcBytesPerRow;
545cdf0e10cSrcweir 				pDestData += nDestBytesPerRow;
546cdf0e10cSrcweir 			}
547cdf0e10cSrcweir 		}
548cdf0e10cSrcweir 		delete pS;
549cdf0e10cSrcweir 		delete pD;
550cdf0e10cSrcweir 	}
551cdf0e10cSrcweir }
552cdf0e10cSrcweir 
553cdf0e10cSrcweir // ------------------------------------------------------------------
554cdf0e10cSrcweir 
555cdf0e10cSrcweir Size AquaSalBitmap::GetSize() const
556cdf0e10cSrcweir {
557cdf0e10cSrcweir 	return Size( mnWidth, mnHeight );
558cdf0e10cSrcweir }
559cdf0e10cSrcweir 
560cdf0e10cSrcweir // ------------------------------------------------------------------
561cdf0e10cSrcweir 
562cdf0e10cSrcweir sal_uInt16 AquaSalBitmap::GetBitCount() const
563cdf0e10cSrcweir {
564cdf0e10cSrcweir 	return mnBits;
565cdf0e10cSrcweir }
566cdf0e10cSrcweir 
567cdf0e10cSrcweir // ------------------------------------------------------------------
568cdf0e10cSrcweir 
569cdf0e10cSrcweir static struct pal_entry
570cdf0e10cSrcweir {
571cdf0e10cSrcweir     sal_uInt8 mnRed;
572cdf0e10cSrcweir     sal_uInt8 mnGreen;
573cdf0e10cSrcweir     sal_uInt8 mnBlue;
574cdf0e10cSrcweir }
575cdf0e10cSrcweir const aImplSalSysPalEntryAry[ 16 ] =
576cdf0e10cSrcweir {
577cdf0e10cSrcweir {	 0,    0,	 0 },
578cdf0e10cSrcweir {	 0,    0, 0x80 },
579cdf0e10cSrcweir {	 0, 0x80,	 0 },
580cdf0e10cSrcweir {	 0, 0x80, 0x80 },
581cdf0e10cSrcweir { 0x80,    0,	 0 },
582cdf0e10cSrcweir { 0x80,    0, 0x80 },
583cdf0e10cSrcweir { 0x80, 0x80,	 0 },
584cdf0e10cSrcweir { 0x80, 0x80, 0x80 },
585cdf0e10cSrcweir { 0xC0, 0xC0, 0xC0 },
586cdf0e10cSrcweir {	 0,    0, 0xFF },
587cdf0e10cSrcweir {	 0, 0xFF,	 0 },
588cdf0e10cSrcweir {	 0, 0xFF, 0xFF },
589cdf0e10cSrcweir { 0xFF,    0,	 0 },
590cdf0e10cSrcweir { 0xFF,    0, 0xFF },
591cdf0e10cSrcweir { 0xFF, 0xFF,	 0 },
592cdf0e10cSrcweir { 0xFF, 0xFF, 0xFF }
593cdf0e10cSrcweir };
594cdf0e10cSrcweir 
595cdf0e10cSrcweir const BitmapPalette& GetDefaultPalette( int mnBits, bool bMonochrome )
596cdf0e10cSrcweir {
597cdf0e10cSrcweir 	if( bMonochrome )
598cdf0e10cSrcweir 		return Bitmap::GetGreyPalette( 1U << mnBits );
599cdf0e10cSrcweir 
600cdf0e10cSrcweir 	// at this point we should provide some kind of default palette
601cdf0e10cSrcweir 	// since all other platforms do so, too.
602cdf0e10cSrcweir 	static bool bDefPalInit = false;
603cdf0e10cSrcweir 	static BitmapPalette aDefPalette256;
604cdf0e10cSrcweir 	static BitmapPalette aDefPalette16;
605cdf0e10cSrcweir 	static BitmapPalette aDefPalette2;
606cdf0e10cSrcweir 	if( ! bDefPalInit )
607cdf0e10cSrcweir 	{
608cdf0e10cSrcweir 		bDefPalInit = true;
609cdf0e10cSrcweir 		aDefPalette256.SetEntryCount( 256 );
610cdf0e10cSrcweir 		aDefPalette16.SetEntryCount( 16 );
611cdf0e10cSrcweir 		aDefPalette2.SetEntryCount( 2 );
612cdf0e10cSrcweir 
613cdf0e10cSrcweir 		// Standard colors
614cdf0e10cSrcweir 		unsigned int i;
615cdf0e10cSrcweir 		for( i = 0; i < 16; i++ )
616cdf0e10cSrcweir 		{
617cdf0e10cSrcweir 			aDefPalette16[i] =
618cdf0e10cSrcweir 			aDefPalette256[i] = BitmapColor( aImplSalSysPalEntryAry[i].mnRed,
619cdf0e10cSrcweir 			                                 aImplSalSysPalEntryAry[i].mnGreen,
620cdf0e10cSrcweir 			                                 aImplSalSysPalEntryAry[i].mnBlue );
621cdf0e10cSrcweir 	        }
622cdf0e10cSrcweir 
623cdf0e10cSrcweir 		aDefPalette2[0] = BitmapColor( 0, 0, 0 );
624cdf0e10cSrcweir 		aDefPalette2[1] = BitmapColor( 0xff, 0xff, 0xff );
625cdf0e10cSrcweir 
626cdf0e10cSrcweir 		// own palette (6/6/6)
627cdf0e10cSrcweir 		const int DITHER_PAL_STEPS = 6;
628cdf0e10cSrcweir 		const sal_uInt8 DITHER_PAL_DELTA = 51;
629cdf0e10cSrcweir 		int nB, nG, nR;
630cdf0e10cSrcweir 		sal_uInt8 nRed, nGreen, nBlue;
631cdf0e10cSrcweir 		for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
632cdf0e10cSrcweir 		{
633cdf0e10cSrcweir 			for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
634cdf0e10cSrcweir 			{
635cdf0e10cSrcweir 				for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
636cdf0e10cSrcweir 				{
637cdf0e10cSrcweir 					aDefPalette256[ i ] = BitmapColor( nRed, nGreen, nBlue );
638cdf0e10cSrcweir 					i++;
639cdf0e10cSrcweir 				}
640cdf0e10cSrcweir 			}
641cdf0e10cSrcweir 		}
642cdf0e10cSrcweir 	}
643cdf0e10cSrcweir 
644cdf0e10cSrcweir 	// now fill in appropriate palette
645cdf0e10cSrcweir 	switch( mnBits )
646cdf0e10cSrcweir 	{
647cdf0e10cSrcweir 	case 1: return aDefPalette2;
648cdf0e10cSrcweir 	case 4: return aDefPalette16;
649cdf0e10cSrcweir 	case 8: return aDefPalette256;
650cdf0e10cSrcweir 	default: break;
651cdf0e10cSrcweir 	}
652cdf0e10cSrcweir 
653cdf0e10cSrcweir 	const static BitmapPalette aEmptyPalette;
654cdf0e10cSrcweir 	return aEmptyPalette;
655cdf0e10cSrcweir }
656cdf0e10cSrcweir 
657cdf0e10cSrcweir BitmapBuffer* AquaSalBitmap::AcquireBuffer( bool /*bReadOnly*/ )
658cdf0e10cSrcweir {
659cdf0e10cSrcweir 	if( !maUserBuffer.get() )
660cdf0e10cSrcweir //	|| maContextBuffer.get() && (maUserBuffer.get() != maContextBuffer.get()) )
661cdf0e10cSrcweir 	{
662cdf0e10cSrcweir 		fprintf(stderr,"ASB::Acq(%dx%d,d=%d)\n",mnWidth,mnHeight,mnBits);
663cdf0e10cSrcweir 		// TODO: AllocateUserData();
664cdf0e10cSrcweir 		return NULL;
665cdf0e10cSrcweir 	}
666cdf0e10cSrcweir 
667cdf0e10cSrcweir 	BitmapBuffer* pBuffer = new BitmapBuffer;
668cdf0e10cSrcweir 	pBuffer->mnWidth = mnWidth;
669cdf0e10cSrcweir 	pBuffer->mnHeight = mnHeight;
670cdf0e10cSrcweir 	pBuffer->maPalette = maPalette;
671cdf0e10cSrcweir 	pBuffer->mnScanlineSize = mnBytesPerRow;
672cdf0e10cSrcweir 	pBuffer->mpBits = maUserBuffer.get();
673cdf0e10cSrcweir 	pBuffer->mnBitCount = mnBits;
674cdf0e10cSrcweir 	switch( mnBits )
675cdf0e10cSrcweir 	{
676cdf0e10cSrcweir 	case 1:		pBuffer->mnFormat = BMP_FORMAT_1BIT_MSB_PAL; break;
677cdf0e10cSrcweir 	case 4:		pBuffer->mnFormat = BMP_FORMAT_4BIT_MSN_PAL; break;
678cdf0e10cSrcweir 	case 8:		pBuffer->mnFormat = BMP_FORMAT_8BIT_PAL; break;
679cdf0e10cSrcweir 	case 16:	pBuffer->mnFormat = BMP_FORMAT_16BIT_TC_MSB_MASK;
680cdf0e10cSrcweir 				pBuffer->maColorMask  = ColorMask( k16BitRedColorMask, k16BitGreenColorMask, k16BitBlueColorMask );
681cdf0e10cSrcweir 				break;
682cdf0e10cSrcweir 	case 24:	pBuffer->mnFormat = BMP_FORMAT_24BIT_TC_BGR; break;
683cdf0e10cSrcweir 	case 32:	pBuffer->mnFormat = BMP_FORMAT_32BIT_TC_ARGB;
684cdf0e10cSrcweir 				pBuffer->maColorMask  = ColorMask( k32BitRedColorMask, k32BitGreenColorMask, k32BitBlueColorMask );
685cdf0e10cSrcweir 				break;
686cdf0e10cSrcweir 	}
687cdf0e10cSrcweir 	pBuffer->mnFormat |= BMP_FORMAT_BOTTOM_UP;
688cdf0e10cSrcweir 
689cdf0e10cSrcweir 	// some BitmapBuffer users depend on a complete palette
690cdf0e10cSrcweir     if( (mnBits <= 8) && !maPalette )
691cdf0e10cSrcweir 		pBuffer->maPalette = GetDefaultPalette( mnBits, true );
692cdf0e10cSrcweir 
693cdf0e10cSrcweir 	return pBuffer;
694cdf0e10cSrcweir }
695cdf0e10cSrcweir 
696cdf0e10cSrcweir // ------------------------------------------------------------------
697cdf0e10cSrcweir 
698cdf0e10cSrcweir void AquaSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
699cdf0e10cSrcweir {
700cdf0e10cSrcweir 	// invalidate graphic context if we have different data
701cdf0e10cSrcweir 	if( !bReadOnly )
702cdf0e10cSrcweir 	{
703cdf0e10cSrcweir 		maPalette = pBuffer->maPalette;
704cdf0e10cSrcweir 		if( mxGraphicContext )
705cdf0e10cSrcweir 			DestroyContext();
706cdf0e10cSrcweir 	}
707cdf0e10cSrcweir 
708cdf0e10cSrcweir 	delete pBuffer;
709cdf0e10cSrcweir }
710cdf0e10cSrcweir 
711cdf0e10cSrcweir // ------------------------------------------------------------------
712cdf0e10cSrcweir 
713cdf0e10cSrcweir CGImageRef AquaSalBitmap::CreateCroppedImage( int nX, int nY, int nNewWidth, int nNewHeight ) const
714cdf0e10cSrcweir {
715cdf0e10cSrcweir 	if( !mxCachedImage )
716cdf0e10cSrcweir 	{
717cdf0e10cSrcweir 		if( !mxGraphicContext )
718cdf0e10cSrcweir 			if( !const_cast<AquaSalBitmap*>(this)->CreateContext() )
719cdf0e10cSrcweir 				return NULL;
720cdf0e10cSrcweir 
721cdf0e10cSrcweir 		mxCachedImage = CGBitmapContextCreateImage( mxGraphicContext );
722cdf0e10cSrcweir 	}
723cdf0e10cSrcweir 
724cdf0e10cSrcweir 	CGImageRef xCroppedImage = NULL;
725cdf0e10cSrcweir     // short circuit if there is nothing to crop
726cdf0e10cSrcweir 	if( !nX && !nY && (mnWidth == nNewWidth) && (mnHeight == nNewHeight) )
727cdf0e10cSrcweir 	{
728cdf0e10cSrcweir 		  xCroppedImage = mxCachedImage;
729cdf0e10cSrcweir 		  CFRetain( xCroppedImage );
730cdf0e10cSrcweir 	}
731cdf0e10cSrcweir 	else
732cdf0e10cSrcweir 	{
733cdf0e10cSrcweir 		nY = mnHeight - (nY + nNewHeight); // adjust for y-mirrored context
734*cd426cceSHerbert Dürr 		const CGRect aCropRect = CGRectMake( nX, nY, nNewWidth, nNewHeight);
735cdf0e10cSrcweir 		xCroppedImage = CGImageCreateWithImageInRect( mxCachedImage, aCropRect );
736cdf0e10cSrcweir 	}
737cdf0e10cSrcweir 
738cdf0e10cSrcweir 	return xCroppedImage;
739cdf0e10cSrcweir }
740cdf0e10cSrcweir 
741cdf0e10cSrcweir // ------------------------------------------------------------------
742cdf0e10cSrcweir 
743cdf0e10cSrcweir static void CFRTLFree(void* /*info*/, const void* data, size_t /*size*/)
744cdf0e10cSrcweir {
745cdf0e10cSrcweir     rtl_freeMemory( const_cast<void*>(data) );
746cdf0e10cSrcweir }
747cdf0e10cSrcweir 
748cdf0e10cSrcweir CGImageRef AquaSalBitmap::CreateWithMask( const AquaSalBitmap& rMask,
749cdf0e10cSrcweir 	int nX, int nY, int nWidth, int nHeight ) const
750cdf0e10cSrcweir {
751cdf0e10cSrcweir     CGImageRef xImage( CreateCroppedImage( nX, nY, nWidth, nHeight ) );
752cdf0e10cSrcweir     if( !xImage )
753cdf0e10cSrcweir     	return NULL;
754cdf0e10cSrcweir 
755cdf0e10cSrcweir 	CGImageRef xMask = rMask.CreateCroppedImage( nX, nY, nWidth, nHeight );
756cdf0e10cSrcweir 	if( !xMask )
757cdf0e10cSrcweir 		return xImage;
758cdf0e10cSrcweir 
759cdf0e10cSrcweir 	// CGImageCreateWithMask() only likes masks or greyscale images => convert if needed
760cdf0e10cSrcweir 	// TODO: isolate in an extra method?
761cdf0e10cSrcweir 	if( !CGImageIsMask(xMask) || (CGImageGetColorSpace(xMask) != GetSalData()->mxGraySpace) )
762cdf0e10cSrcweir 	{
763cdf0e10cSrcweir 	    const CGRect xImageRect=CGRectMake( 0, 0, nWidth, nHeight );//the rect has no offset
764cdf0e10cSrcweir 
765cdf0e10cSrcweir 	    // create the alpha mask image fitting our image
766cdf0e10cSrcweir 	    // TODO: is caching the full mask or the subimage mask worth it?
767cdf0e10cSrcweir 	    int nMaskBytesPerRow = ((nWidth + 3) & ~3);
768cdf0e10cSrcweir 	    void* pMaskMem = rtl_allocateMemory( nMaskBytesPerRow * nHeight );
769cdf0e10cSrcweir 	    CGContextRef xMaskContext = CGBitmapContextCreate( pMaskMem,
770cdf0e10cSrcweir 	    	nWidth, nHeight, 8, nMaskBytesPerRow, GetSalData()->mxGraySpace, kCGImageAlphaNone );
771cdf0e10cSrcweir 	    CGContextDrawImage( xMaskContext, xImageRect, xMask );
772cdf0e10cSrcweir 	    CFRelease( xMask );
773cdf0e10cSrcweir 		CGDataProviderRef xDataProvider( CGDataProviderCreateWithData( NULL,
774cdf0e10cSrcweir 		pMaskMem, nHeight * nMaskBytesPerRow, &CFRTLFree ) );
775cdf0e10cSrcweir 		static const float* pDecode = NULL;
776cdf0e10cSrcweir 		xMask = CGImageMaskCreate( nWidth, nHeight, 8, 8, nMaskBytesPerRow, xDataProvider, pDecode, false );
777cdf0e10cSrcweir 		CFRelease( xDataProvider );
778cdf0e10cSrcweir 		CFRelease( xMaskContext );
779cdf0e10cSrcweir 	}
780cdf0e10cSrcweir 
781cdf0e10cSrcweir 	if( !xMask )
782cdf0e10cSrcweir 		return xImage;
783cdf0e10cSrcweir 
784cdf0e10cSrcweir     // combine image and alpha mask
785cdf0e10cSrcweir     CGImageRef xMaskedImage = CGImageCreateWithMask( xImage, xMask );
786cdf0e10cSrcweir     CFRelease( xMask );
787cdf0e10cSrcweir 	CFRelease( xImage );
788cdf0e10cSrcweir     return xMaskedImage;
789cdf0e10cSrcweir }
790cdf0e10cSrcweir 
791cdf0e10cSrcweir // ------------------------------------------------------------------
792cdf0e10cSrcweir 
793cdf0e10cSrcweir /** creates an image from the given rectangle, replacing all black pixels with nMaskColor and make all other full transparent */
794cdf0e10cSrcweir CGImageRef AquaSalBitmap::CreateColorMask( int nX, int nY, int nWidth, int nHeight, SalColor nMaskColor ) const
795cdf0e10cSrcweir {
796cdf0e10cSrcweir 	CGImageRef xMask = 0;
797cdf0e10cSrcweir 	if( maUserBuffer.get() && (nX + nWidth <= mnWidth) && (nY + nHeight <= mnHeight) )
798cdf0e10cSrcweir 	{
799cdf0e10cSrcweir 		const sal_uInt32 nDestBytesPerRow = nWidth << 2;
800cdf0e10cSrcweir 		sal_uInt32* pMaskBuffer = static_cast<sal_uInt32*>( rtl_allocateMemory( nHeight * nDestBytesPerRow ) );
801cdf0e10cSrcweir 		sal_uInt32* pDest = pMaskBuffer;
802cdf0e10cSrcweir 
803cdf0e10cSrcweir 		ImplPixelFormat* pSourcePixels = ImplPixelFormat::GetFormat( mnBits, maPalette );
804cdf0e10cSrcweir 
805cdf0e10cSrcweir 		if( pMaskBuffer && pSourcePixels )
806cdf0e10cSrcweir 		{
807cdf0e10cSrcweir 			sal_uInt32 nColor;
808cdf0e10cSrcweir 			reinterpret_cast<sal_uInt8*>(&nColor)[0] = 0xff;
809cdf0e10cSrcweir 			reinterpret_cast<sal_uInt8*>(&nColor)[1] = SALCOLOR_RED( nMaskColor );
810cdf0e10cSrcweir 			reinterpret_cast<sal_uInt8*>(&nColor)[2] = SALCOLOR_GREEN( nMaskColor );
811cdf0e10cSrcweir 			reinterpret_cast<sal_uInt8*>(&nColor)[3] = SALCOLOR_BLUE( nMaskColor );
812cdf0e10cSrcweir 
813cdf0e10cSrcweir 			sal_uInt8* pSource = maUserBuffer.get();
814cdf0e10cSrcweir 			if( nY )
815cdf0e10cSrcweir 				pSource += nY * mnBytesPerRow;
816cdf0e10cSrcweir 
817cdf0e10cSrcweir 			int y = nHeight;
818cdf0e10cSrcweir 			while( y-- )
819cdf0e10cSrcweir 			{
820cdf0e10cSrcweir 				pSourcePixels->StartLine( pSource );
821cdf0e10cSrcweir 				pSourcePixels->SkipPixel(nX);
822cdf0e10cSrcweir 				sal_uInt32 x = nWidth;
823cdf0e10cSrcweir 				while( x-- )
824cdf0e10cSrcweir 				{
825cdf0e10cSrcweir 					*pDest++ = ( pSourcePixels->ReadPixel() == 0 ) ? nColor : 0;
826cdf0e10cSrcweir 				}
827cdf0e10cSrcweir 				pSource += mnBytesPerRow;
828cdf0e10cSrcweir 			}
829cdf0e10cSrcweir 
830cdf0e10cSrcweir 			CGDataProviderRef xDataProvider( CGDataProviderCreateWithData(NULL, pMaskBuffer, nHeight * nDestBytesPerRow, &CFRTLFree) );
831cdf0e10cSrcweir 			xMask = CGImageCreate(nWidth, nHeight, 8, 32, nDestBytesPerRow, GetSalData()->mxRGBSpace, kCGImageAlphaPremultipliedFirst, xDataProvider, NULL, true, kCGRenderingIntentDefault);
832cdf0e10cSrcweir 			CFRelease(xDataProvider);
833cdf0e10cSrcweir 		}
834cdf0e10cSrcweir         else
835cdf0e10cSrcweir         {
836cdf0e10cSrcweir             free(pMaskBuffer);
837cdf0e10cSrcweir         }
838cdf0e10cSrcweir 
839cdf0e10cSrcweir 		delete pSourcePixels;
840cdf0e10cSrcweir 	}
841cdf0e10cSrcweir 	return xMask;
842cdf0e10cSrcweir }
843cdf0e10cSrcweir 
844cdf0e10cSrcweir // =======================================================================
845cdf0e10cSrcweir 
846cdf0e10cSrcweir /** AquaSalBitmap::GetSystemData Get platform native image data from existing image
847cdf0e10cSrcweir  *
848cdf0e10cSrcweir  *  @param rData struct BitmapSystemData, defined in vcl/inc/bitmap.hxx
849cdf0e10cSrcweir  *  @return true if successful
850cdf0e10cSrcweir **/
851cdf0e10cSrcweir bool AquaSalBitmap::GetSystemData( BitmapSystemData& rData )
852cdf0e10cSrcweir {
853cdf0e10cSrcweir     bool bRet = false;
854cdf0e10cSrcweir 
855cdf0e10cSrcweir     if( !mxGraphicContext )
856cdf0e10cSrcweir         CreateContext();
857cdf0e10cSrcweir 
858cdf0e10cSrcweir     if ( mxGraphicContext )
859cdf0e10cSrcweir     {
860cdf0e10cSrcweir         bRet = true;
861cdf0e10cSrcweir 
862cdf0e10cSrcweir #ifdef CAIRO
863cdf0e10cSrcweir         if ((CGBitmapContextGetBitsPerPixel(mxGraphicContext) == 32) &&
864cdf0e10cSrcweir             (CGBitmapContextGetBitmapInfo(mxGraphicContext) & kCGBitmapByteOrderMask) != kCGBitmapByteOrder32Host) {
865cdf0e10cSrcweir             /**
866cdf0e10cSrcweir              * We need to hack things because VCL does not use kCGBitmapByteOrder32Host, while Cairo requires it.
867cdf0e10cSrcweir              */
868cdf0e10cSrcweir             OSL_TRACE("AquaSalBitmap::%s(): kCGBitmapByteOrder32Host not found => inserting it.",__func__);
869cdf0e10cSrcweir 
870cdf0e10cSrcweir             CGImageRef xImage = CGBitmapContextCreateImage (mxGraphicContext);
871cdf0e10cSrcweir 
872cdf0e10cSrcweir             // re-create the context with single change: include kCGBitmapByteOrder32Host flag.
873cdf0e10cSrcweir             CGContextRef mxGraphicContextNew = CGBitmapContextCreate( CGBitmapContextGetData(mxGraphicContext),
874cdf0e10cSrcweir                                                                       CGBitmapContextGetWidth(mxGraphicContext),
875cdf0e10cSrcweir                                                                       CGBitmapContextGetHeight(mxGraphicContext),
876cdf0e10cSrcweir                                                                       CGBitmapContextGetBitsPerComponent(mxGraphicContext),
877cdf0e10cSrcweir                                                                       CGBitmapContextGetBytesPerRow(mxGraphicContext),
878cdf0e10cSrcweir                                                                       CGBitmapContextGetColorSpace(mxGraphicContext),
879cdf0e10cSrcweir                                                                       CGBitmapContextGetBitmapInfo(mxGraphicContext) | kCGBitmapByteOrder32Host);
880cdf0e10cSrcweir             CFRelease(mxGraphicContext);
881cdf0e10cSrcweir 
882cdf0e10cSrcweir             // Needs to be flipped
883cdf0e10cSrcweir             CGContextSaveGState( mxGraphicContextNew );
884cdf0e10cSrcweir             CGContextTranslateCTM (mxGraphicContextNew, 0, CGBitmapContextGetHeight(mxGraphicContextNew));
885cdf0e10cSrcweir             CGContextScaleCTM (mxGraphicContextNew, 1.0, -1.0);
886cdf0e10cSrcweir 
887cdf0e10cSrcweir             CGContextDrawImage(mxGraphicContextNew, CGRectMake( 0, 0, CGImageGetWidth(xImage), CGImageGetHeight(xImage)), xImage);
888cdf0e10cSrcweir 
889cdf0e10cSrcweir             // Flip back
890cdf0e10cSrcweir             CGContextRestoreGState( mxGraphicContextNew );
891cdf0e10cSrcweir 
892cdf0e10cSrcweir             CGImageRelease( xImage );
893cdf0e10cSrcweir             mxGraphicContext = mxGraphicContextNew;
894cdf0e10cSrcweir         }
895cdf0e10cSrcweir #endif
896cdf0e10cSrcweir 
897cdf0e10cSrcweir         rData.rImageContext = (void *) mxGraphicContext;
898cdf0e10cSrcweir         rData.mnWidth = mnWidth;
899cdf0e10cSrcweir         rData.mnHeight = mnHeight;
900cdf0e10cSrcweir     }
901cdf0e10cSrcweir 
902cdf0e10cSrcweir     return bRet;
903cdf0e10cSrcweir }
904