LCOV - code coverage report
Current view: top level - libreoffice/vcl/source/gdi - impimagetree.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 115 203 56.7 %
Date: 2012-12-27 Functions: 11 17 64.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             : 
      21             : #include "sal/config.h"
      22             : 
      23             : #include <list>
      24             : #include <memory>
      25             : #include <utility>
      26             : #include <vector>
      27             : #include <boost/unordered_map.hpp>
      28             : #include <boost/shared_ptr.hpp>
      29             : 
      30             : #include "com/sun/star/container/XNameAccess.hpp"
      31             : #include "com/sun/star/io/XInputStream.hpp"
      32             : #include "com/sun/star/lang/Locale.hpp"
      33             : #include "com/sun/star/lang/XMultiServiceFactory.hpp"
      34             : #include "com/sun/star/uno/Any.hxx"
      35             : #include "com/sun/star/uno/Exception.hpp"
      36             : #include "com/sun/star/uno/Reference.hxx"
      37             : #include "com/sun/star/uno/RuntimeException.hpp"
      38             : #include "com/sun/star/uno/Sequence.hxx"
      39             : 
      40             : #include "comphelper/processfactory.hxx"
      41             : 
      42             : #include "osl/file.hxx"
      43             : #include "osl/diagnose.h"
      44             : 
      45             : #include "rtl/bootstrap.hxx"
      46             : #include "rtl/string.h"
      47             : #include "rtl/textenc.h"
      48             : #include "rtl/ustrbuf.hxx"
      49             : #include "rtl/ustring.h"
      50             : #include "rtl/ustring.hxx"
      51             : 
      52             : #include "sal/types.h"
      53             : 
      54             : #include "tools/stream.hxx"
      55             : #include "tools/urlobj.hxx"
      56             : 
      57             : #include "vcl/bitmapex.hxx"
      58             : #include "vcl/pngread.hxx"
      59             : #include "vcl/settings.hxx"
      60             : #include "vcl/svapp.hxx"
      61             : 
      62             : #include "impimagetree.hxx"
      63             : 
      64             : namespace {
      65             : 
      66        1486 : rtl::OUString createPath(
      67             :     rtl::OUString const & name, sal_Int32 pos, rtl::OUString const & locale)
      68             : {
      69        1486 :     rtl::OUStringBuffer b(name.copy(0, pos + 1));
      70        1486 :     b.append(locale);
      71        1486 :     b.append(name.copy(pos));
      72        1486 :     return b.makeStringAndClear();
      73             : }
      74             : 
      75           0 : boost::shared_ptr< SvStream > wrapFile(osl::File & file)
      76             : {
      77             :     // This could use SvInputStream instead if that did not have a broken
      78             :     // SeekPos implementation for an XInputStream that is not also XSeekable
      79             :     // (cf. "@@@" at tags/DEV300_m37/svtools/source/misc1/strmadpt.cxx@264807
      80             :     // l. 593):
      81           0 :     boost::shared_ptr< SvStream > s(new SvMemoryStream);
      82           0 :     for (;;) {
      83             :         void *data[2048];
      84             :         sal_uInt64 n;
      85           0 :         file.read(data, 2048, n);
      86           0 :         s->Write(data, n);
      87           0 :         if (n < 2048) {
      88             :             break;
      89             :         }
      90             :     }
      91           0 :     s->Seek(0);
      92           0 :     return s;
      93             : }
      94             : 
      95           0 : void loadFromFile(
      96             :     osl::File & file,
      97             :     rtl::OUString const & path, BitmapEx & bitmap)
      98             : {
      99           0 :     boost::shared_ptr< SvStream > s(wrapFile(file));
     100           0 :     if (path.endsWithAsciiL(RTL_CONSTASCII_STRINGPARAM(".png")))
     101             :     {
     102           0 :         vcl::PNGReader aPNGReader( *s );
     103           0 :         aPNGReader.SetIgnoreGammaChunk( sal_True );
     104           0 :         bitmap = aPNGReader.Read();
     105             :     } else {
     106           0 :         *s >> bitmap;
     107           0 :     }
     108           0 : }
     109             : 
     110           0 : boost::shared_ptr< SvStream > wrapStream(
     111             :     css::uno::Reference< css::io::XInputStream > const & stream)
     112             : {
     113             :     // This could use SvInputStream instead if that did not have a broken
     114             :     // SeekPos implementation for an XInputStream that is not also XSeekable
     115             :     // (cf. "@@@" at tags/DEV300_m37/svtools/source/misc1/strmadpt.cxx@264807
     116             :     // l. 593):
     117             :     OSL_ASSERT(stream.is());
     118           0 :     boost::shared_ptr< SvStream > s(new SvMemoryStream);
     119           0 :     for (;;) {
     120           0 :         sal_Int32 const size = 2048;
     121           0 :         css::uno::Sequence< sal_Int8 > data(size);
     122           0 :         sal_Int32 n = stream->readBytes(data, size);
     123           0 :         s->Write(data.getConstArray(), n);
     124           0 :         if (n < size) {
     125             :             break;
     126             :         }
     127           0 :     }
     128           0 :     s->Seek(0);
     129           0 :     return s;
     130             : }
     131             : 
     132           0 : void loadFromStream(
     133             :     css::uno::Reference< css::io::XInputStream > const & stream,
     134             :     rtl::OUString const & path, BitmapEx & bitmap)
     135             : {
     136           0 :     boost::shared_ptr< SvStream > s(wrapStream(stream));
     137           0 :     if (path.endsWithAsciiL(RTL_CONSTASCII_STRINGPARAM(".png")))
     138             :     {
     139           0 :         vcl::PNGReader aPNGReader( *s );
     140           0 :         aPNGReader.SetIgnoreGammaChunk( sal_True );
     141           0 :         bitmap = aPNGReader.Read();
     142             :     } else {
     143           0 :         *s >> bitmap;
     144           0 :     }
     145           0 : }
     146             : 
     147             : }
     148             : 
     149          10 : ImplImageTree::ImplImageTree() { m_cacheIcons = true; }
     150             : 
     151          10 : ImplImageTree::~ImplImageTree() {}
     152             : 
     153          90 : bool ImplImageTree::checkStyle(rtl::OUString const & style)
     154             : {
     155             :     bool exists;
     156             : 
     157             :     // using cache because setStyle is an expensive operation
     158             :     // setStyle calls resetPaths => closes any opened zip files with icons, cleans the icon cache, ...
     159          90 :     if (checkStyleCacheLookup(style, exists)) {
     160          10 :         return exists;
     161             :     }
     162             : 
     163          80 :     setStyle(style);
     164             : 
     165          80 :     exists = false;
     166          80 :     const rtl::OUString sBrandURLSuffix("_brand");
     167         410 :     for (Paths::iterator i(m_paths.begin()); i != m_paths.end() && !exists; ++i) {
     168         330 :         ::rtl::OUString aURL = i->first;
     169         330 :         sal_Int32 nFromIndex = aURL.getLength() - sBrandURLSuffix.getLength();
     170             :         // skip brand-specific icon themes; they are incomplete and thus not useful for this check
     171         330 :         if (nFromIndex < 0 || !aURL.match(sBrandURLSuffix, nFromIndex)) {
     172         170 :             osl::File aZip(aURL + ".zip");
     173         170 :             if (aZip.open(osl_File_OpenFlag_Read) == ::osl::FileBase::E_None) {
     174           0 :                 aZip.close();
     175           0 :                 exists = true;
     176             :             }
     177             : 
     178         170 :             osl::Directory aLookaside(aURL);
     179         170 :             if (aLookaside.open() == ::osl::FileBase::E_None) {
     180           0 :                 aLookaside.close();
     181           0 :                 exists = true;
     182           0 :                 m_cacheIcons = false;
     183             :             } else {
     184         170 :                 m_cacheIcons = true;
     185         170 :             }
     186             :         }
     187         330 :     }
     188          80 :     m_checkStyleCache[style] = exists;
     189          80 :     return exists;
     190             : }
     191             : 
     192         743 : bool ImplImageTree::loadImage(
     193             :     rtl::OUString const & name, rtl::OUString const & style, BitmapEx & bitmap,
     194             :     bool localized, bool loadMissing )
     195             : {
     196         743 :     bool found = false;
     197             :     try {
     198         743 :         found = doLoadImage(name, style, bitmap, localized);
     199           0 :     } catch (css::uno::RuntimeException &) {
     200           0 :         if (!loadMissing)
     201           0 :             throw;
     202             :     }
     203         743 :     if (found || !loadMissing)
     204         743 :         return found;
     205             : 
     206             :     OSL_TRACE(
     207             :         "ImplImageTree::loadImage exception couldn't load \"%s\", fetching default image",
     208             :         rtl::OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr());
     209           0 :     return loadDefaultImage(style, bitmap);
     210             : }
     211             : 
     212           0 : bool ImplImageTree::loadDefaultImage(
     213             :     rtl::OUString const & style,
     214             :     BitmapEx& bitmap)
     215             : {
     216             :     return doLoadImage(
     217             :         rtl::OUString("res/grafikde.png"),
     218           0 :         style, bitmap, false);
     219             : }
     220             : 
     221             : 
     222         743 : bool ImplImageTree::doLoadImage(
     223             :     rtl::OUString const & name, rtl::OUString const & style, BitmapEx & bitmap,
     224             :     bool localized)
     225             : {
     226         743 :     setStyle(style);
     227         743 :     if (m_cacheIcons && iconCacheLookup(name, localized, bitmap)) {
     228           0 :         return true;
     229             :     }
     230         743 :     if (!bitmap.IsEmpty()) {
     231           0 :         bitmap.SetEmpty();
     232             :     }
     233         743 :     std::vector< rtl::OUString > paths;
     234         743 :     paths.push_back(name);
     235         743 :     if (localized) {
     236         743 :         sal_Int32 pos = name.lastIndexOf('/');
     237         743 :         if (pos != -1) {
     238             :             /* FIXME-BCP47: this needs to be changed for language tags! */
     239             :             css::lang::Locale const & loc =
     240         743 :                 Application::GetSettings().GetUILanguageTag().getLocale();
     241         743 :             paths.push_back(createPath(name, pos, loc.Language));
     242         743 :             if (!loc.Country.isEmpty()) {
     243         743 :                 rtl::OUStringBuffer b(loc.Language);
     244         743 :                 b.append(sal_Unicode('-'));
     245         743 :                 b.append(loc.Country);
     246         743 :                 rtl::OUString p(createPath(name, pos, b.makeStringAndClear()));
     247         743 :                 paths.push_back(p);
     248         743 :                 if (!loc.Variant.isEmpty()) {
     249           0 :                     b.append(p);
     250           0 :                     b.append(sal_Unicode('-'));
     251           0 :                     b.append(loc.Variant);
     252             :                     paths.push_back(
     253           0 :                         createPath(name, pos, b.makeStringAndClear()));
     254         743 :                 }
     255             :             }
     256             :         }
     257             :     }
     258         743 :     bool found = false;
     259             :     try {
     260         743 :         found = find(paths, bitmap);
     261           0 :     } catch (css::uno::RuntimeException &) {
     262           0 :         throw;
     263           0 :     } catch (const css::uno::Exception & e) {
     264             :         OSL_TRACE(
     265             :             "ImplImageTree::loadImage exception \"%s\"",
     266             :             rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
     267             :     }
     268         743 :     if (m_cacheIcons && found) {
     269           0 :         m_iconCache[name.intern()] = std::make_pair(localized, bitmap);
     270             :     }
     271         743 :     return found;
     272             : }
     273             : 
     274           0 : void ImplImageTree::shutDown() {
     275           0 :     m_style = rtl::OUString();
     276             :         // for safety; empty m_style means "not initialized"
     277           0 :     m_paths.clear();
     278           0 :     m_iconCache.clear();
     279           0 :     m_checkStyleCache.clear();
     280           0 : }
     281             : 
     282         823 : void ImplImageTree::setStyle(rtl::OUString const & style) {
     283             :     OSL_ASSERT(!style.isEmpty()); // empty m_style means "not initialized"
     284         823 :     if (style != m_style) {
     285          90 :         m_style = style;
     286          90 :         resetPaths();
     287          90 :         m_iconCache.clear();
     288             :     }
     289         823 : }
     290             : 
     291          90 : void ImplImageTree::resetPaths() {
     292          90 :     m_paths.clear();
     293             :     {
     294             :         rtl::OUString url(
     295          90 :             "$BRAND_BASE_DIR/program/edition/images");
     296          90 :         rtl::Bootstrap::expandMacros(url);
     297          90 :         INetURLObject u(url);
     298             :         OSL_ASSERT(!u.HasError());
     299             :         m_paths.push_back(
     300             :             std::make_pair(
     301             :                 u.GetMainURL(INetURLObject::NO_DECODE),
     302          90 :                 css::uno::Reference< css::container::XNameAccess >()));
     303             :     }
     304             :     {
     305             :         rtl::OUString url(
     306          90 :             "$BRAND_BASE_DIR/share/config");
     307          90 :         rtl::Bootstrap::expandMacros(url);
     308          90 :         INetURLObject u(url);
     309             :         OSL_ASSERT(!u.HasError());
     310          90 :         rtl::OUStringBuffer b;
     311          90 :         b.appendAscii(RTL_CONSTASCII_STRINGPARAM("images_"));
     312          90 :         b.append(m_style);
     313          90 :         b.appendAscii(RTL_CONSTASCII_STRINGPARAM("_brand"));
     314          90 :         bool ok = u.Append(b.makeStringAndClear(), INetURLObject::ENCODE_ALL);
     315             :         OSL_ASSERT(ok); (void) ok;
     316             :         m_paths.push_back(
     317             :             std::make_pair(
     318             :                 u.GetMainURL(INetURLObject::NO_DECODE),
     319          90 :                 css::uno::Reference< css::container::XNameAccess >()));
     320             :     }
     321             :     {
     322          90 :         rtl::OUString url( "$BRAND_BASE_DIR/share/config/images_brand");
     323          90 :         rtl::Bootstrap::expandMacros(url);
     324             :         m_paths.push_back(
     325             :             std::make_pair(
     326          90 :                 url, css::uno::Reference< css::container::XNameAccess >()));
     327             :     }
     328             :     {
     329             :         rtl::OUString url(
     330          90 :             "$BRAND_BASE_DIR/share/config");
     331          90 :         rtl::Bootstrap::expandMacros(url);
     332          90 :         INetURLObject u(url);
     333             :         OSL_ASSERT(!u.HasError());
     334          90 :         rtl::OUStringBuffer b;
     335          90 :         b.appendAscii(RTL_CONSTASCII_STRINGPARAM("images_"));
     336          90 :         b.append(m_style);
     337          90 :         bool ok = u.Append(b.makeStringAndClear(), INetURLObject::ENCODE_ALL);
     338             :         OSL_ASSERT(ok); (void) ok;
     339             :         m_paths.push_back(
     340             :             std::make_pair(
     341             :                 u.GetMainURL(INetURLObject::NO_DECODE),
     342          90 :                 css::uno::Reference< css::container::XNameAccess >()));
     343             :     }
     344          90 :     if ( m_style == "default" )
     345             :     {
     346          10 :         rtl::OUString url( "$BRAND_BASE_DIR/share/config/images");
     347          10 :         rtl::Bootstrap::expandMacros(url);
     348             :         m_paths.push_back(
     349             :             std::make_pair(
     350          10 :                 url, css::uno::Reference< css::container::XNameAccess >()));
     351             :     }
     352          90 : }
     353             : 
     354          90 : bool ImplImageTree::checkStyleCacheLookup(
     355             :     rtl::OUString const & style, bool &exists)
     356             : {
     357          90 :     CheckStyleCache::iterator i(m_checkStyleCache.find(style));
     358          90 :     if (i != m_checkStyleCache.end()) {
     359          10 :         exists = i->second;
     360          10 :         return true;
     361             :     } else {
     362          80 :         return false;
     363             :     }
     364             : }
     365             : 
     366         743 : bool ImplImageTree::iconCacheLookup(
     367             :     rtl::OUString const & name, bool localized, BitmapEx & bitmap)
     368             : {
     369         743 :     IconCache::iterator i(m_iconCache.find(name));
     370         743 :     if (i != m_iconCache.end() && i->second.first == localized) {
     371           0 :         bitmap = i->second.second;
     372           0 :         return true;
     373             :     } else {
     374         743 :         return false;
     375             :     }
     376             : }
     377             : 
     378         743 : bool ImplImageTree::find(
     379             :     std::vector< rtl::OUString > const & paths, BitmapEx & bitmap)
     380             : {
     381         743 :     if (!m_cacheIcons) {
     382           0 :         for (Paths::iterator i(m_paths.begin()); i != m_paths.end(); ++i) {
     383           0 :             for (std::vector< rtl::OUString >::const_reverse_iterator j(
     384           0 :                 paths.rbegin());
     385           0 :             j != paths.rend(); ++j)
     386             :             {
     387           0 :                 osl::File file(i->first + "/" + *j);
     388           0 :                 if (file.open(osl_File_OpenFlag_Read) == ::osl::FileBase::E_None) {
     389           0 :                     loadFromFile(file, *j, bitmap);
     390           0 :                     file.close();
     391           0 :                     return true;
     392             :                 }
     393           0 :             }
     394             :         }
     395             :     }
     396             : 
     397        1526 :     for (Paths::iterator i(m_paths.begin()); i != m_paths.end();) {
     398          40 :         if (!i->second.is()) {
     399          40 :             css::uno::Sequence< css::uno::Any > args(1);
     400          40 :             args[0] <<= i->first + ".zip";
     401             :             try {
     402           0 :                 i->second.set(
     403          80 :                     comphelper::getProcessServiceFactory()->createInstanceWithArguments(
     404             :                         rtl::OUString( "com.sun.star.packages.zip.ZipFileAccess"),
     405          40 :                         args),
     406          40 :                     css::uno::UNO_QUERY_THROW);
     407           0 :             } catch (css::uno::RuntimeException &) {
     408           0 :                 throw;
     409          80 :             } catch (const css::uno::Exception & e) {
     410             :                 OSL_TRACE(
     411             :                     "ImplImageTree::find exception \"%s\"",
     412             :                     rtl::OUStringToOString(
     413             :                         e.Message, RTL_TEXTENCODING_UTF8).getStr());
     414          40 :                 i = m_paths.erase(i);
     415          40 :                 continue;
     416          40 :             }
     417             :         }
     418           0 :         for (std::vector< rtl::OUString >::const_reverse_iterator j(
     419           0 :                  paths.rbegin());
     420           0 :              j != paths.rend(); ++j)
     421             :         {
     422           0 :             if (i->second->hasByName(*j)) {
     423           0 :                 css::uno::Reference< css::io::XInputStream > s;
     424           0 :                 bool ok = i->second->getByName(*j) >>= s;
     425             :                 OSL_ASSERT(ok); (void) ok;
     426           0 :                 loadFromStream(s, *j, bitmap);
     427           0 :                 return true;
     428             :             }
     429             :         }
     430           0 :         ++i;
     431             :     }
     432         743 :     return false;
     433             : }
     434             : 
     435             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10