LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/vcl/source/gdi - impimagetree.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 143 187 76.5 %
Date: 2013-07-09 Functions: 20 21 95.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : 
      21             : #include "sal/config.h"
      22             : 
      23             : #include <boost/shared_ptr.hpp>
      24             : 
      25             : #include "com/sun/star/container/XNameAccess.hpp"
      26             : #include "com/sun/star/io/XInputStream.hpp"
      27             : #include "com/sun/star/lang/Locale.hpp"
      28             : #include "com/sun/star/lang/XMultiServiceFactory.hpp"
      29             : #include "com/sun/star/packages/zip/ZipFileAccess.hpp"
      30             : #include "com/sun/star/uno/Any.hxx"
      31             : #include "com/sun/star/uno/Exception.hpp"
      32             : #include "com/sun/star/uno/RuntimeException.hpp"
      33             : #include "com/sun/star/uno/Sequence.hxx"
      34             : #include "comphelper/processfactory.hxx"
      35             : #include "osl/file.hxx"
      36             : #include "osl/diagnose.h"
      37             : #include "rtl/bootstrap.hxx"
      38             : 
      39             : #include "tools/stream.hxx"
      40             : #include "tools/urlobj.hxx"
      41             : #include "vcl/bitmapex.hxx"
      42             : #include <vcl/dibtools.hxx>
      43             : #include "vcl/pngread.hxx"
      44             : #include "vcl/settings.hxx"
      45             : #include "vcl/svapp.hxx"
      46             : #include "impimagetree.hxx"
      47             : #include <vcl/dibtools.hxx>
      48             : 
      49             : namespace {
      50             : 
      51        9924 : static OUString createPath(
      52             :     OUString const & name, sal_Int32 pos, OUString const & locale)
      53             : {
      54        9924 :     return name.copy(0, pos + 1) + locale + name.copy(pos);
      55             : }
      56             : 
      57           0 : static boost::shared_ptr< SvStream > wrapFile(osl::File & file)
      58             : {
      59             :     // This could use SvInputStream instead if that did not have a broken
      60             :     // SeekPos implementation for an XInputStream that is not also XSeekable
      61             :     // (cf. "@@@" at tags/DEV300_m37/svtools/source/misc1/strmadpt.cxx@264807
      62             :     // l. 593):
      63           0 :     boost::shared_ptr< SvStream > s(new SvMemoryStream);
      64             :     for (;;) {
      65             :         void *data[2048];
      66             :         sal_uInt64 n;
      67           0 :         file.read(data, 2048, n);
      68           0 :         s->Write(data, n);
      69           0 :         if (n < 2048) {
      70           0 :             break;
      71             :         }
      72           0 :     }
      73           0 :     s->Seek(0);
      74           0 :     return s;
      75             : }
      76             : 
      77        3456 : static boost::shared_ptr< SvStream > wrapStream(
      78             :     css::uno::Reference< css::io::XInputStream > const & stream)
      79             : {
      80             :     // This could use SvInputStream instead if that did not have a broken
      81             :     // SeekPos implementation for an XInputStream that is not also XSeekable
      82             :     // (cf. "@@@" at tags/DEV300_m37/svtools/source/misc1/strmadpt.cxx@264807
      83             :     // l. 593):
      84             :     OSL_ASSERT(stream.is());
      85        3456 :     boost::shared_ptr< SvStream > s(new SvMemoryStream);
      86             :     for (;;) {
      87        3748 :         sal_Int32 const size = 2048;
      88        3748 :         css::uno::Sequence< sal_Int8 > data(size);
      89        3748 :         sal_Int32 n = stream->readBytes(data, size);
      90        3748 :         s->Write(data.getConstArray(), n);
      91        3748 :         if (n < size) {
      92        3456 :             break;
      93             :         }
      94         292 :     }
      95        3456 :     s->Seek(0);
      96        3456 :     return s;
      97             : }
      98             : 
      99        3424 : static void loadImageFromStream(
     100             :     boost::shared_ptr< SvStream > pStream,
     101             :     OUString const & rPath, BitmapEx & rBitmap)
     102             : {
     103        3424 :     if (rPath.endsWith(".png"))
     104             :     {
     105        3420 :         vcl::PNGReader aPNGReader( *pStream );
     106        3420 :         aPNGReader.SetIgnoreGammaChunk( true );
     107        3420 :         rBitmap = aPNGReader.Read();
     108             :     } else {
     109           4 :         ReadDIBBitmapEx(rBitmap, *pStream);
     110             :     }
     111        3424 : }
     112             : 
     113             : }
     114             : 
     115         124 : ImplImageTree::ImplImageTree() { m_cacheIcons = true; }
     116             : 
     117         124 : ImplImageTree::~ImplImageTree() {}
     118             : 
     119         322 : bool ImplImageTree::checkStyle(OUString const & style)
     120             : {
     121             :     bool exists;
     122             : 
     123             :     // using cache because setStyle is an expensive operation
     124             :     // setStyle calls resetPaths => closes any opened zip files with icons, cleans the icon cache, ...
     125         322 :     if (checkStyleCacheLookup(style, exists)) {
     126          29 :         return exists;
     127             :     }
     128             : 
     129         293 :     setStyle(style);
     130             : 
     131         293 :     exists = false;
     132         293 :     OUString aURL = m_path.first;
     133             : 
     134         586 :     osl::File aZip(aURL + ".zip");
     135         293 :     if (aZip.open(osl_File_OpenFlag_Read) == ::osl::FileBase::E_None) {
     136          32 :         aZip.close();
     137          32 :         exists = true;
     138             :     }
     139             : 
     140         586 :     osl::Directory aLookaside(aURL);
     141         293 :     if (aLookaside.open() == ::osl::FileBase::E_None) {
     142           0 :         aLookaside.close();
     143           0 :         exists = true;
     144           0 :         m_cacheIcons = false;
     145             :     } else {
     146         293 :         m_cacheIcons = true;
     147             :     }
     148         293 :     m_checkStyleCache[style] = exists;
     149         586 :     return exists;
     150             : }
     151             : 
     152       18090 : bool ImplImageTree::loadImage(
     153             :     OUString const & name, OUString const & style, BitmapEx & bitmap,
     154             :     bool localized, bool loadMissing )
     155             : {
     156       18090 :     bool found = false;
     157             :     try {
     158       18090 :         found = doLoadImage(name, style, bitmap, localized);
     159           0 :     } catch (css::uno::RuntimeException &) {
     160           0 :         if (!loadMissing)
     161           0 :             throw;
     162             :     }
     163       18090 :     if (found || !loadMissing)
     164       18090 :         return found;
     165             : 
     166             :     SAL_INFO("vcl", "ImplImageTree::loadImage exception couldn't load \""
     167             :         << name << "\", fetching default image");
     168             : 
     169           0 :     return loadDefaultImage(style, bitmap);
     170             : }
     171             : 
     172        4161 : bool ImplImageTree::loadDefaultImage(
     173             :     OUString const & style,
     174             :     BitmapEx& bitmap)
     175             : {
     176             :     return doLoadImage(
     177             :         OUString("res/grafikde.png"),
     178        4161 :         style, bitmap, false);
     179             : }
     180             : 
     181             : 
     182       22251 : bool ImplImageTree::doLoadImage(
     183             :     OUString const & name, OUString const & style, BitmapEx & bitmap,
     184             :     bool localized)
     185             : {
     186       22251 :     setStyle(style);
     187       22251 :     if (m_cacheIcons && iconCacheLookup(name, localized, bitmap)) {
     188       17121 :         return true;
     189             :     }
     190        5130 :     if (!bitmap.IsEmpty()) {
     191           0 :         bitmap.SetEmpty();
     192             :     }
     193        5130 :     std::vector< OUString > paths;
     194        5130 :     paths.push_back(getRealImageName(name));
     195        5130 :     if (localized) {
     196        4962 :         sal_Int32 pos = name.lastIndexOf('/');
     197        4962 :         if (pos != -1) {
     198             :             // find() uses a reverse iterator, so push in reverse order.
     199        4962 :             std::vector< OUString > aFallbacks( Application::GetSettings().GetUILanguageTag().getFallbackStrings());
     200       44658 :             for (std::vector< OUString >::const_reverse_iterator it( aFallbacks.rbegin());
     201       29772 :                     it != aFallbacks.rend(); ++it)
     202             :             {
     203        9924 :                 paths.push_back( getRealImageName( createPath(name, pos, *it) ) );
     204        4962 :             }
     205             :         }
     206             :     }
     207        5130 :     bool found = false;
     208             :     try {
     209        5130 :         found = find(paths, bitmap);
     210           0 :     } catch (css::uno::RuntimeException &) {
     211           0 :         throw;
     212           0 :     } catch (const css::uno::Exception & e) {
     213             :         SAL_INFO("vcl", "ImplImageTree::doLoadImage exception " << e.Message);
     214             :     }
     215        5130 :     if (m_cacheIcons && found) {
     216        3424 :         m_iconCache[name.intern()] = std::make_pair(localized, bitmap);
     217             :     }
     218        5130 :     return found;
     219             : }
     220             : 
     221          94 : void ImplImageTree::shutDown() {
     222          94 :     m_style = OUString();
     223             :         // for safety; empty m_style means "not initialized"
     224          94 :     m_iconCache.clear();
     225          94 :     m_checkStyleCache.clear();
     226          94 :     m_iconLinkCache.clear();
     227          94 : }
     228             : 
     229       22544 : void ImplImageTree::setStyle(OUString const & style) {
     230             :     OSL_ASSERT(!style.isEmpty()); // empty m_style means "not initialized"
     231       22544 :     if (style != m_style) {
     232         322 :         m_style = style;
     233         322 :         resetPaths();
     234         322 :         m_iconCache.clear();
     235         322 :         m_iconLinkCache.clear();
     236         322 :         loadImageLinks();
     237             :     }
     238       22544 : }
     239             : 
     240         322 : void ImplImageTree::resetPaths() {
     241         322 :     OUString url( "$BRAND_BASE_DIR/share/config/" );
     242         322 :     rtl::Bootstrap::expandMacros(url);
     243         322 :     if ( m_style != "default" )
     244             :     {
     245         293 :         INetURLObject u(url);
     246             :         OSL_ASSERT(!u.HasError());
     247         293 :         bool ok = u.Append("images_" + m_style, INetURLObject::ENCODE_ALL);
     248             :         OSL_ASSERT(ok); (void) ok;
     249         293 :         url = u.GetMainURL(INetURLObject::NO_DECODE);
     250             :     }
     251             :     else
     252          29 :         url += "images";
     253         644 :     m_path = std::make_pair(
     254         644 :         url, css::uno::Reference< css::container::XNameAccess >());
     255         322 : }
     256             : 
     257         322 : bool ImplImageTree::checkStyleCacheLookup(
     258             :     OUString const & style, bool &exists)
     259             : {
     260         322 :     CheckStyleCache::iterator i(m_checkStyleCache.find(style));
     261         322 :     if (i != m_checkStyleCache.end()) {
     262          29 :         exists = i->second;
     263          29 :         return true;
     264             :     } else {
     265         293 :         return false;
     266             :     }
     267             : }
     268             : 
     269       22251 : bool ImplImageTree::iconCacheLookup(
     270             :     OUString const & name, bool localized, BitmapEx & bitmap)
     271             : {
     272       22251 :     IconCache::iterator i(m_iconCache.find(name));
     273       22251 :     if (i != m_iconCache.end() && i->second.first == localized) {
     274       17121 :         bitmap = i->second.second;
     275       17121 :         return true;
     276             :     } else {
     277        5130 :         return false;
     278             :     }
     279             : }
     280             : 
     281        5130 : bool ImplImageTree::find(
     282             :     std::vector< OUString > const & paths, BitmapEx & bitmap)
     283             : {
     284        5130 :     if (!m_cacheIcons) {
     285           0 :         for (std::vector< OUString >::const_reverse_iterator j(
     286           0 :                  paths.rbegin());
     287           0 :              j != paths.rend(); ++j)
     288             :         {
     289           0 :             osl::File file(m_path.first + "/" + *j);
     290           0 :             if (file.open(osl_File_OpenFlag_Read) == ::osl::FileBase::E_None) {
     291           0 :                 loadImageFromStream( wrapFile(file), *j, bitmap );
     292           0 :                 file.close();
     293           0 :                 return true;
     294             :             }
     295           0 :         }
     296             :     }
     297             : 
     298        5130 :     if (!m_path.second.is()) {
     299             :         try {
     300        1706 :             m_path.second = css::packages::zip::ZipFileAccess::createWithURL(comphelper::getProcessComponentContext(), m_path.first + ".zip");
     301           0 :         } catch (const css::uno::RuntimeException &) {
     302           0 :             throw;
     303        3412 :         } catch (const css::uno::Exception & e) {
     304             :             SAL_INFO("vcl", "ImplImageTree::find exception "
     305             :                 << e.Message << " for " << m_path.first);
     306        1706 :             return false;
     307             :         }
     308             :     }
     309       30804 :     for (std::vector< OUString >::const_reverse_iterator j(paths.rbegin());
     310       20536 :          j != paths.rend(); ++j)
     311             :     {
     312       10268 :         if (m_path.second->hasByName(*j)) {
     313        3424 :             css::uno::Reference< css::io::XInputStream > s;
     314        3424 :             bool ok = m_path.second->getByName(*j) >>= s;
     315             :             OSL_ASSERT(ok); (void) ok;
     316        3424 :             loadImageFromStream( wrapStream(s), *j, bitmap );
     317        3424 :             return true;
     318             :         }
     319             :     }
     320           0 :     return false;
     321             : }
     322             : 
     323         322 : void ImplImageTree::loadImageLinks()
     324             : {
     325         322 :     const OUString aLinkFilename("links.txt");
     326             : 
     327         322 :     if (!m_cacheIcons)
     328             :     {
     329           0 :         osl::File file(m_path.first + "/" + aLinkFilename);
     330           0 :         if (file.open(osl_File_OpenFlag_Read) == ::osl::FileBase::E_None)
     331             :         {
     332           0 :             parseLinkFile( wrapFile(file) );
     333           0 :             file.close();
     334           0 :             return;
     335           0 :         }
     336             :     }
     337             : 
     338         322 :     if ( !m_path.second.is() )
     339             :     {
     340             :         try
     341             :         {
     342         322 :             m_path.second = css::packages::zip::ZipFileAccess::createWithURL(comphelper::getProcessComponentContext(), m_path.first + ".zip");
     343           0 :         } catch (const css::uno::RuntimeException &) {
     344           0 :             throw;
     345             :         }
     346         580 :         catch (const css::uno::Exception & e)
     347             :         {
     348             :             SAL_INFO("vcl", "ImplImageTree::find exception "
     349             :                 << e.Message << " for " << m_path.first);
     350         290 :             return;
     351             :         }
     352             :     }
     353          32 :     if ( m_path.second->hasByName(aLinkFilename) )
     354             :     {
     355          32 :         css::uno::Reference< css::io::XInputStream > s;
     356          32 :         bool ok = m_path.second->getByName(aLinkFilename) >>= s;
     357             :         OSL_ASSERT(ok); (void) ok;
     358             : 
     359          32 :         parseLinkFile( wrapStream(s) );
     360          32 :         return;
     361           0 :     }
     362             : }
     363             : 
     364          32 : void ImplImageTree::parseLinkFile(boost::shared_ptr< SvStream > pStream)
     365             : {
     366          32 :     OString aLine;
     367          64 :     OUString aLink, aOriginal;
     368       12640 :     while ( pStream->ReadLine( aLine ) )
     369             :     {
     370       12576 :         sal_Int32 nIndex = 0;
     371       12576 :         if ( aLine.isEmpty() )
     372           0 :             continue;
     373       12576 :         aLink = OStringToOUString( aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8 );
     374       12576 :         aOriginal = OStringToOUString( aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8 );
     375       12576 :         if ( aLink.isEmpty() || aOriginal.isEmpty() )
     376             :         {
     377             :             SAL_INFO("vcl", "ImplImageTree::parseLinkFile: icon links.txt parse error. "
     378             :                 "Link is incomplete." );
     379           0 :             continue;
     380             :         }
     381       12576 :         m_iconLinkCache[aLink] = aOriginal;
     382          32 :     }
     383          32 : }
     384             : 
     385       15054 : OUString const & ImplImageTree::getRealImageName(OUString const & name)
     386             : {
     387       15054 :     IconLinkCache::iterator it(m_iconLinkCache.find(name));
     388       15054 :     if (it == m_iconLinkCache.end())
     389       15054 :         return name;
     390           0 :     return it->second;
     391         465 : }
     392             : 
     393             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10