diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.com> | 2015-11-19 12:57:52 +0100 |
---|---|---|
committer | Tomaž Vajngerl <tomaz.vajngerl@collabora.com> | 2015-11-19 13:02:54 +0100 |
commit | 25d60232ff5d882017ffb88453f16fd6cef5534c (patch) | |
tree | b62faddecbe82d0c75a51335c6518e3cdb20f558 /vcl/source/image | |
parent | 6480b4d11a0cf2dd489d30b6290aa6d831704a45 (diff) |
vcl: move and split up "Image" related sources to "image" folder
This commit moves all sources related to Image class into its own
"vcl/source/image" folder. Sources containing more classes were
split up into its own source file.
Change-Id: Ie6edcdb0a7caf936bccdc210c31f78bb15667945
Diffstat (limited to 'vcl/source/image')
-rw-r--r-- | vcl/source/image/Image.cxx | 277 | ||||
-rw-r--r-- | vcl/source/image/ImageArrayData.cxx | 58 | ||||
-rw-r--r-- | vcl/source/image/ImageList.cxx | 462 | ||||
-rw-r--r-- | vcl/source/image/ImageRepository.cxx | 43 | ||||
-rw-r--r-- | vcl/source/image/ImplImage.cxx | 53 | ||||
-rw-r--r-- | vcl/source/image/ImplImageBmp.cxx | 287 | ||||
-rw-r--r-- | vcl/source/image/ImplImageData.cxx | 48 | ||||
-rw-r--r-- | vcl/source/image/ImplImageList.cxx | 75 | ||||
-rw-r--r-- | vcl/source/image/ImplImageTree.cxx | 439 |
9 files changed, 1742 insertions, 0 deletions
diff --git a/vcl/source/image/Image.cxx b/vcl/source/image/Image.cxx new file mode 100644 index 000000000000..cc1f46714ce3 --- /dev/null +++ b/vcl/source/image/Image.cxx @@ -0,0 +1,277 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <osl/file.hxx> +#include <tools/debug.hxx> +#include <tools/stream.hxx> +#include <tools/rc.h> +#include <tools/rc.hxx> +#include <tools/resmgr.hxx> +#include <vcl/settings.hxx> +#include <vcl/outdev.hxx> +#include <vcl/graph.hxx> +#include <vcl/graphicfilter.hxx> +#include <vcl/svapp.hxx> +#include <vcl/image.hxx> +#include <vcl/imagerepository.hxx> +#include <vcl/implimagetree.hxx> +#include <image.h> + +#if OSL_DEBUG_LEVEL > 0 +#include <rtl/strbuf.hxx> +#endif + +using namespace ::com::sun::star; + +Image::Image() : + mpImplData( nullptr ) +{ +} + +Image::Image( const ResId& rResId ) : + mpImplData( nullptr ) +{ + + rResId.SetRT( RSC_IMAGE ); + + ResMgr* pResMgr = rResId.GetResMgr(); + if( pResMgr && pResMgr->GetResource( rResId ) ) + { + pResMgr->Increment( sizeof( RSHEADER_TYPE ) ); + + BitmapEx aBmpEx; + sal_uLong nObjMask = pResMgr->ReadLong(); + + if( nObjMask & RSC_IMAGE_IMAGEBITMAP ) + { + aBmpEx = BitmapEx( ResId( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()), *pResMgr ) ); + pResMgr->Increment( ResMgr::GetObjSize( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()) ) ); + } + + if( nObjMask & RSC_IMAGE_MASKBITMAP ) + { + if( !aBmpEx.IsEmpty() && aBmpEx.GetTransparentType() == TRANSPARENT_NONE ) + { + const Bitmap aMaskBitmap( ResId( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()), *pResMgr ) ); + aBmpEx = BitmapEx( aBmpEx.GetBitmap(), aMaskBitmap ); + } + + pResMgr->Increment( ResMgr::GetObjSize( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()) ) ); + } + + if( nObjMask & RSC_IMAGE_MASKCOLOR ) + { + if( !aBmpEx.IsEmpty() && aBmpEx.GetTransparentType() == TRANSPARENT_NONE ) + { + const Color aMaskColor( ResId( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()), *pResMgr ) ); + aBmpEx = BitmapEx( aBmpEx.GetBitmap(), aMaskColor ); + } + + pResMgr->Increment( ResMgr::GetObjSize( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()) ) ); + } + if( ! aBmpEx.IsEmpty() ) + ImplInit( aBmpEx ); + } +} + +Image::Image( const Image& rImage ) : + mpImplData( rImage.mpImplData ) +{ + + if( mpImplData ) + ++mpImplData->mnRefCount; +} + +Image::Image( const BitmapEx& rBitmapEx ) : + mpImplData( nullptr ) +{ + + ImplInit( rBitmapEx ); +} + +Image::Image( const Bitmap& rBitmap ) : + mpImplData( nullptr ) +{ + + ImplInit( rBitmap ); +} + +Image::Image( const Bitmap& rBitmap, const Bitmap& rMaskBitmap ) : + mpImplData( nullptr ) +{ + + const BitmapEx aBmpEx( rBitmap, rMaskBitmap ); + + ImplInit( aBmpEx ); +} + +Image::Image( const Bitmap& rBitmap, const Color& rColor ) : + mpImplData( nullptr ) +{ + + const BitmapEx aBmpEx( rBitmap, rColor ); + + ImplInit( aBmpEx ); +} + +Image::Image( const uno::Reference< graphic::XGraphic >& rxGraphic ) : + mpImplData( nullptr ) +{ + + const Graphic aGraphic( rxGraphic ); + ImplInit( aGraphic.GetBitmapEx() ); +} + +Image::Image( const OUString &rFileUrl ) : + mpImplData( nullptr ) +{ + OUString aTmp; + osl::FileBase::getSystemPathFromFileURL( rFileUrl, aTmp ); + Graphic aGraphic; + const OUString aFilterName( IMP_PNG ); + if( GRFILTER_OK == GraphicFilter::LoadGraphic( aTmp, aFilterName, aGraphic ) ) + { + ImplInit( aGraphic.GetBitmapEx() ); + } +} + +Image::~Image() +{ + + if( mpImplData && ( 0 == --mpImplData->mnRefCount ) ) + delete mpImplData; +} + +void Image::ImplInit( const BitmapEx& rBmpEx ) +{ + if( !rBmpEx.IsEmpty() ) + { + mpImplData = new ImplImage; + + if( rBmpEx.GetTransparentType() == TRANSPARENT_NONE ) + { + mpImplData->meType = IMAGETYPE_BITMAP; + mpImplData->mpData = new Bitmap( rBmpEx.GetBitmap() ); + } + else + { + mpImplData->meType = IMAGETYPE_IMAGE; + mpImplData->mpData = new ImplImageData( rBmpEx ); + } + } +} + +Size Image::GetSizePixel() const +{ + + Size aRet; + + if( mpImplData ) + { + switch( mpImplData->meType ) + { + case IMAGETYPE_BITMAP: + aRet = static_cast< Bitmap* >( mpImplData->mpData )->GetSizePixel(); + break; + + case IMAGETYPE_IMAGE: + aRet = static_cast< ImplImageData* >( mpImplData->mpData )->maBmpEx.GetSizePixel(); + break; + } + } + + return aRet; +} + +BitmapEx Image::GetBitmapEx() const +{ + + BitmapEx aRet; + + if( mpImplData ) + { + switch( mpImplData->meType ) + { + case IMAGETYPE_BITMAP: + aRet = *static_cast< Bitmap* >( mpImplData->mpData ); + break; + + case IMAGETYPE_IMAGE: + aRet = static_cast< ImplImageData* >( mpImplData->mpData )->maBmpEx; + break; + } + } + + return aRet; +} + +uno::Reference< graphic::XGraphic > Image::GetXGraphic() const +{ + const Graphic aGraphic( GetBitmapEx() ); + + return aGraphic.GetXGraphic(); +} + +Image& Image::operator=( const Image& rImage ) +{ + + if( rImage.mpImplData ) + ++rImage.mpImplData->mnRefCount; + + if( mpImplData && ( 0 == --mpImplData->mnRefCount ) ) + delete mpImplData; + + mpImplData = rImage.mpImplData; + + return *this; +} + +bool Image::operator==( const Image& rImage ) const +{ + + bool bRet = false; + + if( rImage.mpImplData == mpImplData ) + bRet = true; + else if( !rImage.mpImplData || !mpImplData ) + bRet = false; + else if( rImage.mpImplData->mpData == mpImplData->mpData ) + bRet = true; + else if( rImage.mpImplData->meType == mpImplData->meType ) + { + switch( mpImplData->meType ) + { + case IMAGETYPE_BITMAP: + bRet = ( *static_cast< Bitmap* >( rImage.mpImplData->mpData ) == *static_cast< Bitmap* >( mpImplData->mpData ) ); + break; + + case IMAGETYPE_IMAGE: + bRet = static_cast< ImplImageData* >( rImage.mpImplData->mpData )->IsEqual( *static_cast< ImplImageData* >( mpImplData->mpData ) ); + break; + + default: + bRet = false; + break; + } + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/image/ImageArrayData.cxx b/vcl/source/image/ImageArrayData.cxx new file mode 100644 index 000000000000..d7b3bbbcf0ba --- /dev/null +++ b/vcl/source/image/ImageArrayData.cxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <vcl/outdev.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/alpha.hxx> +#include <vcl/window.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/virdev.hxx> +#include <vcl/image.hxx> +#include <vcl/settings.hxx> + +#include <image.h> +#include <memory> + +ImageAryData::ImageAryData( const ImageAryData& rData ) : + maName( rData.maName ), + mnId( rData.mnId ), + maBitmapEx( rData.maBitmapEx ) +{ +} + +ImageAryData::ImageAryData( const OUString &aName, + sal_uInt16 nId, const BitmapEx &aBitmap ) + : maName( aName ), mnId( nId ), maBitmapEx( aBitmap ) +{ +} + +ImageAryData::~ImageAryData() +{ +} + +ImageAryData& ImageAryData::operator=( const ImageAryData& rData ) +{ + maName = rData.maName; + mnId = rData.mnId; + maBitmapEx = rData.maBitmapEx; + + return *this; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/image/ImageList.cxx b/vcl/source/image/ImageList.cxx new file mode 100644 index 000000000000..6c2dff965074 --- /dev/null +++ b/vcl/source/image/ImageList.cxx @@ -0,0 +1,462 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <osl/file.hxx> +#include <tools/debug.hxx> +#include <tools/stream.hxx> +#include <tools/rc.h> +#include <tools/rc.hxx> +#include <tools/resmgr.hxx> +#include <vcl/settings.hxx> +#include <vcl/outdev.hxx> +#include <vcl/graph.hxx> +#include <vcl/graphicfilter.hxx> +#include <vcl/svapp.hxx> +#include <vcl/image.hxx> +#include <vcl/imagerepository.hxx> +#include <vcl/implimagetree.hxx> +#include <image.h> + +#if OSL_DEBUG_LEVEL > 0 +#include <rtl/strbuf.hxx> +#endif + +using namespace ::com::sun::star; + +ImageList::ImageList( sal_uInt16 nInit, sal_uInt16 nGrow ) : + mpImplData( nullptr ), + mnInitSize( nInit ), + mnGrowSize( nGrow ) +{ +} + +ImageList::ImageList( const ResId& rResId ) : + mpImplData( nullptr ), + mnInitSize( 1 ), + mnGrowSize( 4 ) +{ + SAL_INFO( "vcl.gdi", "vcl: ImageList::ImageList( const ResId& rResId )" ); + + rResId.SetRT( RSC_IMAGELIST ); + + ResMgr* pResMgr = rResId.GetResMgr(); + + if( pResMgr && pResMgr->GetResource( rResId ) ) + { + pResMgr->Increment( sizeof( RSHEADER_TYPE ) ); + + sal_uLong nObjMask = pResMgr->ReadLong(); + pResMgr->ReadString(); //skip string + std::unique_ptr< Color > xMaskColor; + + if( nObjMask & RSC_IMAGE_MASKCOLOR ) + xMaskColor.reset( new Color( ResId( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()), *pResMgr ) ) ); + + pResMgr->Increment( ResMgr::GetObjSize( static_cast<RSHEADER_TYPE*>(pResMgr->GetClass()) ) ); + + if( nObjMask & RSC_IMAGELIST_IDLIST ) + { + for( sal_Int32 i = 0, nCount = pResMgr->ReadLong(); i < nCount; ++i ) + pResMgr->ReadLong(); + } + + sal_Int32 nCount = pResMgr->ReadLong(); + ImplInit( static_cast< sal_uInt16 >( nCount ), Size() ); + + BitmapEx aEmpty; + for( sal_Int32 i = 0; i < nCount; ++i ) + { + OUString aName = pResMgr->ReadString(); + sal_uInt16 nId = static_cast< sal_uInt16 >( pResMgr->ReadLong() ); + mpImplData->AddImage( aName, nId, aEmpty ); + } + + if( nObjMask & RSC_IMAGELIST_IDCOUNT ) + pResMgr->ReadShort(); + } +} + +ImageList::ImageList( const ::std::vector< OUString >& rNameVector, + const OUString& rPrefix, + const Color* ) : + mpImplData( nullptr ), + mnInitSize( 1 ), + mnGrowSize( 4 ) +{ + SAL_INFO( "vcl.gdi", "vcl: ImageList::ImageList(const vector< OUString >& ..." ); + + ImplInit( sal::static_int_cast< sal_uInt16 >( rNameVector.size() ), Size() ); + + mpImplData->maPrefix = rPrefix; + for( size_t i = 0; i < rNameVector.size(); ++i ) + { + mpImplData->AddImage( rNameVector[ i ], static_cast< sal_uInt16 >( i ) + 1, BitmapEx() ); + } +} + +ImageList::ImageList( const ImageList& rImageList ) : + mpImplData( rImageList.mpImplData ), + mnInitSize( rImageList.mnInitSize ), + mnGrowSize( rImageList.mnGrowSize ) +{ + + if( mpImplData ) + ++mpImplData->mnRefCount; +} + +ImageList::~ImageList() +{ + if( mpImplData && ( 0 == --mpImplData->mnRefCount ) ) + delete mpImplData; +} + +void ImageList::ImplInit( sal_uInt16 nItems, const Size &rSize ) +{ + mpImplData = new ImplImageList; + mpImplData->maImages.reserve( nItems ); + mpImplData->maImageSize = rSize; +} + +void ImageAryData::Load(const OUString &rPrefix) +{ + OUString aIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme(); + + OUString aFileName = rPrefix; + aFileName += maName; +#if OSL_DEBUG_LEVEL > 0 + bool bSuccess = +#endif + ImplImageTree::get().loadImage(aFileName, aIconTheme, maBitmapEx, true); +#if OSL_DEBUG_LEVEL > 0 + if ( !bSuccess ) + { + OStringBuffer aMessage; + aMessage.append( "ImageAryData::Load: failed to load image '" ); + aMessage.append( OUStringToOString( aFileName, RTL_TEXTENCODING_UTF8 ).getStr() ); + aMessage.append( "'" ); + OSL_FAIL( aMessage.makeStringAndClear().getStr() ); + } +#endif +} + +// FIXME: Rather a performance hazard +BitmapEx ImageList::GetAsHorizontalStrip() const +{ + Size aSize( mpImplData->maImageSize ); + sal_uInt16 nCount = GetImageCount(); + if( !nCount ) + return BitmapEx(); + aSize.Width() *= nCount; + + // Load any stragglers + for (sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++) + { + ImageAryData *pData = mpImplData->maImages[ nIdx ]; + if( pData->IsLoadable() ) + pData->Load( mpImplData->maPrefix ); + } + + BitmapEx aTempl = mpImplData->maImages[ 0 ]->maBitmapEx; + BitmapEx aResult; + Bitmap aPixels( aSize, aTempl.GetBitmap().GetBitCount() ); + if( aTempl.IsAlpha() ) + aResult = BitmapEx( aPixels, AlphaMask( aSize ) ); + else if( aTempl.IsTransparent() ) + aResult = BitmapEx( aPixels, Bitmap( aSize, aTempl.GetMask().GetBitCount() ) ); + else + aResult = BitmapEx( aPixels ); + + Rectangle aSrcRect( Point( 0, 0 ), mpImplData->maImageSize ); + for (sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++) + { + Rectangle aDestRect( Point( nIdx * mpImplData->maImageSize.Width(), 0 ), + mpImplData->maImageSize ); + ImageAryData *pData = mpImplData->maImages[ nIdx ]; + aResult.CopyPixel( aDestRect, aSrcRect, &pData->maBitmapEx); + } + + return aResult; +} + +void ImageList::InsertFromHorizontalStrip( const BitmapEx &rBitmapEx, + const std::vector< OUString > &rNameVector ) +{ + sal_uInt16 nItems = sal::static_int_cast< sal_uInt16 >( rNameVector.size() ); + + if (!nItems) + return; + + Size aSize( rBitmapEx.GetSizePixel() ); + DBG_ASSERT (rBitmapEx.GetSizePixel().Width() % nItems == 0, + "ImageList::InsertFromHorizontalStrip - very odd size"); + aSize.Width() /= nItems; + ImplInit( nItems, aSize ); + + for (sal_uInt16 nIdx = 0; nIdx < nItems; nIdx++) + { + BitmapEx aBitmap( rBitmapEx, Point( nIdx * aSize.Width(), 0 ), aSize ); + mpImplData->AddImage( rNameVector[ nIdx ], nIdx + 1, aBitmap ); + } +} + +void ImageList::InsertFromHorizontalBitmap( const ResId& rResId, + sal_uInt16 nCount, + const Color *pMaskColor, + const Color *pSearchColors, + const Color *pReplaceColors, + sal_uLong nColorCount) +{ + BitmapEx aBmpEx( rResId ); + if (!aBmpEx.IsTransparent()) + { + if( pMaskColor ) + aBmpEx = BitmapEx( aBmpEx.GetBitmap(), *pMaskColor ); + else + aBmpEx = BitmapEx( aBmpEx.GetBitmap() ); + } + if ( nColorCount && pSearchColors && pReplaceColors ) + aBmpEx.Replace( pSearchColors, pReplaceColors, nColorCount ); + + std::vector< OUString > aNames( nCount ); + InsertFromHorizontalStrip( aBmpEx, aNames ); +} + +sal_uInt16 ImageList::ImplGetImageId( const OUString& rImageName ) const +{ + + ImageAryData *pImg = mpImplData->maNameHash[ rImageName ]; + if( pImg ) + return pImg->mnId; + else + return 0; +} + +void ImageList::AddImage( const OUString& rImageName, const Image& rImage ) +{ + DBG_ASSERT( GetImagePos( rImageName ) == IMAGELIST_IMAGE_NOTFOUND, "ImageList::AddImage() - ImageName already exists" ); + + if( !mpImplData ) + ImplInit( 0, rImage.GetSizePixel() ); + + mpImplData->AddImage( rImageName, GetImageCount() + 1, + rImage.GetBitmapEx() ); +} + +void ImageList::ReplaceImage( const OUString& rImageName, const Image& rImage ) +{ + const sal_uInt16 nId = ImplGetImageId( rImageName ); + + if( nId ) + { + //Just replace the bitmap rather than doing RemoveImage / AddImage + //which breaks index-based iteration. + ImageAryData *pImg = mpImplData->maNameHash[ rImageName ]; + pImg->maBitmapEx = rImage.GetBitmapEx(); + } +} + +void ImageList::RemoveImage( sal_uInt16 nId ) +{ + + for( size_t i = 0; i < mpImplData->maImages.size(); ++i ) + { + if( mpImplData->maImages[ i ]->mnId == nId ) + { + mpImplData->RemoveImage( static_cast< sal_uInt16 >( i ) ); + break; + } + } +} + +Image ImageList::GetImage( sal_uInt16 nId ) const +{ + + Image aRet; + + if( mpImplData ) + { + std::vector<ImageAryData *>::iterator aIter; + for( aIter = mpImplData->maImages.begin(); + aIter != mpImplData->maImages.end(); ++aIter) + { + if ((*aIter)->mnId == nId) + { + if( (*aIter)->IsLoadable() ) + (*aIter)->Load( mpImplData->maPrefix ); + + aRet = Image( (*aIter)->maBitmapEx ); + } + } + } + + if (!aRet) + { + BitmapEx rBitmap; + bool res = vcl::ImageRepository::loadDefaultImage(rBitmap); + if (res) + aRet = Image(rBitmap); + } + + return aRet; +} + +Image ImageList::GetImage( const OUString& rImageName ) const +{ + if( mpImplData ) + { + ImageAryData *pImg = mpImplData->maNameHash[ rImageName ]; + + if( pImg ) + { + if( pImg->IsLoadable() ) + pImg->Load( mpImplData->maPrefix ); + return Image( pImg->maBitmapEx ); + } + } + + return Image(); +} + +sal_uInt16 ImageList::GetImageCount() const +{ + + return mpImplData ? static_cast< sal_uInt16 >( mpImplData->maImages.size() ) : 0; +} + +sal_uInt16 ImageList::GetImagePos( sal_uInt16 nId ) const +{ + + if( mpImplData && nId ) + { + for( size_t i = 0; i < mpImplData->maImages.size(); ++i ) + { + if (mpImplData->maImages[ i ]->mnId == nId) + return static_cast< sal_uInt16 >( i ); + } + } + + return IMAGELIST_IMAGE_NOTFOUND; +} + +bool ImageList::HasImageAtPos( sal_uInt16 nId ) const +{ + return GetImagePos( nId ) != IMAGELIST_IMAGE_NOTFOUND; +} + +sal_uInt16 ImageList::GetImagePos( const OUString& rImageName ) const +{ + + if( mpImplData && !rImageName.isEmpty() ) + { + for( size_t i = 0; i < mpImplData->maImages.size(); i++ ) + { + if (mpImplData->maImages[i]->maName == rImageName) + return static_cast< sal_uInt16 >( i ); + } + } + + return IMAGELIST_IMAGE_NOTFOUND; +} + +sal_uInt16 ImageList::GetImageId( sal_uInt16 nPos ) const +{ + + if( mpImplData && (nPos < GetImageCount()) ) + return mpImplData->maImages[ nPos ]->mnId; + + return 0; +} + +OUString ImageList::GetImageName( sal_uInt16 nPos ) const +{ + + if( mpImplData && (nPos < GetImageCount()) ) + return mpImplData->maImages[ nPos ]->maName; + + return OUString(); +} + +void ImageList::GetImageNames( ::std::vector< OUString >& rNames ) const +{ + SAL_INFO( "vcl.gdi", "vcl: ImageList::GetImageNames" ); + + rNames = ::std::vector< OUString >(); + + if( mpImplData ) + { + for( size_t i = 0; i < mpImplData->maImages.size(); i++ ) + { + const OUString& rName( mpImplData->maImages[ i ]->maName ); + if( !rName.isEmpty()) + rNames.push_back( rName ); + } + } +} + +Size ImageList::GetImageSize() const +{ + + Size aRet; + + if( mpImplData ) + { + aRet = mpImplData->maImageSize; + + // force load of 1st image to see - uncommon case. + if( aRet.Width() == 0 && aRet.Height() == 0 && + !mpImplData->maImages.empty() ) + { + Image aTmp = GetImage( mpImplData->maImages[ 0 ]->mnId ); + aRet = mpImplData->maImageSize = aTmp.GetSizePixel(); + } + } + return aRet; +} + +ImageList& ImageList::operator=( const ImageList& rImageList ) +{ + + if( rImageList.mpImplData ) + ++rImageList.mpImplData->mnRefCount; + + if( mpImplData && ( 0 == --mpImplData->mnRefCount ) ) + delete mpImplData; + + mpImplData = rImageList.mpImplData; + + return *this; +} + +bool ImageList::operator==( const ImageList& rImageList ) const +{ + + bool bRet = false; + + if( rImageList.mpImplData == mpImplData ) + bRet = true; + else if( !rImageList.mpImplData || !mpImplData ) + bRet = false; + else if( rImageList.GetImageCount() == GetImageCount() && + rImageList.mpImplData->maImageSize == mpImplData->maImageSize ) + bRet = true; // strange semantic + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/image/ImageRepository.cxx b/vcl/source/image/ImageRepository.cxx new file mode 100644 index 000000000000..dadc622cdcce --- /dev/null +++ b/vcl/source/image/ImageRepository.cxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <vcl/bitmapex.hxx> +#include <vcl/imagerepository.hxx> +#include <vcl/implimagetree.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> + +namespace vcl +{ + bool ImageRepository::loadImage( const OUString& _rName, BitmapEx& _out_rImage, bool _bSearchLanguageDependent, bool loadMissing ) + { + OUString sIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme(); + + return ImplImageTree::get().loadImage( _rName, sIconTheme, _out_rImage, _bSearchLanguageDependent, loadMissing ); + } + + bool ImageRepository::loadDefaultImage( BitmapEx& _out_rImage) + { + OUString sIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme(); + return ImplImageTree::get().loadDefaultImage( sIconTheme,_out_rImage); + } + +} // namespace vcl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/image/ImplImage.cxx b/vcl/source/image/ImplImage.cxx new file mode 100644 index 000000000000..9272cf07b4e1 --- /dev/null +++ b/vcl/source/image/ImplImage.cxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <vcl/outdev.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/alpha.hxx> +#include <vcl/window.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/virdev.hxx> +#include <vcl/image.hxx> +#include <vcl/settings.hxx> + +#include <image.h> +#include <memory> + +ImplImage::ImplImage() + : mnRefCount(1) + , mpData(nullptr) + , meType(IMAGETYPE_BITMAP) +{ +} + +ImplImage::~ImplImage() +{ + switch( meType ) + { + case IMAGETYPE_BITMAP: + delete static_cast< Bitmap* >( mpData ); + break; + + case IMAGETYPE_IMAGE: + delete static_cast< ImplImageData* >( mpData ); + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/image/ImplImageBmp.cxx b/vcl/source/image/ImplImageBmp.cxx new file mode 100644 index 000000000000..cb83cc3ae4ea --- /dev/null +++ b/vcl/source/image/ImplImageBmp.cxx @@ -0,0 +1,287 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <vcl/outdev.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/alpha.hxx> +#include <vcl/window.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/virdev.hxx> +#include <vcl/image.hxx> +#include <vcl/settings.hxx> + +#include <image.h> +#include <memory> + +#define IMPSYSIMAGEITEM_MASK ( 0x01 ) +#define IMPSYSIMAGEITEM_ALPHA ( 0x02 ) + +ImplImageBmp::ImplImageBmp() + : maBitmapChecksum(0) + , mpDisplayBmp(nullptr) + , mpInfoAry(nullptr) + , mnSize(0) +{ +} + +ImplImageBmp::~ImplImageBmp() +{ + delete[] mpInfoAry; + delete mpDisplayBmp; +} + +void ImplImageBmp::Create( const BitmapEx& rBmpEx, long nItemWidth, long nItemHeight, sal_uInt16 nInitSize ) +{ + maBmpEx = rBmpEx; + maDisabledBmpEx.SetEmpty(); + + delete mpDisplayBmp; + mpDisplayBmp = nullptr; + + maSize = Size( nItemWidth, nItemHeight ); + mnSize = nInitSize; + + delete[] mpInfoAry; + mpInfoAry = new sal_uInt8[ mnSize ]; + memset( mpInfoAry, + rBmpEx.IsAlpha() ? IMPSYSIMAGEITEM_ALPHA : ( rBmpEx.IsTransparent() ? IMPSYSIMAGEITEM_MASK : 0 ), + mnSize ); +} + +void ImplImageBmp::Draw( OutputDevice* pOutDev, + const Point& rPos, DrawImageFlags nStyle, + const Size* pSize ) +{ + if( pOutDev->IsDeviceOutputNecessary() ) + { + const Point aSrcPos(0, 0); + Size aOutSize; + + aOutSize = ( pSize ? *pSize : pOutDev->PixelToLogic( maSize ) ); + + if( nStyle & DrawImageFlags::Disable ) + { + BitmapChecksum aChecksum = maBmpEx.GetChecksum(); + if (maBitmapChecksum != aChecksum) + { + maBitmapChecksum = aChecksum; + ImplUpdateDisabledBmpEx(); + } + pOutDev->DrawBitmapEx( rPos, aOutSize, aSrcPos, maSize, maDisabledBmpEx ); + } + else + { + if( nStyle & ( DrawImageFlags::ColorTransform | + DrawImageFlags::Highlight | DrawImageFlags::Deactive | DrawImageFlags::SemiTransparent ) ) + { + BitmapEx aTmpBmpEx; + const Rectangle aCropRect( aSrcPos, maSize ); + + if( mpInfoAry[0] & ( IMPSYSIMAGEITEM_MASK | IMPSYSIMAGEITEM_ALPHA ) ) + aTmpBmpEx = maBmpEx; + else + aTmpBmpEx = maBmpEx.GetBitmap(); + + aTmpBmpEx.Crop( aCropRect ); + + Bitmap aTmpBmp( aTmpBmpEx.GetBitmap() ); + + if( nStyle & ( DrawImageFlags::Highlight | DrawImageFlags::Deactive ) ) + { + BitmapWriteAccess* pAcc = aTmpBmp.AcquireWriteAccess(); + + if( pAcc ) + { + const StyleSettings& rSettings = pOutDev->GetSettings().GetStyleSettings(); + Color aColor; + BitmapColor aCol; + const long nW = pAcc->Width(); + const long nH = pAcc->Height(); + std::unique_ptr<sal_uInt8[]> pMapR(new sal_uInt8[ 256 ]); + std::unique_ptr<sal_uInt8[]> pMapG(new sal_uInt8[ 256 ]); + std::unique_ptr<sal_uInt8[]> pMapB(new sal_uInt8[ 256 ]); + long nX, nY; + + if( nStyle & DrawImageFlags::Highlight ) + aColor = rSettings.GetHighlightColor(); + else + aColor = rSettings.GetDeactiveColor(); + + const sal_uInt8 cR = aColor.GetRed(); + const sal_uInt8 cG = aColor.GetGreen(); + const sal_uInt8 cB = aColor.GetBlue(); + + for( nX = 0L; nX < 256L; nX++ ) + { + pMapR[ nX ] = (sal_uInt8) ( ( ( nY = ( nX + cR ) >> 1 ) > 255 ) ? 255 : nY ); + pMapG[ nX ] = (sal_uInt8) ( ( ( nY = ( nX + cG ) >> 1 ) > 255 ) ? 255 : nY ); + pMapB[ nX ] = (sal_uInt8) ( ( ( nY = ( nX + cB ) >> 1 ) > 255 ) ? 255 : nY ); + } + + if( pAcc->HasPalette() ) + { + for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ ) + { + const BitmapColor& rCol = pAcc->GetPaletteColor( i ); + aCol.SetRed( pMapR[ rCol.GetRed() ] ); + aCol.SetGreen( pMapG[ rCol.GetGreen() ] ); + aCol.SetBlue( pMapB[ rCol.GetBlue() ] ); + pAcc->SetPaletteColor( i, aCol ); + } + } + else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) + { + for( nY = 0L; nY < nH; nY++ ) + { + Scanline pScan = pAcc->GetScanline( nY ); + + for( nX = 0L; nX < nW; nX++ ) + { + *pScan = pMapB[ *pScan ]; pScan++; + *pScan = pMapG[ *pScan ]; pScan++; + *pScan = pMapR[ *pScan ]; pScan++; + } + } + } + else + { + for( nY = 0L; nY < nH; nY++ ) + { + for( nX = 0L; nX < nW; nX++ ) + { + aCol = pAcc->GetPixel( nY, nX ); + aCol.SetRed( pMapR[ aCol.GetRed() ] ); + aCol.SetGreen( pMapG[ aCol.GetGreen() ] ); + aCol.SetBlue( pMapB[ aCol.GetBlue() ] ); + pAcc->SetPixel( nY, nX, aCol ); + } + } + } + + Bitmap::ReleaseAccess( pAcc ); + } + } + + if( nStyle & DrawImageFlags::SemiTransparent ) + { + if( aTmpBmpEx.IsTransparent() ) + { + Bitmap aAlphaBmp( aTmpBmpEx.GetAlpha().GetBitmap() ); + + aAlphaBmp.Adjust( 50 ); + aTmpBmpEx = BitmapEx( aTmpBmp, AlphaMask( aAlphaBmp ) ); + } + else + { + sal_uInt8 cErase = 128; + aTmpBmpEx = BitmapEx( aTmpBmp, AlphaMask( aTmpBmp.GetSizePixel(), &cErase ) ); + } + } + else + { + if( aTmpBmpEx.IsAlpha() ) + aTmpBmpEx = BitmapEx( aTmpBmp, aTmpBmpEx.GetAlpha() ); + else if( aTmpBmpEx.IsTransparent() ) + aTmpBmpEx = BitmapEx( aTmpBmp, aTmpBmpEx.GetMask() ); + } + + pOutDev->DrawBitmapEx( rPos, aOutSize, aTmpBmpEx ); + } + else + { + const BitmapEx* pOutputBmp; + + if( pOutDev->GetOutDevType() == OUTDEV_WINDOW ) + { + ImplUpdateDisplayBmp( pOutDev ); + pOutputBmp = mpDisplayBmp; + } + else + pOutputBmp = &maBmpEx; + + if( pOutputBmp ) + pOutDev->DrawBitmapEx( rPos, aOutSize, aSrcPos, maSize, *pOutputBmp ); + } + } + } +} + +void ImplImageBmp::ImplUpdateDisplayBmp(OutputDevice*) +{ + if (!mpDisplayBmp && !maBmpEx.IsEmpty()) + { + mpDisplayBmp = new BitmapEx(maBmpEx); + } +} + +void ImplImageBmp::ImplUpdateDisabledBmpEx() +{ + const Size aTotalSize( maBmpEx.GetSizePixel() ); + + if( maDisabledBmpEx.IsEmpty() ) + { + Bitmap aGrey( aTotalSize, 8, &Bitmap::GetGreyPalette( 256 ) ); + AlphaMask aGreyAlphaMask( aTotalSize ); + + maDisabledBmpEx = BitmapEx( aGrey, aGreyAlphaMask ); + } + + Bitmap aBmp( maBmpEx.GetBitmap() ); + BitmapReadAccess* pBmp( aBmp.AcquireReadAccess() ); + AlphaMask aBmpAlphaMask( maBmpEx.GetAlpha() ); + BitmapReadAccess* pBmpAlphaMask( aBmpAlphaMask.AcquireReadAccess() ); + Bitmap aGrey( maDisabledBmpEx.GetBitmap() ); + BitmapWriteAccess* pGrey( aGrey.AcquireWriteAccess() ); + AlphaMask aGreyAlphaMask( maDisabledBmpEx.GetAlpha() ); + BitmapWriteAccess* pGreyAlphaMask( aGreyAlphaMask.AcquireWriteAccess() ); + + if( pBmp && pBmpAlphaMask && pGrey && pGreyAlphaMask ) + { + BitmapColor aGreyVal( 0 ); + BitmapColor aGreyAlphaMaskVal( 0 ); + + const int nLeft = 0; + const int nRight = nLeft + maSize.Width(); + const int nTop = 0; + const int nBottom = nTop + maSize.Height(); + + for( int nY = nTop; nY < nBottom; ++nY ) + { + for( int nX = nLeft; nX < nRight; ++nX ) + { + aGreyVal.SetIndex( pBmp->GetLuminance( nY, nX ) ); + pGrey->SetPixel( nY, nX, aGreyVal ); + + const BitmapColor aBmpAlphaMaskVal( pBmpAlphaMask->GetPixel( nY, nX ) ); + + aGreyAlphaMaskVal.SetIndex( static_cast< sal_uInt8 >( ::std::min( aBmpAlphaMaskVal.GetIndex() + 178ul, 255ul ) ) ); + pGreyAlphaMask->SetPixel( nY, nX, aGreyAlphaMaskVal ); + } + } + } + + Bitmap::ReleaseAccess( pBmp ); + aBmpAlphaMask.ReleaseAccess( pBmpAlphaMask ); + Bitmap::ReleaseAccess( pGrey ); + aGreyAlphaMask.ReleaseAccess( pGreyAlphaMask ); + + maDisabledBmpEx = BitmapEx( aGrey, aGreyAlphaMask ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/image/ImplImageData.cxx b/vcl/source/image/ImplImageData.cxx new file mode 100644 index 000000000000..6fc0747b2874 --- /dev/null +++ b/vcl/source/image/ImplImageData.cxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <vcl/outdev.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/alpha.hxx> +#include <vcl/window.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/virdev.hxx> +#include <vcl/image.hxx> +#include <vcl/settings.hxx> + +#include <image.h> +#include <memory> + +ImplImageData::ImplImageData( const BitmapEx& rBmpEx ) : + mpImageBitmap( nullptr ), + maBmpEx( rBmpEx ) +{ +} + +ImplImageData::~ImplImageData() +{ + delete mpImageBitmap; +} + +bool ImplImageData::IsEqual( const ImplImageData& rData ) +{ + return( maBmpEx == rData.maBmpEx ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/image/ImplImageList.cxx b/vcl/source/image/ImplImageList.cxx new file mode 100644 index 000000000000..bc137fc9e2e8 --- /dev/null +++ b/vcl/source/image/ImplImageList.cxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <vcl/outdev.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/alpha.hxx> +#include <vcl/window.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/virdev.hxx> +#include <vcl/image.hxx> +#include <vcl/settings.hxx> + +#include <image.h> +#include <memory> + +ImplImageList::ImplImageList() + : mnRefCount(1) +{ +} + +ImplImageList::ImplImageList( const ImplImageList &aSrc ) + : maPrefix(aSrc.maPrefix) + , maImageSize(aSrc.maImageSize) + , mnRefCount(1) +{ + maImages.reserve( aSrc.maImages.size() ); + for ( ImageAryDataVec::const_iterator aIt = aSrc.maImages.begin(), aEnd = aSrc.maImages.end(); aIt != aEnd; ++aIt ) + { + ImageAryData* pAryData = new ImageAryData( **aIt ); + maImages.push_back( pAryData ); + if( !pAryData->maName.isEmpty() ) + maNameHash [ pAryData->maName ] = pAryData; + } +} + +ImplImageList::~ImplImageList() +{ + for ( ImageAryDataVec::iterator aIt = maImages.begin(), aEnd = maImages.end(); aIt != aEnd; ++aIt ) + delete *aIt; +} + +void ImplImageList::AddImage( const OUString &aName, + sal_uInt16 nId, const BitmapEx &aBitmapEx ) +{ + ImageAryData *pImg = new ImageAryData( aName, nId, aBitmapEx ); + maImages.push_back( pImg ); + if( !aName.isEmpty() ) + maNameHash [ aName ] = pImg; +} + +void ImplImageList::RemoveImage( sal_uInt16 nPos ) +{ + ImageAryData *pImg = maImages[ nPos ]; + if( !pImg->maName.isEmpty() ) + maNameHash.erase( pImg->maName ); + maImages.erase( maImages.begin() + nPos ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/image/ImplImageTree.cxx b/vcl/source/image/ImplImageTree.cxx new file mode 100644 index 000000000000..6726673c867d --- /dev/null +++ b/vcl/source/image/ImplImageTree.cxx @@ -0,0 +1,439 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_folders.h> + +#include "sal/config.h" + +#include "com/sun/star/container/XNameAccess.hpp" +#include "com/sun/star/io/XInputStream.hpp" +#include "com/sun/star/lang/Locale.hpp" +#include "com/sun/star/lang/XMultiServiceFactory.hpp" +#include "com/sun/star/packages/zip/ZipFileAccess.hpp" +#include "com/sun/star/uno/Any.hxx" +#include "com/sun/star/uno/Exception.hpp" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "comphelper/processfactory.hxx" +#include "osl/file.hxx" +#include "osl/diagnose.h" +#include "rtl/bootstrap.hxx" +#include "rtl/uri.hxx" + +#include "tools/stream.hxx" +#include "tools/urlobj.hxx" +#include "vcl/bitmapex.hxx" +#include <vcl/dibtools.hxx> +#include <vcl/implimagetree.hxx> +#include "vcl/pngread.hxx" +#include "vcl/settings.hxx" +#include "vcl/svapp.hxx" +#include <vcldemo-debug.hxx> + +#include <vcl/BitmapProcessor.hxx> +#include <vcl/BitmapTools.hxx> + +using namespace css; + +namespace { + +static OUString createPath(OUString const & name, sal_Int32 pos, OUString const & locale) +{ + return name.copy(0, pos + 1) + locale + name.copy(pos); +} + +static std::shared_ptr<SvStream> wrapStream(css::uno::Reference< css::io::XInputStream > const & stream) +{ + // This could use SvInputStream instead if that did not have a broken + // SeekPos implementation for an XInputStream that is not also XSeekable + // (cf. "@@@" at tags/DEV300_m37/svtools/source/misc1/strmadpt.cxx@264807 + // l. 593): + OSL_ASSERT(stream.is()); + std::shared_ptr<SvStream> s(std::make_shared<SvMemoryStream>()); + for (;;) + { + sal_Int32 const size = 2048; + css::uno::Sequence< sal_Int8 > data(size); + sal_Int32 n = stream->readBytes(data, size); + s->Write(data.getConstArray(), n); + if (n < size) + break; + } + s->Seek(0); + return s; +} + +static void loadImageFromStream(std::shared_ptr<SvStream> xStream, OUString const & rPath, BitmapEx & rBitmap) +{ + if (rPath.endsWith(".png")) + { + vcl::PNGReader aPNGReader(*xStream); + aPNGReader.SetIgnoreGammaChunk( true ); + rBitmap = aPNGReader.Read(); + } + else if (rPath.endsWith(".svg")) + { + vcl::BitmapTools::loadFromSvg(*xStream.get(), rPath, rBitmap); + } + else + { + ReadDIBBitmapEx(rBitmap, *xStream); + } +} + +} + +ImplImageTree & ImplImageTree::get() { + static ImplImageTree s_ImplImageTree; + return s_ImplImageTree; +} + +ImplImageTree::ImplImageTree() +{ +} + +ImplImageTree::~ImplImageTree() +{ +} + +OUString ImplImageTree::getImageUrl( + OUString const & name, OUString const & style, OUString const & lang) +{ + OUString aStyle(style); + while (!aStyle.isEmpty()) + { + try { + setStyle(aStyle); + + std::vector< OUString > paths; + paths.push_back(getRealImageName(name)); + + if (!lang.isEmpty()) + { + sal_Int32 pos = name.lastIndexOf('/'); + if (pos != -1) + { + std::vector<OUString> aFallbacks( + LanguageTag(lang).getFallbackStrings(true)); + for (std::vector< OUString >::reverse_iterator it( aFallbacks.rbegin()); + it != aFallbacks.rend(); ++it) + { + paths.push_back( getRealImageName( createPath(name, pos, *it) ) ); + } + } + } + + try { + if (checkPathAccess()) { + const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess; + + for (std::vector<OUString>::const_reverse_iterator j(paths.rbegin()); j != paths.rend(); ++j) + { + if (rNameAccess->hasByName(*j)) + { + return "vnd.sun.star.zip://" + + rtl::Uri::encode( + maIconSet[maCurrentStyle].maURL + ".zip", + rtl_UriCharClassRegName, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8) + + "/" + *j; + // assuming *j contains no problematic chars + } + } + } + } catch (css::uno::RuntimeException &) { + throw; + } catch (const css::uno::Exception & e) { + SAL_INFO("vcl", "exception " << e.Message); + } + } + catch (css::uno::RuntimeException &) {} + + aStyle = fallbackStyle(aStyle); + } + return OUString(); +} + +OUString ImplImageTree::fallbackStyle(const OUString &style) +{ + if (style == "galaxy") + return OUString(); + else if (style == "industrial") + return OUString("galaxy"); + else if (style == "tango") + return OUString("galaxy"); + else if (style == "breeze") + return OUString("galaxy"); + else if (style == "sifr") + return OUString("breeze"); + + return OUString("tango"); +} + +bool ImplImageTree::loadImage(OUString const & name, OUString const & style, BitmapEx & bitmap, + bool localized, bool loadMissing) +{ + OUString aStyle(style); + while (!aStyle.isEmpty()) + { + try { + if (doLoadImage(name, aStyle, bitmap, localized)) + { + static bool bIconsForDarkTheme = !!getenv("VCL_ICONS_FOR_DARK_THEME"); + if (bIconsForDarkTheme) + bitmap = BitmapProcessor::createLightImage(bitmap); + return true; + } + } + catch (css::uno::RuntimeException &) {} + + aStyle = fallbackStyle(aStyle); + } + + if (!loadMissing) + return false; + + SAL_INFO("vcl", "ImplImageTree::loadImage couldn't load \"" << name << "\", fetching default image"); + + return loadDefaultImage(style, bitmap); +} + +bool ImplImageTree::loadDefaultImage(OUString const & style, BitmapEx& bitmap) +{ + return doLoadImage( + "res/grafikde.png", + style, bitmap, false); +} + +bool ImplImageTree::doLoadImage(OUString const & name, OUString const & style, BitmapEx & bitmap, + bool localized) +{ + setStyle(style); + if (iconCacheLookup(name, localized, bitmap)) + return true; + + if (!bitmap.IsEmpty()) + bitmap.SetEmpty(); + + std::vector< OUString > paths; + paths.push_back(getRealImageName(name)); + + if (localized) + { + sal_Int32 pos = name.lastIndexOf('/'); + if (pos != -1) + { + // findImage() uses a reverse iterator, so push in reverse order. + std::vector< OUString > aFallbacks( Application::GetSettings().GetUILanguageTag().getFallbackStrings(true)); + for (std::vector< OUString >::reverse_iterator it( aFallbacks.rbegin()); + it != aFallbacks.rend(); ++it) + { + paths.push_back( getRealImageName( createPath(name, pos, *it) ) ); + } + } + } + + bool found = false; + try { + found = findImage(paths, bitmap); + } catch (css::uno::RuntimeException &) { + throw; + } catch (const css::uno::Exception & e) { + SAL_INFO("vcl", "ImplImageTree::doLoadImage exception " << e.Message); + } + + if (found) + maIconSet[maCurrentStyle].maIconCache[name] = std::make_pair(localized, bitmap); + + return found; +} + +void ImplImageTree::shutDown() +{ + maCurrentStyle.clear(); + for (StyleIconSet::iterator it = maIconSet.begin(); it != maIconSet.end(); ++it) + { + it->second.maIconCache.clear(); + it->second.maLinkHash.clear(); + } +} + +void ImplImageTree::setStyle(OUString const & style) +{ + assert(!style.isEmpty()); + if (style != maCurrentStyle) + { + maCurrentStyle = style; + createStyle(); + } +} + +void ImplImageTree::createStyle() +{ + if (maIconSet.find(maCurrentStyle) != maIconSet.end()) + return; + + OUString url( "$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/config/" ); + rtl::Bootstrap::expandMacros(url); + if (maCurrentStyle != "default") + { + INetURLObject u(url); + OSL_ASSERT(!u.HasError()); + bool ok = u.Append("images_" + maCurrentStyle, INetURLObject::ENCODE_ALL); + OSL_ASSERT(ok); (void) ok; + url = u.GetMainURL(INetURLObject::NO_DECODE); + } + else + url += "images"; + + maIconSet[maCurrentStyle] = IconSet(url); + + loadImageLinks(); +} + +bool ImplImageTree::iconCacheLookup(OUString const & name, bool localized, BitmapEx & bitmap) +{ + IconCache &rIconCache = maIconSet[maCurrentStyle].maIconCache; + + IconCache::iterator i(rIconCache.find(getRealImageName(name))); + if (i != rIconCache.end() && i->second.first == localized) + { + bitmap = i->second.second; + return true; + } + return false; +} + +bool ImplImageTree::findImage(std::vector<OUString> const & paths, BitmapEx & bitmap) +{ + if (!checkPathAccess()) + return false; + + const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess; + + for (std::vector<OUString>::const_reverse_iterator j(paths.rbegin()); j != paths.rend(); ++j) + { + if (rNameAccess->hasByName(*j)) + { + css::uno::Reference< css::io::XInputStream > s; + bool ok = rNameAccess->getByName(*j) >>= s; + assert(ok); + (void)ok; // prevent unused warning in release build + + loadImageFromStream( wrapStream(s), *j, bitmap ); + return true; + } + } + return false; +} + +void ImplImageTree::loadImageLinks() +{ + const OUString aLinkFilename("links.txt"); + + if (!checkPathAccess()) + return; + + const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess; + + if (rNameAccess->hasByName(aLinkFilename)) + { + css::uno::Reference< css::io::XInputStream > s; + bool ok = rNameAccess->getByName(aLinkFilename) >>= s; + assert(ok); + (void)ok; // prevent unused warning in release build + + parseLinkFile( wrapStream(s) ); + return; + } +} + +void ImplImageTree::parseLinkFile(std::shared_ptr<SvStream> xStream) +{ + OString aLine; + OUString aLink, aOriginal; + int nLineNo = 0; + while (xStream->ReadLine(aLine)) + { + ++nLineNo; + if ( aLine.isEmpty() ) + continue; + + sal_Int32 nIndex = 0; + aLink = OStringToOUString( aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8 ); + aOriginal = OStringToOUString( aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8 ); + + // skip comments, or incomplete entries + if (aLink.isEmpty() || aLink[0] == '#' || aOriginal.isEmpty()) + { + if (aLink.isEmpty() || aOriginal.isEmpty()) + SAL_WARN("vcl", "ImplImageTree::parseLinkFile: icon links.txt parse error, incomplete link at line " << nLineNo); + continue; + } + + maIconSet[maCurrentStyle].maLinkHash[aLink] = aOriginal; + } +} + +OUString const & ImplImageTree::getRealImageName(OUString const & name) +{ + IconLinkHash &rLinkHash = maIconSet[maCurrentStyle].maLinkHash; + + IconLinkHash::iterator it(rLinkHash.find(name)); + if (it == rLinkHash.end()) + return name; + + return it->second; +} + +bool ImplImageTree::checkPathAccess() +{ + uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess; + if (rNameAccess.is()) + return true; + + try { + rNameAccess = css::packages::zip::ZipFileAccess::createWithURL(comphelper::getProcessComponentContext(), maIconSet[maCurrentStyle].maURL + ".zip"); + } + catch (const css::uno::RuntimeException &) { + throw; + } + catch (const css::uno::Exception & e) { + SAL_INFO("vcl", "ImplImageTree::zip file location exception " << e.Message << " for " << maIconSet[maCurrentStyle].maURL); + return false; + } + return rNameAccess.is(); +} + +css::uno::Reference<css::container::XNameAccess> ImplImageTree::getNameAccess() +{ + checkPathAccess(); + return maIconSet[maCurrentStyle].maNameAccess; +} + +/// Recursively dump all names ... +css::uno::Sequence<OUString> ImageTree_getAllImageNames() +{ + css::uno::Reference<css::container::XNameAccess> xRef(ImplImageTree::get().getNameAccess()); + + return xRef->getElementNames(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |