/**************************************************************
 * 
 * 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
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include <tools/ref.hxx>
#include <tools/debug.hxx>
#include <tools/poly.hxx>

#include <vcl/svapp.hxx>
#include <vcl/ctrl.hxx>
#include <vcl/region.hxx>
#include <vcl/virdev.hxx>
#include <vcl/window.hxx>
#include <vcl/metaact.hxx>
#include <vcl/gdimtf.hxx>
#include <vcl/print.hxx>
#include <vcl/outdev.hxx>
#include <vcl/unowrap.hxx>
// declare system types in sysdata.hxx
#include <svsys.h>
#include <vcl/sysdata.hxx>

#include <salgdi.hxx>
#include <sallayout.hxx>
#include <salframe.hxx>
#include <salvd.hxx>
#include <salprn.hxx>
#include <svdata.hxx>
#include <window.h>
#include <outdev.h>
#include <region.h>
#include <outdata.hxx>

#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/vector/b2dvector.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/polygon/b2dlinegeometry.hxx>

#include <com/sun/star/awt/XGraphics.hpp>
#include <com/sun/star/uno/Sequence.hxx>
#include <com/sun/star/rendering/XCanvas.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <vcl/unohelp.hxx>

#include <numeric>

using namespace ::com::sun::star;

DBG_NAME( OutputDevice )
DBG_NAME( Polygon )
DBG_NAME( PolyPolygon )
DBG_NAMEEX( Region )

// -----------------------------------------------------------------------

#ifdef DBG_UTIL
const char* ImplDbgCheckOutputDevice( const void* pObj )
{
	DBG_TESTSOLARMUTEX();

	const OutputDevice* pOutDev = (OutputDevice*)pObj;

	if ( (pOutDev->GetOutDevType() != OUTDEV_DONTKNOW) &&
		 (pOutDev->GetOutDevType() != OUTDEV_WINDOW) &&
		 (pOutDev->GetOutDevType() != OUTDEV_PRINTER) &&
		 (pOutDev->GetOutDevType() != OUTDEV_VIRDEV) )
		return "OutputDevice data overwrite";

	return NULL;
}
#endif

// =======================================================================

#define OUTDEV_POLYPOLY_STACKBUF		32

// =======================================================================

struct ImplObjStack
{
    ImplObjStack*   mpPrev;
    MapMode*        mpMapMode;
    Region*         mpClipRegion;
    Color*          mpLineColor;
    Color*          mpFillColor;
    Font*           mpFont;
    Color*          mpTextColor;
    Color*          mpTextFillColor;
    Color*          mpTextLineColor;
    Color*          mpOverlineColor;
    Point*          mpRefPoint;
    TextAlign       meTextAlign;
    RasterOp        meRasterOp;
    sal_uLong           mnTextLayoutMode;
    LanguageType    meTextLanguage;
    sal_uInt16          mnFlags;
};

// -----------------------------------------------------------------------

static void ImplDeleteObjStack( ImplObjStack* pObjStack )
{
	if ( pObjStack->mnFlags & PUSH_LINECOLOR )
	{
		if ( pObjStack->mpLineColor )
			delete pObjStack->mpLineColor;
	}
	if ( pObjStack->mnFlags & PUSH_FILLCOLOR )
	{
		if ( pObjStack->mpFillColor )
			delete pObjStack->mpFillColor;
	}
	if ( pObjStack->mnFlags & PUSH_FONT )
		delete pObjStack->mpFont;
	if ( pObjStack->mnFlags & PUSH_TEXTCOLOR )
		delete pObjStack->mpTextColor;
	if ( pObjStack->mnFlags & PUSH_TEXTFILLCOLOR )
	{
		if ( pObjStack->mpTextFillColor )
			delete pObjStack->mpTextFillColor;
	}
	if ( pObjStack->mnFlags & PUSH_TEXTLINECOLOR )
	{
		if ( pObjStack->mpTextLineColor )
			delete pObjStack->mpTextLineColor;
	}
	if ( pObjStack->mnFlags & PUSH_OVERLINECOLOR )
	{
		if ( pObjStack->mpOverlineColor )
			delete pObjStack->mpOverlineColor;
	}
	if ( pObjStack->mnFlags & PUSH_MAPMODE )
	{
		if ( pObjStack->mpMapMode )
			delete pObjStack->mpMapMode;
	}
	if ( pObjStack->mnFlags & PUSH_CLIPREGION )
	{
		if ( pObjStack->mpClipRegion )
			delete pObjStack->mpClipRegion;
	}
	if ( pObjStack->mnFlags & PUSH_REFPOINT )
	{
		if ( pObjStack->mpRefPoint )
			delete pObjStack->mpRefPoint;
	}

	delete pObjStack;
}

// -----------------------------------------------------------------------

bool OutputDevice::ImplIsAntiparallel() const
{
    bool bRet = false;
    if( ImplGetGraphics() )
    {
        if( ( (mpGraphics->GetLayout() & SAL_LAYOUT_BIDI_RTL) && ! IsRTLEnabled() ) ||
            ( ! (mpGraphics->GetLayout() & SAL_LAYOUT_BIDI_RTL) && IsRTLEnabled() ) )
        {
            bRet = true;
        }
    }
    return bRet;
}

// -----------------------------------------------------------------------


bool OutputDevice::ImplSelectClipRegion( const Region& rRegion, SalGraphics* pGraphics )
{
	DBG_TESTSOLARMUTEX();

	if( !pGraphics )
	{
		if( !mpGraphics )
			if( !ImplGetGraphics() )
				return false;
		pGraphics = mpGraphics;
	}
	
	bool bClipRegion = pGraphics->SetClipRegion( rRegion, this );
	OSL_ENSURE( bClipRegion, "OutputDevice::ImplSelectClipRegion() - can't cerate region" );
	return bClipRegion;
}


// =======================================================================

Polygon ImplSubdivideBezier( const Polygon& rPoly )
{
    Polygon aPoly;

    // #100127# Use adaptive subdivide instead of fixed 25 segments
    rPoly.AdaptiveSubdivide( aPoly );

    return aPoly;
}

// =======================================================================

PolyPolygon ImplSubdivideBezier( const PolyPolygon& rPolyPoly )
{
    sal_uInt16 i, nPolys = rPolyPoly.Count();
    PolyPolygon aPolyPoly( nPolys );
    for( i=0; i<nPolys; ++i )
        aPolyPoly.Insert( ImplSubdivideBezier( rPolyPoly.GetObject(i) ) );

    return aPolyPoly;
}

// =======================================================================

// #100127# Extracted from OutputDevice::DrawPolyPolygon()
void OutputDevice::ImplDrawPolyPolygon( sal_uInt16 nPoly, const PolyPolygon& rPolyPoly )
{
    // AW: This crashes on empty PolyPolygons, avoid that
    if(!nPoly)
        return;

    sal_uInt32			aStackAry1[OUTDEV_POLYPOLY_STACKBUF];
    PCONSTSALPOINT		aStackAry2[OUTDEV_POLYPOLY_STACKBUF];
    sal_uInt8*				aStackAry3[OUTDEV_POLYPOLY_STACKBUF];
    sal_uInt32*			pPointAry;
    PCONSTSALPOINT* 	pPointAryAry;
    const sal_uInt8**	 	pFlagAryAry;
    sal_uInt16				i = 0, j = 0, last = 0;
    sal_Bool				bHaveBezier = sal_False;
    if ( nPoly > OUTDEV_POLYPOLY_STACKBUF )
    {
        pPointAry		= new sal_uInt32[nPoly];
        pPointAryAry	= new PCONSTSALPOINT[nPoly];
        pFlagAryAry		= new const sal_uInt8*[nPoly];
    }
    else
    {
        pPointAry		= aStackAry1;
        pPointAryAry	= aStackAry2;
        pFlagAryAry		= (const sal_uInt8**)aStackAry3;
    }
    do
    {
        const Polygon&	rPoly = rPolyPoly.GetObject( i );
        sal_uInt16			nSize = rPoly.GetSize();
        if ( nSize )
        {
            pPointAry[j]	= nSize;
            pPointAryAry[j] = (PCONSTSALPOINT)rPoly.GetConstPointAry();
            pFlagAryAry[j]  = rPoly.GetConstFlagAry();
            last 			= i;

            if( pFlagAryAry[j] )
                bHaveBezier = sal_True;

            ++j;
        }

        ++i;
    }
    while ( i < nPoly );

    if ( j == 1 )
    {
        // #100127# Forward beziers to sal, if any
        if( bHaveBezier )
        {
            if( !mpGraphics->DrawPolygonBezier( *pPointAry, *pPointAryAry, *pFlagAryAry, this ) )
            {
                Polygon aPoly = ImplSubdivideBezier( rPolyPoly.GetObject( last ) );
                mpGraphics->DrawPolygon( aPoly.GetSize(), (const SalPoint*)aPoly.GetConstPointAry(), this );
            }
        }
        else
        {
            mpGraphics->DrawPolygon( *pPointAry, *pPointAryAry, this );
        }
    }
    else
    {
        // #100127# Forward beziers to sal, if any
        if( bHaveBezier )
        {
            if( !mpGraphics->DrawPolyPolygonBezier( j, pPointAry, pPointAryAry, pFlagAryAry, this ) )
            {
                PolyPolygon aPolyPoly = ImplSubdivideBezier( rPolyPoly );
                ImplDrawPolyPolygon( aPolyPoly.Count(), aPolyPoly );
            }
        }
        else
        {
            mpGraphics->DrawPolyPolygon( j, pPointAry, pPointAryAry, this );
        }
    }

    if ( pPointAry != aStackAry1 )
    {
        delete[] pPointAry;
        delete[] pPointAryAry;
        delete[] pFlagAryAry;
    }
}

// =======================================================================

OutputDevice::OutputDevice() :
	maRegion( REGION_NULL ),
	maFillColor( COL_WHITE ),
	maTextLineColor( COL_TRANSPARENT ),
	maSettings( Application::GetSettings() )
{
	DBG_CTOR( OutputDevice, ImplDbgCheckOutputDevice );

	mpGraphics			= NULL;
	mpUnoGraphicsList	= NULL;
	mpPrevGraphics		= NULL;
	mpNextGraphics		= NULL;
	mpMetaFile			= NULL;
	mpFontEntry 		= NULL;
	mpFontCache 		= NULL;
	mpFontList			= NULL;
	mpGetDevFontList	= NULL;
	mpGetDevSizeList	= NULL;
	mpObjStack			= NULL;
	mpOutDevData		= NULL;
    mpPDFWriter			= NULL;
    mpAlphaVDev			= NULL;
	mpExtOutDevData		= NULL;
	mnOutOffX			= 0;
	mnOutOffY			= 0;
	mnOutWidth			= 0;
	mnOutHeight 		= 0;
	mnDPIX				= 0;
	mnDPIY				= 0;
	mnTextOffX			= 0;
	mnTextOffY			= 0;
	mnOutOffOrigX		= 0;
	mnOutOffLogicX		= 0;
	mnOutOffOrigY		= 0;
	mnOutOffLogicY		= 0;
	mnEmphasisAscent	= 0;
	mnEmphasisDescent	= 0;
	mnDrawMode			= 0;
	mnTextLayoutMode        = TEXT_LAYOUT_DEFAULT;
	if( Application::GetSettings().GetLayoutRTL() ) //#i84553# tip BiDi preference to RTL
		mnTextLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT;
	meOutDevType		= OUTDEV_DONTKNOW;
    meOutDevViewType    = OUTDEV_VIEWTYPE_DONTKNOW;
	mbMap				= sal_False;
	mbMapIsDefault		= sal_True;
	mbClipRegion		= sal_False;
	mbBackground		= sal_False;
	mbOutput			= sal_True;
	mbDevOutput 		= sal_False;
	mbOutputClipped 	= sal_False;
	maTextColor 		= Color( COL_BLACK );
	maOverlineColor 	= Color( COL_TRANSPARENT );
	meTextAlign 		= maFont.GetAlign();
	meRasterOp			= ROP_OVERPAINT;
	mnAntialiasing		= 0;
    meTextLanguage      = 0;  // TODO: get default from configuration?
	mbLineColor 		= sal_True;
	mbFillColor 		= sal_True;
	mbInitLineColor 	= sal_True;
	mbInitFillColor 	= sal_True;
	mbInitFont			= sal_True;
	mbInitTextColor 	= sal_True;
	mbInitClipRegion	= sal_True;
	mbClipRegionSet 	= sal_False;
	mbKerning			= sal_False;
	mbNewFont			= sal_True;
	mbTextLines 		= sal_False;
	mbTextSpecial		= sal_False;
	mbRefPoint			= sal_False;
    mbEnableRTL         = sal_False;    // mirroring must be explicitly allowed (typically for windows only)

	// struct ImplMapRes
    maMapRes.mnMapOfsX 			= 0;
    maMapRes.mnMapOfsY 			= 0;
    maMapRes.mnMapScNumX 		= 1;
    maMapRes.mnMapScNumY 		= 1;
    maMapRes.mnMapScDenomX 		= 1;
    maMapRes.mnMapScDenomY		= 1;
	// struct ImplThresholdRes
    maThresRes.mnThresLogToPixX	= 0;
    maThresRes.mnThresLogToPixY	= 0;
    maThresRes.mnThresPixToLogX	= 0;
    maThresRes.mnThresPixToLogY	= 0;
}

// -----------------------------------------------------------------------

OutputDevice::~OutputDevice()
{
	DBG_DTOR( OutputDevice, ImplDbgCheckOutputDevice );

	if ( GetUnoGraphicsList() )
	{
		UnoWrapperBase* pWrapper = Application::GetUnoWrapper( sal_False );
		if ( pWrapper )
			pWrapper->ReleaseAllGraphics( this );
		delete mpUnoGraphicsList;
		mpUnoGraphicsList = NULL;
	}

	if ( mpOutDevData )
		ImplDeInitOutDevData();

	ImplObjStack* pData = mpObjStack;
	if ( pData )
	{
		DBG_ERRORFILE( "OutputDevice::~OutputDevice(): OutputDevice::Push() calls != OutputDevice::Pop() calls" );
		while ( pData )
		{
			ImplObjStack* pTemp = pData;
			pData = pData->mpPrev;
			ImplDeleteObjStack( pTemp );
		}
	}

    // release the active font instance
    if( mpFontEntry )
        mpFontCache->Release( mpFontEntry );
    // remove cached results of GetDevFontList/GetDevSizeList
    // TODO: use smart pointers for them
    if( mpGetDevFontList )
        delete mpGetDevFontList;
    if( mpGetDevSizeList )
        delete mpGetDevSizeList;

    // release ImplFontCache specific to this OutputDevice
    // TODO: refcount ImplFontCache
    if( mpFontCache
    && (mpFontCache != ImplGetSVData()->maGDIData.mpScreenFontCache)
    && (ImplGetSVData()->maGDIData.mpScreenFontCache != NULL) )
    {
        delete mpFontCache;
        mpFontCache = NULL;
    }

    // release ImplFontList specific to this OutputDevice
    // TODO: refcount ImplFontList
    if( mpFontList
    && (mpFontList != ImplGetSVData()->maGDIData.mpScreenFontList)
    && (ImplGetSVData()->maGDIData.mpScreenFontList != NULL) )
    {
        mpFontList->Clear();
        delete mpFontList;
        mpFontList = NULL;
    }

    delete mpAlphaVDev;
}

bool OutputDevice::supportsOperation( OutDevSupportType eType ) const
{
	if( !mpGraphics )
		if( !ImplGetGraphics() )
			return false;
	const bool bHasSupport = mpGraphics->supportsOperation( eType );
	return bHasSupport;
}

// -----------------------------------------------------------------------

void OutputDevice::EnableRTL( sal_Bool bEnable )
{
    mbEnableRTL = (bEnable != 0);
    if( meOutDevType == OUTDEV_VIRDEV )
    {
        // virdevs default to not mirroring, they will only be set to mirroring
        // under rare circumstances in the UI, eg the valueset control
        // because each virdev has its own SalGraphics we can safely switch the SalGraphics here
        // ...hopefully
        if( ImplGetGraphics() )
            mpGraphics->SetLayout( mbEnableRTL ? SAL_LAYOUT_BIDI_RTL : 0 );
    }

    // convenience: for controls also switch layout mode
    if( dynamic_cast<Control*>(this) != 0 )
        SetLayoutMode( bEnable ? TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT : TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_TEXTORIGIN_LEFT);

    Window* pWin = dynamic_cast<Window*>(this);
    if( pWin )
        pWin->StateChanged( STATE_CHANGE_MIRRORING );
    
    if( mpAlphaVDev )
        mpAlphaVDev->EnableRTL( bEnable );
}

sal_Bool OutputDevice::ImplHasMirroredGraphics()
{
   // HOTFIX for #i55719#
   if( meOutDevType == OUTDEV_PRINTER )
       return sal_False;

   return ( ImplGetGraphics() && (mpGraphics->GetLayout() & SAL_LAYOUT_BIDI_RTL) );
}

// note: the coordiantes to be remirrored are in frame coordiantes !

void    OutputDevice::ImplReMirror( Point &rPoint ) const
{
    rPoint.X() = mnOutOffX + mnOutWidth - 1 - rPoint.X() + mnOutOffX;
}
void    OutputDevice::ImplReMirror( Rectangle &rRect ) const
{
    long nWidth = rRect.nRight - rRect.nLeft;

    //long lc_x = rRect.nLeft - mnOutOffX;    // normalize
    //lc_x = mnOutWidth - nWidth - 1 - lc_x;  // mirror
    //rRect.nLeft = lc_x + mnOutOffX;         // re-normalize

    rRect.nLeft = mnOutOffX + mnOutWidth - nWidth - 1 - rRect.nLeft + mnOutOffX;
    rRect.nRight = rRect.nLeft + nWidth;
}
void    OutputDevice::ImplReMirror( Region &rRegion ) const
{
	long				nX;
	long				nY;
	long				nWidth;
	long				nHeight;
	ImplRegionInfo		aInfo;
	sal_Bool				bRegionRect;
    Region              aMirroredRegion;

	bRegionRect = rRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
	while ( bRegionRect )
	{
        Rectangle aRect( Point(nX, nY), Size(nWidth, nHeight) );
        ImplReMirror( aRect );
        aMirroredRegion.Union( aRect );
		bRegionRect = rRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
	}
    rRegion = aMirroredRegion;
}


// -----------------------------------------------------------------------

int OutputDevice::ImplGetGraphics() const
{
	DBG_TESTSOLARMUTEX();

	if ( mpGraphics )
		return sal_True;

	mbInitLineColor 	= sal_True;
	mbInitFillColor 	= sal_True;
	mbInitFont			= sal_True;
	mbInitTextColor 	= sal_True;
	mbInitClipRegion	= sal_True;

	ImplSVData* pSVData = ImplGetSVData();
	if ( meOutDevType == OUTDEV_WINDOW )
	{
		Window* pWindow = (Window*)this;

		mpGraphics = pWindow->mpWindowImpl->mpFrame->GetGraphics();
        // try harder if no wingraphics was available directly
		if ( !mpGraphics )
		{
            // find another output device in the same frame
			OutputDevice* pReleaseOutDev = pSVData->maGDIData.mpLastWinGraphics;
			while ( pReleaseOutDev )
			{
				if ( ((Window*)pReleaseOutDev)->mpWindowImpl->mpFrame == pWindow->mpWindowImpl->mpFrame )
					break;
				pReleaseOutDev = pReleaseOutDev->mpPrevGraphics;
			}

			if ( pReleaseOutDev )
			{
                // steal the wingraphics from the other outdev
				mpGraphics = pReleaseOutDev->mpGraphics;
				pReleaseOutDev->ImplReleaseGraphics( sal_False );
			}
			else
			{
                // if needed retry after releasing least recently used wingraphics
				while ( !mpGraphics )
				{
					if ( !pSVData->maGDIData.mpLastWinGraphics )
						break;
					pSVData->maGDIData.mpLastWinGraphics->ImplReleaseGraphics();
					mpGraphics = pWindow->mpWindowImpl->mpFrame->GetGraphics();
				}
			}
		}

        // update global LRU list of wingraphics
		if ( mpGraphics )
		{
			mpNextGraphics = pSVData->maGDIData.mpFirstWinGraphics;
			pSVData->maGDIData.mpFirstWinGraphics = const_cast<OutputDevice*>(this);
			if ( mpNextGraphics )
				mpNextGraphics->mpPrevGraphics = const_cast<OutputDevice*>(this);
			if ( !pSVData->maGDIData.mpLastWinGraphics )
				pSVData->maGDIData.mpLastWinGraphics = const_cast<OutputDevice*>(this);
		}
	}
	else if ( meOutDevType == OUTDEV_VIRDEV )
	{
		const VirtualDevice* pVirDev = (const VirtualDevice*)this;

		if ( pVirDev->mpVirDev )
		{
			mpGraphics = pVirDev->mpVirDev->GetGraphics();
            // if needed retry after releasing least recently used virtual device graphics
			while ( !mpGraphics )
			{
				if ( !pSVData->maGDIData.mpLastVirGraphics )
					break;
				pSVData->maGDIData.mpLastVirGraphics->ImplReleaseGraphics();
				mpGraphics = pVirDev->mpVirDev->GetGraphics();
			}
            // update global LRU list of virtual device graphics
			if ( mpGraphics )
			{
				mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics;
				pSVData->maGDIData.mpFirstVirGraphics = const_cast<OutputDevice*>(this);
				if ( mpNextGraphics )
					mpNextGraphics->mpPrevGraphics = const_cast<OutputDevice*>(this);
				if ( !pSVData->maGDIData.mpLastVirGraphics )
					pSVData->maGDIData.mpLastVirGraphics = const_cast<OutputDevice*>(this);
			}
		}
	}
	else if ( meOutDevType == OUTDEV_PRINTER )
	{
		const Printer* pPrinter = (const Printer*)this;

		if ( pPrinter->mpJobGraphics )
			mpGraphics = pPrinter->mpJobGraphics;
		else if ( pPrinter->mpDisplayDev )
		{
			const VirtualDevice* pVirDev = pPrinter->mpDisplayDev;
			mpGraphics = pVirDev->mpVirDev->GetGraphics();
            // if needed retry after releasing least recently used virtual device graphics
			while ( !mpGraphics )
			{
				if ( !pSVData->maGDIData.mpLastVirGraphics )
					break;
				pSVData->maGDIData.mpLastVirGraphics->ImplReleaseGraphics();
				mpGraphics = pVirDev->mpVirDev->GetGraphics();
			}
            // update global LRU list of virtual device graphics
			if ( mpGraphics )
			{
				mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics;
				pSVData->maGDIData.mpFirstVirGraphics = const_cast<OutputDevice*>(this);
				if ( mpNextGraphics )
					mpNextGraphics->mpPrevGraphics = const_cast<OutputDevice*>(this);
				if ( !pSVData->maGDIData.mpLastVirGraphics )
					pSVData->maGDIData.mpLastVirGraphics = const_cast<OutputDevice*>(this);
			}
		}
		else
		{
			mpGraphics = pPrinter->mpInfoPrinter->GetGraphics();
            // if needed retry after releasing least recently used printer graphics
			while ( !mpGraphics )
			{
				if ( !pSVData->maGDIData.mpLastPrnGraphics )
					break;
				pSVData->maGDIData.mpLastPrnGraphics->ImplReleaseGraphics();
				mpGraphics = pPrinter->mpInfoPrinter->GetGraphics();
			}
            // update global LRU list of printer graphics
			if ( mpGraphics )
			{
				mpNextGraphics = pSVData->maGDIData.mpFirstPrnGraphics;
				pSVData->maGDIData.mpFirstPrnGraphics = const_cast<OutputDevice*>(this);
				if ( mpNextGraphics )
					mpNextGraphics->mpPrevGraphics = const_cast<OutputDevice*>(this);
				if ( !pSVData->maGDIData.mpLastPrnGraphics )
					pSVData->maGDIData.mpLastPrnGraphics = const_cast<OutputDevice*>(this);
			}
		}
	}

	if ( mpGraphics )
	{
		mpGraphics->SetXORMode( (ROP_INVERT == meRasterOp) || (ROP_XOR == meRasterOp), ROP_INVERT == meRasterOp );
        mpGraphics->setAntiAliasB2DDraw(mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW);
        return sal_True;
	}

	return sal_False;
}

// -----------------------------------------------------------------------

void OutputDevice::ImplReleaseGraphics( sal_Bool bRelease )
{
	DBG_TESTSOLARMUTEX();

	if ( !mpGraphics )
		return;

    // release the fonts of the physically released graphics device
    if( bRelease )
    {
#ifndef UNX
        // HACK to fix an urgent P1 printing issue fast
        // WinSalPrinter does not respect GetGraphics/ReleaseGraphics conventions
        // so Printer::mpGraphics often points to a dead WinSalGraphics
        // TODO: fix WinSalPrinter's GetGraphics/ReleaseGraphics handling
        if( meOutDevType != OUTDEV_PRINTER )
#endif
        mpGraphics->ReleaseFonts();

        mbNewFont = true;
        mbInitFont = true;

        if ( mpFontEntry )
        {
            mpFontCache->Release( mpFontEntry );
            mpFontEntry = NULL;
        }

        if ( mpGetDevFontList )
        {
            delete mpGetDevFontList;
            mpGetDevFontList = NULL;
        }

        if ( mpGetDevSizeList )
        {
            delete mpGetDevSizeList;
            mpGetDevSizeList = NULL;
        }
    }

	ImplSVData* pSVData = ImplGetSVData();
	if ( meOutDevType == OUTDEV_WINDOW )
	{
		Window* pWindow = (Window*)this;

		if ( bRelease )
			pWindow->mpWindowImpl->mpFrame->ReleaseGraphics( mpGraphics );
        // remove from global LRU list of window graphics
		if ( mpPrevGraphics )
			mpPrevGraphics->mpNextGraphics = mpNextGraphics;
		else
			pSVData->maGDIData.mpFirstWinGraphics = mpNextGraphics;
		if ( mpNextGraphics )
			mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
		else
			pSVData->maGDIData.mpLastWinGraphics = mpPrevGraphics;
	}
	else if ( meOutDevType == OUTDEV_VIRDEV )
	{
		VirtualDevice* pVirDev = (VirtualDevice*)this;

		if ( bRelease )
			pVirDev->mpVirDev->ReleaseGraphics( mpGraphics );
        // remove from global LRU list of virtual device graphics
		if ( mpPrevGraphics )
			mpPrevGraphics->mpNextGraphics = mpNextGraphics;
		else
			pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics;
		if ( mpNextGraphics )
			mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
		else
			pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics;
	}
	else if ( meOutDevType == OUTDEV_PRINTER )
	{
		Printer* pPrinter = (Printer*)this;

		if ( !pPrinter->mpJobGraphics )
		{
			if ( pPrinter->mpDisplayDev )
			{
				VirtualDevice* pVirDev = pPrinter->mpDisplayDev;
				if ( bRelease )
					pVirDev->mpVirDev->ReleaseGraphics( mpGraphics );
                // remove from global LRU list of virtual device graphics
				if ( mpPrevGraphics )
					mpPrevGraphics->mpNextGraphics = mpNextGraphics;
				else
					pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics;
				if ( mpNextGraphics )
					mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
				else
					pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics;
			}
			else
			{
				if ( bRelease )
					pPrinter->mpInfoPrinter->ReleaseGraphics( mpGraphics );
                // remove from global LRU list of printer graphics
				if ( mpPrevGraphics )
					mpPrevGraphics->mpNextGraphics = mpNextGraphics;
				else
					pSVData->maGDIData.mpFirstPrnGraphics = mpNextGraphics;
				if ( mpNextGraphics )
					mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
				else
					pSVData->maGDIData.mpLastPrnGraphics = mpPrevGraphics;
		   }
		}
	}

	mpGraphics		= NULL;
	mpPrevGraphics	= NULL;
	mpNextGraphics	= NULL;
}

// -----------------------------------------------------------------------

void OutputDevice::ImplInitOutDevData()
{
	if ( !mpOutDevData )
	{
		mpOutDevData = new ImplOutDevData;
		mpOutDevData->mpRotateDev = NULL;
        mpOutDevData->mpRecordLayout = NULL;

		// #i75163#
		mpOutDevData->mpViewTransform = NULL;
		mpOutDevData->mpInverseViewTransform = NULL;
	}
}

// -----------------------------------------------------------------------

// #i75163#
void OutputDevice::ImplInvalidateViewTransform()
{
	if(mpOutDevData)
	{
		if(mpOutDevData->mpViewTransform)
		{
			delete mpOutDevData->mpViewTransform;
			mpOutDevData->mpViewTransform = NULL;
		}

		if(mpOutDevData->mpInverseViewTransform)
		{
			delete mpOutDevData->mpInverseViewTransform;
			mpOutDevData->mpInverseViewTransform = NULL;
		}
	}
}

// -----------------------------------------------------------------------

sal_Bool OutputDevice::ImplIsRecordLayout() const
{
    return mpOutDevData && mpOutDevData->mpRecordLayout;
}

// -----------------------------------------------------------------------

void OutputDevice::ImplDeInitOutDevData()
{
	if ( mpOutDevData )
	{
		if ( mpOutDevData->mpRotateDev )
			delete mpOutDevData->mpRotateDev;

		// #i75163#
		ImplInvalidateViewTransform();

		delete mpOutDevData;
	}
}

// -----------------------------------------------------------------------

void OutputDevice::ImplInitLineColor()
{
	DBG_TESTSOLARMUTEX();

	if( mbLineColor )
	{
		if( ROP_0 == meRasterOp )
			mpGraphics->SetROPLineColor( SAL_ROP_0 );
		else if( ROP_1 == meRasterOp )
			mpGraphics->SetROPLineColor( SAL_ROP_1 );
		else if( ROP_INVERT == meRasterOp )
			mpGraphics->SetROPLineColor( SAL_ROP_INVERT );
		else
			mpGraphics->SetLineColor( ImplColorToSal( maLineColor ) );
	}
	else
		mpGraphics->SetLineColor();

	mbInitLineColor = sal_False;
}

// -----------------------------------------------------------------------

void OutputDevice::ImplInitFillColor()
{
	DBG_TESTSOLARMUTEX();

	if( mbFillColor )
	{
		if( ROP_0 == meRasterOp )
			mpGraphics->SetROPFillColor( SAL_ROP_0 );
		else if( ROP_1 == meRasterOp )
			mpGraphics->SetROPFillColor( SAL_ROP_1 );
		else if( ROP_INVERT == meRasterOp )
			mpGraphics->SetROPFillColor( SAL_ROP_INVERT );
		else
			mpGraphics->SetFillColor( ImplColorToSal( maFillColor ) );
	}
	else
		mpGraphics->SetFillColor();

	mbInitFillColor = sal_False;
}

// -----------------------------------------------------------------------

void OutputDevice::ImplInitClipRegion()
{
	DBG_TESTSOLARMUTEX();

	if ( GetOutDevType() == OUTDEV_WINDOW )
	{
		Window* pWindow = (Window*)this;
		Region	aRegion;

		// Hintergrund-Sicherung zuruecksetzen
		if ( pWindow->mpWindowImpl->mpFrameData->mpFirstBackWin )
			pWindow->ImplInvalidateAllOverlapBackgrounds();
		if ( pWindow->mpWindowImpl->mbInPaint )
			aRegion = *(pWindow->mpWindowImpl->mpPaintRegion);
		else
        {
			aRegion = *(pWindow->ImplGetWinChildClipRegion());
            // --- RTL -- only this region is in frame coordinates, so re-mirror it
            // the mpWindowImpl->mpPaintRegion above is already correct (see ImplCallPaint()) !
            if( ImplIsAntiparallel() )
	            ImplReMirror ( aRegion );
        }
		if ( mbClipRegion )
			aRegion.Intersect( ImplPixelToDevicePixel( maRegion ) );
		if ( aRegion.IsEmpty() )
			mbOutputClipped = sal_True;
		else
		{
			mbOutputClipped = sal_False;
			ImplSelectClipRegion( aRegion );
		}
		mbClipRegionSet = sal_True;
	}
	else
	{
		if ( mbClipRegion )
		{
			if ( maRegion.IsEmpty() )
				mbOutputClipped = sal_True;
			else
			{
				mbOutputClipped = sal_False;
            
				// #102532# Respect output offset also for clip region
                Region aRegion( ImplPixelToDevicePixel( maRegion ) );
                const bool bClipDeviceBounds( ! GetPDFWriter()
                                              && GetOutDevType() != OUTDEV_PRINTER );
                if( bClipDeviceBounds )
                {
                    // #b6520266# Perform actual rect clip against outdev
                    // dimensions, to generate empty clips whenever one of the
                    // values is completely off the device.
                    Rectangle aDeviceBounds( mnOutOffX, mnOutOffY,
                                             mnOutOffX+GetOutputWidthPixel()-1,
                                             mnOutOffY+GetOutputHeightPixel()-1 );
                    aRegion.Intersect( aDeviceBounds );
                }
                ImplSelectClipRegion( aRegion );
			}

			mbClipRegionSet = sal_True;
		}
		else
		{
			if ( mbClipRegionSet )
			{
				mpGraphics->ResetClipRegion();
				mbClipRegionSet = sal_False;
			}

			mbOutputClipped = sal_False;
		}
	}

	mbInitClipRegion = sal_False;
}

// -----------------------------------------------------------------------

void OutputDevice::ImplSetClipRegion( const Region* pRegion )
{
	DBG_TESTSOLARMUTEX();

	if ( !pRegion )
	{
		if ( mbClipRegion )
		{
			maRegion			= Region( REGION_NULL );
			mbClipRegion		= sal_False;
			mbInitClipRegion	= sal_True;
		}
	}
	else
	{
		maRegion			= *pRegion;
		mbClipRegion		= sal_True;
		mbInitClipRegion	= sal_True;
	}
}

// -----------------------------------------------------------------------

void OutputDevice::SetClipRegion()
{
	DBG_TRACE( "OutputDevice::SetClipRegion()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaClipRegionAction( Region(), sal_False ) );

	ImplSetClipRegion( NULL );

    if( mpAlphaVDev )
        mpAlphaVDev->SetClipRegion();
}

// -----------------------------------------------------------------------

void OutputDevice::SetClipRegion( const Region& rRegion )
{
	DBG_TRACE( "OutputDevice::SetClipRegion( rRegion )" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
	DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaClipRegionAction( rRegion, sal_True ) );

	if ( rRegion.GetType() == REGION_NULL )
		ImplSetClipRegion( NULL );
	else
	{
		Region aRegion = LogicToPixel( rRegion );
		ImplSetClipRegion( &aRegion );
	}

    if( mpAlphaVDev )
        mpAlphaVDev->SetClipRegion( rRegion );
}

// -----------------------------------------------------------------------

Region OutputDevice::GetClipRegion() const
{
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	return PixelToLogic( maRegion );
}

// -----------------------------------------------------------------------

Region OutputDevice::GetActiveClipRegion() const
{
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( GetOutDevType() == OUTDEV_WINDOW )
	{
		Region aRegion( REGION_NULL );
		Window* pWindow = (Window*)this;
		if ( pWindow->mpWindowImpl->mbInPaint )
		{
			aRegion = *(pWindow->mpWindowImpl->mpPaintRegion);
			aRegion.Move( -mnOutOffX, -mnOutOffY );
		}
		if ( mbClipRegion )
			aRegion.Intersect( maRegion );
		return PixelToLogic( aRegion );
	}
	else
		return GetClipRegion();
}

// -----------------------------------------------------------------------

void OutputDevice::MoveClipRegion( long nHorzMove, long nVertMove )
{
	DBG_TRACE( "OutputDevice::MoveClipRegion()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( mbClipRegion )
	{
		if( mpMetaFile )
			mpMetaFile->AddAction( new MetaMoveClipRegionAction( nHorzMove, nVertMove ) );

		maRegion.Move( ImplLogicWidthToDevicePixel( nHorzMove ),
					   ImplLogicHeightToDevicePixel( nVertMove ) );
		mbInitClipRegion = sal_True;
	}

    if( mpAlphaVDev )
        mpAlphaVDev->MoveClipRegion( nHorzMove, nVertMove );
}

// -----------------------------------------------------------------------

void OutputDevice::IntersectClipRegion( const Rectangle& rRect )
{
	DBG_TRACE( "OutputDevice::IntersectClipRegion( rRect )" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaISectRectClipRegionAction( rRect ) );

	Rectangle aRect = LogicToPixel( rRect );
	maRegion.Intersect( aRect );
	mbClipRegion		= sal_True;
	mbInitClipRegion	= sal_True;

    if( mpAlphaVDev )
        mpAlphaVDev->IntersectClipRegion( rRect );
}

// -----------------------------------------------------------------------

void OutputDevice::IntersectClipRegion( const Region& rRegion )
{
	DBG_TRACE( "OutputDevice::IntersectClipRegion( rRegion )" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
	DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );

	RegionType eType = rRegion.GetType();

	if ( eType != REGION_NULL )
	{
		if ( mpMetaFile )
			mpMetaFile->AddAction( new MetaISectRegionClipRegionAction( rRegion ) );

		Region aRegion = LogicToPixel( rRegion );
		maRegion.Intersect( aRegion );
		mbClipRegion		= sal_True;
		mbInitClipRegion	= sal_True;
	}

    if( mpAlphaVDev )
        mpAlphaVDev->IntersectClipRegion( rRegion );
}

// -----------------------------------------------------------------------

void OutputDevice::SetDrawMode( sal_uLong nDrawMode )
{
	DBG_TRACE1( "OutputDevice::SetDrawMode( %lx )", nDrawMode );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	mnDrawMode = nDrawMode;

    if( mpAlphaVDev )
        mpAlphaVDev->SetDrawMode( nDrawMode );
}

// -----------------------------------------------------------------------

void OutputDevice::SetRasterOp( RasterOp eRasterOp )
{
	DBG_TRACE1( "OutputDevice::SetRasterOp( %d )", (int)eRasterOp );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaRasterOpAction( eRasterOp ) );

	if ( meRasterOp != eRasterOp )
	{
		meRasterOp = eRasterOp;
		mbInitLineColor = mbInitFillColor = sal_True;

		if( mpGraphics || ImplGetGraphics() )
			mpGraphics->SetXORMode( (ROP_INVERT == meRasterOp) || (ROP_XOR == meRasterOp), ROP_INVERT == meRasterOp );
	}

    if( mpAlphaVDev )
        mpAlphaVDev->SetRasterOp( eRasterOp );
}

// -----------------------------------------------------------------------

void OutputDevice::SetLineColor()
{
	DBG_TRACE( "OutputDevice::SetLineColor()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaLineColorAction( Color(), sal_False ) );

	if ( mbLineColor )
	{
		mbInitLineColor = sal_True;
		mbLineColor = sal_False;
		maLineColor = Color( COL_TRANSPARENT );
	}

    if( mpAlphaVDev )
        mpAlphaVDev->SetLineColor();
}

// -----------------------------------------------------------------------

void OutputDevice::SetLineColor( const Color& rColor )
{
	DBG_TRACE1( "OutputDevice::SetLineColor( %lx )", rColor.GetColor() );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	Color aColor( rColor );

	if( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE |
					   DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE |
                       DRAWMODE_SETTINGSLINE ) )
	{
		if( !ImplIsColorTransparent( aColor ) )
		{
			if( mnDrawMode & DRAWMODE_BLACKLINE )
			{
				aColor = Color( COL_BLACK );
			}
			else if( mnDrawMode & DRAWMODE_WHITELINE )
			{
				aColor = Color( COL_WHITE );
			}
			else if( mnDrawMode & DRAWMODE_GRAYLINE )
			{
				const sal_uInt8 cLum = aColor.GetLuminance();
				aColor = Color( cLum, cLum, cLum );
			}
            else if( mnDrawMode & DRAWMODE_SETTINGSLINE )
            {
                aColor = GetSettings().GetStyleSettings().GetFontColor();
            }

			if( mnDrawMode & DRAWMODE_GHOSTEDLINE )
			{
				aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
								( aColor.GetGreen() >> 1 ) | 0x80,
								( aColor.GetBlue() >> 1 ) | 0x80);
			}
		}
	}

	if( mpMetaFile )
		mpMetaFile->AddAction( new MetaLineColorAction( aColor, sal_True ) );

	if( ImplIsColorTransparent( aColor ) )
	{
		if ( mbLineColor )
		{
			mbInitLineColor = sal_True;
			mbLineColor = sal_False;
			maLineColor = Color( COL_TRANSPARENT );
		}
	}
	else
	{
		if( maLineColor != aColor )
		{
			mbInitLineColor = sal_True;
			mbLineColor = sal_True;
			maLineColor = aColor;
		}
	}

    if( mpAlphaVDev )
        mpAlphaVDev->SetLineColor( COL_BLACK );
}

// -----------------------------------------------------------------------

void OutputDevice::SetFillColor()
{
	DBG_TRACE( "OutputDevice::SetFillColor()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaFillColorAction( Color(), sal_False ) );

	if ( mbFillColor )
	{
		mbInitFillColor = sal_True;
		mbFillColor = sal_False;
		maFillColor = Color( COL_TRANSPARENT );
	}

    if( mpAlphaVDev )
        mpAlphaVDev->SetFillColor();
}

// -----------------------------------------------------------------------

void OutputDevice::SetFillColor( const Color& rColor )
{
	DBG_TRACE1( "OutputDevice::SetFillColor( %lx )", rColor.GetColor() );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	Color aColor( rColor );

	if( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL |
					   DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
					   DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
	{
		if( !ImplIsColorTransparent( aColor ) )
		{
			if( mnDrawMode & DRAWMODE_BLACKFILL )
			{
				aColor = Color( COL_BLACK );
			}
			else if( mnDrawMode & DRAWMODE_WHITEFILL )
			{
				aColor = Color( COL_WHITE );
			}
			else if( mnDrawMode & DRAWMODE_GRAYFILL )
			{
				const sal_uInt8 cLum = aColor.GetLuminance();
				aColor = Color( cLum, cLum, cLum );
			}
			else if( mnDrawMode & DRAWMODE_NOFILL )
			{
				aColor = Color( COL_TRANSPARENT );
			}
            else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
            {
                aColor = GetSettings().GetStyleSettings().GetWindowColor();
            }

			if( mnDrawMode & DRAWMODE_GHOSTEDFILL )
			{
				aColor = Color( (aColor.GetRed() >> 1) | 0x80,
								(aColor.GetGreen() >> 1) | 0x80,
								(aColor.GetBlue() >> 1) | 0x80);
			}
		}
	}

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaFillColorAction( aColor, sal_True ) );

	if ( ImplIsColorTransparent( aColor ) )
	{
		if ( mbFillColor )
		{
			mbInitFillColor = sal_True;
			mbFillColor = sal_False;
			maFillColor = Color( COL_TRANSPARENT );
		}
	}
	else
	{
		if ( maFillColor != aColor )
		{
			mbInitFillColor = sal_True;
			mbFillColor = sal_True;
			maFillColor = aColor;
		}
	}

    if( mpAlphaVDev )
        mpAlphaVDev->SetFillColor( COL_BLACK );
}

// -----------------------------------------------------------------------

void OutputDevice::SetBackground()
{
	DBG_TRACE( "OutputDevice::SetBackground()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	maBackground = Wallpaper();
	mbBackground = sal_False;

    if( mpAlphaVDev )
        mpAlphaVDev->SetBackground();
}

// -----------------------------------------------------------------------

void OutputDevice::SetBackground( const Wallpaper& rBackground )
{
	DBG_TRACE( "OutputDevice::SetBackground( rBackground )" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	maBackground = rBackground;

	if( rBackground.GetStyle() == WALLPAPER_NULL )
		mbBackground = sal_False;
	else
		mbBackground = sal_True;

    if( mpAlphaVDev )
        mpAlphaVDev->SetBackground( rBackground );
}

// -----------------------------------------------------------------------

void OutputDevice::SetRefPoint()
{
	DBG_TRACE( "OutputDevice::SetRefPoint()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaRefPointAction( Point(), sal_False ) );

	mbRefPoint = sal_False;
	maRefPoint.X() = maRefPoint.Y() = 0L;

    if( mpAlphaVDev )
        mpAlphaVDev->SetRefPoint();
}

// -----------------------------------------------------------------------

void OutputDevice::SetRefPoint( const Point& rRefPoint )
{
	DBG_TRACE( "OutputDevice::SetRefPoint( rRefPoint )" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaRefPointAction( rRefPoint, sal_True ) );

	mbRefPoint = sal_True;
	maRefPoint = rRefPoint;

    if( mpAlphaVDev )
        mpAlphaVDev->SetRefPoint( rRefPoint );
}

// -----------------------------------------------------------------------

void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt )
{
	DBG_TRACE( "OutputDevice::DrawLine()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaLineAction( rStartPt, rEndPt ) );

	if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() )
		return;

	if ( !mpGraphics )
	{
		if ( !ImplGetGraphics() )
			return;
	}

	if ( mbInitClipRegion )
		ImplInitClipRegion();
	if ( mbOutputClipped )
		return;

	if ( mbInitLineColor )
		ImplInitLineColor();

	// #i101598# support AA and snap for lines, too
	if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) 
		&& mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
		&& ROP_OVERPAINT == GetRasterOp()
		&& IsLineColor())
	{
		// at least transform with double precision to device coordinates; this will
		// avoid pixel snap of single, appended lines
		const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation());
        const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
		basegfx::B2DPolygon aB2DPolyLine;

		aB2DPolyLine.append(basegfx::B2DPoint(rStartPt.X(), rStartPt.Y()));
		aB2DPolyLine.append(basegfx::B2DPoint(rEndPt.X(), rEndPt.Y()));
		aB2DPolyLine.transform( aTransform );

        if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE)
        {
            aB2DPolyLine = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine);
        }

		if( mpGraphics->DrawPolyLine( aB2DPolyLine, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this))
		{
			return;
		}
	}

	const Point aStartPt(ImplLogicToDevicePixel(rStartPt));
	const Point aEndPt(ImplLogicToDevicePixel(rEndPt));

	mpGraphics->DrawLine( aStartPt.X(), aStartPt.Y(), aEndPt.X(), aEndPt.Y(), this );

    if( mpAlphaVDev )
        mpAlphaVDev->DrawLine( rStartPt, rEndPt );
}

// -----------------------------------------------------------------------

void OutputDevice::impPaintLineGeometryWithEvtlExpand(
    const LineInfo& rInfo,
    basegfx::B2DPolyPolygon aLinePolyPolygon)
{
    const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) 
        && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
        && ROP_OVERPAINT == GetRasterOp()
        && IsLineColor());
    basegfx::B2DPolyPolygon aFillPolyPolygon;
    const bool bDashUsed(LINE_DASH == rInfo.GetStyle());
    const bool bLineWidthUsed(rInfo.GetWidth() > 1);

    if(bDashUsed && aLinePolyPolygon.count())
    {
        ::std::vector< double > fDotDashArray;
        const double fDashLen(rInfo.GetDashLen());
        const double fDotLen(rInfo.GetDotLen());
        const double fDistance(rInfo.GetDistance());

        for(sal_uInt16 a(0); a < rInfo.GetDashCount(); a++)
        {
            fDotDashArray.push_back(fDashLen);
            fDotDashArray.push_back(fDistance);
        }

        for(sal_uInt16 b(0); b < rInfo.GetDotCount(); b++)
        {
            fDotDashArray.push_back(fDotLen);
            fDotDashArray.push_back(fDistance);
        }

        const double fAccumulated(::std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0));

        if(fAccumulated > 0.0)
        {
            basegfx::B2DPolyPolygon aResult;

            for(sal_uInt32 c(0); c < aLinePolyPolygon.count(); c++)
            {
                basegfx::B2DPolyPolygon aLineTraget;
                basegfx::tools::applyLineDashing(
                    aLinePolyPolygon.getB2DPolygon(c),
                    fDotDashArray,
                    &aLineTraget);
                aResult.append(aLineTraget);
            }

            aLinePolyPolygon = aResult;
        }
    }

    if(bLineWidthUsed && aLinePolyPolygon.count())
    {
	    const double fHalfLineWidth((rInfo.GetWidth() * 0.5) + 0.5);

		if(aLinePolyPolygon.areControlPointsUsed())
		{
			// #i110768# When area geometry has to be created, do not
			// use the fallback bezier decomposition inside createAreaGeometry,
			// but one that is at least as good as ImplSubdivideBezier was.
			// There, Polygon::AdaptiveSubdivide was used with default parameter 
			// 1.0 as quality index.
			aLinePolyPolygon = basegfx::tools::adaptiveSubdivideByDistance(aLinePolyPolygon, 1.0);
		}
        
        for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++)
        {
	        aFillPolyPolygon.append(basegfx::tools::createAreaGeometry(
                aLinePolyPolygon.getB2DPolygon(a), 
                fHalfLineWidth, 
                rInfo.GetLineJoin()));
        }
        
        aLinePolyPolygon.clear();
    }

    GDIMetaFile* pOldMetaFile = mpMetaFile;
    mpMetaFile = NULL;

    if(aLinePolyPolygon.count())
    {
        for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++)
        {
            const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a));
            bool bDone(false);

            if(bTryAA)
            {
                bDone = mpGraphics->DrawPolyLine( aCandidate, 0.0, basegfx::B2DVector(1.0,1.0), basegfx::B2DLINEJOIN_NONE, this);
            }

            if(!bDone)
            {
                const Polygon aPolygon(aCandidate);
		        mpGraphics->DrawPolyLine(aPolygon.GetSize(), (const SalPoint*)aPolygon.GetConstPointAry(), this);
            }
        }
    }

    if(aFillPolyPolygon.count())
    {
        const Color 	aOldLineColor( maLineColor );
        const Color 	aOldFillColor( maFillColor );

        SetLineColor();
        ImplInitLineColor();
        SetFillColor( aOldLineColor );
        ImplInitFillColor();

        bool bDone(false);
        
        if(bTryAA)
        {
            bDone = mpGraphics->DrawPolyPolygon(aFillPolyPolygon, 0.0, this);
        }

        if(!bDone)
        {
            for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++)
            {
                const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
			    mpGraphics->DrawPolygon(aPolygon.GetSize(), (const SalPoint*)aPolygon.GetConstPointAry(), this);
            }
        }
        
        SetFillColor( aOldFillColor );
        SetLineColor( aOldLineColor );
    }

    mpMetaFile = pOldMetaFile;
}

// -----------------------------------------------------------------------

void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt,
							 const LineInfo& rLineInfo )
{
	DBG_TRACE( "OutputDevice::DrawLine()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( rLineInfo.IsDefault() )
	{
		DrawLine( rStartPt, rEndPt );
		return;
	}

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaLineAction( rStartPt, rEndPt, rLineInfo ) );

	if ( !IsDeviceOutputNecessary() || !mbLineColor || ( LINE_NONE == rLineInfo.GetStyle() ) || ImplIsRecordLayout() )
		return;

	if( !mpGraphics && !ImplGetGraphics() )
		return;

	if ( mbInitClipRegion )
		ImplInitClipRegion();

	if ( mbOutputClipped )
		return;

	const Point aStartPt( ImplLogicToDevicePixel( rStartPt ) );
	const Point aEndPt( ImplLogicToDevicePixel( rEndPt ) );
	const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) );
    const bool bDashUsed(LINE_DASH == aInfo.GetStyle());
    const bool bLineWidthUsed(aInfo.GetWidth() > 1);

    if ( mbInitLineColor )
        ImplInitLineColor();

    if(bDashUsed || bLineWidthUsed)
    {
        basegfx::B2DPolygon aLinePolygon;
        aLinePolygon.append(basegfx::B2DPoint(aStartPt.X(), aStartPt.Y()));
        aLinePolygon.append(basegfx::B2DPoint(aEndPt.X(), aEndPt.Y()));

        impPaintLineGeometryWithEvtlExpand(aInfo, basegfx::B2DPolyPolygon(aLinePolygon));
    }
	else
	{
		mpGraphics->DrawLine( aStartPt.X(), aStartPt.Y(), aEndPt.X(), aEndPt.Y(), this );
	}

    if( mpAlphaVDev )
        mpAlphaVDev->DrawLine( rStartPt, rEndPt, rLineInfo );
}

// -----------------------------------------------------------------------

void OutputDevice::DrawRect( const Rectangle& rRect )
{
	DBG_TRACE( "OutputDevice::DrawRect()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaRectAction( rRect ) );

	if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || ImplIsRecordLayout() )
		return;

	Rectangle aRect( ImplLogicToDevicePixel( rRect ) );

	if ( aRect.IsEmpty() )
		return;
	aRect.Justify();

	if ( !mpGraphics )
	{
		if ( !ImplGetGraphics() )
			return;
	}

	if ( mbInitClipRegion )
		ImplInitClipRegion();
	if ( mbOutputClipped )
		return;

	if ( mbInitLineColor )
		ImplInitLineColor();
	if ( mbInitFillColor )
		ImplInitFillColor();

	mpGraphics->DrawRect( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), this );

    if( mpAlphaVDev )
        mpAlphaVDev->DrawRect( rRect );
}

// -----------------------------------------------------------------------

void OutputDevice::DrawPolyLine( const Polygon& rPoly )
{
	DBG_TRACE( "OutputDevice::DrawPolyLine()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
	DBG_CHKOBJ( &rPoly, Polygon, NULL );

	if( mpMetaFile )
		mpMetaFile->AddAction( new MetaPolyLineAction( rPoly ) );

	sal_uInt16 nPoints = rPoly.GetSize();

	if ( !IsDeviceOutputNecessary() || !mbLineColor || (nPoints < 2) || ImplIsRecordLayout() )
		return;

	// we need a graphics
	if ( !mpGraphics )
		if ( !ImplGetGraphics() )
			return;

	if ( mbInitClipRegion )
		ImplInitClipRegion();
	if ( mbOutputClipped )
		return;

	if ( mbInitLineColor )
		ImplInitLineColor();

    const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) 
        && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
        && ROP_OVERPAINT == GetRasterOp()
        && IsLineColor());

	// use b2dpolygon drawing if possible
	if(bTryAA && ImpTryDrawPolyLineDirect(rPoly.getB2DPolygon(), 0.0, basegfx::B2DLINEJOIN_NONE))
	{
		basegfx::B2DPolygon aB2DPolyLine(rPoly.getB2DPolygon());
		const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
        const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );

        // transform the polygon
		aB2DPolyLine.transform( aTransform );

        if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE)
        {
            aB2DPolyLine = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine);
        }

		if(mpGraphics->DrawPolyLine( aB2DPolyLine, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this))
		{
			return;
		}
	}

	Polygon aPoly = ImplLogicToDevicePixel( rPoly );
    const SalPoint* pPtAry = (const SalPoint*)aPoly.GetConstPointAry();

    // #100127# Forward beziers to sal, if any
    if( aPoly.HasFlags() )
    {
        const sal_uInt8* pFlgAry = aPoly.GetConstFlagAry();
        if( !mpGraphics->DrawPolyLineBezier( nPoints, pPtAry, pFlgAry, this ) )
        {
            aPoly = ImplSubdivideBezier(aPoly);
            pPtAry = (const SalPoint*)aPoly.GetConstPointAry();
            mpGraphics->DrawPolyLine( aPoly.GetSize(), pPtAry, this );
        }
    }
    else
    {
        mpGraphics->DrawPolyLine( nPoints, pPtAry, this );
    }

    if( mpAlphaVDev )
        mpAlphaVDev->DrawPolyLine( rPoly );
}

// -----------------------------------------------------------------------

void OutputDevice::DrawPolyLine( const Polygon& rPoly, const LineInfo& rLineInfo )
{
	DBG_TRACE( "OutputDevice::DrawPolyLine()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
	DBG_CHKOBJ( &rPoly, Polygon, NULL );

	if ( rLineInfo.IsDefault() )
	{
		DrawPolyLine( rPoly );
		return;
	}

    // #i101491#
    // Try direct Fallback to B2D-Version of DrawPolyLine
    if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) 
        && LINE_SOLID == rLineInfo.GetStyle())
    {
		DrawPolyLine( rPoly.getB2DPolygon(), (double)rLineInfo.GetWidth(), rLineInfo.GetLineJoin());
		return;
    }

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaPolyLineAction( rPoly, rLineInfo ) );

    ImpDrawPolyLineWithLineInfo(rPoly, rLineInfo);
}

void OutputDevice::ImpDrawPolyLineWithLineInfo(const Polygon& rPoly, const LineInfo& rLineInfo)
{
	sal_uInt16 nPoints(rPoly.GetSize());

	if ( !IsDeviceOutputNecessary() || !mbLineColor || ( nPoints < 2 ) || ( LINE_NONE == rLineInfo.GetStyle() ) || ImplIsRecordLayout() )
		return;

    Polygon aPoly = ImplLogicToDevicePixel( rPoly );

    // #100127# LineInfo is not curve-safe, subdivide always
    // 
    // What shall this mean? It's wrong to subdivide here when the
    // polygon is a fat line. In that case, the painted geometry
    // WILL be much different.
    // I also have no idea how this could be related to the given ID
    // which reads 'consolidate boost versions' in the task description.
    // Removing.
    //
    //if( aPoly.HasFlags() )
    //{
    //    aPoly = ImplSubdivideBezier( aPoly );
    //    nPoints = aPoly.GetSize();
    //}

	// we need a graphics
	if ( !mpGraphics && !ImplGetGraphics() )
		return;

	if ( mbInitClipRegion )
		ImplInitClipRegion();

	if ( mbOutputClipped )
		return;

	if ( mbInitLineColor )
		ImplInitLineColor();

    const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) );
    const bool bDashUsed(LINE_DASH == aInfo.GetStyle());
    const bool bLineWidthUsed(aInfo.GetWidth() > 1);

    if(bDashUsed || bLineWidthUsed)
    {
        impPaintLineGeometryWithEvtlExpand(aInfo, basegfx::B2DPolyPolygon(aPoly.getB2DPolygon()));
    }
    else
    {
        // #100127# the subdivision HAS to be done here since only a pointer
        // to an array of points is given to the DrawPolyLine method, there is
        // NO way to find out there that it's a curve.
        if( aPoly.HasFlags() )
        {
            aPoly = ImplSubdivideBezier( aPoly );
            nPoints = aPoly.GetSize();
        }
		
        mpGraphics->DrawPolyLine(nPoints, (const SalPoint*)aPoly.GetConstPointAry(), this);
    }

    if( mpAlphaVDev )
        mpAlphaVDev->DrawPolyLine( rPoly, rLineInfo );
}

// -----------------------------------------------------------------------

void OutputDevice::DrawPolygon( const Polygon& rPoly )
{
	DBG_TRACE( "OutputDevice::DrawPolygon()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
	DBG_CHKOBJ( &rPoly, Polygon, NULL );

	if( mpMetaFile )
		mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) );

	sal_uInt16 nPoints = rPoly.GetSize();

	if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || (nPoints < 2) || ImplIsRecordLayout() )
		return;

	// we need a graphics
	if ( !mpGraphics )
		if ( !ImplGetGraphics() )
			return;

	if ( mbInitClipRegion )
		ImplInitClipRegion();
	if ( mbOutputClipped )
		return;

	if ( mbInitLineColor )
		ImplInitLineColor();
	if ( mbInitFillColor )
		ImplInitFillColor();

	// use b2dpolygon drawing if possible
	if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) 
		&& mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
		&& ROP_OVERPAINT == GetRasterOp()
		&& (IsLineColor() || IsFillColor()))
	{
		const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
		basegfx::B2DPolygon aB2DPolygon(rPoly.getB2DPolygon());
		bool bSuccess(true);

        // transform the polygon and ensure closed
		aB2DPolygon.transform(aTransform);
        aB2DPolygon.setClosed(true);

		if(IsFillColor())
		{
			bSuccess = mpGraphics->DrawPolyPolygon(basegfx::B2DPolyPolygon(aB2DPolygon), 0.0, this);
		}

		if(bSuccess && IsLineColor())
		{
			const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );

			if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE)
			{
				aB2DPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon);
			}

			bSuccess = mpGraphics->DrawPolyLine( aB2DPolygon, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this);
		}

		if(bSuccess)
		{
			return;
		}
	}

	Polygon aPoly = ImplLogicToDevicePixel( rPoly );
	const SalPoint* pPtAry = (const SalPoint*)aPoly.GetConstPointAry();

    // #100127# Forward beziers to sal, if any
    if( aPoly.HasFlags() )
    {
        const sal_uInt8* pFlgAry = aPoly.GetConstFlagAry();
        if( !mpGraphics->DrawPolygonBezier( nPoints, pPtAry, pFlgAry, this ) )
        {
            aPoly = ImplSubdivideBezier(aPoly);
            pPtAry = (const SalPoint*)aPoly.GetConstPointAry();
            mpGraphics->DrawPolygon( aPoly.GetSize(), pPtAry, this );
        }
    }
    else
    {
        mpGraphics->DrawPolygon( nPoints, pPtAry, this );
    }
    if( mpAlphaVDev )
        mpAlphaVDev->DrawPolygon( rPoly );
}

// -----------------------------------------------------------------------

void OutputDevice::DrawPolyPolygon( const PolyPolygon& rPolyPoly )
{
	DBG_TRACE( "OutputDevice::DrawPolyPolygon()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
	DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );

	if( mpMetaFile )
		mpMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) );

	sal_uInt16 nPoly = rPolyPoly.Count();

	if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || !nPoly || ImplIsRecordLayout() )
		return;

	// we need a graphics
	if ( !mpGraphics )
		if ( !ImplGetGraphics() )
			return;

	if ( mbInitClipRegion )
		ImplInitClipRegion();
	if ( mbOutputClipped )
		return;

	if ( mbInitLineColor )
		ImplInitLineColor();
	if ( mbInitFillColor )
		ImplInitFillColor();

	// use b2dpolygon drawing if possible
	if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) 
		&& mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
		&& ROP_OVERPAINT == GetRasterOp()
		&& (IsLineColor() || IsFillColor()))
	{
		const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
		basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPoly.getB2DPolyPolygon());
		bool bSuccess(true);

		// transform the polygon and ensure closed
		aB2DPolyPolygon.transform(aTransform);
        aB2DPolyPolygon.setClosed(true);

		if(IsFillColor())
		{
			bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this);
		}

		if(bSuccess && IsLineColor())
		{
			const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );

			if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE)
			{
				aB2DPolyPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon);
			}

			for(sal_uInt32 a(0); bSuccess && a < aB2DPolyPolygon.count(); a++)
			{
				bSuccess = mpGraphics->DrawPolyLine( aB2DPolyPolygon.getB2DPolygon(a), 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this);
			}
		}

		if(bSuccess)
		{
			return;
		}
	}

	if ( nPoly == 1 )
	{
        // #100127# Map to DrawPolygon
        Polygon aPoly = rPolyPoly.GetObject( 0 );
		if( aPoly.GetSize() >= 2 )
        {
            GDIMetaFile* pOldMF = mpMetaFile;
            mpMetaFile = NULL;

			DrawPolygon( aPoly );

            mpMetaFile = pOldMF;
        }
	}
	else
	{
        // #100127# moved real PolyPolygon draw to separate method,
        // have to call recursively, avoiding duplicate
        // ImplLogicToDevicePixel calls
        ImplDrawPolyPolygon( nPoly, ImplLogicToDevicePixel( rPolyPoly ) );
	}
    if( mpAlphaVDev )
        mpAlphaVDev->DrawPolyPolygon( rPolyPoly );
}

// -----------------------------------------------------------------------

void OutputDevice::DrawPolygon( const ::basegfx::B2DPolygon& rB2DPolygon)
{
    // AW: Do NOT paint empty polygons
    if(rB2DPolygon.count())
    {
        ::basegfx::B2DPolyPolygon aPP( rB2DPolygon );
        DrawPolyPolygon( aPP );
    }
}

// -----------------------------------------------------------------------
// Caution: This method is nearly the same as
// OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency),
// so when changes are made here do not forget to make change sthere, too

void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly )
{
	DBG_TRACE( "OutputDevice::DrawPolyPolygon(B2D&)" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

#if 0
    // MetaB2DPolyPolygonAction is not implemented yet:
    // according to AW adding it is very dangerous since there is a lot
    // of code that uses the metafile actions directly and unless every
    // place that does this knows about the new action we need to fallback
    if( mpMetaFile )
        mpMetaFile->AddAction( new MetaB2DPolyPolygonAction( rB2DPolyPoly ) );
#else
    if( mpMetaFile )
        mpMetaFile->AddAction( new MetaPolyPolygonAction( PolyPolygon( rB2DPolyPoly ) ) );
#endif

	// call helper
	ImpDrawPolyPolygonWithB2DPolyPolygon(rB2DPolyPoly);
}

void OutputDevice::ImpDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyPolygon& rB2DPolyPoly)
{
    // AW: Do NOT paint empty PolyPolygons
    if(!rB2DPolyPoly.count())
        return;

    // we need a graphics
    if( !mpGraphics )
	    if( !ImplGetGraphics() )
		    return;

    if( mbInitClipRegion )
	    ImplInitClipRegion();
    if( mbOutputClipped )
	    return;

    if( mbInitLineColor )
	    ImplInitLineColor();
    if( mbInitFillColor )
	    ImplInitFillColor();

	if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) 
		&& mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
		&& ROP_OVERPAINT == GetRasterOp()
		&& (IsLineColor() || IsFillColor()))
    {
		const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation());
		basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly);
		bool bSuccess(true);

		// transform the polygon and ensure closed
		aB2DPolyPolygon.transform(aTransform);
        aB2DPolyPolygon.setClosed(true);

		if(IsFillColor())
		{
			bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this);
		}

		if(bSuccess && IsLineColor())
		{
			const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );

			if(mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE)
			{
				aB2DPolyPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon);
			}

			for(sal_uInt32 a(0);bSuccess && a < aB2DPolyPolygon.count(); a++)
			{
				bSuccess = mpGraphics->DrawPolyLine( aB2DPolyPolygon.getB2DPolygon(a), 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this);
			}
		}

		if(bSuccess)
		{
			return;
		}
    }

    // fallback to old polygon drawing if needed
    const PolyPolygon aToolsPolyPolygon( rB2DPolyPoly );
    const PolyPolygon aPixelPolyPolygon = ImplLogicToDevicePixel( aToolsPolyPolygon );
    ImplDrawPolyPolygon( aPixelPolyPolygon.Count(), aPixelPolyPolygon );
}

// -----------------------------------------------------------------------

bool OutputDevice::ImpTryDrawPolyLineDirect(
	const basegfx::B2DPolygon& rB2DPolygon,
    double fLineWidth,
    basegfx::B2DLineJoin eLineJoin)
{
    const basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
    basegfx::B2DVector aB2DLineWidth(1.0, 1.0);
    
	// transform the line width if used
    if( fLineWidth != 0.0 )
	{
        aB2DLineWidth = aTransform * ::basegfx::B2DVector( fLineWidth, fLineWidth );
	}

    // transform the polygon
    basegfx::B2DPolygon aB2DPolygon(rB2DPolygon);
    aB2DPolygon.transform(aTransform);
    
    if((mnAntialiasing & ANTIALIASING_PIXELSNAPHAIRLINE) 
		&& aB2DPolygon.count() < 1000)
    {
		// #i98289#, #i101491#
        // better to remove doubles on device coordinates. Also assume from a given amount
        // of points that the single edges are not long enough to smooth
        aB2DPolygon.removeDoublePoints();
        aB2DPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon);
    }

    // draw the polyline
    return mpGraphics->DrawPolyLine( aB2DPolygon, 0.0, aB2DLineWidth, eLineJoin, this);
}

void OutputDevice::DrawPolyLine(
    const basegfx::B2DPolygon& rB2DPolygon,
    double fLineWidth,
    basegfx::B2DLineJoin eLineJoin)
{
	DBG_TRACE( "OutputDevice::DrawPolyLine(B2D&)" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    (void)eLineJoin; // ATM used in UNX, but not in WNT, access it for warning-free

#if 0 // MetaB2DPolyLineAction is not implemented yet:
      // according to AW adding it is very dangerous since there is a lot
      // of code that uses the metafile actions directly and unless every
      // place that does this knows about the new action we need to fallback
    if( mpMetaFile )
        mpMetaFile->AddAction( new MetaB2DPolyLineAction( rB2DPolygon ) );
#else
    if( mpMetaFile )
    {
        LineInfo aLineInfo;
        if( fLineWidth != 0.0 )
            aLineInfo.SetWidth( static_cast<long>(fLineWidth+0.5) );
        const Polygon aToolsPolygon( rB2DPolygon );
        mpMetaFile->AddAction( new MetaPolyLineAction( aToolsPolygon, aLineInfo ) );
    }
#endif

    // AW: Do NOT paint empty PolyPolygons
    if(!rB2DPolygon.count())
        return;

    // we need a graphics
	if( !mpGraphics )
		if( !ImplGetGraphics() )
			return;

	if( mbInitClipRegion )
		ImplInitClipRegion();
	if( mbOutputClipped )
		return;

	if( mbInitLineColor )
		ImplInitLineColor();

    const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) 
        && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
        && ROP_OVERPAINT == GetRasterOp()
        && IsLineColor());

	// use b2dpolygon drawing if possible
	if(bTryAA && ImpTryDrawPolyLineDirect(rB2DPolygon, fLineWidth, eLineJoin))
	{
		return;
	}

	// #i101491#
	// no output yet; fallback to geometry decomposition and use filled polygon paint
	// when line is fat and not too complex. ImpDrawPolyPolygonWithB2DPolyPolygon
	// will do internal needed AA checks etc.
	if(fLineWidth >= 2.5 
		&& rB2DPolygon.count()
		&& rB2DPolygon.count() <= 1000)
	{
		const double fHalfLineWidth((fLineWidth * 0.5) + 0.5);
		const basegfx::B2DPolyPolygon aAreaPolyPolygon(basegfx::tools::createAreaGeometry(
			rB2DPolygon, fHalfLineWidth, eLineJoin));

		const Color aOldLineColor(maLineColor);
		const Color aOldFillColor(maFillColor);

		SetLineColor();
		ImplInitLineColor();
		SetFillColor(aOldLineColor);
		ImplInitFillColor();

		// draw usig a loop; else the topology will paint a PolyPolygon
		for(sal_uInt32 a(0); a < aAreaPolyPolygon.count(); a++)
		{
			ImpDrawPolyPolygonWithB2DPolyPolygon(
				basegfx::B2DPolyPolygon(aAreaPolyPolygon.getB2DPolygon(a)));
		}

        SetLineColor(aOldLineColor);
		ImplInitLineColor();
		SetFillColor(aOldFillColor);
		ImplInitFillColor();

		if(bTryAA)
		{
			// when AA it is necessary to also paint the filled polygon's outline
			// to avoid optical gaps
			for(sal_uInt32 a(0); a < aAreaPolyPolygon.count(); a++)
			{
				ImpTryDrawPolyLineDirect(aAreaPolyPolygon.getB2DPolygon(a), 0.0, basegfx::B2DLINEJOIN_NONE);
			}
		}
	}
	else
	{
		// fallback to old polygon drawing if needed
		const Polygon aToolsPolygon( rB2DPolygon );
		LineInfo aLineInfo;
		if( fLineWidth != 0.0 )
			aLineInfo.SetWidth( static_cast<long>(fLineWidth+0.5) );
		ImpDrawPolyLineWithLineInfo( aToolsPolygon, aLineInfo );
	}
}

// -----------------------------------------------------------------------

sal_uInt32 OutputDevice::GetGCStackDepth() const
{
    const ImplObjStack* pData = mpObjStack;
    sal_uInt32 nDepth = 0;
    while( pData )
    {
        nDepth++;
        pData = pData->mpPrev;
    }
    return nDepth;
}

// -----------------------------------------------------------------------

void OutputDevice::Push( sal_uInt16 nFlags )
{
	DBG_TRACE( "OutputDevice::Push()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( mpMetaFile )
		mpMetaFile->AddAction( new MetaPushAction( nFlags ) );

	ImplObjStack* pData = new ImplObjStack;
	pData->mpPrev = mpObjStack;
	mpObjStack = pData;

	pData->mnFlags = nFlags;

	if ( nFlags & PUSH_LINECOLOR )
	{
		if ( mbLineColor )
			pData->mpLineColor = new Color( maLineColor );
		else
			pData->mpLineColor = NULL;
	}
	if ( nFlags & PUSH_FILLCOLOR )
	{
		if ( mbFillColor )
			pData->mpFillColor = new Color( maFillColor );
		else
			pData->mpFillColor = NULL;
	}
	if ( nFlags & PUSH_FONT )
		pData->mpFont = new Font( maFont );
	if ( nFlags & PUSH_TEXTCOLOR )
		pData->mpTextColor = new Color( GetTextColor() );
	if ( nFlags & PUSH_TEXTFILLCOLOR )
	{
		if ( IsTextFillColor() )
			pData->mpTextFillColor = new Color( GetTextFillColor() );
		else
			pData->mpTextFillColor = NULL;
	}
	if ( nFlags & PUSH_TEXTLINECOLOR )
	{
		if ( IsTextLineColor() )
			pData->mpTextLineColor = new Color( GetTextLineColor() );
		else
			pData->mpTextLineColor = NULL;
	}
	if ( nFlags & PUSH_OVERLINECOLOR )
	{
		if ( IsOverlineColor() )
			pData->mpOverlineColor = new Color( GetOverlineColor() );
		else
			pData->mpOverlineColor = NULL;
	}
	if ( nFlags & PUSH_TEXTALIGN )
		pData->meTextAlign = GetTextAlign();
	if( nFlags & PUSH_TEXTLAYOUTMODE )
		pData->mnTextLayoutMode = GetLayoutMode();
	if( nFlags & PUSH_TEXTLANGUAGE )
		pData->meTextLanguage = GetDigitLanguage();
	if ( nFlags & PUSH_RASTEROP )
		pData->meRasterOp = GetRasterOp();
	if ( nFlags & PUSH_MAPMODE )
	{
		if ( mbMap )
			pData->mpMapMode = new MapMode( maMapMode );
		else
			pData->mpMapMode = NULL;
	}
	if ( nFlags & PUSH_CLIPREGION )
	{
		if ( mbClipRegion )
			pData->mpClipRegion = new Region( maRegion );
		else
			pData->mpClipRegion = NULL;
	}
	if ( nFlags & PUSH_REFPOINT )
	{
		if ( mbRefPoint )
			pData->mpRefPoint = new Point( maRefPoint );
		else
			pData->mpRefPoint = NULL;
	}

    if( mpAlphaVDev )
        mpAlphaVDev->Push();
}

// -----------------------------------------------------------------------

void OutputDevice::Pop()
{
	DBG_TRACE( "OutputDevice::Pop()" );
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if( mpMetaFile )
		mpMetaFile->AddAction( new MetaPopAction() );

	GDIMetaFile*	pOldMetaFile = mpMetaFile;
	ImplObjStack*	pData = mpObjStack;
	mpMetaFile = NULL;

	if ( !pData )
	{
		DBG_ERRORFILE( "OutputDevice::Pop() without OutputDevice::Push()" );
		return;
	}

    if( mpAlphaVDev )
        mpAlphaVDev->Pop();

	mpObjStack = pData->mpPrev;

	if ( pData->mnFlags & PUSH_LINECOLOR )
	{
		if ( pData->mpLineColor )
			SetLineColor( *pData->mpLineColor );
		else
			SetLineColor();
	}
	if ( pData->mnFlags & PUSH_FILLCOLOR )
	{
		if ( pData->mpFillColor )
			SetFillColor( *pData->mpFillColor );
		else
			SetFillColor();
	}
	if ( pData->mnFlags & PUSH_FONT )
		SetFont( *pData->mpFont );
	if ( pData->mnFlags & PUSH_TEXTCOLOR )
		SetTextColor( *pData->mpTextColor );
	if ( pData->mnFlags & PUSH_TEXTFILLCOLOR )
	{
		if ( pData->mpTextFillColor )
			SetTextFillColor( *pData->mpTextFillColor );
		else
			SetTextFillColor();
	}
	if ( pData->mnFlags & PUSH_TEXTLINECOLOR )
	{
		if ( pData->mpTextLineColor )
			SetTextLineColor( *pData->mpTextLineColor );
		else
			SetTextLineColor();
	}
	if ( pData->mnFlags & PUSH_OVERLINECOLOR )
	{
		if ( pData->mpOverlineColor )
			SetOverlineColor( *pData->mpOverlineColor );
		else
			SetOverlineColor();
	}
	if ( pData->mnFlags & PUSH_TEXTALIGN )
		SetTextAlign( pData->meTextAlign );
	if( pData->mnFlags & PUSH_TEXTLAYOUTMODE )
		SetLayoutMode( pData->mnTextLayoutMode );
	if( pData->mnFlags & PUSH_TEXTLANGUAGE )
		SetDigitLanguage( pData->meTextLanguage );
	if ( pData->mnFlags & PUSH_RASTEROP )
		SetRasterOp( pData->meRasterOp );
	if ( pData->mnFlags & PUSH_MAPMODE )
	{
		if ( pData->mpMapMode )
			SetMapMode( *pData->mpMapMode );
		else
			SetMapMode();
	}
	if ( pData->mnFlags & PUSH_CLIPREGION )
		ImplSetClipRegion( pData->mpClipRegion );
	if ( pData->mnFlags & PUSH_REFPOINT )
	{
		if ( pData->mpRefPoint )
			SetRefPoint( *pData->mpRefPoint );
		else
			SetRefPoint();
	}

	ImplDeleteObjStack( pData );

	mpMetaFile = pOldMetaFile;
}

// -----------------------------------------------------------------------

void OutputDevice::SetConnectMetaFile( GDIMetaFile* pMtf )
{
    mpMetaFile = pMtf;
}

// -----------------------------------------------------------------------

void OutputDevice::EnableOutput( sal_Bool bEnable )
{
    mbOutput = (bEnable != 0);

    if( mpAlphaVDev )
        mpAlphaVDev->EnableOutput( bEnable );
}

// -----------------------------------------------------------------------

void OutputDevice::SetSettings( const AllSettings& rSettings )
{
    maSettings = rSettings;

    if( mpAlphaVDev )
        mpAlphaVDev->SetSettings( rSettings );
}

// -----------------------------------------------------------------------

sal_uInt16 OutputDevice::GetBitCount() const
{
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( meOutDevType == OUTDEV_VIRDEV )
		return ((VirtualDevice*)this)->mnBitCount;

	// we need a graphics
	if ( !mpGraphics )
	{
		if ( !((OutputDevice*)this)->ImplGetGraphics() )
			return 0;
	}

	return (sal_uInt16)mpGraphics->GetBitCount();
}

// -----------------------------------------------------------------------

sal_uInt16 OutputDevice::GetAlphaBitCount() const
{
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	if ( meOutDevType == OUTDEV_VIRDEV &&
        mpAlphaVDev != NULL )
    {
		return mpAlphaVDev->GetBitCount();
    }

    return 0;
}

// -----------------------------------------------------------------------

sal_uLong OutputDevice::GetColorCount() const
{
	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );

	const sal_uInt16 nBitCount = GetBitCount();
	return( ( nBitCount > 31 ) ? ULONG_MAX : ( ( (sal_uLong) 1 ) << nBitCount) );
}

// -----------------------------------------------------------------------

sal_Bool OutputDevice::HasAlpha()
{
    return mpAlphaVDev != NULL;
}

// -----------------------------------------------------------------------

::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics > OutputDevice::CreateUnoGraphics()
{
	UnoWrapperBase* pWrapper = Application::GetUnoWrapper();
	return pWrapper ? pWrapper->CreateGraphics( this ) : ::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics >();
}

// -----------------------------------------------------------------------

SystemGraphicsData OutputDevice::GetSystemGfxData() const
{
	if ( !mpGraphics )
	{
		if ( !ImplGetGraphics() )
			return SystemGraphicsData();
	}

    return mpGraphics->GetGraphicsData();
}

// -----------------------------------------------------------------------

::com::sun::star::uno::Any OutputDevice::GetSystemGfxDataAny() const
{
    ::com::sun::star::uno::Any aRet;
    const SystemGraphicsData aSysData = GetSystemGfxData();
    ::com::sun::star::uno::Sequence< sal_Int8 > aSeq( (sal_Int8*)&aSysData,
                                                      aSysData.nSize );

    return uno::makeAny(aSeq);
}

// -----------------------------------------------------------------------

::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas > OutputDevice::GetCanvas() const
{
    uno::Sequence< uno::Any > aArg(6);

    aArg[ 0 ] = uno::makeAny( reinterpret_cast<sal_Int64>(this) );
    aArg[ 2 ] = uno::makeAny( ::com::sun::star::awt::Rectangle( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight ) );
    aArg[ 3 ] = uno::makeAny( sal_False );
    aArg[ 5 ] = GetSystemGfxDataAny();

    uno::Reference<lang::XMultiServiceFactory> xFactory = vcl::unohelper::GetMultiServiceFactory();

    uno::Reference<rendering::XCanvas> xCanvas;

    // Create canvas instance with window handle
    // =========================================
    if ( xFactory.is() )
    {
        static uno::Reference<lang::XMultiServiceFactory> xCanvasFactory(
            xFactory->createInstance(
                OUString( RTL_CONSTASCII_USTRINGPARAM(
                              "com.sun.star."
                              "rendering.CanvasFactory") ) ),
            uno::UNO_QUERY );
        if(xCanvasFactory.is())
        {
            xCanvas.set(
                xCanvasFactory->createInstanceWithArguments(
                    OUString( RTL_CONSTASCII_USTRINGPARAM(
                                  "com.sun.star.rendering.Canvas" )),
                    aArg ),
                uno::UNO_QUERY );
        }
    }

    return xCanvas;
}

// -----------------------------------------------------------------------
