Resolves: tdf#151898 get hidpi font/highlight color icons

Most of this wouldn't be necessary if we could solve the split alpha
problem. In the meantime, let Image take a MetaFile as an arg, record
what we want to do in the metafile, and play it back when we need to
generate the bitmap for to render the image. That way we don't have
alpha to worry about during the recording, and we only have one alpha in
the final rendering, as opposed to having two alphas in a source and in
destination VirtualDevice, which is problematic in most backends.

Change-Id: I5b0d7c498473271f4ab2743f75614b1b93a0e9c9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142598
Tested-by: Jenkins
Reviewed-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
diff --git a/svx/inc/tbxcolorupdate.hxx b/svx/inc/tbxcolorupdate.hxx
index 5c6c7dd..4789376 100644
--- a/svx/inc/tbxcolorupdate.hxx
+++ b/svx/inc/tbxcolorupdate.hxx
@@ -83,6 +83,8 @@ namespace svx
        virtual OUString GetQuickHelpText() const = 0;
        virtual void SetImage(VirtualDevice* pVirDev) = 0;
        virtual VclPtr<VirtualDevice> CreateVirtualDevice() const = 0;
        // true -> use Device to Record to Metafile, false -> Render to Device
        virtual bool RecordVirtualDevice() const = 0;
        virtual vcl::ImageType GetImageSize() const = 0;
        virtual Size GetItemSize(const Size& rImageSize) const = 0;
    };
@@ -103,6 +105,10 @@ namespace svx
        virtual OUString GetQuickHelpText() const override;
        virtual void SetImage(VirtualDevice* pVirDev) override;
        virtual VclPtr<VirtualDevice> CreateVirtualDevice() const override;
        virtual bool RecordVirtualDevice() const  override
        {
            return true;
        }
        virtual vcl::ImageType GetImageSize() const override;
        virtual Size GetItemSize(const Size& rImageSize) const override;
    };
@@ -121,6 +127,10 @@ namespace svx
        virtual OUString GetQuickHelpText() const override;
        virtual void SetImage(VirtualDevice* pVirDev) override;
        virtual VclPtr<VirtualDevice> CreateVirtualDevice() const override;
        virtual bool RecordVirtualDevice() const  override
        {
            return false;
        }
        virtual vcl::ImageType GetImageSize() const override;
        virtual Size GetItemSize(const Size& rImageSize) const override;
    };
diff --git a/svx/source/tbxctrls/tbxcolorupdate.cxx b/svx/source/tbxctrls/tbxcolorupdate.cxx
index f9ca173..4e6ec87f 100644
--- a/svx/source/tbxctrls/tbxcolorupdate.cxx
+++ b/svx/source/tbxctrls/tbxcolorupdate.cxx
@@ -26,6 +26,7 @@
#include <svx/xlndsit.hxx>

#include <vcl/commandinfoprovider.hxx>
#include <vcl/gdimtf.hxx>
#include <vcl/svapp.hxx>
#include <vcl/toolbox.hxx>
#include <vcl/virdev.hxx>
@@ -101,15 +102,21 @@ namespace svx

    void VclToolboxButtonColorUpdater::SetImage(VirtualDevice* pVirDev)
    {
        mpTbx->SetItemImage(mnBtnId, Image(pVirDev->GetBitmapEx(Point(0,0), maBmpSize)));
        GDIMetaFile* pMtf = pVirDev->GetConnectMetaFile();

        assert(pMtf && "should have been set in ToolboxButtonColorUpdaterBase::Update");

        pMtf->Stop();
        pMtf->WindStart();

        Graphic aGraphic(*pMtf);

        mpTbx->SetItemImage(mnBtnId, Image(aGraphic.GetXGraphic()));
    }

    VclPtr<VirtualDevice> VclToolboxButtonColorUpdater::CreateVirtualDevice() const
    {
        auto xRet = VclPtr<VirtualDevice>::Create(*mpTbx->GetOutDev(),
            DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
        xRet->SetBackground(mpTbx->GetControlBackground());
        return xRet;
        return VclPtr<VirtualDevice>::Create(*mpTbx->GetOutDev());
    }

    vcl::ImageType VclToolboxButtonColorUpdater::GetImageSize() const
@@ -171,6 +178,16 @@ namespace svx
        pVirDev->SetOutputSizePixel(aItemSize);
        maBmpSize = aItemSize;

        std::unique_ptr<GDIMetaFile> xMetaFile;
        if (RecordVirtualDevice())
        {
            xMetaFile.reset(new GDIMetaFile);
            xMetaFile->SetPrefSize(pVirDev->GetOutputSize());
            xMetaFile->SetPrefMapMode(pVirDev->GetMapMode());
            xMetaFile->Record(pVirDev.get());
            pVirDev->EnableOutput(false);
        }

        if (maBmpSize.Width() == maBmpSize.Height())
            // tdf#84985 align color bar with icon bottom edge; integer arithmetic e.g. 26 - 26/4 <> 26 * 3/4
            maUpdRect = tools::Rectangle(Point( 0, maBmpSize.Height() - maBmpSize.Height() / 4), Size(maBmpSize.Width(), maBmpSize.Height() / 4));
diff --git a/vcl/inc/image.h b/vcl/inc/image.h
index a6b51f3..c771ef7 100644
--- a/vcl/inc/image.h
+++ b/vcl/inc/image.h
@@ -21,6 +21,7 @@
#define INCLUDED_VCL_INC_IMAGE_H

#include <vcl/bitmapex.hxx>
#include <vcl/gdimtf.hxx>

class SalGraphics;

@@ -32,7 +33,8 @@ private:
    Size maSizePixel;
    /// If set - defines the bitmap via images.zip*
    OUString maStockName;

    /// rare case of dynamically created Image contents
    std::unique_ptr<GDIMetaFile> mxMetaFile;

    /// Original bitmap - or cache of a potentially scaled bitmap
    BitmapEx maBitmapEx;
@@ -43,6 +45,7 @@ private:
public:
    ImplImage(const BitmapEx& rBitmapEx);
    ImplImage(const OUString &aStockName);
    ImplImage(const GDIMetaFile& rMetaFile);

    bool isStock() const
    {
diff --git a/vcl/source/image/Image.cxx b/vcl/source/image/Image.cxx
index 2b0a952..06937ab 100644
--- a/vcl/source/image/Image.cxx
+++ b/vcl/source/image/Image.cxx
@@ -47,6 +47,8 @@ Image::Image(uno::Reference<graphic::XGraphic> const & rxGraphic)
        OUString aPath;
        if (aGraphic.getOriginURL().startsWith("private:graphicrepository/", &aPath))
            mpImplData = std::make_shared<ImplImage>(aPath);
        else if (aGraphic.GetType() == GraphicType::GdiMetafile)
            mpImplData = std::make_shared<ImplImage>(aGraphic.GetGDIMetaFile());
        else
            ImplInit(aGraphic.GetBitmapEx());
    }
diff --git a/vcl/source/image/ImplImage.cxx b/vcl/source/image/ImplImage.cxx
index 6448cb4..756b8dd 100644
--- a/vcl/source/image/ImplImage.cxx
+++ b/vcl/source/image/ImplImage.cxx
@@ -20,7 +20,9 @@
#include <sal/log.hxx>
#include <vcl/svapp.hxx>
#include <vcl/bitmapex.hxx>
#include <vcl/gdimtf.hxx>
#include <vcl/settings.hxx>
#include <vcl/virdev.hxx>
#include <vcl/BitmapFilter.hxx>
#include <vcl/ImageTree.hxx>
#include <bitmap/BitmapDisabledImageFilter.hxx>
@@ -42,6 +44,13 @@ ImplImage::ImplImage(const OUString &aStockName)
{
}

ImplImage::ImplImage(const GDIMetaFile& rMetaFile)
    : maBitmapChecksum(0)
    , maSizePixel(rMetaFile.GetPrefSize())
    , mxMetaFile(new GDIMetaFile(rMetaFile))
{
}

bool ImplImage::loadStockAtScale(SalGraphics* pGraphics, BitmapEx &rBitmapEx)
{
    BitmapEx aBitmapEx;
@@ -141,14 +150,25 @@ bool ImplImage::isEqual(const ImplImage &ref) const

BitmapEx const & ImplImage::getBitmapExForHiDPI(bool bDisabled, SalGraphics* pGraphics)
{
    if (isStock() && pGraphics)
    if ((isStock() || mxMetaFile) && pGraphics)
    {   // check we have the right bitmap cached.
        double fScale = 1.0;
        pGraphics->ShouldDownscaleIconsAtSurface(&fScale);
        Size aTarget(maSizePixel.Width()*fScale,
                     maSizePixel.Height()*fScale);
        if (maBitmapEx.GetSizePixel() != aTarget)
            loadStockAtScale(pGraphics, maBitmapEx);
        {
            if (isStock())
                loadStockAtScale(pGraphics, maBitmapEx);
            else // if (mxMetaFile)
            {
                ScopedVclPtrInstance<VirtualDevice> aVDev(DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
                aVDev->SetOutputSizePixel(aTarget);
                mxMetaFile->WindStart();
                mxMetaFile->Play(*aVDev, Point(), aTarget);
                maBitmapEx = aVDev->GetBitmapEx(Point(), aTarget);
            }
        }
    }
    return getBitmapEx(bDisabled);
}