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

Generated by: LCOV version 1.10