LCOV - code coverage report
Current view: top level - libreoffice/vcl/source/gdi - impimagetree.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 156 203 76.8 %
Date: 2012-12-17 Functions: 15 17 88.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 <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        3652 : rtl::OUString createPath(
      67             :     rtl::OUString const & name, sal_Int32 pos, rtl::OUString const & locale)
      68             : {
      69        3652 :     rtl::OUStringBuffer b(name.copy(0, pos + 1));
      70        3652 :     b.append(locale);
      71        3652 :     b.append(name.copy(pos));
      72        3652 :     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         178 : 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         178 :     boost::shared_ptr< SvStream > s(new SvMemoryStream);
     119           0 :     for (;;) {
     120         178 :         sal_Int32 const size = 2048;
     121         178 :         css::uno::Sequence< sal_Int8 > data(size);
     122         178 :         sal_Int32 n = stream->readBytes(data, size);
     123         178 :         s->Write(data.getConstArray(), n);
     124         178 :         if (n < size) {
     125             :             break;
     126             :         }
     127         178 :     }
     128         178 :     s->Seek(0);
     129         178 :     return s;
     130             : }
     131             : 
     132         178 : void loadFromStream(
     133             :     css::uno::Reference< css::io::XInputStream > const & stream,
     134             :     rtl::OUString const & path, BitmapEx & bitmap)
     135             : {
     136         178 :     boost::shared_ptr< SvStream > s(wrapStream(stream));
     137         178 :     if (path.endsWithAsciiL(RTL_CONSTASCII_STRINGPARAM(".png")))
     138             :     {
     139         178 :         vcl::PNGReader aPNGReader( *s );
     140         178 :         aPNGReader.SetIgnoreGammaChunk( sal_True );
     141         178 :         bitmap = aPNGReader.Read();
     142             :     } else {
     143           0 :         *s >> bitmap;
     144         178 :     }
     145         178 : }
     146             : 
     147             : }
     148             : 
     149          54 : ImplImageTree::ImplImageTree() { m_cacheIcons = true; }
     150             : 
     151          54 : ImplImageTree::~ImplImageTree() {}
     152             : 
     153         416 : 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         416 :     if (checkStyleCacheLookup(style, exists)) {
     160          46 :         return exists;
     161             :     }
     162             : 
     163         370 :     setStyle(style);
     164             : 
     165         370 :     exists = false;
     166         370 :     const rtl::OUString sBrandURLSuffix("_brand");
     167        1896 :     for (Paths::iterator i(m_paths.begin()); i != m_paths.end() && !exists; ++i) {
     168        1526 :         ::rtl::OUString aURL = i->first;
     169        1526 :         sal_Int32 nFromIndex = aURL.getLength() - sBrandURLSuffix.getLength();
     170             :         // skip brand-specific icon themes; they are incomplete and thus not useful for this check
     171        1526 :         if (nFromIndex < 0 || !aURL.match(sBrandURLSuffix, nFromIndex)) {
     172         786 :             osl::File aZip(aURL + ".zip");
     173         786 :             if (aZip.open(osl_File_OpenFlag_Read) == ::osl::FileBase::E_None) {
     174           2 :                 aZip.close();
     175           2 :                 exists = true;
     176             :             }
     177             : 
     178         786 :             osl::Directory aLookaside(aURL);
     179         786 :             if (aLookaside.open() == ::osl::FileBase::E_None) {
     180           0 :                 aLookaside.close();
     181           0 :                 exists = true;
     182           0 :                 m_cacheIcons = false;
     183             :             } else {
     184         786 :                 m_cacheIcons = true;
     185         786 :             }
     186             :         }
     187        1526 :     }
     188         370 :     m_checkStyleCache[style] = exists;
     189         370 :     return exists;
     190             : }
     191             : 
     192        1830 : bool ImplImageTree::loadImage(
     193             :     rtl::OUString const & name, rtl::OUString const & style, BitmapEx & bitmap,
     194             :     bool localized, bool loadMissing )
     195             : {
     196        1830 :     bool found = false;
     197             :     try {
     198        1830 :         found = doLoadImage(name, style, bitmap, localized);
     199           0 :     } catch (css::uno::RuntimeException &) {
     200           0 :         if (!loadMissing)
     201           0 :             throw;
     202             :     }
     203        1830 :     if (found || !loadMissing)
     204        1830 :         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          90 : bool ImplImageTree::loadDefaultImage(
     213             :     rtl::OUString const & style,
     214             :     BitmapEx& bitmap)
     215             : {
     216             :     return doLoadImage(
     217             :         rtl::OUString("res/grafikde.png"),
     218          90 :         style, bitmap, false);
     219             : }
     220             : 
     221             : 
     222        1920 : bool ImplImageTree::doLoadImage(
     223             :     rtl::OUString const & name, rtl::OUString const & style, BitmapEx & bitmap,
     224             :     bool localized)
     225             : {
     226        1920 :     setStyle(style);
     227        1920 :     if (m_cacheIcons && iconCacheLookup(name, localized, bitmap)) {
     228           4 :         return true;
     229             :     }
     230        1916 :     if (!bitmap.IsEmpty()) {
     231           0 :         bitmap.SetEmpty();
     232             :     }
     233        1916 :     std::vector< rtl::OUString > paths;
     234        1916 :     paths.push_back(name);
     235        1916 :     if (localized) {
     236        1826 :         sal_Int32 pos = name.lastIndexOf('/');
     237        1826 :         if (pos != -1) {
     238             :             /* FIXME-BCP47: this needs to be changed for language tags! */
     239             :             css::lang::Locale const & loc =
     240        1826 :                 Application::GetSettings().GetUILanguageTag().getLocale();
     241        1826 :             paths.push_back(createPath(name, pos, loc.Language));
     242        1826 :             if (!loc.Country.isEmpty()) {
     243        1826 :                 rtl::OUStringBuffer b(loc.Language);
     244        1826 :                 b.append(sal_Unicode('-'));
     245        1826 :                 b.append(loc.Country);
     246        1826 :                 rtl::OUString p(createPath(name, pos, b.makeStringAndClear()));
     247        1826 :                 paths.push_back(p);
     248        1826 :                 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        1826 :                 }
     255             :             }
     256             :         }
     257             :     }
     258        1916 :     bool found = false;
     259             :     try {
     260        1916 :         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        1916 :     if (m_cacheIcons && found) {
     269         178 :         m_iconCache[name.intern()] = std::make_pair(localized, bitmap);
     270             :     }
     271        1916 :     return found;
     272             : }
     273             : 
     274           8 : void ImplImageTree::shutDown() {
     275           8 :     m_style = rtl::OUString();
     276             :         // for safety; empty m_style means "not initialized"
     277           8 :     m_paths.clear();
     278           8 :     m_iconCache.clear();
     279           8 :     m_checkStyleCache.clear();
     280           8 : }
     281             : 
     282        2290 : void ImplImageTree::setStyle(rtl::OUString const & style) {
     283             :     OSL_ASSERT(!style.isEmpty()); // empty m_style means "not initialized"
     284        2290 :     if (style != m_style) {
     285         416 :         m_style = style;
     286         416 :         resetPaths();
     287         416 :         m_iconCache.clear();
     288             :     }
     289        2290 : }
     290             : 
     291         416 : void ImplImageTree::resetPaths() {
     292         416 :     m_paths.clear();
     293             :     {
     294             :         rtl::OUString url(
     295         416 :             "$BRAND_BASE_DIR/program/edition/images");
     296         416 :         rtl::Bootstrap::expandMacros(url);
     297         416 :         INetURLObject u(url);
     298             :         OSL_ASSERT(!u.HasError());
     299             :         m_paths.push_back(
     300             :             std::make_pair(
     301             :                 u.GetMainURL(INetURLObject::NO_DECODE),
     302         416 :                 css::uno::Reference< css::container::XNameAccess >()));
     303             :     }
     304             :     {
     305             :         rtl::OUString url(
     306         416 :             "$BRAND_BASE_DIR/share/config");
     307         416 :         rtl::Bootstrap::expandMacros(url);
     308         416 :         INetURLObject u(url);
     309             :         OSL_ASSERT(!u.HasError());
     310         416 :         rtl::OUStringBuffer b;
     311         416 :         b.appendAscii(RTL_CONSTASCII_STRINGPARAM("images_"));
     312         416 :         b.append(m_style);
     313         416 :         b.appendAscii(RTL_CONSTASCII_STRINGPARAM("_brand"));
     314         416 :         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         416 :                 css::uno::Reference< css::container::XNameAccess >()));
     320             :     }
     321             :     {
     322         416 :         rtl::OUString url( "$BRAND_BASE_DIR/share/config/images_brand");
     323         416 :         rtl::Bootstrap::expandMacros(url);
     324             :         m_paths.push_back(
     325             :             std::make_pair(
     326         416 :                 url, css::uno::Reference< css::container::XNameAccess >()));
     327             :     }
     328             :     {
     329             :         rtl::OUString url(
     330         416 :             "$BRAND_BASE_DIR/share/config");
     331         416 :         rtl::Bootstrap::expandMacros(url);
     332         416 :         INetURLObject u(url);
     333             :         OSL_ASSERT(!u.HasError());
     334         416 :         rtl::OUStringBuffer b;
     335         416 :         b.appendAscii(RTL_CONSTASCII_STRINGPARAM("images_"));
     336         416 :         b.append(m_style);
     337         416 :         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         416 :                 css::uno::Reference< css::container::XNameAccess >()));
     343             :     }
     344         416 :     if ( m_style == "default" )
     345             :     {
     346          46 :         rtl::OUString url( "$BRAND_BASE_DIR/share/config/images");
     347          46 :         rtl::Bootstrap::expandMacros(url);
     348             :         m_paths.push_back(
     349             :             std::make_pair(
     350          46 :                 url, css::uno::Reference< css::container::XNameAccess >()));
     351             :     }
     352         416 : }
     353             : 
     354         416 : bool ImplImageTree::checkStyleCacheLookup(
     355             :     rtl::OUString const & style, bool &exists)
     356             : {
     357         416 :     CheckStyleCache::iterator i(m_checkStyleCache.find(style));
     358         416 :     if (i != m_checkStyleCache.end()) {
     359          46 :         exists = i->second;
     360          46 :         return true;
     361             :     } else {
     362         370 :         return false;
     363             :     }
     364             : }
     365             : 
     366        1920 : bool ImplImageTree::iconCacheLookup(
     367             :     rtl::OUString const & name, bool localized, BitmapEx & bitmap)
     368             : {
     369        1920 :     IconCache::iterator i(m_iconCache.find(name));
     370        1920 :     if (i != m_iconCache.end() && i->second.first == localized) {
     371           4 :         bitmap = i->second.second;
     372           4 :         return true;
     373             :     } else {
     374        1916 :         return false;
     375             :     }
     376             : }
     377             : 
     378        1916 : bool ImplImageTree::find(
     379             :     std::vector< rtl::OUString > const & paths, BitmapEx & bitmap)
     380             : {
     381        1916 :     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        4022 :     for (Paths::iterator i(m_paths.begin()); i != m_paths.end();) {
     398         368 :         if (!i->second.is()) {
     399         192 :             css::uno::Sequence< css::uno::Any > args(1);
     400         192 :             args[0] <<= i->first + ".zip";
     401             :             try {
     402           2 :                 i->second.set(
     403         384 :                     comphelper::getProcessServiceFactory()->createInstanceWithArguments(
     404             :                         rtl::OUString( "com.sun.star.packages.zip.ZipFileAccess"),
     405         192 :                         args),
     406         194 :                     css::uno::UNO_QUERY_THROW);
     407           0 :             } catch (css::uno::RuntimeException &) {
     408           0 :                 throw;
     409         380 :             } 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         190 :                 i = m_paths.erase(i);
     415         190 :                 continue;
     416         192 :             }
     417             :         }
     418        1602 :         for (std::vector< rtl::OUString >::const_reverse_iterator j(
     419         178 :                  paths.rbegin());
     420        1068 :              j != paths.rend(); ++j)
     421             :         {
     422         534 :             if (i->second->hasByName(*j)) {
     423         178 :                 css::uno::Reference< css::io::XInputStream > s;
     424         178 :                 bool ok = i->second->getByName(*j) >>= s;
     425             :                 OSL_ASSERT(ok); (void) ok;
     426         178 :                 loadFromStream(s, *j, bitmap);
     427         178 :                 return true;
     428             :             }
     429             :         }
     430           0 :         ++i;
     431             :     }
     432        1738 :     return false;
     433             : }
     434             : 
     435             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10