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