Files
loongoffice/vcl/source/image/ImplImageTree.cxx
Stephan Bergmann 90576b9324 clang-tidy performance-unnecessary-value-param in vcl
Change-Id: I0b53c4bf5b4619cde357cf4eb432b153b1f7e6b5
2016-07-19 10:50:07 +02:00

434 lines
13 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <config_folders.h>
#include "sal/config.h"
#include "com/sun/star/container/XNameAccess.hpp"
#include "com/sun/star/io/XInputStream.hpp"
#include "com/sun/star/lang/Locale.hpp"
#include "com/sun/star/lang/XMultiServiceFactory.hpp"
#include "com/sun/star/packages/zip/ZipFileAccess.hpp"
#include "com/sun/star/uno/Exception.hpp"
#include "com/sun/star/uno/RuntimeException.hpp"
#include "com/sun/star/uno/Sequence.hxx"
#include "comphelper/processfactory.hxx"
#include "osl/file.hxx"
#include "osl/diagnose.h"
#include "rtl/bootstrap.hxx"
#include "rtl/uri.hxx"
#include "tools/stream.hxx"
#include "tools/urlobj.hxx"
#include <vcl/bitmapex.hxx>
#include <vcl/dibtools.hxx>
#include <vcl/implimagetree.hxx>
#include <vcl/pngread.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <vcldemo-debug.hxx>
#include <vcl/BitmapProcessor.hxx>
#include <vcl/BitmapTools.hxx>
using namespace css;
namespace {
OUString createPath(OUString const & name, sal_Int32 pos, OUString const & locale)
{
return name.copy(0, pos + 1) + locale + name.copy(pos);
}
std::shared_ptr<SvStream> wrapStream(css::uno::Reference< css::io::XInputStream > const & stream)
{
// This could use SvInputStream instead if that did not have a broken
// SeekPos implementation for an XInputStream that is not also XSeekable
// (cf. "@@@" at tags/DEV300_m37/svtools/source/misc1/strmadpt.cxx@264807
// l. 593):
OSL_ASSERT(stream.is());
std::shared_ptr<SvStream> s(std::make_shared<SvMemoryStream>());
for (;;)
{
sal_Int32 const size = 2048;
css::uno::Sequence< sal_Int8 > data(size);
sal_Int32 n = stream->readBytes(data, size);
s->WriteBytes(data.getConstArray(), n);
if (n < size)
break;
}
s->Seek(0);
return s;
}
void loadImageFromStream(std::shared_ptr<SvStream> const & xStream, OUString const & rPath, BitmapEx & rBitmap)
{
if (rPath.endsWith(".png"))
{
vcl::PNGReader aPNGReader(*xStream);
aPNGReader.SetIgnoreGammaChunk( true );
rBitmap = aPNGReader.Read();
}
else if (rPath.endsWith(".svg"))
{
vcl::BitmapTools::loadFromSvg(*xStream.get(), rPath, rBitmap);
}
else
{
ReadDIBBitmapEx(rBitmap, *xStream);
}
}
}
ImplImageTree & ImplImageTree::get() {
static ImplImageTree s_ImplImageTree;
return s_ImplImageTree;
}
ImplImageTree::ImplImageTree()
{
}
ImplImageTree::~ImplImageTree()
{
}
OUString ImplImageTree::getImageUrl(
OUString const & name, OUString const & style, OUString const & lang)
{
OUString aStyle(style);
while (!aStyle.isEmpty())
{
try {
setStyle(aStyle);
std::vector< OUString > paths;
paths.push_back(getRealImageName(name));
if (!lang.isEmpty())
{
sal_Int32 pos = name.lastIndexOf('/');
if (pos != -1)
{
std::vector<OUString> aFallbacks(
LanguageTag(lang).getFallbackStrings(true));
for (std::vector< OUString >::reverse_iterator it( aFallbacks.rbegin());
it != aFallbacks.rend(); ++it)
{
paths.push_back( getRealImageName( createPath(name, pos, *it) ) );
}
}
}
try {
if (checkPathAccess()) {
const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess;
for (std::vector<OUString>::const_reverse_iterator j(paths.rbegin()); j != paths.rend(); ++j)
{
if (rNameAccess->hasByName(*j))
{
return "vnd.sun.star.zip://"
+ rtl::Uri::encode(
maIconSet[maCurrentStyle].maURL + ".zip",
rtl_UriCharClassRegName,
rtl_UriEncodeIgnoreEscapes,
RTL_TEXTENCODING_UTF8)
+ "/" + *j;
// assuming *j contains no problematic chars
}
}
}
} catch (css::uno::RuntimeException &) {
throw;
} catch (const css::uno::Exception & e) {
SAL_INFO("vcl", "exception " << e.Message);
}
}
catch (css::uno::RuntimeException &) {}
aStyle = fallbackStyle(aStyle);
}
return OUString();
}
OUString ImplImageTree::fallbackStyle(const OUString &style)
{
if (style == "galaxy")
return OUString();
else if (style == "industrial")
return OUString("galaxy");
else if (style == "tango")
return OUString("galaxy");
else if (style == "breeze")
return OUString("galaxy");
else if (style == "sifr")
return OUString("breeze");
return OUString("tango");
}
bool ImplImageTree::loadImage(OUString const & name, OUString const & style, BitmapEx & bitmap,
bool localized)
{
OUString aStyle(style);
while (!aStyle.isEmpty())
{
try {
if (doLoadImage(name, aStyle, bitmap, localized))
{
static bool bIconsForDarkTheme = !!getenv("VCL_ICONS_FOR_DARK_THEME");
if (bIconsForDarkTheme)
bitmap = BitmapProcessor::createLightImage(bitmap);
return true;
}
}
catch (css::uno::RuntimeException &) {}
aStyle = fallbackStyle(aStyle);
}
return false;
}
bool ImplImageTree::loadDefaultImage(OUString const & style, BitmapEx& bitmap)
{
return doLoadImage(
"res/grafikde.png",
style, bitmap, false);
}
bool ImplImageTree::doLoadImage(OUString const & name, OUString const & style, BitmapEx & bitmap,
bool localized)
{
setStyle(style);
if (iconCacheLookup(name, localized, bitmap))
return true;
if (!bitmap.IsEmpty())
bitmap.SetEmpty();
std::vector< OUString > paths;
paths.push_back(getRealImageName(name));
if (localized)
{
sal_Int32 pos = name.lastIndexOf('/');
if (pos != -1)
{
// findImage() uses a reverse iterator, so push in reverse order.
std::vector< OUString > aFallbacks( Application::GetSettings().GetUILanguageTag().getFallbackStrings(true));
for (std::vector< OUString >::reverse_iterator it( aFallbacks.rbegin());
it != aFallbacks.rend(); ++it)
{
paths.push_back( getRealImageName( createPath(name, pos, *it) ) );
}
}
}
bool found = false;
try {
found = findImage(paths, bitmap);
} catch (css::uno::RuntimeException &) {
throw;
} catch (const css::uno::Exception & e) {
SAL_INFO("vcl", "ImplImageTree::doLoadImage exception " << e.Message);
}
if (found)
maIconSet[maCurrentStyle].maIconCache[name] = std::make_pair(localized, bitmap);
return found;
}
void ImplImageTree::shutDown()
{
maCurrentStyle.clear();
for (StyleIconSet::iterator it = maIconSet.begin(); it != maIconSet.end(); ++it)
{
it->second.maIconCache.clear();
it->second.maLinkHash.clear();
}
}
void ImplImageTree::setStyle(OUString const & style)
{
assert(!style.isEmpty());
if (style != maCurrentStyle)
{
maCurrentStyle = style;
createStyle();
}
}
void ImplImageTree::createStyle()
{
if (maIconSet.find(maCurrentStyle) != maIconSet.end())
return;
OUString url( "$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/config/" );
rtl::Bootstrap::expandMacros(url);
if (maCurrentStyle != "default")
{
INetURLObject u(url);
OSL_ASSERT(!u.HasError());
bool ok = u.Append("images_" + maCurrentStyle, INetURLObject::ENCODE_ALL);
OSL_ASSERT(ok); (void) ok;
url = u.GetMainURL(INetURLObject::NO_DECODE);
}
else
url += "images";
maIconSet[maCurrentStyle] = IconSet(url);
loadImageLinks();
}
bool ImplImageTree::iconCacheLookup(OUString const & name, bool localized, BitmapEx & bitmap)
{
IconCache &rIconCache = maIconSet[maCurrentStyle].maIconCache;
IconCache::iterator i(rIconCache.find(getRealImageName(name)));
if (i != rIconCache.end() && i->second.first == localized)
{
bitmap = i->second.second;
return true;
}
return false;
}
bool ImplImageTree::findImage(std::vector<OUString> const & paths, BitmapEx & bitmap)
{
if (!checkPathAccess())
return false;
const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess;
for (std::vector<OUString>::const_reverse_iterator j(paths.rbegin()); j != paths.rend(); ++j)
{
if (rNameAccess->hasByName(*j))
{
css::uno::Reference< css::io::XInputStream > s;
bool ok = rNameAccess->getByName(*j) >>= s;
assert(ok);
(void)ok; // prevent unused warning in release build
loadImageFromStream( wrapStream(s), *j, bitmap );
return true;
}
}
return false;
}
void ImplImageTree::loadImageLinks()
{
const OUString aLinkFilename("links.txt");
if (!checkPathAccess())
return;
const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess;
if (rNameAccess->hasByName(aLinkFilename))
{
css::uno::Reference< css::io::XInputStream > s;
bool ok = rNameAccess->getByName(aLinkFilename) >>= s;
assert(ok);
(void)ok; // prevent unused warning in release build
parseLinkFile( wrapStream(s) );
return;
}
}
void ImplImageTree::parseLinkFile(std::shared_ptr<SvStream> const & xStream)
{
OString aLine;
OUString aLink, aOriginal;
int nLineNo = 0;
while (xStream->ReadLine(aLine))
{
++nLineNo;
if ( aLine.isEmpty() )
continue;
sal_Int32 nIndex = 0;
aLink = OStringToOUString( aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8 );
aOriginal = OStringToOUString( aLine.getToken(0, ' ', nIndex), RTL_TEXTENCODING_UTF8 );
// skip comments, or incomplete entries
if (aLink.isEmpty() || aLink[0] == '#' || aOriginal.isEmpty())
{
if (aLink.isEmpty() || aOriginal.isEmpty())
SAL_WARN("vcl", "ImplImageTree::parseLinkFile: icon links.txt parse error, incomplete link at line " << nLineNo);
continue;
}
maIconSet[maCurrentStyle].maLinkHash[aLink] = aOriginal;
}
}
OUString const & ImplImageTree::getRealImageName(OUString const & name)
{
IconLinkHash &rLinkHash = maIconSet[maCurrentStyle].maLinkHash;
IconLinkHash::iterator it(rLinkHash.find(name));
if (it == rLinkHash.end())
return name;
return it->second;
}
bool ImplImageTree::checkPathAccess()
{
uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess;
if (rNameAccess.is())
return true;
try {
rNameAccess = css::packages::zip::ZipFileAccess::createWithURL(comphelper::getProcessComponentContext(), maIconSet[maCurrentStyle].maURL + ".zip");
}
catch (const css::uno::RuntimeException &) {
throw;
}
catch (const css::uno::Exception & e) {
SAL_INFO("vcl", "ImplImageTree::zip file location exception " << e.Message << " for " << maIconSet[maCurrentStyle].maURL);
return false;
}
return rNameAccess.is();
}
css::uno::Reference<css::container::XNameAccess> ImplImageTree::getNameAccess()
{
checkPathAccess();
return maIconSet[maCurrentStyle].maNameAccess;
}
/// Recursively dump all names ...
css::uno::Sequence<OUString> ImageTree_getAllImageNames()
{
css::uno::Reference<css::container::XNameAccess> xRef(ImplImageTree::get().getNameAccess());
return xRef->getElementNames();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */