xref: /trunk/main/vcl/source/gdi/image.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 // MARKER(update_precomp.py): autogen include statement, do not remove
28 #include "precompiled_vcl.hxx"
29 
30 #include <boost/scoped_ptr.hpp>
31 #include <boost/scoped_array.hpp>
32 
33 #include <rtl/logfile.hxx>
34 
35 #include <tools/debug.hxx>
36 #include <tools/stream.hxx>
37 #include <tools/rc.h>
38 #include <tools/rc.hxx>
39 #include <tools/resmgr.hxx>
40 
41 #include <vcl/settings.hxx>
42 #include <vcl/outdev.hxx>
43 #include <vcl/graph.hxx>
44 #include <vcl/svapp.hxx>
45 #include <vcl/image.hxx>
46 
47 #include <impimagetree.hxx>
48 #include <image.h>
49 
50 #if OSL_DEBUG_LEVEL > 0
51 #include <rtl/strbuf.hxx>
52 #endif
53 
54 DBG_NAME( Image )
55 DBG_NAME( ImageList )
56 
57 #define IMAGE_FILE_VERSION 100
58 
59 using namespace ::com::sun::star;
60 
61 // ---------
62 // - Image -
63 // ---------
64 
65 Image::Image() :
66     mpImplData( NULL )
67 {
68     DBG_CTOR( Image, NULL );
69 }
70 
71 // -----------------------------------------------------------------------
72 
73 Image::Image( const ResId& rResId ) :
74     mpImplData( NULL )
75 {
76     DBG_CTOR( Image, NULL );
77 
78     rResId.SetRT( RSC_IMAGE );
79 
80     ResMgr* pResMgr = rResId.GetResMgr();
81     if( pResMgr && pResMgr->GetResource( rResId ) )
82     {
83         pResMgr->Increment( sizeof( RSHEADER_TYPE ) );
84 
85         BitmapEx    aBmpEx;
86         sal_uLong       nObjMask = pResMgr->ReadLong();
87 
88         if( nObjMask & RSC_IMAGE_IMAGEBITMAP )
89         {
90             aBmpEx = BitmapEx( ResId( (RSHEADER_TYPE*)pResMgr->GetClass(), *pResMgr ) );
91             pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) );
92         }
93 
94         if( nObjMask & RSC_IMAGE_MASKBITMAP )
95         {
96             if( !aBmpEx.IsEmpty() && aBmpEx.GetTransparentType() == TRANSPARENT_NONE )
97             {
98                 const Bitmap aMaskBitmap( ResId( (RSHEADER_TYPE*)pResMgr->GetClass(), *pResMgr ) );
99                 aBmpEx = BitmapEx( aBmpEx.GetBitmap(), aMaskBitmap );
100             }
101 
102             pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) );
103         }
104 
105         if( nObjMask & RSC_IMAGE_MASKCOLOR )
106         {
107             if( !aBmpEx.IsEmpty() && aBmpEx.GetTransparentType() == TRANSPARENT_NONE )
108             {
109                 const Color aMaskColor( ResId( (RSHEADER_TYPE*)pResMgr->GetClass(), *pResMgr ) );
110                 aBmpEx = BitmapEx( aBmpEx.GetBitmap(), aMaskColor );
111             }
112 
113             pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) );
114         }
115         if( ! aBmpEx.IsEmpty() )
116             ImplInit( aBmpEx );
117     }
118 }
119 
120 // -----------------------------------------------------------------------
121 
122 Image::Image( const Image& rImage ) :
123     mpImplData( rImage.mpImplData )
124 {
125     DBG_CTOR( Image, NULL );
126 
127     if( mpImplData )
128         ++mpImplData->mnRefCount;
129 }
130 
131 // -----------------------------------------------------------------------
132 
133 Image::Image( const BitmapEx& rBitmapEx ) :
134     mpImplData( NULL )
135 {
136     DBG_CTOR( Image, NULL );
137 
138     ImplInit( rBitmapEx );
139 }
140 
141 // -----------------------------------------------------------------------
142 
143 Image::Image( const Bitmap& rBitmap ) :
144     mpImplData( NULL )
145 {
146     DBG_CTOR( Image, NULL );
147 
148     ImplInit( rBitmap );
149 }
150 
151 // -----------------------------------------------------------------------
152 
153 Image::Image( const Bitmap& rBitmap, const Bitmap& rMaskBitmap ) :
154     mpImplData( NULL )
155 {
156     DBG_CTOR( Image, NULL );
157 
158     const BitmapEx aBmpEx( rBitmap, rMaskBitmap );
159 
160     ImplInit( aBmpEx );
161 }
162 
163 // -----------------------------------------------------------------------
164 
165 Image::Image( const Bitmap& rBitmap, const Color& rColor ) :
166     mpImplData( NULL )
167 {
168     DBG_CTOR( Image, NULL );
169 
170     const BitmapEx aBmpEx( rBitmap, rColor );
171 
172     ImplInit( aBmpEx );
173 }
174 
175 // -----------------------------------------------------------------------
176 
177 Image::Image( const uno::Reference< graphic::XGraphic >& rxGraphic ) :
178     mpImplData( NULL )
179 {
180     DBG_CTOR( Image, NULL );
181 
182     const Graphic aGraphic( rxGraphic );
183     ImplInit( aGraphic.GetBitmapEx() );
184 }
185 
186 // -----------------------------------------------------------------------
187 
188 Image::~Image()
189 {
190     DBG_DTOR( Image, NULL );
191 
192     if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
193         delete mpImplData;
194 }
195 
196 // -----------------------------------------------------------------------
197 
198 void Image::ImplInit( const BitmapEx& rBmpEx )
199 {
200     if( !rBmpEx.IsEmpty() )
201     {
202         mpImplData = new ImplImage;
203         mpImplData->mnRefCount = 1;
204 
205         if( rBmpEx.GetTransparentType() == TRANSPARENT_NONE )
206         {
207             mpImplData->meType = IMAGETYPE_BITMAP;
208             mpImplData->mpData = new Bitmap( rBmpEx.GetBitmap() );
209         }
210         else
211         {
212             mpImplData->meType = IMAGETYPE_IMAGE;
213             mpImplData->mpData = new ImplImageData( rBmpEx );
214         }
215     }
216 }
217 
218 // -----------------------------------------------------------------------
219 
220 Size Image::GetSizePixel() const
221 {
222     DBG_CHKTHIS( Image, NULL );
223 
224     Size aRet;
225 
226     if( mpImplData )
227     {
228         switch( mpImplData->meType )
229         {
230             case IMAGETYPE_BITMAP:
231                 aRet = static_cast< Bitmap* >( mpImplData->mpData )->GetSizePixel();
232             break;
233 
234             case IMAGETYPE_IMAGE:
235                 aRet = static_cast< ImplImageData* >( mpImplData->mpData )->maBmpEx.GetSizePixel();
236             break;
237         }
238     }
239 
240     return aRet;
241 }
242 
243 // -----------------------------------------------------------------------
244 
245 BitmapEx Image::GetBitmapEx() const
246 {
247     DBG_CHKTHIS( Image, NULL );
248 
249     BitmapEx aRet;
250 
251     if( mpImplData )
252     {
253         switch( mpImplData->meType )
254         {
255             case IMAGETYPE_BITMAP:
256                 aRet = *static_cast< Bitmap* >( mpImplData->mpData );
257             break;
258 
259             case IMAGETYPE_IMAGE:
260                 aRet = static_cast< ImplImageData* >( mpImplData->mpData )->maBmpEx;
261             break;
262         }
263     }
264 
265     return aRet;
266 }
267 
268 // -----------------------------------------------------------------------
269 
270 uno::Reference< graphic::XGraphic > Image::GetXGraphic() const
271 {
272     const Graphic aGraphic( GetBitmapEx() );
273 
274     return aGraphic.GetXGraphic();
275 }
276 
277 // -----------------------------------------------------------------------
278 
279 Image Image::GetColorTransformedImage( ImageColorTransform eColorTransform ) const
280 {
281     DBG_CHKTHIS( Image, NULL );
282 
283     Image aRet;
284 
285     if( IMAGECOLORTRANSFORM_HIGHCONTRAST == eColorTransform )
286     {
287         BitmapEx aBmpEx( GetBitmapEx() );
288 
289         if( !aBmpEx.IsEmpty() )
290         {
291             Color*  pSrcColors = NULL;
292             Color*  pDstColors = NULL;
293             sal_uLong   nColorCount = 0;
294 
295             Image::GetColorTransformArrays( eColorTransform, pSrcColors, pDstColors, nColorCount );
296 
297             if( nColorCount && pSrcColors && pDstColors )
298             {
299                 aBmpEx.Replace( pSrcColors, pDstColors, nColorCount );
300                 aRet = Image( aBmpEx );
301             }
302 
303             delete[] pSrcColors;
304             delete[] pDstColors;
305         }
306     }
307     else if( IMAGECOLORTRANSFORM_MONOCHROME_BLACK == eColorTransform ||
308              IMAGECOLORTRANSFORM_MONOCHROME_WHITE == eColorTransform  )
309     {
310         BitmapEx aBmpEx( GetBitmapEx() );
311 
312         if( !aBmpEx.IsEmpty() )
313             aRet = Image( aBmpEx.GetColorTransformedBitmapEx( ( BmpColorMode )( eColorTransform ) ) );
314     }
315 
316     if( !aRet )
317         aRet = *this;
318 
319     return aRet;
320 }
321 
322 // -----------------------------------------------------------------------
323 
324 void Image::Invert()
325 {
326     BitmapEx aInvertedBmp( GetBitmapEx() );
327     aInvertedBmp.Invert();
328     *this = aInvertedBmp;
329 }
330 
331 // -----------------------------------------------------------------------
332 
333 void Image::GetColorTransformArrays( ImageColorTransform eColorTransform,
334                                      Color*& rpSrcColor, Color*& rpDstColor, sal_uLong& rColorCount )
335 {
336     if( IMAGECOLORTRANSFORM_HIGHCONTRAST == eColorTransform )
337     {
338         rpSrcColor = new Color[ 4 ];
339         rpDstColor = new Color[ 4 ];
340         rColorCount = 4;
341 
342         rpSrcColor[ 0 ] = Color( COL_BLACK );
343         rpDstColor[ 0 ] = Color( COL_WHITE );
344 
345         rpSrcColor[ 1 ] = Color( COL_WHITE );
346         rpDstColor[ 1 ] = Color( COL_BLACK );
347 
348         rpSrcColor[ 2 ] = Color( COL_BLUE );
349         rpDstColor[ 2 ] = Color( COL_WHITE );
350 
351         rpSrcColor[ 3 ] = Color( COL_LIGHTBLUE );
352         rpDstColor[ 3 ] = Color( COL_WHITE );
353     }
354     else
355     {
356         rpSrcColor = rpDstColor = NULL;
357         rColorCount = 0;
358     }
359 }
360 
361 // -----------------------------------------------------------------------
362 
363 Image& Image::operator=( const Image& rImage )
364 {
365     DBG_CHKTHIS( Image, NULL );
366     DBG_CHKOBJ( &rImage, Image, NULL );
367 
368     if( rImage.mpImplData )
369         ++rImage.mpImplData->mnRefCount;
370 
371     if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
372         delete mpImplData;
373 
374     mpImplData = rImage.mpImplData;
375 
376     return *this;
377 }
378 
379 // -----------------------------------------------------------------------
380 
381 sal_Bool Image::operator==( const Image& rImage ) const
382 {
383     DBG_CHKTHIS( Image, NULL );
384     DBG_CHKOBJ( &rImage, Image, NULL );
385 
386     bool bRet = false;
387 
388     if( rImage.mpImplData == mpImplData )
389         bRet = true;
390     else if( !rImage.mpImplData || !mpImplData )
391         bRet = false;
392     else if( rImage.mpImplData->mpData == mpImplData->mpData )
393         bRet = true;
394     else if( rImage.mpImplData->meType == mpImplData->meType )
395     {
396         switch( mpImplData->meType )
397         {
398             case IMAGETYPE_BITMAP:
399                 bRet = ( *static_cast< Bitmap* >( rImage.mpImplData->mpData ) == *static_cast< Bitmap* >( mpImplData->mpData ) );
400             break;
401 
402             case IMAGETYPE_IMAGE:
403                 bRet = static_cast< ImplImageData* >( rImage.mpImplData->mpData )->IsEqual( *static_cast< ImplImageData* >( mpImplData->mpData ) );
404             break;
405 
406             default:
407                 bRet = false;
408             break;
409         }
410     }
411 
412     return bRet;
413 }
414 
415 // -------------
416 // - ImageList -
417 // -------------
418 
419 ImageList::ImageList( sal_uInt16 nInit, sal_uInt16 nGrow ) :
420     mpImplData( NULL ),
421     mnInitSize( nInit ),
422     mnGrowSize( nGrow )
423 {
424     DBG_CTOR( ImageList, NULL );
425 }
426 
427 // -----------------------------------------------------------------------
428 
429 ImageList::ImageList( const ResId& rResId ) :
430     mpImplData( NULL ),
431     mnInitSize( 1 ),
432     mnGrowSize( 4 )
433 {
434     RTL_LOGFILE_CONTEXT( aLog, "vcl: ImageList::ImageList( const ResId& rResId )" );
435 
436     DBG_CTOR( ImageList, NULL );
437 
438     rResId.SetRT( RSC_IMAGELIST );
439 
440     ResMgr* pResMgr = rResId.GetResMgr();
441 
442     if( pResMgr && pResMgr->GetResource( rResId ) )
443     {
444         pResMgr->Increment( sizeof( RSHEADER_TYPE ) );
445 
446         sal_uLong                               nObjMask = pResMgr->ReadLong();
447         const String                        aPrefix( pResMgr->ReadString() );
448         ::boost::scoped_ptr< Color >        spMaskColor;
449 
450         if( nObjMask & RSC_IMAGE_MASKCOLOR )
451             spMaskColor.reset( new Color( ResId( (RSHEADER_TYPE*)pResMgr->GetClass(), *pResMgr ) ) );
452 
453         pResMgr->Increment( pResMgr->GetObjSize( (RSHEADER_TYPE*)pResMgr->GetClass() ) );
454 
455         if( nObjMask & RSC_IMAGELIST_IDLIST )
456         {
457             for( sal_Int32 i = 0, nCount = pResMgr->ReadLong(); i < nCount; ++i )
458                 pResMgr->ReadLong();
459         }
460 
461         sal_Int32 nCount = pResMgr->ReadLong();
462         ImplInit( static_cast< sal_uInt16 >( nCount ), Size() );
463 
464         BitmapEx aEmpty;
465         for( sal_Int32 i = 0; i < nCount; ++i )
466         {
467             rtl::OUString aName = pResMgr->ReadString();
468             sal_uInt16 nId = static_cast< sal_uInt16 >( pResMgr->ReadLong() );
469             mpImplData->AddImage( aName, nId, aEmpty );
470         }
471 
472         if( nObjMask & RSC_IMAGELIST_IDCOUNT )
473             pResMgr->ReadShort();
474     }
475 }
476 
477 // -----------------------------------------------------------------------
478 
479 ImageList::ImageList( const ::std::vector< ::rtl::OUString >& rNameVector,
480                       const ::rtl::OUString& rPrefix,
481                       const Color* ) :
482     mpImplData( NULL ),
483     mnInitSize( 1 ),
484     mnGrowSize( 4 )
485 {
486     RTL_LOGFILE_CONTEXT( aLog, "vcl: ImageList::ImageList(const vector< OUString >& ..." );
487 
488     DBG_CTOR( ImageList, NULL );
489 
490     ImplInit( sal::static_int_cast< sal_uInt16 >( rNameVector.size() ), Size() );
491 
492     mpImplData->maPrefix = rPrefix;
493     for( sal_uInt32 i = 0; i < rNameVector.size(); ++i )
494     {
495 //      fprintf (stderr, "List %p [%d]: '%s'\n",
496 //               this, i, rtl::OUStringToOString( rNameVector[i], RTL_TEXTENCODING_UTF8 ).getStr() );
497         mpImplData->AddImage( rNameVector[ i ], static_cast< sal_uInt16 >( i ) + 1, BitmapEx() );
498     }
499 }
500 
501 // -----------------------------------------------------------------------
502 
503 ImageList::ImageList( const ImageList& rImageList ) :
504     mpImplData( rImageList.mpImplData ),
505     mnInitSize( rImageList.mnInitSize ),
506     mnGrowSize( rImageList.mnGrowSize )
507 {
508     DBG_CTOR( ImageList, NULL );
509 
510     if( mpImplData )
511         ++mpImplData->mnRefCount;
512 }
513 
514 // -----------------------------------------------------------------------
515 
516 ImageList::~ImageList()
517 {
518     DBG_DTOR( ImageList, NULL );
519 
520     if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
521         delete mpImplData;
522 }
523 
524 void ImageList::ImplInit( sal_uInt16 nItems, const Size &rSize )
525 {
526     mpImplData = new ImplImageList;
527     mpImplData->mnRefCount = 1;
528     mpImplData->maImages.reserve( nItems );
529     mpImplData->maImageSize = rSize;
530 }
531 
532 // -----------------------------------------------------------------------
533 
534 void ImageAryData::Load(const rtl::OUString &rPrefix)
535 {
536     static ImplImageTreeSingletonRef aImageTree;
537 
538     ::rtl::OUString aSymbolsStyle = Application::GetSettings().GetStyleSettings().GetCurrentSymbolsStyleName();
539 
540     BitmapEx aBmpEx;
541 
542 //  fprintf (stderr, "Attempt load of '%s'\n",
543 //           rtl::OUStringToOString( maName, RTL_TEXTENCODING_UTF8 ).getStr() );
544 
545     rtl::OUString aFileName = rPrefix;
546     aFileName += maName;
547 #if OSL_DEBUG_LEVEL > 0
548     bool bSuccess =
549 #endif
550         aImageTree->loadImage( aFileName, aSymbolsStyle, maBitmapEx, true );
551 #if OSL_DEBUG_LEVEL > 0
552     if ( !bSuccess )
553     {
554         ::rtl::OStringBuffer aMessage;
555         aMessage.append( "ImageAryData::Load: failed to load image '" );
556         aMessage.append( ::rtl::OUStringToOString( aFileName, RTL_TEXTENCODING_UTF8 ).getStr() );
557         aMessage.append( "'" );
558         OSL_ENSURE( false, aMessage.makeStringAndClear().getStr() );
559     }
560 #endif
561 }
562 
563 // -----------------------------------------------------------------------
564 
565 void ImageList::ImplMakeUnique()
566 {
567     if( mpImplData && mpImplData->mnRefCount > 1 )
568     {
569         --mpImplData->mnRefCount;
570         mpImplData = new ImplImageList( *mpImplData ) ;
571     }
572 }
573 
574 // -----------------------------------------------------------------------
575 // Rather a performance hazard:
576 BitmapEx ImageList::GetAsHorizontalStrip() const
577 {
578     Size aSize( mpImplData->maImageSize );
579     sal_uInt16 nCount = GetImageCount();
580     if( !nCount )
581         return BitmapEx();
582     aSize.Width() *= nCount;
583 
584     // Load any stragglers
585     for (sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++)
586     {
587         ImageAryData *pData = mpImplData->maImages[ nIdx ];
588         if( pData->IsLoadable() )
589             pData->Load( mpImplData->maPrefix );
590     }
591 
592     BitmapEx aTempl = mpImplData->maImages[ 0 ]->maBitmapEx;
593     BitmapEx aResult;
594     Bitmap aPixels( aSize, aTempl.GetBitmap().GetBitCount() );
595     if( aTempl.IsAlpha() )
596         aResult = BitmapEx( aPixels, AlphaMask( aSize ) );
597     else if( aTempl.IsTransparent() )
598         aResult = BitmapEx( aPixels, Bitmap( aSize, aTempl.GetMask().GetBitCount() ) );
599     else
600         aResult = BitmapEx( aPixels );
601 
602     Rectangle aSrcRect( Point( 0, 0 ), mpImplData->maImageSize );
603     for (sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++)
604     {
605         Rectangle aDestRect( Point( nIdx * mpImplData->maImageSize.Width(), 0 ),
606                              mpImplData->maImageSize );
607         ImageAryData *pData = mpImplData->maImages[ nIdx ];
608         aResult.CopyPixel( aDestRect, aSrcRect, &pData->maBitmapEx);
609     }
610 
611     return aResult;
612 }
613 
614 // -----------------------------------------------------------------------
615 
616 void ImageList::InsertFromHorizontalStrip( const BitmapEx &rBitmapEx,
617                                            const std::vector< rtl::OUString > &rNameVector )
618 {
619     sal_uInt16 nItems = sal::static_int_cast< sal_uInt16 >( rNameVector.size() );
620 
621 //  fprintf (stderr, "InsertFromHorizontalStrip (1) [%d items]\n", nItems);
622 
623     if (!nItems)
624             return;
625 
626     Size aSize( rBitmapEx.GetSizePixel() );
627     DBG_ASSERT (rBitmapEx.GetSizePixel().Width() % nItems == 0,
628                 "ImageList::InsertFromHorizontalStrip - very odd size");
629     aSize.Width() /= nItems;
630     ImplInit( nItems, aSize );
631 
632     for (sal_uInt16 nIdx = 0; nIdx < nItems; nIdx++)
633     {
634         BitmapEx aBitmap( rBitmapEx, Point( nIdx * aSize.Width(), 0 ), aSize );
635         mpImplData->AddImage( rNameVector[ nIdx ], nIdx + 1, aBitmap );
636     }
637 }
638 
639 // -----------------------------------------------------------------------
640 
641 void ImageList::InsertFromHorizontalBitmap( const ResId& rResId,
642                                             sal_uInt16       nCount,
643                                             const Color *pMaskColor,
644                                             const Color *pSearchColors,
645                                             const Color *pReplaceColors,
646                                             sal_uLong        nColorCount)
647 {
648     BitmapEx aBmpEx( rResId );
649     if (!aBmpEx.IsTransparent())
650     {
651         if( pMaskColor )
652             aBmpEx = BitmapEx( aBmpEx.GetBitmap(), *pMaskColor );
653         else
654             aBmpEx = BitmapEx( aBmpEx.GetBitmap() );
655     }
656     if ( nColorCount && pSearchColors && pReplaceColors )
657         aBmpEx.Replace( pSearchColors, pReplaceColors, nColorCount );
658 
659     std::vector< rtl::OUString > aNames( nCount );
660     InsertFromHorizontalStrip( aBmpEx, aNames );
661 }
662 
663 // -----------------------------------------------------------------------
664 
665 sal_uInt16 ImageList::ImplGetImageId( const ::rtl::OUString& rImageName ) const
666 {
667     DBG_CHKTHIS( ImageList, NULL );
668 
669     ImageAryData *pImg = mpImplData->maNameHash[ rImageName ];
670     if( pImg )
671         return pImg->mnId;
672     else
673         return 0;
674 }
675 
676 // -----------------------------------------------------------------------
677 
678 void ImageList::AddImage( sal_uInt16 nId, const Image& rImage )
679 {
680     DBG_CHKTHIS( ImageList, NULL );
681     DBG_CHKOBJ( &rImage, Image, NULL );
682     DBG_ASSERT( nId, "ImageList::AddImage(): ImageId == 0" );
683     DBG_ASSERT( GetImagePos( nId ) == IMAGELIST_IMAGE_NOTFOUND, "ImageList::AddImage() - ImageId already exists" );
684     DBG_ASSERT( rImage.mpImplData, "ImageList::AddImage(): Wrong Size" );
685     DBG_ASSERT( !mpImplData || (rImage.GetSizePixel() == mpImplData->maImageSize), "ImageList::AddImage(): Wrong Size" );
686 
687     if( !mpImplData )
688         ImplInit( 0, rImage.GetSizePixel() );
689 
690     mpImplData->AddImage( rtl::OUString(), nId, rImage.GetBitmapEx());
691 }
692 
693 // -----------------------------------------------------------------------
694 
695 void ImageList::AddImage( const ::rtl::OUString& rImageName, const Image& rImage )
696 {
697     DBG_ASSERT( GetImagePos( rImageName ) == IMAGELIST_IMAGE_NOTFOUND, "ImageList::AddImage() - ImageName already exists" );
698 
699     if( !mpImplData )
700         ImplInit( 0, rImage.GetSizePixel() );
701 
702     mpImplData->AddImage( rImageName, GetImageCount() + 1,
703                           rImage.GetBitmapEx() );
704 }
705 
706 // -----------------------------------------------------------------------
707 
708 void ImageList::ReplaceImage( sal_uInt16 nId, const Image& rImage )
709 {
710     DBG_CHKTHIS( ImageList, NULL );
711     DBG_CHKOBJ( &rImage, Image, NULL );
712     DBG_ASSERT( GetImagePos( nId ) != IMAGELIST_IMAGE_NOTFOUND, "ImageList::ReplaceImage(): Unknown nId" );
713 
714     RemoveImage( nId );
715     AddImage( nId, rImage );
716 }
717 
718 // -----------------------------------------------------------------------
719 
720 void ImageList::ReplaceImage( const ::rtl::OUString& rImageName, const Image& rImage )
721 {
722     const sal_uInt16 nId = ImplGetImageId( rImageName );
723 
724     if( nId )
725     {
726         RemoveImage( nId );
727 
728         if( !mpImplData )
729             ImplInit( 0, rImage.GetSizePixel() );
730         mpImplData->AddImage( rImageName, nId, rImage.GetBitmapEx());
731     }
732 }
733 
734 // -----------------------------------------------------------------------
735 
736 void ImageList::ReplaceImage( sal_uInt16 nId, sal_uInt16 nReplaceId )
737 {
738     DBG_CHKTHIS( ImageList, NULL );
739     DBG_ASSERT( GetImagePos( nId ) != IMAGELIST_IMAGE_NOTFOUND, "ImageList::ReplaceImage(): Unknown nId" );
740     DBG_ASSERT( GetImagePos( nReplaceId ) != IMAGELIST_IMAGE_NOTFOUND, "ImageList::ReplaceImage(): Unknown nReplaceId" );
741 
742     sal_uLong nPosDest = GetImagePos( nId );
743     sal_uLong nPosSrc = GetImagePos( nReplaceId );
744     if( nPosDest != IMAGELIST_IMAGE_NOTFOUND &&
745         nPosSrc != IMAGELIST_IMAGE_NOTFOUND )
746     {
747         ImplMakeUnique();
748         mpImplData->maImages[nPosDest] = mpImplData->maImages[nPosSrc];
749     }
750 }
751 
752 // -----------------------------------------------------------------------
753 
754 void ImageList::ReplaceImage( const ::rtl::OUString& rImageName, const ::rtl::OUString& rReplaceName )
755 {
756     const sal_uInt16 nId1 = ImplGetImageId( rImageName ), nId2 = ImplGetImageId( rReplaceName );
757 
758     if( nId1 && nId2 )
759         ReplaceImage( nId1, nId2 );
760 }
761 
762 // -----------------------------------------------------------------------
763 
764 void ImageList::RemoveImage( sal_uInt16 nId )
765 {
766     DBG_CHKTHIS( ImageList, NULL );
767 
768     for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); ++i )
769     {
770         if( mpImplData->maImages[ i ]->mnId == nId )
771         {
772             mpImplData->RemoveImage( static_cast< sal_uInt16 >( i ) );
773             break;
774         }
775     }
776 }
777 
778 // -----------------------------------------------------------------------
779 
780 void ImageList::RemoveImage( const ::rtl::OUString& rImageName )
781 {
782     const sal_uInt16 nId = ImplGetImageId( rImageName );
783 
784     if( nId )
785         RemoveImage( nId );
786 }
787 
788 // -----------------------------------------------------------------------
789 
790 Image ImageList::GetImage( sal_uInt16 nId ) const
791 {
792     DBG_CHKTHIS( ImageList, NULL );
793 
794 //  fprintf (stderr, "GetImage %d\n", nId);
795 
796     Image aRet;
797 
798     if( mpImplData )
799     {
800         std::vector<ImageAryData *>::iterator aIter;
801         for( aIter = mpImplData->maImages.begin();
802              aIter != mpImplData->maImages.end(); aIter++)
803         {
804             if ((*aIter)->mnId == nId)
805             {
806                 if( (*aIter)->IsLoadable() )
807                     (*aIter)->Load( mpImplData->maPrefix );
808 
809                 aRet = Image( (*aIter)->maBitmapEx );
810             }
811         }
812     }
813 
814     return aRet;
815 }
816 
817 // -----------------------------------------------------------------------
818 
819 Image ImageList::GetImage( const ::rtl::OUString& rImageName ) const
820 {
821 //  fprintf (stderr, "GetImage '%s'\n",
822 //           rtl::OUStringToOString( rImageName, RTL_TEXTENCODING_UTF8 ).getStr() );
823 
824     if( mpImplData )
825     {
826         ImageAryData *pImg = mpImplData->maNameHash[ rImageName ];
827 
828         if( pImg )
829         {
830             if( pImg->IsLoadable() )
831                 pImg->Load( mpImplData->maPrefix );
832             return Image( pImg->maBitmapEx );
833         }
834     }
835 //  fprintf (stderr, "no such image\n");
836 
837     return Image();
838 }
839 
840 // -----------------------------------------------------------------------
841 
842 void ImageList::Clear()
843 {
844     DBG_CHKTHIS( ImageList, NULL );
845 
846     if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
847         delete mpImplData;
848 
849     mpImplData = NULL;
850 }
851 
852 // -----------------------------------------------------------------------
853 
854 sal_uInt16 ImageList::GetImageCount() const
855 {
856     DBG_CHKTHIS( ImageList, NULL );
857 
858     return mpImplData ? static_cast< sal_uInt16 >( mpImplData->maImages.size() ) : 0;
859 }
860 
861 // -----------------------------------------------------------------------
862 
863 sal_uInt16 ImageList::GetImagePos( sal_uInt16 nId ) const
864 {
865     DBG_CHKTHIS( ImageList, NULL );
866 
867     if( mpImplData && nId )
868     {
869         for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); ++i )
870         {
871             if (mpImplData->maImages[ i ]->mnId == nId)
872                 return static_cast< sal_uInt16 >( i );
873         }
874     }
875 
876     return IMAGELIST_IMAGE_NOTFOUND;
877 }
878 
879 bool ImageList::HasImageAtPos( sal_uInt16 nId ) const
880 {
881     return GetImagePos( nId ) != IMAGELIST_IMAGE_NOTFOUND;
882 }
883 
884 // -----------------------------------------------------------------------
885 
886 sal_uInt16 ImageList::GetImagePos( const ::rtl::OUString& rImageName ) const
887 {
888     DBG_CHKTHIS( ImageList, NULL );
889 
890     if( mpImplData && rImageName.getLength() )
891     {
892         for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); i++ )
893         {
894             if (mpImplData->maImages[i]->maName == rImageName)
895                 return static_cast< sal_uInt16 >( i );
896         }
897     }
898 
899     return IMAGELIST_IMAGE_NOTFOUND;
900 }
901 
902 // -----------------------------------------------------------------------
903 
904 sal_uInt16 ImageList::GetImageId( sal_uInt16 nPos ) const
905 {
906     DBG_CHKTHIS( ImageList, NULL );
907 
908     if( mpImplData && (nPos < GetImageCount()) )
909         return mpImplData->maImages[ nPos ]->mnId;
910 
911     return 0;
912 }
913 
914 // -----------------------------------------------------------------------
915 
916 void ImageList::GetImageIds( ::std::vector< sal_uInt16 >& rIds ) const
917 {
918     RTL_LOGFILE_CONTEXT( aLog, "vcl: ImageList::GetImageIds" );
919 
920     DBG_CHKTHIS( ImageList, NULL );
921 
922     rIds = ::std::vector< sal_uInt16 >();
923 
924     if( mpImplData )
925     {
926         for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); i++ )
927             rIds.push_back( mpImplData->maImages[i]->mnId );
928     }
929 }
930 
931 // -----------------------------------------------------------------------
932 
933 ::rtl::OUString ImageList::GetImageName( sal_uInt16 nPos ) const
934 {
935     DBG_CHKTHIS( ImageList, NULL );
936 
937     if( mpImplData && (nPos < GetImageCount()) )
938         return mpImplData->maImages[ nPos ]->maName;
939 
940     return ::rtl::OUString();
941 }
942 
943 // -----------------------------------------------------------------------
944 
945 void ImageList::GetImageNames( ::std::vector< ::rtl::OUString >& rNames ) const
946 {
947     RTL_LOGFILE_CONTEXT( aLog, "vcl: ImageList::GetImageNames" );
948 
949     DBG_CHKTHIS( ImageList, NULL );
950 
951     rNames = ::std::vector< ::rtl::OUString >();
952 
953     if( mpImplData )
954     {
955         for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); i++ )
956         {
957             const rtl::OUString& rName( mpImplData->maImages[ i ]->maName );
958             if( rName.getLength() != 0 )
959                 rNames.push_back( rName );
960         }
961     }
962 }
963 
964 // -----------------------------------------------------------------------
965 
966 Size ImageList::GetImageSize() const
967 {
968     DBG_CHKTHIS( ImageList, NULL );
969 
970     Size aRet;
971 
972     if( mpImplData )
973     {
974         aRet = mpImplData->maImageSize;
975 
976         // force load of 1st image to see - uncommon case.
977         if( aRet.Width() == 0 && aRet.Height() == 0 &&
978             !mpImplData->maImages.empty() )
979         {
980             Image aTmp = GetImage( mpImplData->maImages[ 0 ]->mnId );
981             aRet = mpImplData->maImageSize = aTmp.GetSizePixel();
982         }
983     }
984 //  fprintf (stderr, "GetImageSize returns %d, %d\n",
985 //           aRet.Width(), aRet.Height());
986 
987     return aRet;
988 }
989 
990 // -----------------------------------------------------------------------
991 
992 ImageList& ImageList::operator=( const ImageList& rImageList )
993 {
994     DBG_CHKTHIS( ImageList, NULL );
995     DBG_CHKOBJ( &rImageList, ImageList, NULL );
996 
997     if( rImageList.mpImplData )
998         ++rImageList.mpImplData->mnRefCount;
999 
1000     if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
1001         delete mpImplData;
1002 
1003     mpImplData = rImageList.mpImplData;
1004 
1005     return *this;
1006 }
1007 
1008 // -----------------------------------------------------------------------
1009 
1010 sal_Bool ImageList::operator==( const ImageList& rImageList ) const
1011 {
1012     DBG_CHKTHIS( ImageList, NULL );
1013     DBG_CHKOBJ( &rImageList, ImageList, NULL );
1014 
1015     bool bRet = false;
1016 
1017     if( rImageList.mpImplData == mpImplData )
1018         bRet = true;
1019     else if( !rImageList.mpImplData || !mpImplData )
1020         bRet = false;
1021     else if( rImageList.GetImageCount() == GetImageCount() &&
1022              rImageList.mpImplData->maImageSize == mpImplData->maImageSize )
1023         bRet = true; // strange semantic
1024 
1025     return bRet;
1026 }
1027