text: /**************************************************************
   * 
   * 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 <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;
      bool            mbMapActive;
      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(true),
  	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
  {
      RectangleVector aRectangles;
      rRegion.GetRegionRectangles(aRectangles);
      Region aMirroredRegion;
  
      for(RectangleVector::iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++)
      {
          ImplReMirror(*aRectIter);
          aMirroredRegion.Union(*aRectIter);
      }
  
      rRegion = aMirroredRegion;
  
  //	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 );
                  }
  		        
                  if ( aRegion.IsEmpty() )
                  {
  			        mbOutputClipped = sal_True;
                  }
  		        else
  		        {
  			        mbOutputClipped = sal_False;
  			        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(true);
  			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 );
  
  	if ( mpMetaFile )
  		mpMetaFile->AddAction( new MetaClipRegionAction( rRegion, sal_True ) );
  
  	if ( rRegion.IsNull() )
      {
  		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(true);
  		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 );
  
  	if(!rRegion.IsNull())
  	{
  		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, com::sun::star::drawing::LineCap_BUTT, 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(),
                  rInfo.GetLineCap()));
          }
          
          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, com::sun::star::drawing::LineCap_BUTT, 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++)
              {
                  Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
  
                  // need to subdivide, mpGraphics->DrawPolygon ignores curves
                  aPolygon.AdaptiveSubdivide(aPolygon);
  			    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()))
  	{
  		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, com::sun::star::drawing::LineCap_BUTT, 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(), rLineInfo.GetLineCap());
  		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, 
                  com::sun::star::drawing::LineCap_BUTT,
                  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, 
                      com::sun::star::drawing::LineCap_BUTT,
                      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, 
                      com::sun::star::drawing::LineCap_BUTT,
                      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,
      double fTransparency,
      basegfx::B2DLineJoin eLineJoin,
      com::sun::star::drawing::LineCap eLineCap)
  {
      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, 
          fTransparency, 
          aB2DLineWidth, 
          eLineJoin, 
          eLineCap,
          this);
  }
  
  bool OutputDevice::TryDrawPolyLineDirect(
      const basegfx::B2DPolygon& rB2DPolygon, 
      double fLineWidth, 
      double fTransparency,
      basegfx::B2DLineJoin eLineJoin,
      com::sun::star::drawing::LineCap eLineCap)
  {
      // AW: Do NOT paint empty PolyPolygons
      if(!rB2DPolygon.count())
          return true;
  
      // we need a graphics
      if( !mpGraphics )
          if( !ImplGetGraphics() )
              return false;
  
      if( mbInitClipRegion )
          ImplInitClipRegion();
  
      if( mbOutputClipped )
          return true;
  
      if( mbInitLineColor )
          ImplInitLineColor();
  
      const bool bTryAA((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW) 
          && mpGraphics->supportsOperation(OutDevSupport_B2DDraw)
          && ROP_OVERPAINT == GetRasterOp()
          && IsLineColor());
  
      if(bTryAA)
      {
          if(ImpTryDrawPolyLineDirect(rB2DPolygon, fLineWidth, fTransparency, eLineJoin, eLineCap))
          {
              // worked, add metafile action (if recorded) and return true
              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 ) );
              }
  
              return true;
          }
      }
  
      return false;
  }
  
  void OutputDevice::DrawPolyLine(
      const basegfx::B2DPolygon& rB2DPolygon,
      double fLineWidth,
      basegfx::B2DLineJoin eLineJoin,
      com::sun::star::drawing::LineCap eLineCap)
  {
  	DBG_TRACE( "OutputDevice::DrawPolyLine(B2D&)" );
  	DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
  
  #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, 0.0, eLineJoin, eLineCap))
  	{
  		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,
                  eLineCap));
  		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));
  			}
  		}
  	}
  	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 )
  	{
  		pData->mpMapMode = new MapMode( maMapMode );
          pData->mbMapActive = mbMap;
  	}
  	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();
          mbMap = pData->mbMapActive;
  	}
  	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;
  }
  
  // -----------------------------------------------------------------------
  