vcl: move functionality into FindIncompletelyOccludedBackground()

Change-Id: I228d58c8b16152491e9b46c837f4fbbf9e50a6d5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94024
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
diff --git a/vcl/source/gdi/print2.cxx b/vcl/source/gdi/print2.cxx
index d74a670..e3bdb76 100644
--- a/vcl/source/gdi/print2.cxx
+++ b/vcl/source/gdi/print2.cxx
@@ -92,12 +92,12 @@ bool DoesActionHandleTransparency( const MetaAction& rAct )
bool doesRectCoverWithUniformColor(
        tools::Rectangle const & rPrevRect,
        tools::Rectangle const & rCurrRect,
        OutputDevice const & rMapModeVDev)
        VirtualDevice const * pMapModeVDev)
{
    // shape needs to fully cover previous content, and have uniform
    // color
    return (rMapModeVDev.LogicToPixel(rCurrRect).IsInside(rPrevRect) &&
        rMapModeVDev.IsFillColor());
    return (pMapModeVDev->LogicToPixel(rCurrRect).IsInside(rPrevRect) &&
        pMapModeVDev->IsFillColor());
}

void setComponentsSizeAndColor(ConnectedComponents &rBackgroundComponent, tools::Rectangle const & rRect, Color const& rColor)
@@ -609,6 +609,108 @@ tools::Rectangle ImplCalcActionBounds( const MetaAction& rAct, const OutputDevic
        return tools::Rectangle();
}

int FindIncompletelyOccludedBackground(ConnectedComponents& rBackgroundComponent, GDIMetaFile const & rMtf, VirtualDevice* pMapModeVDev)
{
    MetaAction* pCurrAct=const_cast<GDIMetaFile&>(rMtf).FirstAction();

    int nActionNum = 0;
    int nLastBgAction = -1;
    bool bStillBackground=true; // true until first non-bg action

    while( pCurrAct && bStillBackground )
    {
        switch( pCurrAct->GetType() )
        {
            case MetaActionType::RECT:
            {
                const tools::Rectangle aRect(
                    static_cast<const MetaRectAction*>(pCurrAct)->GetRect());

                if (!doesRectCoverWithUniformColor(rBackgroundComponent.aBounds, aRect, pMapModeVDev))
                {
                    setComponentsSizeAndColor(rBackgroundComponent, aRect, pMapModeVDev->GetFillColor());
                    bStillBackground=false; // incomplete occlusion of background
                }
                else
                {
                    nLastBgAction=nActionNum; // this _is_ background
                }
                break;
            }
            case MetaActionType::POLYGON:
            {
                const tools::Polygon aPoly(
                    static_cast<const MetaPolygonAction*>(pCurrAct)->GetPolygon());
                const tools::Rectangle aRect(aPoly.GetBoundRect());

                if (!basegfx::utils::isRectangle(aPoly.getB2DPolygon()) ||
                    !doesRectCoverWithUniformColor(rBackgroundComponent.aBounds, aRect, pMapModeVDev))
                {
                    setComponentsSizeAndColor(rBackgroundComponent, aRect, pMapModeVDev->GetFillColor());
                    bStillBackground=false; // incomplete occlusion of background
                }
                else
                {
                    nLastBgAction=nActionNum; // this _is_ background
                }
                break;
            }
            case MetaActionType::POLYPOLYGON:
            {
                const tools::PolyPolygon aPoly(
                    static_cast<const MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon());
                const tools::Rectangle aRect(aPoly.GetBoundRect());

                if (aPoly.Count() != 1 ||
                    !basegfx::utils::isRectangle(aPoly[0].getB2DPolygon()) ||
                    !doesRectCoverWithUniformColor(rBackgroundComponent.aBounds, aRect, pMapModeVDev))
                {
                    setComponentsSizeAndColor(rBackgroundComponent, aRect, pMapModeVDev->GetFillColor());
                    bStillBackground=false; // incomplete occlusion of background
                }
                else
                {
                    nLastBgAction=nActionNum; // this _is_ background
                }
                break;
            }
            case MetaActionType::WALLPAPER:
            {
                const tools::Rectangle aRect(
                    static_cast<const MetaWallpaperAction*>(pCurrAct)->GetRect());

                if (!doesRectCoverWithUniformColor(rBackgroundComponent.aBounds, aRect, pMapModeVDev))
                {
                    setComponentsSizeAndColor(rBackgroundComponent, aRect, pMapModeVDev->GetFillColor());
                    bStillBackground=false; // incomplete occlusion of background
                }
                else
                {
                    nLastBgAction=nActionNum; // this _is_ background
                }
                break;
            }
            default:
            {
                if (ImplIsNotTransparent( *pCurrAct, *pMapModeVDev))
                    bStillBackground=false; // non-transparent action, possibly not uniform
                else
                    // extend current bounds (next uniform action needs to fully cover this area)
                    rBackgroundComponent.aBounds.Union(ImplCalcActionBounds(*pCurrAct, *pMapModeVDev));
                break;
            }
        }

        // execute action to get correct MapModes etc.
        pCurrAct->Execute(pMapModeVDev);

        pCurrAct=const_cast<GDIMetaFile&>(rMtf).NextAction();
        ++nActionNum;
    }

    return nLastBgAction;
}

} // end anon namespace

bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, GDIMetaFile& rOutMtf,
@@ -680,110 +782,17 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, 
        aMapModeVDev->mnDPIY = mnDPIY;
        aMapModeVDev->EnableOutput(false);

        int nLastBgAction, nActionNum;

        // weed out page-filling background objects (if they are
        // uniformly coloured). Keeping them outside the other
        // connected components often prevents whole-page bitmap
        // generation.
        bool bStillBackground=true; // true until first non-bg action
        nActionNum=0; nLastBgAction=-1;
        pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
        if( rBackground != COL_TRANSPARENT )
        {
            aBackgroundComponent.aBgColor = rBackground;
            aBackgroundComponent.aBounds = SetBackgroundComponentBounds();
        }
        while( pCurrAct && bStillBackground )
        {
            switch( pCurrAct->GetType() )
            {
                case MetaActionType::RECT:
                {
                    const tools::Rectangle aRect(
                        static_cast<const MetaRectAction*>(pCurrAct)->GetRect());

                    if (!doesRectCoverWithUniformColor(aBackgroundComponent.aBounds, aRect, *aMapModeVDev))
                    {
                        setComponentsSizeAndColor(aBackgroundComponent, aRect, aMapModeVDev->GetFillColor());
                        bStillBackground=false; // incomplete occlusion of background
                    }
                    else
                    {
                        nLastBgAction=nActionNum; // this _is_ background
                    }
                    break;
                }
                case MetaActionType::POLYGON:
                {
                    const tools::Polygon aPoly(
                        static_cast<const MetaPolygonAction*>(pCurrAct)->GetPolygon());
                    const tools::Rectangle aRect(aPoly.GetBoundRect());

                    if (!basegfx::utils::isRectangle(aPoly.getB2DPolygon()) ||
                        !doesRectCoverWithUniformColor(aBackgroundComponent.aBounds, aRect, *aMapModeVDev))
                    {
                        setComponentsSizeAndColor(aBackgroundComponent, aRect, aMapModeVDev->GetFillColor());
                        bStillBackground=false; // incomplete occlusion of background
                    }
                    else
                    {
                        nLastBgAction=nActionNum; // this _is_ background
                    }
                    break;
                }
                case MetaActionType::POLYPOLYGON:
                {
                    const tools::PolyPolygon aPoly(
                        static_cast<const MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon());
                    const tools::Rectangle aRect(aPoly.GetBoundRect());

                    if (aPoly.Count() != 1 ||
                        !basegfx::utils::isRectangle(aPoly[0].getB2DPolygon()) ||
                        !doesRectCoverWithUniformColor(aBackgroundComponent.aBounds, aRect, *aMapModeVDev))
                    {
                        setComponentsSizeAndColor(aBackgroundComponent, aRect, aMapModeVDev->GetFillColor());
                        bStillBackground=false; // incomplete occlusion of background
                    }
                    else
                    {
                        nLastBgAction=nActionNum; // this _is_ background
                    }
                    break;
                }
                case MetaActionType::WALLPAPER:
                {
                    const tools::Rectangle aRect(
                        static_cast<const MetaWallpaperAction*>(pCurrAct)->GetRect());

                    if (!doesRectCoverWithUniformColor(aBackgroundComponent.aBounds, aRect, *aMapModeVDev))
                    {
                        setComponentsSizeAndColor(aBackgroundComponent, aRect, aMapModeVDev->GetFillColor());
                        bStillBackground=false; // incomplete occlusion of background
                    }
                    else
                    {
                        nLastBgAction=nActionNum; // this _is_ background
                    }
                    break;
                }
                default:
                {
                    if (ImplIsNotTransparent( *pCurrAct, *aMapModeVDev))
                        bStillBackground=false; // non-transparent action, possibly not uniform
                    else
                        // extend current bounds (next uniform action needs to fully cover this area)
                        aBackgroundComponent.aBounds.Union(ImplCalcActionBounds(*pCurrAct, *aMapModeVDev));
                    break;
                }
            }

            // execute action to get correct MapModes etc.
            pCurrAct->Execute( aMapModeVDev.get() );

            pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction();
            ++nActionNum;
        }
        int nLastBgAction = FindIncompletelyOccludedBackground(aBackgroundComponent, rInMtf, aMapModeVDev.get());

        // clean up aMapModeVDev
        sal_uInt32 nCount = aMapModeVDev->GetGCStackDepth();
@@ -794,7 +803,7 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, 

        // fast-forward until one after the last background action
        // (need to reconstruct map mode vdev state)
        nActionNum=0;
        int nActionNum=0;
        pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
        while( pCurrAct && nActionNum<=nLastBgAction )
        {