update emoji autocorrect entries from po-files
[LibreOffice.git] / vcl / source / gdi / image.cxx
blob377f5931318b452bc264fcc703e753eaf8a09030
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <boost/scoped_array.hpp>
22 #include <osl/file.hxx>
23 #include <tools/debug.hxx>
24 #include <tools/stream.hxx>
25 #include <tools/rc.h>
26 #include <tools/rc.hxx>
27 #include <tools/resmgr.hxx>
28 #include <vcl/settings.hxx>
29 #include <vcl/outdev.hxx>
30 #include <vcl/graph.hxx>
31 #include <vcl/graphicfilter.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/image.hxx>
34 #include <vcl/imagerepository.hxx>
35 #include <vcl/implimagetree.hxx>
36 #include <image.h>
38 #if OSL_DEBUG_LEVEL > 0
39 #include <rtl/strbuf.hxx>
40 #endif
42 using namespace ::com::sun::star;
44 Image::Image() :
45 mpImplData( NULL )
49 Image::Image( const ResId& rResId ) :
50 mpImplData( NULL )
53 rResId.SetRT( RSC_IMAGE );
55 ResMgr* pResMgr = rResId.GetResMgr();
56 if( pResMgr && pResMgr->GetResource( rResId ) )
58 pResMgr->Increment( sizeof( RSHEADER_TYPE ) );
60 BitmapEx aBmpEx;
61 sal_uLong nObjMask = pResMgr->ReadLong();
63 if( nObjMask & RSC_IMAGE_IMAGEBITMAP )
65 aBmpEx = BitmapEx( ResId( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()), *pResMgr ) );
66 pResMgr->Increment( ResMgr::GetObjSize( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()) ) );
69 if( nObjMask & RSC_IMAGE_MASKBITMAP )
71 if( !aBmpEx.IsEmpty() && aBmpEx.GetTransparentType() == TRANSPARENT_NONE )
73 const Bitmap aMaskBitmap( ResId( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()), *pResMgr ) );
74 aBmpEx = BitmapEx( aBmpEx.GetBitmap(), aMaskBitmap );
77 pResMgr->Increment( ResMgr::GetObjSize( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()) ) );
80 if( nObjMask & RSC_IMAGE_MASKCOLOR )
82 if( !aBmpEx.IsEmpty() && aBmpEx.GetTransparentType() == TRANSPARENT_NONE )
84 const Color aMaskColor( ResId( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()), *pResMgr ) );
85 aBmpEx = BitmapEx( aBmpEx.GetBitmap(), aMaskColor );
88 pResMgr->Increment( ResMgr::GetObjSize( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()) ) );
90 if( ! aBmpEx.IsEmpty() )
91 ImplInit( aBmpEx );
95 Image::Image( const Image& rImage ) :
96 mpImplData( rImage.mpImplData )
99 if( mpImplData )
100 ++mpImplData->mnRefCount;
103 Image::Image( const BitmapEx& rBitmapEx ) :
104 mpImplData( NULL )
107 ImplInit( rBitmapEx );
110 Image::Image( const Bitmap& rBitmap ) :
111 mpImplData( NULL )
114 ImplInit( rBitmap );
117 Image::Image( const Bitmap& rBitmap, const Bitmap& rMaskBitmap ) :
118 mpImplData( NULL )
121 const BitmapEx aBmpEx( rBitmap, rMaskBitmap );
123 ImplInit( aBmpEx );
126 Image::Image( const Bitmap& rBitmap, const Color& rColor ) :
127 mpImplData( NULL )
130 const BitmapEx aBmpEx( rBitmap, rColor );
132 ImplInit( aBmpEx );
135 Image::Image( const uno::Reference< graphic::XGraphic >& rxGraphic ) :
136 mpImplData( NULL )
139 const Graphic aGraphic( rxGraphic );
140 ImplInit( aGraphic.GetBitmapEx() );
143 Image::Image( const OUString &rFileUrl ) :
144 mpImplData( NULL )
146 OUString aTmp;
147 osl::FileBase::getSystemPathFromFileURL( rFileUrl, aTmp );
148 Graphic aGraphic;
149 const OUString aFilterName( IMP_PNG );
150 if( GRFILTER_OK == GraphicFilter::LoadGraphic( aTmp, aFilterName, aGraphic ) )
152 ImplInit( aGraphic.GetBitmapEx() );
156 Image::~Image()
159 if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
160 delete mpImplData;
163 void Image::ImplInit( const BitmapEx& rBmpEx )
165 if( !rBmpEx.IsEmpty() )
167 mpImplData = new ImplImage;
169 if( rBmpEx.GetTransparentType() == TRANSPARENT_NONE )
171 mpImplData->meType = IMAGETYPE_BITMAP;
172 mpImplData->mpData = new Bitmap( rBmpEx.GetBitmap() );
174 else
176 mpImplData->meType = IMAGETYPE_IMAGE;
177 mpImplData->mpData = new ImplImageData( rBmpEx );
182 Size Image::GetSizePixel() const
185 Size aRet;
187 if( mpImplData )
189 switch( mpImplData->meType )
191 case IMAGETYPE_BITMAP:
192 aRet = static_cast< Bitmap* >( mpImplData->mpData )->GetSizePixel();
193 break;
195 case IMAGETYPE_IMAGE:
196 aRet = static_cast< ImplImageData* >( mpImplData->mpData )->maBmpEx.GetSizePixel();
197 break;
201 return aRet;
204 BitmapEx Image::GetBitmapEx() const
207 BitmapEx aRet;
209 if( mpImplData )
211 switch( mpImplData->meType )
213 case IMAGETYPE_BITMAP:
214 aRet = *static_cast< Bitmap* >( mpImplData->mpData );
215 break;
217 case IMAGETYPE_IMAGE:
218 aRet = static_cast< ImplImageData* >( mpImplData->mpData )->maBmpEx;
219 break;
223 return aRet;
226 uno::Reference< graphic::XGraphic > Image::GetXGraphic() const
228 const Graphic aGraphic( GetBitmapEx() );
230 return aGraphic.GetXGraphic();
233 Image& Image::operator=( const Image& rImage )
236 if( rImage.mpImplData )
237 ++rImage.mpImplData->mnRefCount;
239 if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
240 delete mpImplData;
242 mpImplData = rImage.mpImplData;
244 return *this;
247 bool Image::operator==( const Image& rImage ) const
250 bool bRet = false;
252 if( rImage.mpImplData == mpImplData )
253 bRet = true;
254 else if( !rImage.mpImplData || !mpImplData )
255 bRet = false;
256 else if( rImage.mpImplData->mpData == mpImplData->mpData )
257 bRet = true;
258 else if( rImage.mpImplData->meType == mpImplData->meType )
260 switch( mpImplData->meType )
262 case IMAGETYPE_BITMAP:
263 bRet = ( *static_cast< Bitmap* >( rImage.mpImplData->mpData ) == *static_cast< Bitmap* >( mpImplData->mpData ) );
264 break;
266 case IMAGETYPE_IMAGE:
267 bRet = static_cast< ImplImageData* >( rImage.mpImplData->mpData )->IsEqual( *static_cast< ImplImageData* >( mpImplData->mpData ) );
268 break;
270 default:
271 bRet = false;
272 break;
276 return bRet;
279 ImageList::ImageList( sal_uInt16 nInit, sal_uInt16 nGrow ) :
280 mpImplData( NULL ),
281 mnInitSize( nInit ),
282 mnGrowSize( nGrow )
286 ImageList::ImageList( const ResId& rResId ) :
287 mpImplData( NULL ),
288 mnInitSize( 1 ),
289 mnGrowSize( 4 )
291 SAL_INFO( "vcl.gdi", "vcl: ImageList::ImageList( const ResId& rResId )" );
293 rResId.SetRT( RSC_IMAGELIST );
295 ResMgr* pResMgr = rResId.GetResMgr();
297 if( pResMgr && pResMgr->GetResource( rResId ) )
299 pResMgr->Increment( sizeof( RSHEADER_TYPE ) );
301 sal_uLong nObjMask = pResMgr->ReadLong();
302 pResMgr->ReadString(); //skip string
303 std::unique_ptr< Color > xMaskColor;
305 if( nObjMask & RSC_IMAGE_MASKCOLOR )
306 xMaskColor.reset( new Color( ResId( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()), *pResMgr ) ) );
308 pResMgr->Increment( ResMgr::GetObjSize( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()) ) );
310 if( nObjMask & RSC_IMAGELIST_IDLIST )
312 for( sal_Int32 i = 0, nCount = pResMgr->ReadLong(); i < nCount; ++i )
313 pResMgr->ReadLong();
316 sal_Int32 nCount = pResMgr->ReadLong();
317 ImplInit( static_cast< sal_uInt16 >( nCount ), Size() );
319 BitmapEx aEmpty;
320 for( sal_Int32 i = 0; i < nCount; ++i )
322 OUString aName = pResMgr->ReadString();
323 sal_uInt16 nId = static_cast< sal_uInt16 >( pResMgr->ReadLong() );
324 mpImplData->AddImage( aName, nId, aEmpty );
327 if( nObjMask & RSC_IMAGELIST_IDCOUNT )
328 pResMgr->ReadShort();
332 ImageList::ImageList( const ::std::vector< OUString >& rNameVector,
333 const OUString& rPrefix,
334 const Color* ) :
335 mpImplData( NULL ),
336 mnInitSize( 1 ),
337 mnGrowSize( 4 )
339 SAL_INFO( "vcl.gdi", "vcl: ImageList::ImageList(const vector< OUString >& ..." );
341 ImplInit( sal::static_int_cast< sal_uInt16 >( rNameVector.size() ), Size() );
343 mpImplData->maPrefix = rPrefix;
344 for( sal_uInt32 i = 0; i < rNameVector.size(); ++i )
346 mpImplData->AddImage( rNameVector[ i ], static_cast< sal_uInt16 >( i ) + 1, BitmapEx() );
350 ImageList::ImageList( const ImageList& rImageList ) :
351 mpImplData( rImageList.mpImplData ),
352 mnInitSize( rImageList.mnInitSize ),
353 mnGrowSize( rImageList.mnGrowSize )
356 if( mpImplData )
357 ++mpImplData->mnRefCount;
360 ImageList::~ImageList()
362 if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
363 delete mpImplData;
366 void ImageList::ImplInit( sal_uInt16 nItems, const Size &rSize )
368 mpImplData = new ImplImageList;
369 mpImplData->maImages.reserve( nItems );
370 mpImplData->maImageSize = rSize;
373 void ImageAryData::Load(const OUString &rPrefix)
375 OUString aIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme();
377 BitmapEx aBmpEx;
379 OUString aFileName = rPrefix;
380 aFileName += maName;
381 #if OSL_DEBUG_LEVEL > 0
382 bool bSuccess =
383 #endif
384 ImplImageTree::get().loadImage(aFileName, aIconTheme, maBitmapEx, true);
385 #if OSL_DEBUG_LEVEL > 0
386 if ( !bSuccess )
388 OStringBuffer aMessage;
389 aMessage.append( "ImageAryData::Load: failed to load image '" );
390 aMessage.append( OUStringToOString( aFileName, RTL_TEXTENCODING_UTF8 ).getStr() );
391 aMessage.append( "'" );
392 OSL_FAIL( aMessage.makeStringAndClear().getStr() );
394 #endif
397 // FIXME: Rather a performance hazard
398 BitmapEx ImageList::GetAsHorizontalStrip() const
400 Size aSize( mpImplData->maImageSize );
401 sal_uInt16 nCount = GetImageCount();
402 if( !nCount )
403 return BitmapEx();
404 aSize.Width() *= nCount;
406 // Load any stragglers
407 for (sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++)
409 ImageAryData *pData = mpImplData->maImages[ nIdx ];
410 if( pData->IsLoadable() )
411 pData->Load( mpImplData->maPrefix );
414 BitmapEx aTempl = mpImplData->maImages[ 0 ]->maBitmapEx;
415 BitmapEx aResult;
416 Bitmap aPixels( aSize, aTempl.GetBitmap().GetBitCount() );
417 if( aTempl.IsAlpha() )
418 aResult = BitmapEx( aPixels, AlphaMask( aSize ) );
419 else if( aTempl.IsTransparent() )
420 aResult = BitmapEx( aPixels, Bitmap( aSize, aTempl.GetMask().GetBitCount() ) );
421 else
422 aResult = BitmapEx( aPixels );
424 Rectangle aSrcRect( Point( 0, 0 ), mpImplData->maImageSize );
425 for (sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++)
427 Rectangle aDestRect( Point( nIdx * mpImplData->maImageSize.Width(), 0 ),
428 mpImplData->maImageSize );
429 ImageAryData *pData = mpImplData->maImages[ nIdx ];
430 aResult.CopyPixel( aDestRect, aSrcRect, &pData->maBitmapEx);
433 return aResult;
436 void ImageList::InsertFromHorizontalStrip( const BitmapEx &rBitmapEx,
437 const std::vector< OUString > &rNameVector )
439 sal_uInt16 nItems = sal::static_int_cast< sal_uInt16 >( rNameVector.size() );
441 if (!nItems)
442 return;
444 Size aSize( rBitmapEx.GetSizePixel() );
445 DBG_ASSERT (rBitmapEx.GetSizePixel().Width() % nItems == 0,
446 "ImageList::InsertFromHorizontalStrip - very odd size");
447 aSize.Width() /= nItems;
448 ImplInit( nItems, aSize );
450 for (sal_uInt16 nIdx = 0; nIdx < nItems; nIdx++)
452 BitmapEx aBitmap( rBitmapEx, Point( nIdx * aSize.Width(), 0 ), aSize );
453 mpImplData->AddImage( rNameVector[ nIdx ], nIdx + 1, aBitmap );
457 void ImageList::InsertFromHorizontalBitmap( const ResId& rResId,
458 sal_uInt16 nCount,
459 const Color *pMaskColor,
460 const Color *pSearchColors,
461 const Color *pReplaceColors,
462 sal_uLong nColorCount)
464 BitmapEx aBmpEx( rResId );
465 if (!aBmpEx.IsTransparent())
467 if( pMaskColor )
468 aBmpEx = BitmapEx( aBmpEx.GetBitmap(), *pMaskColor );
469 else
470 aBmpEx = BitmapEx( aBmpEx.GetBitmap() );
472 if ( nColorCount && pSearchColors && pReplaceColors )
473 aBmpEx.Replace( pSearchColors, pReplaceColors, nColorCount );
475 std::vector< OUString > aNames( nCount );
476 InsertFromHorizontalStrip( aBmpEx, aNames );
479 sal_uInt16 ImageList::ImplGetImageId( const OUString& rImageName ) const
482 ImageAryData *pImg = mpImplData->maNameHash[ rImageName ];
483 if( pImg )
484 return pImg->mnId;
485 else
486 return 0;
489 void ImageList::AddImage( const OUString& rImageName, const Image& rImage )
491 DBG_ASSERT( GetImagePos( rImageName ) == IMAGELIST_IMAGE_NOTFOUND, "ImageList::AddImage() - ImageName already exists" );
493 if( !mpImplData )
494 ImplInit( 0, rImage.GetSizePixel() );
496 mpImplData->AddImage( rImageName, GetImageCount() + 1,
497 rImage.GetBitmapEx() );
500 void ImageList::ReplaceImage( const OUString& rImageName, const Image& rImage )
502 const sal_uInt16 nId = ImplGetImageId( rImageName );
504 if( nId )
506 //Just replace the bitmap rather than doing RemoveImage / AddImage
507 //which breaks index-based iteration.
508 ImageAryData *pImg = mpImplData->maNameHash[ rImageName ];
509 pImg->maBitmapEx = rImage.GetBitmapEx();
513 void ImageList::RemoveImage( sal_uInt16 nId )
516 for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); ++i )
518 if( mpImplData->maImages[ i ]->mnId == nId )
520 mpImplData->RemoveImage( static_cast< sal_uInt16 >( i ) );
521 break;
526 Image ImageList::GetImage( sal_uInt16 nId ) const
529 Image aRet;
531 if( mpImplData )
533 std::vector<ImageAryData *>::iterator aIter;
534 for( aIter = mpImplData->maImages.begin();
535 aIter != mpImplData->maImages.end(); ++aIter)
537 if ((*aIter)->mnId == nId)
539 if( (*aIter)->IsLoadable() )
540 (*aIter)->Load( mpImplData->maPrefix );
542 aRet = Image( (*aIter)->maBitmapEx );
547 if (!aRet)
549 BitmapEx rBitmap;
550 bool res = vcl::ImageRepository::loadDefaultImage(rBitmap);
551 if (res)
552 aRet = Image(rBitmap);
555 return aRet;
558 Image ImageList::GetImage( const OUString& rImageName ) const
560 if( mpImplData )
562 ImageAryData *pImg = mpImplData->maNameHash[ rImageName ];
564 if( pImg )
566 if( pImg->IsLoadable() )
567 pImg->Load( mpImplData->maPrefix );
568 return Image( pImg->maBitmapEx );
572 return Image();
575 sal_uInt16 ImageList::GetImageCount() const
578 return mpImplData ? static_cast< sal_uInt16 >( mpImplData->maImages.size() ) : 0;
581 sal_uInt16 ImageList::GetImagePos( sal_uInt16 nId ) const
584 if( mpImplData && nId )
586 for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); ++i )
588 if (mpImplData->maImages[ i ]->mnId == nId)
589 return static_cast< sal_uInt16 >( i );
593 return IMAGELIST_IMAGE_NOTFOUND;
596 bool ImageList::HasImageAtPos( sal_uInt16 nId ) const
598 return GetImagePos( nId ) != IMAGELIST_IMAGE_NOTFOUND;
601 sal_uInt16 ImageList::GetImagePos( const OUString& rImageName ) const
604 if( mpImplData && !rImageName.isEmpty() )
606 for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); i++ )
608 if (mpImplData->maImages[i]->maName == rImageName)
609 return static_cast< sal_uInt16 >( i );
613 return IMAGELIST_IMAGE_NOTFOUND;
616 sal_uInt16 ImageList::GetImageId( sal_uInt16 nPos ) const
619 if( mpImplData && (nPos < GetImageCount()) )
620 return mpImplData->maImages[ nPos ]->mnId;
622 return 0;
625 OUString ImageList::GetImageName( sal_uInt16 nPos ) const
628 if( mpImplData && (nPos < GetImageCount()) )
629 return mpImplData->maImages[ nPos ]->maName;
631 return OUString();
634 void ImageList::GetImageNames( ::std::vector< OUString >& rNames ) const
636 SAL_INFO( "vcl.gdi", "vcl: ImageList::GetImageNames" );
638 rNames = ::std::vector< OUString >();
640 if( mpImplData )
642 for( sal_uInt32 i = 0; i < mpImplData->maImages.size(); i++ )
644 const OUString& rName( mpImplData->maImages[ i ]->maName );
645 if( !rName.isEmpty())
646 rNames.push_back( rName );
651 Size ImageList::GetImageSize() const
654 Size aRet;
656 if( mpImplData )
658 aRet = mpImplData->maImageSize;
660 // force load of 1st image to see - uncommon case.
661 if( aRet.Width() == 0 && aRet.Height() == 0 &&
662 !mpImplData->maImages.empty() )
664 Image aTmp = GetImage( mpImplData->maImages[ 0 ]->mnId );
665 aRet = mpImplData->maImageSize = aTmp.GetSizePixel();
668 return aRet;
671 ImageList& ImageList::operator=( const ImageList& rImageList )
674 if( rImageList.mpImplData )
675 ++rImageList.mpImplData->mnRefCount;
677 if( mpImplData && ( 0 == --mpImplData->mnRefCount ) )
678 delete mpImplData;
680 mpImplData = rImageList.mpImplData;
682 return *this;
685 bool ImageList::operator==( const ImageList& rImageList ) const
688 bool bRet = false;
690 if( rImageList.mpImplData == mpImplData )
691 bRet = true;
692 else if( !rImageList.mpImplData || !mpImplData )
693 bRet = false;
694 else if( rImageList.GetImageCount() == GetImageCount() &&
695 rImageList.mpImplData->maImageSize == mpImplData->maImageSize )
696 bRet = true; // strange semantic
698 return bRet;
701 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */