LCOV - code coverage report
Current view: top level - vcl/source/gdi - impimagetree.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 134 164 81.7 %
Date: 2015-06-13 12:38:46 Functions: 18 20 90.0 %
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 "com/sun/star/container/XNameAccess.hpp"
      25             : #include "com/sun/star/io/XInputStream.hpp"
      26             : #include "com/sun/star/lang/Locale.hpp"
      27             : #include "com/sun/star/lang/XMultiServiceFactory.hpp"
      28             : #include "com/sun/star/packages/zip/ZipFileAccess.hpp"
      29             : #include "com/sun/star/uno/Any.hxx"
      30             : #include "com/sun/star/uno/Exception.hpp"
      31             : #include "com/sun/star/uno/RuntimeException.hpp"
      32             : #include "com/sun/star/uno/Sequence.hxx"
      33             : #include "comphelper/processfactory.hxx"
      34             : #include "osl/file.hxx"
      35             : #include "osl/diagnose.h"
      36             : #include "rtl/bootstrap.hxx"
      37             : 
      38             : #include "tools/stream.hxx"
      39             : #include "tools/urlobj.hxx"
      40             : #include "vcl/bitmapex.hxx"
      41             : #include <vcl/dibtools.hxx>
      42             : #include "vcl/pngread.hxx"
      43             : #include "vcl/settings.hxx"
      44             : #include "vcl/svapp.hxx"
      45             : #include "impimagetree.hxx"
      46             : #include <vcldemo-debug.hxx>
      47             : 
      48             : using namespace css;
      49             : 
      50             : namespace {
      51             : 
      52       52386 : static OUString createPath(OUString const & name, sal_Int32 pos, OUString const & locale)
      53             : {
      54       52386 :     return name.copy(0, pos + 1) + locale + name.copy(pos);
      55             : }
      56             : 
      57       11026 : static std::shared_ptr<SvStream> wrapStream(css::uno::Reference< css::io::XInputStream > const & stream)
      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             :     OSL_ASSERT(stream.is());
      64       11026 :     std::shared_ptr<SvStream> s(std::make_shared<SvMemoryStream>());
      65             :     for (;;)
      66             :     {
      67       12389 :         sal_Int32 const size = 2048;
      68       12389 :         css::uno::Sequence< sal_Int8 > data(size);
      69       12389 :         sal_Int32 n = stream->readBytes(data, size);
      70       12389 :         s->Write(data.getConstArray(), n);
      71       12389 :         if (n < size)
      72       11026 :             break;
      73        1363 :     }
      74       11026 :     s->Seek(0);
      75       11026 :     return s;
      76             : }
      77             : 
      78       10804 : static void loadImageFromStream(std::shared_ptr<SvStream> xStream, OUString const & rPath, BitmapEx & rBitmap)
      79             : {
      80       10804 :     if (rPath.endsWith(".png"))
      81             :     {
      82       10802 :         vcl::PNGReader aPNGReader(*xStream);
      83       10802 :         aPNGReader.SetIgnoreGammaChunk( true );
      84       10802 :         rBitmap = aPNGReader.Read();
      85             :     }
      86             :     else
      87             :     {
      88           2 :         ReadDIBBitmapEx(rBitmap, *xStream);
      89             :     }
      90       10804 : }
      91             : 
      92             : }
      93             : 
      94         244 : ImplImageTree::ImplImageTree()
      95             : {
      96         244 : }
      97             : 
      98         244 : ImplImageTree::~ImplImageTree()
      99             : {
     100         244 : }
     101             : 
     102       18767 : OUString ImplImageTree::fallbackStyle(const OUString &style)
     103             : {
     104       18767 :     if (style == "galaxy")
     105          19 :         return OUString();
     106       18748 :     else if (style == "industrial")
     107           0 :         return OUString("galaxy");
     108       18748 :     else if (style == "tango")
     109       18748 :         return OUString("galaxy");
     110           0 :     else if (style == "breeze")
     111           0 :         return OUString("galaxy");
     112           0 :     else if (style == "sifr")
     113           0 :         return OUString("breeze");
     114             : 
     115           0 :     return OUString("tango");
     116             : }
     117             : 
     118       44309 : bool ImplImageTree::loadImage(OUString const & name, OUString const & style, BitmapEx & bitmap,
     119             :     bool localized, bool loadMissing)
     120             : {
     121       44309 :     OUString aStyle(style);
     122      107385 :     while (!aStyle.isEmpty())
     123             :     {
     124             :         try {
     125       63057 :             if (doLoadImage(name, aStyle, bitmap, localized))
     126       44290 :                 return true;
     127             :         }
     128           0 :         catch (css::uno::RuntimeException &) {}
     129             : 
     130       18767 :         aStyle = fallbackStyle(aStyle);
     131             :     }
     132             : 
     133          19 :     if (!loadMissing)
     134          19 :         return false;
     135             : 
     136             :     SAL_INFO("vcl", "ImplImageTree::loadImage couldn't load \"" << name << "\", fetching default image");
     137             : 
     138           0 :     return loadDefaultImage(style, bitmap);
     139             : }
     140             : 
     141         339 : bool ImplImageTree::loadDefaultImage(OUString const & style, BitmapEx& bitmap)
     142             : {
     143             :     return doLoadImage(
     144             :         OUString("res/grafikde.png"),
     145         339 :         style, bitmap, false);
     146             : }
     147             : 
     148       63396 : bool ImplImageTree::doLoadImage(OUString const & name, OUString const & style, BitmapEx & bitmap,
     149             :     bool localized)
     150             : {
     151       63396 :     setStyle(style);
     152       63396 :     if (iconCacheLookup(name, localized, bitmap))
     153       33486 :         return true;
     154             : 
     155       29910 :     if (!bitmap.IsEmpty())
     156           0 :         bitmap.SetEmpty();
     157             : 
     158       29910 :     std::vector< OUString > paths;
     159       29910 :     paths.push_back(getRealImageName(name));
     160             : 
     161       29910 :     if (localized)
     162             :     {
     163       26193 :         sal_Int32 pos = name.lastIndexOf('/');
     164       26193 :         if (pos != -1)
     165             :         {
     166             :             // findImage() uses a reverse iterator, so push in reverse order.
     167       26193 :             std::vector< OUString > aFallbacks( Application::GetSettings().GetUILanguageTag().getFallbackStrings(true));
     168      235737 :             for (std::vector< OUString >::reverse_iterator it( aFallbacks.rbegin());
     169      157158 :                     it != aFallbacks.rend(); ++it)
     170             :             {
     171       52386 :                 paths.push_back( getRealImageName( createPath(name, pos, *it) ) );
     172       26193 :             }
     173             :         }
     174             :     }
     175             : 
     176       29910 :     bool found = false;
     177             :     try {
     178       29910 :         found = findImage(paths, bitmap);
     179           0 :     } catch (css::uno::RuntimeException &) {
     180           0 :         throw;
     181           0 :     } catch (const css::uno::Exception & e) {
     182             :         SAL_INFO("vcl", "ImplImageTree::doLoadImage exception " << e.Message);
     183             :     }
     184             : 
     185       29910 :     if (found)
     186       10804 :         maIconSet[maCurrentStyle].maIconCache[name] = std::make_pair(localized, bitmap);
     187             : 
     188       29910 :     return found;
     189             : }
     190             : 
     191         242 : void ImplImageTree::shutDown()
     192             : {
     193         242 :     maCurrentStyle.clear();
     194         460 :     for (StyleIconSet::iterator it = maIconSet.begin(); it != maIconSet.end(); ++it)
     195             :     {
     196         218 :         it->second.maIconCache.clear();
     197         218 :         it->second.maLinkHash.clear();
     198             :     }
     199         242 : }
     200             : 
     201       63396 : void ImplImageTree::setStyle(OUString const & style)
     202             : {
     203             :     assert(!style.isEmpty());
     204       63396 :     if (style != maCurrentStyle)
     205             :     {
     206       37521 :         maCurrentStyle = style;
     207       37521 :         createStyle();
     208             :     }
     209       63396 : }
     210             : 
     211       37521 : void ImplImageTree::createStyle()
     212             : {
     213       37521 :     if (maIconSet.find(maCurrentStyle) != maIconSet.end())
     214       74820 :         return;
     215             : 
     216         222 :     OUString url( "$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/config/" );
     217         222 :     rtl::Bootstrap::expandMacros(url);
     218         222 :     if (maCurrentStyle != "default")
     219             :     {
     220         222 :         INetURLObject u(url);
     221             :         OSL_ASSERT(!u.HasError());
     222         222 :         bool ok = u.Append("images_" + maCurrentStyle, INetURLObject::ENCODE_ALL);
     223             :         OSL_ASSERT(ok); (void) ok;
     224         222 :         url = u.GetMainURL(INetURLObject::NO_DECODE);
     225             :     }
     226             :     else
     227           0 :         url += "images";
     228             : 
     229         222 :     maIconSet[maCurrentStyle] = IconSet(url);
     230             : 
     231         222 :     loadImageLinks();
     232             : }
     233             : 
     234       63396 : bool ImplImageTree::iconCacheLookup(OUString const & name, bool localized, BitmapEx & bitmap)
     235             : {
     236       63396 :     IconCache &rIconCache = maIconSet[maCurrentStyle].maIconCache;
     237             : 
     238       63396 :     IconCache::iterator i(rIconCache.find(getRealImageName(name)));
     239       63396 :     if (i != rIconCache.end() && i->second.first == localized)
     240             :     {
     241       33486 :         bitmap = i->second.second;
     242       33486 :         return true;
     243             :     }
     244       29910 :     return false;
     245             : }
     246             : 
     247       29910 : bool ImplImageTree::findImage(std::vector<OUString> const & paths, BitmapEx & bitmap)
     248             : {
     249       29910 :     if (!checkPathAccess())
     250           0 :         return false;
     251             : 
     252       29910 :     const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess;
     253             : 
     254      101402 :     for (std::vector<OUString>::const_reverse_iterator j(paths.rbegin()); j != paths.rend(); ++j)
     255             :     {
     256       82296 :         if (rNameAccess->hasByName(*j))
     257             :         {
     258       10804 :             css::uno::Reference< css::io::XInputStream > s;
     259       10804 :             bool ok = rNameAccess->getByName(*j) >>= s;
     260             :             assert(ok);
     261             :             (void)ok; // prevent unused warning in release build
     262             : 
     263       10804 :             loadImageFromStream( wrapStream(s), *j, bitmap );
     264       10804 :             return true;
     265             :         }
     266             :     }
     267       19106 :     return false;
     268             : }
     269             : 
     270         222 : void ImplImageTree::loadImageLinks()
     271             : {
     272         222 :     const OUString aLinkFilename("links.txt");
     273             : 
     274         222 :     if (!checkPathAccess())
     275           0 :         return;
     276             : 
     277         222 :     const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess;
     278             : 
     279         222 :     if (rNameAccess->hasByName(aLinkFilename))
     280             :     {
     281         222 :         css::uno::Reference< css::io::XInputStream > s;
     282         222 :         bool ok = rNameAccess->getByName(aLinkFilename) >>= s;
     283             :         assert(ok);
     284             :         (void)ok; // prevent unused warning in release build
     285             : 
     286         222 :         parseLinkFile( wrapStream(s) );
     287         222 :         return;
     288           0 :     }
     289             : }
     290             : 
     291         222 : void ImplImageTree::parseLinkFile(std::shared_ptr<SvStream> xStream)
     292             : {
     293         222 :     OString aLine;
     294         444 :     OUString aLink, aOriginal;
     295         222 :     int nLineNo = 0;
     296       65268 :     while (xStream->ReadLine(aLine))
     297             :     {
     298       64824 :         ++nLineNo;
     299       64824 :         if ( aLine.isEmpty() )
     300           0 :             continue;
     301             : 
     302       64824 :         sal_Int32 nIndex = 0;
     303       64824 :         aLink = OStringToOUString( aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8 );
     304       64824 :         aOriginal = OStringToOUString( aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8 );
     305             : 
     306             :         // skip comments, or incomplete entries
     307       64824 :         if (aLink.isEmpty() || aLink[0] == '#' || aOriginal.isEmpty())
     308             :         {
     309           0 :             if (aLink.isEmpty() || aOriginal.isEmpty())
     310             :                 SAL_WARN("vcl", "ImplImageTree::parseLinkFile: icon links.txt parse error, incomplete link at line " << nLineNo);
     311           0 :             continue;
     312             :         }
     313             : 
     314       64824 :         maIconSet[maCurrentStyle].maLinkHash[aLink] = aOriginal;
     315         222 :     }
     316         222 : }
     317             : 
     318      145692 : OUString const & ImplImageTree::getRealImageName(OUString const & name)
     319             : {
     320      145692 :     IconLinkHash &rLinkHash = maIconSet[maCurrentStyle].maLinkHash;
     321             : 
     322      145692 :     IconLinkHash::iterator it(rLinkHash.find(name));
     323      145692 :     if (it == rLinkHash.end())
     324      125063 :         return name;
     325             : 
     326       20629 :     return it->second;
     327             : }
     328             : 
     329       30132 : bool ImplImageTree::checkPathAccess()
     330             : {
     331       30132 :     uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess;
     332       30132 :     if (rNameAccess.is())
     333       29910 :         return true;
     334             : 
     335             :     try {
     336         222 :         rNameAccess = css::packages::zip::ZipFileAccess::createWithURL(comphelper::getProcessComponentContext(), maIconSet[maCurrentStyle].maURL + ".zip");
     337             :     }
     338           0 :     catch (const css::uno::RuntimeException &) {
     339           0 :         throw;
     340             :     }
     341           0 :     catch (const css::uno::Exception & e) {
     342             :         SAL_INFO("vcl", "ImplImageTree::zip file location exception " << e.Message << " for " << maIconSet[maCurrentStyle].maURL);
     343           0 :         return false;
     344             :     }
     345         222 :     return rNameAccess.is();
     346             : }
     347             : 
     348           0 : css::uno::Reference<css::container::XNameAccess> ImplImageTree::getNameAccess()
     349             : {
     350           0 :     checkPathAccess();
     351           0 :     return maIconSet[maCurrentStyle].maNameAccess;
     352             : }
     353             : 
     354             : /// Recursively dump all names ...
     355           0 : css::uno::Sequence<OUString> ImageTree_getAllImageNames()
     356             : {
     357           0 :     static ImplImageTreeSingletonRef aImageTree;
     358             : 
     359           0 :     css::uno::Reference<css::container::XNameAccess> xRef(aImageTree->getNameAccess());
     360             : 
     361           0 :     return xRef->getElementNames();
     362             : }
     363             : 
     364             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11