vcl: fix virtual device lifecycle.

Also remove an over-optimistic assert & ref-holding in dispose piece.

Change-Id: I6ce6abb666c8143502fc450a26e1ba2aac787455
diff --git a/include/vcl/virdev.hxx b/include/vcl/virdev.hxx
index 06dbae6..88f9fb6 100644
--- a/include/vcl/virdev.hxx
+++ b/include/vcl/virdev.hxx
@@ -118,6 +118,7 @@ public:
                                      sal_uInt16 nBitCount);

    virtual             ~VirtualDevice();
    virtual void        dispose() SAL_OVERRIDE;

    virtual void        EnableRTL( bool bEnable = true ) SAL_OVERRIDE;

diff --git a/vcl/qa/cppunit/lifecycle.cxx b/vcl/qa/cppunit/lifecycle.cxx
index 04a4719..8be94a5 100644
--- a/vcl/qa/cppunit/lifecycle.cxx
+++ b/vcl/qa/cppunit/lifecycle.cxx
@@ -15,6 +15,7 @@
#include <vcl/edit.hxx>
#include <vcl/combobox.hxx>
#include <vcl/field.hxx>
#include <vcl/virdev.hxx>

class LifecycleTest : public test::BootstrapFixture
{
@@ -24,6 +25,7 @@ public:
    LifecycleTest() : BootstrapFixture(true, false) {}

    void testCast();
    void testVirtualDevice();
    void testMultiDispose();
    void testIsolatedWidgets();
    void testParentedWidgets();
@@ -31,6 +33,7 @@ public:

    CPPUNIT_TEST_SUITE(LifecycleTest);
    CPPUNIT_TEST(testCast);
    CPPUNIT_TEST(testVirtualDevice);
    CPPUNIT_TEST(testMultiDispose);
    CPPUNIT_TEST(testIsolatedWidgets);
    CPPUNIT_TEST(testParentedWidgets);
@@ -52,6 +55,11 @@ void LifecycleTest::testCast()
//    VclPtr<PushButton> xButton2(xWindow);
}

void LifecycleTest::testVirtualDevice()
{
    VclPtr<VirtualDevice> pVDev = new VirtualDevice();
}

void LifecycleTest::testMultiDispose()
{
    VclPtr<WorkWindow> xWin(new WorkWindow((vcl::Window *)NULL,
diff --git a/vcl/source/filter/wmf/winmtf.cxx b/vcl/source/filter/wmf/winmtf.cxx
index 72c20cb..1e807f1 100644
--- a/vcl/source/filter/wmf/winmtf.cxx
+++ b/vcl/source/filter/wmf/winmtf.cxx
@@ -236,12 +236,12 @@ WinMtfFontStyle::WinMtfFontStyle( LOGFONTW& rFont )
    {
        // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
        SolarMutexGuard aGuard;
        VirtualDevice aVDev;
        VclPtr<VirtualDevice> pVDev = new VirtualDevice();

        // converting the cell height into a font height
        aFont.SetSize( aFontSize );
        aVDev.SetFont( aFont );
        FontMetric aMetric( aVDev.GetFontMetric() );
        pVDev->SetFont( aFont );
        FontMetric aMetric( pVDev->GetFontMetric() );
        long nHeight = aMetric.GetAscent() + aMetric.GetDescent();
        if (nHeight)
        {
@@ -1448,20 +1448,20 @@ void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, b
    {
        // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
        SolarMutexGuard aGuard;
        VirtualDevice aVDev;
        VclPtr<VirtualDevice> pVDev = new VirtualDevice();

        sal_Int32 nTextWidth;
        aVDev.SetMapMode( MapMode( MAP_100TH_MM ) );
        aVDev.SetFont( maFont );
        pVDev->SetMapMode( MapMode( MAP_100TH_MM ) );
        pVDev->SetFont( maFont );
        if( pDXArry )
        {
            sal_uInt32 nLen = rText.getLength();
            nTextWidth = aVDev.GetTextWidth( OUString(rText[ nLen - 1 ]) );
            nTextWidth = pVDev->GetTextWidth( OUString(rText[ nLen - 1 ]) );
            if( nLen > 1 )
                nTextWidth += pDXArry[ nLen - 2 ];
        }
        else
            nTextWidth = aVDev.GetTextWidth( rText );
            nTextWidth = pVDev->GetTextWidth( rText );

        if( mnTextAlign & TA_UPDATECP )
            rPosition = maActPos;
@@ -1497,12 +1497,12 @@ void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, b
        {
            // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
            SolarMutexGuard aGuard;
            VirtualDevice aVDev;
            VclPtr<VirtualDevice> pVDev = new VirtualDevice();

            pDX = new long[ rText.getLength() ];
            aVDev.SetMapMode( MAP_100TH_MM );
            aVDev.SetFont( maLatestFont );
            aVDev.GetTextArray( rText, pDX, 0, rText.getLength());
            pVDev->SetMapMode( MAP_100TH_MM );
            pVDev->SetFont( maLatestFont );
            pVDev->GetTextArray( rText, pDX, 0, rText.getLength());
        }
        mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition, rText, pDX, 0, rText.getLength() ) );
        if ( !pDXArry )     // this means we have created our own array
@@ -1516,26 +1516,26 @@ void WinMtfOutput::ImplDrawBitmap( const Point& rPos, const Size& rSize, const B
    BitmapEx aBmpEx( rBitmap );
    if ( mbComplexClip )
    {
        VirtualDevice aVDev;
        VclPtr<VirtualDevice> pVDev = new VirtualDevice();
        MapMode aMapMode( MAP_100TH_MM );
        aMapMode.SetOrigin( Point( -rPos.X(), -rPos.Y() ) );
        const Size aOutputSizePixel( aVDev.LogicToPixel( rSize, aMapMode ) );
        const Size aOutputSizePixel( pVDev->LogicToPixel( rSize, aMapMode ) );
        const Size aSizePixel( rBitmap.GetSizePixel() );
        if ( aOutputSizePixel.Width() && aOutputSizePixel.Height() )
        {
            aMapMode.SetScaleX( Fraction( aSizePixel.Width(), aOutputSizePixel.Width() ) );
            aMapMode.SetScaleY( Fraction( aSizePixel.Height(), aOutputSizePixel.Height() ) );
        }
        aVDev.SetMapMode( aMapMode );
        aVDev.SetOutputSizePixel( aSizePixel );
        aVDev.SetFillColor( Color( COL_BLACK ) );
        pVDev->SetMapMode( aMapMode );
        pVDev->SetOutputSizePixel( aSizePixel );
        pVDev->SetFillColor( Color( COL_BLACK ) );
        const tools::PolyPolygon aClip( aClipPath.getClipPath() );
        aVDev.DrawPolyPolygon( aClip );
        pVDev->DrawPolyPolygon( aClip );
        const Point aEmptyPoint;

        // #i50672# Extract whole VDev content (to match size of rBitmap)
        aVDev.EnableMapMode( false );
        Bitmap aMask( aVDev.GetBitmap( aEmptyPoint, aSizePixel ).CreateMask( Color( COL_WHITE ) ) );
        pVDev->EnableMapMode( false );
        Bitmap aMask( pVDev->GetBitmap( aEmptyPoint, aSizePixel ).CreateMask( Color( COL_WHITE ) ) );

        if ( aBmpEx.IsTransparent() )
        {
diff --git a/vcl/source/gdi/virdev.cxx b/vcl/source/gdi/virdev.cxx
index eec2fa9..b8ce392 100644
--- a/vcl/source/gdi/virdev.cxx
+++ b/vcl/source/gdi/virdev.cxx
@@ -255,6 +255,12 @@ VirtualDevice::VirtualDevice(const SystemGraphicsData *pData, const Size &rSize,
VirtualDevice::~VirtualDevice()
{
    SAL_INFO( "vcl.gdi", "VirtualDevice::~VirtualDevice()" );
    disposeOnce();
}

void VirtualDevice::dispose()
{
    SAL_INFO( "vcl.gdi", "VirtualDevice::dispose()" );

    ImplSVData* pSVData = ImplGetSVData();

@@ -272,6 +278,8 @@ VirtualDevice::~VirtualDevice()
        mpNext->mpPrev = mpPrev;
    else
        pSVData->maGDIData.mpLastVirDev = mpPrev;

    OutputDevice::dispose();
}

bool VirtualDevice::InnerImplSetOutputSizePixel( const Size& rNewSize, bool bErase,
diff --git a/vcl/source/outdev/outdev.cxx b/vcl/source/outdev/outdev.cxx
index 5d59ee1..d39a76d 100644
--- a/vcl/source/outdev/outdev.cxx
+++ b/vcl/source/outdev/outdev.cxx
@@ -82,6 +82,7 @@ namespace {
// Begin initializer and accessor public functions

OutputDevice::OutputDevice() :
    mnRefCnt(0),
    maRegion(true),
    maFillColor( COL_WHITE ),
    maTextLineColor( COL_TRANSPARENT ),
@@ -179,6 +180,8 @@ OutputDevice::OutputDevice() :
    // #i75163#
    mpOutDevData->mpViewTransform   = NULL;
    mpOutDevData->mpInverseViewTransform = NULL;

    mbDisposed = false;
}

OutputDevice::~OutputDevice()
@@ -194,10 +197,10 @@ void OutputDevice::disposeOnce()

    // catch badness where our OutputDevice sub-class was not
    // wrapped safely in a VclPtr cosily.
    assert( mnRefCnt > 0 );
    // FIXME: as/when we make our destructors all protected,
    // we should introduce this assert:
    //    assert( mnRefCnt > 0 );

    // hold a ref in case something unusual happens during dispose.
    VclPtr<OutputDevice> aRef(this);
    dispose();
}