summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRadek Doulik <rodo@novell.com>2013-03-14 09:36:43 +0100
committerRadek Doulik <rodo@novell.com>2013-03-14 13:21:24 +0100
commit22f63477a3300d474c3d6832232b888f75c7290c (patch)
tree7fc4d0970fd5d58fe950e9b618ba87533c53b6e8
parent87354e7fc1f63480bdef092047f912682bc7ac58 (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.cxx30
-rw-r--r--canvas/source/cairo/cairo_canvasbitmap.hxx4
-rw-r--r--canvas/source/cairo/cairo_xlib_cairo.cxx7
-rw-r--r--canvas/source/cairo/cairo_xlib_cairo.hxx1
-rw-r--r--vcl/inc/unx/salbmp.h4
-rw-r--r--vcl/inc/vcl/bitmap.hxx3
-rw-r--r--vcl/source/gdi/bitmap.cxx13
-rw-r--r--vcl/source/gdi/gdimtf.cxx.orig3184
-rw-r--r--vcl/source/helper/canvastools.cxx25
-rw-r--r--vcl/unx/generic/gdi/salbmp.cxx16
-rw-r--r--vcl/unx/generic/gdi/salgdi2.cxx4
-rw-r--r--vcl/unx/generic/gdi/salgdi2.cxx.orig1009
-rw-r--r--vcl/unx/generic/gdi/salgdi2.cxx.rej13
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 );