diff options
Diffstat (limited to 'vcl/source/image/ImplImageTree.cxx')
-rw-r--r-- | vcl/source/image/ImplImageTree.cxx | 363 |
1 files changed, 234 insertions, 129 deletions
diff --git a/vcl/source/image/ImplImageTree.cxx b/vcl/source/image/ImplImageTree.cxx index 30659c661166..a112ddb2bcb7 100644 --- a/vcl/source/image/ImplImageTree.cxx +++ b/vcl/source/image/ImplImageTree.cxx @@ -47,16 +47,54 @@ #include <vcl/BitmapProcessor.hxx> #include <vcl/BitmapTools.hxx> +#include <vcl/pngwrite.hxx> -using namespace css; - -namespace { +namespace +{ OUString createPath(OUString const & name, sal_Int32 pos, OUString const & locale) { return name.copy(0, pos + 1) + locale + name.copy(pos); } +OUString getIconThemeFolderUrl() +{ + OUString sUrl("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/config/"); + rtl::Bootstrap::expandMacros(sUrl); + return sUrl; +} + +OUString getIconCacheUrl(OUString const & sStyle, OUString const & sVariant, OUString const & sName) +{ + OUString sUrl("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/"); + sUrl += sStyle + "/" + sVariant + "/" + sName; + rtl::Bootstrap::expandMacros(sUrl); + return sUrl; +} + +OUString createIconCacheUrl(OUString const & sStyle, OUString const & sVariant, OUString const & sName) +{ + OUString sUrl(getIconCacheUrl(sStyle, sVariant, sName)); + OUString sDir = sUrl.copy(0, sUrl.lastIndexOf('/')); + osl::Directory::createPath(sDir); + return sUrl; +} + +bool urlExists(OUString const & sUrl) +{ + osl::File aFile(sUrl); + osl::FileBase::RC eRC = aFile.open(osl_File_OpenFlag_Read); + if (osl::FileBase::E_None == eRC) + return true; + return false; +} + +OUString getNameNoExtension(OUString const & sName) +{ + sal_Int32 nDotPosition = sName.lastIndexOf('.'); + return sName.copy(0, nDotPosition); +} + 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 @@ -78,8 +116,18 @@ std::shared_ptr<SvStream> wrapStream(css::uno::Reference< css::io::XInputStream return s; } -void loadImageFromStream(std::shared_ptr<SvStream> const & xStream, OUString const & rPath, BitmapEx & rBitmap) +void loadImageFromStream(std::shared_ptr<SvStream> const & xStream, OUString const & rPath, BitmapEx & rBitmap, const ImageLoadFlags eFlags) { + static bool bIconsForDarkTheme = !!getenv("VCL_ICONS_FOR_DARK_THEME"); + + bool bConvertToDarkTheme = bIconsForDarkTheme; + if (eFlags & ImageLoadFlags::IgnoreDarkTheme) + bConvertToDarkTheme = false; + + sal_Int32 aScaleFactor = Application::GetDefaultDevice()->GetDPIScaleFactor(); + if (eFlags & ImageLoadFlags::IgnoreScalingFactor) + aScaleFactor = 1; + if (rPath.endsWith(".png")) { vcl::PNGReader aPNGReader(*xStream); @@ -88,12 +136,21 @@ void loadImageFromStream(std::shared_ptr<SvStream> const & xStream, OUString con } else if (rPath.endsWith(".svg")) { - vcl::BitmapTools::loadFromSvg(*xStream.get(), rPath, rBitmap); + vcl::bitmap::loadFromSvg(*xStream.get(), rPath, rBitmap, double(aScaleFactor)); + if (bConvertToDarkTheme) + rBitmap = BitmapProcessor::createLightImage(rBitmap); + return; } else { ReadDIBBitmapEx(rBitmap, *xStream); } + + if (bConvertToDarkTheme) + rBitmap = BitmapProcessor::createLightImage(rBitmap); + + if (aScaleFactor > 1) + rBitmap.Scale(double(aScaleFactor), double(aScaleFactor), BmpScaleFlag::Fast); } } @@ -111,144 +168,179 @@ ImplImageTree::~ImplImageTree() { } -OUString ImplImageTree::getImageUrl( - OUString const & name, OUString const & style, OUString const & lang) +std::vector<OUString> ImplImageTree::getPaths(OUString const & name, LanguageTag& rLanguageTag) { - OUString aStyle(style); + std::vector<OUString> sPaths; + + sal_Int32 pos = name.lastIndexOf('/'); + if (pos != -1) + { + for (OUString& rFallback : rLanguageTag.getFallbackStrings(true)) + { + OUString aFallbackName = getRealImageName(createPath(name, pos, rFallback)); + sPaths.push_back(getNameNoExtension(aFallbackName) + ".svg"); + sPaths.push_back(aFallbackName); + } + } + + OUString aRealName = getRealImageName(name); + sPaths.push_back(getNameNoExtension(aRealName) + ".svg"); + sPaths.push_back(aRealName); + + return sPaths; +} + +OUString ImplImageTree::getImageUrl(OUString const & rName, OUString const & rStyle, OUString const & rLang) +{ + OUString aStyle(rStyle); + while (!aStyle.isEmpty()) { - try { + try + { setStyle(aStyle); - std::vector< OUString > paths; - paths.push_back(getRealImageName(name)); - - if (!lang.isEmpty()) + if (checkPathAccess()) { - 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) ) ); - } - } - } + IconSet& rIconSet = getCurrentIconSet(); + const css::uno::Reference<css::container::XNameAccess>& rNameAccess = rIconSet.maNameAccess; - try { - if (checkPathAccess()) { - const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess; + LanguageTag aLanguageTag(rLang); - for (std::vector<OUString>::const_reverse_iterator j(paths.rbegin()); j != paths.rend(); ++j) + for (OUString& rPath: getPaths(rName, aLanguageTag)) + { + if (rNameAccess->hasByName(rPath)) { - 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 - } + return "vnd.sun.star.zip://" + + rtl::Uri::encode(rIconSet.maURL, rtl_UriCharClassRegName, + rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8) + + "/" + rPath; } } - } catch (css::uno::RuntimeException &) { - throw; - } catch (const css::uno::Exception & e) { - SAL_INFO("vcl", "exception " << e.Message); } } - catch (css::uno::RuntimeException &) {} + catch (const css::uno::Exception & e) + { + SAL_INFO("vcl", "exception " << e.Message); + } aStyle = fallbackStyle(aStyle); } return OUString(); } -OUString ImplImageTree::fallbackStyle(const OUString &style) +OUString ImplImageTree::fallbackStyle(const OUString& rsStyle) { - 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"); - else if (style == "breeze_dark") - return OUString("breeze"); - - return OUString("tango"); -} - -bool ImplImageTree::loadImage(OUString const & name, OUString const & style, BitmapEx & bitmap, - bool localized) + OUString sResult; + + if (rsStyle == "galaxy") + sResult = ""; + else if (rsStyle == "industrial" || rsStyle == "tango" || rsStyle == "breeze") + sResult = "galaxy"; + else if (rsStyle == "sifr" || rsStyle == "breeze_dark") + sResult = "breeze"; + else + sResult = "tango"; + + return sResult; +} + +bool ImplImageTree::loadImage(OUString const & name, OUString const & style, BitmapEx & rBitmap, bool localized, const ImageLoadFlags eFlags) { 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); + try + { + if (doLoadImage(name, aStyle + "_svg", rBitmap, localized, eFlags)) + return true; + } + catch (css::uno::RuntimeException &) + {} + + try + { + if (doLoadImage(name, aStyle, rBitmap, localized, eFlags)) return true; - } } - catch (css::uno::RuntimeException &) {} + catch (css::uno::RuntimeException &) + {} aStyle = fallbackStyle(aStyle); } - return false; } -bool ImplImageTree::loadDefaultImage(OUString const & style, BitmapEx& bitmap) +bool ImplImageTree::loadDefaultImage(OUString const & style, BitmapEx& bitmap, const ImageLoadFlags eFlags) +{ + return doLoadImage("res/grafikde.png", style, bitmap, false, eFlags); +} + +OUString createVariant(const ImageLoadFlags eFlags) +{ + static bool bIconsForDarkTheme = !!getenv("VCL_ICONS_FOR_DARK_THEME"); + + bool bConvertToDarkTheme = bIconsForDarkTheme; + if (eFlags & ImageLoadFlags::IgnoreDarkTheme) + bConvertToDarkTheme = false; + + sal_Int32 aScaleFactor = Application::GetDefaultDevice()->GetDPIScaleFactor(); + if (eFlags & ImageLoadFlags::IgnoreScalingFactor) + aScaleFactor = 1; + + OUString aVariant; + if (aScaleFactor == 2) + aVariant = "2x"; + + if (bConvertToDarkTheme) + aVariant += "-dark"; + + return aVariant; +} + +bool loadDiskCachedVersion(OUString const & sStyle, OUString const & sVariant, OUString const & sName, BitmapEx & rBitmapEx) +{ + OUString sUrl(getIconCacheUrl(sStyle, sVariant, sName)); + if (!urlExists(sUrl)) + return false; + SvFileStream aFileStream(sUrl, StreamMode::READ); + vcl::PNGReader aPNGReader(aFileStream); + aPNGReader.SetIgnoreGammaChunk( true ); + rBitmapEx = aPNGReader.Read(); + return true; +} + +void cacheBitmapToDisk(OUString const & sStyle, OUString const & sVariant, OUString const & sName, BitmapEx & rBitmapEx) { - return doLoadImage( - "res/grafikde.png", - style, bitmap, false); + OUString sUrl(createIconCacheUrl(sStyle, sVariant, sName)); + vcl::PNGWriter aWriter(rBitmapEx); + try + { + SvFileStream aStream(sUrl, StreamMode::WRITE); + aWriter.Write(aStream); + aStream.Close(); + } + catch (...) + {} } -bool ImplImageTree::doLoadImage(OUString const & name, OUString const & style, BitmapEx & bitmap, - bool localized) +bool ImplImageTree::doLoadImage(OUString const & name, OUString const & style, BitmapEx & bitmap, bool localized, const ImageLoadFlags eFlags) { setStyle(style); - if (iconCacheLookup(name, localized, bitmap)) + + if (iconCacheLookup(name, localized, eFlags, bitmap)) return true; if (!bitmap.IsEmpty()) bitmap.SetEmpty(); - std::vector< OUString > paths; - paths.push_back(getRealImageName(name)); + LanguageTag aLanguageTag = Application::GetSettings().GetUILanguageTag(); - 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) ) ); - } - } - } + std::vector<OUString> paths = getPaths(name, aLanguageTag); bool found = false; try { - found = findImage(paths, bitmap); + found = findImage(paths, bitmap, eFlags); } catch (css::uno::RuntimeException &) { throw; } catch (const css::uno::Exception & e) { @@ -256,7 +348,12 @@ bool ImplImageTree::doLoadImage(OUString const & name, OUString const & style, B } if (found) - maIconSet[maCurrentStyle].maIconCache[name] = std::make_pair(localized, bitmap); + { + OUString aVariant = createVariant(eFlags); + if (!aVariant.isEmpty()) + cacheBitmapToDisk(style, aVariant, name, bitmap); + getCurrentIconSet().maIconCache[name] = std::make_pair(localized, bitmap); + } return found; } @@ -264,11 +361,7 @@ bool ImplImageTree::doLoadImage(OUString const & name, OUString const & style, B void ImplImageTree::shutDown() { maCurrentStyle.clear(); - for (StyleIconSet::iterator it = maIconSet.begin(); it != maIconSet.end(); ++it) - { - it->second.maIconCache.clear(); - it->second.maLinkHash.clear(); - } + maIconSets.clear(); } void ImplImageTree::setStyle(OUString const & style) @@ -283,30 +376,35 @@ void ImplImageTree::setStyle(OUString const & style) void ImplImageTree::createStyle() { - if (maIconSet.find(maCurrentStyle) != maIconSet.end()) + if (maIconSets.find(maCurrentStyle) != maIconSets.end()) return; - OUString url( "$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/config/" ); - rtl::Bootstrap::expandMacros(url); + OUString sThemeUrl; + if (maCurrentStyle != "default") { - INetURLObject u(url); - OSL_ASSERT(!u.HasError()); - bool ok = u.Append("images_" + maCurrentStyle, INetURLObject::ENCODE_ALL); + INetURLObject aUrl(getIconThemeFolderUrl()); + OSL_ASSERT(!aUrl.HasError()); + + bool ok = aUrl.Append("images_" + maCurrentStyle, INetURLObject::ENCODE_ALL); OSL_ASSERT(ok); (void) ok; - url = u.GetMainURL(INetURLObject::NO_DECODE); + sThemeUrl = aUrl.GetMainURL(INetURLObject::NO_DECODE) + ".zip"; + } else - url += "images"; + sThemeUrl += "images"; + + if (!urlExists(sThemeUrl)) + return; - maIconSet[maCurrentStyle] = IconSet(url); + maIconSets[maCurrentStyle] = IconSet(sThemeUrl); loadImageLinks(); } -bool ImplImageTree::iconCacheLookup(OUString const & name, bool localized, BitmapEx & bitmap) +bool ImplImageTree::iconCacheLookup(OUString const & name, bool localized, const ImageLoadFlags eFlags, BitmapEx & bitmap) { - IconCache &rIconCache = maIconSet[maCurrentStyle].maIconCache; + IconCache& rIconCache = getCurrentIconSet().maIconCache; IconCache::iterator i(rIconCache.find(getRealImageName(name))); if (i != rIconCache.end() && i->second.first == localized) @@ -314,26 +412,31 @@ bool ImplImageTree::iconCacheLookup(OUString const & name, bool localized, Bitma bitmap = i->second.second; return true; } + + OUString aVariant = createVariant(eFlags); + if (!aVariant.isEmpty() && loadDiskCachedVersion(maCurrentStyle, aVariant, name, bitmap)) + return true; + return false; } -bool ImplImageTree::findImage(std::vector<OUString> const & paths, BitmapEx & bitmap) +bool ImplImageTree::findImage(std::vector<OUString> const & paths, BitmapEx & bitmap, const ImageLoadFlags eFlags) { if (!checkPathAccess()) return false; - const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess; + const css::uno::Reference<css::container::XNameAccess>& rNameAccess = getCurrentIconSet().maNameAccess; - for (std::vector<OUString>::const_reverse_iterator j(paths.rbegin()); j != paths.rend(); ++j) + for (const OUString& rPath : paths) { - if (rNameAccess->hasByName(*j)) + if (rNameAccess->hasByName(rPath)) { - css::uno::Reference< css::io::XInputStream > s; - bool ok = rNameAccess->getByName(*j) >>= s; + css::uno::Reference<css::io::XInputStream> aStream; + bool ok = rNameAccess->getByName(rPath) >>= aStream; assert(ok); (void)ok; // prevent unused warning in release build - loadImageFromStream( wrapStream(s), *j, bitmap ); + loadImageFromStream(wrapStream(aStream), rPath, bitmap, eFlags); return true; } } @@ -347,7 +450,7 @@ void ImplImageTree::loadImageLinks() if (!checkPathAccess()) return; - const uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess; + const css::uno::Reference<css::container::XNameAccess> &rNameAccess = getCurrentIconSet().maNameAccess; if (rNameAccess->hasByName(aLinkFilename)) { @@ -384,13 +487,13 @@ void ImplImageTree::parseLinkFile(std::shared_ptr<SvStream> const & xStream) continue; } - maIconSet[maCurrentStyle].maLinkHash[aLink] = aOriginal; + getCurrentIconSet().maLinkHash[aLink] = aOriginal; } } OUString const & ImplImageTree::getRealImageName(OUString const & name) { - IconLinkHash &rLinkHash = maIconSet[maCurrentStyle].maLinkHash; + IconLinkHash &rLinkHash = maIconSets[maCurrentStyle].maLinkHash; IconLinkHash::iterator it(rLinkHash.find(name)); if (it == rLinkHash.end()) @@ -401,18 +504,20 @@ OUString const & ImplImageTree::getRealImageName(OUString const & name) bool ImplImageTree::checkPathAccess() { - uno::Reference<container::XNameAccess> &rNameAccess = maIconSet[maCurrentStyle].maNameAccess; + IconSet& rIconSet = getCurrentIconSet(); + css::uno::Reference<css::container::XNameAccess> &rNameAccess = rIconSet.maNameAccess; if (rNameAccess.is()) return true; - try { - rNameAccess = css::packages::zip::ZipFileAccess::createWithURL(comphelper::getProcessComponentContext(), maIconSet[maCurrentStyle].maURL + ".zip"); + try + { + rNameAccess = css::packages::zip::ZipFileAccess::createWithURL(comphelper::getProcessComponentContext(), rIconSet.maURL); } 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); + SAL_INFO("vcl", "ImplImageTree::zip file location exception " << e.Message << " for " << rIconSet.maURL); return false; } return rNameAccess.is(); @@ -421,7 +526,7 @@ bool ImplImageTree::checkPathAccess() css::uno::Reference<css::container::XNameAccess> ImplImageTree::getNameAccess() { checkPathAccess(); - return maIconSet[maCurrentStyle].maNameAccess; + return getCurrentIconSet().maNameAccess; } /// Recursively dump all names ... |