    /* -*- 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 <memory>
    #include <impanmvw.hxx>

    #include <vcl/virdev.hxx>
    #include <vcl/window.hxx>
    #include <tools/helpers.hxx>

    #include <window.h>

    ImplAnimView::ImplAnimView( Animation* pParent, OutputDevice* pOut,
                                const Point& rPt, const Size& rSz,
                                sal_uLong nExtraData,
                                OutputDevice* pFirstFrameOutDev ) :
            mpParent        ( pParent ),
            mpOut           ( pFirstFrameOutDev ? pFirstFrameOutDev : pOut ),
            mnExtraData     ( nExtraData ),
            maPt            ( rPt ),
            maSz            ( rSz ),
            maSzPix         ( mpOut->LogicToPixel( maSz ) ),
            maClip          ( mpOut->GetClipRegion() ),
            mpBackground    ( VclPtr<VirtualDevice>::Create() ),
            mpRestore       ( VclPtr<VirtualDevice>::Create() ),
            meLastDisposal  ( Disposal::Back ),
            mbPause         ( false ),
            mbMarked        ( false ),
            mbHMirr         ( maSz.Width() < 0 ),
            mbVMirr         ( maSz.Height() < 0 )
    {
        Animation::ImplIncAnimCount();

        // Mirrored horizontally?
        if( mbHMirr )
        {
            maDispPt.setX( maPt.X() + maSz.Width() + 1 );
            maDispSz.setWidth( -maSz.Width() );
            maSzPix.setWidth( -maSzPix.Width() );
        }
        else
        {
            maDispPt.setX( maPt.X() );
            maDispSz.setWidth( maSz.Width() );
        }

        // Mirrored vertically?
        if( mbVMirr )
        {
            maDispPt.setY( maPt.Y() + maSz.Height() + 1 );
            maDispSz.setHeight( -maSz.Height() );
            maSzPix.setHeight( -maSzPix.Height() );
        }
        else
        {
            maDispPt.setY( maPt.Y() );
            maDispSz.setHeight( maSz.Height() );
        }

        // save background
        mpBackground->SetOutputSizePixel( maSzPix );

        if( mpOut->GetOutDevType() == OUTDEV_WINDOW )
        {
            MapMode aTempMap( mpOut->GetMapMode() );
            aTempMap.SetOrigin( Point() );
            mpBackground->SetMapMode( aTempMap );
            static_cast<vcl::Window*>( mpOut.get() )->SaveBackground( maDispPt, maDispSz, *mpBackground );
            mpBackground->SetMapMode( MapMode() );
        }
        else
            mpBackground->DrawOutDev( Point(), maSzPix, maDispPt, maDispSz, *mpOut );

        // Initialize drawing to actual position
        drawToPos( mpParent->ImplGetCurPos() );

        // If first frame OutputDevice is set, update variables now for real OutputDevice
        if( pFirstFrameOutDev )
            maClip = ( mpOut = pOut )->GetClipRegion();
    }

    ImplAnimView::~ImplAnimView()
    {
        mpBackground.disposeAndClear();
        mpRestore.disposeAndClear();

        Animation::ImplDecAnimCount();
    }

    bool ImplAnimView::matches( OutputDevice* pOut, long nExtraData ) const
    {
        bool bRet = false;

        if( nExtraData )
        {
            if( ( mnExtraData == nExtraData ) && ( !pOut || ( pOut == mpOut ) ) )
                bRet = true;
        }
        else if( !pOut || ( pOut == mpOut ) )
            bRet = true;

        return bRet;
    }

    void ImplAnimView::getPosSize( const AnimationBitmap& rAnm, Point& rPosPix, Size& rSizePix )
    {
        const Size& rAnmSize = mpParent->GetDisplaySizePixel();
        Point       aPt2( rAnm.aPosPix.X() + rAnm.aSizePix.Width() - 1,
                          rAnm.aPosPix.Y() + rAnm.aSizePix.Height() - 1 );
        double      fFactX, fFactY;

        // calculate x scaling
        if( rAnmSize.Width() > 1 )
            fFactX = static_cast<double>( maSzPix.Width() - 1 ) / ( rAnmSize.Width() - 1 );
        else
            fFactX = 1.0;

        // calculate y scaling
        if( rAnmSize.Height() > 1 )
            fFactY = static_cast<double>( maSzPix.Height() - 1 ) / ( rAnmSize.Height() - 1 );
        else
            fFactY = 1.0;

        rPosPix.setX( FRound( rAnm.aPosPix.X() * fFactX ) );
        rPosPix.setY( FRound( rAnm.aPosPix.Y() * fFactY ) );

        aPt2.setX( FRound( aPt2.X() * fFactX ) );
        aPt2.setY( FRound( aPt2.Y() * fFactY ) );

        rSizePix.setWidth( aPt2.X() - rPosPix.X() + 1 );
        rSizePix.setHeight( aPt2.Y() - rPosPix.Y() + 1 );

        // Mirrored horizontally?
        if( mbHMirr )
            rPosPix.setX( maSzPix.Width() - 1 - aPt2.X() );

        // Mirrored vertically?
        if( mbVMirr )
            rPosPix.setY( maSzPix.Height() - 1 - aPt2.Y() );
    }

    void ImplAnimView::drawToPos( sal_uLong nPos )
    {
        VclPtr<vcl::RenderContext> pRenderContext = mpOut;

        std::unique_ptr<PaintBufferGuard> pGuard;
        if (mpOut->GetOutDevType() == OUTDEV_WINDOW)
        {
            vcl::Window* pWindow = static_cast<vcl::Window*>(mpOut.get());
            pGuard.reset(new PaintBufferGuard(pWindow->ImplGetWindowImpl()->mpFrameData, pWindow));
            pRenderContext = pGuard->GetRenderContext();
        }

        ScopedVclPtrInstance<VirtualDevice> aVDev;
        std::unique_ptr<vcl::Region> xOldClip(!maClip.IsNull() ? new vcl::Region( pRenderContext->GetClipRegion() ) : nullptr);

        aVDev->SetOutputSizePixel( maSzPix, false );
        nPos = std::min( nPos, static_cast<sal_uLong>(mpParent->Count()) - 1 );

        for( sal_uLong i = 0; i <= nPos; i++ )
            draw( i, aVDev.get() );

        if (xOldClip)
            pRenderContext->SetClipRegion( maClip );

        pRenderContext->DrawOutDev( maDispPt, maDispSz, Point(), maSzPix, *aVDev.get() );
        if (pGuard)
            pGuard->SetPaintRect(tools::Rectangle(maDispPt, maDispSz));

        if (xOldClip)
            pRenderContext->SetClipRegion(*xOldClip);
    }

    void ImplAnimView::draw( sal_uLong nPos, VirtualDevice* pVDev )
    {
        VclPtr<vcl::RenderContext> pRenderContext = mpOut;

        std::unique_ptr<PaintBufferGuard> pGuard;
        if (!pVDev && mpOut->GetOutDevType() == OUTDEV_WINDOW)
        {
            vcl::Window* pWindow = static_cast<vcl::Window*>(mpOut.get());
            pGuard.reset(new PaintBufferGuard(pWindow->ImplGetWindowImpl()->mpFrameData, pWindow));
            pRenderContext = pGuard->GetRenderContext();
        }

        tools::Rectangle aOutRect( pRenderContext->PixelToLogic( Point() ), pRenderContext->GetOutputSize() );

        // check, if output lies out of display
        if( aOutRect.Intersection( tools::Rectangle( maDispPt, maDispSz ) ).IsEmpty() )
            setMarked( true );
        else if( !mbPause )
        {
            VclPtr<VirtualDevice>   pDev;
            Point                   aPosPix;
            Point                   aBmpPosPix;
            Size                    aSizePix;
            Size                    aBmpSizePix;
            const sal_uLong             nLastPos = mpParent->Count() - 1;
            const AnimationBitmap&  rAnm = mpParent->Get( static_cast<sal_uInt16>( mnActPos = std::min( nPos, nLastPos ) ) );

            getPosSize( rAnm, aPosPix, aSizePix );

            // Mirrored horizontally?
            if( mbHMirr )
            {
                aBmpPosPix.setX( aPosPix.X() + aSizePix.Width() - 1 );
                aBmpSizePix.setWidth( -aSizePix.Width() );
            }
            else
            {
                aBmpPosPix.setX( aPosPix.X() );
                aBmpSizePix.setWidth( aSizePix.Width() );
            }

            // Mirrored vertically?
            if( mbVMirr )
            {
                aBmpPosPix.setY( aPosPix.Y() + aSizePix.Height() - 1 );
                aBmpSizePix.setHeight( -aSizePix.Height() );
            }
            else
            {
                aBmpPosPix.setY( aPosPix.Y() );
                aBmpSizePix.setHeight( aSizePix.Height() );
            }

            // get output device
            if( !pVDev )
            {
                pDev = VclPtr<VirtualDevice>::Create();
                pDev->SetOutputSizePixel( maSzPix, false );
                pDev->DrawOutDev( Point(), maSzPix, maDispPt, maDispSz, *pRenderContext );
            }
            else
                pDev = pVDev;

            // restore background after each run
            if( !nPos )
            {
                meLastDisposal = Disposal::Back;
                maRestPt = Point();
                maRestSz = maSzPix;
            }

            // restore
            if( ( Disposal::Not != meLastDisposal ) && maRestSz.Width() && maRestSz.Height() )
            {
                if( Disposal::Back == meLastDisposal )
                    pDev->DrawOutDev( maRestPt, maRestSz, maRestPt, maRestSz, *mpBackground );
                else
                    pDev->DrawOutDev( maRestPt, maRestSz, Point(), maRestSz, *mpRestore );
            }

            meLastDisposal = rAnm.eDisposal;
            maRestPt = aPosPix;
            maRestSz = aSizePix;

            // What do we need to restore the next time?
            // Put it into a bitmap if needed, else delete
            // SaveBitmap to conserve memory
            if( ( meLastDisposal == Disposal::Back ) || ( meLastDisposal == Disposal::Not ) )
                mpRestore->SetOutputSizePixel( Size( 1, 1 ), false );
            else
            {
                mpRestore->SetOutputSizePixel( maRestSz, false );
                mpRestore->DrawOutDev( Point(), maRestSz, aPosPix, aSizePix, *pDev );
            }

            pDev->DrawBitmapEx( aBmpPosPix, aBmpSizePix, rAnm.aBmpEx );

            if( !pVDev )
            {
                std::unique_ptr<vcl::Region> xOldClip(!maClip.IsNull() ? new vcl::Region( pRenderContext->GetClipRegion() ) : nullptr);

                if (xOldClip)
                    pRenderContext->SetClipRegion( maClip );

                pRenderContext->DrawOutDev( maDispPt, maDispSz, Point(), maSzPix, *pDev );
                if (pGuard)
                    pGuard->SetPaintRect(tools::Rectangle(maDispPt, maDispSz));

                if( xOldClip)
                {
                    pRenderContext->SetClipRegion(*xOldClip);
                    xOldClip.reset();
                }

                pDev.disposeAndClear();

                if( pRenderContext->GetOutDevType() == OUTDEV_WINDOW )
                    static_cast<vcl::Window*>( pRenderContext.get() )->Flush();
            }
        }
    }

    void ImplAnimView::repaint()
    {
        const bool bOldPause = mbPause;

        if( mpOut->GetOutDevType() == OUTDEV_WINDOW )
        {
            MapMode aTempMap( mpOut->GetMapMode() );
            aTempMap.SetOrigin( Point() );
            mpBackground->SetMapMode( aTempMap );
            static_cast<vcl::Window*>( mpOut.get() )->SaveBackground( maDispPt, maDispSz, *mpBackground );
            mpBackground->SetMapMode( MapMode() );
        }
        else
            mpBackground->DrawOutDev( Point(), maSzPix, maDispPt, maDispSz, *mpOut );

        mbPause = false;
        drawToPos( mnActPos );
        mbPause = bOldPause;
    }

    AInfo* ImplAnimView::createAInfo() const
    {
        AInfo* pAInfo = new AInfo;

        pAInfo->aStartOrg = maPt;
        pAInfo->aStartSize = maSz;
        pAInfo->pOutDev = mpOut;
        pAInfo->pViewData = const_cast<ImplAnimView *>(this);
        pAInfo->nExtraData = mnExtraData;
        pAInfo->bPause = mbPause;

        return pAInfo;
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V730 It is possible that not all members of a class are initialized inside the constructor. Consider inspecting: mnActPos.