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