xref: /aoo41x/main/vcl/source/gdi/bmpacc.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <vcl/salbtype.hxx>
32 #include <vcl/bitmap.hxx>
33 #include <vcl/bmpacc.hxx>
34 
35 #include <impbmp.hxx>
36 
37 #include <string.h>
38 
39 // --------------------
40 // - BitmapReadAccess -
41 // --------------------
42 
43 BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap, sal_Bool bModify ) :
44 			mpBuffer		( NULL ),
45 			mpScanBuf		( NULL ),
46 			mFncGetPixel	( NULL ),
47 			mFncSetPixel	( NULL ),
48 			mbModify		( bModify )
49 {
50 	ImplCreate( rBitmap );
51 }
52 
53 // ------------------------------------------------------------------
54 
55 BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap ) :
56 			mpBuffer		( NULL ),
57 			mpScanBuf		( NULL ),
58 			mFncGetPixel	( NULL ),
59 			mFncSetPixel	( NULL ),
60 			mbModify		( sal_False )
61 {
62 	ImplCreate( rBitmap );
63 }
64 
65 // ------------------------------------------------------------------
66 
67 BitmapReadAccess::~BitmapReadAccess()
68 {
69 	ImplDestroy();
70 }
71 
72 // ------------------------------------------------------------------
73 
74 void BitmapReadAccess::ImplCreate( Bitmap& rBitmap )
75 {
76 	ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap();
77 
78 	DBG_ASSERT( pImpBmp, "Forbidden Access to empty bitmap!" );
79 
80 	if( pImpBmp )
81 	{
82 		if( mbModify && !maBitmap.ImplGetImpBitmap() )
83 		{
84 			rBitmap.ImplMakeUnique();
85 			pImpBmp = rBitmap.ImplGetImpBitmap();
86 		}
87 		else
88 		{
89 			DBG_ASSERT( !mbModify || pImpBmp->ImplGetRefCount() == 2,
90 						"Unpredictable results: bitmap is referenced more than once!" );
91 		}
92 
93 		mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify );
94 
95 		if( !mpBuffer )
96 		{
97 			ImpBitmap* pNewImpBmp = new ImpBitmap;
98 
99 			if( pNewImpBmp->ImplCreate( *pImpBmp, rBitmap.GetBitCount()  ) )
100 			{
101 				pImpBmp = pNewImpBmp;
102 				rBitmap.ImplSetImpBitmap( pImpBmp );
103 				mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify );
104 			}
105 			else
106 				delete pNewImpBmp;
107 		}
108 
109 		if( mpBuffer )
110 		{
111 			const long	nHeight = mpBuffer->mnHeight;
112 			Scanline	pTmpLine = mpBuffer->mpBits;
113 
114 			mpScanBuf = new Scanline[ nHeight ];
115 			maColorMask = mpBuffer->maColorMask;
116 
117 			if( BMP_SCANLINE_ADJUSTMENT( mpBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
118 			{
119 				for( long nY = 0L; nY < nHeight; nY++, pTmpLine += mpBuffer->mnScanlineSize )
120 					mpScanBuf[ nY ] = pTmpLine;
121 			}
122 			else
123 			{
124 				for( long nY = nHeight - 1; nY >= 0; nY--, pTmpLine += mpBuffer->mnScanlineSize )
125 					mpScanBuf[ nY ] = pTmpLine;
126 			}
127 
128 			if( !ImplSetAccessPointers( BMP_SCANLINE_FORMAT( mpBuffer->mnFormat ) ) )
129 			{
130 				delete[] mpScanBuf;
131 				mpScanBuf = NULL;
132 
133 				pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify );
134 				mpBuffer = NULL;
135 			}
136 			else
137 				maBitmap = rBitmap;
138 		}
139 	}
140 }
141 
142 // ------------------------------------------------------------------
143 
144 void BitmapReadAccess::ImplDestroy()
145 {
146 	ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap();
147 
148 	delete[] mpScanBuf;
149 	mpScanBuf = NULL;
150 
151 	if( mpBuffer && pImpBmp )
152 	{
153 		pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify );
154 		mpBuffer = NULL;
155 	}
156 }
157 
158 // ------------------------------------------------------------------
159 
160 sal_Bool BitmapReadAccess::ImplSetAccessPointers( sal_uLong nFormat )
161 {
162 	sal_Bool bRet = sal_True;
163 
164 	switch( nFormat )
165 	{
166 		CASE_FORMAT( _1BIT_MSB_PAL )
167 		CASE_FORMAT( _1BIT_LSB_PAL )
168 		CASE_FORMAT( _4BIT_MSN_PAL )
169 		CASE_FORMAT( _4BIT_LSN_PAL )
170 		CASE_FORMAT( _8BIT_PAL )
171 		CASE_FORMAT( _8BIT_TC_MASK )
172 		CASE_FORMAT( _16BIT_TC_MSB_MASK )
173 		CASE_FORMAT( _16BIT_TC_LSB_MASK )
174 		CASE_FORMAT( _24BIT_TC_BGR )
175 		CASE_FORMAT( _24BIT_TC_RGB )
176 		CASE_FORMAT( _24BIT_TC_MASK )
177 		CASE_FORMAT( _32BIT_TC_ABGR )
178 		CASE_FORMAT( _32BIT_TC_ARGB )
179 		CASE_FORMAT( _32BIT_TC_BGRA )
180 		CASE_FORMAT( _32BIT_TC_RGBA )
181 		CASE_FORMAT( _32BIT_TC_MASK )
182 
183 		default:
184 			bRet = sal_False;
185 		break;
186 	}
187 
188 	return bRet;
189 }
190 
191 // ------------------------------------------------------------------
192 
193 void BitmapReadAccess::ImplZeroInitUnusedBits()
194 {
195 	const sal_uInt32 nWidth = Width(), nHeight = Height(), nScanSize = GetScanlineSize();
196 
197 	if( nWidth && nHeight && nScanSize && GetBuffer() )
198 	{
199 		sal_uInt32 nBits;
200         bool       bMsb;
201 
202         const sal_uLong nScanlineFormat = GetScanlineFormat();
203 		switch( nScanlineFormat )
204 		{
205             case( BMP_FORMAT_1BIT_MSB_PAL ):
206 				nBits = 1;
207 				bMsb = true;
208                 break;
209 
210             case( BMP_FORMAT_1BIT_LSB_PAL ):
211 				nBits = 1;
212 				bMsb = false;
213                 break;
214 
215 			case( BMP_FORMAT_4BIT_MSN_PAL ):
216 				nBits = 4;
217 				bMsb = true;
218                 break;
219 
220             case( BMP_FORMAT_4BIT_LSN_PAL ):
221 				nBits = 4;
222 				bMsb = false;
223                 break;
224 
225 			case( BMP_FORMAT_8BIT_PAL ):
226 			case( BMP_FORMAT_8BIT_TC_MASK ):
227 				bMsb = true;
228 				nBits = 8;
229 			break;
230 
231 			case( BMP_FORMAT_16BIT_TC_MSB_MASK ):
232 			case( BMP_FORMAT_16BIT_TC_LSB_MASK ):
233 				bMsb = true;
234 				nBits = 16;
235 			break;
236 
237 			case( BMP_FORMAT_24BIT_TC_BGR ):
238 			case( BMP_FORMAT_24BIT_TC_RGB ):
239 			case( BMP_FORMAT_24BIT_TC_MASK ):
240 				bMsb = true;
241 				nBits = 24;
242 			break;
243 
244 			case( BMP_FORMAT_32BIT_TC_ABGR ):
245 			case( BMP_FORMAT_32BIT_TC_ARGB ):
246 			case( BMP_FORMAT_32BIT_TC_BGRA ):
247 			case( BMP_FORMAT_32BIT_TC_RGBA ):
248 			case( BMP_FORMAT_32BIT_TC_MASK ):
249 				bMsb = true;
250 				nBits = 32;
251 			break;
252 
253 			default:
254 			{
255 				DBG_ERROR( "BitmapWriteAccess::ZeroInitUnusedBits: Unsupported pixel format");
256 				nBits = 0;
257 				bMsb = true;
258 			}
259 			break;
260 		}
261 
262         nBits *= nWidth;
263 		if( nScanSize % 4 || !bMsb )
264         {
265             DBG_ASSERT( 8*nScanSize >= nBits,
266                         "BitmapWriteAccess::ZeroInitUnusedBits: span size smaller than width?!");
267 			const sal_uInt32 nLeftOverBits = 8*sizeof(sal_uInt8)*nScanSize - nBits;
268             if( nLeftOverBits != 0 ) // else there is really nothing to do
269             {
270                 const sal_uInt32 nBytes = (nLeftOverBits + 7U) >> 3U;
271                 sal_uInt8	     nMask;
272 
273                 if( bMsb )
274                     nMask = static_cast<sal_uInt8>(0xffU << (nLeftOverBits & 3UL));
275                 else
276                     nMask = static_cast<sal_uInt8>(0xffU >> (nLeftOverBits & 3UL));
277 
278                 sal_uInt8* pLastBytes = (sal_uInt8*)GetBuffer() + ( nScanSize - nBytes );
279                 for( sal_uInt32 i = 0; i < nHeight; i++, pLastBytes += nScanSize )
280                 {
281                     *pLastBytes &= nMask;
282                     for( sal_uInt32 j = 1; j < nBytes; j++ )
283                         pLastBytes[j] = 0;
284                 }
285             }
286         }
287         else if( nBits & 0x1f )
288 		{
289 			sal_uInt32	nMask = 0xffffffff << ( ( nScanSize << 3 ) - nBits );
290 			sal_uInt8*		pLast4Bytes = (sal_uInt8*) GetBuffer() + ( nScanSize - 4 );
291 
292 #ifdef OSL_LITENDIAN
293 			nMask = SWAPLONG( nMask );
294 #endif
295 			for( sal_uInt32 i = 0; i < nHeight; i++, pLast4Bytes += nScanSize )
296 				( *(sal_uInt32*) pLast4Bytes ) &= nMask;
297 		}
298 	}
299 }
300 
301 // ------------------------------------------------------------------
302 
303 void BitmapReadAccess::Flush()
304 {
305 	ImplDestroy();
306 }
307 
308 // ------------------------------------------------------------------
309 
310 void BitmapReadAccess::ReAccess( sal_Bool bModify )
311 {
312 	const ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap();
313 
314 	DBG_ASSERT( !mpBuffer, "No ReAccess possible while bitmap is being accessed!" );
315 	DBG_ASSERT( pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ), "Accessed bitmap does not exist anymore!" );
316 
317 	if( !mpBuffer && pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ) )
318 	{
319 		mbModify = bModify;
320 		ImplCreate( maBitmap );
321 	}
322 }
323 
324 // ------------------------------------------------------------------
325 
326 sal_uInt16 BitmapReadAccess::GetBestPaletteIndex( const BitmapColor& rBitmapColor ) const
327 {
328 	return( HasPalette() ? mpBuffer->maPalette.GetBestIndex( rBitmapColor ) : 0 );
329 }
330 
331 // ---------------------
332 // - BitmapWriteAccess -
333 // ---------------------
334 
335 BitmapWriteAccess::BitmapWriteAccess( Bitmap& rBitmap ) :
336             BitmapReadAccess( rBitmap, sal_True ),
337             mpLineColor     ( NULL ),
338             mpFillColor     ( NULL )
339 {
340 }
341 
342 // ------------------------------------------------------------------
343 
344 BitmapWriteAccess::~BitmapWriteAccess()
345 {
346 	delete mpLineColor;
347 	delete mpFillColor;
348 }
349 
350 // ------------------------------------------------------------------
351 
352 void BitmapWriteAccess::CopyScanline( long nY, const BitmapReadAccess& rReadAcc )
353 {
354 	DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" );
355 	DBG_ASSERT( nY < rReadAcc.Height(), "y-coordinate in source out of range!" );
356 	DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
357 
358 	if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) &&
359 		( GetScanlineSize() >= rReadAcc.GetScanlineSize() ) )
360 	{
361 		memcpy( mpScanBuf[ nY ], rReadAcc.GetScanline( nY ), rReadAcc.GetScanlineSize() );
362 	}
363 	else
364         // TODO: use fastbmp infrastructure
365 		for( long nX = 0L, nWidth = Min( mpBuffer->mnWidth, rReadAcc.Width() ); nX < nWidth; nX++ )
366 			SetPixel( nY, nX, rReadAcc.GetPixel( nY, nX ) );
367 }
368 
369 // ------------------------------------------------------------------
370 
371 void BitmapWriteAccess::CopyScanline( long nY, ConstScanline aSrcScanline,
372 									  sal_uLong nSrcScanlineFormat, sal_uLong nSrcScanlineSize )
373 {
374 	const sal_uLong nFormat = BMP_SCANLINE_FORMAT( nSrcScanlineFormat );
375 
376 	DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" );
377 	DBG_ASSERT( ( HasPalette() && nFormat <= BMP_FORMAT_8BIT_PAL ) ||
378 				( !HasPalette() && nFormat > BMP_FORMAT_8BIT_PAL ),
379 				"No copying possible between palette and non palette scanlines!" );
380 
381 	const sal_uLong nCount = Min( GetScanlineSize(), nSrcScanlineSize );
382 
383 	if( nCount )
384 	{
385 		if( GetScanlineFormat() == BMP_SCANLINE_FORMAT( nSrcScanlineFormat ) )
386 			memcpy( mpScanBuf[ nY ], aSrcScanline, nCount );
387 		else
388 		{
389 			DBG_ASSERT( nFormat != BMP_FORMAT_8BIT_TC_MASK &&
390                         nFormat != BMP_FORMAT_16BIT_TC_MSB_MASK && nFormat != BMP_FORMAT_16BIT_TC_LSB_MASK &&
391 						nFormat != BMP_FORMAT_24BIT_TC_MASK && nFormat != BMP_FORMAT_32BIT_TC_MASK,
392 						"No support for pixel formats with color masks yet!" );
393 
394             // TODO: use fastbmp infrastructure
395             FncGetPixel pFncGetPixel;
396 
397 			switch( nFormat )
398 			{
399 				case( BMP_FORMAT_1BIT_MSB_PAL ):	pFncGetPixel = GetPixelFor_1BIT_MSB_PAL; break;
400 				case( BMP_FORMAT_1BIT_LSB_PAL ):	pFncGetPixel = GetPixelFor_1BIT_LSB_PAL; break;
401 				case( BMP_FORMAT_4BIT_MSN_PAL ):	pFncGetPixel = GetPixelFor_4BIT_MSN_PAL; break;
402 				case( BMP_FORMAT_4BIT_LSN_PAL ):	pFncGetPixel = GetPixelFor_4BIT_LSN_PAL; break;
403 				case( BMP_FORMAT_8BIT_PAL ):		pFncGetPixel = GetPixelFor_8BIT_PAL; break;
404 				case( BMP_FORMAT_8BIT_TC_MASK ):	pFncGetPixel = GetPixelFor_8BIT_TC_MASK; break;
405 				case( BMP_FORMAT_16BIT_TC_MSB_MASK ):	pFncGetPixel = GetPixelFor_16BIT_TC_MSB_MASK; break;
406 				case( BMP_FORMAT_16BIT_TC_LSB_MASK ):	pFncGetPixel = GetPixelFor_16BIT_TC_LSB_MASK; break;
407 				case( BMP_FORMAT_24BIT_TC_BGR ):	pFncGetPixel = GetPixelFor_24BIT_TC_BGR; break;
408 				case( BMP_FORMAT_24BIT_TC_RGB ):	pFncGetPixel = GetPixelFor_24BIT_TC_RGB; break;
409 				case( BMP_FORMAT_24BIT_TC_MASK ):	pFncGetPixel = GetPixelFor_24BIT_TC_MASK; break;
410 				case( BMP_FORMAT_32BIT_TC_ABGR ):	pFncGetPixel = GetPixelFor_32BIT_TC_ABGR; break;
411 				case( BMP_FORMAT_32BIT_TC_ARGB ):	pFncGetPixel = GetPixelFor_32BIT_TC_ARGB; break;
412 				case( BMP_FORMAT_32BIT_TC_BGRA ):	pFncGetPixel = GetPixelFor_32BIT_TC_BGRA; break;
413 				case( BMP_FORMAT_32BIT_TC_RGBA ):	pFncGetPixel = GetPixelFor_32BIT_TC_RGBA; break;
414 				case( BMP_FORMAT_32BIT_TC_MASK ):	pFncGetPixel = GetPixelFor_32BIT_TC_MASK; break;
415 
416 				default:
417 					pFncGetPixel = NULL;
418 				break;
419 			}
420 
421 			if( pFncGetPixel )
422 			{
423 				const ColorMask aDummyMask;
424 
425 				for( long nX = 0L, nWidth = mpBuffer->mnWidth; nX < nWidth; nX++ )
426 					SetPixel( nY, nX, pFncGetPixel( aSrcScanline, nX, aDummyMask ) );
427 			}
428 		}
429 	}
430 }
431 
432 
433 // ------------------------------------------------------------------
434 
435 void BitmapWriteAccess::CopyBuffer( const BitmapReadAccess& rReadAcc )
436 {
437 	DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
438 
439 	if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) &&
440 		( GetScanlineSize() == rReadAcc.GetScanlineSize() ) )
441 	{
442 		const long	nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() );
443 		const sal_uLong nCount = nHeight * mpBuffer->mnScanlineSize;
444 
445 		memcpy( mpBuffer->mpBits, rReadAcc.GetBuffer(), nCount );
446 	}
447 	else
448 		for( long nY = 0L, nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() ); nY < nHeight; nY++ )
449 			CopyScanline( nY, rReadAcc );
450 }
451