LCOV - code coverage report
Current view: top level - vcl/source/gdi - impimagetree.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 7 164 4.3 %
Date: 2014-04-14 Functions: 3 17 17.6 %
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             : #include <config_folders.h>
      21             : 
      22             : #include "sal/config.h"
      23             : 
      24             : #include <boost/shared_ptr.hpp>
      25             : 
      26             : #include "com/sun/star/container/XNameAccess.hpp"
      27             : #include "com/sun/star/io/XInputStream.hpp"
      28             : #include "com/sun/star/lang/Locale.hpp"
      29             : #include "com/sun/star/lang/XMultiServiceFactory.hpp"
      30             : #include "com/sun/star/packages/zip/ZipFileAccess.hpp"
      31             : #include "com/sun/star/uno/Any.hxx"
      32             : #include "com/sun/star/uno/Exception.hpp"
      33             : #include "com/sun/star/uno/RuntimeException.hpp"
      34             : #include "com/sun/star/uno/Sequence.hxx"
      35             : #include "comphelper/processfactory.hxx"
      36             : #include "osl/file.hxx"
      37             : #include "osl/diagnose.h"
      38             : #include "rtl/bootstrap.hxx"
      39             : 
      40             : #include "tools/stream.hxx"
      41             : #include "tools/urlobj.hxx"
      42             : #include "vcl/bitmapex.hxx"
      43             : #include <vcl/dibtools.hxx>
      44             : #include "vcl/pngread.hxx"
      45             : #include "vcl/settings.hxx"
      46             : #include "vcl/svapp.hxx"
      47             : #include "impimagetree.hxx"
      48             : 
      49             : namespace {
      50             : 
      51           0 : static OUString createPath(
      52             :     OUString const & name, sal_Int32 pos, OUString const & locale)
      53             : {
      54           0 :     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           0 : 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           0 :     boost::shared_ptr< SvStream > s(new SvMemoryStream);
      86             :     for (;;) {
      87           0 :         sal_Int32 const size = 2048;
      88           0 :         css::uno::Sequence< sal_Int8 > data(size);
      89           0 :         sal_Int32 n = stream->readBytes(data, size);
      90           0 :         s->Write(data.getConstArray(), n);
      91           0 :         if (n < size) {
      92           0 :             break;
      93             :         }
      94           0 :     }
      95           0 :     s->Seek(0);
      96           0 :     return s;
      97             : }
      98             : 
      99           0 : static void loadImageFromStream(
     100             :     boost::shared_ptr< SvStream > pStream,
     101             :     OUString const & rPath, BitmapEx & rBitmap)
     102             : {
     103           0 :     if (rPath.endsWith(".png"))
     104             :     {
     105           0 :         vcl::PNGReader aPNGReader( *pStream );
     106           0 :         aPNGReader.SetIgnoreGammaChunk( true );
     107           0 :         rBitmap = aPNGReader.Read();
     108             :     } else {
     109           0 :         ReadDIBBitmapEx(rBitmap, *pStream);
     110             :     }
     111           0 : }
     112             : 
     113             : }
     114             : 
     115           1 : ImplImageTree::ImplImageTree() { m_cacheIcons = true; }
     116             : 
     117           1 : ImplImageTree::~ImplImageTree() {}
     118             : 
     119           0 : bool ImplImageTree::loadImage(
     120             :     OUString const & name, OUString const & style, BitmapEx & bitmap,
     121             :     bool localized, bool loadMissing )
     122             : {
     123           0 :     bool found = false;
     124             :     try {
     125           0 :         found = doLoadImage(name, style, bitmap, localized);
     126           0 :     } catch (css::uno::RuntimeException &) {
     127           0 :         if (!loadMissing)
     128           0 :             throw;
     129             :     }
     130           0 :     if (found || !loadMissing)
     131           0 :         return found;
     132             : 
     133             :     SAL_INFO("vcl", "ImplImageTree::loadImage exception couldn't load \""
     134             :         << name << "\", fetching default image");
     135             : 
     136           0 :     return loadDefaultImage(style, bitmap);
     137             : }
     138             : 
     139           0 : bool ImplImageTree::loadDefaultImage(
     140             :     OUString const & style,
     141             :     BitmapEx& bitmap)
     142             : {
     143             :     return doLoadImage(
     144             :         OUString("res/grafikde.png"),
     145           0 :         style, bitmap, false);
     146             : }
     147             : 
     148           0 : bool ImplImageTree::doLoadImage(
     149             :     OUString const & name, OUString const & style, BitmapEx & bitmap,
     150             :     bool localized)
     151             : {
     152           0 :     setStyle(style);
     153           0 :     if (m_cacheIcons && iconCacheLookup(name, localized, bitmap)) {
     154           0 :         return true;
     155             :     }
     156           0 :     if (!bitmap.IsEmpty()) {
     157           0 :         bitmap.SetEmpty();
     158             :     }
     159           0 :     std::vector< OUString > paths;
     160           0 :     paths.push_back(getRealImageName(name));
     161           0 :     if (localized) {
     162           0 :         sal_Int32 pos = name.lastIndexOf('/');
     163           0 :         if (pos != -1) {
     164             :             // find() uses a reverse iterator, so push in reverse order.
     165           0 :             std::vector< OUString > aFallbacks( Application::GetSettings().GetUILanguageTag().getFallbackStrings( true));
     166           0 :             for (std::vector< OUString >::reverse_iterator it( aFallbacks.rbegin());
     167           0 :                     it != aFallbacks.rend(); ++it)
     168             :             {
     169           0 :                 paths.push_back( getRealImageName( createPath(name, pos, *it) ) );
     170           0 :             }
     171             :         }
     172             :     }
     173           0 :     bool found = false;
     174             :     try {
     175           0 :         found = find(paths, bitmap);
     176           0 :     } catch (css::uno::RuntimeException &) {
     177           0 :         throw;
     178           0 :     } catch (const css::uno::Exception & e) {
     179             :         SAL_INFO("vcl", "ImplImageTree::doLoadImage exception " << e.Message);
     180             :     }
     181           0 :     if (m_cacheIcons && found) {
     182           0 :         m_iconCache[name.intern()] = std::make_pair(localized, bitmap);
     183             :     }
     184           0 :     return found;
     185             : }
     186             : 
     187           1 : void ImplImageTree::shutDown() {
     188           1 :     m_style = OUString();
     189             :         // for safety; empty m_style means "not initialized"
     190           1 :     m_iconCache.clear();
     191           1 :     m_linkHash.clear();
     192           1 : }
     193             : 
     194           0 : void ImplImageTree::setStyle(OUString const & style) {
     195             :     OSL_ASSERT(!style.isEmpty()); // empty m_style means "not initialized"
     196           0 :     if (style != m_style) {
     197           0 :         m_style = style;
     198           0 :         resetPaths();
     199           0 :         m_iconCache.clear();
     200           0 :         m_linkHash.clear();
     201           0 :         loadImageLinks();
     202             :     }
     203           0 : }
     204             : 
     205           0 : void ImplImageTree::resetPaths() {
     206           0 :     OUString url( "$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/config/" );
     207           0 :     rtl::Bootstrap::expandMacros(url);
     208           0 :     if ( m_style != "default" )
     209             :     {
     210           0 :         INetURLObject u(url);
     211             :         OSL_ASSERT(!u.HasError());
     212           0 :         bool ok = u.Append("images_" + m_style, INetURLObject::ENCODE_ALL);
     213             :         OSL_ASSERT(ok); (void) ok;
     214           0 :         url = u.GetMainURL(INetURLObject::NO_DECODE);
     215             :     }
     216             :     else
     217           0 :         url += "images";
     218           0 :     m_path = std::make_pair(
     219           0 :         url, css::uno::Reference< css::container::XNameAccess >());
     220           0 : }
     221             : 
     222           0 : bool ImplImageTree::iconCacheLookup(
     223             :     OUString const & name, bool localized, BitmapEx & bitmap)
     224             : {
     225           0 :     IconCache::iterator i(m_iconCache.find(getRealImageName(name)));
     226           0 :     if (i != m_iconCache.end() && i->second.first == localized) {
     227           0 :         bitmap = i->second.second;
     228           0 :         return true;
     229             :     }
     230           0 :     return false;
     231             : }
     232             : 
     233           0 : bool ImplImageTree::find(
     234             :     std::vector< OUString > const & paths, BitmapEx & bitmap)
     235             : {
     236           0 :     if (!m_cacheIcons) {
     237           0 :         for (std::vector< OUString >::const_reverse_iterator j(
     238           0 :                  paths.rbegin());
     239           0 :              j != paths.rend(); ++j)
     240             :         {
     241           0 :             osl::File file(m_path.first + "/" + *j);
     242           0 :             if (file.open(osl_File_OpenFlag_Read) == ::osl::FileBase::E_None) {
     243           0 :                 loadImageFromStream( wrapFile(file), *j, bitmap );
     244           0 :                 file.close();
     245           0 :                 return true;
     246             :             }
     247           0 :         }
     248             :     }
     249             : 
     250           0 :     if (!m_path.second.is()) {
     251             :         try {
     252           0 :             m_path.second = css::packages::zip::ZipFileAccess::createWithURL(comphelper::getProcessComponentContext(), m_path.first + ".zip");
     253           0 :         } catch (const css::uno::RuntimeException &) {
     254           0 :             throw;
     255           0 :         } catch (const css::uno::Exception & e) {
     256             :             SAL_INFO("vcl", "ImplImageTree::find exception "
     257             :                 << e.Message << " for " << m_path.first);
     258           0 :             return false;
     259             :         }
     260             :     }
     261           0 :     for (std::vector< OUString >::const_reverse_iterator j(paths.rbegin());
     262           0 :          j != paths.rend(); ++j)
     263             :     {
     264           0 :         if (m_path.second->hasByName(*j)) {
     265           0 :             css::uno::Reference< css::io::XInputStream > s;
     266           0 :             bool ok = m_path.second->getByName(*j) >>= s;
     267             :             OSL_ASSERT(ok); (void) ok;
     268           0 :             loadImageFromStream( wrapStream(s), *j, bitmap );
     269           0 :             return true;
     270             :         }
     271             :     }
     272           0 :     return false;
     273             : }
     274             : 
     275           0 : void ImplImageTree::loadImageLinks()
     276             : {
     277           0 :     const OUString aLinkFilename("links.txt");
     278             : 
     279           0 :     if (!m_cacheIcons)
     280             :     {
     281           0 :         osl::File file(m_path.first + "/" + aLinkFilename);
     282           0 :         if (file.open(osl_File_OpenFlag_Read) == ::osl::FileBase::E_None)
     283             :         {
     284           0 :             parseLinkFile( wrapFile(file) );
     285           0 :             file.close();
     286           0 :             return;
     287           0 :         }
     288             :     }
     289             : 
     290           0 :     if ( !m_path.second.is() )
     291             :     {
     292             :         try
     293             :         {
     294           0 :             m_path.second = css::packages::zip::ZipFileAccess::createWithURL(comphelper::getProcessComponentContext(), m_path.first + ".zip");
     295           0 :         } catch (const css::uno::RuntimeException &) {
     296           0 :             throw;
     297             :         }
     298           0 :         catch (const css::uno::Exception & e)
     299             :         {
     300             :             SAL_INFO("vcl", "ImplImageTree::find exception "
     301             :                 << e.Message << " for " << m_path.first);
     302           0 :             return;
     303             :         }
     304             :     }
     305           0 :     if ( m_path.second->hasByName(aLinkFilename) )
     306             :     {
     307           0 :         css::uno::Reference< css::io::XInputStream > s;
     308           0 :         bool ok = m_path.second->getByName(aLinkFilename) >>= s;
     309             :         OSL_ASSERT(ok); (void) ok;
     310             : 
     311           0 :         parseLinkFile( wrapStream(s) );
     312           0 :         return;
     313           0 :     }
     314             : }
     315             : 
     316           0 : void ImplImageTree::parseLinkFile(boost::shared_ptr< SvStream > pStream)
     317             : {
     318           0 :     OString aLine;
     319           0 :     OUString aLink, aOriginal;
     320           0 :     int nLineNo = 0;
     321           0 :     while ( pStream->ReadLine( aLine ) )
     322             :     {
     323           0 :         ++nLineNo;
     324           0 :         if ( aLine.isEmpty() )
     325           0 :             continue;
     326             : 
     327           0 :         sal_Int32 nIndex = 0;
     328           0 :         aLink = OStringToOUString( aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8 );
     329           0 :         aOriginal = OStringToOUString( aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8 );
     330             : 
     331             :         // skip comments, or incomplete entries
     332           0 :         if (aLink.isEmpty() || aLink[0] == '#' || aOriginal.isEmpty())
     333             :         {
     334           0 :             if (aLink.isEmpty() || aOriginal.isEmpty())
     335             :                 SAL_WARN("vcl", "ImplImageTree::parseLinkFile: icon links.txt parse error, incomplete link at line " << nLineNo);
     336           0 :             continue;
     337             :         }
     338             : 
     339           0 :         m_linkHash[aLink] = aOriginal;
     340           0 :     }
     341           0 : }
     342             : 
     343           0 : OUString const & ImplImageTree::getRealImageName(OUString const & name)
     344             : {
     345           0 :     IconLinkHash::iterator it(m_linkHash.find(name));
     346           0 :     if (it == m_linkHash.end())
     347           0 :         return name;
     348           0 :     return it->second;
     349             : }
     350             : 
     351             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10