framework/Library_fwk.mk | 2 framework/source/uiconfiguration/ImageArrayData.cxx | 91 ------- framework/source/uiconfiguration/ImageList.cxx | 149 ++++-------- framework/source/uiconfiguration/ImageList.hxx | 24 + framework/source/uiconfiguration/ImplImageList.cxx | 71 ----- framework/source/uiconfiguration/image.h | 67 ----- framework/source/uiconfiguration/imagemanagerimpl.cxx | 2 include/LibreOfficeKit/LibreOfficeKit.hxx | 2 include/vcl/ImageTree.hxx | 6 include/vcl/graph.hxx | 2 include/vcl/image.hxx | 3 libreofficekit/qa/gtktiledviewer/gtv-application-window.cxx | 15 - libreofficekit/qa/gtktiledviewer/gtv-application-window.hxx | 2 libreofficekit/qa/gtktiledviewer/gtv-application.cxx | 5 libreofficekit/qa/tilebench/tilebench.cxx | 2 libreofficekit/source/gtk/lokdocview.cxx | 63 +++++ sd/source/ui/controller/slidelayoutcontroller.cxx | 11 sd/source/ui/sidebar/LayoutMenu.cxx | 10 sfx2/source/sidebar/Tools.cxx | 9 vcl/inc/image.h | 26 ++ vcl/inc/implimagetree.hxx | 15 - vcl/source/control/fixed.cxx | 3 vcl/source/gdi/graph.cxx | 13 + vcl/source/helper/commandinfoprovider.cxx | 23 - vcl/source/image/Image.cxx | 133 ++++------ vcl/source/image/ImageTree.cxx | 10 vcl/source/image/ImplImage.cxx | 120 +++++++++ vcl/source/image/ImplImageTree.cxx | 37 ++ vcl/source/window/builder.cxx | 8 vcl/source/window/msgbox.cxx | 11 vcl/source/window/paint.cxx | 11 vcl/source/window/winproc.cxx | 6 32 files changed, 479 insertions(+), 473 deletions(-)
New commits: commit ad747625c821232790a4c435d4efe8629f849294 Author: Michael Meeks <michael.me...@collabora.com> AuthorDate: Mon Nov 26 16:59:42 2018 +0000 Commit: Michael Meeks <michael.me...@collabora.com> CommitDate: Tue Sep 24 13:58:53 2019 +0100 Use lazy-loading stock Image to simplify framework image lists. Project stock names through XGraphic via origin URL. (cherry picked from commit 77b88eebaadebb626108172e4f2de36c60960051) Change-Id: Ib445694f7c142a163ef7e7bc0beea39b88b99e14 diff --git a/framework/source/uiconfiguration/ImageList.cxx b/framework/source/uiconfiguration/ImageList.cxx index 100e152b17fc..93b89e71dc05 100644 --- a/framework/source/uiconfiguration/ImageList.cxx +++ b/framework/source/uiconfiguration/ImageList.cxx @@ -44,9 +44,7 @@ ImageList::ImageList(const std::vector< OUString >& rNameVector, maPrefix = rPrefix; for( size_t i = 0; i < rNameVector.size(); ++i ) - { - ImplAddImage( rNameVector[ i ], static_cast< sal_uInt16 >( i ) + 1, BitmapEx() ); - } + ImplAddImage( rPrefix, rNameVector[ i ], static_cast< sal_uInt16 >( i ) + 1, Image() ); } // FIXME: Rather a performance hazard @@ -57,15 +55,7 @@ BitmapEx ImageList::GetAsHorizontalStrip() const return BitmapEx(); Size aSize( maImageSize.Width() * nCount, maImageSize.Height() ); - // Load any stragglers - for (sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++) - { - ImageAryData *pData = maImages[ nIdx ].get(); - if( pData->IsLoadable() ) - ImplLoad(*pData); - } - - BitmapEx aTempl = maImages[ 0 ]->maBitmapEx; + BitmapEx aTempl = maImages[ 0 ]->maImage.GetBitmapEx(); BitmapEx aResult( aTempl, Point(), aSize ); tools::Rectangle aSrcRect( Point( 0, 0 ), maImageSize ); @@ -74,7 +64,8 @@ BitmapEx ImageList::GetAsHorizontalStrip() const tools::Rectangle aDestRect( Point( nIdx * maImageSize.Width(), 0 ), maImageSize ); ImageAryData *pData = maImages[ nIdx ].get(); - aResult.CopyPixel( aDestRect, aSrcRect, &pData->maBitmapEx); + BitmapEx aTmp = pData->maImage.GetBitmapEx(); + aResult.CopyPixel( aDestRect, aSrcRect, &aTmp ); } return aResult; @@ -101,7 +92,7 @@ void ImageList::InsertFromHorizontalStrip( const BitmapEx &rBitmapEx, for (sal_uInt16 nIdx = 0; nIdx < nItems; nIdx++) { BitmapEx aBitmap( rBitmapEx, Point( nIdx * aSize.Width(), 0 ), aSize ); - ImplAddImage( rNameVector[ nIdx ], nIdx + 1, aBitmap ); + ImplAddImage( maPrefix, rNameVector[ nIdx ], nIdx + 1, Image( aBitmap ) ); } } @@ -117,8 +108,7 @@ void ImageList::AddImage( const OUString& rImageName, const Image& rImage ) { SAL_WARN_IF( GetImagePos( rImageName ) != IMAGELIST_IMAGE_NOTFOUND, "vcl", "ImageList::AddImage() - ImageName already exists" ); - ImplAddImage( rImageName, GetImageCount() + 1, - rImage.GetBitmapEx() ); + ImplAddImage( maPrefix, rImageName, GetImageCount() + 1, rImage ); } void ImageList::ReplaceImage( const OUString& rImageName, const Image& rImage ) @@ -127,10 +117,10 @@ void ImageList::ReplaceImage( const OUString& rImageName, const Image& rImage ) if( nId ) { - //Just replace the bitmap rather than doing RemoveImage / AddImage - //which breaks index-based iteration. + // Just replace the bitmap rather than doing RemoveImage / AddImage + // which breaks index-based iteration. ImageAryData *pImg = maNameHash[ rImageName ]; - pImg->maBitmapEx = rImage.GetBitmapEx(); + pImg->maImage = rImage; } } @@ -151,10 +141,7 @@ Image ImageList::GetImage( const OUString& rImageName ) const auto it = maNameHash.find( rImageName ); if (it == maNameHash.end()) return Image(); - ImageAryData *pImg = it->second; - if( pImg->IsLoadable() ) - ImplLoad( *pImg ); - return Image( pImg->maBitmapEx ); + return it->second->maImage; } sal_uInt16 ImageList::GetImageCount() const @@ -200,10 +187,14 @@ void ImageList::GetImageNames( std::vector< OUString >& rNames ) const } } -void ImageList::ImplAddImage( const OUString &aName, - sal_uInt16 nId, const BitmapEx &aBitmapEx ) +void ImageList::ImplAddImage( const OUString &aPrefix, const OUString &aName, + sal_uInt16 nId, const Image &aImage ) { - ImageAryData *pImg = new ImageAryData{ aName, nId, aBitmapEx }; + Image aInsert = aImage; + if (!aInsert) + aInsert = Image( "private:graphicrepository/" + aPrefix + aName ); + + ImageAryData *pImg = new ImageAryData{ aName, nId, aInsert }; maImages.emplace_back( pImg ); if( !aName.isEmpty() ) maNameHash [ aName ] = pImg; @@ -217,29 +208,4 @@ void ImageList::ImplRemoveImage( sal_uInt16 nPos ) maImages.erase( maImages.begin() + nPos ); } -void ImageList::ImplLoad(ImageAryData& rImageData) const -{ - OUString aIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme(); - - OUString aFileName = maPrefix + rImageData.maName; - - bool bSuccess = ImageTree::get().loadImage(aFileName, aIconTheme, rImageData.maBitmapEx, true); - - /* If the uno command has parameters, passed in from a toolbar, - * recover from failure by removing the parameters from the file name - */ - if (!bSuccess && aFileName.indexOf("%3f") > 0) - { - sal_Int32 nStart = aFileName.indexOf("%3f"); - sal_Int32 nEnd = aFileName.lastIndexOf("."); - - aFileName = aFileName.replaceAt(nStart, nEnd - nStart, ""); - bSuccess = ImageTree::get().loadImage(aFileName, aIconTheme, rImageData.maBitmapEx, true); - } - - SAL_WARN_IF(!bSuccess, "fwk.uiconfiguration", "Failed to load image '" << aFileName - << "' from icon theme '" << aIconTheme << "'"); -} - - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/uiconfiguration/ImageList.hxx b/framework/source/uiconfiguration/ImageList.hxx index f610692fb672..7f72c980fdb3 100644 --- a/framework/source/uiconfiguration/ImageList.hxx +++ b/framework/source/uiconfiguration/ImageList.hxx @@ -20,18 +20,16 @@ #ifndef FRAMEWORK_SOURCE_UICONFIGURATION_IMAGELIST_HXX #define FRAMEWORK_SOURCE_UICONFIGURATION_IMAGELIST_HXX -#include <vcl/bitmapex.hxx> +#include <vcl/image.hxx> #include <unordered_map> #include <vector> // Images identified by either name, or by id struct ImageAryData { - OUString maName; - sal_uInt16 mnId; - BitmapEx maBitmapEx; - - bool IsLoadable() { return maBitmapEx.IsEmpty() && !maName.isEmpty(); } + OUString maName; + sal_uInt16 mnId; + Image maImage; }; class ImageList @@ -69,7 +67,7 @@ private: Size maImageSize; sal_uInt16 ImplGetImageId( const OUString& rImageName ) const; - void ImplAddImage( const OUString &aName, sal_uInt16 nId, const BitmapEx &aBitmapEx ); + void ImplAddImage( const OUString &aPrefix, const OUString &aName, sal_uInt16 nId, const Image &aImage ); void ImplRemoveImage( sal_uInt16 nPos ); void ImplLoad(ImageAryData&) const; }; diff --git a/framework/source/uiconfiguration/imagemanagerimpl.cxx b/framework/source/uiconfiguration/imagemanagerimpl.cxx index 650d44e2a1e4..5695de44dca5 100644 --- a/framework/source/uiconfiguration/imagemanagerimpl.cxx +++ b/framework/source/uiconfiguration/imagemanagerimpl.cxx @@ -713,7 +713,7 @@ namespace { css::uno::Reference< css::graphic::XGraphic > GetXGraphic(const Image &rImage) { - return Graphic(rImage.GetBitmapEx()).GetXGraphic(); + return Graphic(rImage).GetXGraphic(); } } diff --git a/include/vcl/graph.hxx b/include/vcl/graph.hxx index 3b91a3269478..cc8df96fc68c 100644 --- a/include/vcl/graph.hxx +++ b/include/vcl/graph.hxx @@ -102,6 +102,7 @@ public: bool getSnapHorVerLines() const { return mbSnapHorVerLines; } }; +class Image; class VCL_DLLPUBLIC Graphic { private: @@ -119,6 +120,7 @@ public: Graphic( const Graphic& rGraphic ); Graphic( Graphic&& rGraphic ); Graphic( const Bitmap& rBmp ); + Graphic( const Image& rImage ); Graphic( const BitmapEx& rBmpEx ); Graphic( const VectorGraphicDataPtr& rVectorGraphicDataPtr ); Graphic( const Animation& rAnimation ); diff --git a/include/vcl/image.hxx b/include/vcl/image.hxx index 526243bcf382..862f1806296c 100644 --- a/include/vcl/image.hxx +++ b/include/vcl/image.hxx @@ -52,7 +52,6 @@ namespace vcl class SAL_WARN_UNUSED VCL_DLLPUBLIC Image { friend class ::OutputDevice; - public: Image(); explicit Image( const BitmapEx& rBitmapEx ); @@ -67,6 +66,8 @@ public: bool operator==( const Image& rImage ) const; bool operator!=( const Image& rImage ) const { return !(Image::operator==( rImage )); } + SAL_DLLPRIVATE OUString GetStock() const; + void Draw(OutputDevice* pOutDev, const Point& rPos, DrawImageFlags nStyle, const Size* pSize = nullptr); private: diff --git a/sfx2/source/sidebar/Tools.cxx b/sfx2/source/sidebar/Tools.cxx index 0f0f596f936d..cebfc93013d9 100644 --- a/sfx2/source/sidebar/Tools.cxx +++ b/sfx2/source/sidebar/Tools.cxx @@ -53,14 +53,13 @@ Image Tools::GetImage ( { if (rsURL.getLength() > 0) { + OUString sPath; + if (rsURL.startsWith(".uno:")) - { return vcl::CommandInfoProvider::GetImageForCommand(rsURL, rxFrame); - } - else - { + + else if (rsURL.startsWith("private:graphicrepository/", &sPath)) return Image(rsURL); - } } return Image(); } diff --git a/vcl/inc/image.h b/vcl/inc/image.h index c9fb5393191a..5048a850aade 100644 --- a/vcl/inc/image.h +++ b/vcl/inc/image.h @@ -42,6 +42,11 @@ struct ImplImage bool isStock() const { return maStockName.getLength() > 0; } + OUString getStock() const + { + return maStockName; + } + /// get size in co-ordinates not scaled for HiDPI Size getSizePixel(); /// Legacy - the original bitmap diff --git a/vcl/source/gdi/graph.cxx b/vcl/source/gdi/graph.cxx index 0b2c043572db..9a9cfea8502f 100644 --- a/vcl/source/gdi/graph.cxx +++ b/vcl/source/gdi/graph.cxx @@ -21,6 +21,7 @@ #include <vcl/outdev.hxx> #include <vcl/svapp.hxx> #include <vcl/graph.hxx> +#include <vcl/image.hxx> #include <vcl/metaact.hxx> #include <impgraph.hxx> #include <com/sun/star/lang/XMultiServiceFactory.hpp> @@ -33,6 +34,7 @@ #include <graphic/UnoGraphic.hxx> #include <vcl/GraphicExternalLink.hxx> +#include <image.h> using namespace ::com::sun::star; @@ -216,6 +218,17 @@ Graphic::Graphic(const BitmapEx& rBmpEx) { } +// We use XGraphic for passing toolbar images across app UNO aps +// and we need to be able to see and preserve 'stock' images too. +Graphic::Graphic(const Image& rImage) + // FIXME: should really defer the BitmapEx load. + : mxImpGraphic(new ImpGraphic(rImage.GetBitmapEx())) +{ + OUString aStock = rImage.GetStock(); + if (aStock.getLength()) + mxImpGraphic->setOriginURL("private:graphicrepository/" + aStock); +} + Graphic::Graphic(const VectorGraphicDataPtr& rVectorGraphicDataPtr) : mxImpGraphic(vcl::graphic::Manager::get().newInstance(rVectorGraphicDataPtr)) { diff --git a/vcl/source/helper/commandinfoprovider.cxx b/vcl/source/helper/commandinfoprovider.cxx index ee9196c6411e..80bc04f876a5 100644 --- a/vcl/source/helper/commandinfoprovider.cxx +++ b/vcl/source/helper/commandinfoprovider.cxx @@ -295,13 +295,13 @@ OUString GetRealCommandForCommand(const OUString& rCommandName, return GetCommandProperty("TargetURL", rCommandName, rsModuleName); } -static BitmapEx GetBitmapForCommand(const OUString& rsCommandName, - const Reference<frame::XFrame>& rxFrame, - vcl::ImageType eImageType) +static Reference<graphic::XGraphic> GetXGraphicForCommand(const OUString& rsCommandName, + const Reference<frame::XFrame>& rxFrame, + vcl::ImageType eImageType) { if (rsCommandName.isEmpty()) - return BitmapEx(); + return nullptr; sal_Int16 nImageType(ui::ImageType::COLOR_NORMAL | ui::ImageType::SIZE_DEFAULT); @@ -324,11 +324,7 @@ static BitmapEx GetBitmapForCommand(const OUString& rsCommandName, aGraphicSeq = xDocImgMgr->getImages( nImageType, aImageCmdSeq ); Reference<graphic::XGraphic> xGraphic = aGraphicSeq[0]; - const Graphic aGraphic(xGraphic); - BitmapEx aBitmap(aGraphic.GetBitmapEx()); - - if (!!aBitmap) - return aBitmap; + return xGraphic; } } catch (Exception&) @@ -347,23 +343,20 @@ static BitmapEx GetBitmapForCommand(const OUString& rsCommandName, aGraphicSeq = xModuleImageManager->getImages(nImageType, aImageCmdSeq); Reference<graphic::XGraphic> xGraphic(aGraphicSeq[0]); - - const Graphic aGraphic(xGraphic); - - return aGraphic.GetBitmapEx(); + return xGraphic; } catch (Exception&) { } - return BitmapEx(); + return nullptr; } Image GetImageForCommand(const OUString& rsCommandName, const Reference<frame::XFrame>& rxFrame, vcl::ImageType eImageType) { - return Image(GetBitmapForCommand(rsCommandName, rxFrame, eImageType)); + return Image(GetXGraphicForCommand(rsCommandName, rxFrame, eImageType)); } sal_Int32 GetPropertiesForCommand ( diff --git a/vcl/source/image/Image.cxx b/vcl/source/image/Image.cxx index ecb514c5bbac..218f2f8512fc 100644 --- a/vcl/source/image/Image.cxx +++ b/vcl/source/image/Image.cxx @@ -49,24 +49,28 @@ Image::Image(const BitmapEx& rBitmapEx) Image::Image(const css::uno::Reference< css::graphic::XGraphic >& rxGraphic) { - const Graphic aGraphic(rxGraphic); - ImplInit(aGraphic.GetBitmapEx()); + if (rxGraphic.is()) + { + const Graphic aGraphic(rxGraphic); + + OUString aPath; + if (aGraphic.getOriginURL().startsWith("private:graphicrepository/", &aPath)) + mpImplData = std::make_shared<ImplImage>(aPath); + else + ImplInit(aGraphic.GetBitmapEx()); + } } Image::Image(const OUString & rFileUrl) { - sal_Int32 nIndex = 0; - if (rFileUrl.getToken( 0, '/', nIndex ) == "private:graphicrepository") - { - mpImplData.reset(new ImplImage(rFileUrl.copy(nIndex))); - } + OUString sImageName; + if (rFileUrl.startsWith("private:graphicrepository/", &sImageName)) + mpImplData = std::make_shared<ImplImage>(sImageName); else { Graphic aGraphic; if (ERRCODE_NONE == GraphicFilter::LoadGraphic(rFileUrl, IMP_PNG, aGraphic)) - { ImplInit(aGraphic.GetBitmapEx()); - } } } @@ -76,6 +80,13 @@ void Image::ImplInit(const BitmapEx& rBitmapEx) mpImplData.reset(new ImplImage(rBitmapEx)); } +OUString Image::GetStock() const +{ + if (mpImplData) + return mpImplData->getStock(); + return OUString(); +} + Size Image::GetSizePixel() const { if (mpImplData) diff --git a/vcl/source/image/ImplImage.cxx b/vcl/source/image/ImplImage.cxx index 95d605e47173..dc5f12ab8b59 100644 --- a/vcl/source/image/ImplImage.cxx +++ b/vcl/source/image/ImplImage.cxx @@ -53,13 +53,37 @@ ImplImage::ImplImage(const OUString &aStockName) bool ImplImage::loadStockAtScale(double fScale, BitmapEx &rBitmapEx) { BitmapEx aBitmapEx; + + ImageLoadFlags eScalingFlags = ImageLoadFlags::NONE; + sal_Int32 nScalePercentage = -1; + + if (comphelper::LibreOfficeKit::isActive()) // scale at the surface + { + nScalePercentage = fScale * 100.0; + eScalingFlags = ImageLoadFlags::IgnoreScalingFactor; + } + OUString aIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme(); if (!ImageTree::get().loadImage(maStockName, aIconTheme, aBitmapEx, true, - fScale * 100.0, - ImageLoadFlags::IgnoreScalingFactor)) + nScalePercentage, eScalingFlags)) { - SAL_WARN("vcl", "Failed to load scaled image from " << maStockName << " at " << fScale); - return false; + /* If the uno command has parameters, passed in from a toolbar, + * recover from failure by removing the parameters from the file name + */ + if (maStockName.indexOf("%3f") > 0) + { + sal_Int32 nStart = maStockName.indexOf("%3f"); + sal_Int32 nEnd = maStockName.lastIndexOf("."); + + OUString aFileName = maStockName.replaceAt(nStart, nEnd - nStart, ""); + if (!ImageTree::get().loadImage(aFileName, aIconTheme, aBitmapEx, true, + nScalePercentage, eScalingFlags)) + { + SAL_WARN("vcl", "Failed to load scaled image from " << maStockName << + " and " << aFileName << " at " << fScale); + return false; + } + } } rBitmapEx = aBitmapEx; return true; @@ -123,7 +147,7 @@ BitmapEx ImplImage::getBitmapExForHiDPI(bool bDisabled) // FIXME: DPI scaling should be tied to the outdev really ... double fScale = comphelper::LibreOfficeKit::getDPIScale(); Size aTarget(maSizePixel.Width()*fScale, - maSizePixel.Height()*fScale); + maSizePixel.Height()*fScale); if (maBitmapEx.GetSizePixel() != aTarget) loadStockAtScale(fScale, maBitmapEx); } commit aa201ce2fc11a4ecd5dc2ac55c35db737e01275a Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Fri Jul 19 16:31:37 2019 +0200 Commit: Michael Meeks <michael.me...@collabora.com> CommitDate: Tue Sep 24 13:58:52 2019 +0100 simplify ImageList we don't need an Impl pattern here Change-Id: I93d0c5904a3aee8844987c7e36c19319d071d2f4 Reviewed-on: https://gerrit.libreoffice.org/75960 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/framework/Library_fwk.mk b/framework/Library_fwk.mk index 9057aaa6048a..6d1f124f2f5a 100644 --- a/framework/Library_fwk.mk +++ b/framework/Library_fwk.mk @@ -113,9 +113,7 @@ $(eval $(call gb_Library_add_exception_objects,fwk,\ framework/source/services/taskcreatorsrv \ framework/source/services/urltransformer \ framework/source/uiconfiguration/CommandImageResolver \ - framework/source/uiconfiguration/ImageArrayData \ framework/source/uiconfiguration/ImageList \ - framework/source/uiconfiguration/ImplImageList \ framework/source/uiconfiguration/globalsettings \ framework/source/uiconfiguration/graphicnameaccess \ framework/source/uiconfiguration/imagemanager \ diff --git a/framework/source/uiconfiguration/ImageArrayData.cxx b/framework/source/uiconfiguration/ImageArrayData.cxx deleted file mode 100644 index 570d2846ff77..000000000000 --- a/framework/source/uiconfiguration/ImageArrayData.cxx +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- 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 <vcl/outdev.hxx> -#include <vcl/bitmapex.hxx> -#include <vcl/alpha.hxx> -#include <vcl/window.hxx> -#include <vcl/bitmapaccess.hxx> -#include <vcl/virdev.hxx> -#include <vcl/image.hxx> -#include <vcl/settings.hxx> -#include <vcl/svapp.hxx> -#include <vcl/ImageTree.hxx> - -#include "image.h" -#include <memory> -#include <sal/log.hxx> - -#if OSL_DEBUG_LEVEL > 0 -#include <rtl/strbuf.hxx> -#endif - -ImageAryData::ImageAryData( const ImageAryData& rData ) : - maName( rData.maName ), - mnId( rData.mnId ), - maBitmapEx( rData.maBitmapEx ) -{ -} - -ImageAryData::ImageAryData( const OUString &aName, - sal_uInt16 nId, const BitmapEx &aBitmap ) - : maName( aName ), mnId( nId ), maBitmapEx( aBitmap ) -{ -} - -ImageAryData::~ImageAryData() -{ -} - -ImageAryData& ImageAryData::operator=( const ImageAryData& rData ) -{ - maName = rData.maName; - mnId = rData.mnId; - maBitmapEx = rData.maBitmapEx; - - return *this; -} - -void ImageAryData::Load(const OUString &rPrefix) -{ - OUString aIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme(); - - OUString aFileName = rPrefix; - aFileName += maName; - - bool bSuccess = ImageTree::get().loadImage(aFileName, aIconTheme, maBitmapEx, true); - - /* If the uno command has parameters, passed in from a toolbar, - * recover from failure by removing the parameters from the file name - */ - if (!bSuccess && aFileName.indexOf("%3f") > 0) - { - sal_Int32 nStart = aFileName.indexOf("%3f"); - sal_Int32 nEnd = aFileName.lastIndexOf("."); - - aFileName = aFileName.replaceAt(nStart, nEnd - nStart, ""); - bSuccess = ImageTree::get().loadImage(aFileName, aIconTheme, maBitmapEx, true); - } - - SAL_WARN_IF(!bSuccess, "fwk.uiconfiguration", "Failed to load image '" << aFileName - << "' from icon theme '" << aIconTheme << "'"); -} - - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/uiconfiguration/ImageList.cxx b/framework/source/uiconfiguration/ImageList.cxx index 0bb10d3d2bdb..100e152b17fc 100644 --- a/framework/source/uiconfiguration/ImageList.cxx +++ b/framework/source/uiconfiguration/ImageList.cxx @@ -29,7 +29,6 @@ #include <vcl/image.hxx> #include <vcl/imagerepository.hxx> #include <vcl/ImageTree.hxx> -#include "image.h" #include "ImageList.hxx" ImageList::ImageList() @@ -41,48 +40,40 @@ ImageList::ImageList(const std::vector< OUString >& rNameVector, { SAL_INFO( "vcl", "vcl: ImageList::ImageList(const vector< OUString >& ..." ); - ImplInit( sal::static_int_cast< sal_uInt16 >( rNameVector.size() ), Size() ); + maImages.reserve( rNameVector.size() ); - mpImplData->maPrefix = rPrefix; + maPrefix = rPrefix; for( size_t i = 0; i < rNameVector.size(); ++i ) { - mpImplData->AddImage( rNameVector[ i ], static_cast< sal_uInt16 >( i ) + 1, BitmapEx() ); + ImplAddImage( rNameVector[ i ], static_cast< sal_uInt16 >( i ) + 1, BitmapEx() ); } } -void ImageList::ImplInit( sal_uInt16 nItems, const Size &rSize ) -{ - mpImplData.reset(new ImplImageList); - mpImplData->maImages.reserve( nItems ); - mpImplData->maImageSize = rSize; -} - // FIXME: Rather a performance hazard BitmapEx ImageList::GetAsHorizontalStrip() const { - Size aSize( mpImplData->maImageSize ); - sal_uInt16 nCount = GetImageCount(); + sal_uInt16 nCount = maImages.size(); if( !nCount ) return BitmapEx(); - aSize.setWidth( aSize.Width() * nCount ); + Size aSize( maImageSize.Width() * nCount, maImageSize.Height() ); // Load any stragglers for (sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++) { - ImageAryData *pData = mpImplData->maImages[ nIdx ].get(); + ImageAryData *pData = maImages[ nIdx ].get(); if( pData->IsLoadable() ) - pData->Load( mpImplData->maPrefix ); + ImplLoad(*pData); } - BitmapEx aTempl = mpImplData->maImages[ 0 ]->maBitmapEx; + BitmapEx aTempl = maImages[ 0 ]->maBitmapEx; BitmapEx aResult( aTempl, Point(), aSize ); - tools::Rectangle aSrcRect( Point( 0, 0 ), mpImplData->maImageSize ); + tools::Rectangle aSrcRect( Point( 0, 0 ), maImageSize ); for (sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++) { - tools::Rectangle aDestRect( Point( nIdx * mpImplData->maImageSize.Width(), 0 ), - mpImplData->maImageSize ); - ImageAryData *pData = mpImplData->maImages[ nIdx ].get(); + tools::Rectangle aDestRect( Point( nIdx * maImageSize.Width(), 0 ), + maImageSize ); + ImageAryData *pData = maImages[ nIdx ].get(); aResult.CopyPixel( aDestRect, aSrcRect, &pData->maBitmapEx); } @@ -101,32 +92,32 @@ void ImageList::InsertFromHorizontalStrip( const BitmapEx &rBitmapEx, DBG_ASSERT (rBitmapEx.GetSizePixel().Width() % nItems == 0, "ImageList::InsertFromHorizontalStrip - very odd size"); aSize.setWidth( aSize.Width() / nItems ); - ImplInit( nItems, aSize ); + maImages.clear(); + maNameHash.clear(); + maImages.reserve( nItems ); + maImageSize = aSize; + maPrefix.clear(); for (sal_uInt16 nIdx = 0; nIdx < nItems; nIdx++) { BitmapEx aBitmap( rBitmapEx, Point( nIdx * aSize.Width(), 0 ), aSize ); - mpImplData->AddImage( rNameVector[ nIdx ], nIdx + 1, aBitmap ); + ImplAddImage( rNameVector[ nIdx ], nIdx + 1, aBitmap ); } } sal_uInt16 ImageList::ImplGetImageId( const OUString& rImageName ) const { - ImageAryData *pImg = mpImplData->maNameHash[ rImageName ]; - if( pImg ) - return pImg->mnId; - else + auto it = maNameHash.find( rImageName ); + if (it == maNameHash.end()) return 0; + return it->second->mnId; } void ImageList::AddImage( const OUString& rImageName, const Image& rImage ) { SAL_WARN_IF( GetImagePos( rImageName ) != IMAGELIST_IMAGE_NOTFOUND, "vcl", "ImageList::AddImage() - ImageName already exists" ); - if( !mpImplData ) - ImplInit( 0, rImage.GetSizePixel() ); - - mpImplData->AddImage( rImageName, GetImageCount() + 1, + ImplAddImage( rImageName, GetImageCount() + 1, rImage.GetBitmapEx() ); } @@ -138,18 +129,18 @@ void ImageList::ReplaceImage( const OUString& rImageName, const Image& rImage ) { //Just replace the bitmap rather than doing RemoveImage / AddImage //which breaks index-based iteration. - ImageAryData *pImg = mpImplData->maNameHash[ rImageName ]; + ImageAryData *pImg = maNameHash[ rImageName ]; pImg->maBitmapEx = rImage.GetBitmapEx(); } } void ImageList::RemoveImage( sal_uInt16 nId ) { - for( size_t i = 0; i < mpImplData->maImages.size(); ++i ) + for( size_t i = 0; i < maImages.size(); ++i ) { - if( mpImplData->maImages[ i ]->mnId == nId ) + if( maImages[ i ]->mnId == nId ) { - mpImplData->RemoveImage( static_cast< sal_uInt16 >( i ) ); + ImplRemoveImage( static_cast< sal_uInt16 >( i ) ); break; } } @@ -157,33 +148,27 @@ void ImageList::RemoveImage( sal_uInt16 nId ) Image ImageList::GetImage( const OUString& rImageName ) const { - if( mpImplData ) - { - ImageAryData *pImg = mpImplData->maNameHash[ rImageName ]; - - if( pImg ) - { - if( pImg->IsLoadable() ) - pImg->Load( mpImplData->maPrefix ); - return Image( pImg->maBitmapEx ); - } - } - - return Image(); + auto it = maNameHash.find( rImageName ); + if (it == maNameHash.end()) + return Image(); + ImageAryData *pImg = it->second; + if( pImg->IsLoadable() ) + ImplLoad( *pImg ); + return Image( pImg->maBitmapEx ); } sal_uInt16 ImageList::GetImageCount() const { - return mpImplData ? static_cast< sal_uInt16 >( mpImplData->maImages.size() ) : 0; + return static_cast< sal_uInt16 >( maImages.size() ); } sal_uInt16 ImageList::GetImagePos( const OUString& rImageName ) const { - if( mpImplData && !rImageName.isEmpty() ) + if( !rImageName.isEmpty() ) { - for( size_t i = 0; i < mpImplData->maImages.size(); i++ ) + for( size_t i = 0; i < maImages.size(); i++ ) { - if (mpImplData->maImages[i]->maName == rImageName) + if (maImages[i]->maName == rImageName) return static_cast< sal_uInt16 >( i ); } } @@ -193,18 +178,12 @@ sal_uInt16 ImageList::GetImagePos( const OUString& rImageName ) const sal_uInt16 ImageList::GetImageId( sal_uInt16 nPos ) const { - if( mpImplData && (nPos < GetImageCount()) ) - return mpImplData->maImages[ nPos ]->mnId; - - return 0; + return maImages[ nPos ]->mnId; } OUString ImageList::GetImageName( sal_uInt16 nPos ) const { - if( mpImplData && (nPos < GetImageCount()) ) - return mpImplData->maImages[ nPos ]->maName; - - return OUString(); + return maImages[ nPos ]->maName; } void ImageList::GetImageNames( std::vector< OUString >& rNames ) const @@ -213,30 +192,54 @@ void ImageList::GetImageNames( std::vector< OUString >& rNames ) const rNames = std::vector< OUString >(); - if( mpImplData ) + for(auto const & pImage : maImages) { - for(auto const & pImage : mpImplData->maImages) - { - const OUString& rName( pImage->maName ); - if( !rName.isEmpty()) - rNames.push_back( rName ); - } + const OUString& rName( pImage->maName ); + if( !rName.isEmpty()) + rNames.push_back( rName ); } } -bool ImageList::operator==( const ImageList& rImageList ) const +void ImageList::ImplAddImage( const OUString &aName, + sal_uInt16 nId, const BitmapEx &aBitmapEx ) +{ + ImageAryData *pImg = new ImageAryData{ aName, nId, aBitmapEx }; + maImages.emplace_back( pImg ); + if( !aName.isEmpty() ) + maNameHash [ aName ] = pImg; +} + +void ImageList::ImplRemoveImage( sal_uInt16 nPos ) +{ + ImageAryData *pImg = maImages[ nPos ].get(); + if( !pImg->maName.isEmpty() ) + maNameHash.erase( pImg->maName ); + maImages.erase( maImages.begin() + nPos ); +} + +void ImageList::ImplLoad(ImageAryData& rImageData) const { - bool bRet = false; + OUString aIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme(); - if( rImageList.mpImplData == mpImplData ) - bRet = true; - else if( !rImageList.mpImplData || !mpImplData ) - bRet = false; - else if( rImageList.GetImageCount() == GetImageCount() && - rImageList.mpImplData->maImageSize == mpImplData->maImageSize ) - bRet = true; // strange semantic + OUString aFileName = maPrefix + rImageData.maName; - return bRet; + bool bSuccess = ImageTree::get().loadImage(aFileName, aIconTheme, rImageData.maBitmapEx, true); + + /* If the uno command has parameters, passed in from a toolbar, + * recover from failure by removing the parameters from the file name + */ + if (!bSuccess && aFileName.indexOf("%3f") > 0) + { + sal_Int32 nStart = aFileName.indexOf("%3f"); + sal_Int32 nEnd = aFileName.lastIndexOf("."); + + aFileName = aFileName.replaceAt(nStart, nEnd - nStart, ""); + bSuccess = ImageTree::get().loadImage(aFileName, aIconTheme, rImageData.maBitmapEx, true); + } + + SAL_WARN_IF(!bSuccess, "fwk.uiconfiguration", "Failed to load image '" << aFileName + << "' from icon theme '" << aIconTheme << "'"); } + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/uiconfiguration/ImageList.hxx b/framework/source/uiconfiguration/ImageList.hxx index 85c9459a7b5d..f610692fb672 100644 --- a/framework/source/uiconfiguration/ImageList.hxx +++ b/framework/source/uiconfiguration/ImageList.hxx @@ -20,6 +20,20 @@ #ifndef FRAMEWORK_SOURCE_UICONFIGURATION_IMAGELIST_HXX #define FRAMEWORK_SOURCE_UICONFIGURATION_IMAGELIST_HXX +#include <vcl/bitmapex.hxx> +#include <unordered_map> +#include <vector> + +// Images identified by either name, or by id +struct ImageAryData +{ + OUString maName; + sal_uInt16 mnId; + BitmapEx maBitmapEx; + + bool IsLoadable() { return maBitmapEx.IsEmpty() && !maName.isEmpty(); } +}; + class ImageList { public: @@ -47,15 +61,17 @@ public: OUString GetImageName( sal_uInt16 nPos ) const; void GetImageNames( ::std::vector< OUString >& rNames ) const; - bool operator==( const ImageList& rImageList ) const; - bool operator!=( const ImageList& rImageList ) const { return !(ImageList::operator==( rImageList )); } - private: - std::shared_ptr<ImplImageList> mpImplData; + std::vector< std::unique_ptr<ImageAryData> > maImages; + std::unordered_map< OUString, ImageAryData * > maNameHash; + OUString maPrefix; + Size maImageSize; - void ImplInit( sal_uInt16 nItems, const Size &rSize ); sal_uInt16 ImplGetImageId( const OUString& rImageName ) const; + void ImplAddImage( const OUString &aName, sal_uInt16 nId, const BitmapEx &aBitmapEx ); + void ImplRemoveImage( sal_uInt16 nPos ); + void ImplLoad(ImageAryData&) const; }; #endif // INCLUDED_VCL_IMAGE_HXX diff --git a/framework/source/uiconfiguration/ImplImageList.cxx b/framework/source/uiconfiguration/ImplImageList.cxx deleted file mode 100644 index 1c594f16bf89..000000000000 --- a/framework/source/uiconfiguration/ImplImageList.cxx +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- 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 <vcl/outdev.hxx> -#include <vcl/bitmapex.hxx> -#include <vcl/alpha.hxx> -#include <vcl/window.hxx> -#include <vcl/bitmapaccess.hxx> -#include <vcl/virdev.hxx> -#include <vcl/image.hxx> -#include <vcl/settings.hxx> - -#include "image.h" -#include <memory> - -ImplImageList::ImplImageList() -{ -} - -ImplImageList::ImplImageList( const ImplImageList &aSrc ) - : maPrefix(aSrc.maPrefix) - , maImageSize(aSrc.maImageSize) -{ - maImages.reserve( aSrc.maImages.size() ); - for (auto const& elem : aSrc.maImages) - { - ImageAryData* pAryData = new ImageAryData(*elem); - maImages.emplace_back( pAryData ); - if( !pAryData->maName.isEmpty() ) - maNameHash [ pAryData->maName ] = pAryData; - } -} - -ImplImageList::~ImplImageList() -{ -} - -void ImplImageList::AddImage( const OUString &aName, - sal_uInt16 nId, const BitmapEx &aBitmapEx ) -{ - ImageAryData *pImg = new ImageAryData( aName, nId, aBitmapEx ); - maImages.emplace_back( pImg ); - if( !aName.isEmpty() ) - maNameHash [ aName ] = pImg; -} - -void ImplImageList::RemoveImage( sal_uInt16 nPos ) -{ - ImageAryData *pImg = maImages[ nPos ].get(); - if( !pImg->maName.isEmpty() ) - maNameHash.erase( pImg->maName ); - maImages.erase( maImages.begin() + nPos ); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/uiconfiguration/image.h b/framework/source/uiconfiguration/image.h deleted file mode 100644 index 96c952d3dfe3..000000000000 --- a/framework/source/uiconfiguration/image.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- 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 . - */ - -#ifndef FRAMEWORK_SOURCE_UICONFIGURATION_IMAGE_H -#define FRAMEWORK_SOURCE_UICONFIGURATION_IMAGE_H - -#include <vcl/bitmapex.hxx> - -#include <unordered_map> -#include <vector> - -struct ImageAryData -{ - OUString maName; - // Images identified by either name, or by id - sal_uInt16 mnId; - BitmapEx maBitmapEx; - - ImageAryData( const OUString &aName, - sal_uInt16 nId, const BitmapEx &aBitmap ); - ImageAryData( const ImageAryData& rData ); - ~ImageAryData(); - - bool IsLoadable() { return maBitmapEx.IsEmpty() && !maName.isEmpty(); } - void Load(const OUString &rPrefix); - - ImageAryData& operator=( const ImageAryData& rData ); -}; - -struct ImplImageList -{ - typedef std::unordered_map< OUString, ImageAryData * > - ImageAryDataNameHash; - - std::vector< std::unique_ptr<ImageAryData> > maImages; - ImageAryDataNameHash maNameHash; - OUString maPrefix; - Size maImageSize; - - ImplImageList(); - ImplImageList( const ImplImageList &aSrc ); - ~ImplImageList(); - - void AddImage( const OUString &aName, - sal_uInt16 nId, const BitmapEx &aBitmapEx ); - void RemoveImage( sal_uInt16 nPos ); -}; - -#endif // INCLUDED_VCL_INC_IMAGE_H - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 06c7b477cabae385f2f9c2eb50b69dc750504366 Author: Michael Meeks <michael.me...@collabora.com> AuthorDate: Mon Nov 26 19:50:38 2018 +0000 Commit: Michael Meeks <michael.me...@collabora.com> CommitDate: Tue Sep 24 13:58:52 2019 +0100 Propagate stock info through slide layouts. (cherry picked from commit f107161bbd0eb4ee5766f5f983d18b32b929b15c) Change-Id: If717db82fe6ab14bbf32225c1f1c95f44954f011 diff --git a/sd/source/ui/controller/slidelayoutcontroller.cxx b/sd/source/ui/controller/slidelayoutcontroller.cxx index 6f4ba93c1e92..6d4396be865b 100644 --- a/sd/source/ui/controller/slidelayoutcontroller.cxx +++ b/sd/source/ui/controller/slidelayoutcontroller.cxx @@ -134,7 +134,7 @@ static void fillLayoutValueSet( ValueSet* pValue, const snewfoil_value_info_layo OUString aText(SdResId(pInfo->mpStrResId)); Image aImg("private:graphicrepository/" + OUString::createFromAscii(pInfo->msBmpResId)); pValue->InsertItem(static_cast<sal_uInt16>(pInfo->maAutoLayout)+1, aImg, aText); - aLayoutItemSize.setWidth( std::max( aLayoutItemSize.Width(), aImg.GetSizePixel().Width() ) ); + aLayoutItemSize.setWidth( std::max( aLayoutItemSize.Width(), aImg.GetSizePixel().Width() ) ); aLayoutItemSize.setHeight( std::max( aLayoutItemSize.Height(), aImg.GetSizePixel().Height() ) ); } diff --git a/sd/source/ui/sidebar/LayoutMenu.cxx b/sd/source/ui/sidebar/LayoutMenu.cxx index e0da346e9d6a..c336dcd1cfaa 100644 --- a/sd/source/ui/sidebar/LayoutMenu.cxx +++ b/sd/source/ui/sidebar/LayoutMenu.cxx @@ -529,12 +529,16 @@ void LayoutMenu::Fill() { if ((WritingMode_TB_RL != pInfo->meWritingMode) || bVertical) { - BitmapEx aBmp(OUString::createFromAscii(pInfo->msBmpResId)); + Image aImg("private:graphicrepository/" + OUString::createFromAscii(pInfo->msBmpResId)); if (bRightToLeft && (WritingMode_TB_RL != pInfo->meWritingMode)) - aBmp.Mirror (BmpMirrorFlags::Horizontal); + { // FIXME: avoid interpolating RTL layouts. + BitmapEx aRTL = aImg.GetBitmapEx(); + aRTL.Mirror(BmpMirrorFlags::Horizontal); + aImg = Image(aRTL); + } - InsertItem(i, Image(aBmp), SdResId(pInfo->mpStrResId)); + InsertItem(i, aImg, SdResId(pInfo->mpStrResId)); SetItemData (i, new AutoLayout(pInfo->maAutoLayout)); } } commit 117676cd8bac08c40cb6511fffdc944bec6f90f8 Author: Michael Meeks <michael.me...@collabora.com> AuthorDate: Mon Nov 26 14:00:08 2018 +0000 Commit: Michael Meeks <michael.me...@collabora.com> CommitDate: Tue Sep 24 13:58:52 2019 +0100 Use HiDPI scaling to load scaled images. We render these at apparently the same pixel size as normal images, but the underlying canvas is larger so these then end up pixel-matching the true underlying grid. Change-Id: Ic4b749127e9c81da78d06b34d9f88c5635dc64b9 Reviewed-on: https://gerrit.libreoffice.org/64044 Tested-by: Jenkins Reviewed-by: Michael Meeks <michael.me...@collabora.com> diff --git a/vcl/inc/image.h b/vcl/inc/image.h index f966a8c62c1f..c9fb5393191a 100644 --- a/vcl/inc/image.h +++ b/vcl/inc/image.h @@ -44,9 +44,13 @@ struct ImplImage /// get size in co-ordinates not scaled for HiDPI Size getSizePixel(); + /// Legacy - the original bitmap BitmapEx getBitmapEx(bool bDisabled = false); + /// Taking account of HiDPI scaling + BitmapEx getBitmapExForHiDPI(bool bDisabled = false); bool isEqual(const ImplImage &ref) const; bool isSizeEmpty() const { return maSizePixel == Size(0, 0); } + bool loadStockAtScale(double fScale, BitmapEx &rBitmapEx); }; #endif // INCLUDED_VCL_INC_IMAGE_H diff --git a/vcl/source/image/Image.cxx b/vcl/source/image/Image.cxx index 8bce4839a1ea..ecb514c5bbac 100644 --- a/vcl/source/image/Image.cxx +++ b/vcl/source/image/Image.cxx @@ -111,13 +111,9 @@ void Image::Draw(OutputDevice* pOutDev, const Point& rPos, DrawImageFlags nStyle if (!mpImplData || (!pOutDev->IsDeviceOutputNecessary() && pOutDev->GetConnectMetaFile() == nullptr)) return; - const Point aSrcPos(0, 0); - Size aBitmapSizePixel = mpImplData->getSizePixel(); + Size aOutSize = pSize ? *pSize : pOutDev->PixelToLogic(mpImplData->getSizePixel()); - Size aOutSize = pSize ? *pSize : pOutDev->PixelToLogic(aBitmapSizePixel); - - // FIXME: do the HiDPI scaling fun here [!] =) - BitmapEx aRenderBmp = mpImplData->getBitmapEx(!!(nStyle & DrawImageFlags::Disable)); + BitmapEx aRenderBmp = mpImplData->getBitmapExForHiDPI(!!(nStyle & DrawImageFlags::Disable)); if (!(nStyle & DrawImageFlags::Disable) && (nStyle & (DrawImageFlags::ColorTransform | DrawImageFlags::Highlight | @@ -154,7 +150,7 @@ void Image::Draw(OutputDevice* pOutDev, const Point& rPos, DrawImageFlags nStyle aRenderBmp = aTempBitmapEx; } - pOutDev->DrawBitmapEx(rPos, aOutSize, aSrcPos, aBitmapSizePixel, aRenderBmp); + pOutDev->DrawBitmapEx(rPos, aOutSize, aRenderBmp); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/image/ImplImage.cxx b/vcl/source/image/ImplImage.cxx index 471dcb091e3d..95d605e47173 100644 --- a/vcl/source/image/ImplImage.cxx +++ b/vcl/source/image/ImplImage.cxx @@ -18,6 +18,7 @@ */ #include <sal/log.hxx> +#include <vcl/svapp.hxx> #include <vcl/outdev.hxx> #include <vcl/bitmapex.hxx> #include <vcl/alpha.hxx> @@ -49,6 +50,21 @@ ImplImage::ImplImage(const OUString &aStockName) { } +bool ImplImage::loadStockAtScale(double fScale, BitmapEx &rBitmapEx) +{ + BitmapEx aBitmapEx; + OUString aIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme(); + if (!ImageTree::get().loadImage(maStockName, aIconTheme, aBitmapEx, true, + fScale * 100.0, + ImageLoadFlags::IgnoreScalingFactor)) + { + SAL_WARN("vcl", "Failed to load scaled image from " << maStockName << " at " << fScale); + return false; + } + rBitmapEx = aBitmapEx; + return true; +} + Size ImplImage::getSizePixel() { Size aRet; @@ -56,13 +72,11 @@ Size ImplImage::getSizePixel() aRet = maSizePixel; else if (isStock()) { - BitmapEx aBitmapEx; - if (vcl::ImageRepository::loadImage(maStockName, aBitmapEx)) + if (loadStockAtScale(1.0, maBitmapEx)) { assert(!maDisabledBitmapEx); assert(maBitmapChecksum == 0); - maBitmapEx = aBitmapEx; - maSizePixel = aBitmapEx.GetSizePixel(); + maSizePixel = maBitmapEx.GetSizePixel(); aRet = maSizePixel; } else @@ -102,4 +116,18 @@ bool ImplImage::isEqual(const ImplImage &ref) const return maBitmapEx == ref.maBitmapEx; } +BitmapEx ImplImage::getBitmapExForHiDPI(bool bDisabled) +{ + if (isStock()) + { // check we have the right bitmap cached. + // FIXME: DPI scaling should be tied to the outdev really ... + double fScale = comphelper::LibreOfficeKit::getDPIScale(); + Size aTarget(maSizePixel.Width()*fScale, + maSizePixel.Height()*fScale); + if (maBitmapEx.GetSizePixel() != aTarget) + loadStockAtScale(fScale, maBitmapEx); + } + return getBitmapEx(bDisabled); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 635f94b4368ffe68d61a85f46b95a9f3e2982bd8 Author: Michael Meeks <michael.me...@collabora.com> AuthorDate: Mon Nov 26 13:24:03 2018 +0000 Commit: Michael Meeks <michael.me...@collabora.com> CommitDate: Tue Sep 24 13:58:52 2019 +0100 Add explicit API scaling via ImageTree API. Also add image scale to in-memory cache lookup. Change-Id: I1e84b922d4a9ab2f1723c5cb8a72f295c6940504 Reviewed-on: https://gerrit.libreoffice.org/64043 Tested-by: Jenkins Reviewed-by: Michael Meeks <michael.me...@collabora.com> diff --git a/include/vcl/ImageTree.hxx b/include/vcl/ImageTree.hxx index 6598c34c09e9..4b49a31f30b9 100644 --- a/include/vcl/ImageTree.hxx +++ b/include/vcl/ImageTree.hxx @@ -64,6 +64,12 @@ public: BitmapEx & bitmap, bool localized, const ImageLoadFlags eFlags = ImageLoadFlags::NONE); + VCL_DLLPUBLIC bool loadImage( + OUString const & name, OUString const & style, + BitmapEx & bitmap, bool localized, + sal_Int32 nScalePercentage, + const ImageLoadFlags eFlags = ImageLoadFlags::NONE); + VCL_DLLPUBLIC css::uno::Reference<css::container::XNameAccess> const & getNameAccess(); diff --git a/vcl/inc/implimagetree.hxx b/vcl/inc/implimagetree.hxx index 3768b04388b3..1e81aba8fac8 100644 --- a/vcl/inc/implimagetree.hxx +++ b/vcl/inc/implimagetree.hxx @@ -46,14 +46,17 @@ struct ImageRequestParameters bool mbLocalized; ImageLoadFlags const meFlags; bool mbWriteImageToCache; + sal_Int32 mnScalePercentage; - ImageRequestParameters(const OUString & rName, const OUString & rStyle, BitmapEx& rBitmap, bool bLocalized, ImageLoadFlags eFlags) + ImageRequestParameters(const OUString & rName, const OUString & rStyle, BitmapEx& rBitmap, bool bLocalized, + ImageLoadFlags eFlags, sal_Int32 nScalePercentage) : msName(rName) , msStyle(rStyle) , mrBitmap(rBitmap) , mbLocalized(bLocalized) , meFlags(eFlags) , mbWriteImageToCache(false) + , mnScalePercentage(nScalePercentage) {} bool convertToDarkTheme(); @@ -75,7 +78,8 @@ public: bool loadImage( OUString const & name, OUString const & style, BitmapEx & bitmap, bool localized, - const ImageLoadFlags eFlags); + const ImageLoadFlags eFlags, + sal_Int32 nScalePercentage = -1); /** a crude form of life cycle control (called from DeInitVCL; otherwise, * if the ImplImageTree singleton were destroyed during exit that would @@ -88,14 +92,15 @@ private: ImplImageTree(const ImplImageTree&) = delete; ImplImageTree& operator=(const ImplImageTree&) = delete; - typedef std::unordered_map<OUString, std::pair<bool, BitmapEx>> IconCache; + typedef std::unordered_map<OUString, std::pair<bool,BitmapEx>> IconCache; + typedef std::unordered_map<sal_Int32, std::unique_ptr<IconCache>> ScaledIconCache; typedef std::unordered_map<OUString, OUString> IconLinkHash; struct IconSet { OUString maURL; css::uno::Reference<css::container::XNameAccess> maNameAccess; - IconCache maIconCache; + ScaledIconCache maScaledIconCaches; IconLinkHash maLinkHash; IconSet() @@ -128,6 +133,8 @@ private: void createStyle(); + IconCache &getIconCache(ImageRequestParameters& rParameters); + bool iconCacheLookup(ImageRequestParameters& rParameters); bool findImage(std::vector<OUString> const & rPaths, ImageRequestParameters& rParameters); diff --git a/vcl/source/image/ImageTree.cxx b/vcl/source/image/ImageTree.cxx index 2e20183b0da5..826671e110ec 100644 --- a/vcl/source/image/ImageTree.cxx +++ b/vcl/source/image/ImageTree.cxx @@ -37,9 +37,17 @@ std::shared_ptr<SvMemoryStream> ImageTree::getImageStream(OUString const & rName bool ImageTree::loadImage(OUString const & rName, OUString const & rStyle, BitmapEx & rBitmap, bool bLocalized, + sal_Int32 nScalePercentage, const ImageLoadFlags eFlags) { - return mpImplImageTree->loadImage(rName, rStyle, rBitmap, bLocalized, eFlags); + return mpImplImageTree->loadImage(rName, rStyle, rBitmap, bLocalized, eFlags, nScalePercentage); +} + +bool ImageTree::loadImage(OUString const & rName, OUString const & rStyle, + BitmapEx & rBitmap, bool bLocalized, + const ImageLoadFlags eFlags) +{ + return loadImage(rName, rStyle, rBitmap, bLocalized, -1, eFlags); } css::uno::Reference<css::container::XNameAccess> const & ImageTree::getNameAccess() diff --git a/vcl/source/image/ImplImageTree.cxx b/vcl/source/image/ImplImageTree.cxx index 1fed00908365..22fd194b3a8d 100644 --- a/vcl/source/image/ImplImageTree.cxx +++ b/vcl/source/image/ImplImageTree.cxx @@ -69,6 +69,8 @@ sal_Int32 ImageRequestParameters::scalePercentage() sal_Int32 aScalePercentage = 100; if (!(meFlags & ImageLoadFlags::IgnoreScalingFactor)) aScalePercentage = Application::GetDefaultDevice()->GetDPIScalePercentage(); + else if (mnScalePercentage > 0) + aScalePercentage = mnScalePercentage; return aScalePercentage; } @@ -96,17 +98,17 @@ OUString createPath(OUString const & name, sal_Int32 pos, OUString const & local return name.copy(0, pos + 1) + locale + name.copy(pos); } -OUString getIconCacheUrl(OUString const & sStyle, OUString const & sVariant, OUString const & sName) +OUString getIconCacheUrl(OUString const & sVariant, ImageRequestParameters const & rParameters) { OUString sUrl("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/"); - sUrl += sStyle + "/" + sVariant + "/" + sName; + sUrl += rParameters.msStyle + "/" + sVariant + "/" + rParameters.msName; rtl::Bootstrap::expandMacros(sUrl); return sUrl; } -OUString createIconCacheUrl(OUString const & sStyle, OUString const & sVariant, OUString const & sName) +OUString createIconCacheUrl(OUString const & sVariant, ImageRequestParameters const & rParameters) { - OUString sUrl(getIconCacheUrl(sStyle, sVariant, sName)); + OUString sUrl(getIconCacheUrl(sVariant, rParameters)); OUString sDir = sUrl.copy(0, sUrl.lastIndexOf('/')); osl::Directory::createPath(sDir); return sUrl; @@ -315,14 +317,15 @@ OUString ImplImageTree::fallbackStyle(const OUString& rsStyle) return sResult; } -bool ImplImageTree::loadImage(OUString const & rName, OUString const & rStyle, BitmapEx & rBitmap, bool localized, const ImageLoadFlags eFlags) +bool ImplImageTree::loadImage(OUString const & rName, OUString const & rStyle, BitmapEx & rBitmap, bool localized, + const ImageLoadFlags eFlags, sal_Int32 nScalePercentage) { OUString aCurrentStyle(rStyle); while (!aCurrentStyle.isEmpty()) { try { - ImageRequestParameters aParameters(rName, aCurrentStyle, rBitmap, localized, eFlags); + ImageRequestParameters aParameters(rName, aCurrentStyle, rBitmap, localized, eFlags, nScalePercentage); if (doLoadImage(aParameters)) return true; } @@ -349,7 +352,7 @@ static OUString createVariant(ImageRequestParameters& rParameters) static bool loadDiskCachedVersion(OUString const & sVariant, ImageRequestParameters& rParameters) { - OUString sUrl(getIconCacheUrl(rParameters.msStyle, sVariant, rParameters.msName)); + OUString sUrl(getIconCacheUrl(sVariant, rParameters)); if (!urlExists(sUrl)) return false; SvFileStream aFileStream(sUrl, StreamMode::READ); @@ -361,7 +364,7 @@ static bool loadDiskCachedVersion(OUString const & sVariant, ImageRequestParamet static void cacheBitmapToDisk(OUString const & sVariant, ImageRequestParameters const & rParameters) { - OUString sUrl(createIconCacheUrl(rParameters.msStyle, sVariant, rParameters.msName)); + OUString sUrl(createIconCacheUrl(sVariant, rParameters)); vcl::PNGWriter aWriter(rParameters.mrBitmap); try { @@ -382,9 +385,7 @@ bool ImplImageTree::doLoadImage(ImageRequestParameters& rParameters) OUString aVariant = createVariant(rParameters); if (loadDiskCachedVersion(aVariant, rParameters)) - { return true; - } if (!rParameters.mrBitmap.IsEmpty()) rParameters.mrBitmap.SetEmpty(); @@ -414,7 +415,7 @@ bool ImplImageTree::doLoadImage(ImageRequestParameters& rParameters) { cacheBitmapToDisk(aVariant, rParameters); } - getCurrentIconSet().maIconCache[rParameters.msName] = std::make_pair(rParameters.mbLocalized, rParameters.mrBitmap); + getIconCache(rParameters)[rParameters.msName] = std::make_pair(rParameters.mbLocalized, rParameters.mrBitmap); } return bFound; @@ -482,9 +483,20 @@ void ImplImageTree::createStyle() loadImageLinks(); } +/// Find an icon cache for the right scale factor +ImplImageTree::IconCache &ImplImageTree::getIconCache(ImageRequestParameters& rParameters) +{ + IconSet &rSet = getCurrentIconSet(); + auto it = rSet.maScaledIconCaches.find(rParameters.mnScalePercentage); + if ( it != rSet.maScaledIconCaches.end() ) + return *it->second.get(); + rSet.maScaledIconCaches[rParameters.mnScalePercentage] = std::unique_ptr<IconCache>(new IconCache); + return *rSet.maScaledIconCaches[rParameters.mnScalePercentage].get(); +} + bool ImplImageTree::iconCacheLookup(ImageRequestParameters& rParameters) { - IconCache& rIconCache = getCurrentIconSet().maIconCache; + IconCache& rIconCache = getIconCache(rParameters); IconCache::iterator i(rIconCache.find(getRealImageName(rParameters.msName))); if (i != rIconCache.end() && i->second.first == rParameters.mbLocalized) @@ -513,6 +525,7 @@ bool ImplImageTree::findImage(std::vector<OUString> const & rPaths, ImageRequest (void)ok; // prevent unused warning in release build loadImageFromStream(wrapStream(aStream), rPath, rParameters); + return true; } } commit 5261c30266cf920f1ba0bd75874e498f3aca004d Author: Michael Meeks <michael.me...@collabora.com> AuthorDate: Mon Nov 26 11:06:20 2018 +0000 Commit: Michael Meeks <michael.me...@collabora.com> CommitDate: Tue Sep 24 13:58:52 2019 +0100 Preserve stock images until render time. This allows us to choose to render HiDPI images at the right time, when we have the DPI of the device to render to. The first step in a better, and more industry standard way of improving our UI for HiDPI via rendering level scaling that should retain a consistent look across the app with many fewer changes. Change-Id: I36681f3242cb650de4f0b2d0fcdffbe5618e30fc Reviewed-on: https://gerrit.libreoffice.org/64040 Tested-by: Jenkins Reviewed-by: Michael Meeks <michael.me...@collabora.com> diff --git a/sd/source/ui/controller/slidelayoutcontroller.cxx b/sd/source/ui/controller/slidelayoutcontroller.cxx index 611920043515..6f4ba93c1e92 100644 --- a/sd/source/ui/controller/slidelayoutcontroller.cxx +++ b/sd/source/ui/controller/slidelayoutcontroller.cxx @@ -132,13 +132,10 @@ static void fillLayoutValueSet( ValueSet* pValue, const snewfoil_value_info_layo for( ; pInfo->mpStrResId; pInfo++ ) { OUString aText(SdResId(pInfo->mpStrResId)); - BitmapEx aBmp(OUString::createFromAscii(pInfo->msBmpResId)); - - pValue->InsertItem(static_cast<sal_uInt16>(pInfo->maAutoLayout)+1, - Image(aBmp), aText); - - aLayoutItemSize.setWidth( std::max( aLayoutItemSize.Width(), aBmp.GetSizePixel().Width() ) ); - aLayoutItemSize.setHeight( std::max( aLayoutItemSize.Height(), aBmp.GetSizePixel().Height() ) ); + Image aImg("private:graphicrepository/" + OUString::createFromAscii(pInfo->msBmpResId)); + pValue->InsertItem(static_cast<sal_uInt16>(pInfo->maAutoLayout)+1, aImg, aText); + aLayoutItemSize.setWidth( std::max( aLayoutItemSize.Width(), aImg.GetSizePixel().Width() ) ); + aLayoutItemSize.setHeight( std::max( aLayoutItemSize.Height(), aImg.GetSizePixel().Height() ) ); } aLayoutItemSize = pValue->CalcItemSizePixel( aLayoutItemSize ); diff --git a/vcl/inc/image.h b/vcl/inc/image.h index 1cb0c43cdd72..f966a8c62c1f 100644 --- a/vcl/inc/image.h +++ b/vcl/inc/image.h @@ -28,10 +28,25 @@ struct ImplImage { BitmapChecksum maBitmapChecksum; - BitmapEx const maBitmapEx; + /// if non-empty: cached original size of maStockName else Size of maBitmap + Size maSizePixel; + /// If set - defines the bitmap via images.zip* + OUString maStockName; + + /// Original bitmap - or cache of a potentially scaled bitmap + BitmapEx maBitmapEx; BitmapEx maDisabledBitmapEx; ImplImage(const BitmapEx& rBitmapEx); + ImplImage(const OUString &aStockName); + + bool isStock() const { return maStockName.getLength() > 0; } + + /// get size in co-ordinates not scaled for HiDPI + Size getSizePixel(); + BitmapEx getBitmapEx(bool bDisabled = false); + bool isEqual(const ImplImage &ref) const; + bool isSizeEmpty() const { return maSizePixel == Size(0, 0); } }; #endif // INCLUDED_VCL_INC_IMAGE_H diff --git a/vcl/source/control/fixed.cxx b/vcl/source/control/fixed.cxx index 435c0b6a6a67..f1cb825ad6b2 100644 --- a/vcl/source/control/fixed.cxx +++ b/vcl/source/control/fixed.cxx @@ -965,8 +965,7 @@ void FixedImage::SetModeImage( const Image& rImage ) Image FixedImage::loadThemeImage(const OUString &rFileName) { - BitmapEx aBitmap(rFileName); - return Image(aBitmap); + return Image("private:graphicrepository/" + rFileName); } bool FixedImage::set_property(const OString &rKey, const OUString &rValue) diff --git a/vcl/source/image/Image.cxx b/vcl/source/image/Image.cxx index 049e3bef5d0d..8bce4839a1ea 100644 --- a/vcl/source/image/Image.cxx +++ b/vcl/source/image/Image.cxx @@ -58,17 +58,11 @@ Image::Image(const OUString & rFileUrl) sal_Int32 nIndex = 0; if (rFileUrl.getToken( 0, '/', nIndex ) == "private:graphicrepository") { - OUString sPathName(rFileUrl.copy(nIndex)); - BitmapEx aBitmapEx; - if (vcl::ImageRepository::loadImage(sPathName, aBitmapEx)) - { - ImplInit(aBitmapEx); - } + mpImplData.reset(new ImplImage(rFileUrl.copy(nIndex))); } else { Graphic aGraphic; - if (ERRCODE_NONE == GraphicFilter::LoadGraphic(rFileUrl, IMP_PNG, aGraphic)) { ImplInit(aGraphic.GetBitmapEx()); @@ -79,33 +73,23 @@ Image::Image(const OUString & rFileUrl) void Image::ImplInit(const BitmapEx& rBitmapEx) { if (!rBitmapEx.IsEmpty()) - { mpImplData.reset(new ImplImage(rBitmapEx)); - } } Size Image::GetSizePixel() const { - Size aRet; - if (mpImplData) - { - aRet = mpImplData->maBitmapEx.GetSizePixel(); - } - - return aRet; + return mpImplData->getSizePixel(); + else + return Size(); } BitmapEx Image::GetBitmapEx() const { - BitmapEx aRet; - if (mpImplData) - { - aRet = mpImplData->maBitmapEx; - } - - return aRet; + return mpImplData->getBitmapEx(); + else + return BitmapEx(); } bool Image::operator==(const Image& rImage) const @@ -117,7 +101,7 @@ bool Image::operator==(const Image& rImage) const else if (!rImage.mpImplData || !mpImplData) bRet = false; else - bRet = rImage.mpImplData->maBitmapEx == mpImplData->maBitmapEx; + bRet = rImage.mpImplData->isEqual(*mpImplData); return bRet; } @@ -128,63 +112,49 @@ void Image::Draw(OutputDevice* pOutDev, const Point& rPos, DrawImageFlags nStyle return; const Point aSrcPos(0, 0); - Size aBitmapSizePixel = mpImplData->maBitmapEx.GetSizePixel(); + Size aBitmapSizePixel = mpImplData->getSizePixel(); Size aOutSize = pSize ? *pSize : pOutDev->PixelToLogic(aBitmapSizePixel); - if (nStyle & DrawImageFlags::Disable) - { - BitmapChecksum aChecksum = mpImplData->maBitmapEx.GetChecksum(); - if (mpImplData->maBitmapChecksum != aChecksum) - { - BitmapEx aDisabledBmpEx(mpImplData->maBitmapEx); - BitmapFilter::Filter(aDisabledBmpEx, BitmapDisabledImageFilter()); + // FIXME: do the HiDPI scaling fun here [!] =) + BitmapEx aRenderBmp = mpImplData->getBitmapEx(!!(nStyle & DrawImageFlags::Disable)); - mpImplData->maBitmapChecksum = aChecksum; - mpImplData->maDisabledBitmapEx = aDisabledBmpEx; - } - pOutDev->DrawBitmapEx(rPos, aOutSize, aSrcPos, aBitmapSizePixel, mpImplData->maDisabledBitmapEx); - } - else + if (!(nStyle & DrawImageFlags::Disable) && + (nStyle & (DrawImageFlags::ColorTransform | DrawImageFlags::Highlight | + DrawImageFlags::Deactive | DrawImageFlags::SemiTransparent))) { - if (nStyle & (DrawImageFlags::ColorTransform | DrawImageFlags::Highlight | - DrawImageFlags::Deactive | DrawImageFlags::SemiTransparent)) + BitmapEx aTempBitmapEx(aRenderBmp); + + if (nStyle & (DrawImageFlags::Highlight | DrawImageFlags::Deactive)) { - BitmapEx aTempBitmapEx(mpImplData->maBitmapEx); + const StyleSettings& rSettings = pOutDev->GetSettings().GetStyleSettings(); + Color aColor; + if (nStyle & DrawImageFlags::Highlight) + aColor = rSettings.GetHighlightColor(); + else + aColor = rSettings.GetDeactiveColor(); + + BitmapFilter::Filter(aTempBitmapEx, BitmapColorizeFilter(aColor)); + } - if (nStyle & (DrawImageFlags::Highlight | DrawImageFlags::Deactive)) + if (nStyle & DrawImageFlags::SemiTransparent) + { + if (aTempBitmapEx.IsTransparent()) { - const StyleSettings& rSettings = pOutDev->GetSettings().GetStyleSettings(); - Color aColor; - if (nStyle & DrawImageFlags::Highlight) - aColor = rSettings.GetHighlightColor(); - else - aColor = rSettings.GetDeactiveColor(); - - BitmapFilter::Filter(aTempBitmapEx, BitmapColorizeFilter(aColor)); + Bitmap aAlphaBmp(aTempBitmapEx.GetAlpha().GetBitmap()); + aAlphaBmp.Adjust(50); + aTempBitmapEx = BitmapEx(aTempBitmapEx.GetBitmap(), AlphaMask(aAlphaBmp)); } - - if (nStyle & DrawImageFlags::SemiTransparent) + else { - if (aTempBitmapEx.IsTransparent()) - { - Bitmap aAlphaBmp(aTempBitmapEx.GetAlpha().GetBitmap()); - aAlphaBmp.Adjust(50); - aTempBitmapEx = BitmapEx(aTempBitmapEx.GetBitmap(), AlphaMask(aAlphaBmp)); - } - else - { - sal_uInt8 cErase = 128; - aTempBitmapEx = BitmapEx(aTempBitmapEx.GetBitmap(), AlphaMask(aTempBitmapEx.GetSizePixel(), &cErase)); - } + sal_uInt8 cErase = 128; + aTempBitmapEx = BitmapEx(aTempBitmapEx.GetBitmap(), AlphaMask(aTempBitmapEx.GetSizePixel(), &cErase)); } - pOutDev->DrawBitmapEx(rPos, aOutSize, aSrcPos, aTempBitmapEx.GetSizePixel(), aTempBitmapEx); - } - else - { - pOutDev->DrawBitmapEx(rPos, aOutSize, aSrcPos, mpImplData->maBitmapEx.GetSizePixel(), mpImplData->maBitmapEx); } + aRenderBmp = aTempBitmapEx; } + + pOutDev->DrawBitmapEx(rPos, aOutSize, aSrcPos, aBitmapSizePixel, aRenderBmp); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/image/ImplImage.cxx b/vcl/source/image/ImplImage.cxx index 82a2099e8813..471dcb091e3d 100644 --- a/vcl/source/image/ImplImage.cxx +++ b/vcl/source/image/ImplImage.cxx @@ -17,6 +17,7 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <sal/log.hxx> #include <vcl/outdev.hxx> #include <vcl/bitmapex.hxx> #include <vcl/alpha.hxx> @@ -25,15 +26,80 @@ #include <vcl/virdev.hxx> #include <vcl/image.hxx> #include <vcl/settings.hxx> +#include <vcl/BitmapFilter.hxx> +#include <vcl/ImageTree.hxx> +#include <vcl/imagerepository.hxx> +#include <BitmapDisabledImageFilter.hxx> +#include <comphelper/lok.hxx> #include <image.h> #include <memory> ImplImage::ImplImage(const BitmapEx &rBitmapEx) : maBitmapChecksum(0) + , maSizePixel(rBitmapEx.GetSizePixel()) , maBitmapEx(rBitmapEx) - , maDisabledBitmapEx() { } +ImplImage::ImplImage(const OUString &aStockName) + : maBitmapChecksum(0) + , maSizePixel(0,0) // defer size lookup + , maStockName( aStockName ) +{ +} + +Size ImplImage::getSizePixel() +{ + Size aRet; + if (!isSizeEmpty()) + aRet = maSizePixel; + else if (isStock()) + { + BitmapEx aBitmapEx; + if (vcl::ImageRepository::loadImage(maStockName, aBitmapEx)) + { + assert(!maDisabledBitmapEx); + assert(maBitmapChecksum == 0); + maBitmapEx = aBitmapEx; + maSizePixel = aBitmapEx.GetSizePixel(); + aRet = maSizePixel; + } + else + SAL_WARN("vcl", "Failed to load stock icon " << maStockName); + } + return aRet; +} + +/// non-HiDPI compatibility method. +BitmapEx ImplImage::getBitmapEx(bool bDisabled) +{ + getSizePixel(); // force load, and at unity scale. + if (bDisabled) + { + // Changed since we last generated this. + BitmapChecksum aChecksum = maBitmapEx.GetChecksum(); + if (maBitmapChecksum != aChecksum || + maDisabledBitmapEx.GetSizePixel() != maBitmapEx.GetSizePixel()) + { + maDisabledBitmapEx = maBitmapEx; + BitmapFilter::Filter(maDisabledBitmapEx, BitmapDisabledImageFilter()); + maBitmapChecksum = aChecksum; + } + return maDisabledBitmapEx; + } + + return maBitmapEx; +} + +bool ImplImage::isEqual(const ImplImage &ref) const +{ + if (isStock() != ref.isStock()) + return false; + if (isStock()) + return maStockName == ref.maStockName; + else + return maBitmapEx == ref.maBitmapEx; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx index e2833756b87e..70a62b10463b 100644 --- a/vcl/source/window/builder.cxx +++ b/vcl/source/window/builder.cxx @@ -658,8 +658,8 @@ VclBuilder::VclBuilder(vcl::Window *pParent, const OUString& sUIDir, const OUStr SAL_WARN_IF(eType != SymbolType::IMAGE, "vcl.layout", "unimplemented symbol type for radiobuttons"); if (eType == SymbolType::IMAGE) { - BitmapEx aBitmap(mapStockToImageResource(rImageInfo.m_sStock)); - Image const aImage(aBitmap); + Image const aImage("private:graphicrepository/" + + mapStockToImageResource(rImageInfo.m_sStock)); if (!elem.m_bRadio) pTargetButton->SetModeImage(aImage); else @@ -703,8 +703,8 @@ VclBuilder::VclBuilder(vcl::Window *pParent, const OUString& sUIDir, const OUStr if (eType != SymbolType::IMAGE) continue; - BitmapEx aBitmap(mapStockToImageResource(rImageInfo.m_sStock)); - const Image aImage(aBitmap); + Image const aImage("private:graphicrepository/" + + mapStockToImageResource(rImageInfo.m_sStock)); pImage->SetImage(aImage); } diff --git a/vcl/source/window/msgbox.cxx b/vcl/source/window/msgbox.cxx index b91f3b2fb973..31307c542a9c 100644 --- a/vcl/source/window/msgbox.cxx +++ b/vcl/source/window/msgbox.cxx @@ -37,12 +37,13 @@ static void ImplInitMsgBoxImageList() { ImplSVData* pSVData = ImplGetSVData(); - if (pSVData->maWinData.maMsgBoxImgList.empty()) + std::vector<Image> &rImages = pSVData->maWinData.maMsgBoxImgList; + if (rImages.empty()) { - pSVData->maWinData.maMsgBoxImgList.emplace_back(BitmapEx(SV_RESID_BITMAP_ERRORBOX)); - pSVData->maWinData.maMsgBoxImgList.emplace_back(BitmapEx(SV_RESID_BITMAP_QUERYBOX)); - pSVData->maWinData.maMsgBoxImgList.emplace_back(BitmapEx(SV_RESID_BITMAP_WARNINGBOX)); - pSVData->maWinData.maMsgBoxImgList.emplace_back(BitmapEx(SV_RESID_BITMAP_INFOBOX)); + rImages.emplace_back(Image("private:graphicrepository/" SV_RESID_BITMAP_ERRORBOX)); + rImages.emplace_back(Image("private:graphicrepository/" SV_RESID_BITMAP_QUERYBOX)); + rImages.emplace_back(Image("private:graphicrepository/" SV_RESID_BITMAP_WARNINGBOX)); + rImages.emplace_back(Image("private:graphicrepository/" SV_RESID_BITMAP_INFOBOX)); } } commit 825fe58f3ab3dcb1d216b9d49e502b6bb7b91771 Author: Michael Meeks <michael.me...@collabora.com> AuthorDate: Fri Apr 26 20:04:00 2019 +0100 Commit: Michael Meeks <michael.me...@collabora.com> CommitDate: Tue Sep 24 13:58:52 2019 +0100 lok: disable VCL painting and whole window invalidation. The reasoning is somewhat complex: void Window::ImplInvalidateFrameRegion( const vcl::Region* pRegion, InvalidateFlags nFlags ) sets the mnPaintFlags on the mpWindowImpl - and then queues an idle paint. This paint in LOK mode does ~nothing - since all rendering is tiled, although amazingly it does emit eg. selection callbacks. However the paint flag - changes the behavior of Window::Update() to force a complete window invalidate. This happens, but only rarely - when a key-event manages to get into the mainloop before the idle paint handler arrives and does nothing (except clear the paint flags). So - don't do these big invalidations we don't need to in lok mode, unless it is for dialogs - which presumably Pranav wanted fixed by 625087b58f3b7. Change-Id: I88dda34b8d8bba9c89296d883ad9169fe49a7c5e Reviewed-on: https://gerrit.libreoffice.org/71396 Reviewed-by: Michael Meeks <michael.me...@collabora.com> Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> Tested-by: Jan Holesovsky <ke...@collabora.com> diff --git a/vcl/source/window/paint.cxx b/vcl/source/window/paint.cxx index 8d3f88e9dfce..a94689cc42ad 100644 --- a/vcl/source/window/paint.cxx +++ b/vcl/source/window/paint.cxx @@ -33,6 +33,7 @@ #include <salframe.hxx> #include <svdata.hxx> #include <comphelper/lok.hxx> +#include <comphelper/profilezone.hxx> #if HAVE_FEATURE_OPENGL #include <vcl/opengl/OpenGLHelper.hxx> #endif @@ -634,6 +635,8 @@ void Window::ImplCallOverlapPaint() IMPL_LINK_NOARG(Window, ImplHandlePaintHdl, Timer *, void) { + comphelper::ProfileZone aZone("VCL idle re-paint"); + // save paint events until layout is done if (IsSystemWindow() && static_cast<const SystemWindow*>(this)->hasPendingLayout()) { @@ -655,6 +658,8 @@ IMPL_LINK_NOARG(Window, ImplHandlePaintHdl, Timer *, void) IMPL_LINK_NOARG(Window, ImplHandleResizeTimerHdl, Timer *, void) { + comphelper::ProfileZone aZone("VCL idle resize"); + if( mpWindowImpl->mbReallyVisible ) { ImplCallResize(); @@ -722,6 +727,7 @@ void Window::ImplInvalidateFrameRegion( const vcl::Region* pRegion, InvalidateFl pParent->ImplInvalidateFrameRegion( pChildRegion, nFlags ); } } + if ( !mpWindowImpl->mpFrameData->maPaintIdle.IsActive() ) mpWindowImpl->mpFrameData->maPaintIdle.Start(); } @@ -1324,10 +1330,13 @@ void Window::Update() } pUpdateWindow->ImplCallPaint(nullptr, pUpdateWindow->mpWindowImpl->mnPaintFlags); - pUpdateWindow->LogicInvalidate(nullptr); + + if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow->GetParentDialog()) + pUpdateWindow->LogicInvalidate(nullptr); if (xWindow->IsDisposed()) return; + bFlush = true; } commit 25793b8c889f78244388f5b46069a9bc1b2f0fde Author: Jan Holesovsky <ke...@collabora.com> AuthorDate: Thu May 2 11:14:40 2019 +0200 Commit: Michael Meeks <michael.me...@collabora.com> CommitDate: Tue Sep 24 13:58:52 2019 +0100 lok: We changed the (unstable) ABI, but let's allow the older C++ API. Helps building the Online before the appropriate patch gets merged. Change-Id: I9983d546bb0cb7fb472806622a0a10e3a4d3ab87 Reviewed-on: https://gerrit.libreoffice.org/71664 Reviewed-by: Michael Meeks <michael.me...@collabora.com> Tested-by: Michael Meeks <michael.me...@collabora.com> diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx b/include/LibreOfficeKit/LibreOfficeKit.hxx index e2ca0902edd7..dd0ad0391643 100644 --- a/include/LibreOfficeKit/LibreOfficeKit.hxx +++ b/include/LibreOfficeKit/LibreOfficeKit.hxx @@ -188,7 +188,7 @@ public: * * @param nWindowid */ - void postWindow(unsigned nWindowId, int nAction, const char* pData) + void postWindow(unsigned nWindowId, int nAction, const char* pData = nullptr) { return mpDoc->pClass->postWindow(mpDoc, nWindowId, nAction, pData); } diff --git a/libreofficekit/qa/tilebench/tilebench.cxx b/libreofficekit/qa/tilebench/tilebench.cxx index d0fc87283d35..61d337f6c518 100644 --- a/libreofficekit/qa/tilebench/tilebench.cxx +++ b/libreofficekit/qa/tilebench/tilebench.cxx @@ -286,7 +286,7 @@ static void testDialog( Document *pDocument, const char *uno_cmd ) } aTimes.emplace_back("post close dialog"); - pDocument->postWindow(nDialogId, LOK_WINDOW_CLOSE, nullptr); + pDocument->postWindow(nDialogId, LOK_WINDOW_CLOSE); aTimes.emplace_back(); pDocument->destroyView(view); commit c7a75f85056610256dd4594135f6e851ab34eaf6 Author: Michael Meeks <michael.me...@collabora.com> AuthorDate: Thu May 9 18:25:22 2019 +0100 Commit: Michael Meeks <michael.me...@collabora.com> CommitDate: Tue Sep 24 13:58:52 2019 +0100 unipoll: add a --unipoll parameter to gtktiledviewer. Arguably should be the default. Implementation is a bit cute - re-starting the main-loop as a child of a callback from its idle handler. Change-Id: I95e87c8a4ae3de745d7ca1f636859dd1d8deca17 Reviewed-on: https://gerrit.libreoffice.org/72072 Tested-by: Jenkins Reviewed-by: Michael Meeks <michael.me...@collabora.com> diff --git a/libreofficekit/qa/gtktiledviewer/gtv-application-window.cxx b/libreofficekit/qa/gtktiledviewer/gtv-application-window.cxx index 1de1aa94568d..564c1de137c6 100644 --- a/libreofficekit/qa/gtktiledviewer/gtv-application-window.cxx +++ b/libreofficekit/qa/gtktiledviewer/gtv-application-window.cxx @@ -356,9 +356,18 @@ gtv_application_window_load_document(GtvApplicationWindow* window, *(priv->m_pRenderingArgs) = *aArgs; // setup lokdocview - window->lokdocview = lok_doc_view_new_from_user_profile(priv->m_pRenderingArgs->m_aLoPath.c_str(), - priv->m_pRenderingArgs->m_aUserProfile.empty() ? nullptr : priv->m_pRenderingArgs->m_aUserProfile.c_str(), - nullptr, nullptr); + const char *pUserProfile = priv->m_pRenderingArgs->m_aUserProfile.empty() ? + nullptr : priv->m_pRenderingArgs->m_aUserProfile.c_str(); + + window->lokdocview = GTK_WIDGET( + g_initable_new(LOK_TYPE_DOC_VIEW, nullptr, nullptr, + "lopath", priv->m_pRenderingArgs->m_aLoPath.c_str(), + "unipoll", priv->m_pRenderingArgs->m_bUnipoll, + "userprofileurl", pUserProfile, + "halign", GTK_ALIGN_CENTER, + "valign", GTK_ALIGN_CENTER, + nullptr)); + gtk_container_add(GTK_CONTAINER(window->scrolledwindow), window->lokdocview); setupDocView(window); diff --git a/libreofficekit/qa/gtktiledviewer/gtv-application-window.hxx b/libreofficekit/qa/gtktiledviewer/gtv-application-window.hxx index 748195c5aff0..21508097e077 100644 --- a/libreofficekit/qa/gtktiledviewer/gtv-application-window.hxx +++ b/libreofficekit/qa/gtktiledviewer/gtv-application-window.hxx @@ -24,6 +24,7 @@ struct GtvRenderingArgs std::string m_aLoPath; std::string m_aUserProfile; bool m_bEnableTiledAnnotations; + bool m_bUnipoll; std::string m_aBackgroundColor; bool m_bHidePageShadow; @@ -31,6 +32,7 @@ struct GtvRenderingArgs GtvRenderingArgs() : m_bEnableTiledAnnotations(false), + m_bUnipoll(false), m_bHidePageShadow(false), m_bHideWhiteSpace(false) { } diff --git a/libreofficekit/qa/gtktiledviewer/gtv-application.cxx b/libreofficekit/qa/gtktiledviewer/gtv-application.cxx index cd0a88a85fe2..7481076778eb 100644 --- a/libreofficekit/qa/gtktiledviewer/gtv-application.cxx +++ b/libreofficekit/qa/gtktiledviewer/gtv-application.cxx @@ -52,6 +52,7 @@ gtv_application_init(GtvApplication* app) { { "version", 0, 0, G_OPTION_ARG_NONE, nullptr, "Show LOkit version", nullptr }, { "lo-path", 0, 0, G_OPTION_ARG_STRING, nullptr, "LO path", nullptr }, + { "unipoll", 0, 0, G_OPTION_ARG_NONE, nullptr, "Enable unified polling loop", nullptr }, { "user-profile", 0, 0, G_OPTION_ARG_STRING, nullptr, "User profile to use", nullptr }, { "enable-tiled-annotations", 0, 0, G_OPTION_ARG_NONE, nullptr, "Whether tiled annotations should be enabled", nullptr }, { "background-color", 0, 0, G_OPTION_ARG_STRING, nullptr, "Background color", nullptr }, @@ -98,11 +99,13 @@ gtv_application_handle_local_options(GApplication* app, GVariantDict* options) return 1; // Cannot afford to continue in absence of this param } + if (g_variant_dict_contains(options, "unipoll")) + priv->m_pRenderingArgs->m_bUnipoll = true; + if (g_variant_dict_contains(options, "version")) { if (!priv->m_pRenderingArgs->m_aLoPath.empty()) { - // FIXME: Crashes for some reason GtkWidget* pDocView = lok_doc_view_new(priv->m_pRenderingArgs->m_aLoPath.c_str(), nullptr, nullptr); const gchar* versionInfo = lok_doc_view_get_version_info(LOK_DOC_VIEW(pDocView)); if (versionInfo) diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx index 1d7814e0b5c9..f48916298dbe 100644 --- a/libreofficekit/source/gtk/lokdocview.cxx +++ b/libreofficekit/source/gtk/lokdocview.cxx @@ -85,6 +85,7 @@ struct LOKDocViewPrivateImpl gboolean m_bInit; // initializeForRendering() has been called gboolean m_bCanZoomIn; gboolean m_bCanZoomOut; + gboolean m_bUnipoll; LibreOfficeKit* m_pOffice; LibreOfficeKitDocument* m_pDocument; @@ -198,6 +199,7 @@ struct LOKDocViewPrivateImpl m_bInit(false), m_bCanZoomIn(true), m_bCanZoomOut(true), + m_bUnipoll(false), m_pOffice(nullptr), m_pDocument(nullptr), lokThreadPool(nullptr), @@ -287,6 +289,7 @@ enum PROP_0, PROP_LO_PATH, + PROP_LO_UNIPOLL, PROP_LO_POINTER, PROP_USER_PROFILE_URL, PROP_DOC_PATH, @@ -2433,6 +2436,9 @@ static void lok_doc_view_set_property (GObject* object, guint propId, const GVal case PROP_LO_PATH: priv->m_aLOPath = g_value_get_string (value); break; + case PROP_LO_UNIPOLL: + priv->m_bUnipoll = g_value_get_boolean (value); + break; case PROP_LO_POINTER: priv->m_pOffice = static_cast<LibreOfficeKit*>(g_value_get_pointer(value)); break; @@ -2495,6 +2501,9 @@ static void lok_doc_view_get_property (GObject* object, guint propId, GValue *va case PROP_LO_PATH: g_value_set_string (value, priv->m_aLOPath.c_str()); break; + case PROP_LO_UNIPOLL: + g_value_set_boolean (value, priv->m_bUnipoll); + break; case PROP_LO_POINTER: g_value_set_pointer(value, priv->m_pOffice); break; @@ -2620,6 +2629,41 @@ static void lok_doc_view_finalize (GObject* object) G_OBJECT_CLASS (lok_doc_view_parent_class)->finalize (object); } +// kicks the mainloop awake +static gboolean timeout_wakeup(void *) +{ + return FALSE; +} + +// integrate our mainloop with LOK's +static int lok_poll_callback(void*, int timeoutUs) +{ + if (timeoutUs) + { + guint timeout = g_timeout_add(timeoutUs / 1000, timeout_wakeup, nullptr); + g_main_context_iteration(nullptr, TRUE); + g_source_remove(timeout); + } + else + g_main_context_iteration(nullptr, FALSE); + + return 0; +} + +// thread-safe wakeup of our mainloop +static void lok_wake_callback(void *) +{ + g_main_context_wakeup(nullptr); +} + +static gboolean spin_lok_loop(void *pData) +{ + LOKDocView *pDocView = LOK_DOC_VIEW (pData); + LOKDocViewPrivate& priv = getPrivate(pDocView); + priv->m_pOffice->pClass->runLoop(priv->m_pOffice, lok_poll_callback, lok_wake_callback, nullptr); + return FALSE; +} + static gboolean lok_doc_view_initable_init (GInitable *initable, GCancellable* /*cancellable*/, GError **error) { LOKDocView *pDocView = LOK_DOC_VIEW (initable); @@ -2628,6 +2672,9 @@ static gboolean lok_doc_view_initable_init (GInitable *initable, GCancellable* / if (priv->m_pOffice != nullptr) return TRUE; + if (priv->m_bUnipoll) + g_setenv("SAL_LOK_OPTIONS", "unipoll", FALSE); + priv->m_pOffice = lok_init_2(priv->m_aLOPath.c_str(), priv->m_aUserProfileURL.empty() ? nullptr : priv->m_aUserProfileURL.c_str()); if (priv->m_pOffice == nullptr) @@ -2642,6 +2689,9 @@ static gboolean lok_doc_view_initable_init (GInitable *initable, GCancellable* / priv->m_nLOKFeatures |= LOK_FEATURE_VIEWID_IN_VISCURSOR_INVALIDATION_CALLBACK; priv->m_pOffice->pClass->setOptionalFeatures(priv->m_pOffice, priv->m_nLOKFeatures); + if (priv->m_bUnipoll) + g_idle_add(spin_lok_loop, pDocView); + return TRUE; } @@ -2682,6 +2732,19 @@ static void lok_doc_view_class_init (LOKDocViewClass* pClass) G_PARAM_STATIC_STRINGS)); /** + * LOKDocView:unipoll: + * + * Whether we use our own unified polling mainloop in place of glib's + */ + properties[PROP_LO_UNIPOLL] = + g_param_spec_boolean("unipoll", + "Unified Polling", + "Whether we use a custom unified polling loop", + FALSE, + static_cast<GParamFlags>(G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** * LOKDocView:lopointer: * * A LibreOfficeKit* in case lok_init() is already called commit caf68cc79e05c2e2e9ff6a535da5562b45596ad1 Author: Michael Meeks <michael.me...@collabora.com> AuthorDate: Thu Jun 6 17:43:20 2019 +0100 Commit: Michael Meeks <michael.me...@collabora.com> CommitDate: Tue Sep 24 13:58:52 2019 +0100 lok: remove ext text event re-entrancy hazard. Change-Id: I7566c158330bab77589d422c61c64210727ab835 Reviewed-on: https://gerrit.libreoffice.org/73625 Tested-by: Jenkins Reviewed-by: Michael Meeks <michael.me...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/73756 Reviewed-by: Andras Timar <andras.ti...@collabora.com> Tested-by: Andras Timar <andras.ti...@collabora.com> diff --git a/vcl/source/window/winproc.cxx b/vcl/source/window/winproc.cxx index 3f127e0afd08..99fefdeece20 100644 --- a/vcl/source/window/winproc.cxx +++ b/vcl/source/window/winproc.cxx @@ -1137,6 +1137,12 @@ static bool ImplHandleExtTextInput( vcl::Window* pWindow, } if( !pChild->ImplGetWindowImpl()->mpFrameData->mnFocusId ) break; + + if (comphelper::LibreOfficeKit::isActive()) + { + SAL_WARN("vcl", "Failed to get ext text input context"); + break; + } Application::Yield(); } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits