xref: /trunk/main/vcl/source/gdi/bitmapex.cxx (revision 0399a9fd)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include <ctype.h>
28 #include <rtl/crc.h>
29 #include <tools/stream.hxx>
30 #include <tools/debug.hxx>
31 #include <tools/rc.h>
32 #include <vcl/salbtype.hxx>
33 #include <vcl/outdev.hxx>
34 #include <vcl/alpha.hxx>
35 #include <vcl/bitmapex.hxx>
36 #include <vcl/pngread.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/bmpacc.hxx>
39 #include <vcl/dibtools.hxx>
40 #include <image.h>
41 #include <impimagetree.hxx>
42 #include <basegfx/matrix/b2dhommatrixtools.hxx>
43 
44 // ------------
45 // - BitmapEx -
46 // ------------
47 
BitmapEx()48 BitmapEx::BitmapEx() :
49 		eTransparent( TRANSPARENT_NONE ),
50 		bAlpha		( sal_False )
51 {
52 }
53 
54 // ------------------------------------------------------------------
55 
BitmapEx(const BitmapEx & rBitmapEx)56 BitmapEx::BitmapEx( const BitmapEx& rBitmapEx ) :
57 		aBitmap				( rBitmapEx.aBitmap ),
58 		aMask				( rBitmapEx.aMask ),
59 		aBitmapSize			( rBitmapEx.aBitmapSize ),
60 		aTransparentColor	( rBitmapEx.aTransparentColor ),
61 		eTransparent		( rBitmapEx.eTransparent ),
62 		bAlpha				( rBitmapEx.bAlpha )
63 {
64 }
65 
BitmapEx(const BitmapEx & rBitmapEx,Point aSrc,Size aSize)66 BitmapEx::BitmapEx( const BitmapEx& rBitmapEx, Point aSrc, Size aSize ) :
67 		eTransparent( TRANSPARENT_NONE ),
68 		bAlpha		( sal_False )
69 {
70 	if( rBitmapEx.IsEmpty() )
71 		return;
72 
73 	aBitmap = Bitmap( aSize, rBitmapEx.aBitmap.GetBitCount() );
74 	aBitmapSize = aSize;
75 	if( rBitmapEx.IsAlpha() )
76 	{
77 		bAlpha = sal_True;
78 		aMask = AlphaMask( aSize ).ImplGetBitmap();
79 	}
80 	else if( rBitmapEx.IsTransparent() )
81 		aMask = Bitmap( aSize, rBitmapEx.aMask.GetBitCount() );
82 
83 	Rectangle aDestRect( Point( 0, 0 ), aSize );
84 	Rectangle aSrcRect( aSrc, aSize );
85 	CopyPixel( aDestRect, aSrcRect, &rBitmapEx );
86 }
87 
88 // ------------------------------------------------------------------
89 
BitmapEx(const ResId & rResId)90 BitmapEx::BitmapEx( const ResId& rResId ) :
91 		eTransparent( TRANSPARENT_NONE ),
92 		bAlpha		( sal_False )
93 {
94 	static ImplImageTreeSingletonRef	aImageTree;
95 	ResMgr* 							pResMgr = NULL;
96 
97 	ResMgr::GetResourceSkipHeader( rResId.SetRT( RSC_BITMAP ), &pResMgr );
98 	pResMgr->ReadLong();
99 	pResMgr->ReadLong();
100 
101 	const String aFileName( pResMgr->ReadString() );
102 	::rtl::OUString aCurrentSymbolsStyle = Application::GetSettings().GetStyleSettings().GetCurrentSymbolsStyleName();
103 
104 	if( !aImageTree->loadImage( aFileName, aCurrentSymbolsStyle, *this ) )
105 	{
106 #ifdef DBG_UTIL
107 		ByteString aErrorStr( "BitmapEx::BitmapEx( const ResId& rResId ): could not load image <" );
108 		DBG_ERROR( ( ( aErrorStr += ByteString( aFileName, RTL_TEXTENCODING_ASCII_US ) ) += '>' ).GetBuffer() );
109 #endif
110 	}
111 }
112 
113 // ------------------------------------------------------------------
114 
BitmapEx(const Bitmap & rBmp)115 BitmapEx::BitmapEx( const Bitmap& rBmp ) :
116 		aBitmap		( rBmp ),
117 		aBitmapSize	( aBitmap.GetSizePixel() ),
118 		eTransparent( TRANSPARENT_NONE ),
119 		bAlpha		( sal_False )
120 {
121 }
122 
123 // ------------------------------------------------------------------
124 
BitmapEx(const Bitmap & rBmp,const Bitmap & rMask)125 BitmapEx::BitmapEx( const Bitmap& rBmp, const Bitmap& rMask ) :
126 		aBitmap			( rBmp ),
127 		aMask			( rMask ),
128 		aBitmapSize		( aBitmap.GetSizePixel() ),
129 		eTransparent	( !rMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ),
130 		bAlpha			( sal_False )
131 {
132 	if(!!aBitmap && !!aMask && aBitmap.GetSizePixel() != aMask.GetSizePixel())
133 	{
134 		OSL_ENSURE(false, "Mask size differs from Bitmap size, corrected Mask (!)");
135 		aMask.Scale(aBitmap.GetSizePixel());
136 	}
137 
138 	// #105489# Ensure a mask is exactly one bit deep
139 	if( !!aMask && aMask.GetBitCount() != 1 )
140 	{
141 		OSL_TRACE("BitmapEx: forced mask to monochrome");
142 		aMask.ImplMakeMono( 255 );
143 	}
144 }
145 
146 // ------------------------------------------------------------------
147 
BitmapEx(const Bitmap & rBmp,const AlphaMask & rAlphaMask)148 BitmapEx::BitmapEx( const Bitmap& rBmp, const AlphaMask& rAlphaMask ) :
149 		aBitmap			( rBmp ),
150 		aMask			( rAlphaMask.ImplGetBitmap() ),
151 		aBitmapSize		( aBitmap.GetSizePixel() ),
152 		eTransparent	( !rAlphaMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ),
153 		bAlpha			( !rAlphaMask ? sal_False : sal_True )
154 {
155 	if(!!aBitmap && !!aMask && aBitmap.GetSizePixel() != aMask.GetSizePixel())
156 	{
157 		OSL_ENSURE(false, "Alpha size differs from Bitmap size, corrected Mask (!)");
158 		aMask.Scale(rBmp.GetSizePixel());
159 	}
160 
161 	// #i75531# the workaround below can go when
162 	// X11SalGraphics::drawAlphaBitmap()'s render acceleration
163 	// can handle the bitmap depth mismatch directly
164 	if( aBitmap.GetBitCount() < aMask.GetBitCount() )
165 		aBitmap.Convert( BMP_CONVERSION_24BIT );
166 }
167 
168 // ------------------------------------------------------------------
169 
BitmapEx(const Bitmap & rBmp,const Color & rTransparentColor)170 BitmapEx::BitmapEx( const Bitmap& rBmp, const Color& rTransparentColor ) :
171 		aBitmap				( rBmp ),
172 		aBitmapSize			( aBitmap.GetSizePixel() ),
173 		aTransparentColor	( rTransparentColor ),
174 		eTransparent		( TRANSPARENT_BITMAP ),
175 		bAlpha				( sal_False )
176 {
177 	aMask = aBitmap.CreateMask( aTransparentColor );
178 
179 	DBG_ASSERT( rBmp.GetSizePixel() == aMask.GetSizePixel(),
180 				"BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask." );
181 }
182 
183 // ------------------------------------------------------------------
184 
~BitmapEx()185 BitmapEx::~BitmapEx()
186 {
187 }
188 
189 // ------------------------------------------------------------------
190 
191 // ------------------------------------------------------------------
192 
operator =(const BitmapEx & rBitmapEx)193 BitmapEx& BitmapEx::operator=( const BitmapEx& rBitmapEx )
194 {
195 	if( &rBitmapEx != this )
196 	{
197 		aBitmap = rBitmapEx.aBitmap;
198 		aMask = rBitmapEx.aMask;
199 		aBitmapSize = rBitmapEx.aBitmapSize;
200 		aTransparentColor = rBitmapEx.aTransparentColor;
201 		eTransparent = rBitmapEx.eTransparent;
202 		bAlpha = rBitmapEx.bAlpha;
203 	}
204 
205 	return *this;
206 }
207 
208 // ------------------------------------------------------------------
209 
operator ==(const BitmapEx & rBitmapEx) const210 sal_Bool BitmapEx::operator==( const BitmapEx& rBitmapEx ) const
211 {
212 	if( eTransparent != rBitmapEx.eTransparent )
213 		return sal_False;
214 
215 	if( aBitmap != rBitmapEx.aBitmap )
216 		return sal_False;
217 
218 	if( aBitmapSize != rBitmapEx.aBitmapSize )
219 		return sal_False;
220 
221 	if( eTransparent == TRANSPARENT_NONE )
222 		return sal_True;
223 
224 	if( eTransparent == TRANSPARENT_COLOR )
225 		return aTransparentColor == rBitmapEx.aTransparentColor;
226 
227 	return( ( aMask == rBitmapEx.aMask ) && ( bAlpha == rBitmapEx.bAlpha ) );
228 }
229 
230 // ------------------------------------------------------------------
231 
IsEqual(const BitmapEx & rBmpEx) const232 sal_Bool BitmapEx::IsEqual( const BitmapEx& rBmpEx ) const
233 {
234 	return( rBmpEx.eTransparent == eTransparent &&
235 			rBmpEx.bAlpha == bAlpha &&
236 			rBmpEx.aBitmap.IsEqual( aBitmap ) &&
237 			rBmpEx.aMask.IsEqual( aMask ) );
238 }
239 
240 // ------------------------------------------------------------------
241 
IsEmpty() const242 sal_Bool BitmapEx::IsEmpty() const
243 {
244 	return( aBitmap.IsEmpty() && aMask.IsEmpty() );
245 }
246 
247 // ------------------------------------------------------------------
248 
SetEmpty()249 void BitmapEx::SetEmpty()
250 {
251 	aBitmap.SetEmpty();
252 	aMask.SetEmpty();
253 	eTransparent = TRANSPARENT_NONE;
254 	bAlpha = sal_False;
255 }
256 
257 // ------------------------------------------------------------------
258 
Clear()259 void BitmapEx::Clear()
260 {
261 	SetEmpty();
262 }
263 
264 // ------------------------------------------------------------------
265 
IsTransparent() const266 sal_Bool BitmapEx::IsTransparent() const
267 {
268 	return( eTransparent != TRANSPARENT_NONE );
269 }
270 
271 // ------------------------------------------------------------------
272 
IsAlpha() const273 sal_Bool BitmapEx::IsAlpha() const
274 {
275 	return( IsTransparent() && bAlpha );
276 }
277 
278 // ------------------------------------------------------------------
279 
GetBitmap(const Color * pTransReplaceColor) const280 Bitmap BitmapEx::GetBitmap( const Color* pTransReplaceColor ) const
281 {
282 	Bitmap aRetBmp( aBitmap );
283 
284 	if( pTransReplaceColor && ( eTransparent != TRANSPARENT_NONE ) )
285 	{
286 		Bitmap aTempMask;
287 
288 		if( eTransparent == TRANSPARENT_COLOR )
289 			aTempMask = aBitmap.CreateMask( aTransparentColor );
290 		else
291 			aTempMask = aMask;
292 
293 		if( !IsAlpha() )
294 			aRetBmp.Replace( aTempMask, *pTransReplaceColor );
295 		else
296 			aRetBmp.Replace( GetAlpha(), *pTransReplaceColor );
297 	}
298 
299 	return aRetBmp;
300 }
301 
302 // ------------------------------------------------------------------
303 
GetColorTransformedBitmapEx(BmpColorMode eColorMode) const304 BitmapEx BitmapEx::GetColorTransformedBitmapEx( BmpColorMode eColorMode ) const
305 {
306 	BitmapEx aRet;
307 
308 	if( BMP_COLOR_HIGHCONTRAST == eColorMode )
309 	{
310 		aRet = *this;
311 		aRet.aBitmap = aBitmap.GetColorTransformedBitmap( eColorMode );
312 	}
313 	else if( BMP_COLOR_MONOCHROME_BLACK == eColorMode ||
314 			 BMP_COLOR_MONOCHROME_WHITE == eColorMode )
315 	{
316 		aRet = *this;
317 		aRet.aBitmap = aRet.aBitmap.GetColorTransformedBitmap( eColorMode );
318 
319 		if( !aRet.aMask.IsEmpty() )
320 		{
321 			aRet.aMask.CombineSimple( aRet.aBitmap, BMP_COMBINE_OR );
322 			aRet.aBitmap.Erase( ( BMP_COLOR_MONOCHROME_BLACK == eColorMode ) ? COL_BLACK : COL_WHITE );
323 
324 			DBG_ASSERT( aRet.aBitmap.GetSizePixel() == aRet.aMask.GetSizePixel(),
325 						"BitmapEx::GetColorTransformedBitmapEx(): size mismatch for bitmap and alpha mask." );
326 		}
327 	}
328 
329 	return aRet;
330 }
331 
332 // ------------------------------------------------------------------
333 
GetMask() const334 Bitmap BitmapEx::GetMask() const
335 {
336 	Bitmap aRet( aMask );
337 
338 	if( IsAlpha() )
339 		aRet.ImplMakeMono( 255 );
340 
341 	return aRet;
342 }
343 
344 // ------------------------------------------------------------------
345 
GetAlpha() const346 AlphaMask BitmapEx::GetAlpha() const
347 {
348 	AlphaMask aAlpha;
349 
350 	if( IsAlpha() )
351 		aAlpha.ImplSetBitmap( aMask );
352 	else
353 		aAlpha = aMask;
354 
355 	return aAlpha;
356 }
357 
358 // ------------------------------------------------------------------
359 
GetSizeBytes() const360 sal_uLong BitmapEx::GetSizeBytes() const
361 {
362 	sal_uLong nSizeBytes = aBitmap.GetSizeBytes();
363 
364 	if( eTransparent == TRANSPARENT_BITMAP )
365 		nSizeBytes += aMask.GetSizeBytes();
366 
367 	return nSizeBytes;
368 }
369 
370 // ------------------------------------------------------------------
371 
GetChecksum() const372 sal_uLong BitmapEx::GetChecksum() const
373 {
374 	sal_uInt32	nCrc = aBitmap.GetChecksum();
375 	SVBT32		aBT32;
376 
377 	UInt32ToSVBT32( (long) eTransparent, aBT32 );
378 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
379 
380 	UInt32ToSVBT32( (long) bAlpha, aBT32 );
381 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
382 
383 	if( ( TRANSPARENT_BITMAP == eTransparent ) && !aMask.IsEmpty() )
384 	{
385 		UInt32ToSVBT32( aMask.GetChecksum(), aBT32 );
386 		nCrc = rtl_crc32( nCrc, aBT32, 4 );
387 	}
388 
389 	return nCrc;
390 }
391 
392 // ------------------------------------------------------------------
393 
SetSizePixel(const Size & rNewSize,sal_uInt32 nScaleFlag)394 void BitmapEx::SetSizePixel( const Size& rNewSize, sal_uInt32 nScaleFlag )
395 {
396 	if(GetSizePixel() != rNewSize)
397 	{
398 		Scale( rNewSize, nScaleFlag );
399 	}
400 }
401 
402 // ------------------------------------------------------------------
403 
Invert()404 sal_Bool BitmapEx::Invert()
405 {
406 	sal_Bool bRet = sal_False;
407 
408 	if( !!aBitmap )
409 	{
410 		bRet = aBitmap.Invert();
411 
412 		if( bRet && ( eTransparent == TRANSPARENT_COLOR ) )
413 			aTransparentColor = BitmapColor( aTransparentColor ).Invert();
414 	}
415 
416 	return bRet;
417 }
418 
419 // ------------------------------------------------------------------
420 
Mirror(sal_uLong nMirrorFlags)421 sal_Bool BitmapEx::Mirror( sal_uLong nMirrorFlags )
422 {
423 	sal_Bool bRet = sal_False;
424 
425 	if( !!aBitmap )
426 	{
427 		bRet = aBitmap.Mirror( nMirrorFlags );
428 
429 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
430 			aMask.Mirror( nMirrorFlags );
431 	}
432 
433 	return bRet;
434 }
435 
436 // ------------------------------------------------------------------
437 
Scale(const double & rScaleX,const double & rScaleY,sal_uInt32 nScaleFlag)438 sal_Bool BitmapEx::Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag )
439 {
440 	sal_Bool bRet = sal_False;
441 
442 	if( !!aBitmap )
443 	{
444 		bRet = aBitmap.Scale( rScaleX, rScaleY, nScaleFlag );
445 
446 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
447 		{
448 			aMask.Scale( rScaleX, rScaleY, nScaleFlag );
449 		}
450 
451 		aBitmapSize = aBitmap.GetSizePixel();
452 
453 		DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
454 					"BitmapEx::Scale(): size mismatch for bitmap and alpha mask." );
455 	}
456 
457 	return bRet;
458 }
459 
460 // ------------------------------------------------------------------------
461 
Scale(const Size & rNewSize,sal_uInt32 nScaleFlag)462 sal_Bool BitmapEx::Scale( const Size& rNewSize, sal_uInt32 nScaleFlag )
463 {
464 	sal_Bool bRet;
465 
466 	if( aBitmapSize.Width() && aBitmapSize.Height() )
467 	{
468 		bRet = Scale( (double) rNewSize.Width() / aBitmapSize.Width(),
469 					  (double) rNewSize.Height() / aBitmapSize.Height(),
470 					  nScaleFlag );
471 	}
472 	else
473 		bRet = sal_True;
474 
475 	return bRet;
476 }
477 
478 // ------------------------------------------------------------------
479 
Rotate(long nAngle10,const Color & rFillColor)480 sal_Bool BitmapEx::Rotate( long nAngle10, const Color& rFillColor )
481 {
482 	sal_Bool bRet = sal_False;
483 
484 	if( !!aBitmap )
485 	{
486 		const sal_Bool bTransRotate = ( Color( COL_TRANSPARENT ) == rFillColor );
487 
488 		if( bTransRotate )
489 		{
490 			if( eTransparent == TRANSPARENT_COLOR )
491 				bRet = aBitmap.Rotate( nAngle10, aTransparentColor );
492 			else
493 			{
494 				bRet = aBitmap.Rotate( nAngle10, COL_BLACK );
495 
496 				if( eTransparent == TRANSPARENT_NONE )
497 				{
498 					aMask = Bitmap( aBitmapSize, 1 );
499 					aMask.Erase( COL_BLACK );
500 					eTransparent = TRANSPARENT_BITMAP;
501 				}
502 
503 				if( bRet && !!aMask )
504 					aMask.Rotate( nAngle10, COL_WHITE );
505 			}
506 		}
507 		else
508 		{
509 			bRet = aBitmap.Rotate( nAngle10, rFillColor );
510 
511 			if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
512 				aMask.Rotate( nAngle10, COL_WHITE );
513 		}
514 
515 		aBitmapSize = aBitmap.GetSizePixel();
516 
517 		DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
518 					"BitmapEx::Rotate(): size mismatch for bitmap and alpha mask." );
519 	}
520 
521 	return bRet;
522 }
523 
524 // ------------------------------------------------------------------
525 
Crop(const Rectangle & rRectPixel)526 sal_Bool BitmapEx::Crop( const Rectangle& rRectPixel )
527 {
528 	sal_Bool bRet = sal_False;
529 
530 	if( !!aBitmap )
531 	{
532 		bRet = aBitmap.Crop( rRectPixel );
533 
534 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
535 			aMask.Crop( rRectPixel );
536 
537 		aBitmapSize = aBitmap.GetSizePixel();
538 
539 		DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
540 					"BitmapEx::Crop(): size mismatch for bitmap and alpha mask." );
541 	}
542 
543 	return bRet;
544 }
545 
546 // ------------------------------------------------------------------
547 
Convert(BmpConversion eConversion)548 sal_Bool BitmapEx::Convert( BmpConversion eConversion )
549 {
550 	return( !!aBitmap ? aBitmap.Convert( eConversion ) : sal_False );
551 }
552 
553 // ------------------------------------------------------------------
554 
ReduceColors(sal_uInt16 nNewColorCount,BmpReduce eReduce)555 sal_Bool BitmapEx::ReduceColors( sal_uInt16 nNewColorCount, BmpReduce eReduce )
556 {
557 	return( !!aBitmap ? aBitmap.ReduceColors( nNewColorCount, eReduce ) : sal_False );
558 }
559 
560 // ------------------------------------------------------------------
561 
Expand(sal_uLong nDX,sal_uLong nDY,const Color * pInitColor,sal_Bool bExpandTransparent)562 sal_Bool BitmapEx::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor, sal_Bool bExpandTransparent )
563 {
564 	sal_Bool bRet = sal_False;
565 
566 	if( !!aBitmap )
567 	{
568 		bRet = aBitmap.Expand( nDX, nDY, pInitColor );
569 
570 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
571 		{
572 			Color aColor( bExpandTransparent ? COL_WHITE : COL_BLACK );
573 			aMask.Expand( nDX, nDY, &aColor );
574 		}
575 
576 		aBitmapSize = aBitmap.GetSizePixel();
577 
578 		DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
579 					"BitmapEx::Expand(): size mismatch for bitmap and alpha mask." );
580 	}
581 
582 	return bRet;
583 }
584 
585 // ------------------------------------------------------------------
586 
CopyPixel(const Rectangle & rRectDst,const Rectangle & rRectSrc,const BitmapEx * pBmpExSrc)587 sal_Bool BitmapEx::CopyPixel( const Rectangle& rRectDst, const Rectangle& rRectSrc,
588 						  const BitmapEx* pBmpExSrc )
589 {
590 	sal_Bool bRet = sal_False;
591 
592 	if( !pBmpExSrc || pBmpExSrc->IsEmpty() )
593 	{
594 		if( !aBitmap.IsEmpty() )
595 		{
596 			bRet = aBitmap.CopyPixel( rRectDst, rRectSrc );
597 
598 			if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
599 				aMask.CopyPixel( rRectDst, rRectSrc );
600 		}
601 	}
602 	else
603 	{
604 		if( !aBitmap.IsEmpty() )
605 		{
606 			bRet = aBitmap.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aBitmap );
607 
608 			if( bRet )
609 			{
610 				if( pBmpExSrc->IsAlpha() )
611 				{
612 					if( IsAlpha() )
613 						// cast to use the optimized AlphaMask::CopyPixel
614 						((AlphaMask*) &aMask)->CopyPixel( rRectDst, rRectSrc, (AlphaMask*)&pBmpExSrc->aMask );
615 					else if( IsTransparent() )
616 					{
617 						AlphaMask* pAlpha = new AlphaMask( aMask );
618 
619 						aMask = pAlpha->ImplGetBitmap();
620 						delete pAlpha;
621 						bAlpha = sal_True;
622 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
623 					}
624 					else
625 					{
626 						sal_uInt8	cBlack = 0;
627 						AlphaMask*	pAlpha = new AlphaMask( GetSizePixel(), &cBlack );
628 
629 						aMask = pAlpha->ImplGetBitmap();
630 						delete pAlpha;
631 						eTransparent = TRANSPARENT_BITMAP;
632 						bAlpha = sal_True;
633 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
634 					}
635 				}
636 				else if( pBmpExSrc->IsTransparent() )
637 				{
638 					if( IsAlpha() )
639 					{
640 						AlphaMask aAlpha( pBmpExSrc->aMask );
641 						aMask.CopyPixel( rRectDst, rRectSrc, &aAlpha.ImplGetBitmap() );
642 					}
643 					else if( IsTransparent() )
644 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
645 					else
646 					{
647 						aMask = Bitmap( GetSizePixel(), 1 );
648 						aMask.Erase( Color( COL_BLACK ) );
649 						eTransparent = TRANSPARENT_BITMAP;
650 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
651 					}
652 				}
653 				else if( IsAlpha() )
654 				{
655 					sal_uInt8			cBlack = 0;
656 					const AlphaMask		aAlphaSrc( pBmpExSrc->GetSizePixel(), &cBlack );
657 
658 					aMask.CopyPixel( rRectDst, rRectSrc, &aAlphaSrc.ImplGetBitmap() );
659 				}
660 				else if( IsTransparent() )
661 				{
662 					Bitmap aMaskSrc( pBmpExSrc->GetSizePixel(), 1 );
663 
664 					aMaskSrc.Erase( Color( COL_BLACK ) );
665 					aMask.CopyPixel( rRectDst, rRectSrc, &aMaskSrc );
666 				}
667 			}
668 		}
669 	}
670 
671 	return bRet;
672 }
673 
674 // ------------------------------------------------------------------
675 
Erase(const Color & rFillColor)676 sal_Bool BitmapEx::Erase( const Color& rFillColor )
677 {
678 	sal_Bool bRet = sal_False;
679 
680 	if( !!aBitmap )
681 	{
682 		bRet = aBitmap.Erase( rFillColor );
683 
684 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
685 		{
686 			// #104416# Respect transparency on fill color
687 			if( rFillColor.GetTransparency() )
688 			{
689 				const Color aFill( rFillColor.GetTransparency(), rFillColor.GetTransparency(), rFillColor.GetTransparency() );
690 				aMask.Erase( aFill );
691 			}
692 			else
693 			{
694 				const Color aBlack( COL_BLACK );
695 				aMask.Erase( aBlack );
696 			}
697 		}
698 	}
699 
700 	return bRet;
701 }
702 
703 // ------------------------------------------------------------------
704 
Dither(sal_uLong nDitherFlags)705 sal_Bool BitmapEx::Dither( sal_uLong nDitherFlags )
706 {
707 	return( !!aBitmap ? aBitmap.Dither( nDitherFlags ) : sal_False );
708 }
709 
710 // ------------------------------------------------------------------
711 
Replace(const Color & rSearchColor,const Color & rReplaceColor,sal_uLong nTol)712 sal_Bool BitmapEx::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
713 {
714 	return( !!aBitmap ? aBitmap.Replace( rSearchColor, rReplaceColor, nTol ) : sal_False );
715 }
716 
717 // ------------------------------------------------------------------
718 
Replace(const Color * pSearchColors,const Color * pReplaceColors,sal_uLong nColorCount,const sal_uLong * pTols)719 sal_Bool BitmapEx::Replace( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount, const sal_uLong* pTols )
720 {
721 	return( !!aBitmap ? aBitmap.Replace( pSearchColors, pReplaceColors, nColorCount, (sal_uLong*) pTols ) : sal_False );
722 }
723 
724 // ------------------------------------------------------------------
725 
Adjust(short nLuminancePercent,short nContrastPercent,short nChannelRPercent,short nChannelGPercent,short nChannelBPercent,double fGamma,sal_Bool bInvert)726 sal_Bool BitmapEx::Adjust( short nLuminancePercent, short nContrastPercent,
727 					   short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
728 					   double fGamma, sal_Bool bInvert )
729 {
730 	return( !!aBitmap ? aBitmap.Adjust( nLuminancePercent, nContrastPercent,
731 										nChannelRPercent, nChannelGPercent, nChannelBPercent,
732 										fGamma, bInvert ) : sal_False );
733 }
734 
735 // ------------------------------------------------------------------
736 
Filter(BmpFilter eFilter,const BmpFilterParam * pFilterParam,const Link * pProgress)737 sal_Bool BitmapEx::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress )
738 {
739 	return( !!aBitmap ? aBitmap.Filter( eFilter, pFilterParam, pProgress ) : sal_False );
740 }
741 
742 // ------------------------------------------------------------------
743 
Draw(OutputDevice * pOutDev,const Point & rDestPt) const744 void BitmapEx::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const
745 {
746 	pOutDev->DrawBitmapEx( rDestPt, *this );
747 }
748 
749 // ------------------------------------------------------------------
750 
Draw(OutputDevice * pOutDev,const Point & rDestPt,const Size & rDestSize) const751 void BitmapEx::Draw( OutputDevice* pOutDev,
752 					 const Point& rDestPt, const Size& rDestSize ) const
753 {
754 	pOutDev->DrawBitmapEx( rDestPt, rDestSize, *this );
755 }
756 
757 // ------------------------------------------------------------------
758 
Draw(OutputDevice * pOutDev,const Point & rDestPt,const Size & rDestSize,const Point & rSrcPtPixel,const Size & rSrcSizePixel) const759 void BitmapEx::Draw( OutputDevice* pOutDev,
760 					 const Point& rDestPt, const Size& rDestSize,
761 					 const Point& rSrcPtPixel, const Size& rSrcSizePixel ) const
762 {
763 	pOutDev->DrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, *this );
764 }
765 
766 // ------------------------------------------------------------------
767 
GetTransparency(sal_Int32 nX,sal_Int32 nY) const768 sal_uInt8 BitmapEx::GetTransparency(sal_Int32 nX, sal_Int32 nY) const
769 {
770 	sal_uInt8 nTransparency(0xff);
771 
772 	if(!aBitmap.IsEmpty())
773 	{
774 		if(nX >= 0 && nX < aBitmapSize.Width() && nY >= 0 && nY < aBitmapSize.Height())
775 		{
776 			switch(eTransparent)
777 			{
778 				case TRANSPARENT_NONE:
779 				{
780 					// not transparent, ergo all covered
781 					nTransparency = 0x00;
782 					break;
783 				}
784 				case TRANSPARENT_COLOR:
785 				{
786 					Bitmap aTestBitmap(aBitmap);
787 					BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
788 
789 					if(pRead)
790 					{
791 						const Color aColor = pRead->GetColor(nY, nX);
792 
793 						// if color is not equal to TransparentColor, we are not transparent
794 						if(aColor != aTransparentColor)
795 						{
796 							nTransparency = 0x00;
797 						}
798 
799 						aTestBitmap.ReleaseAccess(pRead);
800 					}
801 					break;
802 				}
803 				case TRANSPARENT_BITMAP:
804 				{
805 					if(!aMask.IsEmpty())
806 					{
807 						Bitmap aTestBitmap(aMask);
808 						BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
809 
810 						if(pRead)
811 						{
812 							const BitmapColor aBitmapColor(pRead->GetPixel(nY, nX));
813 
814 							if(bAlpha)
815 							{
816 								nTransparency = aBitmapColor.GetIndex();
817 							}
818 							else
819 							{
820 								if(0x00 == aBitmapColor.GetIndex())
821 								{
822 									nTransparency = 0x00;
823 								}
824 							}
825 
826 							aTestBitmap.ReleaseAccess(pRead);
827 						}
828 					}
829 					break;
830 				}
831 			}
832 		}
833 	}
834 
835 	return nTransparency;
836 }
837 
838 // ------------------------------------------------------------------
839 
840 namespace
841 {
impTransformBitmap(const Bitmap & rSource,const Size aDestinationSize,const basegfx::B2DHomMatrix & rTransform,bool bSmooth)842 	Bitmap impTransformBitmap(
843 		const Bitmap& rSource,
844 		const Size aDestinationSize,
845 		const basegfx::B2DHomMatrix& rTransform,
846 		bool bSmooth)
847 	{
848 		Bitmap aDestination(aDestinationSize, 24);
849 		BitmapWriteAccess* pWrite = aDestination.AcquireWriteAccess();
850 
851 		if(pWrite)
852 		{
853 			//const Size aContentSizePixel(rSource.GetSizePixel());
854 			BitmapReadAccess* pRead = (const_cast< Bitmap& >(rSource)).AcquireReadAccess();
855 
856 			if(pRead)
857 			{
858 				const Size aDestinationSizePixel(aDestination.GetSizePixel());
859 				const BitmapColor aOutside(BitmapColor(0xff, 0xff, 0xff));
860 
861 				for(sal_Int32 y(0L); y < aDestinationSizePixel.getHeight(); y++)
862 				{
863 					for(sal_Int32 x(0L); x < aDestinationSizePixel.getWidth(); x++)
864 					{
865 						const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y));
866 
867 						if(bSmooth)
868 						{
869 							pWrite->SetPixel(
870 								y,
871 								x,
872 								pRead->GetInterpolatedColorWithFallback(
873 									aSourceCoor.getY(),
874 									aSourceCoor.getX(),
875 									aOutside));
876 						}
877 						else
878 						{
879 							// this version does the correct <= 0.0 checks, so no need
880 							// to do the static_cast< sal_Int32 > self and make an error
881 							pWrite->SetPixel(
882 								y,
883 								x,
884 								pRead->GetColorWithFallback(
885 									aSourceCoor.getY(),
886 									aSourceCoor.getX(),
887 									aOutside));
888 						}
889 					}
890 				}
891 
892 				delete pRead;
893 			}
894 
895 			delete pWrite;
896 		}
897 
898 		rSource.AdaptBitCount(aDestination);
899 
900 		return aDestination;
901 	}
902 } // end of anonymous namespace
903 
TransformBitmapEx(double fWidth,double fHeight,const basegfx::B2DHomMatrix & rTransformation,bool bSmooth) const904 BitmapEx BitmapEx::TransformBitmapEx(
905 	double fWidth,
906 	double fHeight,
907 	const basegfx::B2DHomMatrix& rTransformation,
908 	bool bSmooth) const
909 {
910 	if(fWidth <= 1 || fHeight <= 1)
911 		return BitmapEx();
912 
913 	// force destination to 24 bit, we want to smooth output
914 	const Size aDestinationSize(basegfx::fround(fWidth), basegfx::fround(fHeight));
915 	const Bitmap aDestination(impTransformBitmap(GetBitmap(), aDestinationSize, rTransformation, bSmooth));
916 
917 	// create mask
918 	if(IsTransparent())
919 	{
920 		if(IsAlpha())
921 		{
922 			const Bitmap aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize, rTransformation, bSmooth));
923 			return BitmapEx(aDestination, AlphaMask(aAlpha));
924 		}
925 		else
926 		{
927 			const Bitmap aMask(impTransformBitmap(GetMask(), aDestinationSize, rTransformation, false));
928 			return BitmapEx(aDestination, aMask);
929 		}
930 	}
931 
932 	return BitmapEx(aDestination);
933 }
934 
935 // ------------------------------------------------------------------
936 
getTransformed(const basegfx::B2DHomMatrix & rTransformation,const basegfx::B2DRange & rVisibleRange,double fMaximumArea,bool bSmooth) const937 BitmapEx BitmapEx::getTransformed(
938 	const basegfx::B2DHomMatrix& rTransformation,
939 	const basegfx::B2DRange& rVisibleRange,
940 	double fMaximumArea,
941 	bool bSmooth) const
942 {
943 	BitmapEx aRetval;
944 
945 	if(IsEmpty())
946 		return aRetval;
947 
948 	const sal_uInt32 nSourceWidth(GetSizePixel().Width());
949 	const sal_uInt32 nSourceHeight(GetSizePixel().Height());
950 
951 	if(!nSourceWidth || !nSourceHeight)
952 		return aRetval;
953 
954 	// Get aOutlineRange
955 	basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0);
956 
957 	aOutlineRange.transform(rTransformation);
958 
959 	// create visible range from it by moving from relative to absolute
960 	basegfx::B2DRange aVisibleRange(rVisibleRange);
961 
962 	aVisibleRange.transform(
963 		basegfx::tools::createScaleTranslateB2DHomMatrix(
964 			aOutlineRange.getRange(),
965 			aOutlineRange.getMinimum()));
966 
967 	// get target size (which is visible range's size)
968 	double fWidth(aVisibleRange.getWidth());
969 	double fHeight(aVisibleRange.getHeight());
970 
971 	if(fWidth < 1.0 || fHeight < 1.0)
972 	{
973 		return aRetval;
974 	}
975 
976 	// test if discrete size (pixel) maybe too big and limit it
977 	const double fArea(fWidth * fHeight);
978 	const bool bNeedToReduce(basegfx::fTools::more(fArea, fMaximumArea));
979 	double fReduceFactor(1.0);
980 
981 	if(bNeedToReduce)
982 	{
983 		fReduceFactor = sqrt(fMaximumArea / fArea);
984 		fWidth *= fReduceFactor;
985 		fHeight *= fReduceFactor;
986 	}
987 
988 	// Build complete transform from source pixels to target pixels.
989 	// Start by scaling from source pixel size to unit coordinates
990 	basegfx::B2DHomMatrix aTransform(
991 		basegfx::tools::createScaleB2DHomMatrix(
992 			1.0 / nSourceWidth,
993 			1.0 / nSourceHeight));
994 
995 	// multiply with given transform which leads from unit coordinates inside
996 	// aOutlineRange
997 	aTransform = rTransformation * aTransform;
998 
999 	// subtract top-left of absolute VisibleRange
1000 	aTransform.translate(
1001 		-aVisibleRange.getMinX(),
1002 		-aVisibleRange.getMinY());
1003 
1004 	// scale to target pixels (if needed)
1005 	if(bNeedToReduce)
1006 	{
1007 		aTransform.scale(fReduceFactor, fReduceFactor);
1008 	}
1009 
1010 	// invert to get transformation from target pixel coordinates to source pixels
1011 	aTransform.invert();
1012 
1013 	// create bitmap using source, destination and linear back-transformation
1014 	aRetval = TransformBitmapEx(fWidth, fHeight, aTransform, bSmooth);
1015 
1016 	return aRetval;
1017 }
1018 
1019 // ------------------------------------------------------------------
1020 
ModifyBitmapEx(const basegfx::BColorModifierStack & rBColorModifierStack) const1021 BitmapEx BitmapEx::ModifyBitmapEx(const basegfx::BColorModifierStack& rBColorModifierStack) const
1022 {
1023 	Bitmap aChangedBitmap(GetBitmap());
1024 	bool bDone(false);
1025 
1026 	for(sal_uInt32 a(rBColorModifierStack.count()); a && !bDone; )
1027 	{
1028 		const basegfx::BColorModifierSharedPtr& rModifier = rBColorModifierStack.getBColorModifier(--a);
1029 		const basegfx::BColorModifier_replace* pReplace = dynamic_cast< const basegfx::BColorModifier_replace* >(rModifier.get());
1030 
1031 		if(pReplace)
1032 		{
1033 			// complete replace
1034 			if(IsTransparent())
1035 			{
1036 				// clear bitmap with dest color
1037 				if(aChangedBitmap.GetBitCount() <= 8)
1038 				{
1039 					// do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given
1040 					// erase color is determined and used -> this may be different from what is
1041 					// wanted here. Better create a new bitmap with the needed color explicitly
1042 					BitmapReadAccess* pReadAccess = aChangedBitmap.AcquireReadAccess();
1043 					OSL_ENSURE(pReadAccess, "Got no Bitmap ReadAccess ?!?");
1044 
1045 					if(pReadAccess)
1046 					{
1047 						BitmapPalette aNewPalette(pReadAccess->GetPalette());
1048 						aNewPalette[0] = BitmapColor(Color(pReplace->getBColor()));
1049 						aChangedBitmap = Bitmap(
1050 							aChangedBitmap.GetSizePixel(),
1051 							aChangedBitmap.GetBitCount(),
1052 							&aNewPalette);
1053 						delete pReadAccess;
1054 					}
1055 				}
1056 				else
1057 				{
1058 					aChangedBitmap.Erase(Color(pReplace->getBColor()));
1059 				}
1060 			}
1061 			else
1062 			{
1063 				// erase bitmap, caller will know to paint direct
1064 				aChangedBitmap.SetEmpty();
1065 			}
1066 
1067 			bDone = true;
1068 		}
1069 		else
1070 		{
1071 			BitmapWriteAccess* pContent = aChangedBitmap.AcquireWriteAccess();
1072 
1073 			if(pContent)
1074 			{
1075 				const double fConvertColor(1.0 / 255.0);
1076 
1077 				if(pContent->HasPalette())
1078 				{
1079 					const sal_uInt16 nCount(pContent->GetPaletteEntryCount());
1080 
1081 					for(sal_uInt16 a(0); a < nCount; a++)
1082 					{
1083 						const BitmapColor& rCol = pContent->GetPaletteColor(a);
1084 						const basegfx::BColor aBSource(
1085 							rCol.GetRed() * fConvertColor,
1086 							rCol.GetGreen() * fConvertColor,
1087 							rCol.GetBlue() * fConvertColor);
1088 						const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource));
1089 						pContent->SetPaletteColor(a, BitmapColor(Color(aBDest)));
1090 					}
1091 				}
1092 				else if(BMP_FORMAT_24BIT_TC_BGR == pContent->GetScanlineFormat())
1093 				{
1094 					for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
1095 					{
1096 						Scanline pScan = pContent->GetScanline(y);
1097 
1098 						for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
1099 						{
1100 							const basegfx::BColor aBSource(
1101 								*(pScan + 2)* fConvertColor,
1102 								*(pScan + 1) * fConvertColor,
1103 								*pScan * fConvertColor);
1104 							const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource));
1105 							*pScan++ = static_cast< sal_uInt8 >(aBDest.getBlue() * 255.0);
1106 							*pScan++ = static_cast< sal_uInt8 >(aBDest.getGreen() * 255.0);
1107 							*pScan++ = static_cast< sal_uInt8 >(aBDest.getRed() * 255.0);
1108 						}
1109 					}
1110 				}
1111 				else if(BMP_FORMAT_24BIT_TC_RGB == pContent->GetScanlineFormat())
1112 				{
1113 					for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
1114 					{
1115 						Scanline pScan = pContent->GetScanline(y);
1116 
1117 						for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
1118 						{
1119 							const basegfx::BColor aBSource(
1120 								*pScan * fConvertColor,
1121 								*(pScan + 1) * fConvertColor,
1122 								*(pScan + 2) * fConvertColor);
1123 							const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource));
1124 							*pScan++ = static_cast< sal_uInt8 >(aBDest.getRed() * 255.0);
1125 							*pScan++ = static_cast< sal_uInt8 >(aBDest.getGreen() * 255.0);
1126 							*pScan++ = static_cast< sal_uInt8 >(aBDest.getBlue() * 255.0);
1127 						}
1128 					}
1129 				}
1130 				else
1131 				{
1132 					for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
1133 					{
1134 						for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
1135 						{
1136 							const BitmapColor aBMCol(pContent->GetColor(y, x));
1137 							const basegfx::BColor aBSource(
1138 								(double)aBMCol.GetRed() * fConvertColor,
1139 								(double)aBMCol.GetGreen() * fConvertColor,
1140 								(double)aBMCol.GetBlue() * fConvertColor);
1141 							const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource));
1142 
1143 							pContent->SetPixel(y, x, BitmapColor(Color(aBDest)));
1144 						}
1145 					}
1146 				}
1147 
1148 				delete pContent;
1149 			}
1150 		}
1151 	}
1152 
1153 	if(aChangedBitmap.IsEmpty())
1154 	{
1155 		return BitmapEx();
1156 	}
1157 	else
1158 	{
1159 		if(IsTransparent())
1160 		{
1161 			if(IsAlpha())
1162 			{
1163 				return BitmapEx(aChangedBitmap, GetAlpha());
1164 			}
1165 			else
1166 			{
1167 				return BitmapEx(aChangedBitmap, GetMask());
1168 			}
1169 		}
1170 		else
1171 		{
1172 			return BitmapEx(aChangedBitmap);
1173 		}
1174 	}
1175 }
1176 
1177 // -----------------------------------------------------------------------------
1178 
createBlendFrame(const Size & rSize,sal_uInt8 nAlpha,Color aColorTopLeft,Color aColorBottomRight)1179 BitmapEx VCL_DLLPUBLIC createBlendFrame(
1180 	const Size& rSize,
1181 	sal_uInt8 nAlpha,
1182 	Color aColorTopLeft,
1183 	Color aColorBottomRight)
1184 {
1185 	const sal_uInt32 nW(rSize.Width());
1186 	const sal_uInt32 nH(rSize.Height());
1187 
1188 	if(nW || nH)
1189 	{
1190 		Color aColTopRight(aColorTopLeft);
1191 		Color aColBottomLeft(aColorTopLeft);
1192 		const sal_uInt32 nDE(nW + nH);
1193 
1194 		aColTopRight.Merge(aColorBottomRight, 255 - sal_uInt8((nW * 255) / nDE));
1195 		aColBottomLeft.Merge(aColorBottomRight, 255 - sal_uInt8((nH * 255) / nDE));
1196 
1197 		return createBlendFrame(rSize, nAlpha, aColorTopLeft, aColTopRight, aColorBottomRight, aColBottomLeft);
1198 	}
1199 
1200 	return BitmapEx();
1201 }
1202 
createBlendFrame(const Size & rSize,sal_uInt8 nAlpha,Color aColorTopLeft,Color aColorTopRight,Color aColorBottomRight,Color aColorBottomLeft)1203 BitmapEx VCL_DLLPUBLIC createBlendFrame(
1204 	const Size& rSize,
1205 	sal_uInt8 nAlpha,
1206 	Color aColorTopLeft,
1207 	Color aColorTopRight,
1208 	Color aColorBottomRight,
1209 	Color aColorBottomLeft)
1210 {
1211 	static Size aLastSize(0, 0);
1212 	static sal_uInt8 nLastAlpha(0);
1213 	static Color aLastColorTopLeft(COL_BLACK);
1214 	static Color aLastColorTopRight(COL_BLACK);
1215 	static Color aLastColorBottomRight(COL_BLACK);
1216 	static Color aLastColorBottomLeft(COL_BLACK);
1217 	static BitmapEx aLastResult;
1218 
1219 	if(aLastSize == rSize
1220 		&& nLastAlpha == nAlpha
1221 		&& aLastColorTopLeft == aColorTopLeft
1222 		&& aLastColorTopRight == aColorTopRight
1223 		&& aLastColorBottomRight == aColorBottomRight
1224 		&& aLastColorBottomLeft == aColorBottomLeft)
1225 	{
1226 		return aLastResult;
1227 	}
1228 
1229 	aLastSize = rSize;
1230 	nLastAlpha = nAlpha;
1231 	aLastColorTopLeft = aColorTopLeft;
1232 	aLastColorTopRight = aColorTopRight;
1233 	aLastColorBottomRight = aColorBottomRight;
1234 	aLastColorBottomLeft = aColorBottomLeft;
1235 	aLastResult.Clear();
1236 
1237 	const long nW(rSize.Width());
1238 	const long nH(rSize.Height());
1239 
1240 	if(nW && nH)
1241 	{
1242 		sal_uInt8 aEraseTrans(0xff);
1243 		Bitmap aContent(rSize, 24);
1244 		AlphaMask aAlpha(rSize, &aEraseTrans);
1245 
1246 		aContent.Erase(COL_BLACK);
1247 
1248 		BitmapWriteAccess* pContent = aContent.AcquireWriteAccess();
1249 		BitmapWriteAccess* pAlpha = aAlpha.AcquireWriteAccess();
1250 
1251 		if(pContent && pAlpha)
1252 		{
1253 			long x(0);
1254 			long y(0);
1255 
1256 			// x == 0, y == 0, top-left corner
1257 			pContent->SetPixel(0, 0, aColorTopLeft);
1258 			pAlpha->SetPixelIndex(0, 0, nAlpha);
1259 
1260 			// y == 0, top line left to right
1261 			for(x = 1; x < nW - 1; x++)
1262 			{
1263 				Color aMix(aColorTopLeft);
1264 
1265 				aMix.Merge(aColorTopRight, 255 - sal_uInt8((x * 255) / nW));
1266 				pContent->SetPixel(0, x, aMix);
1267 				pAlpha->SetPixelIndex(0, x, nAlpha);
1268 			}
1269 
1270 			// x == nW - 1, y == 0, top-right corner
1271 			// #123690# Caution! When nW is 1, x == nW is possible (!)
1272 			if(x < nW)
1273 			{
1274 				pContent->SetPixel(0, x, aColorTopRight);
1275 				pAlpha->SetPixelIndex(0, x, nAlpha);
1276 			}
1277 
1278 			// x == 0 and nW - 1, left and right line top-down
1279 			for(y = 1; y < nH - 1; y++)
1280 			{
1281 				Color aMixA(aColorTopLeft);
1282 
1283 				aMixA.Merge(aColorBottomLeft, 255 - sal_uInt8((y * 255) / nH));
1284 				pContent->SetPixel(y, 0, aMixA);
1285 				pAlpha->SetPixelIndex(y, 0, nAlpha);
1286 
1287 				// #123690# Caution! When nW is 1, x == nW is possible (!)
1288 				if(x < nW)
1289 				{
1290 					Color aMixB(aColorTopRight);
1291 
1292 					aMixB.Merge(aColorBottomRight, 255 - sal_uInt8((y * 255) / nH));
1293 					pContent->SetPixel(y, x, aMixB);
1294 					pAlpha->SetPixelIndex(y, x, nAlpha);
1295 				}
1296 			}
1297 
1298 			// #123690# Caution! When nH is 1, y == nH is possible (!)
1299 			if(y < nH)
1300 			{
1301 				// x == 0, y == nH - 1, bottom-left corner
1302 				pContent->SetPixel(y, 0, aColorBottomLeft);
1303 				pAlpha->SetPixelIndex(y, 0, nAlpha);
1304 
1305 				// y == nH - 1, bottom line left to right
1306 				for(x = 1; x < nW - 1; x++)
1307 				{
1308 					Color aMix(aColorBottomLeft);
1309 
1310 					aMix.Merge(aColorBottomRight, 255 - sal_uInt8(((x - 0)* 255) / nW));
1311 					pContent->SetPixel(y, x, aMix);
1312 					pAlpha->SetPixelIndex(y, x, nAlpha);
1313 				}
1314 
1315 				// x == nW - 1, y == nH - 1, bottom-right corner
1316 				// #123690# Caution! When nW is 1, x == nW is possible (!)
1317 				if(x < nW)
1318 				{
1319 					pContent->SetPixel(y, x, aColorBottomRight);
1320 					pAlpha->SetPixelIndex(y, x, nAlpha);
1321 				}
1322 			}
1323 
1324 			aContent.ReleaseAccess(pContent);
1325 			aAlpha.ReleaseAccess(pAlpha);
1326 
1327 			aLastResult = BitmapEx(aContent, aAlpha);
1328 		}
1329 		else
1330 		{
1331 			if(pContent)
1332 			{
1333 				aContent.ReleaseAccess(pContent);
1334 			}
1335 
1336 			if(pAlpha)
1337 			{
1338 				aAlpha.ReleaseAccess(pAlpha);
1339 			}
1340 		}
1341 	}
1342 
1343 	return aLastResult;
1344 }
1345 
1346 /* vim: set noet sw=4 ts=4: */
1347