move ToolboxButtonColorUpdater bitmap update to VirtualDevice

to avoid doing a read-modify-write cycle on the item images on the
toolbar, add an overlay image member to Toolbox items.

part of the process of making Bitmap an internal detail of vcl/

Change-Id: Ie4a886c48484a06694fc4c066ee0845b39d27f0b
Reviewed-on: https://gerrit.libreoffice.org/49649
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/include/vcl/toolbox.hxx b/include/vcl/toolbox.hxx
index eeab33c..700da27 100644
--- a/include/vcl/toolbox.hxx
+++ b/include/vcl/toolbox.hxx
@@ -373,6 +373,7 @@ public:
    void                SetItemData( sal_uInt16 nItemId, void* pNewData );
    void*               GetItemData( sal_uInt16 nItemId ) const;
    void                SetItemImage( sal_uInt16 nItemId, const Image& rImage );
    void                SetItemOverlayImage( sal_uInt16 nItemId, const Image& rImage );
    Image               GetItemImage( sal_uInt16 nItemId ) const;
    void                SetItemImageAngle( sal_uInt16 nItemId, long nAngle10 );
    void                SetItemImageMirrorMode( sal_uInt16 nItemId, bool bMirror );
diff --git a/svx/source/tbxctrls/tbxcolorupdate.cxx b/svx/source/tbxctrls/tbxcolorupdate.cxx
index 9748340..4b80480 100644
--- a/svx/source/tbxctrls/tbxcolorupdate.cxx
+++ b/svx/source/tbxctrls/tbxcolorupdate.cxx
@@ -23,7 +23,7 @@
#include <svx/xdef.hxx>

#include <vcl/toolbox.hxx>
#include <vcl/bitmapaccess.hxx>
#include <vcl/virdev.hxx>
#include <vcl/settings.hxx>
#include <tools/debug.hxx>

@@ -82,54 +82,21 @@ namespace svx

        if ((maCurColor == aColor) && !bSizeChanged && !bDisplayModeChanged && !bForceUpdate)
            return;

        // create an empty bitmap, and copy the original bitmap inside
        // (so that it grows in case the original bitmap was smaller)
        sal_uInt8 nAlpha = 255;
        BitmapEx aBmpEx(Bitmap(aItemSize, 24), AlphaMask(aItemSize, &nAlpha));

        BitmapEx aSource(aImage.GetBitmapEx());
        long nWidth = std::min(aItemSize.Width(), aSource.GetSizePixel().Width());
        long nHeight = std::min(aItemSize.Height(), aSource.GetSizePixel().Height());

        tools::Rectangle aRect(Point(0, 0), Size(nWidth, nHeight));

        aBmpEx.CopyPixel( aRect, aRect, &aSource );

        Bitmap              aBmp( aBmpEx.GetBitmap() );
        BitmapWriteAccess*  pBmpAcc = aBmp.IsEmpty() ? nullptr : aBmp.AcquireWriteAccess();

        maBmpSize = aBmp.GetSizePixel();

        if (!pBmpAcc)
        if (!aItemSize.Width() || !aItemSize.Height())
            return;

        Bitmap              aMsk;
        BitmapWriteAccess*  pMskAcc;

        if (aBmpEx.IsAlpha())
        {
            aMsk = aBmpEx.GetAlpha().GetBitmap();
            pMskAcc = aMsk.AcquireWriteAccess();
        }
        else if (aBmpEx.IsTransparent())
        {
            aMsk = aBmpEx.GetMask();
            pMskAcc = aMsk.AcquireWriteAccess();
        }
        else
        {
            pMskAcc = nullptr;
        }
        ScopedVclPtr<VirtualDevice> pVirDev(VclPtr<VirtualDevice>::Create());
        pVirDev->SetOutputSizePixel(aItemSize);
        maBmpSize = aItemSize;

        mbWasHiContrastMode = mpTbx->GetSettings().GetStyleSettings().GetHighContrastMode();

        if ((COL_TRANSPARENT != aColor.GetColor()) && (maBmpSize.Width() == maBmpSize.Height()))
            pBmpAcc->SetLineColor(aColor);
            pVirDev->SetLineColor(aColor);
        else if( mpTbx->GetBackground().GetColor().IsDark() )
            pBmpAcc->SetLineColor(Color(COL_WHITE));
            pVirDev->SetLineColor(Color(COL_WHITE));
        else
            pBmpAcc->SetLineColor(Color(COL_BLACK));
            pVirDev->SetLineColor(Color(COL_BLACK));

        // use not only COL_TRANSPARENT for detection of transparence,
        // but the method/way which is designed to do that
@@ -138,11 +105,11 @@ namespace svx

        if (bIsTransparent)
        {
            pBmpAcc->SetFillColor();
            pVirDev->SetFillColor(Color(255, 0, 0, 0));
        }
        else
        {
            pBmpAcc->SetFillColor(maCurColor);
            pVirDev->SetFillColor(maCurColor);
        }

        if (maBmpSize.Width() == maBmpSize.Height())
@@ -151,34 +118,9 @@ namespace svx
        else
            maUpdRect = tools::Rectangle(Point( maBmpSize.Height() + 2, 2), Point(maBmpSize.Width() - 3, maBmpSize.Height() - 3));

        pBmpAcc->DrawRect(maUpdRect);
        pVirDev->DrawRect(maUpdRect);

        if (pMskAcc)
        {
            if (bIsTransparent)
            {
                pMskAcc->SetLineColor(COL_BLACK);
                pMskAcc->SetFillColor(COL_WHITE);
            }
            else
                pMskAcc->SetFillColor(COL_BLACK);

            pMskAcc->DrawRect(maUpdRect);
        }

        Bitmap::ReleaseAccess(pBmpAcc);

        if (pMskAcc)
            Bitmap::ReleaseAccess(pMskAcc);

        if (aBmpEx.IsAlpha())
            aBmpEx = BitmapEx(aBmp, AlphaMask(aMsk));
        else if (aBmpEx.IsTransparent())
            aBmpEx = BitmapEx(aBmp, aMsk);
        else
            aBmpEx = aBmp;

        mpTbx->SetItemImage(mnBtnId, Image(aBmpEx));
        mpTbx->SetItemOverlayImage(mnBtnId, Image(pVirDev->GetBitmapEx(Point(0,0), aItemSize)));
    }
}

diff --git a/vcl/inc/toolbox.h b/vcl/inc/toolbox.h
index f908cc5b..9d928ce 100644
--- a/vcl/inc/toolbox.h
+++ b/vcl/inc/toolbox.h
@@ -37,6 +37,7 @@ struct ImplToolItem
    VclPtr<vcl::Window> mpWindow; //don't dispose mpWindow - we get copied around
    void*               mpUserData;
    Image               maImage;
    Image               maOverlayImage;
    long                mnImageAngle;
    bool                mbMirrorMode;
    OUString            maText;
diff --git a/vcl/source/window/toolbox.cxx b/vcl/source/window/toolbox.cxx
index a2b1400..e803124 100644
--- a/vcl/source/window/toolbox.cxx
+++ b/vcl/source/window/toolbox.cxx
@@ -2793,6 +2793,7 @@ void ToolBox::ImplDrawItem(vcl::RenderContext& rRenderContext, ImplToolItems::si
    if ( bImage )
    {
        const Image* pImage = &(pItem->maImage);
        const Image& rOverlayImage = pItem->maOverlayImage;
        aImageSize = pImage->GetSizePixel();

        // determine drawing flags
@@ -2837,6 +2838,8 @@ void ToolBox::ImplDrawItem(vcl::RenderContext& rRenderContext, ImplToolItems::si
            }
        }
        rRenderContext.DrawImage(Point( nImageOffX, nImageOffY ), *pImage, nImageStyle);
        if (!!rOverlayImage)
            rRenderContext.DrawImage(Point( nImageOffX, nImageOffY ), rOverlayImage, nImageStyle);
    }

    // draw the text
diff --git a/vcl/source/window/toolbox2.cxx b/vcl/source/window/toolbox2.cxx
index 23d5971..6cdd0ed 100644
--- a/vcl/source/window/toolbox2.cxx
+++ b/vcl/source/window/toolbox2.cxx
@@ -965,6 +965,28 @@ void ToolBox::SetItemImage( sal_uInt16 nItemId, const Image& rImage )
    }
}

void ToolBox::SetItemOverlayImage( sal_uInt16 nItemId, const Image& rImage )
{
    ImplToolItems::size_type nPos = GetItemPos( nItemId );

    if ( nPos != ITEM_NOTFOUND )
    {
        ImplToolItem* pItem = &mpData->m_aItems[nPos];
        Size aOldSize = pItem->maOverlayImage.GetSizePixel();

        pItem->maOverlayImage = rImage;

        // only once all is calculated, do extra work
        if (!mbCalc)
        {
            if (aOldSize != pItem->maOverlayImage.GetSizePixel())
                ImplInvalidate( true );
            else
                ImplUpdateItem( nPos );
        }
    }
}

static Image ImplRotImage( const Image& rImage, long nAngle10 )
{
    BitmapEx    aRotBitmapEx( rImage.GetBitmapEx() );