diff options
author | Radek Doulik <rodo@novell.com> | 2013-03-14 09:36:43 +0100 |
---|---|---|
committer | Radek Doulik <rodo@novell.com> | 2013-03-14 13:21:24 +0100 |
commit | 22f63477a3300d474c3d6832232b888f75c7290c (patch) | |
tree | 7fc4d0970fd5d58fe950e9b618ba87533c53b6e8 | |
parent | 87354e7fc1f63480bdef092047f912682bc7ac58 (diff) |
pass argb32 pixmaps from vcl to canvas, avoiding costly x11 roundtrips
- fixes also problem with emf+ rendering for slideshow
Change-Id: Icb894d3f37b29f23d3f267c944d827eefbf47fda
-rw-r--r-- | canvas/source/cairo/cairo_canvasbitmap.cxx | 30 | ||||
-rw-r--r-- | canvas/source/cairo/cairo_canvasbitmap.hxx | 4 | ||||
-rw-r--r-- | canvas/source/cairo/cairo_xlib_cairo.cxx | 7 | ||||
-rw-r--r-- | canvas/source/cairo/cairo_xlib_cairo.hxx | 1 | ||||
-rw-r--r-- | vcl/inc/unx/salbmp.h | 4 | ||||
-rw-r--r-- | vcl/inc/vcl/bitmap.hxx | 3 | ||||
-rw-r--r-- | vcl/source/gdi/bitmap.cxx | 13 | ||||
-rw-r--r-- | vcl/source/gdi/gdimtf.cxx.orig | 3184 | ||||
-rw-r--r-- | vcl/source/helper/canvastools.cxx | 25 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salbmp.cxx | 16 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salgdi2.cxx | 4 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salgdi2.cxx.orig | 1009 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salgdi2.cxx.rej | 13 |
13 files changed, 4301 insertions, 12 deletions
diff --git a/canvas/source/cairo/cairo_canvasbitmap.cxx b/canvas/source/cairo/cairo_canvasbitmap.cxx index 91f61940dc1d..c0759c02653e 100644 --- a/canvas/source/cairo/cairo_canvasbitmap.cxx +++ b/canvas/source/cairo/cairo_canvasbitmap.cxx @@ -134,6 +134,30 @@ namespace cairocanvas return maCanvasHelper.repaint( pSurface, viewState, renderState ); } + void SAL_CALL CanvasBitmap::setFastPropertyValue( sal_Int32 nHandle, const ::com::sun::star::uno::Any& rAny ) throw (uno::RuntimeException) + { + sal_Int64 nPointer; + + if ( nHandle == 0 ) + { + rAny >>= nPointer; + + if ( nPointer ) + { + ::Bitmap *pBitmap = reinterpret_cast< ::Bitmap* >( nPointer ); + + mpBufferSurface = createSurface( *pBitmap ); + mpBufferCairo = mpBufferSurface->getCairo(); + + ::Size aSize( pBitmap->GetSizePixel() ); + maSize = ::basegfx::B2ISize( aSize.getWidth(), aSize.getHeight() ); + + maCanvasHelper.setSize( maSize ); + maCanvasHelper.setSurface( mpBufferSurface, mbHasAlpha ); + } + } + } + uno::Any SAL_CALL CanvasBitmap::getFastPropertyValue( sal_Int32 nHandle ) throw (uno::RuntimeException) { uno::Any aRV( sal_Int32(0) ); @@ -152,10 +176,11 @@ namespace cairocanvas #ifdef CAIRO_HAS_XLIB_SURFACE X11Surface* pXlibSurface=dynamic_cast<X11Surface*>(mpBufferSurface.get()); OSL_ASSERT(pXlibSurface); - uno::Sequence< uno::Any > args( 3 ); + uno::Sequence< uno::Any > args( 4 ); args[0] = uno::Any( false ); // do not call XFreePixmap on it args[1] = uno::Any( pXlibSurface->getPixmap()->mhDrawable ); args[2] = uno::Any( sal_Int32( pXlibSurface->getDepth() ) ); + args[3] = uno::Any( sal_Int64( pXlibSurface->getVisual () ) ); aRV = uno::Any( args ); #elif defined CAIRO_HAS_QUARTZ_SURFACE @@ -180,7 +205,7 @@ namespace cairocanvas case 2: { #ifdef CAIRO_HAS_XLIB_SURFACE - uno::Sequence< uno::Any > args( 3 ); + uno::Sequence< uno::Any > args( 4 ); SurfaceSharedPtr pAlphaSurface = mpSurfaceProvider->createSurface( maSize, CAIRO_CONTENT_COLOR ); CairoSharedPtr pAlphaCairo = pAlphaSurface->getCairo(); X11Surface* pXlibSurface=dynamic_cast<X11Surface*>(pAlphaSurface.get()); @@ -199,6 +224,7 @@ namespace cairocanvas args[0] = uno::Any( true ); args[1] = ::com::sun::star::uno::Any( pPixmap->mhDrawable ); args[2] = ::com::sun::star::uno::Any( sal_Int32( pXlibSurface->getDepth () ) ); + args[3] = ::com::sun::star::uno::Any( sal_Int64( pXlibSurface->getVisual () ) ); pPixmap->clear(); // caller takes ownership of pixmap // return pixmap and alphachannel pixmap - it will be used in BitmapEx diff --git a/canvas/source/cairo/cairo_canvasbitmap.hxx b/canvas/source/cairo/cairo_canvasbitmap.hxx index b1d669ed5713..bef03f557cd0 100644 --- a/canvas/source/cairo/cairo_canvasbitmap.hxx +++ b/canvas/source/cairo/cairo_canvasbitmap.hxx @@ -115,14 +115,14 @@ namespace cairocanvas // 2nd the pixmap handle // 3rd the pixmap depth virtual ::com::sun::star::uno::Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle) throw (::com::sun::star::uno::RuntimeException); - virtual void SAL_CALL setFastPropertyValue(sal_Int32, const ::com::sun::star::uno::Any&) throw (::com::sun::star::uno::RuntimeException) {} + virtual void SAL_CALL setFastPropertyValue(sal_Int32, const ::com::sun::star::uno::Any&) throw (::com::sun::star::uno::RuntimeException); private: SurfaceProviderRef mpSurfaceProvider; ::cairo::SurfaceSharedPtr mpBufferSurface; ::cairo::CairoSharedPtr mpBufferCairo; - const ::basegfx::B2ISize maSize; + ::basegfx::B2ISize maSize; const bool mbHasAlpha; }; } diff --git a/canvas/source/cairo/cairo_xlib_cairo.cxx b/canvas/source/cairo/cairo_xlib_cairo.cxx index cd13ea133004..3086fd562096 100644 --- a/canvas/source/cairo/cairo_xlib_cairo.cxx +++ b/canvas/source/cairo/cairo_xlib_cairo.cxx @@ -187,7 +187,7 @@ namespace cairo mpSurface( cairo_xlib_surface_create( (Display*)rSysData.pDisplay, (Drawable)rData.aPixmap, - (Visual*) rSysData.pVisual, + (Visual*) (rData.aVisual ? rData.aVisual : rSysData.pVisual), rData.mnWidth, rData.mnHeight ), &cairo_surface_destroy) { @@ -312,6 +312,11 @@ namespace cairo return -1; } + void* X11Surface::getVisual() const + { + return cairo_xlib_surface_get_visual( mpSurface.get() ); + } + SurfaceSharedPtr createSurface( const CairoSurfaceSharedPtr& rSurface ) { return SurfaceSharedPtr(new X11Surface(rSurface)); diff --git a/canvas/source/cairo/cairo_xlib_cairo.hxx b/canvas/source/cairo/cairo_xlib_cairo.hxx index 105c570eae7d..080258bb04d2 100644 --- a/canvas/source/cairo/cairo_xlib_cairo.hxx +++ b/canvas/source/cairo/cairo_xlib_cairo.hxx @@ -92,6 +92,7 @@ namespace cairo { X11PixmapSharedPtr getPixmap() const { return mpPixmap; } void* getRenderFormat() const { return maSysData.pRenderFormat; } long getDrawable() const { return mpPixmap ? mpPixmap->mhDrawable : maSysData.hDrawable; } + void* getVisual() const; }; } diff --git a/vcl/inc/unx/salbmp.h b/vcl/inc/unx/salbmp.h index 6973507d15d7..70307a175a7c 100644 --- a/vcl/inc/unx/salbmp.h +++ b/vcl/inc/unx/salbmp.h @@ -80,6 +80,7 @@ public: SAL_DLLPRIVATE bool ImplCreateFromDrawable( Drawable aDrawable, + void* pVisual, SalX11Screen nXScreen, long nDrawableDepth, long nX, @@ -162,6 +163,7 @@ class ImplSalDDB private: Pixmap maPixmap; + void* mpVisual; SalTwoRect maTwoRect; long mnDepth; SalX11Screen mnXScreen; @@ -193,6 +195,7 @@ public: ImplSalDDB( Drawable aDrawable, + void *pVisual, SalX11Screen nXScreen, long nDrawableDepth, long nX, @@ -204,6 +207,7 @@ public: ~ImplSalDDB(); Pixmap ImplGetPixmap() const { return maPixmap; } + void* ImplGetVisual() const { return mpVisual; } long ImplGetWidth() const { return maTwoRect.mnDestWidth; } long ImplGetHeight() const { return maTwoRect.mnDestHeight; } long ImplGetDepth() const { return mnDepth; } diff --git a/vcl/inc/vcl/bitmap.hxx b/vcl/inc/vcl/bitmap.hxx index 7e1fced00998..2a0b139df92e 100644 --- a/vcl/inc/vcl/bitmap.hxx +++ b/vcl/inc/vcl/bitmap.hxx @@ -325,6 +325,7 @@ struct BitmapSystemData void* rImageContext; //Image context (CGContextRef) #else void* aPixmap; + void* aVisual; #endif int mnWidth; int mnHeight; @@ -846,6 +847,8 @@ public: const BmpFilterParam* pFilterParam = NULL, const Link* pProgress = NULL ); + bool HasAlpha(); + public: BitmapReadAccess* AcquireReadAccess(); BitmapWriteAccess* AcquireWriteAccess(); diff --git a/vcl/source/gdi/bitmap.cxx b/vcl/source/gdi/bitmap.cxx index 436092a89828..98de0a4e2f84 100644 --- a/vcl/source/gdi/bitmap.cxx +++ b/vcl/source/gdi/bitmap.cxx @@ -1901,4 +1901,17 @@ bool Bitmap::GetSystemData( BitmapSystemData& rData ) const return bRet; } +bool Bitmap::HasAlpha() +{ + bool bRet = false; + if( mpImpBmp ) + { + SalBitmap* pSalBitmap = mpImpBmp->ImplGetSalBitmap(); + if( pSalBitmap ) + bRet = pSalBitmap->HasAlpha(); + } + + return bRet; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/gdimtf.cxx.orig b/vcl/source/gdi/gdimtf.cxx.orig new file mode 100644 index 000000000000..bf19753b1f15 --- /dev/null +++ b/vcl/source/gdi/gdimtf.cxx.orig @@ -0,0 +1,3184 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <rtl/crc.h> +#include <tools/stream.hxx> +#include <tools/vcompat.hxx> +#include <vcl/metaact.hxx> +#include <vcl/salbtype.hxx> +#include <vcl/outdev.hxx> +#include <vcl/window.hxx> +#include <vcl/cvtsvm.hxx> +#include <vcl/virdev.hxx> +#include <vcl/svapp.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/graphictools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <vcl/canvastools.hxx> + +#include <salbmp.hxx> +#include <salinst.hxx> +#include <svdata.hxx> + +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <com/sun/star/rendering/MtfRenderer.hpp> +#include <com/sun/star/rendering/XBitmapCanvas.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/awt/XGraphics.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/graphic/XGraphicRenderer.hpp> + +using namespace com::sun::star; + +// ----------- +// - Defines - +// ----------- + +#define GAMMA( _def_cVal, _def_InvGamma ) ((sal_uInt8)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L)) + +// -------------------------- +// - Color exchange structs - +// -------------------------- + +struct ImplColAdjustParam +{ + sal_uInt8* pMapR; + sal_uInt8* pMapG; + sal_uInt8* pMapB; +}; + +struct ImplBmpAdjustParam +{ + short nLuminancePercent; + short nContrastPercent; + short nChannelRPercent; + short nChannelGPercent; + short nChannelBPercent; + double fGamma; + sal_Bool bInvert; +}; + +// ----------------------------------------------------------------------------- + +struct ImplColConvertParam +{ + MtfConversion eConversion; +}; + +struct ImplBmpConvertParam +{ + BmpConversion eConversion; +}; + +// ----------------------------------------------------------------------------- + +struct ImplColMonoParam +{ + Color aColor; +}; + +struct ImplBmpMonoParam +{ + Color aColor; +}; + +// ----------------------------------------------------------------------------- + +struct ImplColReplaceParam +{ + sal_uLong* pMinR; + sal_uLong* pMaxR; + sal_uLong* pMinG; + sal_uLong* pMaxG; + sal_uLong* pMinB; + sal_uLong* pMaxB; + const Color* pDstCols; + sal_uLong nCount; +}; + +struct ImplBmpReplaceParam +{ + const Color* pSrcCols; + const Color* pDstCols; + sal_uLong nCount; + const sal_uLong* pTols; +}; + +// --------------- +// - GDIMetaFile - +// --------------- + +GDIMetaFile::GDIMetaFile() : + nCurrentActionElement( 0 ), + aPrefSize ( 1, 1 ), + pPrev ( NULL ), + pNext ( NULL ), + pOutDev ( NULL ), + bPause ( sal_False ), + bRecord ( sal_False ), + bUseCanvas ( sal_False ) +{ +} + +// ------------------------------------------------------------------------ + +GDIMetaFile::GDIMetaFile( const GDIMetaFile& rMtf ) : + aPrefMapMode ( rMtf.aPrefMapMode ), + aPrefSize ( rMtf.aPrefSize ), + aHookHdlLink ( rMtf.aHookHdlLink ), + pPrev ( rMtf.pPrev ), + pNext ( rMtf.pNext ), + pOutDev ( NULL ), + bPause ( sal_False ), + bRecord ( sal_False ), + bUseCanvas ( rMtf.bUseCanvas ) +{ + // RefCount der MetaActions erhoehen + for( size_t i = 0, n = rMtf.GetActionSize(); i < n; ++i ) + { + rMtf.GetAction( i )->Duplicate(); + aList.push_back( rMtf.GetAction( i ) ); + } + + if( rMtf.bRecord ) + { + Record( rMtf.pOutDev ); + + if ( rMtf.bPause ) + Pause( sal_True ); + } +} + +// ------------------------------------------------------------------------ + +GDIMetaFile::~GDIMetaFile() +{ + Clear(); +} + +// ------------------------------------------------------------------------ + +size_t GDIMetaFile::GetActionSize() const +{ + return aList.size(); +} + +// ------------------------------------------------------------------------ + +MetaAction* GDIMetaFile::GetAction( size_t nAction ) const +{ + return (nAction < aList.size()) ? aList[ nAction ] : NULL; +} + +// ------------------------------------------------------------------------ + +MetaAction* GDIMetaFile::FirstAction() +{ + nCurrentActionElement = 0; + return aList.empty() ? NULL : aList[ 0 ]; +} + +// ------------------------------------------------------------------------ + +MetaAction* GDIMetaFile::NextAction() +{ + return ( nCurrentActionElement + 1 < aList.size() ) ? aList[ ++nCurrentActionElement ] : NULL; +} + +// ------------------------------------------------------------------------ + +MetaAction* GDIMetaFile::ReplaceAction( MetaAction* pAction, size_t nAction ) +{ + if ( nAction >= aList.size() ) + { + // this method takes ownership of pAction and is + // therefore responsible for deleting it + pAction->Delete(); + return NULL; + } + //fdo#39995 This does't increment the incoming action ref-count nor does it + //decrement the outgoing action ref-count + std::swap(pAction, aList[nAction]); + return pAction; +} + +// ------------------------------------------------------------------------ + +GDIMetaFile& GDIMetaFile::operator=( const GDIMetaFile& rMtf ) +{ + if( this != &rMtf ) + { + Clear(); + + // RefCount der MetaActions erhoehen + for( size_t i = 0, n = rMtf.GetActionSize(); i < n; ++i ) + { + rMtf.GetAction( i )->Duplicate(); + aList.push_back( rMtf.GetAction( i ) ); + } + + aPrefMapMode = rMtf.aPrefMapMode; + aPrefSize = rMtf.aPrefSize; + aHookHdlLink = rMtf.aHookHdlLink; + pPrev = rMtf.pPrev; + pNext = rMtf.pNext; + pOutDev = NULL; + bPause = sal_False; + bRecord = sal_False; + bUseCanvas = rMtf.bUseCanvas; + + if( rMtf.bRecord ) + { + Record( rMtf.pOutDev ); + + if( rMtf.bPause ) + Pause( sal_True ); + } + } + + return *this; +} + +// ------------------------------------------------------------------------ + +sal_Bool GDIMetaFile::operator==( const GDIMetaFile& rMtf ) const +{ + const size_t nObjCount = aList.size(); + sal_Bool bRet = sal_False; + + if( this == &rMtf ) + bRet = sal_True; + else if( rMtf.GetActionSize() == nObjCount && + rMtf.GetPrefSize() == aPrefSize && + rMtf.GetPrefMapMode() == aPrefMapMode ) + { + bRet = sal_True; + + for( size_t n = 0; n < nObjCount; n++ ) + { + if( aList[ n ] != rMtf.GetAction( n ) ) + { + bRet = sal_False; + break; + } + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Clear() +{ + if( bRecord ) + Stop(); + + for( size_t i = 0, n = aList.size(); i < n; ++i ) + aList[ i ]->Delete(); + aList.clear(); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Linker( OutputDevice* pOut, sal_Bool bLink ) +{ + if( bLink ) + { + pNext = NULL; + pPrev = pOut->GetConnectMetaFile(); + pOut->SetConnectMetaFile( this ); + + if( pPrev ) + pPrev->pNext = this; + } + else + { + if( pNext ) + { + pNext->pPrev = pPrev; + + if( pPrev ) + pPrev->pNext = pNext; + } + else + { + if( pPrev ) + pPrev->pNext = NULL; + + pOut->SetConnectMetaFile( pPrev ); + } + + pPrev = NULL; + pNext = NULL; + } +} + +// ------------------------------------------------------------------------ + +long GDIMetaFile::Hook() +{ + return aHookHdlLink.Call( this ); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Record( OutputDevice* pOut ) +{ + if( bRecord ) + Stop(); + + nCurrentActionElement = aList.empty() ? 0 : (aList.size() - 1); + pOutDev = pOut; + bRecord = sal_True; + Linker( pOut, sal_True ); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Play( GDIMetaFile& rMtf, size_t nPos ) +{ + if ( !bRecord && !rMtf.bRecord ) + { + MetaAction* pAction = GetCurAction(); + const size_t nObjCount = aList.size(); + + rMtf.UseCanvas( rMtf.GetUseCanvas() || bUseCanvas ); + + if( nPos > nObjCount ) + nPos = nObjCount; + + for( size_t nCurPos = nCurrentActionElement; nCurPos < nPos; nCurPos++ ) + { + if( !Hook() ) + { + pAction->Duplicate(); + rMtf.AddAction( pAction ); + } + + pAction = NextAction(); + } + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Play( OutputDevice* pOut, size_t nPos ) +{ + if( !bRecord ) + { + MetaAction* pAction = GetCurAction(); + const size_t nObjCount = aList.size(); + size_t nSyncCount = ( pOut->GetOutDevType() == OUTDEV_WINDOW ) ? 0x000000ff : 0xffffffff; + + if( nPos > nObjCount ) + nPos = nObjCount; + + // #i23407# Set backwards-compatible text language and layout mode + // This is necessary, since old metafiles don't even know of these + // recent add-ons. Newer metafiles must of course explicitly set + // those states. + pOut->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE ); + pOut->SetLayoutMode( 0 ); + pOut->SetDigitLanguage( 0 ); + + OSL_TRACE("GDIMetaFile::Play on device of size: %d x %d", pOut->GetOutputSizePixel().Width(), pOut->GetOutputSizePixel().Height()); + + if( !ImplPlayWithRenderer( pOut, Point(0,0), pOut->GetOutputSizePixel() ) ) { + size_t i = 0; + for( size_t nCurPos = nCurrentActionElement; nCurPos < nPos; nCurPos++ ) + { + if( !Hook() ) + { + MetaCommentAction* pCommentAct = static_cast<MetaCommentAction*>(pAction); + if( pAction->GetType() == META_COMMENT_ACTION && + pCommentAct->GetComment() == "DELEGATE_PLUGGABLE_RENDERER" ) + { + ImplDelegate2PluggableRenderer(pCommentAct, pOut); + } + else + { + pAction->Execute( pOut ); + } + + // flush output from time to time + if( i++ > nSyncCount ) + ( (Window*) pOut )->Flush(), i = 0; + } + + pAction = NextAction(); + } + } + pOut->Pop(); + } +} + +// ------------------------------------------------------------------------ + +bool GDIMetaFile::ImplPlayWithRenderer( OutputDevice* pOut, const Point& rPos, Size rDestSize ) +{ + if (!bUseCanvas) + return false; + + const Window* win = dynamic_cast <Window*> ( pOut ); + + if (!win) + win = Application::GetActiveTopWindow(); + if (!win) + win = Application::GetFirstTopLevelWindow(); + + if (!win) + return false; + + try + { + uno::Reference<rendering::XCanvas> xCanvas = win->GetCanvas (); + + if (!xCanvas.is()) + return false; + + Size aSize (rDestSize.Width () + 1, rDestSize.Height () + 1); + uno::Reference<rendering::XBitmap> xBitmap = xCanvas->getDevice ()->createCompatibleAlphaBitmap (vcl::unotools::integerSize2DFromSize( aSize)); + uno::Reference< lang::XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); + if( xBitmap.is () ) + { + uno::Reference< rendering::XMtfRenderer > xMtfRenderer; + uno::Sequence< uno::Any > args (1); + uno::Reference< rendering::XBitmapCanvas > xBitmapCanvas( xBitmap, uno::UNO_QUERY ); + if( xBitmapCanvas.is() ) + { + args[0] = uno::Any( xBitmapCanvas ); + xMtfRenderer.set( xFactory->createInstanceWithArguments( ::rtl::OUString("com.sun.star.rendering.MtfRenderer"), + args ), uno::UNO_QUERY ); + + if( xMtfRenderer.is() ) + { + xBitmapCanvas->clear(); + uno::Reference< beans::XFastPropertySet > xMtfFastPropertySet( xMtfRenderer, uno::UNO_QUERY ); + if( xMtfFastPropertySet.is() ) + // set this metafile to the renderer to + // speedup things (instead of copying data to + // sequence of bytes passed to renderer) + xMtfFastPropertySet->setFastPropertyValue( 0, uno::Any( reinterpret_cast<sal_Int64>( this ) ) ); + + xMtfRenderer->draw( rDestSize.Width(), rDestSize.Height() ); + + uno::Reference< beans::XFastPropertySet > xFastPropertySet( xBitmapCanvas, uno::UNO_QUERY ); + if( xFastPropertySet.get() ) + { + // 0 means get BitmapEx + uno::Any aAny = xFastPropertySet->getFastPropertyValue( 0 ); + BitmapEx* pBitmapEx = (BitmapEx*) *reinterpret_cast<const sal_Int64*>(aAny.getValue()); + if( pBitmapEx ) { + pOut->DrawBitmapEx( rPos, *pBitmapEx ); + delete pBitmapEx; + return true; + } + } + + SalBitmap* pSalBmp = ImplGetSVData()->mpDefInst->CreateSalBitmap(); + SalBitmap* pSalMask = ImplGetSVData()->mpDefInst->CreateSalBitmap(); + + if( pSalBmp->Create( xBitmapCanvas, aSize ) && pSalMask->Create( xBitmapCanvas, aSize, true ) ) + { + Bitmap aBitmap( pSalBmp ); + Bitmap aMask( pSalMask ); + AlphaMask aAlphaMask( aMask ); + BitmapEx aBitmapEx( aBitmap, aAlphaMask ); + pOut->DrawBitmapEx( rPos, aBitmapEx ); + return true; + } + + delete pSalBmp; + delete pSalMask; + } + } + } + } + catch (const uno::RuntimeException& ) + { + throw; // runtime errors are fatal + } + catch (const uno::Exception& e) + { + // ignore errors, no way of reporting them here + SAL_WARN("vcl", + "GDIMetaFile::ImplPlayWithRenderer: exception: " << e.Message); + } + + return false; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::ImplDelegate2PluggableRenderer( const MetaCommentAction* pAct, OutputDevice* pOut ) +{ + OSL_ASSERT( pAct->GetComment() == "DELEGATE_PLUGGABLE_RENDERER" ); + + // read payload - string of service name, followed by raw render input + const sal_uInt8* pData = pAct->GetData(); + const sal_uInt8* const pEndData = pData + pAct->GetDataSize(); + if( !pData ) + return; + + ::rtl::OUStringBuffer aBuffer; + while( pData<pEndData && *pData ) + aBuffer.append(static_cast<sal_Unicode>(*pData++)); + const ::rtl::OUString aRendererServiceName=aBuffer.makeStringAndClear(); + ++pData; + + while( pData<pEndData && *pData ) + aBuffer.append(static_cast<sal_Unicode>(*pData++)); + const ::rtl::OUString aGraphicServiceName=aBuffer.makeStringAndClear(); + ++pData; + + uno::Reference< lang::XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); + if( pData<pEndData ) + { + try + { + // instantiate render service + uno::Sequence<uno::Any> aRendererArgs(1); + aRendererArgs[0] = makeAny(uno::Reference<awt::XGraphics>(pOut->CreateUnoGraphics())); + uno::Reference<graphic::XGraphicRenderer> xRenderer( + xFactory->createInstanceWithArguments( + aRendererServiceName, + aRendererArgs), + uno::UNO_QUERY ); + + // instantiate graphic service + uno::Reference<graphic::XGraphic> xGraphic( + xFactory->createInstance( + aGraphicServiceName), + uno::UNO_QUERY ); + + uno::Reference<lang::XInitialization> xInit( + xGraphic, uno::UNO_QUERY); + + if(xGraphic.is() && xRenderer.is() && xInit.is()) + { + // delay intialization of XGraphic, to only expose + // XGraphic-generating services to arbitrary binary data + uno::Sequence< sal_Int8 > aSeq( + (sal_Int8*)&pData, pEndData-pData ); + uno::Sequence<uno::Any> aGraphicsArgs(1); + aGraphicsArgs[0] = makeAny(aSeq); + xInit->initialize(aGraphicsArgs); + + xRenderer->render(xGraphic); + } + } + catch (const uno::RuntimeException&) + { + // runtime errors are fatal + throw; + } + catch (const uno::Exception& e) + { + // ignore errors, no way of reporting them here + SAL_WARN("vcl", "GDIMetaFile::ImplDelegate2PluggableRenderer:" + " exception: " << e.Message); + } + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Play( OutputDevice* pOut, const Point& rPos, + const Size& rSize, size_t nPos ) +{ + Region aDrawClipRegion; + MapMode aDrawMap( GetPrefMapMode() ); + Size aDestSize( pOut->LogicToPixel( rSize ) ); + + if( aDestSize.Width() && aDestSize.Height() ) + { + GDIMetaFile* pMtf = pOut->GetConnectMetaFile(); + + if( ImplPlayWithRenderer( pOut, rPos, aDestSize ) ) + return; + + Size aTmpPrefSize( pOut->LogicToPixel( GetPrefSize(), aDrawMap ) ); + + if( !aTmpPrefSize.Width() ) + aTmpPrefSize.Width() = aDestSize.Width(); + + if( !aTmpPrefSize.Height() ) + aTmpPrefSize.Height() = aDestSize.Height(); + + Fraction aScaleX( aDestSize.Width(), aTmpPrefSize.Width() ); + Fraction aScaleY( aDestSize.Height(), aTmpPrefSize.Height() ); + + aScaleX *= aDrawMap.GetScaleX(); aDrawMap.SetScaleX( aScaleX ); + aScaleY *= aDrawMap.GetScaleY(); aDrawMap.SetScaleY( aScaleY ); + + // #i47260# Convert logical output position to offset within + // the metafile's mapmode. Therefore, disable pixel offset on + // outdev, it's inverse mnOutOffLogicX/Y is calculated for a + // different mapmode (the one currently set on pOut, that is) + // - thus, aDrawMap's origin would generally be wrong. And + // even _if_ aDrawMap is similar to pOutDev's current mapmode, + // it's _still_ undesirable to have pixel offset unequal zero, + // because one would still get round-off errors (the + // round-trip error for LogicToPixel( PixelToLogic() ) was the + // reason for having pixel offset in the first place). + const Size& rOldOffset( pOut->GetPixelOffset() ); + const Size aEmptySize; + pOut->SetPixelOffset( aEmptySize ); + aDrawMap.SetOrigin( pOut->PixelToLogic( pOut->LogicToPixel( rPos ), aDrawMap ) ); + pOut->SetPixelOffset( rOldOffset ); + + pOut->Push(); + + if ( pMtf && pMtf->IsRecord() && ( pOut->GetOutDevType() != OUTDEV_PRINTER ) ) + pOut->SetRelativeMapMode( aDrawMap ); + else + pOut->SetMapMode( aDrawMap ); + + // #i23407# Set backwards-compatible text language and layout mode + // This is necessary, since old metafiles don't even know of these + // recent add-ons. Newer metafiles must of course explicitly set + // those states. + pOut->SetLayoutMode( 0 ); + pOut->SetDigitLanguage( 0 ); + + Play( pOut, nPos ); + + pOut->Pop(); + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Pause( sal_Bool _bPause ) +{ + if( bRecord ) + { + if( _bPause ) + { + if( !bPause ) + Linker( pOutDev, sal_False ); + } + else + { + if( bPause ) + Linker( pOutDev, sal_True ); + } + + bPause = _bPause; + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Stop() +{ + if( bRecord ) + { + bRecord = sal_False; + + if( !bPause ) + Linker( pOutDev, sal_False ); + else + bPause = sal_False; + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::WindStart() +{ + if( !bRecord ) + nCurrentActionElement = 0; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::WindPrev() +{ + if( !bRecord ) + if ( nCurrentActionElement > 0 ) + --nCurrentActionElement; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::AddAction( MetaAction* pAction ) +{ + aList.push_back( pAction ); + + if( pPrev ) + { + pAction->Duplicate(); + pPrev->AddAction( pAction ); + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::AddAction( MetaAction* pAction, size_t nPos ) +{ + if ( nPos < aList.size() ) + { + ::std::vector< MetaAction* >::iterator it = aList.begin(); + ::std::advance( it, nPos ); + aList.insert( it, pAction ); + } + else + { + aList.push_back( pAction ); + } + + if( pPrev ) + { + pAction->Duplicate(); + pPrev->AddAction( pAction, nPos ); + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::push_back( MetaAction* pAction ) +{ + aList.push_back( pAction ); +} + +// ------------------------------------------------------------------------ + +// @since #110496# +void GDIMetaFile::RemoveAction( size_t nPos ) +{ + if ( nPos < aList.size() ) + { + ::std::vector< MetaAction* >::iterator it = aList.begin(); + ::std::advance( it, nPos ); + (*it)->Delete(); + aList.erase( it ); + + } + + if( pPrev ) + pPrev->RemoveAction( nPos ); +} + +// ------------------------------------------------------------------------ + +sal_Bool GDIMetaFile::Mirror( sal_uLong nMirrorFlags ) +{ + const Size aOldPrefSize( GetPrefSize() ); + long nMoveX, nMoveY; + double fScaleX, fScaleY; + sal_Bool bRet; + + if( nMirrorFlags & MTF_MIRROR_HORZ ) + nMoveX = SAL_ABS( aOldPrefSize.Width() ) - 1, fScaleX = -1.0; + else + nMoveX = 0, fScaleX = 1.0; + + if( nMirrorFlags & MTF_MIRROR_VERT ) + nMoveY = SAL_ABS( aOldPrefSize.Height() ) - 1, fScaleY = -1.0; + else + nMoveY = 0, fScaleY = 1.0; + + if( ( fScaleX != 1.0 ) || ( fScaleY != 1.0 ) ) + { + Scale( fScaleX, fScaleY ); + Move( nMoveX, nMoveY ); + SetPrefSize( aOldPrefSize ); + bRet = sal_True; + } + else + bRet = sal_False; + + return bRet; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Move( long nX, long nY ) +{ + const Size aBaseOffset( nX, nY ); + Size aOffset( aBaseOffset ); + VirtualDevice aMapVDev; + + aMapVDev.EnableOutput( sal_False ); + aMapVDev.SetMapMode( GetPrefMapMode() ); + + for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() ) + { + const long nType = pAct->GetType(); + MetaAction* pModAct; + + if( pAct->GetRefCount() > 1 ) + { + aList[ nCurrentActionElement ] = pModAct = pAct->Clone(); + pAct->Delete(); + } + else + pModAct = pAct; + + if( ( META_MAPMODE_ACTION == nType ) || + ( META_PUSH_ACTION == nType ) || + ( META_POP_ACTION == nType ) ) + { + pModAct->Execute( &aMapVDev ); + aOffset = aMapVDev.LogicToLogic( aBaseOffset, GetPrefMapMode(), aMapVDev.GetMapMode() ); + } + + pModAct->Move( aOffset.Width(), aOffset.Height() ); + } +} + +void GDIMetaFile::Move( long nX, long nY, long nDPIX, long nDPIY ) +{ + const Size aBaseOffset( nX, nY ); + Size aOffset( aBaseOffset ); + VirtualDevice aMapVDev; + + aMapVDev.EnableOutput( sal_False ); + aMapVDev.SetReferenceDevice( nDPIX, nDPIY ); + aMapVDev.SetMapMode( GetPrefMapMode() ); + + for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() ) + { + const long nType = pAct->GetType(); + MetaAction* pModAct; + + if( pAct->GetRefCount() > 1 ) + { + aList[ nCurrentActionElement ] = pModAct = pAct->Clone(); + pAct->Delete(); + } + else + pModAct = pAct; + + if( ( META_MAPMODE_ACTION == nType ) || + ( META_PUSH_ACTION == nType ) || + ( META_POP_ACTION == nType ) ) + { + pModAct->Execute( &aMapVDev ); + if( aMapVDev.GetMapMode().GetMapUnit() == MAP_PIXEL ) + { + aOffset = aMapVDev.LogicToPixel( aBaseOffset, GetPrefMapMode() ); + MapMode aMap( aMapVDev.GetMapMode() ); + aOffset.Width() = static_cast<long>(aOffset.Width() * (double)aMap.GetScaleX()); + aOffset.Height() = static_cast<long>(aOffset.Height() * (double)aMap.GetScaleY()); + } + else + aOffset = aMapVDev.LogicToLogic( aBaseOffset, GetPrefMapMode(), aMapVDev.GetMapMode() ); + } + + pModAct->Move( aOffset.Width(), aOffset.Height() ); + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Scale( double fScaleX, double fScaleY ) +{ + for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() ) + { + MetaAction* pModAct; + + if( pAct->GetRefCount() > 1 ) + { + aList[ nCurrentActionElement ] = pModAct = pAct->Clone(); + pAct->Delete(); + } + else + pModAct = pAct; + + pModAct->Scale( fScaleX, fScaleY ); + } + + aPrefSize.Width() = FRound( aPrefSize.Width() * fScaleX ); + aPrefSize.Height() = FRound( aPrefSize.Height() * fScaleY ); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Scale( const Fraction& rScaleX, const Fraction& rScaleY ) +{ + Scale( (double) rScaleX, (double) rScaleY ); +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Clip( const Rectangle& i_rClipRect ) +{ + Rectangle aCurRect( i_rClipRect ); + VirtualDevice aMapVDev; + + aMapVDev.EnableOutput( sal_False ); + aMapVDev.SetMapMode( GetPrefMapMode() ); + + for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() ) + { + const long nType = pAct->GetType(); + + if( ( META_MAPMODE_ACTION == nType ) || + ( META_PUSH_ACTION == nType ) || + ( META_POP_ACTION == nType ) ) + { + pAct->Execute( &aMapVDev ); + aCurRect = aMapVDev.LogicToLogic( i_rClipRect, GetPrefMapMode(), aMapVDev.GetMapMode() ); + } + else if( nType == META_CLIPREGION_ACTION ) + { + MetaClipRegionAction* pOldAct = (MetaClipRegionAction*)pAct; + Region aNewReg( aCurRect ); + if( pOldAct->IsClipping() ) + aNewReg.Intersect( pOldAct->GetRegion() ); + MetaClipRegionAction* pNewAct = new MetaClipRegionAction( aNewReg, sal_True ); + aList[ nCurrentActionElement ] = pNewAct; + pOldAct->Delete(); + } + } +} + +// ------------------------------------------------------------------------ + +Point GDIMetaFile::ImplGetRotatedPoint( const Point& rPt, const Point& rRotatePt, + const Size& rOffset, double fSin, double fCos ) +{ + const long nX = rPt.X() - rRotatePt.X(); + const long nY = rPt.Y() - rRotatePt.Y(); + + return Point( FRound( fCos * nX + fSin * nY ) + rRotatePt.X() + rOffset.Width(), + -FRound( fSin * nX - fCos * nY ) + rRotatePt.Y() + rOffset.Height() ); +} + +// ------------------------------------------------------------------------ + +Polygon GDIMetaFile::ImplGetRotatedPolygon( const Polygon& rPoly, const Point& rRotatePt, + const Size& rOffset, double fSin, double fCos ) +{ + Polygon aRet( rPoly ); + + aRet.Rotate( rRotatePt, fSin, fCos ); + aRet.Move( rOffset.Width(), rOffset.Height() ); + + return aRet; +} + +// ------------------------------------------------------------------------ + +PolyPolygon GDIMetaFile::ImplGetRotatedPolyPolygon( const PolyPolygon& rPolyPoly, const Point& rRotatePt, + const Size& rOffset, double fSin, double fCos ) +{ + PolyPolygon aRet( rPolyPoly ); + + aRet.Rotate( rRotatePt, fSin, fCos ); + aRet.Move( rOffset.Width(), rOffset.Height() ); + + return aRet; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::ImplAddGradientEx( GDIMetaFile& rMtf, + const OutputDevice& rMapDev, + const PolyPolygon& rPolyPoly, + const Gradient& rGrad ) +{ + // #105055# Generate comment, GradientEx and Gradient actions + // (within DrawGradient) + VirtualDevice aVDev( rMapDev, 0 ); + aVDev.EnableOutput( sal_False ); + GDIMetaFile aGradMtf; + + aGradMtf.Record( &aVDev ); + aVDev.DrawGradient( rPolyPoly, rGrad ); + aGradMtf.Stop(); + + size_t i, nAct( aGradMtf.GetActionSize() ); + for( i=0; i < nAct; ++i ) + { + MetaAction* pMetaAct = aGradMtf.GetAction( i ); + pMetaAct->Duplicate(); + rMtf.AddAction( pMetaAct ); + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Rotate( long nAngle10 ) +{ + nAngle10 %= 3600L; + nAngle10 = ( nAngle10 < 0L ) ? ( 3599L + nAngle10 ) : nAngle10; + + if( nAngle10 ) + { + GDIMetaFile aMtf; + VirtualDevice aMapVDev; + const double fAngle = F_PI1800 * nAngle10; + const double fSin = sin( fAngle ); + const double fCos = cos( fAngle ); + Rectangle aRect=Rectangle( Point(), GetPrefSize() ); + Polygon aPoly( aRect ); + + aPoly.Rotate( Point(), fSin, fCos ); + + aMapVDev.EnableOutput( sal_False ); + aMapVDev.SetMapMode( GetPrefMapMode() ); + + const Rectangle aNewBound( aPoly.GetBoundRect() ); + + const Point aOrigin( GetPrefMapMode().GetOrigin().X(), GetPrefMapMode().GetOrigin().Y() ); + const Size aOffset( -aNewBound.Left(), -aNewBound.Top() ); + + Point aRotAnchor( aOrigin ); + Size aRotOffset( aOffset ); + + for( MetaAction* pAction = FirstAction(); pAction; pAction = NextAction() ) + { + const sal_uInt16 nActionType = pAction->GetType(); + + switch( nActionType ) + { + case( META_PIXEL_ACTION ): + { + MetaPixelAction* pAct = (MetaPixelAction*) pAction; + aMtf.AddAction( new MetaPixelAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ), + pAct->GetColor() ) ); + } + break; + + case( META_POINT_ACTION ): + { + MetaPointAction* pAct = (MetaPointAction*) pAction; + aMtf.AddAction( new MetaPointAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ) ) ); + } + break; + + case( META_LINE_ACTION ): + { + MetaLineAction* pAct = (MetaLineAction*) pAction; + aMtf.AddAction( new MetaLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ), + ImplGetRotatedPoint( pAct->GetEndPoint(), aRotAnchor, aRotOffset, fSin, fCos ), + pAct->GetLineInfo() ) ); + } + break; + + case( META_RECT_ACTION ): + { + MetaRectAction* pAct = (MetaRectAction*) pAction; + aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ) ) ); + } + break; + + case( META_ROUNDRECT_ACTION ): + { + MetaRoundRectAction* pAct = (MetaRoundRectAction*) pAction; + const Polygon aRoundRectPoly( pAct->GetRect(), pAct->GetHorzRound(), pAct->GetVertRound() ); + + aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aRoundRectPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) ); + } + break; + + case( META_ELLIPSE_ACTION ): + { + MetaEllipseAction* pAct = (MetaEllipseAction*) pAction; + const Polygon aEllipsePoly( pAct->GetRect().Center(), pAct->GetRect().GetWidth() >> 1, pAct->GetRect().GetHeight() >> 1 ); + + aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aEllipsePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) ); + } + break; + + case( META_ARC_ACTION ): + { + MetaArcAction* pAct = (MetaArcAction*) pAction; + const Polygon aArcPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), POLY_ARC ); + + aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aArcPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) ); + } + break; + + case( META_PIE_ACTION ): + { + MetaPieAction* pAct = (MetaPieAction*) pAction; + const Polygon aPiePoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), POLY_PIE ); + + aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aPiePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) ); + } + break; + + case( META_CHORD_ACTION ): + { + MetaChordAction* pAct = (MetaChordAction*) pAction; + const Polygon aChordPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), POLY_CHORD ); + + aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aChordPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) ); + } + break; + + case( META_POLYLINE_ACTION ): + { + MetaPolyLineAction* pAct = (MetaPolyLineAction*) pAction; + aMtf.AddAction( new MetaPolyLineAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->GetLineInfo() ) ); + } + break; + + case( META_POLYGON_ACTION ): + { + MetaPolygonAction* pAct = (MetaPolygonAction*) pAction; + aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) ); + } + break; + + case( META_POLYPOLYGON_ACTION ): + { + MetaPolyPolygonAction* pAct = (MetaPolyPolygonAction*) pAction; + aMtf.AddAction( new MetaPolyPolygonAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) ); + } + break; + + case( META_TEXT_ACTION ): + { + MetaTextAction* pAct = (MetaTextAction*) pAction; + aMtf.AddAction( new MetaTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ), + pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) ); + } + break; + + case( META_TEXTARRAY_ACTION ): + { + MetaTextArrayAction* pAct = (MetaTextArrayAction*) pAction; + aMtf.AddAction( new MetaTextArrayAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ), + pAct->GetText(), pAct->GetDXArray(), pAct->GetIndex(), pAct->GetLen() ) ); + } + break; + + case( META_STRETCHTEXT_ACTION ): + { + MetaStretchTextAction* pAct = (MetaStretchTextAction*) pAction; + aMtf.AddAction( new MetaStretchTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ), + pAct->GetWidth(), pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) ); + } + break; + + case( META_TEXTLINE_ACTION ): + { + MetaTextLineAction* pAct = (MetaTextLineAction*) pAction; + aMtf.AddAction( new MetaTextLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ), + pAct->GetWidth(), pAct->GetStrikeout(), pAct->GetUnderline(), pAct->GetOverline() ) ); + } + break; + + case( META_BMPSCALE_ACTION ): + { + MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction; + Polygon aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) ); + Rectangle aBmpRect( aBmpPoly.GetBoundRect() ); + BitmapEx aBmpEx( pAct->GetBitmap() ); + + aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) ); + aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), + aBmpEx ) ); + } + break; + + case( META_BMPSCALEPART_ACTION ): + { + MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction; + Polygon aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() ), aRotAnchor, aRotOffset, fSin, fCos ) ); + Rectangle aBmpRect( aBmpPoly.GetBoundRect() ); + BitmapEx aBmpEx( pAct->GetBitmap() ); + + aBmpEx.Crop( Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) ); + aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) ); + + aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) ); + } + break; + + case( META_BMPEXSCALE_ACTION ): + { + MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction; + Polygon aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) ); + Rectangle aBmpRect( aBmpPoly.GetBoundRect() ); + BitmapEx aBmpEx( pAct->GetBitmapEx() ); + + aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) ); + + aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) ); + } + break; + + case( META_BMPEXSCALEPART_ACTION ): + { + MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction; + Polygon aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() ), aRotAnchor, aRotOffset, fSin, fCos ) ); + Rectangle aBmpRect( aBmpPoly.GetBoundRect() ); + BitmapEx aBmpEx( pAct->GetBitmapEx() ); + + aBmpEx.Crop( Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) ); + aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) ); + + aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) ); + } + break; + + case( META_GRADIENT_ACTION ): + { + MetaGradientAction* pAct = (MetaGradientAction*) pAction; + + ImplAddGradientEx( aMtf, aMapVDev, + ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ), + pAct->GetGradient() ); + } + break; + + case( META_GRADIENTEX_ACTION ): + { + MetaGradientExAction* pAct = (MetaGradientExAction*) pAction; + aMtf.AddAction( new MetaGradientExAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), + pAct->GetGradient() ) ); + } + break; + + // #105055# Handle gradientex comment block correctly + case( META_COMMENT_ACTION ): + { + MetaCommentAction* pCommentAct = (MetaCommentAction*) pAction; + if( pCommentAct->GetComment() == "XGRAD_SEQ_BEGIN" ) + { + int nBeginComments( 1 ); + pAction = NextAction(); + + // skip everything, except gradientex action + while( pAction ) + { + const sal_uInt16 nType = pAction->GetType(); + + if( META_GRADIENTEX_ACTION == nType ) + { + // Add rotated gradientex + MetaGradientExAction* pAct = (MetaGradientExAction*) pAction; + ImplAddGradientEx( aMtf, aMapVDev, + ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), + pAct->GetGradient() ); + } + else if( META_COMMENT_ACTION == nType) + { + MetaCommentAction* pAct = (MetaCommentAction*) pAction; + if( pAct->GetComment() == "XGRAD_SEQ_END" ) + { + // handle nested blocks + --nBeginComments; + + // gradientex comment block: end reached, done. + if( !nBeginComments ) + break; + } + else if( pAct->GetComment() == "XGRAD_SEQ_BEGIN" ) + { + // handle nested blocks + ++nBeginComments; + } + + } + + pAction =NextAction(); + } + } + else + { + sal_Bool bPathStroke = (pCommentAct->GetComment() == "XPATHSTROKE_SEQ_BEGIN"); + if ( bPathStroke || pCommentAct->GetComment() == "XPATHFILL_SEQ_BEGIN" ) + { + if ( pCommentAct->GetDataSize() ) + { + SvMemoryStream aMemStm( (void*)pCommentAct->GetData(), pCommentAct->GetDataSize(), STREAM_READ ); + SvMemoryStream aDest; + if ( bPathStroke ) + { + SvtGraphicStroke aStroke; + aMemStm >> aStroke; + Polygon aPath; + aStroke.getPath( aPath ); + aStroke.setPath( ImplGetRotatedPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) ); + aDest << aStroke; + aMtf.AddAction( new MetaCommentAction( "XPATHSTROKE_SEQ_BEGIN", 0, + static_cast<const sal_uInt8*>( aDest.GetData()), aDest.Tell() ) ); + } + else + { + SvtGraphicFill aFill; + aMemStm >> aFill; + PolyPolygon aPath; + aFill.getPath( aPath ); + aFill.setPath( ImplGetRotatedPolyPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) ); + aDest << aFill; + aMtf.AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0, + static_cast<const sal_uInt8*>( aDest.GetData()), aDest.Tell() ) ); + } + } + } + else if ( pCommentAct->GetComment() == "XPATHSTROKE_SEQ_END" + || pCommentAct->GetComment() == "XPATHFILL_SEQ_END" ) + { + pAction->Execute( &aMapVDev ); + pAction->Duplicate(); + aMtf.AddAction( pAction ); + } + } + } + break; + + case( META_HATCH_ACTION ): + { + MetaHatchAction* pAct = (MetaHatchAction*) pAction; + Hatch aHatch( pAct->GetHatch() ); + + aHatch.SetAngle( aHatch.GetAngle() + (sal_uInt16) nAngle10 ); + aMtf.AddAction( new MetaHatchAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), + aHatch ) ); + } + break; + + case( META_TRANSPARENT_ACTION ): + { + MetaTransparentAction* pAct = (MetaTransparentAction*) pAction; + aMtf.AddAction( new MetaTransparentAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), + pAct->GetTransparence() ) ); + } + break; + + case( META_FLOATTRANSPARENT_ACTION ): + { + MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction; + GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() ); + Polygon aMtfPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) ); + Rectangle aMtfRect( aMtfPoly.GetBoundRect() ); + + aTransMtf.Rotate( nAngle10 ); + aMtf.AddAction( new MetaFloatTransparentAction( aTransMtf, aMtfRect.TopLeft(), aMtfRect.GetSize(), + pAct->GetGradient() ) ); + } + break; + + case( META_EPS_ACTION ): + { + MetaEPSAction* pAct = (MetaEPSAction*) pAction; + GDIMetaFile aEPSMtf( pAct->GetSubstitute() ); + Polygon aEPSPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) ); + Rectangle aEPSRect( aEPSPoly.GetBoundRect() ); + + aEPSMtf.Rotate( nAngle10 ); + aMtf.AddAction( new MetaEPSAction( aEPSRect.TopLeft(), aEPSRect.GetSize(), + pAct->GetLink(), aEPSMtf ) ); + } + break; + + case( META_CLIPREGION_ACTION ): + { + MetaClipRegionAction* pAct = (MetaClipRegionAction*) pAction; + + if( pAct->IsClipping() && pAct->GetRegion().HasPolyPolygon() ) + aMtf.AddAction( new MetaClipRegionAction( Region( ImplGetRotatedPolyPolygon( pAct->GetRegion().GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ), sal_True ) ); + else + { + pAction->Duplicate(); + aMtf.AddAction( pAction ); + } + } + break; + + case( META_ISECTRECTCLIPREGION_ACTION ): + { + MetaISectRectClipRegionAction* pAct = (MetaISectRectClipRegionAction*) pAction; + aMtf.AddAction( new MetaISectRegionClipRegionAction( ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ) ) ); + } + break; + + case( META_ISECTREGIONCLIPREGION_ACTION ): + { + MetaISectRegionClipRegionAction* pAct = (MetaISectRegionClipRegionAction*) pAction; + const Region& rRegion = pAct->GetRegion(); + + if( rRegion.HasPolyPolygon() ) + aMtf.AddAction( new MetaISectRegionClipRegionAction( Region( ImplGetRotatedPolyPolygon( rRegion.GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) ) ); + else + { + pAction->Duplicate(); + aMtf.AddAction( pAction ); + } + } + break; + + case( META_REFPOINT_ACTION ): + { + MetaRefPointAction* pAct = (MetaRefPointAction*) pAction; + aMtf.AddAction( new MetaRefPointAction( ImplGetRotatedPoint( pAct->GetRefPoint(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->IsSetting() ) ); + } + break; + + case( META_FONT_ACTION ): + { + MetaFontAction* pAct = (MetaFontAction*) pAction; + Font aFont( pAct->GetFont() ); + + aFont.SetOrientation( aFont.GetOrientation() + (sal_uInt16) nAngle10 ); + aMtf.AddAction( new MetaFontAction( aFont ) ); + } + break; + + case( META_BMP_ACTION ): + case( META_BMPEX_ACTION ): + case( META_MASK_ACTION ): + case( META_MASKSCALE_ACTION ): + case( META_MASKSCALEPART_ACTION ): + case( META_WALLPAPER_ACTION ): + case( META_TEXTRECT_ACTION ): + case( META_MOVECLIPREGION_ACTION ): + { + OSL_FAIL( "GDIMetaFile::Rotate(): unsupported action" ); + } + break; + + default: + { + pAction->Execute( &aMapVDev ); + pAction->Duplicate(); + aMtf.AddAction( pAction ); + + // update rotation point and offset, if necessary + if( ( META_MAPMODE_ACTION == nActionType ) || + ( META_PUSH_ACTION == nActionType ) || + ( META_POP_ACTION == nActionType ) ) + { + aRotAnchor = aMapVDev.LogicToLogic( aOrigin, aPrefMapMode, aMapVDev.GetMapMode() ); + aRotOffset = aMapVDev.LogicToLogic( aOffset, aPrefMapMode, aMapVDev.GetMapMode() ); + } + } + break; + } + } + + aMtf.aPrefMapMode = aPrefMapMode; + aMtf.aPrefSize = aNewBound.GetSize(); + + *this = aMtf; + } +} + +// ------------------------------------------------------------------------ + +static void ImplActionBounds( Rectangle& o_rOutBounds, + const Rectangle& i_rInBounds, + const std::vector<Rectangle>& i_rClipStack, + Rectangle* o_pHairline ) +{ + Rectangle aBounds( i_rInBounds ); + if( ! i_rInBounds.IsEmpty() && ! i_rClipStack.empty() && ! i_rClipStack.back().IsEmpty() ) + aBounds.Intersection( i_rClipStack.back() ); + if( ! aBounds.IsEmpty() ) + { + if( ! o_rOutBounds.IsEmpty() ) + o_rOutBounds.Union( aBounds ); + else + o_rOutBounds = aBounds; + + if(o_pHairline) + { + if( ! o_pHairline->IsEmpty() ) + o_pHairline->Union( aBounds ); + else + *o_pHairline = aBounds; + } + } +} + +Rectangle GDIMetaFile::GetBoundRect( OutputDevice& i_rReference, Rectangle* pHairline ) const +{ + GDIMetaFile aMtf; + VirtualDevice aMapVDev( i_rReference ); + + aMapVDev.EnableOutput( sal_False ); + aMapVDev.SetMapMode( GetPrefMapMode() ); + + std::vector<Rectangle> aClipStack( 1, Rectangle() ); + std::vector<sal_uInt16> aPushFlagStack; + + Rectangle aBound; + + if(pHairline) + *pHairline = Rectangle(); + + const sal_uLong nCount(GetActionSize()); + + for(sal_uLong a(0); a < nCount; a++) + { + MetaAction* pAction = GetAction(a); + const sal_uInt16 nActionType = pAction->GetType(); + Rectangle* pUseHairline = (pHairline && aMapVDev.IsLineColor()) ? pHairline : 0; + + switch( nActionType ) + { + case( META_PIXEL_ACTION ): + { + MetaPixelAction* pAct = (MetaPixelAction*) pAction; + ImplActionBounds( aBound, + Rectangle( aMapVDev.LogicToLogic( pAct->GetPoint(), aMapVDev.GetMapMode(), GetPrefMapMode() ), + aMapVDev.PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ), + aClipStack, pUseHairline ); + } + break; + + case( META_POINT_ACTION ): + { + MetaPointAction* pAct = (MetaPointAction*) pAction; + ImplActionBounds( aBound, + Rectangle( aMapVDev.LogicToLogic( pAct->GetPoint(), aMapVDev.GetMapMode(), GetPrefMapMode() ), + aMapVDev.PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ), + aClipStack, pUseHairline ); + } + break; + + case( META_LINE_ACTION ): + { + MetaLineAction* pAct = (MetaLineAction*) pAction; + Point aP1( pAct->GetStartPoint() ), aP2( pAct->GetEndPoint() ); + Rectangle aRect( aP1, aP2 ); + aRect.Justify(); + + if(pUseHairline) + { + const LineInfo& rLineInfo = pAct->GetLineInfo(); + + if(0 != rLineInfo.GetWidth()) + pUseHairline = 0; + } + + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline ); + } + break; + + case( META_RECT_ACTION ): + { + MetaRectAction* pAct = (MetaRectAction*) pAction; + ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline ); + } + break; + + case( META_ROUNDRECT_ACTION ): + { + MetaRoundRectAction* pAct = (MetaRoundRectAction*) pAction; + ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline ); + } + break; + + case( META_ELLIPSE_ACTION ): + { + MetaEllipseAction* pAct = (MetaEllipseAction*) pAction; + ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline ); + } + break; + + case( META_ARC_ACTION ): + { + MetaArcAction* pAct = (MetaArcAction*) pAction; + // FIXME: this is imprecise + // e.g. for small arcs the whole rectangle is WAY too large + ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline ); + } + break; + + case( META_PIE_ACTION ): + { + MetaPieAction* pAct = (MetaPieAction*) pAction; + // FIXME: this is imprecise + // e.g. for small arcs the whole rectangle is WAY too large + ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline ); + } + break; + + case( META_CHORD_ACTION ): + { + MetaChordAction* pAct = (MetaChordAction*) pAction; + // FIXME: this is imprecise + // e.g. for small arcs the whole rectangle is WAY too large + ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline ); + } + break; + + case( META_POLYLINE_ACTION ): + { + MetaPolyLineAction* pAct = (MetaPolyLineAction*) pAction; + Rectangle aRect( pAct->GetPolygon().GetBoundRect() ); + + if(pUseHairline) + { + const LineInfo& rLineInfo = pAct->GetLineInfo(); + + if(0 != rLineInfo.GetWidth()) + pUseHairline = 0; + } + + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline ); + } + break; + + case( META_POLYGON_ACTION ): + { + MetaPolygonAction* pAct = (MetaPolygonAction*) pAction; + Rectangle aRect( pAct->GetPolygon().GetBoundRect() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline ); + } + break; + + case( META_POLYPOLYGON_ACTION ): + { + MetaPolyPolygonAction* pAct = (MetaPolyPolygonAction*) pAction; + Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline ); + } + break; + + case( META_TEXT_ACTION ): + { + MetaTextAction* pAct = (MetaTextAction*) pAction; + Rectangle aRect; + // hdu said base = index + aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen() ); + Point aPt( pAct->GetPoint() ); + aRect.Move( aPt.X(), aPt.Y() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_TEXTARRAY_ACTION ): + { + MetaTextArrayAction* pAct = (MetaTextArrayAction*) pAction; + Rectangle aRect; + // hdu said base = index + aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(), + 0, pAct->GetDXArray() ); + Point aPt( pAct->GetPoint() ); + aRect.Move( aPt.X(), aPt.Y() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_STRETCHTEXT_ACTION ): + { + MetaStretchTextAction* pAct = (MetaStretchTextAction*) pAction; + Rectangle aRect; + // hdu said base = index + aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(), + pAct->GetWidth(), NULL ); + Point aPt( pAct->GetPoint() ); + aRect.Move( aPt.X(), aPt.Y() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_TEXTLINE_ACTION ): + { + MetaTextLineAction* pAct = (MetaTextLineAction*) pAction; + // measure a test string to get ascend and descent right + static const sal_Unicode pStr[] = { 0xc4, 0x67, 0 }; + rtl::OUString aStr( pStr ); + + Rectangle aRect; + aMapVDev.GetTextBoundRect( aRect, aStr, 0, 0, aStr.getLength(), 0, NULL ); + Point aPt( pAct->GetStartPoint() ); + aRect.Move( aPt.X(), aPt.Y() ); + aRect.Right() = aRect.Left() + pAct->GetWidth(); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_BMPSCALE_ACTION ): + { + MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction; + Rectangle aRect( pAct->GetPoint(), pAct->GetSize() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_BMPSCALEPART_ACTION ): + { + MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction; + Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_BMPEXSCALE_ACTION ): + { + MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction; + Rectangle aRect( pAct->GetPoint(), pAct->GetSize() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_BMPEXSCALEPART_ACTION ): + { + MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction; + Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_GRADIENT_ACTION ): + { + MetaGradientAction* pAct = (MetaGradientAction*) pAction; + Rectangle aRect( pAct->GetRect() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_GRADIENTEX_ACTION ): + { + MetaGradientExAction* pAct = (MetaGradientExAction*) pAction; + Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_COMMENT_ACTION ): + { + // nothing to do + }; + break; + + case( META_HATCH_ACTION ): + { + MetaHatchAction* pAct = (MetaHatchAction*) pAction; + Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_TRANSPARENT_ACTION ): + { + MetaTransparentAction* pAct = (MetaTransparentAction*) pAction; + Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_FLOATTRANSPARENT_ACTION ): + { + MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction; + // MetaFloatTransparentAction is defined limiting it's content Metafile + // to it's geometry definition(Point, Size), so use these directly + const Rectangle aRect( pAct->GetPoint(), pAct->GetSize() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_EPS_ACTION ): + { + MetaEPSAction* pAct = (MetaEPSAction*) pAction; + Rectangle aRect( pAct->GetPoint(), pAct->GetSize() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_CLIPREGION_ACTION ): + { + MetaClipRegionAction* pAct = (MetaClipRegionAction*) pAction; + if( pAct->IsClipping() ) + aClipStack.back() = aMapVDev.LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ); + else + aClipStack.back() = Rectangle(); + } + break; + + case( META_ISECTRECTCLIPREGION_ACTION ): + { + MetaISectRectClipRegionAction* pAct = (MetaISectRectClipRegionAction*) pAction; + Rectangle aRect( aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ) ); + if( aClipStack.back().IsEmpty() ) + aClipStack.back() = aRect; + else + aClipStack.back().Intersection( aRect ); + } + break; + + case( META_ISECTREGIONCLIPREGION_ACTION ): + { + MetaISectRegionClipRegionAction* pAct = (MetaISectRegionClipRegionAction*) pAction; + Rectangle aRect( aMapVDev.LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ) ); + if( aClipStack.back().IsEmpty() ) + aClipStack.back() = aRect; + else + aClipStack.back().Intersection( aRect ); + } + break; + + case( META_BMP_ACTION ): + { + MetaBmpAction* pAct = (MetaBmpAction*) pAction; + Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmap().GetSizePixel() ) ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_BMPEX_ACTION ): + { + MetaBmpExAction* pAct = (MetaBmpExAction*) pAction; + Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmapEx().GetSizePixel() ) ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_MASK_ACTION ): + { + MetaMaskAction* pAct = (MetaMaskAction*) pAction; + Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmap().GetSizePixel() ) ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_MASKSCALE_ACTION ): + { + MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction; + Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_MASKSCALEPART_ACTION ): + { + MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction; + Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_WALLPAPER_ACTION ): + { + MetaWallpaperAction* pAct = (MetaWallpaperAction*) pAction; + Rectangle aRect( pAct->GetRect() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_TEXTRECT_ACTION ): + { + MetaTextRectAction* pAct = (MetaTextRectAction*) pAction; + Rectangle aRect( pAct->GetRect() ); + ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 ); + } + break; + + case( META_MOVECLIPREGION_ACTION ): + { + MetaMoveClipRegionAction* pAct = (MetaMoveClipRegionAction*) pAction; + if( ! aClipStack.back().IsEmpty() ) + { + Size aDelta( pAct->GetHorzMove(), pAct->GetVertMove() ); + aDelta = aMapVDev.LogicToLogic( aDelta, aMapVDev.GetMapMode(), GetPrefMapMode() ); + aClipStack.back().Move( aDelta.Width(), aDelta.Width() ); + } + } + break; + + default: + { + pAction->Execute( &aMapVDev ); + + if( nActionType == META_PUSH_ACTION ) + { + MetaPushAction* pAct = (MetaPushAction*) pAction; + aPushFlagStack.push_back( pAct->GetFlags() ); + if( (aPushFlagStack.back() & PUSH_CLIPREGION) != 0 ) + { + Rectangle aRect( aClipStack.back() ); + aClipStack.push_back( aRect ); + } + } + else if( nActionType == META_POP_ACTION ) + { + // sanity check + if( ! aPushFlagStack.empty() ) + { + if( (aPushFlagStack.back() & PUSH_CLIPREGION) != 0 ) + { + if( aClipStack.size() > 1 ) + aClipStack.pop_back(); + } + aPushFlagStack.pop_back(); + } + } + } + break; + } + } + return aBound; +} + +// ------------------------------------------------------------------------ + +Color GDIMetaFile::ImplColAdjustFnc( const Color& rColor, const void* pColParam ) +{ + return Color( rColor.GetTransparency(), + ( (const ImplColAdjustParam*) pColParam )->pMapR[ rColor.GetRed() ], + ( (const ImplColAdjustParam*) pColParam )->pMapG[ rColor.GetGreen() ], + ( (const ImplColAdjustParam*) pColParam )->pMapB[ rColor.GetBlue() ] ); + +} + +// ------------------------------------------------------------------------ + +BitmapEx GDIMetaFile::ImplBmpAdjustFnc( const BitmapEx& rBmpEx, const void* pBmpParam ) +{ + const ImplBmpAdjustParam* p = (const ImplBmpAdjustParam*) pBmpParam; + BitmapEx aRet( rBmpEx ); + + aRet.Adjust( p->nLuminancePercent, p->nContrastPercent, + p->nChannelRPercent, p->nChannelGPercent, p->nChannelBPercent, + p->fGamma, p->bInvert ); + + return aRet; +} + +// ------------------------------------------------------------------------ + +Color GDIMetaFile::ImplColConvertFnc( const Color& rColor, const void* pColParam ) +{ + sal_uInt8 cLum = rColor.GetLuminance(); + + if( MTF_CONVERSION_1BIT_THRESHOLD == ( (const ImplColConvertParam*) pColParam )->eConversion ) + cLum = ( cLum < 128 ) ? 0 : 255; + + return Color( rColor.GetTransparency(), cLum, cLum, cLum ); +} + +// ------------------------------------------------------------------------ + +BitmapEx GDIMetaFile::ImplBmpConvertFnc( const BitmapEx& rBmpEx, const void* pBmpParam ) +{ + BitmapEx aRet( rBmpEx ); + + aRet.Convert( ( (const ImplBmpConvertParam*) pBmpParam )->eConversion ); + + return aRet; +} + +// ------------------------------------------------------------------------ + +Color GDIMetaFile::ImplColMonoFnc( const Color&, const void* pColParam ) +{ + return( ( (const ImplColMonoParam*) pColParam )->aColor ); +} + +// ------------------------------------------------------------------------ + +BitmapEx GDIMetaFile::ImplBmpMonoFnc( const BitmapEx& rBmpEx, const void* pBmpParam ) +{ + BitmapPalette aPal( 3 ); + + aPal[ 0 ] = Color( COL_BLACK ); + aPal[ 1 ] = Color( COL_WHITE ); + aPal[ 2 ] = ( (const ImplBmpMonoParam*) pBmpParam )->aColor; + + Bitmap aBmp( rBmpEx.GetSizePixel(), 4, &aPal ); + aBmp.Erase( ( (const ImplBmpMonoParam*) pBmpParam )->aColor ); + + if( rBmpEx.IsAlpha() ) + return BitmapEx( aBmp, rBmpEx.GetAlpha() ); + else if( rBmpEx.IsTransparent() ) + return BitmapEx( aBmp, rBmpEx.GetMask() ); + else + return aBmp; +} + +// ------------------------------------------------------------------------ + +Color GDIMetaFile::ImplColReplaceFnc( const Color& rColor, const void* pColParam ) +{ + const sal_uLong nR = rColor.GetRed(), nG = rColor.GetGreen(), nB = rColor.GetBlue(); + + for( sal_uLong i = 0; i < ( (const ImplColReplaceParam*) pColParam )->nCount; i++ ) + { + if( ( ( (const ImplColReplaceParam*) pColParam )->pMinR[ i ] <= nR ) && + ( ( (const ImplColReplaceParam*) pColParam )->pMaxR[ i ] >= nR ) && + ( ( (const ImplColReplaceParam*) pColParam )->pMinG[ i ] <= nG ) && + ( ( (const ImplColReplaceParam*) pColParam )->pMaxG[ i ] >= nG ) && + ( ( (const ImplColReplaceParam*) pColParam )->pMinB[ i ] <= nB ) && + ( ( (const ImplColReplaceParam*) pColParam )->pMaxB[ i ] >= nB ) ) + { + return( ( (const ImplColReplaceParam*) pColParam )->pDstCols[ i ] ); + } + } + + return rColor; +} + +// ------------------------------------------------------------------------ + +BitmapEx GDIMetaFile::ImplBmpReplaceFnc( const BitmapEx& rBmpEx, const void* pBmpParam ) +{ + const ImplBmpReplaceParam* p = (const ImplBmpReplaceParam*) pBmpParam; + BitmapEx aRet( rBmpEx ); + + aRet.Replace( p->pSrcCols, p->pDstCols, p->nCount, p->pTols ); + + return aRet; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::ImplExchangeColors( ColorExchangeFnc pFncCol, const void* pColParam, + BmpExchangeFnc pFncBmp, const void* pBmpParam ) +{ + GDIMetaFile aMtf; + + aMtf.aPrefSize = aPrefSize; + aMtf.aPrefMapMode = aPrefMapMode; + aMtf.bUseCanvas = bUseCanvas; + + for( MetaAction* pAction = FirstAction(); pAction; pAction = NextAction() ) + { + const sal_uInt16 nType = pAction->GetType(); + + switch( nType ) + { + case( META_PIXEL_ACTION ): + { + MetaPixelAction* pAct = (MetaPixelAction*) pAction; + aMtf.push_back( new MetaPixelAction( pAct->GetPoint(), pFncCol( pAct->GetColor(), pColParam ) ) ); + } + break; + + case( META_LINECOLOR_ACTION ): + { + MetaLineColorAction* pAct = (MetaLineColorAction*) pAction; + + if( !pAct->IsSetting() ) + pAct->Duplicate(); + else + pAct = new MetaLineColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True ); + + aMtf.push_back( pAct ); + } + break; + + case( META_FILLCOLOR_ACTION ): + { + MetaFillColorAction* pAct = (MetaFillColorAction*) pAction; + + if( !pAct->IsSetting() ) + pAct->Duplicate(); + else + pAct = new MetaFillColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True ); + + aMtf.push_back( pAct ); + } + break; + + case( META_TEXTCOLOR_ACTION ): + { + MetaTextColorAction* pAct = (MetaTextColorAction*) pAction; + aMtf.push_back( new MetaTextColorAction( pFncCol( pAct->GetColor(), pColParam ) ) ); + } + break; + + case( META_TEXTFILLCOLOR_ACTION ): + { + MetaTextFillColorAction* pAct = (MetaTextFillColorAction*) pAction; + + if( !pAct->IsSetting() ) + pAct->Duplicate(); + else + pAct = new MetaTextFillColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True ); + + aMtf.push_back( pAct ); + } + break; + + case( META_TEXTLINECOLOR_ACTION ): + { + MetaTextLineColorAction* pAct = (MetaTextLineColorAction*) pAction; + + if( !pAct->IsSetting() ) + pAct->Duplicate(); + else + pAct = new MetaTextLineColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True ); + + aMtf.push_back( pAct ); + } + break; + + case( META_OVERLINECOLOR_ACTION ): + { + MetaOverlineColorAction* pAct = (MetaOverlineColorAction*) pAction; + + if( !pAct->IsSetting() ) + pAct->Duplicate(); + else + pAct = new MetaOverlineColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True ); + + aMtf.push_back( pAct ); + } + break; + + case( META_FONT_ACTION ): + { + MetaFontAction* pAct = (MetaFontAction*) pAction; + Font aFont( pAct->GetFont() ); + + aFont.SetColor( pFncCol( aFont.GetColor(), pColParam ) ); + aFont.SetFillColor( pFncCol( aFont.GetFillColor(), pColParam ) ); + aMtf.push_back( new MetaFontAction( aFont ) ); + } + break; + + case( META_WALLPAPER_ACTION ): + { + MetaWallpaperAction* pAct = (MetaWallpaperAction*) pAction; + Wallpaper aWall( pAct->GetWallpaper() ); + const Rectangle& rRect = pAct->GetRect(); + + aWall.SetColor( pFncCol( aWall.GetColor(), pColParam ) ); + + if( aWall.IsBitmap() ) + aWall.SetBitmap( pFncBmp( aWall.GetBitmap(), pBmpParam ) ); + + if( aWall.IsGradient() ) + { + Gradient aGradient( aWall.GetGradient() ); + + aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) ); + aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) ); + aWall.SetGradient( aGradient ); + } + + aMtf.push_back( new MetaWallpaperAction( rRect, aWall ) ); + } + break; + + case( META_BMP_ACTION ): + case( META_BMPEX_ACTION ): + case( META_MASK_ACTION ): + { + OSL_FAIL( "Don't use bitmap actions of this type in metafiles!" ); + } + break; + + case( META_BMPSCALE_ACTION ): + { + MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction; + aMtf.push_back( new MetaBmpScaleAction( pAct->GetPoint(), pAct->GetSize(), + pFncBmp( pAct->GetBitmap(), pBmpParam ).GetBitmap() ) ); + } + break; + + case( META_BMPSCALEPART_ACTION ): + { + MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction; + aMtf.push_back( new MetaBmpScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(), + pAct->GetSrcPoint(), pAct->GetSrcSize(), + pFncBmp( pAct->GetBitmap(), pBmpParam ).GetBitmap() ) + ); + } + break; + + case( META_BMPEXSCALE_ACTION ): + { + MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction; + aMtf.push_back( new MetaBmpExScaleAction( pAct->GetPoint(), pAct->GetSize(), + pFncBmp( pAct->GetBitmapEx(), pBmpParam ) ) + ); + } + break; + + case( META_BMPEXSCALEPART_ACTION ): + { + MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction; + aMtf.push_back( new MetaBmpExScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(), + pAct->GetSrcPoint(), pAct->GetSrcSize(), + pFncBmp( pAct->GetBitmapEx(), pBmpParam ) ) + ); + } + break; + + case( META_MASKSCALE_ACTION ): + { + MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction; + aMtf.push_back( new MetaMaskScaleAction( pAct->GetPoint(), pAct->GetSize(), + pAct->GetBitmap(), + pFncCol( pAct->GetColor(), pColParam ) ) + ); + } + break; + + case( META_MASKSCALEPART_ACTION ): + { + MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction; + aMtf.push_back( new MetaMaskScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(), + pAct->GetSrcPoint(), pAct->GetSrcSize(), + pAct->GetBitmap(), + pFncCol( pAct->GetColor(), pColParam ) ) + ); + } + break; + + case( META_GRADIENT_ACTION ): + { + MetaGradientAction* pAct = (MetaGradientAction*) pAction; + Gradient aGradient( pAct->GetGradient() ); + + aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) ); + aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) ); + aMtf.push_back( new MetaGradientAction( pAct->GetRect(), aGradient ) ); + } + break; + + case( META_GRADIENTEX_ACTION ): + { + MetaGradientExAction* pAct = (MetaGradientExAction*) pAction; + Gradient aGradient( pAct->GetGradient() ); + + aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) ); + aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) ); + aMtf.push_back( new MetaGradientExAction( pAct->GetPolyPolygon(), aGradient ) ); + } + break; + + case( META_HATCH_ACTION ): + { + MetaHatchAction* pAct = (MetaHatchAction*) pAction; + Hatch aHatch( pAct->GetHatch() ); + + aHatch.SetColor( pFncCol( aHatch.GetColor(), pColParam ) ); + aMtf.push_back( new MetaHatchAction( pAct->GetPolyPolygon(), aHatch ) ); + } + break; + + case( META_FLOATTRANSPARENT_ACTION ): + { + MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction; + GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() ); + + aTransMtf.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam ); + aMtf.push_back( new MetaFloatTransparentAction( aTransMtf, + pAct->GetPoint(), pAct->GetSize(), + pAct->GetGradient() ) + ); + } + break; + + case( META_EPS_ACTION ): + { + MetaEPSAction* pAct = (MetaEPSAction*) pAction; + GDIMetaFile aSubst( pAct->GetSubstitute() ); + + aSubst.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam ); + aMtf.push_back( new MetaEPSAction( pAct->GetPoint(), pAct->GetSize(), + pAct->GetLink(), aSubst ) + ); + } + break; + + default: + { + pAction->Duplicate(); + aMtf.push_back( pAction ); + } + break; + } + } + + *this = aMtf; +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Adjust( short nLuminancePercent, short nContrastPercent, + short nChannelRPercent, short nChannelGPercent, + short nChannelBPercent, double fGamma, sal_Bool bInvert ) +{ + // nothing to do? => return quickly + if( nLuminancePercent || nContrastPercent || + nChannelRPercent || nChannelGPercent || nChannelBPercent || + ( fGamma != 1.0 ) || bInvert ) + { + double fM, fROff, fGOff, fBOff, fOff; + ImplColAdjustParam aColParam; + ImplBmpAdjustParam aBmpParam; + + aColParam.pMapR = new sal_uInt8[ 256 ]; + aColParam.pMapG = new sal_uInt8[ 256 ]; + aColParam.pMapB = new sal_uInt8[ 256 ]; + + // calculate slope + if( nContrastPercent >= 0 ) + fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) ); + else + fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0; + + // total offset = luminance offset + contrast offset + fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0; + + // channel offset = channel offset + total offset + fROff = nChannelRPercent * 2.55 + fOff; + fGOff = nChannelGPercent * 2.55 + fOff; + fBOff = nChannelBPercent * 2.55 + fOff; + + // calculate gamma value + fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma ); + const sal_Bool bGamma = ( fGamma != 1.0 ); + + // create mapping table + for( long nX = 0L; nX < 256L; nX++ ) + { + aColParam.pMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L ); + aColParam.pMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L ); + aColParam.pMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L ); + + if( bGamma ) + { + aColParam.pMapR[ nX ] = GAMMA( aColParam.pMapR[ nX ], fGamma ); + aColParam.pMapG[ nX ] = GAMMA( aColParam.pMapG[ nX ], fGamma ); + aColParam.pMapB[ nX ] = GAMMA( aColParam.pMapB[ nX ], fGamma ); + } + + if( bInvert ) + { + aColParam.pMapR[ nX ] = ~aColParam.pMapR[ nX ]; + aColParam.pMapG[ nX ] = ~aColParam.pMapG[ nX ]; + aColParam.pMapB[ nX ] = ~aColParam.pMapB[ nX ]; + } + } + + aBmpParam.nLuminancePercent = nLuminancePercent; + aBmpParam.nContrastPercent = nContrastPercent; + aBmpParam.nChannelRPercent = nChannelRPercent; + aBmpParam.nChannelGPercent = nChannelGPercent; + aBmpParam.nChannelBPercent = nChannelBPercent; + aBmpParam.fGamma = fGamma; + aBmpParam.bInvert = bInvert; + + // do color adjustment + ImplExchangeColors( ImplColAdjustFnc, &aColParam, ImplBmpAdjustFnc, &aBmpParam ); + + delete[] aColParam.pMapR; + delete[] aColParam.pMapG; + delete[] aColParam.pMapB; + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::Convert( MtfConversion eConversion ) +{ + // nothing to do? => return quickly + if( eConversion != MTF_CONVERSION_NONE ) + { + ImplColConvertParam aColParam; + ImplBmpConvertParam aBmpParam; + + aColParam.eConversion = eConversion; + aBmpParam.eConversion = ( MTF_CONVERSION_1BIT_THRESHOLD == eConversion ) ? BMP_CONVERSION_1BIT_THRESHOLD : BMP_CONVERSION_8BIT_GREYS; + + ImplExchangeColors( ImplColConvertFnc, &aColParam, ImplBmpConvertFnc, &aBmpParam ); + } +} + +// ------------------------------------------------------------------------ + +void GDIMetaFile::ReplaceColors( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount, sal_uLong* pTols ) +{ + ImplColReplaceParam aColParam; + ImplBmpReplaceParam aBmpParam; + + aColParam.pMinR = new sal_uLong[ nColorCount ]; + aColParam.pMaxR = new sal_uLong[ nColorCount ]; + aColParam.pMinG = new sal_uLong[ nColorCount ]; + aColParam.pMaxG = new sal_uLong[ nColorCount ]; + aColParam.pMinB = new sal_uLong[ nColorCount ]; + aColParam.pMaxB = new sal_uLong[ nColorCount ]; + + for( sal_uLong i = 0; i < nColorCount; i++ ) + { + const long nTol = pTols ? ( pTols[ i ] * 255 ) / 100 : 0; + long nVal; + + nVal = pSearchColors[ i ].GetRed(); + aColParam.pMinR[ i ] = (sal_uLong) Max( nVal - nTol, 0L ); + aColParam.pMaxR[ i ] = (sal_uLong) Min( nVal + nTol, 255L ); + + nVal = pSearchColors[ i ].GetGreen(); + aColParam.pMinG[ i ] = (sal_uLong) Max( nVal - nTol, 0L ); + aColParam.pMaxG[ i ] = (sal_uLong) Min( nVal + nTol, 255L ); + + nVal = pSearchColors[ i ].GetBlue(); + aColParam.pMinB[ i ] = (sal_uLong) Max( nVal - nTol, 0L ); + aColParam.pMaxB[ i ] = (sal_uLong) Min( nVal + nTol, 255L ); + } + + aColParam.pDstCols = pReplaceColors; + aColParam.nCount = nColorCount; + + aBmpParam.pSrcCols = pSearchColors; + aBmpParam.pDstCols = pReplaceColors; + aBmpParam.nCount = nColorCount; + aBmpParam.pTols = pTols; + + ImplExchangeColors( ImplColReplaceFnc, &aColParam, ImplBmpReplaceFnc, &aBmpParam ); + + delete[] aColParam.pMinR; + delete[] aColParam.pMaxR; + delete[] aColParam.pMinG; + delete[] aColParam.pMaxG; + delete[] aColParam.pMinB; + delete[] aColParam.pMaxB; +}; + +// ------------------------------------------------------------------------ + +GDIMetaFile GDIMetaFile::GetMonochromeMtf( const Color& rColor ) const +{ + GDIMetaFile aRet( *this ); + + ImplColMonoParam aColParam; + ImplBmpMonoParam aBmpParam; + + aColParam.aColor = rColor; + aBmpParam.aColor = rColor; + + aRet.ImplExchangeColors( ImplColMonoFnc, &aColParam, ImplBmpMonoFnc, &aBmpParam ); + + return aRet; +} + +// ------------------------------------------------------------------------ + +sal_uLong GDIMetaFile::GetChecksum() const +{ + GDIMetaFile aMtf; + SvMemoryStream aMemStm( 65535, 65535 ); + ImplMetaWriteData aWriteData; + SVBT16 aBT16; + SVBT32 aBT32; + sal_uLong nCrc = 0; + + aWriteData.meActualCharSet = aMemStm.GetStreamCharSet(); + for( size_t i = 0, nObjCount = GetActionSize(); i < nObjCount; i++ ) + { + MetaAction* pAction = GetAction( i ); + + switch( pAction->GetType() ) + { + case( META_BMP_ACTION ): + { + MetaBmpAction* pAct = (MetaBmpAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_BMPSCALE_ACTION ): + { + MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_BMPSCALEPART_ACTION ): + { + MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_BMPEX_ACTION ): + { + MetaBmpExAction* pAct = (MetaBmpExAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_BMPEXSCALE_ACTION ): + { + MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_BMPEXSCALEPART_ACTION ): + { + MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_MASK_ACTION ): + { + MetaMaskAction* pAct = (MetaMaskAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_MASKSCALE_ACTION ): + { + MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case( META_MASKSCALEPART_ACTION ): + { + MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction; + + ShortToSVBT16( pAct->GetType(), aBT16 ); + nCrc = rtl_crc32( nCrc, aBT16, 2 ); + + UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + + UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 ); + nCrc = rtl_crc32( nCrc, aBT32, 4 ); + } + break; + + case META_EPS_ACTION : + { + MetaEPSAction* pAct = (MetaEPSAction*) pAction; + nCrc = rtl_crc32( nCrc, pAct->GetLink().GetData(), pAct->GetLink().GetDataSize() ); + } + break; + + case META_CLIPREGION_ACTION : + { + MetaClipRegionAction* pAct = dynamic_cast< MetaClipRegionAction* >(pAction); + const Region& rRegion = pAct->GetRegion(); + + if(rRegion.HasPolyPolygon()) + { + // It has shown that this is a possible bottleneck for checksum calculation. + // In worst case a very expensive RegionHandle representation gets created. + // In this case it's cheaper to use the PolyPolygon + const basegfx::B2DPolyPolygon aPolyPolygon(rRegion.GetB2DPolyPolygon()); + const sal_uInt32 nPolyCount(aPolyPolygon.count()); + SVBT64 aSVBT64; + + for(sal_uInt32 a(0); a < nPolyCount; a++) + { + const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(a)); + const sal_uInt32 nPointCount(aPolygon.count()); + const bool bControl(aPolygon.areControlPointsUsed()); + + for(sal_uInt32 b(0); b < nPointCount; b++) + { + const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(b)); + + DoubleToSVBT64(aPoint.getX(), aSVBT64); + nCrc = rtl_crc32(nCrc, aSVBT64, 8); + DoubleToSVBT64(aPoint.getY(), aSVBT64); + nCrc = rtl_crc32(nCrc, aSVBT64, 8); + + if(bControl) + { + if(aPolygon.isPrevControlPointUsed(b)) + { + const basegfx::B2DPoint aCtrl(aPolygon.getPrevControlPoint(b)); + + DoubleToSVBT64(aCtrl.getX(), aSVBT64); + nCrc = rtl_crc32(nCrc, aSVBT64, 8); + DoubleToSVBT64(aCtrl.getY(), aSVBT64); + nCrc = rtl_crc32(nCrc, aSVBT64, 8); + } + + if(aPolygon.isNextControlPointUsed(b)) + { + const basegfx::B2DPoint aCtrl(aPolygon.getNextControlPoint(b)); + + DoubleToSVBT64(aCtrl.getX(), aSVBT64); + nCrc = rtl_crc32(nCrc, aSVBT64, 8); + DoubleToSVBT64(aCtrl.getY(), aSVBT64); + nCrc = rtl_crc32(nCrc, aSVBT64, 8); + } + } + } + } + + SVBT8 aSVBT8; + ByteToSVBT8((sal_uInt8)pAct->IsClipping(), aSVBT8); + nCrc = rtl_crc32(nCrc, aSVBT8, 1); + } + else + { + pAction->Write( aMemStm, &aWriteData ); + nCrc = rtl_crc32( nCrc, aMemStm.GetData(), aMemStm.Tell() ); + aMemStm.Seek( 0 ); + } + } + break; + + default: + { + pAction->Write( aMemStm, &aWriteData ); + nCrc = rtl_crc32( nCrc, aMemStm.GetData(), aMemStm.Tell() ); + aMemStm.Seek( 0 ); + } + break; + } + } + + return nCrc; +} + +// ------------------------------------------------------------------------ + +sal_uLong GDIMetaFile::GetSizeBytes() const +{ + sal_uLong nSizeBytes = 0; + + for( size_t i = 0, nObjCount = GetActionSize(); i < nObjCount; ++i ) + { + MetaAction* pAction = GetAction( i ); + + // default action size is set to 32 (=> not the exact value) + nSizeBytes += 32; + + // add sizes for large action content + switch( pAction->GetType() ) + { + case( META_BMP_ACTION ): nSizeBytes += ( (MetaBmpAction*) pAction )->GetBitmap().GetSizeBytes(); break; + case( META_BMPSCALE_ACTION ): nSizeBytes += ( (MetaBmpScaleAction*) pAction )->GetBitmap().GetSizeBytes(); break; + case( META_BMPSCALEPART_ACTION ): nSizeBytes += ( (MetaBmpScalePartAction*) pAction )->GetBitmap().GetSizeBytes(); break; + + case( META_BMPEX_ACTION ): nSizeBytes += ( (MetaBmpExAction*) pAction )->GetBitmapEx().GetSizeBytes(); break; + case( META_BMPEXSCALE_ACTION ): nSizeBytes += ( (MetaBmpExScaleAction*) pAction )->GetBitmapEx().GetSizeBytes(); break; + case( META_BMPEXSCALEPART_ACTION ): nSizeBytes += ( (MetaBmpExScalePartAction*) pAction )->GetBitmapEx().GetSizeBytes(); break; + + case( META_MASK_ACTION ): nSizeBytes += ( (MetaMaskAction*) pAction )->GetBitmap().GetSizeBytes(); break; + case( META_MASKSCALE_ACTION ): nSizeBytes += ( (MetaMaskScaleAction*) pAction )->GetBitmap().GetSizeBytes(); break; + case( META_MASKSCALEPART_ACTION ): nSizeBytes += ( (MetaMaskScalePartAction*) pAction )->GetBitmap().GetSizeBytes(); break; + + case( META_POLYLINE_ACTION ): nSizeBytes += ( ( (MetaPolyLineAction*) pAction )->GetPolygon().GetSize() * sizeof( Point ) ); break; + case( META_POLYGON_ACTION ): nSizeBytes += ( ( (MetaPolygonAction*) pAction )->GetPolygon().GetSize() * sizeof( Point ) ); break; + case( META_POLYPOLYGON_ACTION ): + { + const PolyPolygon& rPolyPoly = ( (MetaPolyPolygonAction*) pAction )->GetPolyPolygon(); + + for( sal_uInt16 n = 0; n < rPolyPoly.Count(); ++n ) + nSizeBytes += ( rPolyPoly[ n ].GetSize() * sizeof( Point ) ); + } + break; + + case( META_TEXT_ACTION ): nSizeBytes += ( ( (MetaTextAction*) pAction )->GetText().getLength() * sizeof( sal_Unicode ) ); break; + case( META_STRETCHTEXT_ACTION ): nSizeBytes += ( ( (MetaStretchTextAction*) pAction )->GetText().getLength() * sizeof( sal_Unicode ) ); break; + case( META_TEXTRECT_ACTION ): nSizeBytes += ( ( (MetaTextRectAction*) pAction )->GetText().getLength() * sizeof( sal_Unicode ) ); break; + case( META_TEXTARRAY_ACTION ): + { + MetaTextArrayAction* pTextArrayAction = (MetaTextArrayAction*) pAction; + + nSizeBytes += ( pTextArrayAction->GetText().getLength() * sizeof( sal_Unicode ) ); + + if( pTextArrayAction->GetDXArray() ) + nSizeBytes += ( pTextArrayAction->GetLen() << 2 ); + } + break; + } + } + + return( nSizeBytes ); +} + +// ------------------------------------------------------------------------ + +SvStream& operator>>( SvStream& rIStm, GDIMetaFile& rGDIMetaFile ) +{ + if( !rIStm.GetError() ) + { + char aId[ 7 ]; + sal_uLong nStmPos = rIStm.Tell(); + sal_uInt16 nOldFormat = rIStm.GetNumberFormatInt(); + + rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + aId[ 0 ] = 0; + aId[ 6 ] = 0; + rIStm.Read( aId, 6 ); + + if ( !strcmp( aId, "VCLMTF" ) ) + { + // new format + VersionCompat* pCompat; + MetaAction* pAction; + sal_uInt32 nStmCompressMode = 0; + sal_uInt32 nCount = 0; + + pCompat = new VersionCompat( rIStm, STREAM_READ ); + + rIStm >> nStmCompressMode; + rIStm >> rGDIMetaFile.aPrefMapMode; + rIStm >> rGDIMetaFile.aPrefSize; + rIStm >> nCount; + + delete pCompat; + + ImplMetaReadData aReadData; + aReadData.meActualCharSet = rIStm.GetStreamCharSet(); + + for( sal_uInt32 nAction = 0UL; ( nAction < nCount ) && !rIStm.IsEof(); nAction++ ) + { + pAction = MetaAction::ReadMetaAction( rIStm, &aReadData ); + + if( pAction ) + rGDIMetaFile.AddAction( pAction ); + } + } + else + { + // to avoid possible compiler optimizations => new/delete + rIStm.Seek( nStmPos ); + delete( new SVMConverter( rIStm, rGDIMetaFile, CONVERT_FROM_SVM1 ) ); + } + + // check for errors + if( rIStm.GetError() ) + { + rGDIMetaFile.Clear(); + rIStm.Seek( nStmPos ); + } + + rIStm.SetNumberFormatInt( nOldFormat ); + } + + return rIStm; +} + +// ------------------------------------------------------------------------ + +SvStream& operator<<( SvStream& rOStm, const GDIMetaFile& rGDIMetaFile ) +{ + if( !rOStm.GetError() ) + { + static const char* pEnableSVM1 = getenv( "SAL_ENABLE_SVM1" ); + static const bool bNoSVM1 = (NULL == pEnableSVM1 ) || ( '0' == *pEnableSVM1 ); + + if( bNoSVM1 || rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 ) + { + const_cast< GDIMetaFile& >( rGDIMetaFile ).Write( rOStm ); + } + else + { + delete( new SVMConverter( rOStm, const_cast< GDIMetaFile& >( rGDIMetaFile ), CONVERT_TO_SVM1 ) ); + } + +#ifdef DEBUG + if( !bNoSVM1 && rOStm.GetVersion() < SOFFICE_FILEFORMAT_50 ) + { +OSL_TRACE( \ +"GDIMetaFile would normally be written in old SVM1 format by this call. \ +The current implementation always writes in VCLMTF format. \ +Please set environment variable SAL_ENABLE_SVM1 to '1' to reenable old behavior" ); + } +#endif // DEBUG + } + + return rOStm; +} + +// ------------------------------------------------------------------------ + +SvStream& GDIMetaFile::Read( SvStream& rIStm ) +{ + Clear(); + rIStm >> *this; + + return rIStm; +} + +// ------------------------------------------------------------------------ + +SvStream& GDIMetaFile::Write( SvStream& rOStm ) +{ + VersionCompat* pCompat; + const sal_uInt32 nStmCompressMode = rOStm.GetCompressMode(); + sal_uInt16 nOldFormat = rOStm.GetNumberFormatInt(); + + rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + rOStm.Write( "VCLMTF", 6 ); + + pCompat = new VersionCompat( rOStm, STREAM_WRITE, 1 ); + + rOStm << nStmCompressMode; + rOStm << aPrefMapMode; + rOStm << aPrefSize; + rOStm << (sal_uInt32) GetActionSize(); + + delete pCompat; + + ImplMetaWriteData aWriteData; + + aWriteData.meActualCharSet = rOStm.GetStreamCharSet(); + + MetaAction* pAct = (MetaAction*)FirstAction(); + while ( pAct ) + { + pAct->Write( rOStm, &aWriteData ); + pAct = (MetaAction*)NextAction(); + } + + rOStm.SetNumberFormatInt( nOldFormat ); + + return rOStm; +} + +// ------------------------------------------------------------------------ + +sal_Bool GDIMetaFile::CreateThumbnail( sal_uInt32 nMaximumExtent, + BitmapEx& rBmpEx, + const BitmapEx* pOverlay, + const Rectangle* pOverlayRect ) const +{ + // the implementation is provided by KA + + // initialization seems to be complicated but is used to avoid rounding errors + VirtualDevice aVDev; + const Point aNullPt; + const Point aTLPix( aVDev.LogicToPixel( aNullPt, GetPrefMapMode() ) ); + const Point aBRPix( aVDev.LogicToPixel( Point( GetPrefSize().Width() - 1, GetPrefSize().Height() - 1 ), GetPrefMapMode() ) ); + Size aDrawSize( aVDev.LogicToPixel( GetPrefSize(), GetPrefMapMode() ) ); + Size aSizePix( labs( aBRPix.X() - aTLPix.X() ) + 1, labs( aBRPix.Y() - aTLPix.Y() ) + 1 ); + + if ( !rBmpEx.IsEmpty() ) + rBmpEx.SetEmpty(); + + // determine size that has the same aspect ratio as image size and + // fits into the rectangle determined by nMaximumExtent + if ( aSizePix.Width() && aSizePix.Height() + && ( sal::static_int_cast< unsigned long >(aSizePix.Width()) > + nMaximumExtent || + sal::static_int_cast< unsigned long >(aSizePix.Height()) > + nMaximumExtent ) ) + { + const Size aOldSizePix( aSizePix ); + double fWH = static_cast< double >( aSizePix.Width() ) / aSizePix.Height(); + + if ( fWH <= 1.0 ) + { + aSizePix.Width() = FRound( nMaximumExtent * fWH ); + aSizePix.Height() = nMaximumExtent; + } + else + { + aSizePix.Width() = nMaximumExtent; + aSizePix.Height() = FRound( nMaximumExtent / fWH ); + } + + aDrawSize.Width() = FRound( ( static_cast< double >( aDrawSize.Width() ) * aSizePix.Width() ) / aOldSizePix.Width() ); + aDrawSize.Height() = FRound( ( static_cast< double >( aDrawSize.Height() ) * aSizePix.Height() ) / aOldSizePix.Height() ); + } + + Size aFullSize; + Point aBackPosPix; + Rectangle aOverlayRect; + + // calculate addigtional positions and sizes if an overlay image is used + if ( pOverlay ) + { + aFullSize = Size( nMaximumExtent, nMaximumExtent ); + aOverlayRect = Rectangle( aNullPt, aFullSize ); + + aOverlayRect.Intersection( pOverlayRect ? *pOverlayRect : Rectangle( aNullPt, pOverlay->GetSizePixel() ) ); + + if ( !aOverlayRect.IsEmpty() ) + aBackPosPix = Point( ( nMaximumExtent - aSizePix.Width() ) >> 1, ( nMaximumExtent - aSizePix.Height() ) >> 1 ); + else + pOverlay = NULL; + } + else + { + aFullSize = aSizePix; + pOverlay = NULL; + } + + // draw image(s) into VDev and get resulting image + if ( aVDev.SetOutputSizePixel( aFullSize ) ) + { + // draw metafile into VDev + const_cast<GDIMetaFile *>(this)->WindStart(); + const_cast<GDIMetaFile *>(this)->Play( &aVDev, aBackPosPix, aDrawSize ); + + // draw overlay if necessary + if ( pOverlay ) + aVDev.DrawBitmapEx( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), *pOverlay ); + + // get paint bitmap + Bitmap aBmp( aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) ); + + // assure that we have a true color image + if ( aBmp.GetBitCount() != 24 ) + aBmp.Convert( BMP_CONVERSION_24BIT ); + + // create resulting mask bitmap with metafile output set to black + GDIMetaFile aMonchromeMtf( GetMonochromeMtf( COL_BLACK ) ); + aVDev.DrawWallpaper( Rectangle( aNullPt, aSizePix ), Wallpaper( Color( COL_WHITE ) ) ); + aMonchromeMtf.WindStart(); + aMonchromeMtf.Play( &aVDev, aBackPosPix, aDrawSize ); + + // watch for overlay mask + if ( pOverlay ) + { + Bitmap aOverlayMergeBmp( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ) ); + + // create ANDed resulting mask at overlay area + if ( pOverlay->IsTransparent() ) + aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), pOverlay->GetMask() ); + else + { + aVDev.SetLineColor( COL_BLACK ); + aVDev.SetFillColor( COL_BLACK ); + aVDev.DrawRect( aOverlayRect); + } + + aOverlayMergeBmp.CombineSimple( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ), BMP_COMBINE_AND ); + aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), aOverlayMergeBmp ); + } + + rBmpEx = BitmapEx( aBmp, aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) ); + } + + return !rBmpEx.IsEmpty(); +} + +void GDIMetaFile::UseCanvas( sal_Bool _bUseCanvas ) +{ + bUseCanvas = _bUseCanvas; +} + +// ------------------------------------------------------------------------ + +MetaCommentAction* makePluggableRendererAction( const rtl::OUString& rRendererServiceName, + const rtl::OUString& rGraphicServiceName, + const void* _pData, + sal_uInt32 nDataSize ) +{ + const sal_uInt8* pData=(sal_uInt8*)_pData; + + // data gets copied twice, unfortunately + rtl::OString aRendererServiceName( + rRendererServiceName.getStr(), + rRendererServiceName.getLength(), + RTL_TEXTENCODING_ASCII_US); + rtl::OString aGraphicServiceName( + rGraphicServiceName.getStr(), + rGraphicServiceName.getLength(), + RTL_TEXTENCODING_ASCII_US); + + std::vector<sal_uInt8> aMem( + aRendererServiceName.getLength()+ + aGraphicServiceName.getLength()+2+nDataSize); + sal_uInt8* pMem=&aMem[0]; + + std::copy(aRendererServiceName.getStr(), + aRendererServiceName.getStr()+aRendererServiceName.getLength()+1, + pMem); + pMem+=aRendererServiceName.getLength()+1; + std::copy(aGraphicServiceName.getStr(), + aGraphicServiceName.getStr()+aGraphicServiceName.getLength()+1, + pMem); + pMem+=aGraphicServiceName.getLength()+1; + + std::copy(pData,pData+nDataSize, + pMem); + + return new MetaCommentAction( + "DELEGATE_PLUGGABLE_RENDERER", + 0, + &aMem[0], + aMem.size()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/helper/canvastools.cxx b/vcl/source/helper/canvastools.cxx index 75ad8721e3a9..d05f7e78bfb3 100644 --- a/vcl/source/helper/canvastools.cxx +++ b/vcl/source/helper/canvastools.cxx @@ -21,6 +21,8 @@ #include <rtl/logfile.hxx> #include <cppuhelper/compbase1.hxx> +#include <com/sun/star/beans/XFastPropertySet.hpp> + #include <com/sun/star/geometry/RealSize2D.hpp> #include <com/sun/star/geometry/RealPoint2D.hpp> #include <com/sun/star/geometry/RealRectangle2D.hpp> @@ -70,11 +72,32 @@ namespace vcl { namespace unotools { - uno::Reference< rendering::XBitmap > xBitmapFromBitmapEx( const uno::Reference< rendering::XGraphicDevice >& /*xGraphicDevice*/, + uno::Reference< rendering::XBitmap > xBitmapFromBitmapEx( const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice, const ::BitmapEx& inputBitmap ) { RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::xBitmapFromBitmapEx()" ); + if ( inputBitmap.GetBitmap().HasAlpha() ) + { + geometry::IntegerSize2D aSize; + + aSize.Width = aSize.Height = 1; + + uno::Reference< rendering::XBitmap > xBitmap = xGraphicDevice->createCompatibleAlphaBitmap( aSize ); + + uno::Reference< beans::XFastPropertySet > rPropSet( xBitmap, uno::UNO_QUERY ); + if ( rPropSet.is() ) + { + Bitmap aBitmap = inputBitmap.GetBitmap(); + rPropSet->setFastPropertyValue( 0, uno::Any( sal_Int64( &aBitmap ))); + + aSize = xBitmap->getSize(); + + if ( aSize.Width != 1 || aSize.Height != 1 ) + return xBitmap; + } + } + return new vcl::unotools::VclCanvasBitmap( inputBitmap ); } diff --git a/vcl/unx/generic/gdi/salbmp.cxx b/vcl/unx/generic/gdi/salbmp.cxx index faa04c7c7dba..bf9a703d1beb 100644 --- a/vcl/unx/generic/gdi/salbmp.cxx +++ b/vcl/unx/generic/gdi/salbmp.cxx @@ -566,6 +566,7 @@ XImage* X11SalBitmap::ImplCreateXImage( // ----------------------------------------------------------------------------- bool X11SalBitmap::ImplCreateFromDrawable( Drawable aDrawable, + void *pVisual, SalX11Screen nScreen, long nDrawableDepth, long nX, @@ -576,7 +577,7 @@ bool X11SalBitmap::ImplCreateFromDrawable( Destroy(); if( aDrawable && nWidth && nHeight && nDrawableDepth ) - mpDDB = new ImplSalDDB( aDrawable, nScreen, nDrawableDepth, nX, nY, nWidth, nHeight ); + mpDDB = new ImplSalDDB( aDrawable, pVisual, nScreen, nDrawableDepth, nX, nY, nWidth, nHeight ); return( mpDDB != NULL ); } @@ -736,7 +737,8 @@ bool X11SalBitmap::Create( const SalBitmap& rSSalBmp ) } else if( rSalBmp.mpDDB ) ImplCreateFromDrawable( rSalBmp.mpDDB->ImplGetPixmap(), - rSalBmp.mpDDB->ImplGetScreen(), + rSalBmp.mpDDB->ImplGetVisual(), + rSalBmp.mpDDB->ImplGetScreen(), rSalBmp.mpDDB->ImplGetDepth(), 0, 0, rSalBmp.mpDDB->ImplGetWidth(), rSalBmp.mpDDB->ImplGetHeight() ); @@ -775,11 +777,13 @@ bool X11SalBitmap::Create( if( xFastPropertySet->getFastPropertyValue(bMask ? 2 : 1) >>= args ) { long pixmapHandle; - if( ( args[1] >>= pixmapHandle ) && ( args[2] >>= depth ) ) { + sal_Int64 nVisualPtr; + if( args.getLength() >= 4 && ( args[1] >>= pixmapHandle ) && ( args[2] >>= depth ) && ( args[3] >>= nVisualPtr ) ) { mbGrey = bMask; bool bSuccess = ImplCreateFromDrawable( pixmapHandle, + reinterpret_cast<void*>(nVisualPtr), // FIXME: this seems multi-screen broken to me SalX11Screen( 0 ), depth, @@ -891,6 +895,7 @@ bool X11SalBitmap::GetSystemData( BitmapSystemData& rData ) // prolly not a good idea, since it's accessed from // non-platform aware code in vcl/bitmap.hxx) rData.aPixmap = (void*)mpDDB->ImplGetPixmap(); + rData.aVisual = mpDDB->ImplGetVisual (); rData.mnWidth = mpDDB->ImplGetWidth (); rData.mnHeight = mpDDB->ImplGetHeight (); return true; @@ -906,6 +911,7 @@ bool X11SalBitmap::GetSystemData( BitmapSystemData& rData ) ImplSalDDB::ImplSalDDB( XImage* pImage, Drawable aDrawable, SalX11Screen nXScreen, const SalTwoRect& rTwoRect ) : maPixmap ( 0 ) + , mpVisual ( NULL ) , maTwoRect ( rTwoRect ) , mnDepth ( pImage->depth ) , mnXScreen ( nXScreen ) @@ -937,13 +943,15 @@ ImplSalDDB::ImplSalDDB( XImage* pImage, Drawable aDrawable, ImplSalDDB::ImplSalDDB( Drawable aDrawable, + void *pVisual, SalX11Screen nXScreen, long nDrawableDepth, long nX, long nY, long nWidth, long nHeight -) : mnDepth( nDrawableDepth ) +) : mpVisual ( pVisual ) + , mnDepth( nDrawableDepth ) , mnXScreen( nXScreen ) { SalDisplay* pSalDisp = GetGenericData()->GetSalDisplay(); diff --git a/vcl/unx/generic/gdi/salgdi2.cxx b/vcl/unx/generic/gdi/salgdi2.cxx index 82c1e3b68035..67eee82eedec 100644 --- a/vcl/unx/generic/gdi/salgdi2.cxx +++ b/vcl/unx/generic/gdi/salgdi2.cxx @@ -90,7 +90,7 @@ void X11SalGraphics::CopyScreenArea( Display* pDisplay, else { X11SalBitmap aBM; - aBM.ImplCreateFromDrawable( aSrc, nXScreenSrc, nSrcDepth, src_x, src_y, w, h ); + aBM.ImplCreateFromDrawable( aSrc, NULL, nXScreenSrc, nSrcDepth, src_x, src_y, w, h ); SalTwoRect aTwoRect; aTwoRect.mnSrcX = aTwoRect.mnSrcY = 0; aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = w; @@ -913,7 +913,7 @@ SalBitmap *X11SalGraphics::getBitmap( long nX, long nY, long nDX, long nDY ) nBitCount = 1; if( ! bFakeWindowBG ) - pSalBitmap->ImplCreateFromDrawable( GetDrawable(), m_nXScreen, nBitCount, nX, nY, nDX, nDY ); + pSalBitmap->ImplCreateFromDrawable( GetDrawable(), NULL, m_nXScreen, nBitCount, nX, nY, nDX, nDY ); else pSalBitmap->Create( Size( nDX, nDY ), (nBitCount > 8) ? 24 : nBitCount, BitmapPalette( nBitCount > 8 ? nBitCount : 0 ) ); diff --git a/vcl/unx/generic/gdi/salgdi2.cxx.orig b/vcl/unx/generic/gdi/salgdi2.cxx.orig new file mode 100644 index 000000000000..82c1e3b68035 --- /dev/null +++ b/vcl/unx/generic/gdi/salgdi2.cxx.orig @@ -0,0 +1,1009 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <stdio.h> +#include <poll.h> + +#include "vcl/salbtype.hxx" + +#include "unx/salunx.h" +#include "unx/saldata.hxx" +#include "unx/saldisp.hxx" +#include "unx/salbmp.h" +#include "unx/salgdi.h" +#include "unx/salframe.h" +#include "unx/salvd.h" +#include <unx/x11/xlimits.hxx> +#include "xrender_peer.hxx" + +#include "generic/printergfx.hxx" + +#include "vcl/bmpacc.hxx" +#include <outdata.hxx> + +#undef SALGDI2_TESTTRANS + +// -=-= debugging =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +// ----------------------------------------------------------------------------- + +#if (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS +#define DBG_TESTTRANS( _def_drawable ) \ +{ \ + XCopyArea( pXDisp, _def_drawable, aDrawable, GetCopyGC(), \ + 0, 0, \ + pPosAry->mnDestWidth, pPosAry->mnDestHeight, \ + 0, 0 ); \ +} +#else // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS +#define DBG_TESTTRANS( _def_drawable ) +#endif // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS + +// -=-= X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +void X11SalGraphics::CopyScreenArea( Display* pDisplay, + Drawable aSrc, SalX11Screen nXScreenSrc, int nSrcDepth, + Drawable aDest, SalX11Screen nXScreenDest, int nDestDepth, + GC aDestGC, + int src_x, int src_y, + unsigned int w, unsigned int h, + int dest_x, int dest_y ) +{ + if( nSrcDepth == nDestDepth ) + { + if( nXScreenSrc == nXScreenDest ) + XCopyArea( pDisplay, aSrc, aDest, aDestGC, + src_x, src_y, w, h, dest_x, dest_y ); + else + { + GetGenericData()->ErrorTrapPush(); + XImage* pImage = XGetImage( pDisplay, aSrc, src_x, src_y, w, h, + AllPlanes, ZPixmap ); + if( pImage ) + { + if( pImage->data ) + XPutImage( pDisplay, aDest, aDestGC, pImage, + 0, 0, dest_x, dest_y, w, h ); + XDestroyImage( pImage ); + } + GetGenericData()->ErrorTrapPop(); + } + } + else + { + X11SalBitmap aBM; + aBM.ImplCreateFromDrawable( aSrc, nXScreenSrc, nSrcDepth, src_x, src_y, w, h ); + SalTwoRect aTwoRect; + aTwoRect.mnSrcX = aTwoRect.mnSrcY = 0; + aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = w; + aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = h; + aTwoRect.mnDestX = dest_x; + aTwoRect.mnDestY = dest_y; + aBM.ImplDraw( aDest, nXScreenDest, nDestDepth, aTwoRect,aDestGC ); + } +} + +GC X11SalGraphics::CreateGC( Drawable hDrawable, unsigned long nMask ) +{ + XGCValues values; + + values.graphics_exposures = False; + values.foreground = m_pColormap->GetBlackPixel() + ^ m_pColormap->GetWhitePixel(); + values.function = GXxor; + values.line_width = 1; + values.fill_style = FillStippled; + values.stipple = GetDisplay()->GetInvert50( m_nXScreen ); + values.subwindow_mode = ClipByChildren; + + return XCreateGC( GetXDisplay(), hDrawable, nMask | GCSubwindowMode, &values ); +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +inline GC X11SalGraphics::GetMonoGC( Pixmap hPixmap ) +{ + if( !pMonoGC_ ) + pMonoGC_ = CreateGC( hPixmap ); + + if( !bMonoGC_ ) + { + SetClipRegion( pMonoGC_ ); + bMonoGC_ = sal_True; + } + + return pMonoGC_; +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +inline GC X11SalGraphics::GetCopyGC() +{ + if( bXORMode_ ) return GetInvertGC(); + + if( !pCopyGC_ ) + pCopyGC_ = CreateGC( GetDrawable() ); + + if( !bCopyGC_ ) + { + SetClipRegion( pCopyGC_ ); + bCopyGC_ = sal_True; + } + return pCopyGC_; +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +GC X11SalGraphics::GetInvertGC() +{ + if( !pInvertGC_ ) + pInvertGC_ = CreateGC( GetDrawable(), + GCGraphicsExposures + | GCForeground + | GCFunction + | GCLineWidth ); + + if( !bInvertGC_ ) + { + SetClipRegion( pInvertGC_ ); + bInvertGC_ = sal_True; + } + return pInvertGC_; +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +GC X11SalGraphics::GetInvert50GC() +{ + if( !pInvert50GC_ ) + { + XGCValues values; + + values.graphics_exposures = False; + values.foreground = m_pColormap->GetWhitePixel(); + values.background = m_pColormap->GetBlackPixel(); + values.function = GXinvert; + values.line_width = 1; + values.line_style = LineSolid; + unsigned long nValueMask = + GCGraphicsExposures + | GCForeground + | GCBackground + | GCFunction + | GCLineWidth + | GCLineStyle + | GCFillStyle + | GCStipple; + + char* pEnv = getenv( "SAL_DO_NOT_USE_INVERT50" ); + if( pEnv && ! strcasecmp( pEnv, "true" ) ) + { + values.fill_style = FillSolid; + nValueMask &= ~ GCStipple; + } + else + { + values.fill_style = FillStippled; + values.stipple = GetDisplay()->GetInvert50( m_nXScreen ); + } + + pInvert50GC_ = XCreateGC( GetXDisplay(), GetDrawable(), + nValueMask, + &values ); + } + + if( !bInvert50GC_ ) + { + SetClipRegion( pInvert50GC_ ); + bInvert50GC_ = sal_True; + } + return pInvert50GC_; +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +inline GC X11SalGraphics::GetStippleGC() +{ + if( !pStippleGC_ ) + pStippleGC_ = CreateGC( GetDrawable(), + GCGraphicsExposures + | GCFillStyle + | GCLineWidth ); + + if( !bStippleGC_ ) + { + XSetFunction( GetXDisplay(), pStippleGC_, bXORMode_ ? GXxor : GXcopy ); + SetClipRegion( pStippleGC_ ); + bStippleGC_ = sal_True; + } + + return pStippleGC_; +} + +// -=-= SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +extern "C" +{ + static Bool GraphicsExposePredicate( Display*, XEvent* pEvent, XPointer pFrameWindow ) + { + Bool bRet = False; + if( (pEvent->type == GraphicsExpose || pEvent->type == NoExpose) && + pEvent->xnoexpose.drawable == (Drawable)pFrameWindow ) + { + bRet = True; + } + return bRet; + } +} + + +void X11SalGraphics::YieldGraphicsExpose() +{ + // get frame if necessary + SalFrame* pFrame = m_pFrame; + Display* pDisplay = GetXDisplay(); + XLIB_Window aWindow = GetDrawable(); + if( ! pFrame ) + { + const std::list< SalFrame* >& rFrames = GetGenericData()->GetSalDisplay()->getFrames(); + for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end() && ! pFrame; ++it ) + { + const SystemEnvData* pEnvData = (*it)->GetSystemData(); + if( Drawable(pEnvData->aWindow) == aWindow ) + pFrame = *it; + } + if( ! pFrame ) + return; + } + + XEvent aEvent; + while( XCheckTypedWindowEvent( pDisplay, aWindow, Expose, &aEvent ) ) + { + SalPaintEvent aPEvt( aEvent.xexpose.x, aEvent.xexpose.y, aEvent.xexpose.width+1, aEvent.xexpose.height+1 ); + pFrame->CallCallback( SALEVENT_PAINT, &aPEvt ); + } + + do + { + if( ! GetDisplay()->XIfEventWithTimeout( &aEvent, (XPointer)aWindow, GraphicsExposePredicate ) ) + // this should not happen at all; still sometimes it happens + break; + + if( aEvent.type == NoExpose ) + break; + + if( pFrame ) + { + SalPaintEvent aPEvt( aEvent.xgraphicsexpose.x, aEvent.xgraphicsexpose.y, aEvent.xgraphicsexpose.width+1, aEvent.xgraphicsexpose.height+1 ); + pFrame->CallCallback( SALEVENT_PAINT, &aPEvt ); + } + } while( aEvent.xgraphicsexpose.count != 0 ); +} + +void X11SalGraphics::copyBits( const SalTwoRect *pPosAry, + SalGraphics *pSSrcGraphics ) +{ + X11SalGraphics* pSrcGraphics = pSSrcGraphics + ? static_cast<X11SalGraphics*>(pSSrcGraphics) + : this; + + if( pPosAry->mnSrcWidth <= 0 + || pPosAry->mnSrcHeight <= 0 + || pPosAry->mnDestWidth <= 0 + || pPosAry->mnDestHeight <= 0 ) + { + return; + } + + int n; + if( pSrcGraphics == this ) + { + n = 2; + } + else if( pSrcGraphics->bWindow_ ) + { + // window or compatible virtual device + if( pSrcGraphics->GetDisplay() == GetDisplay() && + pSrcGraphics->m_nXScreen == m_nXScreen && + pSrcGraphics->GetVisual().GetDepth() == GetVisual().GetDepth() + ) + n = 2; // same Display + else + n = 1; // printer or other display + } + else if( pSrcGraphics->bVirDev_ ) + { + // printer compatible virtual device + if( bPrinter_ ) + n = 2; // printer or compatible virtual device == same display + else + n = 1; // window or compatible virtual device + } + else + n = 0; + + if( n == 2 + && pPosAry->mnSrcWidth == pPosAry->mnDestWidth + && pPosAry->mnSrcHeight == pPosAry->mnDestHeight + ) + { + // #i60699# Need to generate graphics exposures (to repaint + // obscured areas beneath overlapping windows), src and dest + // are the same window. + const bool bNeedGraphicsExposures( pSrcGraphics == this && + !bVirDev_ && + pSrcGraphics->bWindow_ ); + + GC pCopyGC; + + if( bXORMode_ + && !pSrcGraphics->bVirDev_ + && (GetDisplay()->GetProperties() & PROPERTY_BUG_XCopyArea_GXxor) ) + { + Pixmap hPixmap = limitXCreatePixmap( GetXDisplay(), + pSrcGraphics->GetDrawable(), // source + pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, + pSrcGraphics->GetBitCount() ); + + pCopyGC = GetDisplay()->GetCopyGC( m_nXScreen ); + + if( bNeedGraphicsExposures ) + XSetGraphicsExposures( GetXDisplay(), + pCopyGC, + True ); + + XCopyArea( GetXDisplay(), + pSrcGraphics->GetDrawable(), // source + hPixmap, // destination + pCopyGC, // no clipping + pPosAry->mnSrcX, pPosAry->mnSrcY, + pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, + 0, 0 ); // destination + XCopyArea( GetXDisplay(), + hPixmap, // source + GetDrawable(), // destination + GetInvertGC(), // destination clipping + 0, 0, // source + pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, + pPosAry->mnDestX, pPosAry->mnDestY ); + XFreePixmap( GetXDisplay(), hPixmap ); + } + else + { + pCopyGC = GetCopyGC(); + + if( bNeedGraphicsExposures ) + XSetGraphicsExposures( GetXDisplay(), + pCopyGC, + True ); + + XCopyArea( GetXDisplay(), + pSrcGraphics->GetDrawable(), // source + GetDrawable(), // destination + pCopyGC, // destination clipping + pPosAry->mnSrcX, pPosAry->mnSrcY, + pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, + pPosAry->mnDestX, pPosAry->mnDestY ); + } + + if( bNeedGraphicsExposures ) + { + YieldGraphicsExpose(); + + if( pCopyGC ) + XSetGraphicsExposures( GetXDisplay(), + pCopyGC, + False ); + } + } + else if( n ) + { + // #i60699# No chance to handle graphics exposures - we copy + // to a temp bitmap first, into which no repaints are + // technically possible. + SalBitmap *pDDB = pSrcGraphics->getBitmap( pPosAry->mnSrcX, + pPosAry->mnSrcY, + pPosAry->mnSrcWidth, + pPosAry->mnSrcHeight ); + + if( !pDDB ) + { + stderr0( "SalGraphics::CopyBits !pSrcGraphics->GetBitmap()\n" ); + return; + } + + SalTwoRect aPosAry( *pPosAry ); + + aPosAry.mnSrcX = 0, aPosAry.mnSrcY = 0; + drawBitmap( &aPosAry, *pDDB ); + + delete pDDB; + } + else { + stderr0( "X11SalGraphics::CopyBits from Printer not yet implemented\n" ); + } +} + +// -------------------------------------------------------------------------- + +void X11SalGraphics::copyArea ( long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, + sal_uInt16 ) +{ + SalTwoRect aPosAry; + + aPosAry.mnDestX = nDestX; + aPosAry.mnDestY = nDestY; + aPosAry.mnDestWidth = nSrcWidth; + aPosAry.mnDestHeight = nSrcHeight; + + aPosAry.mnSrcX = nSrcX; + aPosAry.mnSrcY = nSrcY; + aPosAry.mnSrcWidth = nSrcWidth; + aPosAry.mnSrcHeight = nSrcHeight; + + copyBits ( &aPosAry, 0 ); +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +void X11SalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap ) +{ + const SalDisplay* pSalDisp = GetDisplay(); + Display* pXDisp = pSalDisp->GetDisplay(); + const Drawable aDrawable( GetDrawable() ); + const SalColormap& rColMap = pSalDisp->GetColormap( m_nXScreen ); + const long nDepth = GetDisplay()->GetVisual( m_nXScreen ).GetDepth(); + GC aGC( GetCopyGC() ); + XGCValues aOldVal, aNewVal; + int nValues = GCForeground | GCBackground; + + if( rSalBitmap.GetBitCount() == 1 ) + { + // set foreground/background values for 1Bit bitmaps + XGetGCValues( pXDisp, aGC, nValues, &aOldVal ); + + aNewVal.foreground = rColMap.GetWhitePixel(); + aNewVal.background = rColMap.GetBlackPixel(); + + //fdo#33455 handle 1 bit depth pngs with palette entries + //to set fore/back colors + if (const BitmapBuffer* pBitmapBuffer = const_cast<SalBitmap&>(rSalBitmap).AcquireBuffer(true)) + { + const BitmapPalette& rPalette = pBitmapBuffer->maPalette; + if (rPalette.GetEntryCount() == 2) + { + aNewVal.foreground = rColMap.GetPixel(ImplColorToSal(rPalette[0])); + aNewVal.background = rColMap.GetPixel(ImplColorToSal(rPalette[1])); + } + } + + XChangeGC( pXDisp, aGC, nValues, &aNewVal ); + } + + if ( rSalBitmap.GetBitCount() == 32 && rSalBitmap.HasAlpha() ) + drawAlphaBitmapOpt( *pPosAry, rSalBitmap, rSalBitmap, false ); + else + static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aDrawable, m_nXScreen, nDepth, *pPosAry, aGC ); + + if( rSalBitmap.GetBitCount() == 1 ) + XChangeGC( pXDisp, aGC, nValues, &aOldVal ); + XFlush( pXDisp ); +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +void X11SalGraphics::drawBitmap( const SalTwoRect* pPosAry, + const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap ) +{ + DBG_ASSERT( !bPrinter_, "Drawing of transparent bitmaps on printer devices is strictly forbidden" ); + + // decide if alpha masking or transparency masking is needed + BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rMaskBitmap).AcquireBuffer( sal_True ); + if( pAlphaBuffer != NULL ) + { + int nMaskFormat = pAlphaBuffer->mnFormat; + const_cast<SalBitmap&>(rMaskBitmap).ReleaseBuffer( pAlphaBuffer, sal_True ); + if( nMaskFormat == BMP_FORMAT_8BIT_PAL ) + drawAlphaBitmap( *pPosAry, rSrcBitmap, rMaskBitmap ); + } + + drawMaskedBitmap( pPosAry, rSrcBitmap, rMaskBitmap ); +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +void X11SalGraphics::drawMaskedBitmap( const SalTwoRect* pPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rTransBitmap ) +{ + const SalDisplay* pSalDisp = GetDisplay(); + Display* pXDisp = pSalDisp->GetDisplay(); + Drawable aDrawable( GetDrawable() ); + + // figure work mode depth. If this is a VDev Drawable, use its + // bitdepth to create pixmaps for, otherwise, XCopyArea will + // refuse to work. + const sal_uInt16 nDepth( m_pVDev ? + m_pVDev->GetDepth() : + pSalDisp->GetVisual( m_nXScreen ).GetDepth() ); + Pixmap aFG( limitXCreatePixmap( pXDisp, aDrawable, pPosAry->mnDestWidth, + pPosAry->mnDestHeight, nDepth ) ); + Pixmap aBG( limitXCreatePixmap( pXDisp, aDrawable, pPosAry->mnDestWidth, + pPosAry->mnDestHeight, nDepth ) ); + + if( aFG && aBG ) + { + GC aTmpGC; + XGCValues aValues; + const SalColormap& rColMap = pSalDisp->GetColormap( m_nXScreen ); + const int nBlack = rColMap.GetBlackPixel(), nWhite = rColMap.GetWhitePixel(); + const int nValues = GCFunction | GCForeground | GCBackground; + SalTwoRect aTmpRect( *pPosAry ); aTmpRect.mnDestX = aTmpRect.mnDestY = 0; + + // draw paint bitmap in pixmap #1 + aValues.function = GXcopy, aValues.foreground = nWhite, aValues.background = nBlack; + aTmpGC = XCreateGC( pXDisp, aFG, nValues, &aValues ); + static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aFG, m_nXScreen, nDepth, aTmpRect, aTmpGC ); + DBG_TESTTRANS( aFG ); + + // draw background in pixmap #2 + XCopyArea( pXDisp, aDrawable, aBG, aTmpGC, + pPosAry->mnDestX, pPosAry->mnDestY, + pPosAry->mnDestWidth, pPosAry->mnDestHeight, + 0, 0 ); + + DBG_TESTTRANS( aBG ); + + // mask out paint bitmap in pixmap #1 (transparent areas 0) + aValues.function = GXand, aValues.foreground = 0x00000000, aValues.background = 0xffffffff; + XChangeGC( pXDisp, aTmpGC, nValues, &aValues ); + static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aFG, m_nXScreen, 1, aTmpRect, aTmpGC ); + + DBG_TESTTRANS( aFG ); + + // #105055# For XOR mode, keep background behind bitmap intact + if( !bXORMode_ ) + { + // mask out background in pixmap #2 (nontransparent areas 0) + aValues.function = GXand, aValues.foreground = 0xffffffff, aValues.background = 0x00000000; + XChangeGC( pXDisp, aTmpGC, nValues, &aValues ); + static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aBG, m_nXScreen, 1, aTmpRect, aTmpGC ); + + DBG_TESTTRANS( aBG ); + } + + // merge pixmap #1 and pixmap #2 in pixmap #2 + aValues.function = GXxor, aValues.foreground = 0xffffffff, aValues.background = 0x00000000; + XChangeGC( pXDisp, aTmpGC, nValues, &aValues ); + XCopyArea( pXDisp, aFG, aBG, aTmpGC, + 0, 0, + pPosAry->mnDestWidth, pPosAry->mnDestHeight, + 0, 0 ); + DBG_TESTTRANS( aBG ); + + // #105055# Disable XOR temporarily + sal_Bool bOldXORMode( bXORMode_ ); + bXORMode_ = sal_False; + + // copy pixmap #2 (result) to background + XCopyArea( pXDisp, aBG, aDrawable, GetCopyGC(), + 0, 0, + pPosAry->mnDestWidth, pPosAry->mnDestHeight, + pPosAry->mnDestX, pPosAry->mnDestY ); + + DBG_TESTTRANS( aBG ); + + bXORMode_ = bOldXORMode; + + XFreeGC( pXDisp, aTmpGC ); + XFlush( pXDisp ); + } + else + drawBitmap( pPosAry, rSalBitmap ); + + if( aFG ) + XFreePixmap( pXDisp, aFG ); + + if( aBG ) + XFreePixmap( pXDisp, aBG ); +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +bool X11SalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, + const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp ) +{ + return drawAlphaBitmapOpt( rTR, rSrcBitmap, rAlphaBmp ); +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +bool X11SalGraphics::drawAlphaBitmapOpt( const SalTwoRect& rTR, + const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp, bool bUseAlphaBitmap ) +{ + // non 8-bit alpha not implemented yet + if( bUseAlphaBitmap && rAlphaBmp.GetBitCount() != 8 ) + return false; + + // horizontal mirroring not implemented yet + if( rTR.mnDestWidth < 0 ) + return false; + + // stretched conversion is not implemented yet + if( rTR.mnDestWidth != rTR.mnSrcWidth ) + return false; + if( rTR.mnDestHeight!= rTR.mnSrcHeight ) + return false; + + // create destination picture + Picture aDstPic = GetXRenderPicture(); + if( !aDstPic ) + return false; + + const SalDisplay* pSalDisp = GetDisplay(); + const SalVisual& rSalVis = pSalDisp->GetVisual( m_nXScreen ); + Display* pXDisplay = pSalDisp->GetDisplay(); + + Picture aAlphaPic = 0; + Pixmap aAlphaPM = 0; + // create source Picture + int nDepth = m_pVDev ? m_pVDev->GetDepth() : rSalVis.GetDepth(); + const X11SalBitmap& rSrcX11Bmp = static_cast<const X11SalBitmap&>( rSrcBitmap ); + ImplSalDDB* pSrcDDB = rSrcX11Bmp.ImplGetDDB( hDrawable_, m_nXScreen, bUseAlphaBitmap ? nDepth : 32, rTR ); + if( !pSrcDDB ) + return false; + + //#i75249# workaround for ImplGetDDB() giving us back a different depth than + // we requested. E.g. mask pixmaps are always compatible with the drawable + // TODO: find an appropriate picture format for these cases + // then remove the workaround below and the one for #i75531# + if( bUseAlphaBitmap && nDepth != pSrcDDB->ImplGetDepth() ) + return false; + + Pixmap aSrcPM = pSrcDDB->ImplGetPixmap(); + if( !aSrcPM ) + return false; + + // create source picture + // TODO: use scoped picture + Visual* pSrcXVisual = rSalVis.GetVisual(); + XRenderPeer& rPeer = XRenderPeer::GetInstance(); + XRenderPictFormat* pSrcVisFmt = bUseAlphaBitmap ? rPeer.FindVisualFormat( pSrcXVisual ) : rPeer.FindStandardFormat( PictStandardARGB32 ); + if( !pSrcVisFmt ) + return false; + Picture aSrcPic = rPeer.CreatePicture( aSrcPM, pSrcVisFmt, 0, NULL ); + if( !aSrcPic ) + return false; + + if ( bUseAlphaBitmap ) { + // create alpha Picture + + // TODO: use SalX11Bitmap functionality and caching for the Alpha Pixmap + // problem is that they don't provide an 8bit Pixmap on a non-8bit display + BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rAlphaBmp).AcquireBuffer( sal_True ); + + // an XImage needs its data top_down + // TODO: avoid wrongly oriented images in upper layers! + const int nImageSize = pAlphaBuffer->mnHeight * pAlphaBuffer->mnScanlineSize; + const char* pSrcBits = (char*)pAlphaBuffer->mpBits; + char* pAlphaBits = new char[ nImageSize ]; + if( BMP_SCANLINE_ADJUSTMENT( pAlphaBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN ) + memcpy( pAlphaBits, pSrcBits, nImageSize ); + else + { + char* pDstBits = pAlphaBits + nImageSize; + const int nLineSize = pAlphaBuffer->mnScanlineSize; + for(; (pDstBits -= nLineSize) >= pAlphaBits; pSrcBits += nLineSize ) + memcpy( pDstBits, pSrcBits, nLineSize ); + } + + // the alpha values need to be inverted for XRender + // TODO: make upper layers use standard alpha + long* pLDst = (long*)pAlphaBits; + for( int i = nImageSize/sizeof(long); --i >= 0; ++pLDst ) + *pLDst = ~*pLDst; + + char* pCDst = (char*)pLDst; + for( int i = nImageSize & (sizeof(long)-1); --i >= 0; ++pCDst ) + *pCDst = ~*pCDst; + + const XRenderPictFormat* pAlphaFormat = rPeer.GetStandardFormatA8(); + XImage* pAlphaImg = XCreateImage( pXDisplay, pSrcXVisual, 8, ZPixmap, 0, + pAlphaBits, pAlphaBuffer->mnWidth, pAlphaBuffer->mnHeight, + pAlphaFormat->depth, pAlphaBuffer->mnScanlineSize ); + + aAlphaPM = limitXCreatePixmap( pXDisplay, hDrawable_, + rTR.mnDestWidth, rTR.mnDestHeight, 8 ); + + XGCValues aAlphaGCV; + aAlphaGCV.function = GXcopy; + GC aAlphaGC = XCreateGC( pXDisplay, aAlphaPM, GCFunction, &aAlphaGCV ); + XPutImage( pXDisplay, aAlphaPM, aAlphaGC, pAlphaImg, + rTR.mnSrcX, rTR.mnSrcY, 0, 0, rTR.mnDestWidth, rTR.mnDestHeight ); + XFreeGC( pXDisplay, aAlphaGC ); + XFree( pAlphaImg ); + if( pAlphaBits != (char*)pAlphaBuffer->mpBits ) + delete[] pAlphaBits; + + const_cast<SalBitmap&>(rAlphaBmp).ReleaseBuffer( pAlphaBuffer, sal_True ); + + XRenderPictureAttributes aAttr; + aAttr.repeat = true; + aAlphaPic = rPeer.CreatePicture( aAlphaPM, pAlphaFormat, CPRepeat, &aAttr ); + if( !aAlphaPic ) + return false; + } + + // set clipping + if( mpClipRegion && !XEmptyRegion( mpClipRegion ) ) + rPeer.SetPictureClipRegion( aDstPic, mpClipRegion ); + + // paint source * mask over destination picture + rPeer.CompositePicture( PictOpOver, aSrcPic, bUseAlphaBitmap ? aAlphaPic : None, aDstPic, + rTR.mnSrcX, rTR.mnSrcY, 0, 0, + rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight ); + + if ( bUseAlphaBitmap ) + { + if ( aAlphaPic ) + rPeer.FreePicture( aAlphaPic ); + if ( aAlphaPM ) + XFreePixmap( pXDisplay, aAlphaPM ); + } + rPeer.FreePicture( aSrcPic ); + return true; +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +bool X11SalGraphics::drawAlphaRect( long nX, long nY, long nWidth, + long nHeight, sal_uInt8 nTransparency ) +{ + if( ! m_pFrame && ! m_pVDev ) + return false; + + if( bPenGC_ || !bBrushGC_ || bXORMode_ ) + return false; // can only perform solid fills without XOR. + + if( m_pVDev && m_pVDev->GetDepth() < 8 ) + return false; + + Picture aDstPic = GetXRenderPicture(); + if( !aDstPic ) + return false; + + const double fTransparency = (100 - nTransparency) * (1.0/100); + const XRenderColor aRenderColor = GetXRenderColor( nBrushColor_ , fTransparency); + + XRenderPeer& rPeer = XRenderPeer::GetInstance(); + rPeer.FillRectangle( PictOpOver, + aDstPic, + &aRenderColor, + nX, nY, + nWidth, nHeight ); + + return true; +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +void X11SalGraphics::drawBitmap( const SalTwoRect*, + const SalBitmap&, + SalColor ) +{ + OSL_FAIL( "::DrawBitmap with transparent color not supported" ); +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +void X11SalGraphics::drawMask( const SalTwoRect* pPosAry, + const SalBitmap &rSalBitmap, + SalColor nMaskColor ) +{ + const SalDisplay* pSalDisp = GetDisplay(); + Display* pXDisp = pSalDisp->GetDisplay(); + Drawable aDrawable( GetDrawable() ); + Pixmap aStipple( limitXCreatePixmap( pXDisp, aDrawable, + pPosAry->mnDestWidth, + pPosAry->mnDestHeight, 1 ) ); + + if( aStipple ) + { + SalTwoRect aTwoRect( *pPosAry ); aTwoRect.mnDestX = aTwoRect.mnDestY = 0; + GC aTmpGC; + XGCValues aValues; + + // create a stipple bitmap first (set bits are changed to unset bits and vice versa) + aValues.function = GXcopyInverted; + aValues.foreground = 1, aValues.background = 0; + aTmpGC = XCreateGC( pXDisp, aStipple, GCFunction | GCForeground | GCBackground, &aValues ); + static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aStipple, m_nXScreen, 1, aTwoRect, aTmpGC ); + + XFreeGC( pXDisp, aTmpGC ); + + // Set stipple and draw rectangle + GC aStippleGC( GetStippleGC() ); + int nX = pPosAry->mnDestX, nY = pPosAry->mnDestY; + + XSetStipple( pXDisp, aStippleGC, aStipple ); + XSetTSOrigin( pXDisp, aStippleGC, nX, nY ); + XSetForeground( pXDisp, aStippleGC, GetPixel( nMaskColor ) ); + XFillRectangle( pXDisp, aDrawable, aStippleGC, + nX, nY, + pPosAry->mnDestWidth, pPosAry->mnDestHeight ); + XFreePixmap( pXDisp, aStipple ); + XFlush( pXDisp ); + } + else + drawBitmap( pPosAry, rSalBitmap ); +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +SalBitmap *X11SalGraphics::getBitmap( long nX, long nY, long nDX, long nDY ) +{ + if( bPrinter_ && !bVirDev_ ) + return NULL; + + bool bFakeWindowBG = false; + + // normalize + if( nDX < 0 ) + { + nX += nDX; + nDX = -nDX; + } + if ( nDY < 0 ) + { + nY += nDY; + nDY = -nDY; + } + + if( bWindow_ && !bVirDev_ ) + { + XWindowAttributes aAttrib; + + XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib ); + if( aAttrib.map_state != IsViewable ) + bFakeWindowBG = true; + else + { + long nOrgDX = nDX, nOrgDY = nDY; + + // clip to window size + if ( nX < 0 ) + { + nDX += nX; + nX = 0; + } + if ( nY < 0 ) + { + nDY += nY; + nY = 0; + } + if( nX + nDX > aAttrib.width ) + nDX = aAttrib.width - nX; + if( nY + nDY > aAttrib.height ) + nDY = aAttrib.height - nY; + + // inside ? + if( nDX <= 0 || nDY <= 0 ) + { + bFakeWindowBG = true; + nDX = nOrgDX; + nDY = nOrgDY; + } + } + } + + X11SalBitmap* pSalBitmap = new X11SalBitmap; + sal_uInt16 nBitCount = GetBitCount(); + + if( &GetDisplay()->GetColormap( m_nXScreen ) != &GetColormap() ) + nBitCount = 1; + + if( ! bFakeWindowBG ) + pSalBitmap->ImplCreateFromDrawable( GetDrawable(), m_nXScreen, nBitCount, nX, nY, nDX, nDY ); + else + pSalBitmap->Create( Size( nDX, nDY ), (nBitCount > 8) ? 24 : nBitCount, BitmapPalette( nBitCount > 8 ? nBitCount : 0 ) ); + + return pSalBitmap; +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +SalColor X11SalGraphics::getPixel( long nX, long nY ) +{ + if( bWindow_ && !bVirDev_ ) + { + XWindowAttributes aAttrib; + + XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib ); + if( aAttrib.map_state != IsViewable ) + { + stderr0( "X11SalGraphics::GetPixel drawable not viewable\n" ); + return 0; + } + } + + XImage *pXImage = XGetImage( GetXDisplay(), + GetDrawable(), + nX, nY, + 1, 1, + AllPlanes, + ZPixmap ); + if( !pXImage ) + { + stderr0( "X11SalGraphics::GetPixel !XGetImage()\n" ); + return 0; + } + + XColor aXColor; + + aXColor.pixel = XGetPixel( pXImage, 0, 0 ); + XDestroyImage( pXImage ); + + return GetColormap().GetColor( aXColor.pixel ); +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +void X11SalGraphics::invert( long nX, + long nY, + long nDX, + long nDY, + SalInvert nFlags ) +{ + GC pGC; + if( SAL_INVERT_50 & nFlags ) + { + pGC = GetInvert50GC(); + XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY ); + } + else + { + if ( SAL_INVERT_TRACKFRAME & nFlags ) + { + pGC = GetTrackingGC(); + XDrawRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY ); + } + else + { + pGC = GetInvertGC(); + XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY ); + } + } +} + +bool X11SalGraphics::supportsOperation( OutDevSupportType eType ) const +{ + bool bRet = false; + switch( eType ) + { + case OutDevSupport_TransparentRect: + case OutDevSupport_B2DDraw: + { + XRenderPeer& rPeer = XRenderPeer::GetInstance(); + const SalDisplay* pSalDisp = GetDisplay(); + const SalVisual& rSalVis = pSalDisp->GetVisual( m_nXScreen ); + + Visual* pDstXVisual = rSalVis.GetVisual(); + XRenderPictFormat* pDstVisFmt = rPeer.FindVisualFormat( pDstXVisual ); + if( pDstVisFmt ) + bRet = true; + } + break; + default: break; + } + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/gdi/salgdi2.cxx.rej b/vcl/unx/generic/gdi/salgdi2.cxx.rej new file mode 100644 index 000000000000..284ddfc53be6 --- /dev/null +++ b/vcl/unx/generic/gdi/salgdi2.cxx.rej @@ -0,0 +1,13 @@ +--- vcl/unx/generic/gdi/salgdi2.cxx ++++ vcl/unx/generic/gdi/salgdi2.cxx +@@ -658,8 +658,8 @@ + const SalVisual& rSalVis = pSalDisp->GetVisual( m_nXScreen ); + Display* pXDisplay = pSalDisp->GetDisplay(); + +- Picture aAlphaPic; +- Pixmap aAlphaPM; ++ Picture aAlphaPic = 0; ++ Pixmap aAlphaPM = 0; + // create source Picture + int nDepth = m_pVDev ? m_pVDev->GetDepth() : rSalVis.GetDepth(); + const X11SalBitmap& rSrcX11Bmp = static_cast<const X11SalBitmap&>( rSrcBitmap ); |