summaryrefslogtreecommitdiff
path: root/canvas/source/tools
diff options
context:
space:
mode:
Diffstat (limited to 'canvas/source/tools')
-rw-r--r--canvas/source/tools/bitmap.cxx838
-rw-r--r--canvas/source/tools/cachedprimitivebase.cxx112
-rw-r--r--canvas/source/tools/canvascustomspritehelper.cxx496
-rwxr-xr-xcanvas/source/tools/canvastools.cxx1044
-rw-r--r--canvas/source/tools/canvastools.flt4
-rw-r--r--canvas/source/tools/elapsedtime.cxx224
-rw-r--r--canvas/source/tools/image.cxx2394
-rw-r--r--canvas/source/tools/image.hxx298
-rw-r--r--canvas/source/tools/image_sysprereq.h102
-rw-r--r--canvas/source/tools/imagecachedprimitive.hxx57
-rw-r--r--canvas/source/tools/makefile.mk101
-rw-r--r--canvas/source/tools/page.cxx152
-rw-r--r--canvas/source/tools/page.hxx157
-rw-r--r--canvas/source/tools/pagemanager.cxx216
-rw-r--r--canvas/source/tools/pagemanager.hxx94
-rw-r--r--canvas/source/tools/parametricpolypolygon.cxx290
-rw-r--r--canvas/source/tools/prioritybooster.cxx83
-rw-r--r--canvas/source/tools/propertysethelper.cxx187
-rw-r--r--canvas/source/tools/spriteredrawmanager.cxx520
-rw-r--r--canvas/source/tools/surface.cxx496
-rw-r--r--canvas/source/tools/surface.hxx162
-rw-r--r--canvas/source/tools/surfaceproxy.cxx182
-rw-r--r--canvas/source/tools/surfaceproxy.hxx134
-rw-r--r--canvas/source/tools/surfaceproxymanager.cxx86
-rw-r--r--canvas/source/tools/surfacerect.hxx135
-rw-r--r--canvas/source/tools/verifyinput.cxx926
26 files changed, 9490 insertions, 0 deletions
diff --git a/canvas/source/tools/bitmap.cxx b/canvas/source/tools/bitmap.cxx
new file mode 100644
index 000000000000..eb7732b9a8f6
--- /dev/null
+++ b/canvas/source/tools/bitmap.cxx
@@ -0,0 +1,838 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/rendering/bitmap.hxx>
+#include <canvas/rendering/isurfaceproxy.hxx>
+#include <basegfx/vector/b2isize.hxx>
+#include "image.hxx"
+#include <algorithm>
+#include <iterator>
+
+
+using namespace ::com::sun::star;
+
+namespace canvas
+{
+ class ImplBitmap
+ {
+ public:
+ ImplBitmap( const ::basegfx::B2IVector& rSize,
+ const ISurfaceProxyManagerSharedPtr& rMgr,
+ bool bWithAlpha ) :
+ mpImage(),
+ mpSurfaceProxy(),
+ mbIsSurfaceDirty( true )
+ {
+ ENSURE_OR_THROW( rMgr,
+ "Bitmap::Bitmap(): Invalid surface proxy manager" );
+
+ Image::Description desc;
+
+ desc.eFormat = bWithAlpha ? Image::FMT_A8R8G8B8 : Image::FMT_R8G8B8;
+ desc.nWidth = rSize.getX();
+ desc.nHeight = rSize.getY();
+ desc.nStride = 0;
+ desc.pBuffer = NULL;
+
+ mpImage.reset( new Image(desc) );
+
+ // clear the surface [fill with opaque black]
+ mpImage->clear(0,255,255,255);
+
+ // create a (possibly hardware accelerated) mirror surface.
+ mpSurfaceProxy = rMgr->createSurfaceProxy( mpImage );
+ }
+
+ bool hasAlpha() const
+ {
+ if( !mpImage )
+ return false;
+
+ return (mpImage->getDescription().eFormat == Image::FMT_A8R8G8B8);
+ }
+
+ ::basegfx::B2IVector getSize() const
+ {
+ return ::basegfx::B2IVector( mpImage->getWidth(),
+ mpImage->getHeight() );
+ }
+
+ ::com::sun::star::uno::Sequence< sal_Int8 > getData( ::com::sun::star::rendering::IntegerBitmapLayout& /*bitmapLayout*/,
+ const ::com::sun::star::geometry::IntegerRectangle2D& rect )
+ {
+ const IColorBuffer::Format format = mpImage->getFormat();
+ const sal_uInt32 dwNumBytesPerPixel = getNumBytes(format);
+ const sal_uInt32 dwPitch = mpImage->getWidth()*dwNumBytesPerPixel;
+
+ if(!(dwNumBytesPerPixel))
+ return uno::Sequence< sal_Int8 >();
+
+ const sal_uInt32 dwWidth = rect.X2-rect.X1;
+ const sal_uInt32 dwHeight = rect.Y2-rect.Y1;
+
+ uno::Sequence< sal_Int8 > aRes(dwWidth*dwHeight*4);
+ sal_uInt8 *pDst = reinterpret_cast<sal_uInt8 *>(aRes.getArray());
+
+ const sal_uInt8 *pSrc = mpImage->lock()+(rect.Y1*dwPitch)+(rect.X1*dwNumBytesPerPixel);
+ const sal_uInt32 dwSpanSizeInBytes = dwNumBytesPerPixel*dwWidth;
+ for(sal_uInt32 y=0; y<dwHeight; ++y)
+ {
+ rtl_copyMemory(pDst,pSrc,dwSpanSizeInBytes);
+ pDst += dwSpanSizeInBytes;
+ pSrc += dwPitch;
+ }
+ mpImage->unlock();
+
+ return aRes;
+ }
+
+ void setData( const ::com::sun::star::uno::Sequence< sal_Int8 >& data,
+ const ::com::sun::star::rendering::IntegerBitmapLayout& /*bitmapLayout*/,
+ const ::com::sun::star::geometry::IntegerRectangle2D& rect )
+ {
+ const IColorBuffer::Format format = mpImage->getFormat();
+ const sal_uInt32 dwNumBytesPerPixel = getNumBytes(format);
+ const sal_uInt32 dwPitch = mpImage->getWidth()*dwNumBytesPerPixel;
+
+ if(!(dwNumBytesPerPixel))
+ return;
+
+ const sal_uInt32 dwWidth = rect.X2-rect.X1;
+ const sal_uInt32 dwHeight = rect.Y2-rect.Y1;
+ const sal_uInt8 *pSrc = reinterpret_cast<const sal_uInt8 *>(data.getConstArray());
+
+ sal_uInt8 *pDst = mpImage->lock()+(rect.Y1*dwPitch)+(rect.X1*dwNumBytesPerPixel);
+ const sal_uInt32 dwSpanSizeInBytes = dwNumBytesPerPixel*dwWidth;
+ for(sal_uInt32 y=0; y<dwHeight; ++y)
+ {
+ rtl_copyMemory(pDst,pSrc,dwSpanSizeInBytes);
+ pSrc += dwSpanSizeInBytes;
+ pDst += dwPitch;
+ }
+ mpImage->unlock();
+ }
+
+ void setPixel( const ::com::sun::star::uno::Sequence< sal_Int8 >& color,
+ const ::com::sun::star::rendering::IntegerBitmapLayout& /*bitmapLayout*/,
+ const ::com::sun::star::geometry::IntegerPoint2D& pos )
+ {
+ struct ARGBColor
+ {
+ sal_uInt8 a;
+ sal_uInt8 r;
+ sal_uInt8 g;
+ sal_uInt8 b;
+ };
+
+ union ARGB
+ {
+ ARGBColor Color;
+ sal_uInt32 color;
+
+ inline ARGB( sal_uInt32 _color ) : color(_color) {}
+ };
+
+ ARGB argb(0xFFFFFFFF);
+
+ if(color.getLength() > 2)
+ {
+ argb.Color.r = static_cast<sal_uInt8>(color[0]);
+ argb.Color.g = static_cast<sal_uInt8>(color[1]);
+ argb.Color.b = static_cast<sal_uInt8>(color[2]);
+ if(color.getLength() > 3)
+ argb.Color.a = static_cast<sal_uInt8>(255.0f*color[3]);
+ }
+
+ const IColorBuffer::Format format = mpImage->getFormat();
+ const sal_uInt32 dwNumBytesPerPixel = getNumBytes(format);
+ const sal_uInt32 dwPitch = mpImage->getWidth()*dwNumBytesPerPixel;
+
+ if(!(dwNumBytesPerPixel))
+ return;
+
+ sal_uInt8 *pDst = mpImage->lock()+(pos.Y*dwPitch)+(pos.X*dwNumBytesPerPixel);
+
+ switch(format)
+ {
+ case IColorBuffer::FMT_R8G8B8:
+ pDst[0] = argb.Color.r;
+ pDst[1] = argb.Color.g;
+ pDst[2] = argb.Color.b;
+ break;
+ case IColorBuffer::FMT_A8R8G8B8:
+ case IColorBuffer::FMT_X8R8G8B8:
+ pDst[0] = argb.Color.a;
+ pDst[1] = argb.Color.r;
+ pDst[2] = argb.Color.g;
+ pDst[3] = argb.Color.b;
+ break;
+ default:
+ break;
+ }
+
+ mpImage->unlock();
+ }
+
+ uno::Sequence< sal_Int8 > getPixel( ::com::sun::star::rendering::IntegerBitmapLayout& /*bitmapLayout*/,
+ const ::com::sun::star::geometry::IntegerPoint2D& pos )
+ {
+ const IColorBuffer::Format format = mpImage->getFormat();
+ const sal_uInt32 dwNumBytesPerPixel = getNumBytes(format);
+ const sal_uInt32 dwPitch = mpImage->getWidth()*dwNumBytesPerPixel;
+
+ if(!(dwNumBytesPerPixel))
+ return uno::Sequence< sal_Int8 >();
+
+ uno::Sequence< sal_Int8 > aRet(dwNumBytesPerPixel);
+ const sal_uInt8 *pSrc = mpImage->lock()+(pos.Y*dwPitch)+(pos.X*dwNumBytesPerPixel);
+
+ switch(format)
+ {
+ case IColorBuffer::FMT_R8G8B8:
+ aRet[0] = pSrc[0];
+ aRet[1] = pSrc[1];
+ aRet[2] = pSrc[2];
+ break;
+ case IColorBuffer::FMT_A8R8G8B8:
+ case IColorBuffer::FMT_X8R8G8B8:
+ aRet[0] = pSrc[1];
+ aRet[1] = pSrc[2];
+ aRet[2] = pSrc[3];
+ aRet[3] = pSrc[0];
+ break;
+ default:
+ break;
+ }
+
+ mpImage->unlock();
+
+ return aRet;
+ }
+
+ // the IColorBuffer interface
+ // ==========================
+
+ bool draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ if( mbIsSurfaceDirty )
+ {
+ mpSurfaceProxy->setColorBufferDirty();
+ mbIsSurfaceDirty = false;
+ }
+
+ return mpSurfaceProxy->draw( fAlpha, rPos, rTransform );
+ }
+
+ bool draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DRange& rArea,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ if( mbIsSurfaceDirty )
+ {
+ mpSurfaceProxy->setColorBufferDirty();
+ mbIsSurfaceDirty = false;
+ }
+
+ return mpSurfaceProxy->draw( fAlpha, rPos, rArea, rTransform );
+ }
+
+
+ bool draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DPolyPolygon& rClipPoly,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ if( mbIsSurfaceDirty )
+ {
+ mpSurfaceProxy->setColorBufferDirty();
+ mbIsSurfaceDirty = false;
+ }
+
+ return mpSurfaceProxy->draw( fAlpha, rPos, rClipPoly, rTransform );
+ }
+
+ void clear( const uno::Sequence< double >& color )
+ {
+ if(color.getLength() > 2)
+ {
+ mbIsSurfaceDirty = true;
+
+ if(color.getLength() > 3)
+ {
+ mpImage->clear( static_cast<sal_uInt8>(255.0f*color[0]),
+ static_cast<sal_uInt8>(255.0f*color[1]),
+ static_cast<sal_uInt8>(255.0f*color[2]),
+ static_cast<sal_uInt8>(255.0f*color[3]) );
+ }
+ else
+ {
+ mpImage->clear( static_cast<sal_uInt8>(255.0f*color[0]),
+ static_cast<sal_uInt8>(255.0f*color[1]),
+ static_cast<sal_uInt8>(255.0f*color[2]),
+ 255 );
+ }
+ }
+ }
+
+ void fillB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ mbIsSurfaceDirty = true;
+
+ mpImage->fillB2DPolyPolygon( rPolyPolygon,
+ viewState,
+ renderState );
+ }
+
+
+ // the XCanvas-render interface
+ // ============================
+
+ void drawPoint( const geometry::RealPoint2D& aPoint,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ mbIsSurfaceDirty = true;
+
+ mpImage->drawPoint( aPoint, viewState, renderState );
+ }
+
+ void drawLine( const geometry::RealPoint2D& aStartPoint,
+ const geometry::RealPoint2D& aEndPoint,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ mbIsSurfaceDirty = true;
+
+ mpImage->drawLine( aStartPoint, aEndPoint, viewState, renderState );
+ }
+
+ void drawBezier( const geometry::RealBezierSegment2D& aBezierSegment,
+ const geometry::RealPoint2D& aEndPoint,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ mbIsSurfaceDirty = true;
+
+ mpImage->drawBezier( aBezierSegment, aEndPoint, viewState, renderState );
+ }
+
+ ICachedPrimitiveSharedPtr drawPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ mbIsSurfaceDirty = true;
+
+ return setupCachedPrimitive(
+ mpImage->drawPolyPolygon( xPolyPolygon, viewState, renderState ) );
+ }
+
+ ICachedPrimitiveSharedPtr strokePolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const rendering::StrokeAttributes& strokeAttributes )
+ {
+ mbIsSurfaceDirty = true;
+
+ return setupCachedPrimitive(
+ mpImage->strokePolyPolygon( xPolyPolygon,
+ viewState,
+ renderState,
+ strokeAttributes ) );
+ }
+
+ ICachedPrimitiveSharedPtr strokeTexturedPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const uno::Sequence< rendering::Texture >& textures,
+ const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations,
+ const rendering::StrokeAttributes& strokeAttributes )
+ {
+ mbIsSurfaceDirty = true;
+
+ ::std::vector< ImageSharedPtr > aTextureAnnotations;
+ convertTextureAnnotations( aTextureAnnotations,
+ textureAnnotations );
+
+ return setupCachedPrimitive(
+ mpImage->strokeTexturedPolyPolygon( xPolyPolygon,
+ viewState,
+ renderState,
+ textures,
+ aTextureAnnotations,
+ strokeAttributes ) );
+ }
+
+ ICachedPrimitiveSharedPtr strokeTextureMappedPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const uno::Sequence< rendering::Texture >& textures,
+ const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations,
+ const uno::Reference< geometry::XMapping2D >& xMapping,
+ const rendering::StrokeAttributes& strokeAttributes )
+ {
+ mbIsSurfaceDirty = true;
+
+ ::std::vector< ImageSharedPtr > aTextureAnnotations;
+ convertTextureAnnotations( aTextureAnnotations,
+ textureAnnotations );
+
+ return setupCachedPrimitive(
+ mpImage->strokeTextureMappedPolyPolygon( xPolyPolygon,
+ viewState,
+ renderState,
+ textures,
+ aTextureAnnotations,
+ xMapping,
+ strokeAttributes ) );
+ }
+
+
+ ICachedPrimitiveSharedPtr fillPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ mbIsSurfaceDirty = true;
+
+ return setupCachedPrimitive(
+ mpImage->fillPolyPolygon( xPolyPolygon,
+ viewState,
+ renderState ) );
+ }
+
+ ICachedPrimitiveSharedPtr fillTexturedPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const uno::Sequence< rendering::Texture >& textures,
+ const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations )
+ {
+ mbIsSurfaceDirty = true;
+
+ ::std::vector< ImageSharedPtr > aTextureAnnotations;
+ convertTextureAnnotations( aTextureAnnotations,
+ textureAnnotations );
+
+ return setupCachedPrimitive(
+ mpImage->fillTexturedPolyPolygon( xPolyPolygon,
+ viewState,
+ renderState,
+ textures,
+ aTextureAnnotations ) );
+ }
+
+
+ ICachedPrimitiveSharedPtr fillTextureMappedPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const uno::Sequence< rendering::Texture >& textures,
+ const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations,
+ const uno::Reference< geometry::XMapping2D >& xMapping )
+ {
+ mbIsSurfaceDirty = true;
+
+ ::std::vector< ImageSharedPtr > aTextureAnnotations;
+ convertTextureAnnotations( aTextureAnnotations,
+ textureAnnotations );
+
+ return setupCachedPrimitive(
+ mpImage->fillTextureMappedPolyPolygon( xPolyPolygon,
+ viewState,
+ renderState,
+ textures,
+ aTextureAnnotations,
+ xMapping ) );
+ }
+
+ ICachedPrimitiveSharedPtr drawBitmap(
+ const uno::Reference< rendering::XBitmap >& xBitmap,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ mbIsSurfaceDirty = true;
+
+ return setupCachedPrimitive(
+ mpImage->drawBitmap( xBitmap,
+ viewState,
+ renderState ) );
+ }
+
+ ICachedPrimitiveSharedPtr drawBitmap(
+ const ::boost::shared_ptr<Bitmap>& rImage,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ mbIsSurfaceDirty = true;
+
+ return setupCachedPrimitive(
+ mpImage->drawBitmap( rImage->mpImpl->mpImage,
+ viewState,
+ renderState ) );
+ }
+
+ ICachedPrimitiveSharedPtr drawBitmapModulated(
+ const uno::Reference< rendering::XBitmap >& xBitmap,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ mbIsSurfaceDirty = true;
+
+ return setupCachedPrimitive(
+ mpImage->drawBitmapModulated( xBitmap,
+ viewState,
+ renderState ) );
+ }
+
+
+ ICachedPrimitiveSharedPtr drawBitmapModulated(
+ const ::boost::shared_ptr<Bitmap>& rImage,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ mbIsSurfaceDirty = true;
+
+ return setupCachedPrimitive(
+ mpImage->drawBitmapModulated( rImage->mpImpl->mpImage,
+ viewState,
+ renderState ) );
+ }
+
+ private:
+ ICachedPrimitiveSharedPtr setupCachedPrimitive(
+ const ImageCachedPrimitiveSharedPtr& rCachedPrimitive ) const
+ {
+ if( rCachedPrimitive )
+ rCachedPrimitive->setImage( mpImage );
+
+ return rCachedPrimitive;
+ }
+
+ void convertTextureAnnotations( ::std::vector< ImageSharedPtr >& o_rTextureAnnotations,
+ const ::std::vector< BitmapSharedPtr >& textureAnnotations )
+ {
+ ::std::vector< BitmapSharedPtr >::const_iterator aCurr( textureAnnotations.begin() );
+ const ::std::vector< BitmapSharedPtr >::const_iterator aEnd( textureAnnotations.end() );
+ while( aCurr != aEnd )
+ {
+ if( aCurr->get() != NULL )
+ o_rTextureAnnotations.push_back( (*aCurr)->mpImpl->mpImage );
+ else
+ o_rTextureAnnotations.push_back( ImageSharedPtr() );
+
+ ++aCurr;
+ }
+ }
+
+ sal_uInt32 getNumBytes( IColorBuffer::Format format )
+ {
+ switch(format)
+ {
+ case IColorBuffer::FMT_R8G8B8:
+ return 3;
+ case IColorBuffer::FMT_A8R8G8B8:
+ case IColorBuffer::FMT_X8R8G8B8:
+ return 4;
+ default:
+ return 0;
+ }
+ }
+
+ ImageSharedPtr mpImage;
+ ISurfaceProxySharedPtr mpSurfaceProxy;
+ bool mbIsSurfaceDirty;
+ };
+
+
+ /////////////////////////////////////////////////////////////////
+ // Actual Bitmap pimpl forwarding functions
+ /////////////////////////////////////////////////////////////////
+
+ Bitmap::Bitmap( const ::basegfx::B2IVector& rSize,
+ const ISurfaceProxyManagerSharedPtr& rMgr,
+ bool bWithAlpha ) :
+ mpImpl( new ImplBitmap( rSize,
+ rMgr,
+ bWithAlpha ) )
+ {
+ }
+
+ Bitmap::~Bitmap()
+ {
+ // outline destructor is _necessary_, because ImplBitmap is an
+ // incomplete type outside this file.
+ }
+
+ // forward all methods to ImplBitmap
+ // ==================================================
+
+ bool Bitmap::hasAlpha() const
+ {
+ return mpImpl->hasAlpha();
+ }
+
+ ::basegfx::B2IVector Bitmap::getSize() const
+ {
+ return mpImpl->getSize();
+ }
+
+ ::com::sun::star::uno::Sequence< sal_Int8 > Bitmap::getData(
+ ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout,
+ const ::com::sun::star::geometry::IntegerRectangle2D& rect )
+ {
+ return mpImpl->getData(bitmapLayout,rect);
+ }
+
+ void Bitmap::setData(
+ const ::com::sun::star::uno::Sequence< sal_Int8 >& data,
+ const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout,
+ const ::com::sun::star::geometry::IntegerRectangle2D& rect )
+ {
+ mpImpl->setData(data,bitmapLayout,rect);
+ }
+
+ void Bitmap::setPixel(
+ const ::com::sun::star::uno::Sequence< sal_Int8 >& color,
+ const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout,
+ const ::com::sun::star::geometry::IntegerPoint2D& pos )
+ {
+ mpImpl->setPixel(color,bitmapLayout,pos);
+ }
+
+ uno::Sequence< sal_Int8 > Bitmap::getPixel(
+ ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout,
+ const ::com::sun::star::geometry::IntegerPoint2D& pos )
+ {
+ return mpImpl->getPixel(bitmapLayout,pos);
+ }
+
+ bool Bitmap::draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ return mpImpl->draw( fAlpha, rPos, rTransform );
+ }
+
+ bool Bitmap::draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DRange& rArea,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ return mpImpl->draw( fAlpha, rPos, rArea, rTransform );
+ }
+
+
+ bool Bitmap::draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DPolyPolygon& rClipPoly,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ return mpImpl->draw( fAlpha, rPos, rClipPoly, rTransform );
+ }
+
+ void Bitmap::clear( const uno::Sequence< double >& color )
+ {
+ mpImpl->clear( color );
+ }
+
+ void Bitmap::fillB2DPolyPolygon(
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ mpImpl->fillB2DPolyPolygon( rPolyPolygon, viewState, renderState );
+ }
+
+ void Bitmap::drawPoint( const geometry::RealPoint2D& aPoint,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ return mpImpl->drawPoint( aPoint, viewState, renderState );
+ }
+
+ void Bitmap::drawLine( const geometry::RealPoint2D& aStartPoint,
+ const geometry::RealPoint2D& aEndPoint,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ return mpImpl->drawLine( aStartPoint, aEndPoint, viewState, renderState );
+ }
+
+ void Bitmap::drawBezier( const geometry::RealBezierSegment2D& aBezierSegment,
+ const geometry::RealPoint2D& aEndPoint,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ return mpImpl->drawBezier( aBezierSegment, aEndPoint, viewState, renderState );
+ }
+
+ ICachedPrimitiveSharedPtr Bitmap::drawPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ return mpImpl->drawPolyPolygon( xPolyPolygon, viewState, renderState );
+ }
+
+ ICachedPrimitiveSharedPtr Bitmap::strokePolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const rendering::StrokeAttributes& strokeAttributes )
+ {
+ return mpImpl->strokePolyPolygon( xPolyPolygon, viewState, renderState, strokeAttributes );
+ }
+
+ ICachedPrimitiveSharedPtr Bitmap::strokeTexturedPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const uno::Sequence< rendering::Texture >& textures,
+ const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations,
+ const rendering::StrokeAttributes& strokeAttributes )
+ {
+ return mpImpl->strokeTexturedPolyPolygon( xPolyPolygon,
+ viewState,
+ renderState,
+ textures,
+ textureAnnotations,
+ strokeAttributes );
+ }
+
+ ICachedPrimitiveSharedPtr Bitmap::strokeTextureMappedPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const uno::Sequence< rendering::Texture >& textures,
+ const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations,
+ const uno::Reference< geometry::XMapping2D >& xMapping,
+ const rendering::StrokeAttributes& strokeAttributes )
+ {
+ return mpImpl->strokeTextureMappedPolyPolygon( xPolyPolygon,
+ viewState,
+ renderState,
+ textures,
+ textureAnnotations,
+ xMapping,
+ strokeAttributes );
+ }
+
+
+ ICachedPrimitiveSharedPtr Bitmap::fillPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ return mpImpl->fillPolyPolygon( xPolyPolygon,
+ viewState,
+ renderState );
+ }
+
+ ICachedPrimitiveSharedPtr Bitmap::fillTexturedPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const uno::Sequence< rendering::Texture >& textures,
+ const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations )
+ {
+ return mpImpl->fillTexturedPolyPolygon( xPolyPolygon,
+ viewState,
+ renderState,
+ textures,
+ textureAnnotations );
+ }
+
+ ICachedPrimitiveSharedPtr Bitmap::fillTextureMappedPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const uno::Sequence< rendering::Texture >& textures,
+ const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations,
+ const uno::Reference< geometry::XMapping2D >& xMapping )
+ {
+ return mpImpl->fillTextureMappedPolyPolygon( xPolyPolygon,
+ viewState,
+ renderState,
+ textures,
+ textureAnnotations,
+ xMapping );
+ }
+
+ ICachedPrimitiveSharedPtr Bitmap::drawBitmap(
+ const uno::Reference< rendering::XBitmap >& xBitmap,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ return mpImpl->drawBitmap( xBitmap,
+ viewState,
+ renderState );
+ }
+
+ ICachedPrimitiveSharedPtr Bitmap::drawBitmap(
+ const ::boost::shared_ptr<Bitmap>& rImage,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ return mpImpl->drawBitmap( rImage,
+ viewState,
+ renderState );
+ }
+
+ ICachedPrimitiveSharedPtr Bitmap::drawBitmapModulated(
+ const uno::Reference< rendering::XBitmap >& xBitmap,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ return mpImpl->drawBitmapModulated( xBitmap,
+ viewState,
+ renderState );
+ }
+
+ ICachedPrimitiveSharedPtr Bitmap::drawBitmapModulated(
+ const ::boost::shared_ptr<Bitmap>& rImage,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ return mpImpl->drawBitmapModulated( rImage,
+ viewState,
+ renderState );
+ }
+}
diff --git a/canvas/source/tools/cachedprimitivebase.cxx b/canvas/source/tools/cachedprimitivebase.cxx
new file mode 100644
index 000000000000..0d850b842007
--- /dev/null
+++ b/canvas/source/tools/cachedprimitivebase.cxx
@@ -0,0 +1,112 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include <canvas/debug.hxx>
+#include <canvas/base/cachedprimitivebase.hxx>
+
+#include <com/sun/star/rendering/RepaintResult.hpp>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/tools/canvastools.hxx>
+
+
+using namespace ::com::sun::star;
+
+#define IMPLEMENTATION_NAME "canvas::CachedPrimitiveBase"
+#define SERVICE_NAME "com.sun.star.rendering.CachedBitmap"
+
+namespace canvas
+{
+ CachedPrimitiveBase::CachedPrimitiveBase( const rendering::ViewState& rUsedViewState,
+ const uno::Reference< rendering::XCanvas >& rTarget,
+ bool bFailForChangedViewTransform ) :
+ CachedPrimitiveBase_Base( m_aMutex ),
+ maUsedViewState( rUsedViewState ),
+ mxTarget( rTarget ),
+ mbFailForChangedViewTransform( bFailForChangedViewTransform )
+ {
+ }
+
+ CachedPrimitiveBase::~CachedPrimitiveBase()
+ {
+ }
+
+ void SAL_CALL CachedPrimitiveBase::disposing()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ maUsedViewState.Clip.clear();
+ mxTarget.clear();
+ }
+
+ sal_Int8 SAL_CALL CachedPrimitiveBase::redraw( const rendering::ViewState& aState ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ ::basegfx::B2DHomMatrix aUsedTransformation;
+ ::basegfx::B2DHomMatrix aNewTransformation;
+
+ ::basegfx::unotools::homMatrixFromAffineMatrix( aUsedTransformation,
+ maUsedViewState.AffineTransform );
+ ::basegfx::unotools::homMatrixFromAffineMatrix( aNewTransformation,
+ aState.AffineTransform );
+
+ const bool bSameViewTransforms( aUsedTransformation == aNewTransformation );
+
+ if( mbFailForChangedViewTransform &&
+ !bSameViewTransforms )
+ {
+ // differing transformations, don't try to draft the
+ // output, just plain fail here.
+ return rendering::RepaintResult::FAILED;
+ }
+
+ return doRedraw( aState,
+ maUsedViewState,
+ mxTarget,
+ bSameViewTransforms );
+ }
+
+ ::rtl::OUString SAL_CALL CachedPrimitiveBase::getImplementationName( ) throw (uno::RuntimeException)
+ {
+ return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) );
+ }
+
+ sal_Bool SAL_CALL CachedPrimitiveBase::supportsService( const ::rtl::OUString& ServiceName ) throw (uno::RuntimeException)
+ {
+ return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) );
+ }
+
+ uno::Sequence< ::rtl::OUString > SAL_CALL CachedPrimitiveBase::getSupportedServiceNames( ) throw (uno::RuntimeException)
+ {
+ uno::Sequence< ::rtl::OUString > aRet(1);
+ aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) );
+
+ return aRet;
+ }
+}
diff --git a/canvas/source/tools/canvascustomspritehelper.cxx b/canvas/source/tools/canvascustomspritehelper.cxx
new file mode 100644
index 000000000000..f9d4f186d7a7
--- /dev/null
+++ b/canvas/source/tools/canvascustomspritehelper.cxx
@@ -0,0 +1,496 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+#include <canvas/canvastools.hxx>
+
+#include <rtl/math.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/numeric/ftools.hxx>
+
+#include <canvas/base/canvascustomspritehelper.hxx>
+
+using namespace ::com::sun::star;
+
+
+namespace canvas
+{
+ bool CanvasCustomSpriteHelper::updateClipState( const Sprite::Reference& rSprite )
+ {
+ if( !mxClipPoly.is() )
+ {
+ // empty clip polygon -> everything is visible now
+ maCurrClipBounds.reset();
+ mbIsCurrClipRectangle = true;
+ }
+ else
+ {
+ const sal_Int32 nNumClipPolygons( mxClipPoly->getNumberOfPolygons() );
+
+ // clip is not empty - determine actual update area
+ ::basegfx::B2DPolyPolygon aClipPath(
+ polyPolygonFromXPolyPolygon2D( mxClipPoly ) );
+
+ // apply sprite transformation also to clip!
+ aClipPath.transform( maTransform );
+
+ // clip which is about to be set, expressed as a
+ // b2drectangle
+ const ::basegfx::B2DRectangle& rClipBounds(
+ ::basegfx::tools::getRange( aClipPath ) );
+
+ const ::basegfx::B2DRectangle aBounds( 0.0, 0.0,
+ maSize.getX(),
+ maSize.getY() );
+
+ // rectangular area which is actually covered by the sprite.
+ // coordinates are relative to the sprite origin.
+ ::basegfx::B2DRectangle aSpriteRectPixel;
+ ::canvas::tools::calcTransformedRectBounds( aSpriteRectPixel,
+ aBounds,
+ maTransform );
+
+ // aClipBoundsA = new clip bound rect, intersected
+ // with sprite area
+ ::basegfx::B2DRectangle aClipBoundsA(rClipBounds);
+ aClipBoundsA.intersect( aSpriteRectPixel );
+
+ if( nNumClipPolygons != 1 )
+ {
+ // clip cannot be a single rectangle -> cannot
+ // optimize update
+ mbIsCurrClipRectangle = false;
+ maCurrClipBounds = aClipBoundsA;
+ }
+ else
+ {
+ // new clip could be a single rectangle - check
+ // that now:
+ const bool bNewClipIsRect(
+ ::basegfx::tools::isRectangle( aClipPath.getB2DPolygon(0) ) );
+
+ // both new and old clip are truly rectangles
+ // - can now take the optimized path
+ const bool bUseOptimizedUpdate( bNewClipIsRect &&
+ mbIsCurrClipRectangle );
+
+ const ::basegfx::B2DRectangle aOldBounds( maCurrClipBounds );
+
+ // store new current clip type
+ maCurrClipBounds = aClipBoundsA;
+ mbIsCurrClipRectangle = bNewClipIsRect;
+
+ if( mbActive &&
+ bUseOptimizedUpdate )
+ {
+ // aClipBoundsB = maCurrClipBounds, i.e. last
+ // clip, intersected with sprite area
+ typedef ::std::vector< ::basegfx::B2DRectangle > VectorOfRects;
+ VectorOfRects aClipDifferences;
+
+ // get all rectangles covered by exactly one
+ // of the polygons (aka XOR)
+ ::basegfx::computeSetDifference(aClipDifferences,
+ aClipBoundsA,
+ aOldBounds);
+
+ // aClipDifferences now contains the final
+ // update areas, coordinates are still relative
+ // to the sprite origin. before submitting
+ // this area to 'updateSprite()' we need to
+ // translate this area to the final position,
+ // coordinates need to be relative to the
+ // spritecanvas.
+ VectorOfRects::const_iterator aCurr( aClipDifferences.begin() );
+ const VectorOfRects::const_iterator aEnd( aClipDifferences.end() );
+ while( aCurr != aEnd )
+ {
+ mpSpriteCanvas->updateSprite(
+ rSprite,
+ maPosition,
+ ::basegfx::B2DRectangle(
+ maPosition + aCurr->getMinimum(),
+ maPosition + aCurr->getMaximum() ) );
+ ++aCurr;
+ }
+
+ // update calls all done
+ return true;
+ }
+ }
+ }
+
+ // caller needs to perform update calls
+ return false;
+ }
+
+ CanvasCustomSpriteHelper::CanvasCustomSpriteHelper() :
+ mpSpriteCanvas(),
+ maCurrClipBounds(),
+ maPosition(),
+ maSize(),
+ maTransform(),
+ mxClipPoly(),
+ mfPriority(0.0),
+ mfAlpha(0.0),
+ mbActive(false),
+ mbIsCurrClipRectangle(true),
+ mbIsContentFullyOpaque( false ),
+ mbAlphaDirty( true ),
+ mbPositionDirty( true ),
+ mbTransformDirty( true ),
+ mbClipDirty( true ),
+ mbPrioDirty( true ),
+ mbVisibilityDirty( true )
+ {
+ }
+
+ void CanvasCustomSpriteHelper::init( const geometry::RealSize2D& rSpriteSize,
+ const SpriteSurface::Reference& rOwningSpriteCanvas )
+ {
+ ENSURE_OR_THROW( rOwningSpriteCanvas.get(),
+ "CanvasCustomSpriteHelper::init(): Invalid owning sprite canvas" );
+
+ mpSpriteCanvas = rOwningSpriteCanvas;
+ maSize.setX( ::std::max( 1.0,
+ ceil( rSpriteSize.Width ) ) ); // round up to nearest int,
+ // enforce sprite to have at
+ // least (1,1) pixel size
+ maSize.setY( ::std::max( 1.0,
+ ceil( rSpriteSize.Height ) ) );
+ }
+
+ void CanvasCustomSpriteHelper::disposing()
+ {
+ mpSpriteCanvas.clear();
+ }
+
+ void CanvasCustomSpriteHelper::clearingContent( const Sprite::Reference& /*rSprite*/ )
+ {
+ // about to clear content to fully transparent
+ mbIsContentFullyOpaque = false;
+ }
+
+ void CanvasCustomSpriteHelper::checkDrawBitmap( const Sprite::Reference& rSprite,
+ const uno::Reference< rendering::XBitmap >& xBitmap,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ // check whether bitmap is non-alpha, and whether its
+ // transformed size covers the whole sprite.
+ if( !xBitmap->hasAlpha() )
+ {
+ const geometry::IntegerSize2D& rInputSize(
+ xBitmap->getSize() );
+ const ::basegfx::B2DSize& rOurSize(
+ rSprite->getSizePixel() );
+
+ ::basegfx::B2DHomMatrix aTransform;
+ if( tools::isInside(
+ ::basegfx::B2DRectangle( 0.0,0.0,
+ rOurSize.getX(),
+ rOurSize.getY() ),
+ ::basegfx::B2DRectangle( 0.0,0.0,
+ rInputSize.Width,
+ rInputSize.Height ),
+ ::canvas::tools::mergeViewAndRenderTransform(aTransform,
+ viewState,
+ renderState) ) )
+ {
+ // bitmap is opaque and will fully cover the sprite,
+ // set flag appropriately
+ mbIsContentFullyOpaque = true;
+ }
+ }
+ }
+
+ void CanvasCustomSpriteHelper::setAlpha( const Sprite::Reference& rSprite,
+ double alpha )
+ {
+ if( !mpSpriteCanvas.get() )
+ return; // we're disposed
+
+ if( alpha != mfAlpha )
+ {
+ mfAlpha = alpha;
+
+ if( mbActive )
+ {
+ mpSpriteCanvas->updateSprite( rSprite,
+ maPosition,
+ getUpdateArea() );
+ }
+
+ mbAlphaDirty = true;
+ }
+ }
+
+ void CanvasCustomSpriteHelper::move( const Sprite::Reference& rSprite,
+ const geometry::RealPoint2D& aNewPos,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ if( !mpSpriteCanvas.get() )
+ return; // we're disposed
+
+ ::basegfx::B2DHomMatrix aTransform;
+ ::canvas::tools::mergeViewAndRenderTransform(aTransform,
+ viewState,
+ renderState);
+
+ // convert position to device pixel
+ ::basegfx::B2DPoint aPoint(
+ ::basegfx::unotools::b2DPointFromRealPoint2D(aNewPos) );
+ aPoint *= aTransform;
+
+ if( aPoint != maPosition )
+ {
+ const ::basegfx::B2DRectangle& rBounds( getFullSpriteRect() );
+
+ if( mbActive )
+ {
+ mpSpriteCanvas->moveSprite( rSprite,
+ rBounds.getMinimum(),
+ rBounds.getMinimum() - maPosition + aPoint,
+ rBounds.getRange() );
+ }
+
+ maPosition = aPoint;
+ mbPositionDirty = true;
+ }
+ }
+
+ void CanvasCustomSpriteHelper::transform( const Sprite::Reference& rSprite,
+ const geometry::AffineMatrix2D& aTransformation )
+ {
+ ::basegfx::B2DHomMatrix aMatrix;
+ ::basegfx::unotools::homMatrixFromAffineMatrix(aMatrix,
+ aTransformation);
+
+ if( maTransform != aMatrix )
+ {
+ // retrieve bounds before and after transformation change.
+ const ::basegfx::B2DRectangle& rPrevBounds( getUpdateArea() );
+
+ maTransform = aMatrix;
+
+ if( !updateClipState( rSprite ) &&
+ mbActive )
+ {
+ mpSpriteCanvas->updateSprite( rSprite,
+ maPosition,
+ rPrevBounds );
+ mpSpriteCanvas->updateSprite( rSprite,
+ maPosition,
+ getUpdateArea() );
+ }
+
+ mbTransformDirty = true;
+ }
+ }
+
+ void CanvasCustomSpriteHelper::clip( const Sprite::Reference& rSprite,
+ const uno::Reference< rendering::XPolyPolygon2D >& xClip )
+ {
+ // NULL xClip explicitely allowed here (to clear clipping)
+
+ // retrieve bounds before and after clip change.
+ const ::basegfx::B2DRectangle& rPrevBounds( getUpdateArea() );
+
+ mxClipPoly = xClip;
+
+ if( !updateClipState( rSprite ) &&
+ mbActive )
+ {
+ mpSpriteCanvas->updateSprite( rSprite,
+ maPosition,
+ rPrevBounds );
+ mpSpriteCanvas->updateSprite( rSprite,
+ maPosition,
+ getUpdateArea() );
+ }
+
+ mbClipDirty = true;
+ }
+
+ void CanvasCustomSpriteHelper::setPriority( const Sprite::Reference& rSprite,
+ double nPriority )
+ {
+ if( !mpSpriteCanvas.get() )
+ return; // we're disposed
+
+ if( nPriority != mfPriority )
+ {
+ mfPriority = nPriority;
+
+ if( mbActive )
+ {
+ mpSpriteCanvas->updateSprite( rSprite,
+ maPosition,
+ getUpdateArea() );
+ }
+
+ mbPrioDirty = true;
+ }
+ }
+
+ void CanvasCustomSpriteHelper::show( const Sprite::Reference& rSprite )
+ {
+ if( !mpSpriteCanvas.get() )
+ return; // we're disposed
+
+ if( !mbActive )
+ {
+ mpSpriteCanvas->showSprite( rSprite );
+ mbActive = true;
+
+ // TODO(P1): if clip is the NULL clip (nothing visible),
+ // also save us the update call.
+
+ if( mfAlpha != 0.0 )
+ {
+ mpSpriteCanvas->updateSprite( rSprite,
+ maPosition,
+ getUpdateArea() );
+ }
+
+ mbVisibilityDirty = true;
+ }
+ }
+
+ void CanvasCustomSpriteHelper::hide( const Sprite::Reference& rSprite )
+ {
+ if( !mpSpriteCanvas.get() )
+ return; // we're disposed
+
+ if( mbActive )
+ {
+ mpSpriteCanvas->hideSprite( rSprite );
+ mbActive = false;
+
+ // TODO(P1): if clip is the NULL clip (nothing visible),
+ // also save us the update call.
+
+ if( mfAlpha != 0.0 )
+ {
+ mpSpriteCanvas->updateSprite( rSprite,
+ maPosition,
+ getUpdateArea() );
+ }
+
+ mbVisibilityDirty = true;
+ }
+ }
+
+ // Sprite interface
+ bool CanvasCustomSpriteHelper::isAreaUpdateOpaque( const ::basegfx::B2DRange& rUpdateArea ) const
+ {
+ if( !mbIsCurrClipRectangle ||
+ !mbIsContentFullyOpaque ||
+ !::rtl::math::approxEqual(mfAlpha, 1.0) )
+ {
+ // sprite either transparent, or clip rect does not
+ // represent exact bounds -> update might not be fully
+ // opaque
+ return false;
+ }
+ else
+ {
+ // make sure sprite rect fully covers update area -
+ // although the update area originates from the sprite,
+ // it's by no means guaranteed that it's limited to this
+ // sprite's update area - after all, other sprites might
+ // have been merged, or this sprite is moving.
+ return getUpdateArea().isInside( rUpdateArea );
+ }
+ }
+
+ ::basegfx::B2DPoint CanvasCustomSpriteHelper::getPosPixel() const
+ {
+ return maPosition;
+ }
+
+ ::basegfx::B2DVector CanvasCustomSpriteHelper::getSizePixel() const
+ {
+ return maSize;
+ }
+
+ ::basegfx::B2DRange CanvasCustomSpriteHelper::getUpdateArea( const ::basegfx::B2DRange& rBounds ) const
+ {
+ // Internal! Only call with locked object mutex!
+ ::basegfx::B2DHomMatrix aTransform( maTransform );
+ aTransform.translate( maPosition.getX(),
+ maPosition.getY() );
+
+ // transform bounds at origin, as the sprite transformation is
+ // formulated that way
+ ::basegfx::B2DRectangle aTransformedBounds;
+ return ::canvas::tools::calcTransformedRectBounds( aTransformedBounds,
+ rBounds,
+ aTransform );
+ }
+
+ ::basegfx::B2DRange CanvasCustomSpriteHelper::getUpdateArea() const
+ {
+ // Internal! Only call with locked object mutex!
+
+ // return effective sprite rect, i.e. take active clip into
+ // account
+ if( maCurrClipBounds.isEmpty() )
+ return getUpdateArea( ::basegfx::B2DRectangle( 0.0, 0.0,
+ maSize.getX(),
+ maSize.getY() ) );
+ else
+ return ::basegfx::B2DRectangle(
+ maPosition + maCurrClipBounds.getMinimum(),
+ maPosition + maCurrClipBounds.getMaximum() );
+ }
+
+ double CanvasCustomSpriteHelper::getPriority() const
+ {
+ return mfPriority;
+ }
+
+ ::basegfx::B2DRange CanvasCustomSpriteHelper::getFullSpriteRect() const
+ {
+ // Internal! Only call with locked object mutex!
+ return getUpdateArea( ::basegfx::B2DRectangle( 0.0, 0.0,
+ maSize.getX(),
+ maSize.getY() ) );
+ }
+}
diff --git a/canvas/source/tools/canvastools.cxx b/canvas/source/tools/canvastools.cxx
new file mode 100755
index 000000000000..ad833cc3ca40
--- /dev/null
+++ b/canvas/source/tools/canvastools.cxx
@@ -0,0 +1,1044 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <com/sun/star/geometry/AffineMatrix2D.hpp>
+#include <com/sun/star/geometry/Matrix2D.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/util/Endianness.hpp>
+#include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
+#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
+#include <com/sun/star/rendering/ColorSpaceType.hpp>
+#include <com/sun/star/rendering/ColorComponentTag.hpp>
+#include <com/sun/star/rendering/RenderingIntent.hpp>
+#include <com/sun/star/rendering/RenderState.hpp>
+#include <com/sun/star/rendering/ViewState.hpp>
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/rendering/XColorSpace.hpp>
+#include <com/sun/star/rendering/CompositeOperation.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/range/b2irange.hxx>
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/point/b2ipoint.hxx>
+#include <basegfx/vector/b2ivector.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+#include <cppuhelper/compbase1.hxx>
+#include <rtl/instance.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/window.hxx>
+#include <vcl/canvastools.hxx>
+
+#include <canvas/canvastools.hxx>
+
+#include <limits>
+
+
+using namespace ::com::sun::star;
+
+namespace com { namespace sun { namespace star { namespace rendering
+{
+ bool operator==( const RenderState& renderState1,
+ const RenderState& renderState2 )
+ {
+ if( renderState1.Clip != renderState2.Clip )
+ return false;
+
+ if( renderState1.DeviceColor != renderState2.DeviceColor )
+ return false;
+
+ if( renderState1.CompositeOperation != renderState2.CompositeOperation )
+ return false;
+
+ ::basegfx::B2DHomMatrix mat1, mat2;
+ ::canvas::tools::getRenderStateTransform( mat1, renderState1 );
+ ::canvas::tools::getRenderStateTransform( mat2, renderState2 );
+ if( mat1 != mat2 )
+ return false;
+
+ return true;
+ }
+
+ bool operator==( const ViewState& viewState1,
+ const ViewState& viewState2 )
+ {
+ if( viewState1.Clip != viewState2.Clip )
+ return false;
+
+ ::basegfx::B2DHomMatrix mat1, mat2;
+ ::canvas::tools::getViewStateTransform( mat1, viewState1 );
+ ::canvas::tools::getViewStateTransform( mat2, viewState2 );
+ if( mat1 != mat2 )
+ return false;
+
+ return true;
+ }
+}}}}
+
+namespace canvas
+{
+ namespace tools
+ {
+ geometry::RealSize2D createInfiniteSize2D()
+ {
+ return geometry::RealSize2D(
+ ::std::numeric_limits<double>::infinity(),
+ ::std::numeric_limits<double>::infinity() );
+ }
+
+ rendering::RenderState& initRenderState( rendering::RenderState& renderState )
+ {
+ // setup identity transform
+ setIdentityAffineMatrix2D( renderState.AffineTransform );
+ renderState.Clip = uno::Reference< rendering::XPolyPolygon2D >();
+ renderState.DeviceColor = uno::Sequence< double >();
+ renderState.CompositeOperation = rendering::CompositeOperation::OVER;
+
+ return renderState;
+ }
+
+ rendering::ViewState& initViewState( rendering::ViewState& viewState )
+ {
+ // setup identity transform
+ setIdentityAffineMatrix2D( viewState.AffineTransform );
+ viewState.Clip = uno::Reference< rendering::XPolyPolygon2D >();
+
+ return viewState;
+ }
+
+ ::basegfx::B2DHomMatrix& getViewStateTransform( ::basegfx::B2DHomMatrix& transform,
+ const rendering::ViewState& viewState )
+ {
+ return ::basegfx::unotools::homMatrixFromAffineMatrix( transform, viewState.AffineTransform );
+ }
+
+ rendering::ViewState& setViewStateTransform( rendering::ViewState& viewState,
+ const ::basegfx::B2DHomMatrix& transform )
+ {
+ ::basegfx::unotools::affineMatrixFromHomMatrix( viewState.AffineTransform, transform );
+
+ return viewState;
+ }
+
+ ::basegfx::B2DHomMatrix& getRenderStateTransform( ::basegfx::B2DHomMatrix& transform,
+ const rendering::RenderState& renderState )
+ {
+ return ::basegfx::unotools::homMatrixFromAffineMatrix( transform, renderState.AffineTransform );
+ }
+
+ rendering::RenderState& setRenderStateTransform( rendering::RenderState& renderState,
+ const ::basegfx::B2DHomMatrix& transform )
+ {
+ ::basegfx::unotools::affineMatrixFromHomMatrix( renderState.AffineTransform, transform );
+
+ return renderState;
+ }
+
+ rendering::RenderState& appendToRenderState( rendering::RenderState& renderState,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ ::basegfx::B2DHomMatrix transform;
+
+ getRenderStateTransform( transform, renderState );
+ return setRenderStateTransform( renderState, transform * rTransform );
+ }
+
+ rendering::ViewState& appendToViewState( rendering::ViewState& viewState,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ ::basegfx::B2DHomMatrix transform;
+
+ getViewStateTransform( transform, viewState );
+ return setViewStateTransform( viewState, transform * rTransform );
+ }
+
+ rendering::RenderState& prependToRenderState( rendering::RenderState& renderState,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ ::basegfx::B2DHomMatrix transform;
+
+ getRenderStateTransform( transform, renderState );
+ return setRenderStateTransform( renderState, rTransform * transform );
+ }
+
+ rendering::ViewState& prependToViewState( rendering::ViewState& viewState,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ ::basegfx::B2DHomMatrix transform;
+
+ getViewStateTransform( transform, viewState );
+ return setViewStateTransform( viewState, rTransform * transform );
+ }
+
+ ::basegfx::B2DHomMatrix& mergeViewAndRenderTransform( ::basegfx::B2DHomMatrix& combinedTransform,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ ::basegfx::B2DHomMatrix viewTransform;
+
+ ::basegfx::unotools::homMatrixFromAffineMatrix( combinedTransform, renderState.AffineTransform );
+ ::basegfx::unotools::homMatrixFromAffineMatrix( viewTransform, viewState.AffineTransform );
+
+ // this statement performs combinedTransform = viewTransform * combinedTransform
+ combinedTransform *= viewTransform;
+
+ return combinedTransform;
+ }
+
+ rendering::ViewState& mergeViewAndRenderState( rendering::ViewState& resultViewState,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const uno::Reference< rendering::XCanvas >& /*xCanvas*/ )
+ {
+ ::basegfx::B2DHomMatrix aTmpMatrix;
+ geometry::AffineMatrix2D convertedMatrix;
+
+ resultViewState.Clip = NULL; // TODO(F2): intersect clippings
+
+ return setViewStateTransform(
+ resultViewState,
+ mergeViewAndRenderTransform( aTmpMatrix,
+ viewState,
+ renderState ) );
+ }
+
+ geometry::AffineMatrix2D& setIdentityAffineMatrix2D( geometry::AffineMatrix2D& matrix )
+ {
+ matrix.m00 = 1.0;
+ matrix.m01 = 0.0;
+ matrix.m02 = 0.0;
+ matrix.m10 = 0.0;
+ matrix.m11 = 1.0;
+ matrix.m12 = 0.0;
+
+ return matrix;
+ }
+
+ geometry::Matrix2D& setIdentityMatrix2D( geometry::Matrix2D& matrix )
+ {
+ matrix.m00 = 1.0;
+ matrix.m01 = 0.0;
+ matrix.m10 = 0.0;
+ matrix.m11 = 1.0;
+
+ return matrix;
+ }
+
+ namespace
+ {
+ class StandardColorSpace : public cppu::WeakImplHelper1< com::sun::star::rendering::XIntegerBitmapColorSpace >
+ {
+ private:
+ uno::Sequence< sal_Int8 > maComponentTags;
+ uno::Sequence< sal_Int32 > maBitCounts;
+
+ virtual ::sal_Int8 SAL_CALL getType( ) throw (uno::RuntimeException)
+ {
+ return rendering::ColorSpaceType::RGB;
+ }
+ virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) throw (uno::RuntimeException)
+ {
+ return maComponentTags;
+ }
+ virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) throw (uno::RuntimeException)
+ {
+ return rendering::RenderingIntent::PERCEPTUAL;
+ }
+ virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) throw (uno::RuntimeException)
+ {
+ return uno::Sequence< beans::PropertyValue >();
+ }
+ virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
+ const uno::Reference< rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ // TODO(P3): if we know anything about target
+ // colorspace, this can be greatly sped up
+ uno::Sequence<rendering::ARGBColor> aIntermediate(
+ convertToARGB(deviceColor));
+ return targetColorSpace->convertFromARGB(aIntermediate);
+ }
+ virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const double* pIn( deviceColor.getConstArray() );
+ const sal_Size nLen( deviceColor.getLength() );
+ ENSURE_ARG_OR_THROW2(nLen%4==0,
+ "number of channels no multiple of 4",
+ static_cast<rendering::XColorSpace*>(this), 0);
+
+ uno::Sequence< rendering::RGBColor > aRes(nLen/4);
+ rendering::RGBColor* pOut( aRes.getArray() );
+ for( sal_Size i=0; i<nLen; i+=4 )
+ {
+ *pOut++ = rendering::RGBColor(pIn[0],pIn[1],pIn[2]);
+ pIn += 4;
+ }
+ return aRes;
+ }
+ virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const double* pIn( deviceColor.getConstArray() );
+ const sal_Size nLen( deviceColor.getLength() );
+ ENSURE_ARG_OR_THROW2(nLen%4==0,
+ "number of channels no multiple of 4",
+ static_cast<rendering::XColorSpace*>(this), 0);
+
+ uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
+ rendering::ARGBColor* pOut( aRes.getArray() );
+ for( sal_Size i=0; i<nLen; i+=4 )
+ {
+ *pOut++ = rendering::ARGBColor(pIn[3],pIn[0],pIn[1],pIn[2]);
+ pIn += 4;
+ }
+ return aRes;
+ }
+ virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const double* pIn( deviceColor.getConstArray() );
+ const sal_Size nLen( deviceColor.getLength() );
+ ENSURE_ARG_OR_THROW2(nLen%4==0,
+ "number of channels no multiple of 4",
+ static_cast<rendering::XColorSpace*>(this), 0);
+
+ uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
+ rendering::ARGBColor* pOut( aRes.getArray() );
+ for( sal_Size i=0; i<nLen; i+=4 )
+ {
+ *pOut++ = rendering::ARGBColor(pIn[3],pIn[3]*pIn[0],pIn[3]*pIn[1],pIn[3]*pIn[2]);
+ pIn += 4;
+ }
+ return aRes;
+ }
+ virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const rendering::RGBColor* pIn( rgbColor.getConstArray() );
+ const sal_Size nLen( rgbColor.getLength() );
+
+ uno::Sequence< double > aRes(nLen*4);
+ double* pColors=aRes.getArray();
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ *pColors++ = pIn->Red;
+ *pColors++ = pIn->Green;
+ *pColors++ = pIn->Blue;
+ *pColors++ = 1.0;
+ ++pIn;
+ }
+ return aRes;
+ }
+ virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
+ const sal_Size nLen( rgbColor.getLength() );
+
+ uno::Sequence< double > aRes(nLen*4);
+ double* pColors=aRes.getArray();
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ *pColors++ = pIn->Red;
+ *pColors++ = pIn->Green;
+ *pColors++ = pIn->Blue;
+ *pColors++ = pIn->Alpha;
+ ++pIn;
+ }
+ return aRes;
+ }
+ virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
+ const sal_Size nLen( rgbColor.getLength() );
+
+ uno::Sequence< double > aRes(nLen*4);
+ double* pColors=aRes.getArray();
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ *pColors++ = pIn->Red/pIn->Alpha;
+ *pColors++ = pIn->Green/pIn->Alpha;
+ *pColors++ = pIn->Blue/pIn->Alpha;
+ *pColors++ = pIn->Alpha;
+ ++pIn;
+ }
+ return aRes;
+ }
+
+ // XIntegerBitmapColorSpace
+ virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) throw (uno::RuntimeException)
+ {
+ return 32;
+ }
+ virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) throw (uno::RuntimeException)
+ {
+ return maBitCounts;
+ }
+ virtual ::sal_Int8 SAL_CALL getEndianness( ) throw (uno::RuntimeException)
+ {
+ return util::Endianness::LITTLE;
+ }
+ virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
+ const uno::Reference< rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ if( dynamic_cast<StandardColorSpace*>(targetColorSpace.get()) )
+ {
+ const sal_Int8* pIn( deviceColor.getConstArray() );
+ const sal_Size nLen( deviceColor.getLength() );
+ ENSURE_ARG_OR_THROW2(nLen%4==0,
+ "number of channels no multiple of 4",
+ static_cast<rendering::XColorSpace*>(this), 0);
+
+ uno::Sequence<double> aRes(nLen);
+ double* pOut( aRes.getArray() );
+ for( sal_Size i=0; i<nLen; i+=4 )
+ {
+ *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
+ *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
+ *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
+ *pOut++ = vcl::unotools::toDoubleColor(255-*pIn++);
+ }
+ return aRes;
+ }
+ else
+ {
+ // TODO(P3): if we know anything about target
+ // colorspace, this can be greatly sped up
+ uno::Sequence<rendering::ARGBColor> aIntermediate(
+ convertIntegerToARGB(deviceColor));
+ return targetColorSpace->convertFromARGB(aIntermediate);
+ }
+ }
+ virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
+ const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ if( dynamic_cast<StandardColorSpace*>(targetColorSpace.get()) )
+ {
+ // it's us, so simply pass-through the data
+ return deviceColor;
+ }
+ else
+ {
+ // TODO(P3): if we know anything about target
+ // colorspace, this can be greatly sped up
+ uno::Sequence<rendering::ARGBColor> aIntermediate(
+ convertIntegerToARGB(deviceColor));
+ return targetColorSpace->convertIntegerFromARGB(aIntermediate);
+ }
+ }
+ virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const sal_Int8* pIn( deviceColor.getConstArray() );
+ const sal_Size nLen( deviceColor.getLength() );
+ ENSURE_ARG_OR_THROW2(nLen%4==0,
+ "number of channels no multiple of 4",
+ static_cast<rendering::XColorSpace*>(this), 0);
+
+ uno::Sequence< rendering::RGBColor > aRes(nLen/4);
+ rendering::RGBColor* pOut( aRes.getArray() );
+ for( sal_Size i=0; i<nLen; i+=4 )
+ {
+ *pOut++ = rendering::RGBColor(
+ vcl::unotools::toDoubleColor(pIn[0]),
+ vcl::unotools::toDoubleColor(pIn[1]),
+ vcl::unotools::toDoubleColor(pIn[2]));
+ pIn += 4;
+ }
+ return aRes;
+ }
+
+ virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const sal_Int8* pIn( deviceColor.getConstArray() );
+ const sal_Size nLen( deviceColor.getLength() );
+ ENSURE_ARG_OR_THROW2(nLen%4==0,
+ "number of channels no multiple of 4",
+ static_cast<rendering::XColorSpace*>(this), 0);
+
+ uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
+ rendering::ARGBColor* pOut( aRes.getArray() );
+ for( sal_Size i=0; i<nLen; i+=4 )
+ {
+ *pOut++ = rendering::ARGBColor(
+ vcl::unotools::toDoubleColor(255-pIn[3]),
+ vcl::unotools::toDoubleColor(pIn[0]),
+ vcl::unotools::toDoubleColor(pIn[1]),
+ vcl::unotools::toDoubleColor(pIn[2]));
+ pIn += 4;
+ }
+ return aRes;
+ }
+
+ virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const sal_Int8* pIn( deviceColor.getConstArray() );
+ const sal_Size nLen( deviceColor.getLength() );
+ ENSURE_ARG_OR_THROW2(nLen%4==0,
+ "number of channels no multiple of 4",
+ static_cast<rendering::XColorSpace*>(this), 0);
+
+ uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
+ rendering::ARGBColor* pOut( aRes.getArray() );
+ for( sal_Size i=0; i<nLen; i+=4 )
+ {
+ const sal_Int8 nAlpha( 255-pIn[3] );
+ *pOut++ = rendering::ARGBColor(
+ vcl::unotools::toDoubleColor(nAlpha),
+ vcl::unotools::toDoubleColor(nAlpha*pIn[0]),
+ vcl::unotools::toDoubleColor(nAlpha*pIn[1]),
+ vcl::unotools::toDoubleColor(nAlpha*pIn[2]));
+ pIn += 4;
+ }
+ return aRes;
+ }
+
+ virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const rendering::RGBColor* pIn( rgbColor.getConstArray() );
+ const sal_Size nLen( rgbColor.getLength() );
+
+ uno::Sequence< sal_Int8 > aRes(nLen*4);
+ sal_Int8* pColors=aRes.getArray();
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ *pColors++ = vcl::unotools::toByteColor(pIn->Red);
+ *pColors++ = vcl::unotools::toByteColor(pIn->Green);
+ *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
+ *pColors++ = 0;
+ ++pIn;
+ }
+ return aRes;
+ }
+
+ virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
+ const sal_Size nLen( rgbColor.getLength() );
+
+ uno::Sequence< sal_Int8 > aRes(nLen*4);
+ sal_Int8* pColors=aRes.getArray();
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ *pColors++ = vcl::unotools::toByteColor(pIn->Red);
+ *pColors++ = vcl::unotools::toByteColor(pIn->Green);
+ *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
+ *pColors++ = 255-vcl::unotools::toByteColor(pIn->Alpha);
+ ++pIn;
+ }
+ return aRes;
+ }
+
+ virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
+ const sal_Size nLen( rgbColor.getLength() );
+
+ uno::Sequence< sal_Int8 > aRes(nLen*4);
+ sal_Int8* pColors=aRes.getArray();
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ *pColors++ = vcl::unotools::toByteColor(pIn->Red/pIn->Alpha);
+ *pColors++ = vcl::unotools::toByteColor(pIn->Green/pIn->Alpha);
+ *pColors++ = vcl::unotools::toByteColor(pIn->Blue/pIn->Alpha);
+ *pColors++ = 255-vcl::unotools::toByteColor(pIn->Alpha);
+ ++pIn;
+ }
+ return aRes;
+ }
+
+ public:
+ StandardColorSpace() :
+ maComponentTags(4),
+ maBitCounts(4)
+ {
+ sal_Int8* pTags = maComponentTags.getArray();
+ sal_Int32* pBitCounts = maBitCounts.getArray();
+ pTags[0] = rendering::ColorComponentTag::RGB_RED;
+ pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
+ pTags[2] = rendering::ColorComponentTag::RGB_BLUE;
+ pTags[3] = rendering::ColorComponentTag::ALPHA;
+
+ pBitCounts[0] =
+ pBitCounts[1] =
+ pBitCounts[2] =
+ pBitCounts[3] = 8;
+ }
+ };
+
+ struct StandardColorSpaceHolder : public rtl::StaticWithInit<uno::Reference<rendering::XIntegerBitmapColorSpace>,
+ StandardColorSpaceHolder>
+ {
+ uno::Reference<rendering::XIntegerBitmapColorSpace> operator()()
+ {
+ return new StandardColorSpace();
+ }
+ };
+ }
+
+ uno::Reference<rendering::XIntegerBitmapColorSpace> getStdColorSpace()
+ {
+ return StandardColorSpaceHolder::get();
+ }
+
+ rendering::IntegerBitmapLayout getStdMemoryLayout( const geometry::IntegerSize2D& rBmpSize )
+ {
+ rendering::IntegerBitmapLayout aLayout;
+
+ aLayout.ScanLines = rBmpSize.Height;
+ aLayout.ScanLineBytes = rBmpSize.Width*4;
+ aLayout.ScanLineStride = aLayout.ScanLineBytes;
+ aLayout.PlaneStride = 0;
+ aLayout.ColorSpace = getStdColorSpace();
+ aLayout.Palette.clear();
+ aLayout.IsMsbFirst = sal_False;
+
+ return aLayout;
+ }
+
+ ::Color stdIntSequenceToColor( const uno::Sequence<sal_Int8>& rColor )
+ {
+#ifdef OSL_BIGENDIAN
+ const sal_Int8* pCols( rColor.getConstArray() );
+ return ::Color( pCols[3], pCols[0], pCols[1], pCols[2] );
+#else
+ return ::Color( *reinterpret_cast< const ::ColorData* >(rColor.getConstArray()) );
+#endif
+ }
+
+ uno::Sequence<sal_Int8> colorToStdIntSequence( const ::Color& rColor )
+ {
+ uno::Sequence<sal_Int8> aRet(4);
+ sal_Int8* pCols( aRet.getArray() );
+#ifdef OSL_BIGENDIAN
+ pCols[0] = rColor.GetRed();
+ pCols[1] = rColor.GetGreen();
+ pCols[2] = rColor.GetBlue();
+ pCols[3] = 255-rColor.GetTransparency();
+#else
+ *reinterpret_cast<sal_Int32*>(pCols) = rColor.GetColor();
+#endif
+ return aRet;
+ }
+
+ // Create a corrected view transformation out of the give one,
+ // which ensures that the rectangle given by (0,0) and
+ // rSpriteSize is mapped with its left,top corner to (0,0)
+ // again. This is required to properly render sprite
+ // animations to buffer bitmaps.
+ ::basegfx::B2DHomMatrix& calcRectToOriginTransform( ::basegfx::B2DHomMatrix& o_transform,
+ const ::basegfx::B2DRange& i_srcRect,
+ const ::basegfx::B2DHomMatrix& i_transformation )
+ {
+ if( i_srcRect.isEmpty() )
+ return o_transform=i_transformation;
+
+ // transform by given transformation
+ ::basegfx::B2DRectangle aTransformedRect;
+
+ calcTransformedRectBounds( aTransformedRect,
+ i_srcRect,
+ i_transformation );
+
+ // now move resulting left,top point of bounds to (0,0)
+ const basegfx::B2DHomMatrix aCorrectedTransform(basegfx::tools::createTranslateB2DHomMatrix(
+ -aTransformedRect.getMinX(), -aTransformedRect.getMinY()));
+
+ // prepend to original transformation
+ o_transform = aCorrectedTransform * i_transformation;
+
+ return o_transform;
+ }
+
+ ::basegfx::B2DRange& calcTransformedRectBounds( ::basegfx::B2DRange& outRect,
+ const ::basegfx::B2DRange& inRect,
+ const ::basegfx::B2DHomMatrix& transformation )
+ {
+ outRect.reset();
+
+ if( inRect.isEmpty() )
+ return outRect;
+
+ // transform all four extremal points of the rectangle,
+ // take bounding rect of those.
+
+ // transform left-top point
+ outRect.expand( transformation * inRect.getMinimum() );
+
+ // transform bottom-right point
+ outRect.expand( transformation * inRect.getMaximum() );
+
+ ::basegfx::B2DPoint aPoint;
+
+ // transform top-right point
+ aPoint.setX( inRect.getMaxX() );
+ aPoint.setY( inRect.getMinY() );
+
+ aPoint *= transformation;
+ outRect.expand( aPoint );
+
+ // transform bottom-left point
+ aPoint.setX( inRect.getMinX() );
+ aPoint.setY( inRect.getMaxY() );
+
+ aPoint *= transformation;
+ outRect.expand( aPoint );
+
+ // over and out.
+ return outRect;
+ }
+
+ ::basegfx::B2DHomMatrix& calcRectToRectTransform( ::basegfx::B2DHomMatrix& o_transform,
+ const ::basegfx::B2DRange& destRect,
+ const ::basegfx::B2DRange& srcRect,
+ const ::basegfx::B2DHomMatrix& transformation )
+ {
+ if( srcRect.isEmpty() ||
+ destRect.isEmpty() )
+ {
+ return o_transform=transformation;
+ }
+
+ // transform inputRect by transformation
+ ::basegfx::B2DRectangle aTransformedRect;
+ calcTransformedRectBounds( aTransformedRect,
+ srcRect,
+ transformation );
+
+ // now move resulting left,top point of bounds to (0,0)
+ basegfx::B2DHomMatrix aCorrectedTransform(basegfx::tools::createTranslateB2DHomMatrix(
+ -aTransformedRect.getMinX(), -aTransformedRect.getMinY()));
+
+ // scale to match outRect
+ const double xDenom( aTransformedRect.getWidth() );
+ const double yDenom( aTransformedRect.getHeight() );
+ if( xDenom != 0.0 && yDenom != 0.0 )
+ aCorrectedTransform.scale( destRect.getWidth() / xDenom,
+ destRect.getHeight() / yDenom );
+ // TODO(E2): error handling
+
+ // translate to final position
+ aCorrectedTransform.translate( destRect.getMinX(),
+ destRect.getMinY() );
+
+ ::basegfx::B2DHomMatrix transform( transformation );
+ o_transform = aCorrectedTransform * transform;
+
+ return o_transform;
+ }
+
+ bool isInside( const ::basegfx::B2DRange& rContainedRect,
+ const ::basegfx::B2DRange& rTransformRect,
+ const ::basegfx::B2DHomMatrix& rTransformation )
+ {
+ if( rContainedRect.isEmpty() || rTransformRect.isEmpty() )
+ return false;
+
+ ::basegfx::B2DPolygon aPoly(
+ ::basegfx::tools::createPolygonFromRect( rTransformRect ) );
+ aPoly.transform( rTransformation );
+
+ return ::basegfx::tools::isInside( aPoly,
+ ::basegfx::tools::createPolygonFromRect(
+ rContainedRect ),
+ true );
+ }
+
+ namespace
+ {
+ bool clipAreaImpl( ::basegfx::B2IRange* o_pDestArea,
+ ::basegfx::B2IRange& io_rSourceArea,
+ ::basegfx::B2IPoint& io_rDestPoint,
+ const ::basegfx::B2IRange& rSourceBounds,
+ const ::basegfx::B2IRange& rDestBounds )
+ {
+ const ::basegfx::B2IPoint aSourceTopLeft(
+ io_rSourceArea.getMinimum() );
+
+ ::basegfx::B2IRange aLocalSourceArea( io_rSourceArea );
+
+ // clip source area (which must be inside rSourceBounds)
+ aLocalSourceArea.intersect( rSourceBounds );
+
+ if( aLocalSourceArea.isEmpty() )
+ return false;
+
+ // calc relative new source area points (relative to orig
+ // source area)
+ const ::basegfx::B2IVector aUpperLeftOffset(
+ aLocalSourceArea.getMinimum()-aSourceTopLeft );
+ const ::basegfx::B2IVector aLowerRightOffset(
+ aLocalSourceArea.getMaximum()-aSourceTopLeft );
+
+ ::basegfx::B2IRange aLocalDestArea( io_rDestPoint + aUpperLeftOffset,
+ io_rDestPoint + aLowerRightOffset );
+
+ // clip dest area (which must be inside rDestBounds)
+ aLocalDestArea.intersect( rDestBounds );
+
+ if( aLocalDestArea.isEmpty() )
+ return false;
+
+ // calc relative new dest area points (relative to orig
+ // source area)
+ const ::basegfx::B2IVector aDestUpperLeftOffset(
+ aLocalDestArea.getMinimum()-io_rDestPoint );
+ const ::basegfx::B2IVector aDestLowerRightOffset(
+ aLocalDestArea.getMaximum()-io_rDestPoint );
+
+ io_rSourceArea = ::basegfx::B2IRange( aSourceTopLeft + aDestUpperLeftOffset,
+ aSourceTopLeft + aDestLowerRightOffset );
+ io_rDestPoint = aLocalDestArea.getMinimum();
+
+ if( o_pDestArea )
+ *o_pDestArea = aLocalDestArea;
+
+ return true;
+ }
+ }
+
+ bool clipScrollArea( ::basegfx::B2IRange& io_rSourceArea,
+ ::basegfx::B2IPoint& io_rDestPoint,
+ ::std::vector< ::basegfx::B2IRange >& o_ClippedAreas,
+ const ::basegfx::B2IRange& rBounds )
+ {
+ ::basegfx::B2IRange aResultingDestArea;
+
+ // compute full destination area (to determine uninitialized
+ // areas below)
+ const ::basegfx::B2I64Tuple& rRange( io_rSourceArea.getRange() );
+ ::basegfx::B2IRange aInputDestArea( io_rDestPoint.getX(),
+ io_rDestPoint.getY(),
+ (io_rDestPoint.getX()
+ + static_cast<sal_Int32>(rRange.getX())),
+ (io_rDestPoint.getY()
+ + static_cast<sal_Int32>(rRange.getY())) );
+ // limit to output area (no point updating outside of it)
+ aInputDestArea.intersect( rBounds );
+
+ // clip to rBounds
+ if( !clipAreaImpl( &aResultingDestArea,
+ io_rSourceArea,
+ io_rDestPoint,
+ rBounds,
+ rBounds ) )
+ return false;
+
+ // finally, compute all areas clipped off the total
+ // destination area.
+ ::basegfx::computeSetDifference( o_ClippedAreas,
+ aInputDestArea,
+ aResultingDestArea );
+
+ return true;
+ }
+
+ bool clipBlit( ::basegfx::B2IRange& io_rSourceArea,
+ ::basegfx::B2IPoint& io_rDestPoint,
+ const ::basegfx::B2IRange& rSourceBounds,
+ const ::basegfx::B2IRange& rDestBounds )
+ {
+ return clipAreaImpl( NULL,
+ io_rSourceArea,
+ io_rDestPoint,
+ rSourceBounds,
+ rDestBounds );
+ }
+
+ ::basegfx::B2IRange spritePixelAreaFromB2DRange( const ::basegfx::B2DRange& rRange )
+ {
+ if( rRange.isEmpty() )
+ return ::basegfx::B2IRange();
+
+ const ::basegfx::B2IPoint aTopLeft( ::basegfx::fround( rRange.getMinX() ),
+ ::basegfx::fround( rRange.getMinY() ) );
+ return ::basegfx::B2IRange( aTopLeft,
+ aTopLeft + ::basegfx::B2IPoint(
+ ::basegfx::fround( rRange.getWidth() ),
+ ::basegfx::fround( rRange.getHeight() ) ) );
+ }
+
+ uno::Sequence< uno::Any >& getDeviceInfo( const uno::Reference< rendering::XCanvas >& i_rxCanvas,
+ uno::Sequence< uno::Any >& o_rxParams )
+ {
+ o_rxParams.realloc( 0 );
+
+ if( i_rxCanvas.is() )
+ {
+ try
+ {
+ uno::Reference< rendering::XGraphicDevice > xDevice( i_rxCanvas->getDevice(),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference< lang::XServiceInfo > xServiceInfo( xDevice,
+ uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xPropSet( xDevice,
+ uno::UNO_QUERY_THROW );
+
+ o_rxParams.realloc( 2 );
+
+ o_rxParams[ 0 ] = uno::makeAny( xServiceInfo->getImplementationName() );
+ o_rxParams[ 1 ] = uno::makeAny( xPropSet->getPropertyValue(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DeviceHandle") ) ) );
+ }
+ catch( uno::Exception& )
+ {
+ // ignore, but return empty sequence
+ }
+ }
+
+ return o_rxParams;
+ }
+
+ awt::Rectangle getAbsoluteWindowRect( const awt::Rectangle& rRect,
+ const uno::Reference< awt::XWindow2 >& xWin )
+ {
+ awt::Rectangle aRetVal( rRect );
+
+ ::Window* pWindow = VCLUnoHelper::GetWindow(xWin);
+ if( pWindow )
+ {
+ ::Point aPoint( aRetVal.X,
+ aRetVal.Y );
+
+ aPoint = pWindow->OutputToScreenPixel( aPoint );
+
+ aRetVal.X = aPoint.X();
+ aRetVal.Y = aPoint.Y();
+ }
+
+ return aRetVal;
+ }
+
+ ::basegfx::B2DPolyPolygon getBoundMarksPolyPolygon( const ::basegfx::B2DRange& rRange )
+ {
+ ::basegfx::B2DPolyPolygon aPolyPoly;
+ ::basegfx::B2DPolygon aPoly;
+
+ const double nX0( rRange.getMinX() );
+ const double nY0( rRange.getMinY() );
+ const double nX1( rRange.getMaxX() );
+ const double nY1( rRange.getMaxY() );
+
+ aPoly.append( ::basegfx::B2DPoint( nX0+4,
+ nY0 ) );
+ aPoly.append( ::basegfx::B2DPoint( nX0,
+ nY0 ) );
+ aPoly.append( ::basegfx::B2DPoint( nX0,
+ nY0+4 ) );
+ aPolyPoly.append( aPoly ); aPoly.clear();
+
+ aPoly.append( ::basegfx::B2DPoint( nX1-4,
+ nY0 ) );
+ aPoly.append( ::basegfx::B2DPoint( nX1,
+ nY0 ) );
+ aPoly.append( ::basegfx::B2DPoint( nX1,
+ nY0+4 ) );
+ aPolyPoly.append( aPoly ); aPoly.clear();
+
+ aPoly.append( ::basegfx::B2DPoint( nX0+4,
+ nY1 ) );
+ aPoly.append( ::basegfx::B2DPoint( nX0,
+ nY1 ) );
+ aPoly.append( ::basegfx::B2DPoint( nX0,
+ nY1-4 ) );
+ aPolyPoly.append( aPoly ); aPoly.clear();
+
+ aPoly.append( ::basegfx::B2DPoint( nX1-4,
+ nY1 ) );
+ aPoly.append( ::basegfx::B2DPoint( nX1,
+ nY1 ) );
+ aPoly.append( ::basegfx::B2DPoint( nX1,
+ nY1-4 ) );
+ aPolyPoly.append( aPoly );
+
+ return aPolyPoly;
+ }
+
+ int calcGradientStepCount( ::basegfx::B2DHomMatrix& rTotalTransform,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const rendering::Texture& texture,
+ int nColorSteps )
+ {
+ // calculate overall texture transformation (directly from
+ // texture to device space).
+ ::basegfx::B2DHomMatrix aMatrix;
+
+ rTotalTransform.identity();
+ ::basegfx::unotools::homMatrixFromAffineMatrix( rTotalTransform,
+ texture.AffineTransform );
+ ::canvas::tools::mergeViewAndRenderTransform(aMatrix,
+ viewState,
+ renderState);
+ rTotalTransform *= aMatrix; // prepend total view/render transformation
+
+ // determine size of gradient in device coordinate system
+ // (to e.g. determine sensible number of gradient steps)
+ ::basegfx::B2DPoint aLeftTop( 0.0, 0.0 );
+ ::basegfx::B2DPoint aLeftBottom( 0.0, 1.0 );
+ ::basegfx::B2DPoint aRightTop( 1.0, 0.0 );
+ ::basegfx::B2DPoint aRightBottom( 1.0, 1.0 );
+
+ aLeftTop *= rTotalTransform;
+ aLeftBottom *= rTotalTransform;
+ aRightTop *= rTotalTransform;
+ aRightBottom*= rTotalTransform;
+
+ // longest line in gradient bound rect
+ const int nGradientSize(
+ static_cast<int>(
+ ::std::max(
+ ::basegfx::B2DVector(aRightBottom-aLeftTop).getLength(),
+ ::basegfx::B2DVector(aRightTop-aLeftBottom).getLength() ) + 1.0 ) );
+
+ // typical number for pixel of the same color (strip size)
+ const int nStripSize( nGradientSize < 50 ? 2 : 4 );
+
+ // use at least three steps, and at utmost the number of color
+ // steps
+ return ::std::max( 3,
+ ::std::min(
+ nGradientSize / nStripSize,
+ nColorSteps ) );
+ }
+
+ } // namespace tools
+
+} // namespace canvas
diff --git a/canvas/source/tools/canvastools.flt b/canvas/source/tools/canvastools.flt
new file mode 100644
index 000000000000..a230939309da
--- /dev/null
+++ b/canvas/source/tools/canvastools.flt
@@ -0,0 +1,4 @@
+__CT
+__real
+internal
+agg \ No newline at end of file
diff --git a/canvas/source/tools/elapsedtime.cxx b/canvas/source/tools/elapsedtime.cxx
new file mode 100644
index 000000000000..6ca58a2bf1ee
--- /dev/null
+++ b/canvas/source/tools/elapsedtime.cxx
@@ -0,0 +1,224 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include "osl/time.h"
+#include "osl/diagnose.h"
+#include "canvas/elapsedtime.hxx"
+
+#if defined(WIN) || defined(WNT)
+
+#if defined _MSC_VER
+#pragma warning(push,1)
+#endif
+
+// TEMP!!!
+// Awaiting corresponding functionality in OSL
+//
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winbase.h>
+#include <mmsystem.h>
+#endif
+
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include <algorithm>
+#include <limits>
+
+namespace canvas {
+namespace tools {
+
+
+#if defined(WIN) || defined(WNT)
+// TODO(Q2): is 0 okay for the failure case here?
+double ElapsedTime::getSystemTime()
+{
+ // TEMP!!!
+ // Awaiting corresponding functionality in OSL
+ //
+
+ // is there a performance counter available?
+ static bool bTimeSetupDone( false );
+ static bool bPerfTimerAvailable( false );
+ static LONGLONG nPerfCountFreq;
+
+ // TODO(F1): This _might_ cause problems, as it prevents correct
+ // time handling for very long lifetimes of this class's
+ // surrounding component in memory. When the difference between
+ // current sys time and nInitialCount exceeds IEEE double's
+ // mantissa, time will start to run jerky.
+ static LONGLONG nInitialCount;
+
+ if( !bTimeSetupDone )
+ {
+ if( QueryPerformanceFrequency(
+ reinterpret_cast<LARGE_INTEGER *>(&nPerfCountFreq) ) )
+ {
+ // read initial time:
+ QueryPerformanceCounter(
+ reinterpret_cast<LARGE_INTEGER *>(&nInitialCount) );
+ bPerfTimerAvailable = true;
+ }
+ bTimeSetupDone = true;
+ }
+
+ if( bPerfTimerAvailable )
+ {
+ LONGLONG nCurrCount;
+ QueryPerformanceCounter(
+ reinterpret_cast<LARGE_INTEGER *>(&nCurrCount) );
+ nCurrCount -= nInitialCount;
+ return double(nCurrCount) / nPerfCountFreq;
+ }
+ else
+ {
+ LONGLONG nCurrTime = timeGetTime();
+ return double(nCurrTime) / 1000.0;
+ }
+}
+
+#else // ! WNT
+
+// TODO(Q2): is 0 okay for the failure case here?
+double ElapsedTime::getSystemTime()
+{
+ TimeValue aTimeVal;
+ if( osl_getSystemTime( &aTimeVal ) )
+ return ((aTimeVal.Nanosec * 10e-10) + aTimeVal.Seconds);
+ else
+ return 0.0;
+}
+
+#endif
+
+ElapsedTime::ElapsedTime()
+ : m_pTimeBase(),
+ m_fLastQueriedTime( 0.0 ),
+ m_fStartTime( getSystemTime() ),
+ m_fFrozenTime( 0.0 ),
+ m_bInPauseMode( false ),
+ m_bInHoldMode( false )
+{
+}
+
+ElapsedTime::ElapsedTime(
+ boost::shared_ptr<ElapsedTime> const & pTimeBase )
+ : m_pTimeBase( pTimeBase ),
+ m_fLastQueriedTime( 0.0 ),
+ m_fStartTime( getCurrentTime() ),
+ m_fFrozenTime( 0.0 ),
+ m_bInPauseMode( false ),
+ m_bInHoldMode( false )
+{
+}
+
+boost::shared_ptr<ElapsedTime> const & ElapsedTime::getTimeBase() const
+{
+ return m_pTimeBase;
+}
+
+void ElapsedTime::reset()
+{
+ m_fLastQueriedTime = 0.0;
+ m_fStartTime = getCurrentTime();
+ m_fFrozenTime = 0.0;
+ m_bInPauseMode = false;
+ m_bInHoldMode = false;
+}
+
+void ElapsedTime::adjustTimer( double fOffset, bool /*bLimitToLastQueriedTime*/ )
+{
+ // to make getElapsedTime() become _larger_, have to reduce
+ // m_fStartTime.
+ m_fStartTime -= fOffset;
+
+ // also adjust frozen time, this method must _always_ affect the
+ // value returned by getElapsedTime()!
+ if (m_bInHoldMode || m_bInPauseMode)
+ m_fFrozenTime += fOffset;
+}
+
+double ElapsedTime::getCurrentTime() const
+{
+ return m_pTimeBase.get() == 0
+ ? getSystemTime() : m_pTimeBase->getElapsedTimeImpl();
+}
+
+double ElapsedTime::getElapsedTime() const
+{
+ m_fLastQueriedTime = getElapsedTimeImpl();
+ return m_fLastQueriedTime;
+}
+
+double ElapsedTime::getElapsedTimeImpl() const
+{
+ if (m_bInHoldMode || m_bInPauseMode)
+ return m_fFrozenTime;
+
+ return getCurrentTime() - m_fStartTime;
+}
+
+void ElapsedTime::pauseTimer()
+{
+ m_fFrozenTime = getElapsedTimeImpl();
+ m_bInPauseMode = true;
+}
+
+void ElapsedTime::continueTimer()
+{
+ m_bInPauseMode = false;
+
+ // stop pausing, time runs again. Note that
+ // getElapsedTimeImpl() honors hold mode, i.e. a
+ // continueTimer() in hold mode will preserve the latter
+ const double fPauseDuration( getElapsedTimeImpl() - m_fFrozenTime );
+
+ // adjust start time, such that subsequent getElapsedTime() calls
+ // will virtually start from m_fFrozenTime.
+ m_fStartTime += fPauseDuration;
+}
+
+void ElapsedTime::holdTimer()
+{
+ // when called during hold mode (e.g. more than once per time
+ // object), the original hold time will be maintained.
+ m_fFrozenTime = getElapsedTimeImpl();
+ m_bInHoldMode = true;
+}
+
+void ElapsedTime::releaseTimer()
+{
+ m_bInHoldMode = false;
+}
+
+} // namespace tools
+} // namespace canvas
diff --git a/canvas/source/tools/image.cxx b/canvas/source/tools/image.cxx
new file mode 100644
index 000000000000..b6183e463e99
--- /dev/null
+++ b/canvas/source/tools/image.cxx
@@ -0,0 +1,2394 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <canvas/canvastools.hxx>
+#include <canvas/parametricpolypolygon.hxx>
+
+#include <com/sun/star/rendering/RepaintResult.hpp>
+#include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
+
+#include <vcl/canvastools.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/bmpacc.hxx>
+
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
+#include <basegfx/polygon/b2dpolygontriangulator.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+
+#include "image.hxx"
+
+#define CANVAS_IMAGE_CXX
+#include "image_sysprereq.h"
+
+//////////////////////////////////////////////////////////////////////////////////
+// platform-dependend includes [wrapped into their own namepsaces]
+//////////////////////////////////////////////////////////////////////////////////
+
+#if defined(WNT)
+# if defined _MSC_VER
+# pragma warning(push,1)
+# endif
+
+ namespace win32
+ {
+ #undef DECLARE_HANDLE
+ #undef WB_LEFT
+ #undef WB_RIGHT
+ #undef APIENTRY
+ #define WIN32_LEAN_AND_MEAN
+ #define NOMINMAX
+ #include <windows.h>
+ }
+
+# if defined _MSC_VER
+# pragma warning(pop)
+# endif
+#elif defined(OS2)
+ namespace os2
+ {
+ #include <svpm.h>
+ }
+#else
+#if !defined(QUARTZ)
+ namespace unx
+ {
+ #include <X11/Xlib.h>
+ }
+#endif
+#endif
+
+#include <algorithm>
+
+using namespace ::com::sun::star;
+
+namespace canvas { namespace
+{
+ //////////////////////////////////////////////////////////////////////////////////
+ // TransAffineFromAffineMatrix
+ //////////////////////////////////////////////////////////////////////////////////
+
+ ::agg::trans_affine transAffineFromAffineMatrix( const geometry::AffineMatrix2D& m )
+ {
+ return agg::trans_affine(m.m00,
+ m.m10,
+ m.m01,
+ m.m11,
+ m.m02,
+ m.m12);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // TransAffineFromB2DHomMatrix
+ //////////////////////////////////////////////////////////////////////////////////
+
+ ::agg::trans_affine transAffineFromB2DHomMatrix( const ::basegfx::B2DHomMatrix& m )
+ {
+ return agg::trans_affine(m.get(0,0),
+ m.get(1,0),
+ m.get(0,1),
+ m.get(1,1),
+ m.get(0,2),
+ m.get(1,2));
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // ARGB
+ //////////////////////////////////////////////////////////////////////////////////
+
+ struct ARGBColor
+ {
+ sal_uInt8 a;
+ sal_uInt8 r;
+ sal_uInt8 g;
+ sal_uInt8 b;
+ };
+
+ /// ARGB color
+ union ARGB
+ {
+ ARGBColor Color;
+ sal_uInt32 color;
+
+ ARGB() :
+ color(0)
+ {
+ }
+
+ explicit ARGB( sal_uInt32 _color ) :
+ color(_color)
+ {
+ }
+
+ ARGB( sal_uInt8 _a,
+ sal_uInt8 _r,
+ sal_uInt8 _g,
+ sal_uInt8 _b )
+ {
+ Color.a = _a;
+ Color.r = _r;
+ Color.g = _g;
+ Color.b = _b;
+ }
+
+ ARGB( sal_uInt32 default_color,
+ const ::com::sun::star::uno::Sequence< double >& sequence ) :
+ color(default_color)
+ {
+ if(sequence.getLength() > 2)
+ {
+ Color.r = static_cast<sal_uInt8>(255.0f*sequence[0]);
+ Color.g = static_cast<sal_uInt8>(255.0f*sequence[1]);
+ Color.b = static_cast<sal_uInt8>(255.0f*sequence[2]);
+ if(sequence.getLength() > 3)
+ Color.a = static_cast<sal_uInt8>(255.0f*sequence[3]);
+ }
+ }
+
+ ARGB( const ARGB& rhs ) :
+ color( rhs.color )
+ {
+ }
+
+ ARGB &operator=( const ARGB &rhs )
+ {
+ color=rhs.color;
+ return *this;
+ }
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // setupState
+ //////////////////////////////////////////////////////////////////////////////////
+
+ /// Calc common output state from XCanvas parameters
+ void setupState( ::basegfx::B2DHomMatrix& o_rViewTransform,
+ ::basegfx::B2DHomMatrix& o_rRenderTransform,
+ ::std::auto_ptr< ::basegfx::B2DPolyPolygon >& o_rViewClip,
+ ::std::auto_ptr< ::basegfx::B2DPolyPolygon >& o_rRenderClip,
+ ARGB& o_rRenderColor,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ ::basegfx::unotools::homMatrixFromAffineMatrix(o_rRenderTransform,
+ renderState.AffineTransform);
+ ::basegfx::unotools::homMatrixFromAffineMatrix(o_rViewTransform,
+ viewState.AffineTransform);
+
+ o_rRenderColor = ARGB(0xFFFFFFFF,
+ renderState.DeviceColor);
+
+ // TODO(F3): handle compositing modes
+
+ if( viewState.Clip.is() )
+ {
+ ::basegfx::B2DPolyPolygon aViewClip(
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( viewState.Clip ));
+
+ if(aViewClip.areControlPointsUsed())
+ aViewClip = ::basegfx::tools::adaptiveSubdivideByAngle(aViewClip);
+
+ o_rViewClip.reset( new ::basegfx::B2DPolyPolygon( aViewClip ) );
+ }
+
+ if( renderState.Clip.is() )
+ {
+ ::basegfx::B2DPolyPolygon aRenderClip(
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( viewState.Clip ) );
+
+ if(aRenderClip.areControlPointsUsed())
+ aRenderClip = ::basegfx::tools::adaptiveSubdivideByAngle(aRenderClip);
+
+ o_rRenderClip.reset( new ::basegfx::B2DPolyPolygon( aRenderClip ) );
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // clipAndTransformPolygon
+ //////////////////////////////////////////////////////////////////////////////////
+
+ /** Clip and transform given polygon
+
+ @param io_rClippee
+ Polygon to clip
+
+ @param bIsFilledPolyPolygon
+ When true, the polygon is clipped as if it was to be rendered
+ with fill, when false, the polygon is clipped as if it was to
+ be rendered with stroking.
+ */
+ void clipAndTransformPolygon( ::basegfx::B2DPolyPolygon& io_rClippee,
+ bool bIsFilledPolyPolygon,
+ const ::basegfx::B2DHomMatrix& rViewTransform,
+ const ::basegfx::B2DHomMatrix& rRenderTransform,
+ const ::basegfx::B2DPolyPolygon* pViewClip,
+ const ::basegfx::B2DPolyPolygon* pRenderClip )
+ {
+ ::basegfx::B2DPolyPolygon aPolyPolygon(io_rClippee);
+ io_rClippee.clear();
+
+ // clip contour against renderclip
+ if( pRenderClip )
+ {
+ // AW: Simplified
+ aPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
+ aPolyPolygon, *pRenderClip, true, !bIsFilledPolyPolygon);
+ }
+
+ if( !aPolyPolygon.count() )
+ return;
+
+ // transform result into view space
+ aPolyPolygon.transform(rRenderTransform);
+
+ // clip contour against viewclip
+ if( pViewClip )
+ {
+ // AW: Simplified
+ aPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
+ aPolyPolygon, *pViewClip, true, !bIsFilledPolyPolygon);
+ }
+
+ if(!(aPolyPolygon.count()))
+ return;
+
+ // transform result into device space
+ aPolyPolygon.transform(rViewTransform);
+
+ io_rClippee = aPolyPolygon;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // setupPolyPolygon
+ //////////////////////////////////////////////////////////////////////////////////
+
+ void setupPolyPolygon( ::basegfx::B2DPolyPolygon& io_rClippee,
+ bool bIsFilledPolyPolygon,
+ ARGB& o_rRenderColor,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ ::basegfx::B2DHomMatrix aViewTransform;
+ ::basegfx::B2DHomMatrix aRenderTransform;
+ ::std::auto_ptr< ::basegfx::B2DPolyPolygon > pViewClip;
+ ::std::auto_ptr< ::basegfx::B2DPolyPolygon > pRenderClip;
+
+ setupState( aViewTransform,
+ aRenderTransform,
+ pViewClip,
+ pRenderClip,
+ o_rRenderColor,
+ viewState,
+ renderState );
+
+ clipAndTransformPolygon( io_rClippee,
+ bIsFilledPolyPolygon,
+ aViewTransform,
+ aRenderTransform,
+ pViewClip.get(),
+ pRenderClip.get() );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // RawABGRBitmap
+ //////////////////////////////////////////////////////////////////////////////////
+
+ // Raw ABGR [AABBGGRR] 32bit continous
+ struct RawABGRBitmap
+ {
+ sal_Int32 mnWidth;
+ sal_Int32 mnHeight;
+ sal_uInt8* mpBitmapData;
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // vclBitmapEx2Raw
+ //////////////////////////////////////////////////////////////////////////////////
+
+ void vclBitmapEx2Raw( const ::BitmapEx& rBmpEx, RawABGRBitmap& rBmpData )
+ {
+ Bitmap aBitmap( rBmpEx.GetBitmap() );
+
+ ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(),
+ aBitmap );
+
+ const sal_Int32 nWidth( rBmpData.mnWidth );
+ const sal_Int32 nHeight( rBmpData.mnHeight );
+
+ ENSURE_OR_THROW( pReadAccess.get() != NULL,
+ "vclBitmapEx2Raw(): "
+ "Unable to acquire read acces to bitmap" );
+
+ if( rBmpEx.IsTransparent())
+ {
+ if( rBmpEx.IsAlpha() )
+ {
+ // 8bit alpha mask
+ Bitmap aAlpha( rBmpEx.GetAlpha().GetBitmap() );
+
+ ScopedBitmapReadAccess pAlphaReadAccess( aAlpha.AcquireReadAccess(),
+ aAlpha );
+
+ // By convention, the access buffer always has
+ // one of the following formats:
+ //
+ // BMP_FORMAT_1BIT_MSB_PAL
+ // BMP_FORMAT_4BIT_MSN_PAL
+ // BMP_FORMAT_8BIT_PAL
+ // BMP_FORMAT_16BIT_TC_LSB_MASK
+ // BMP_FORMAT_24BIT_TC_BGR
+ // BMP_FORMAT_32BIT_TC_MASK
+ //
+ // and is always BMP_FORMAT_BOTTOM_UP
+ //
+ // This is the way
+ // WinSalBitmap::AcquireBuffer() sets up the
+ // buffer
+
+ ENSURE_OR_THROW( pAlphaReadAccess.get() != NULL,
+ "vclBitmapEx2Raw(): "
+ "Unable to acquire read acces to alpha" );
+
+ ENSURE_OR_THROW( pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
+ pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK,
+ "vclBitmapEx2Raw(): "
+ "Unsupported alpha scanline format" );
+
+ BitmapColor aCol;
+ sal_uInt8* pCurrOutput( rBmpData.mpBitmapData );
+ int x, y;
+
+ for( y=0; y<nHeight; ++y )
+ {
+ switch( pReadAccess->GetScanlineFormat() )
+ {
+ case BMP_FORMAT_8BIT_PAL:
+ {
+ Scanline pScan = pReadAccess->GetScanline( y );
+ Scanline pAScan = pAlphaReadAccess->GetScanline( y );
+
+ for( x=0; x<nWidth; ++x )
+ {
+ aCol = pReadAccess->GetPaletteColor( *pScan++ );
+
+ *pCurrOutput++ = aCol.GetBlue();
+ *pCurrOutput++ = aCol.GetGreen();
+ *pCurrOutput++ = aCol.GetRed();
+
+ // out notion of alpha is
+ // different from the rest
+ // of the world's
+ *pCurrOutput++ = 255 - (BYTE)*pAScan++;
+ }
+ }
+ break;
+
+ case BMP_FORMAT_24BIT_TC_BGR:
+ {
+ Scanline pScan = pReadAccess->GetScanline( y );
+ Scanline pAScan = pAlphaReadAccess->GetScanline( y );
+
+ for( x=0; x<nWidth; ++x )
+ {
+ // store as RGBA
+ *pCurrOutput++ = *pScan++;
+ *pCurrOutput++ = *pScan++;
+ *pCurrOutput++ = *pScan++;
+
+ // out notion of alpha is
+ // different from the rest
+ // of the world's
+ *pCurrOutput++ = 255 - (BYTE)*pAScan++;
+ }
+ }
+ break;
+
+ // TODO(P2): Might be advantageous
+ // to hand-formulate the following
+ // formats, too.
+ case BMP_FORMAT_1BIT_MSB_PAL:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_4BIT_MSN_PAL:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_16BIT_TC_LSB_MASK:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_32BIT_TC_MASK:
+ {
+ Scanline pAScan = pAlphaReadAccess->GetScanline( y );
+
+ // using fallback for those
+ // seldom formats
+ for( x=0; x<nWidth; ++x )
+ {
+ // yes. x and y are swapped on Get/SetPixel
+ aCol = pReadAccess->GetColor(y,x);
+
+ *pCurrOutput++ = aCol.GetBlue();
+ *pCurrOutput++ = aCol.GetGreen();
+ *pCurrOutput++ = aCol.GetRed();
+
+ // out notion of alpha is
+ // different from the rest
+ // of the world's
+ *pCurrOutput++ = 255 - (BYTE)*pAScan++;
+ }
+ }
+ break;
+
+ case BMP_FORMAT_1BIT_LSB_PAL:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_4BIT_LSN_PAL:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_8BIT_TC_MASK:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_24BIT_TC_RGB:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_24BIT_TC_MASK:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_16BIT_TC_MSB_MASK:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_32BIT_TC_ABGR:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_32BIT_TC_ARGB:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_32BIT_TC_BGRA:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_32BIT_TC_RGBA:
+ // FALLTHROUGH intended
+ default:
+ ENSURE_OR_THROW( false,
+ "vclBitmapEx2Raw(): "
+ "Unexpected scanline format - has "
+ "WinSalBitmap::AcquireBuffer() changed?" );
+ }
+ }
+ }
+ else
+ {
+ // 1bit alpha mask
+ Bitmap aMask( rBmpEx.GetMask() );
+
+ ScopedBitmapReadAccess pMaskReadAccess( aMask.AcquireReadAccess(),
+ aMask );
+
+ // By convention, the access buffer always has
+ // one of the following formats:
+ //
+ // BMP_FORMAT_1BIT_MSB_PAL
+ // BMP_FORMAT_4BIT_MSN_PAL
+ // BMP_FORMAT_8BIT_PAL
+ // BMP_FORMAT_16BIT_TC_LSB_MASK
+ // BMP_FORMAT_24BIT_TC_BGR
+ // BMP_FORMAT_32BIT_TC_MASK
+ //
+ // and is always BMP_FORMAT_BOTTOM_UP
+ //
+ // This is the way
+ // WinSalBitmap::AcquireBuffer() sets up the
+ // buffer
+
+ ENSURE_OR_THROW( pMaskReadAccess.get() != NULL,
+ "vclBitmapEx2Raw(): "
+ "Unable to acquire read acces to mask" );
+
+ ENSURE_OR_THROW( pMaskReadAccess->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL,
+ "vclBitmapEx2Raw(): "
+ "Unsupported mask scanline format" );
+
+ BitmapColor aCol;
+ int nCurrBit;
+ const int nMask( 1L );
+ const int nInitialBit(7);
+ sal_uInt32 *pBuffer = reinterpret_cast<sal_uInt32 *>(rBmpData.mpBitmapData);
+ int x, y;
+
+ // mapping table, to get from mask index color to
+ // alpha value (which depends on the mask's palette)
+ sal_uInt8 aColorMap[2];
+
+ const BitmapColor& rCol0( pMaskReadAccess->GetPaletteColor( 0 ) );
+ const BitmapColor& rCol1( pMaskReadAccess->GetPaletteColor( 1 ) );
+
+ // shortcut for true luminance calculation
+ // (assumes that palette is grey-level). Note the
+ // swapped the indices here, to account for the
+ // fact that VCL's notion of alpha is inverted to
+ // the rest of the world's.
+ aColorMap[0] = rCol1.GetRed();
+ aColorMap[1] = rCol0.GetRed();
+
+ for( y=0; y<nHeight; ++y )
+ {
+ switch( pReadAccess->GetScanlineFormat() )
+ {
+ case BMP_FORMAT_8BIT_PAL:
+ {
+ Scanline pScan = pReadAccess->GetScanline( y );
+ Scanline pMScan = pMaskReadAccess->GetScanline( y );
+
+ for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x )
+ {
+ aCol = pReadAccess->GetPaletteColor( *pScan++ );
+
+ // RGB -> ABGR
+ unsigned int color = aCol.GetRed();
+ color |= aCol.GetGreen()<<8;
+ color |= aCol.GetBlue()<<16;
+ color |= aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ]<<24;
+ *pBuffer++ = color;
+ nCurrBit = ((nCurrBit - 1) % 8L) & 7L;
+ }
+ }
+ break;
+
+ case BMP_FORMAT_24BIT_TC_BGR:
+ {
+ Scanline pScan = pReadAccess->GetScanline( y );
+ Scanline pMScan = pMaskReadAccess->GetScanline( y );
+
+ for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x )
+ {
+ // BGR -> ABGR
+ unsigned int color = (*pScan++)<<16;
+ color |= (*pScan++)<<8;
+ color |= (*pScan++);
+ color |= (aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ])<<24;
+ *pBuffer++ = color;
+ nCurrBit = ((nCurrBit - 1) % 8L) & 7L;
+ }
+ }
+ break;
+
+ // TODO(P2): Might be advantageous
+ // to hand-formulate the following
+ // formats, too.
+ case BMP_FORMAT_1BIT_MSB_PAL:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_4BIT_MSN_PAL:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_16BIT_TC_LSB_MASK:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_32BIT_TC_MASK:
+ {
+ Scanline pMScan = pMaskReadAccess->GetScanline( y );
+
+ // using fallback for those
+ // seldom formats
+ for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x )
+ {
+ // yes. x and y are swapped on Get/SetPixel
+ aCol = pReadAccess->GetColor(y,x);
+
+ // -> ABGR
+ unsigned int color = aCol.GetBlue()<<16;
+ color |= aCol.GetGreen()<<8;
+ color |= aCol.GetRed();
+ color |= (aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ])<<24;
+ *pBuffer++ = color;
+ nCurrBit = ((nCurrBit - 1) % 8L) & 7L;
+ }
+ }
+ break;
+
+ case BMP_FORMAT_1BIT_LSB_PAL:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_4BIT_LSN_PAL:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_8BIT_TC_MASK:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_24BIT_TC_RGB:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_24BIT_TC_MASK:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_16BIT_TC_MSB_MASK:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_32BIT_TC_ABGR:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_32BIT_TC_ARGB:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_32BIT_TC_BGRA:
+ // FALLTHROUGH intended
+ case BMP_FORMAT_32BIT_TC_RGBA:
+ // FALLTHROUGH intended
+ default:
+ ENSURE_OR_THROW( false,
+ "vclBitmapEx2Raw(): "
+ "Unexpected scanline format - has "
+ "WinSalBitmap::AcquireBuffer() changed?" );
+ }
+ }
+ }
+ }
+ else
+ {
+ // *no* alpha mask
+ ULONG nFormat = pReadAccess->GetScanlineFormat();
+ BYTE *pBuffer = reinterpret_cast<BYTE *>(rBmpData.mpBitmapData);
+
+ switch(nFormat)
+ {
+ case BMP_FORMAT_24BIT_TC_BGR:
+
+ {
+ sal_Int32 height = pReadAccess->Height();
+ for(sal_Int32 y=0; y<height; ++y)
+ {
+ BYTE *pScanline=pReadAccess->GetScanline(y);
+ sal_Int32 width = pReadAccess->Width();
+ for(sal_Int32 x=0; x<width; ++x)
+ {
+ // BGR -> RGB
+ BYTE b(*pScanline++);
+ BYTE g(*pScanline++);
+ BYTE r(*pScanline++);
+ *pBuffer++ = r;
+ *pBuffer++ = g;
+ *pBuffer++ = b;
+ }
+ }
+ }
+ break;
+
+ case BMP_FORMAT_24BIT_TC_RGB:
+
+ {
+ sal_Int32 height = pReadAccess->Height();
+ for(sal_Int32 y=0; y<height; ++y)
+ {
+ BYTE *pScanline=pReadAccess->GetScanline(y);
+ sal_Int32 width = pReadAccess->Width();
+ for(sal_Int32 x=0; x<width; ++x)
+ {
+ // RGB -> RGB
+ BYTE r(*pScanline++);
+ BYTE g(*pScanline++);
+ BYTE b(*pScanline++);
+ *pBuffer++ = r;
+ *pBuffer++ = g;
+ *pBuffer++ = b;
+ }
+ }
+ }
+ break;
+
+ case BMP_FORMAT_1BIT_MSB_PAL:
+ case BMP_FORMAT_1BIT_LSB_PAL:
+ case BMP_FORMAT_4BIT_MSN_PAL:
+ case BMP_FORMAT_4BIT_LSN_PAL:
+ case BMP_FORMAT_8BIT_PAL:
+
+ {
+ sal_Int32 height = pReadAccess->Height();
+ for(sal_Int32 y=0; y<height; ++y)
+ {
+ BYTE *pScanline=pReadAccess->GetScanline(y);
+ sal_Int32 width = pReadAccess->Width();
+ for(sal_Int32 x=0; x<width; ++x)
+ {
+ BitmapColor aCol(pReadAccess->GetPaletteColor(*pScanline++));
+
+ *pBuffer++ = aCol.GetRed();
+ *pBuffer++ = aCol.GetGreen();
+ *pBuffer++ = aCol.GetBlue();
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // color_generator_linear
+ //////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct color_generator_linear
+ {
+ typedef typename T::value_type value_type;
+
+ color_generator_linear( const T &c1,
+ const T &c2,
+ unsigned int aSteps ) : maSteps(aSteps),
+ maColor1(c1),
+ maColor2(c2)
+ {
+ }
+
+ unsigned size() const { return maSteps; }
+ const T operator [] (unsigned v) const
+ {
+ const double w = double(v)/maSteps;
+ return T( static_cast<value_type>(maColor1.r+(maColor2.r-maColor1.r)*w),
+ static_cast<value_type>(maColor1.g+(maColor2.g-maColor1.g)*w),
+ static_cast<value_type>(maColor1.b+(maColor2.b-maColor1.b)*w),
+ static_cast<value_type>(maColor1.a+(maColor2.a-maColor1.a)*w));
+ }
+
+ unsigned int maSteps;
+ const T maColor1;
+ const T maColor2;
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // color_generator_axial
+ //////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct color_generator_axial
+ {
+ typedef typename T::value_type value_type;
+
+ color_generator_axial( const T &c1,
+ const T &c2,
+ unsigned int aSteps ) : maSteps(aSteps),
+ maColor1(c1),
+ maColor2(c2)
+ {
+ }
+
+ unsigned size() const { return maSteps; }
+ const T operator [] (unsigned v) const
+ {
+ const double aHalfSteps = maSteps/2.0;
+ const double w = (v >= aHalfSteps) ?
+ 1.0-((double(v)-aHalfSteps)/aHalfSteps) :
+ (double(v)*2.0)/maSteps;
+ return T( static_cast<value_type>(maColor1.r+(maColor2.r-maColor1.r)*w),
+ static_cast<value_type>(maColor1.g+(maColor2.g-maColor1.g)*w),
+ static_cast<value_type>(maColor1.b+(maColor2.b-maColor1.b)*w),
+ static_cast<value_type>(maColor1.a+(maColor2.a-maColor1.a)*w));
+ }
+
+ unsigned int maSteps;
+ const T maColor1;
+ const T maColor2;
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // color_generator_adaptor
+ //////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct color_generator_adaptor
+ {
+ color_generator_adaptor( const T &c1,
+ const T &c2,
+ unsigned int aSteps ) : linear_generator(c1,c2,aSteps),
+ axial_generator(c1,c2,aSteps),
+ mbLinear(true) {}
+ void set_linear( bool bLinear ) { mbLinear=bLinear; }
+ unsigned size() const { return mbLinear ? linear_generator.size() : axial_generator.size(); }
+ const T operator [] (unsigned v) const
+ {
+ return mbLinear ?
+ linear_generator.operator [] (v) :
+ axial_generator.operator [] (v);
+ }
+
+ color_generator_linear<T> linear_generator;
+ color_generator_axial<T> axial_generator;
+ bool mbLinear;
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // gradient_polymorphic_wrapper_base
+ //////////////////////////////////////////////////////////////////////////////////
+
+ struct gradient_polymorphic_wrapper_base
+ {
+ virtual int calculate(int x, int y, int) const = 0;
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // gradient_polymorphic_wrapper
+ //////////////////////////////////////////////////////////////////////////////////
+
+ template<class GradientF> struct gradient_polymorphic_wrapper :
+ public gradient_polymorphic_wrapper_base
+ {
+ virtual int calculate(int x, int y, int d) const
+ {
+ return m_gradient.calculate(x, y, d);
+ }
+ GradientF m_gradient;
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // gradient_rect
+ //////////////////////////////////////////////////////////////////////////////////
+
+ class gradient_rect
+ {
+ public:
+
+ int width;
+ int height;
+
+ inline int calculate(int x, int y, int d) const
+ {
+ int ax = abs(x);
+ int ay = abs(y);
+ int clamp_x = height>width ? 0 : (width-height);
+ int clamp_y = height>width ? (height-width) : 0;
+ int value_x = (ax-clamp_x)*d/(width-clamp_x);
+ int value_y = (ay-clamp_y)*d/(height-clamp_y);
+ if(ax < (clamp_x))
+ value_x = 0;
+ if(ay < (clamp_y))
+ value_y = 0;
+ return value_x > value_y ? value_x : value_y;
+ }
+ };
+
+ sal_uInt32 getBytesPerPixel( IColorBuffer::Format eFormat )
+ {
+ switch(eFormat)
+ {
+ default:
+ OSL_ENSURE(false, "Unexpected pixel format");
+ // FALLTHROUGH intended
+ case IColorBuffer::FMT_R8G8B8:
+ return 3L;
+ case IColorBuffer::FMT_A8R8G8B8:
+ return 4L;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::drawLinePolyPolygon
+//////////////////////////////////////////////////////////////////////////////////
+
+template<class pixel_format>
+void Image::drawLinePolyPolygonImpl( const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ double fStrokeWidth,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+{
+ ::basegfx::B2DPolyPolygon aPolyPolygon( rPolyPolygon );
+ ARGB aRenderColor;
+
+ setupPolyPolygon( aPolyPolygon, false, aRenderColor, viewState, renderState );
+
+ if( !aPolyPolygon.count() )
+ return;
+
+ // Class template pixel_formats_rgb24 has full knowledge about this
+ // particular pixel format in memory. The only template parameter
+ // can be order_rgb24 or order_bgr24 that determines the order of color channels.
+ //typedef agg::pixfmt_rgba32 pixel_format;
+ pixel_format pixf(maRenderingBuffer);
+
+ // There are two basic renderers with almost the same functionality:
+ // renderer_base and renderer_mclip. The first one is used most often
+ // and it performs low level clipping.
+ // This simply adds clipping to the graphics buffer, the clip rect
+ // will be initialized to the area of the framebuffer.
+ typedef agg::renderer_base<pixel_format> renderer_base;
+ agg::renderer_base<pixel_format> renb(pixf);
+
+ // To draw Anti-Aliased primitives one shoud *rasterize* them first.
+ // The primary rasterization technique in AGG is scanline based.
+ // That is, a polygon is converted into a number of horizontal
+ // scanlines and then the scanlines are being rendered one by one.
+ // To transfer information from a rasterizer to the scanline renderer
+ // there scanline containers are used. A scanline consists of a
+ // number of horizontal, non-intersecting spans. All spans must be ordered by X.
+ // --> *packed* scanline container
+ agg::scanline_p8 sl;
+
+ typedef agg::renderer_outline_aa<renderer_base> renderer_type;
+ typedef agg::rasterizer_outline_aa<renderer_type> rasterizer_type;
+ agg::line_profile_aa profile;
+ profile.width(fStrokeWidth);
+ renderer_type ren(renb, profile);
+ rasterizer_type ras(ren);
+
+ const agg::rgba8 fillcolor(aRenderColor.Color.r,
+ aRenderColor.Color.g,
+ aRenderColor.Color.b,
+ aRenderColor.Color.a);
+ ren.color(fillcolor);
+
+ agg::path_storage path;
+ agg::conv_curve<agg::path_storage> curve(path);
+
+ for(sal_uInt32 nPolygon=0; nPolygon<aPolyPolygon.count(); ++nPolygon)
+ {
+ const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(nPolygon));
+ const sal_uInt32 nPointCount(aPolygon.count());
+
+ if(nPointCount)
+ {
+ if(aPolygon.areControlPointsUsed())
+ {
+ // prepare edge-based loop
+ basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0));
+ const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount);
+
+ // first vertex
+ path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY());
+
+ for(sal_uInt32 a(0); a < nEdgeCount; a++)
+ {
+ // access next point
+ const sal_uInt32 nNextIndex((a + 1) % nPointCount);
+ const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex));
+
+ // get control points
+ const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a));
+ const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex));
+
+ // specify first cp, second cp, next vertex
+ path.curve4(
+ aControlNext.getX(), aControlNext.getY(),
+ aControlPrev.getX(), aControlPrev.getY(),
+ aNextPoint.getX(), aNextPoint.getY());
+
+ // prepare next step
+ aCurrentPoint = aNextPoint;
+ }
+ }
+ else
+ {
+ const basegfx::B2DPoint aStartPoint(aPolygon.getB2DPoint(0));
+ ras.move_to_d(aStartPoint.getX(), aStartPoint.getY());
+
+ for(sal_uInt32 a(1); a < nPointCount; a++)
+ {
+ const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a));
+ ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY());
+ }
+
+ ras.render(aPolygon.isClosed());
+ }
+ }
+ }
+
+ ras.add_path(curve);
+ ras.render(false);
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::drawLinePolyPolygon
+//////////////////////////////////////////////////////////////////////////////////
+
+void Image::drawLinePolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly,
+ double fStrokeWidth,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+{
+ switch(maDesc.eFormat)
+ {
+ case FMT_R8G8B8:
+ drawLinePolyPolygonImpl<agg::pixfmt_rgb24>(rPoly,fStrokeWidth,viewState,renderState);
+ break;
+ case FMT_A8R8G8B8:
+ drawLinePolyPolygonImpl<agg::pixfmt_rgba32>(rPoly,fStrokeWidth,viewState,renderState);
+ break;
+ default:
+ OSL_ENSURE(false, "Unexpected pixel format");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::implDrawBitmap
+//////////////////////////////////////////////////////////////////////////////////
+
+/** internal utility function to draw one image into another one.
+ the source image will be drawn with respect to the given
+ transform and clip settings.
+ */
+ImageCachedPrimitiveSharedPtr Image::implDrawBitmap(
+ const Image& rBitmap,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+{
+ ::basegfx::B2DPolyPolygon aPoly(
+ ::basegfx::tools::createPolygonFromRect(
+ ::basegfx::B2DRange(0.0, 0.0,
+ rBitmap.maDesc.nWidth,
+ rBitmap.maDesc.nHeight ) ) );
+ ARGB aFillColor;
+
+ setupPolyPolygon( aPoly, true, aFillColor, viewState, renderState );
+
+ if( !aPoly.count() )
+ return ImageCachedPrimitiveSharedPtr();
+
+ ::basegfx::B2DHomMatrix aViewTransform;
+ ::basegfx::B2DHomMatrix aRenderTransform;
+ ::basegfx::B2DHomMatrix aTextureTransform;
+
+ ::basegfx::unotools::homMatrixFromAffineMatrix(aRenderTransform,
+ renderState.AffineTransform);
+ ::basegfx::unotools::homMatrixFromAffineMatrix(aViewTransform,
+ viewState.AffineTransform);
+ aTextureTransform *= aRenderTransform;
+
+ // TODO(F2): Fill in texture
+ rendering::Texture aTexture;
+
+ return fillTexturedPolyPolygon( rBitmap,
+ aPoly,
+ aTextureTransform,
+ aViewTransform,
+ aTexture );
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// cachedPrimitiveFTPP [cachedPrimitive for [F]ill[T]extured[P]oly[P]olygon]
+//////////////////////////////////////////////////////////////////////////////////
+
+#if AGG_VERSION >= 2400
+template<class pixel_format_dst,class span_gen_type>
+#else
+template<class pixel_format,class span_gen_type>
+#endif
+class cachedPrimitiveFTPP : public ImageCachedPrimitive
+{
+ public:
+
+ cachedPrimitiveFTPP( const ::basegfx::B2DHomMatrix &rTransform,
+ const ::basegfx::B2DHomMatrix &rViewTransform,
+ agg::rendering_buffer &dst,
+ const agg::rendering_buffer& src ) :
+ aTransform(rTransform),
+ inter(tm),
+ filter(filter_kernel),
+#if AGG_VERSION >= 2400
+ pixs(const_cast<agg::rendering_buffer&>(src)),
+ source(pixs),
+ sg(source,inter,filter),
+ pixd(dst),
+ rb(pixd),
+ ren(rb,sa,sg)
+#else
+ sg(sa,src,inter,filter),
+ pixf(dst),
+ rb(pixf),
+ ren(rb,sg)
+#endif
+ {
+ ::basegfx::B2DHomMatrix aFinalTransform(aTransform);
+ aFinalTransform *= rViewTransform;
+ tm = transAffineFromB2DHomMatrix(aFinalTransform);
+ tm.invert();
+ }
+
+ virtual void setImage( const ::boost::shared_ptr< class Image >& rTargetImage )
+ {
+ pImage=rTargetImage;
+ }
+
+ virtual sal_Int8 redraw( const ::com::sun::star::rendering::ViewState& aState ) const
+ {
+ ::basegfx::B2DHomMatrix aViewTransform;
+ ::basegfx::unotools::homMatrixFromAffineMatrix(aViewTransform,aState.AffineTransform);
+ ::basegfx::B2DHomMatrix aFinalTransform(aTransform);
+ aFinalTransform *= aViewTransform;
+ tm = transAffineFromB2DHomMatrix(aFinalTransform);
+ tm.invert();
+ redraw();
+ return ::com::sun::star::rendering::RepaintResult::REDRAWN;
+ }
+
+ inline void redraw() const { agg::render_scanlines(ras, sl, ren); }
+
+ mutable agg::rasterizer_scanline_aa<> ras;
+
+ private:
+
+ typedef agg::span_interpolator_linear<> interpolator_type;
+#if AGG_VERSION >= 2400
+ typedef agg::renderer_base<pixel_format_dst> renderer_base;
+ typedef agg::span_allocator< typename span_gen_type::color_type > span_alloc_type;
+ typedef agg::renderer_scanline_aa<renderer_base, span_alloc_type, span_gen_type> renderer_type;
+ typedef typename span_gen_type::source_type source_type;
+ typedef typename span_gen_type::source_type::pixfmt_type pixel_format_src;
+#else
+ typedef agg::renderer_base<pixel_format> renderer_base;
+ typedef agg::renderer_scanline_aa<renderer_base, span_gen_type> renderer_type;
+#endif
+
+ ::basegfx::B2DHomMatrix aTransform;
+ interpolator_type inter;
+ agg::image_filter_bilinear filter_kernel;
+ agg::image_filter_lut filter;
+#if AGG_VERSION >= 2400
+ span_alloc_type sa;
+ pixel_format_src pixs;
+ source_type source;
+#else
+ agg::span_allocator< typename span_gen_type::color_type > sa;
+#endif
+ span_gen_type sg;
+#if AGG_VERSION >= 2400
+ pixel_format_dst pixd;
+#else
+ pixel_format pixf;
+#endif
+ renderer_base rb;
+ mutable renderer_type ren;
+ mutable agg::scanline_p8 sl;
+ mutable agg::trans_affine tm;
+ ImageSharedPtr pImage;
+};
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::fillTexturedPolyPolygon
+//////////////////////////////////////////////////////////////////////////////////
+
+template<class pixel_format,class span_gen_type>
+ImageCachedPrimitiveSharedPtr Image::fillTexturedPolyPolygonImpl(
+ const Image& rTexture,
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const ::basegfx::B2DHomMatrix& rOverallTransform,
+ const ::basegfx::B2DHomMatrix& rViewTransform,
+ const rendering::Texture& )
+{
+ // calculate final overall transform.
+ ::basegfx::B2DHomMatrix aOverallTransform(rOverallTransform);
+ aOverallTransform *= rViewTransform;
+
+ // instead of always using the full-blown solution we
+ // first check to see if this is a simple rectangular
+ // 1-to-1 copy from source to destination image.
+ ::basegfx::B2DTuple aTranslate(aOverallTransform.get(0,2),aOverallTransform.get(1,2));
+ ::basegfx::B2DTuple aSize(rTexture.maDesc.nWidth,rTexture.maDesc.nHeight);
+ ::basegfx::B2DRange aRange(aTranslate,aTranslate+aSize);
+ ::basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
+ aPolyPolygon.transform(aOverallTransform);
+ if(::basegfx::tools::isPolyPolygonEqualRectangle(aPolyPolygon,aRange))
+ {
+ // yes, we can take the shortcut.
+ // but we need to clip the destination rectangle
+ // against the boundary of the destination image.
+ sal_Int32 dwSrcX(0);
+ sal_Int32 dwSrcY(0);
+ sal_Int32 dwDstX(static_cast<sal_Int32>(aTranslate.getX()));
+ sal_Int32 dwDstY(static_cast<sal_Int32>(aTranslate.getY()));
+ sal_Int32 dwWidth(rTexture.maDesc.nWidth);
+ sal_Int32 dwHeight(rTexture.maDesc.nHeight);
+
+ // prevent fast copy if destination position is not an
+ // integer coordinate. otherwise we would most probably
+ // introduce visual glitches while combining this with
+ // high-accuracy rendering stuff.
+ if( ::basegfx::fTools::equalZero(aTranslate.getX()-dwDstX) &&
+ ::basegfx::fTools::equalZero(aTranslate.getY()-dwDstY))
+ {
+ // clip against destination boundary. shrink size if
+ // necessary, modify destination position if we need to.
+ if(dwDstX < 0) { dwWidth-=dwDstX; dwSrcX=-dwDstX; dwDstX=0; }
+ if(dwDstY < 0) { dwHeight-=dwDstY; dwSrcY=-dwDstY; dwDstY=0; }
+ const sal_Int32 dwRight(dwDstX+dwWidth);
+ const sal_Int32 dwBottom(dwDstY+dwHeight);
+ if(dwRight > dwWidth)
+ dwWidth -= dwRight-dwWidth;
+ if(dwBottom > dwHeight)
+ dwHeight -= dwBottom-dwHeight;
+
+ // calculate source buffer
+ const Description &srcDesc = rTexture.maDesc;
+ const sal_uInt32 dwSrcBytesPerPixel(getBytesPerPixel(srcDesc.eFormat));
+ const sal_uInt32 dwSrcPitch(srcDesc.nWidth*dwSrcBytesPerPixel+srcDesc.nStride);
+ sal_uInt8 *pSrcBuffer = rTexture.maDesc.pBuffer+(dwSrcPitch*dwSrcX)+(dwSrcBytesPerPixel*dwSrcY);
+
+ // calculate destination buffer
+ const Description &dstDesc = maDesc;
+ const sal_uInt32 dwDstBytesPerPixel(getBytesPerPixel(dstDesc.eFormat));
+ const sal_uInt32 dwDstPitch(dstDesc.nWidth*dwDstBytesPerPixel+dstDesc.nStride);
+ sal_uInt8 *pDstBuffer = maDesc.pBuffer+(dwDstPitch*dwDstY)+(dwDstBytesPerPixel*dwDstX);
+
+ // if source and destination format match, we can simply
+ // copy whole scanlines.
+ if(srcDesc.eFormat == dstDesc.eFormat)
+ {
+ const sal_Size dwNumBytesPerScanline(dwSrcBytesPerPixel*dwWidth);
+ for(sal_Int32 y=0; y<dwHeight; ++y)
+ {
+ rtl_copyMemory(pDstBuffer,pSrcBuffer,dwNumBytesPerScanline);
+ pSrcBuffer += dwSrcPitch;
+ pDstBuffer += dwDstPitch;
+ }
+ }
+ else
+ {
+ // otherwise [formats do not match], we need to copy
+ // each pixel one by one and convert from source to destination format.
+ if(srcDesc.eFormat == FMT_A8R8G8B8 && dstDesc.eFormat == FMT_R8G8B8)
+ {
+ for(sal_Int32 y=0; y<dwHeight; ++y)
+ {
+ sal_uInt8 *pSrc=pSrcBuffer;
+ sal_uInt8 *pDst=pDstBuffer;
+ for(sal_Int32 x=0; x<dwWidth; ++x)
+ {
+ BYTE r(*pSrc++);
+ BYTE g(*pSrc++);
+ BYTE b(*pSrc++);
+ BYTE Alpha(*pSrc++);
+ BYTE OneMinusAlpha(0xFF-Alpha);
+ *pDst=(((r*Alpha)+((*pDst)*OneMinusAlpha))/0xFF);
+ ++pDst;
+ *pDst=(((g*Alpha)+((*pDst)*OneMinusAlpha))/0xFF);
+ ++pDst;
+ *pDst=(((b*Alpha)+((*pDst)*OneMinusAlpha))/0xFF);
+ ++pDst;
+ }
+ pSrcBuffer += dwSrcPitch;
+ pDstBuffer += dwDstPitch;
+ }
+ }
+ else if(srcDesc.eFormat == FMT_R8G8B8 && dstDesc.eFormat == FMT_A8R8G8B8)
+ {
+ for(sal_Int32 y=0; y<dwHeight; ++y)
+ {
+ sal_uInt8 *pSrc=pSrcBuffer;
+ sal_uInt8 *pDst=pDstBuffer;
+ for(sal_Int32 x=0; x<dwWidth; ++x)
+ {
+ BYTE r(*pSrc++);
+ BYTE g(*pSrc++);
+ BYTE b(*pSrc++);
+ *pDst++=r;
+ *pDst++=g;
+ *pDst++=b;
+ *pDst++=0xFF;
+ }
+ pSrcBuffer += dwSrcPitch;
+ pDstBuffer += dwDstPitch;
+ }
+ }
+ }
+
+ return ImageCachedPrimitiveSharedPtr();
+ }
+ }
+
+ typedef cachedPrimitiveFTPP<pixel_format,span_gen_type> cachedPrimitive_t;
+ cachedPrimitive_t *pPrimitive = new cachedPrimitive_t( rOverallTransform,
+ rViewTransform,
+ maRenderingBuffer,
+ rTexture.maRenderingBuffer);
+
+ agg::path_storage path;
+ agg::conv_curve<agg::path_storage> curve(path);
+
+ for(sal_uInt32 nPolygon(0); nPolygon < rPolyPolygon.count(); nPolygon++)
+ {
+ const basegfx::B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(nPolygon));
+ const sal_uInt32 nPointCount(aPolygon.count());
+
+ if(nPointCount)
+ {
+ if(aPolygon.areControlPointsUsed())
+ {
+ // prepare edge-based loop
+ basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0));
+ const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount);
+
+ // first vertex
+ path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY());
+
+ for(sal_uInt32 a(0); a < nEdgeCount; a++)
+ {
+ // access next point
+ const sal_uInt32 nNextIndex((a + 1) % nPointCount);
+ const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex));
+
+ // get control points
+ const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a));
+ const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex));
+
+ // specify first cp, second cp, next vertex
+ path.curve4(
+ aControlNext.getX(), aControlNext.getY(),
+ aControlPrev.getX(), aControlPrev.getY(),
+ aNextPoint.getX(), aNextPoint.getY());
+
+ // prepare next step
+ aCurrentPoint = aNextPoint;
+ }
+ }
+ else
+ {
+ const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(0));
+ pPrimitive->ras.move_to_d(aPoint.getX(), aPoint.getY());
+
+ for(sal_uInt32 a(1); a < nPointCount; a++)
+ {
+ const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a));
+ pPrimitive->ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY());
+ }
+
+ if(aPolygon.isClosed())
+ {
+ pPrimitive->ras.close_polygon();
+ }
+ }
+ }
+ }
+
+ pPrimitive->ras.add_path(curve);
+ pPrimitive->redraw();
+
+ return ImageCachedPrimitiveSharedPtr(pPrimitive);
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::fillTexturedPolyPolygon
+//////////////////////////////////////////////////////////////////////////////////
+
+ImageCachedPrimitiveSharedPtr Image::fillTexturedPolyPolygon(
+ const Image& rTexture,
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const ::basegfx::B2DHomMatrix& rOverallTransform,
+ const ::basegfx::B2DHomMatrix& rViewTransform,
+ const rendering::Texture& texture )
+{
+ typedef agg::wrap_mode_repeat wrap_x_type;
+ typedef agg::wrap_mode_repeat wrap_y_type;
+ typedef agg::pixfmt_rgb24 pixfmt_rgb24;
+ typedef agg::pixfmt_rgba32 pixfmt_rgba32;
+#if AGG_VERSION >= 2400
+ typedef agg::image_accessor_wrap< pixfmt_rgba32, wrap_x_type, wrap_y_type > img_source_type_rgba;
+ typedef agg::image_accessor_wrap< pixfmt_rgb24, wrap_x_type, wrap_y_type > img_source_type_rgb;
+
+ typedef agg::span_image_resample_rgba_affine< img_source_type_rgba > span_gen_type_rgba;
+ typedef agg::span_image_resample_rgb_affine< img_source_type_rgb > span_gen_type_rgb;
+#else
+ typedef agg::span_pattern_resample_rgba_affine< pixfmt_rgba32::color_type,
+ pixfmt_rgba32::order_type,
+ wrap_x_type,
+ wrap_y_type> span_gen_type_rgba;
+ typedef agg::span_pattern_resample_rgb_affine< pixfmt_rgb24::color_type,
+ pixfmt_rgb24::order_type,
+ wrap_x_type,
+ wrap_y_type> span_gen_type_rgb;
+#endif
+
+ const Format nDest = maDesc.eFormat;
+ const Format nSource = rTexture.maDesc.eFormat;
+
+ if(nDest == FMT_R8G8B8 && nSource == FMT_R8G8B8)
+ {
+ return fillTexturedPolyPolygonImpl< agg::pixfmt_rgb24,
+ span_gen_type_rgb >(
+ rTexture,
+ rPolyPolygon,
+ rOverallTransform,
+ rViewTransform,
+ texture );
+ }
+ else if(nDest == FMT_R8G8B8 && nSource == FMT_A8R8G8B8)
+ {
+ return fillTexturedPolyPolygonImpl< agg::pixfmt_rgb24,
+ span_gen_type_rgba >(
+ rTexture,
+ rPolyPolygon,
+ rOverallTransform,
+ rViewTransform,
+ texture );
+ }
+ else if(nDest == FMT_A8R8G8B8 && nSource == FMT_R8G8B8)
+ {
+ return fillTexturedPolyPolygonImpl< agg::pixfmt_rgba32,
+ span_gen_type_rgb >(
+ rTexture,
+ rPolyPolygon,
+ rOverallTransform,
+ rViewTransform,
+ texture );
+ }
+ else if(nDest == FMT_A8R8G8B8 && nSource == FMT_A8R8G8B8)
+ {
+ return fillTexturedPolyPolygonImpl< agg::pixfmt_rgba32,
+ span_gen_type_rgba >(
+ rTexture,
+ rPolyPolygon,
+ rOverallTransform,
+ rViewTransform,
+ texture );
+ }
+ else
+ {
+ OSL_ENSURE(false, "Unexpected pixel format");
+ }
+
+ return ImageCachedPrimitiveSharedPtr();
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::fillGradient
+//////////////////////////////////////////////////////////////////////////////////
+
+template<class pixel_format>
+void Image::fillGradientImpl( const ParametricPolyPolygon::Values& rValues,
+ const uno::Sequence< double >& rUnoColor1,
+ const uno::Sequence< double >& rUnoColor2,
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const ::basegfx::B2DHomMatrix& rOverallTransform,
+ const rendering::Texture& )
+{
+ const ARGB aColor1(0xFFFFFFFF,
+ rUnoColor1);
+ const ARGB aColor2(0xFFFFFFFF,
+ rUnoColor2);
+
+ // first of all we need to provide the framebuffer we want to render to.
+ // the properties of the framebuffer are
+ // 1) memory & layout [width, height, stride]
+ // 2) pixelformat
+ // 3) clipping
+
+ // Class template pixel_formats_rgb24 has full knowledge about this
+ // particular pixel format in memory. The only template parameter
+ // can be order_rgb24 or order_bgr24 that determines the order of color channels.
+ pixel_format pixf(maRenderingBuffer);
+
+ // There are two basic renderers with almost the same functionality:
+ // renderer_base and renderer_mclip. The first one is used most often
+ // and it performs low level clipping.
+ // This simply adds clipping to the graphics buffer, the clip rect
+ // will be initialized to the area of the framebuffer.
+ typedef agg::renderer_base<pixel_format> renderer_base;
+ renderer_base rb(pixf);
+
+ // bounding rectangle of untransformed polypolygon
+ const ::basegfx::B2DRange& rBounds(::basegfx::tools::getRange(rPolyPolygon));
+
+ // the color generator produces a specific color from
+ // some given interpolation value.
+ // number of steps for color interpolation
+ typedef typename pixel_format::color_type color_type;
+ color_type color1(agg::rgba8(aColor1.Color.r,
+ aColor1.Color.g,
+ aColor1.Color.b,
+ 255));
+ color_type color2(agg::rgba8(aColor2.Color.r,
+ aColor2.Color.g,
+ aColor2.Color.b,
+ 255));
+ typedef color_generator_adaptor<color_type> color_generator_type;
+ unsigned int dwNumSteps = static_cast<unsigned int>(rBounds.getWidth());
+ color_generator_type colors(color1,color2,dwNumSteps);
+ colors.set_linear(true);
+
+ // color = f(x,y)
+ gradient_polymorphic_wrapper<agg::gradient_x> gf_x;
+ gradient_polymorphic_wrapper<agg::gradient_radial> gf_radial;
+ gradient_polymorphic_wrapper<gradient_rect> gf_rectangular;
+ gf_rectangular.m_gradient.width = static_cast<int>(rBounds.getWidth())<<4;
+ gf_rectangular.m_gradient.height = static_cast<int>(rBounds.getHeight())<<4;
+ const gradient_polymorphic_wrapper_base *gf[] = { &gf_x, // GRADIENT_LINEAR
+ &gf_x, // GRADIENT_AXIAL
+ &gf_radial, // GRADIENT_ELLIPTICAL
+ &gf_rectangular // GRADIENT_RECTANGULAR
+ };
+
+ // how do texture coordinates change when the pixel coordinate change?
+ typedef agg::span_interpolator_linear<> interpolator_type;
+ agg::trans_affine tm;
+ tm *= agg::trans_affine_scaling(1.0f/rBounds.getWidth(),
+ 1.0f/rBounds.getHeight());
+ if(rValues.meType == ParametricPolyPolygon::GRADIENT_ELLIPTICAL ||
+ rValues.meType == ParametricPolyPolygon::GRADIENT_RECTANGULAR)
+ {
+ //tm *= trans_affine_scaling(mnAspectRatio,+1.0f);
+ //const double fAspect = aBounds.getWidth()/aBounds.getHeight();
+ //tm *= trans_affine_scaling(+0.5f,+0.5f*(1.0f/fAspect));
+ //tm *= trans_affine_translation(+0.5f,+0.5f);
+ tm *= agg::trans_affine_scaling(+0.5f,+0.5f);
+ tm *= agg::trans_affine_translation(+0.5f,+0.5f);
+ }
+ tm *= transAffineFromB2DHomMatrix(rOverallTransform);
+ tm.invert();
+ interpolator_type inter(tm);
+
+ // spanline allocators reserve memory for the color values
+ // filled up by the spanline generators.
+ typedef agg::span_allocator<color_type> gradient_span_alloc;
+ gradient_span_alloc span_alloc;
+
+ // scanline generators create the actual color values for
+ // some specific coordinate range of a scanline.
+ typedef agg::span_gradient<color_type,
+ interpolator_type,
+ gradient_polymorphic_wrapper_base,
+ color_generator_type > gradient_span_gen;
+#if AGG_VERSION >= 2400
+ gradient_span_gen span_gen(inter,
+ *gf[rValues.meType],
+ colors,
+ 0,
+ dwNumSteps);
+#else
+ gradient_span_gen span_gen(span_alloc,
+ inter,
+ *gf[rValues.meType],
+ colors,
+ 0,
+ dwNumSteps);
+#endif
+
+ // To draw Anti-Aliased primitives one shoud *rasterize* them first.
+ // The primary rasterization technique in AGG is scanline based.
+ // That is, a polygon is converted into a number of horizontal
+ // scanlines and then the scanlines are being rendered one by one.
+ // To transfer information from a rasterizer to the scanline renderer
+ // there scanline containers are used. A scanline consists of a
+ // number of horizontal, non-intersecting spans. All spans must be ordered by X.
+ // --> packed scanline container
+ agg::scanline_p8 sl;
+
+ // antialiased scanline renderer with pattern filling capability
+ // [in contrast to solid renderers, that is]
+ // the instance of this particular renderer combines the
+ // renderbuffer [i.e. destination] and the spanline generator [i.e. source]
+#if AGG_VERSION >= 2400
+ typedef agg::renderer_scanline_aa<renderer_base, gradient_span_alloc, gradient_span_gen> renderer_gradient;
+ renderer_gradient r1(rb, span_alloc, span_gen);
+#else
+ typedef agg::renderer_scanline_aa<renderer_base, gradient_span_gen> renderer_gradient;
+ renderer_gradient r1(rb, span_gen);
+#endif
+
+ // instantiate the rasterizer and feed the incoming polypolygon.
+ agg::rasterizer_scanline_aa<> ras;
+ agg::path_storage path;
+ agg::conv_curve<agg::path_storage> curve(path);
+
+ for(sal_uInt32 nPolygon(0); nPolygon < rPolyPolygon.count(); nPolygon++)
+ {
+ const basegfx::B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(nPolygon));
+ const sal_uInt32 nPointCount(aPolygon.count());
+
+ if(nPointCount)
+ {
+ if(aPolygon.areControlPointsUsed())
+ {
+ // prepare edge-based loop
+ basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0));
+ const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount);
+
+ // first vertex
+ path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY());
+
+ for(sal_uInt32 a(0); a < nEdgeCount; a++)
+ {
+ // access next point
+ const sal_uInt32 nNextIndex((a + 1) % nPointCount);
+ const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex));
+
+ // get control points
+ const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a));
+ const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex));
+
+ // specify first cp, second cp, next vertex
+ path.curve4(
+ aControlNext.getX(), aControlNext.getY(),
+ aControlPrev.getX(), aControlPrev.getY(),
+ aNextPoint.getX(), aNextPoint.getY());
+
+ // prepare next step
+ aCurrentPoint = aNextPoint;
+ }
+ }
+ else
+ {
+ const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(0));
+ ras.move_to_d(aPoint.getX(), aPoint.getY());
+
+ for(sal_uInt32 a(1); a < nPointCount; a++)
+ {
+ const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a));
+ ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY());
+ }
+
+ if(aPolygon.isClosed())
+ {
+ ras.close_polygon();
+ }
+ }
+ }
+ }
+
+ // everything is up and running, go...
+ ras.add_path(curve);
+ render_scanlines(ras,sl,r1);
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::fillGradient
+//////////////////////////////////////////////////////////////////////////////////
+
+void Image::fillGradient( const ParametricPolyPolygon::Values& rValues,
+ const uno::Sequence< double >& rUnoColor1,
+ const uno::Sequence< double >& rUnoColor2,
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const ::basegfx::B2DHomMatrix& rOverallTransform,
+ const rendering::Texture& texture )
+{
+ switch(maDesc.eFormat)
+ {
+ case FMT_R8G8B8:
+ fillGradientImpl<agg::pixfmt_rgb24>(rValues,rUnoColor1,rUnoColor2,rPolyPolygon,rOverallTransform,texture);
+ break;
+ case FMT_A8R8G8B8:
+ fillGradientImpl<agg::pixfmt_rgba32>(rValues,rUnoColor1,rUnoColor2,rPolyPolygon,rOverallTransform,texture);
+ break;
+ default:
+ OSL_ENSURE(false, "Unexpected pixel format");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::fromVCLBitmap
+//////////////////////////////////////////////////////////////////////////////////
+
+bool Image::fromVCLBitmap( ::BitmapEx& rBmpEx )
+{
+ const ::Size aBmpSize( rBmpEx.GetSizePixel() );
+ Image::Description desc;
+ desc.eFormat = rBmpEx.IsTransparent() ? FMT_A8R8G8B8 : FMT_R8G8B8;
+ desc.nWidth = aBmpSize.Width();
+ desc.nHeight = aBmpSize.Height();
+ desc.nStride = 0;
+ const sal_uInt32 nPitch(desc.nWidth*getBytesPerPixel(desc.eFormat)+desc.nStride);
+ desc.pBuffer = new sal_uInt8 [nPitch*desc.nHeight];
+ maDesc = desc;
+ mbBufferHasUserOwnership = false;
+ maRenderingBuffer.attach(static_cast<agg::int8u *>(desc.pBuffer),
+ desc.nWidth,
+ desc.nHeight,
+ nPitch);
+ RawABGRBitmap aBmpData;
+ aBmpData.mnWidth = aBmpSize.Width();
+ aBmpData.mnHeight = aBmpSize.Height();
+ aBmpData.mpBitmapData = static_cast<sal_uInt8 *>(desc.pBuffer);
+ vclBitmapEx2Raw(rBmpEx,aBmpData);
+
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::Image
+//////////////////////////////////////////////////////////////////////////////////
+
+Image::Image( const Description& rDesc ) :
+ maDesc( rDesc ),
+ maRenderingBuffer(),
+ mbBufferHasUserOwnership( rDesc.pBuffer != NULL )
+{
+#if defined(PROFILER)
+ for(int i=0; i<TIMER_MAX; ++i)
+ maElapsedTime[i]=0.0;
+#endif
+
+ // allocate own buffer memory, if not provided
+ sal_uInt8* pBuffer = maDesc.pBuffer;
+ const sal_uInt32 nWidth(maDesc.nWidth);
+ const sal_uInt32 nHeight(maDesc.nHeight);
+ const sal_uInt32 nStride(maDesc.nStride);
+ const sal_uInt32 nPitch(nWidth*getBytesPerPixel(maDesc.eFormat)
+ + nStride);
+
+ if( !pBuffer )
+ pBuffer = new sal_uInt8 [nPitch*nHeight];
+
+ maDesc.pBuffer = pBuffer;
+
+ // attach graphics buffer
+ maRenderingBuffer.attach(
+ static_cast<agg::int8u *>(pBuffer),
+ nWidth,
+ nHeight,
+ nPitch );
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::Image
+//////////////////////////////////////////////////////////////////////////////////
+
+Image::Image( const uno::Reference< rendering::XBitmap >& xBitmap ) :
+ maDesc(),
+ maRenderingBuffer(),
+ mbBufferHasUserOwnership( false )
+{
+#if defined(PROFILER)
+ for(int i=0; i<TIMER_MAX; ++i)
+ maElapsedTime[i]=0.0;
+#endif
+
+ // TODO(F1): Add support for floating point bitmap formats
+ uno::Reference<rendering::XIntegerReadOnlyBitmap> xIntBmp(xBitmap,
+ uno::UNO_QUERY_THROW);
+ ::BitmapEx aBmpEx = ::vcl::unotools::bitmapExFromXBitmap(xIntBmp);
+ if( !!aBmpEx )
+ fromVCLBitmap(aBmpEx);
+
+ // TODO(F2): Fallback to XIntegerBitmap interface for import
+ OSL_ENSURE(false,
+ "Image::Image(): Cannot retrieve bitmap data!" );
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::~Image
+//////////////////////////////////////////////////////////////////////////////////
+
+Image::~Image()
+{
+#if defined(PROFILER)
+
+ double aAccumulatedTime(0.0);
+ for(int i=0; i<TIMER_MAX; ++i)
+ aAccumulatedTime += maElapsedTime[i];
+
+ OSL_TRACE("Image %d - %d %d %d %d %d\n",(int)(aAccumulatedTime*1000.0),
+ (int)(maElapsedTime[TIMER_FILLTEXTUREDPOLYPOLYGON]*1000.0),
+ (int)(maElapsedTime[TIMER_FILLB2DPOLYPOLYGON]*1000.0),
+ (int)(maElapsedTime[TIMER_DRAWPOLYPOLYGON]*1000.0),
+ (int)(maElapsedTime[TIMER_FILLPOLYPOLYGON]*1000.0),
+ (int)(maElapsedTime[TIMER_DRAWBITMAP]*1000.0));
+
+#endif
+
+ if( !mbBufferHasUserOwnership )
+ delete [] maDesc.pBuffer;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::clear
+//////////////////////////////////////////////////////////////////////////////////
+
+template<class pixel_format>
+void Image::clearImpl( sal_uInt8 a,
+ sal_uInt8 r,
+ sal_uInt8 g,
+ sal_uInt8 b )
+{
+ pixel_format pixf(maRenderingBuffer);
+ agg::renderer_base<pixel_format> renb(pixf);
+
+ renb.clear(agg::rgba8(r,g,b,a));
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::clear
+//////////////////////////////////////////////////////////////////////////////////
+
+void Image::clear( sal_uInt8 a,
+ sal_uInt8 r,
+ sal_uInt8 g,
+ sal_uInt8 b )
+{
+ switch(maDesc.eFormat)
+ {
+ case FMT_R8G8B8:
+ return clearImpl<agg::pixfmt_rgb24>(a,r,g,b);
+ case FMT_A8R8G8B8:
+ return clearImpl<agg::pixfmt_rgba32>(a,r,g,b);
+ default:
+ OSL_ENSURE(false, "Unexpected pixel format");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::fillB2DPolyPolygon
+//////////////////////////////////////////////////////////////////////////////////
+
+void Image::fillB2DPolyPolygon(
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+{
+#if defined(PROFILER)
+ ScopeTimer aTimer(TIMER_FILLB2DPOLYPOLYGON,this);
+#endif
+
+ switch(maDesc.eFormat)
+ {
+ case FMT_R8G8B8:
+ fillPolyPolygonImpl<agg::pixfmt_rgb24>(rPolyPolygon,viewState,renderState);
+ break;
+ case FMT_A8R8G8B8:
+ fillPolyPolygonImpl<agg::pixfmt_rgba32>(rPolyPolygon,viewState,renderState);
+ break;
+ default:
+ OSL_ENSURE(false, "Unexpected pixel format");
+ break;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::lock
+//////////////////////////////////////////////////////////////////////////////////
+
+sal_uInt8* Image::lock() const
+{
+ return maDesc.pBuffer;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::unlock
+//////////////////////////////////////////////////////////////////////////////////
+
+void Image::unlock() const
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::getWidth
+//////////////////////////////////////////////////////////////////////////////////
+
+sal_uInt32 Image::getWidth() const
+{
+ return maDesc.nWidth;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::getHeight
+//////////////////////////////////////////////////////////////////////////////////
+
+sal_uInt32 Image::getHeight() const
+{
+ return maDesc.nHeight;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::getStride
+//////////////////////////////////////////////////////////////////////////////////
+
+sal_uInt32 Image::getStride() const
+{
+ return maDesc.nWidth*getBytesPerPixel(maDesc.eFormat)+maDesc.nStride;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::getFormat
+//////////////////////////////////////////////////////////////////////////////////
+
+IColorBuffer::Format Image::getFormat() const
+{
+ return maDesc.eFormat;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::drawPoint
+//////////////////////////////////////////////////////////////////////////////////
+
+void Image::drawPoint( const geometry::RealPoint2D& /*aPoint*/,
+ const rendering::ViewState& /*viewState*/,
+ const rendering::RenderState& /*renderState*/ )
+{
+ OSL_ENSURE(false,
+ "Image::drawPoint(): NYI" );
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::drawLine
+//////////////////////////////////////////////////////////////////////////////////
+
+void Image::drawLine( const geometry::RealPoint2D& aStartPoint,
+ const geometry::RealPoint2D& aEndPoint,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+{
+ ::basegfx::B2DPolygon aLinePoly;
+ aLinePoly.append(
+ ::basegfx::unotools::b2DPointFromRealPoint2D( aStartPoint ) );
+ aLinePoly.append(
+ ::basegfx::unotools::b2DPointFromRealPoint2D( aEndPoint ) );
+
+ drawLinePolyPolygon( ::basegfx::B2DPolyPolygon( aLinePoly ),
+ 1.0,
+ viewState,
+ renderState );
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::drawBezier
+//////////////////////////////////////////////////////////////////////////////////
+
+void Image::drawBezier( const geometry::RealBezierSegment2D& aBezierSegment,
+ const geometry::RealPoint2D& aEndPoint,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+{
+ basegfx::B2DPolygon aBezierPoly;
+
+ aBezierPoly.append(basegfx::B2DPoint(aBezierSegment.Px, aBezierSegment.Py));
+ aBezierPoly.appendBezierSegment(
+ basegfx::B2DPoint(aBezierSegment.C1x, aBezierSegment.C1y),
+ basegfx::B2DPoint(aBezierSegment.C2x, aBezierSegment.C2y),
+ basegfx::unotools::b2DPointFromRealPoint2D(aEndPoint));
+
+ drawLinePolyPolygon( ::basegfx::B2DPolyPolygon( aBezierPoly ),
+ 1.0,
+ viewState,
+ renderState );
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::drawPolyPolygon
+//////////////////////////////////////////////////////////////////////////////////
+
+ImageCachedPrimitiveSharedPtr Image::drawPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+{
+#if defined(PROFILER)
+ ScopeTimer aTimer(TIMER_DRAWPOLYPOLYGON,this);
+#endif
+
+ if( !xPolyPolygon.is() )
+ return ImageCachedPrimitiveSharedPtr();
+
+ drawLinePolyPolygon( ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ),
+ 1.0,
+ viewState,
+ renderState );
+
+ // TODO(F2): Implement sensible ImageCachedPrimitive
+ return ImageCachedPrimitiveSharedPtr();
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::strokePolyPolygon
+//////////////////////////////////////////////////////////////////////////////////
+
+ImageCachedPrimitiveSharedPtr Image::strokePolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const rendering::StrokeAttributes& strokeAttributes )
+{
+ if( !xPolyPolygon.is() )
+ return ImageCachedPrimitiveSharedPtr();
+
+ drawLinePolyPolygon( ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ),
+ strokeAttributes.StrokeWidth,
+ viewState,
+ renderState );
+
+ // TODO(F2): Implement sensible ImageCachedPrimitive
+ return ImageCachedPrimitiveSharedPtr();
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::strokeTexturedPolyPolygon
+//////////////////////////////////////////////////////////////////////////////////
+
+ImageCachedPrimitiveSharedPtr Image::strokeTexturedPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
+ const rendering::ViewState& /*viewState*/,
+ const rendering::RenderState& /*renderState*/,
+ const uno::Sequence< rendering::Texture >& /*textures*/,
+ const ::std::vector< ::boost::shared_ptr<Image> >& /*textureAnnotations*/,
+ const rendering::StrokeAttributes& /*strokeAttributes*/ )
+{
+ OSL_ENSURE(false,
+ "Image::strokeTexturedPolyPolygon(): NYI" );
+
+ // TODO(F2): Implement sensible ImageCachedPrimitive
+ return ImageCachedPrimitiveSharedPtr();
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::strokeTextureMappedPolyPolygon
+//////////////////////////////////////////////////////////////////////////////////
+
+ImageCachedPrimitiveSharedPtr Image::strokeTextureMappedPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
+ const rendering::ViewState& /*viewState*/,
+ const rendering::RenderState& /*renderState*/,
+ const uno::Sequence< rendering::Texture >& /*textures*/,
+ const ::std::vector< ::boost::shared_ptr<Image> >& /*textureAnnotations*/,
+ const uno::Reference< geometry::XMapping2D >& /*xMapping*/,
+ const rendering::StrokeAttributes& /*strokeAttributes*/ )
+{
+ OSL_ENSURE(false,
+ "Image::strokeTextureMappedPolyPolygon(): NYI" );
+
+ // TODO(F2): Implement sensible ImageCachedPrimitive
+ return ImageCachedPrimitiveSharedPtr();
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::fillPolyPolygon
+//////////////////////////////////////////////////////////////////////////////////
+
+template<class pixel_format>
+ImageCachedPrimitiveSharedPtr Image::fillPolyPolygonImpl(
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+{
+#if defined(PROFILER)
+ ScopeTimer aTimer(TIMER_FILLPOLYPOLYGON,this);
+#endif
+
+ ARGB aFillColor;
+
+ ::basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
+ setupPolyPolygon( aPolyPolygon, true, aFillColor, viewState, renderState );
+
+ if( !aPolyPolygon.count() )
+ return ImageCachedPrimitiveSharedPtr();
+
+ pixel_format pixf(maRenderingBuffer);
+ agg::renderer_base<pixel_format> renb(pixf);
+
+ // Scanline renderer for solid filling.
+ agg::renderer_scanline_aa_solid<agg::renderer_base<pixel_format> > ren(renb);
+
+ // Rasterizer & scanline
+ agg::rasterizer_scanline_aa<> ras;
+ agg::scanline_p8 sl;
+
+ agg::path_storage path;
+ agg::conv_curve<agg::path_storage> curve(path);
+
+ for(sal_uInt32 nPolygon(0); nPolygon < aPolyPolygon.count(); nPolygon++)
+ {
+ const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(nPolygon));
+ const sal_uInt32 nPointCount(aPolygon.count());
+
+ if(nPointCount)
+ {
+ if(aPolygon.areControlPointsUsed())
+ {
+ // prepare edge-based loop
+ basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0));
+ const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount);
+
+ // first vertex
+ path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY());
+
+ for(sal_uInt32 a(0); a < nEdgeCount; a++)
+ {
+ // access next point
+ const sal_uInt32 nNextIndex((a + 1) % nPointCount);
+ const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex));
+
+ // get control points
+ const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a));
+ const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex));
+
+ // specify first cp, second cp, next vertex
+ path.curve4(
+ aControlNext.getX(), aControlNext.getY(),
+ aControlPrev.getX(), aControlPrev.getY(),
+ aNextPoint.getX(), aNextPoint.getY());
+
+ // prepare next step
+ aCurrentPoint = aNextPoint;
+ }
+ }
+ else
+ {
+ const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(0));
+ ras.move_to_d(aPoint.getX(), aPoint.getY());
+
+ for(sal_uInt32 a(1); a < nPointCount; a++)
+ {
+ const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a));
+ ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY());
+ }
+
+ if(aPolygon.isClosed())
+ {
+ ras.close_polygon();
+ }
+ }
+ }
+ }
+
+ ras.add_path(curve);
+ agg::rgba8 fillcolor(aFillColor.Color.r,aFillColor.Color.g,aFillColor.Color.b,aFillColor.Color.a);
+ ren.color(fillcolor);
+ agg::render_scanlines(ras, sl, ren);
+
+ // TODO(F2): Implement sensible ImageCachedPrimitive
+ return ImageCachedPrimitiveSharedPtr();
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::fillPolyPolygon
+//////////////////////////////////////////////////////////////////////////////////
+
+ImageCachedPrimitiveSharedPtr Image::fillPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+{
+ if( !xPolyPolygon.is() )
+ return ImageCachedPrimitiveSharedPtr();
+
+ ::basegfx::B2DPolyPolygon aPoly(
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ) );
+
+ switch(maDesc.eFormat)
+ {
+ case FMT_R8G8B8:
+ return fillPolyPolygonImpl<agg::pixfmt_rgb24>(aPoly,viewState,renderState);
+ case FMT_A8R8G8B8:
+ return fillPolyPolygonImpl<agg::pixfmt_rgba32>(aPoly,viewState,renderState);
+ default:
+ OSL_ENSURE(false, "Unexpected pixel format");
+ break;
+ }
+
+ return ImageCachedPrimitiveSharedPtr();
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::fillTexturedPolyPolygon
+//////////////////////////////////////////////////////////////////////////////////
+
+ImageCachedPrimitiveSharedPtr Image::fillTexturedPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const uno::Sequence< rendering::Texture >& textures,
+ const ::std::vector< ::boost::shared_ptr<Image> >& textureAnnotations )
+{
+#if defined(PROFILER)
+ ScopeTimer aTimer(TIMER_FILLTEXTUREDPOLYPOLYGON,this);
+#endif
+
+ if( !xPolyPolygon.is() )
+ return ImageCachedPrimitiveSharedPtr();
+
+ ::basegfx::B2DPolyPolygon aPoly(
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ) );
+ ARGB aFillColor;
+
+ setupPolyPolygon( aPoly, true, aFillColor, viewState, renderState );
+
+ if( !aPoly.count() )
+ return ImageCachedPrimitiveSharedPtr();
+
+ ::basegfx::B2DHomMatrix aViewTransform;
+ ::basegfx::B2DHomMatrix aRenderTransform;
+ ::basegfx::B2DHomMatrix aTextureTransform;
+
+ ::basegfx::unotools::homMatrixFromAffineMatrix(aTextureTransform,
+ textures[0].AffineTransform);
+ ::basegfx::unotools::homMatrixFromAffineMatrix(aRenderTransform,
+ renderState.AffineTransform);
+ ::basegfx::unotools::homMatrixFromAffineMatrix(aViewTransform,
+ viewState.AffineTransform);
+ aTextureTransform *= aRenderTransform;
+
+ // TODO(F1): Multi-texturing
+ if( textures[0].Gradient.is() )
+ {
+ aTextureTransform *= aViewTransform;
+
+ // try to cast XParametricPolyPolygon2D reference to
+ // our implementation class.
+ ::canvas::ParametricPolyPolygon* pGradient =
+ dynamic_cast< ::canvas::ParametricPolyPolygon* >( textures[0].Gradient.get() );
+
+ if( pGradient )
+ {
+ const ParametricPolyPolygon::Values& rValues(
+ pGradient->getValues() );
+
+ // TODO: use all the colors and place them on given positions/stops
+ // TODO(E1): Return value
+ // TODO(F1): FillRule
+ fillGradient( rValues,
+ rValues.maColors [0],
+ rValues.maColors [rValues.maColors.getLength () - 1],
+ aPoly,
+ aTextureTransform,
+ textures[0] );
+ }
+ }
+ else if( textures[0].Bitmap.is() )
+ {
+ ImageSharedPtr pTexture;
+
+ if( textureAnnotations[0].get() != NULL )
+ pTexture = textureAnnotations[0];
+ else
+ pTexture.reset( new Image( textures[0].Bitmap ) );
+
+ const sal_uInt32 nWidth(pTexture->maDesc.nWidth);
+ const sal_uInt32 nHeight(pTexture->maDesc.nHeight);
+
+ // scale texture into one-by-one unit rect.
+ aTextureTransform.scale(1.0f/nWidth,
+ 1.0f/nHeight);
+
+ // TODO(E1): Return value
+ // TODO(F1): FillRule
+ return fillTexturedPolyPolygon( *pTexture,
+ aPoly,
+ aTextureTransform,
+ aViewTransform,
+ textures[0] );
+ }
+
+ // TODO(F2): Implement sensible ImageCachedPrimitive
+ return ImageCachedPrimitiveSharedPtr();
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::fillTextureMappedPolyPolygon
+//////////////////////////////////////////////////////////////////////////////////
+
+ImageCachedPrimitiveSharedPtr Image::fillTextureMappedPolyPolygon(
+ const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
+ const rendering::ViewState& /*viewState*/,
+ const rendering::RenderState& /*renderState*/,
+ const uno::Sequence< rendering::Texture >& /*textures*/,
+ const ::std::vector< ::boost::shared_ptr<Image> >& /*textureAnnotations*/,
+ const uno::Reference< geometry::XMapping2D >& /*xMapping*/ )
+{
+ OSL_ENSURE(false,
+ "Image::fillTextureMappedPolyPolygon(): NYI" );
+
+ // TODO(F2): Implement sensible ImageCachedPrimitive
+ return ImageCachedPrimitiveSharedPtr();
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::drawBitmap
+//////////////////////////////////////////////////////////////////////////////////
+
+ImageCachedPrimitiveSharedPtr Image::drawBitmap(
+ const uno::Reference< rendering::XBitmap >& xBitmap,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+{
+#if defined(PROFILER)
+ ScopeTimer aTimer(TIMER_DRAWBITMAP,this);
+#endif
+
+ // TODO(P3): Implement bitmap caching
+ if( !xBitmap.is() )
+ return ImageCachedPrimitiveSharedPtr();
+/*
+ XBitmapAccessor accessor( xBitmap );
+ if(accessor.isValid())
+ {
+ Image aImage( accessor.getDesc() );
+
+ implDrawBitmap( aImage,
+ viewState,
+ renderState );
+
+ // TODO(F2): Implement sensible ImageCachedPrimitive
+ return ImageCachedPrimitiveSharedPtr();
+ }
+*/
+ Image aImage( xBitmap );
+
+ return implDrawBitmap( aImage,viewState,renderState );
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::drawBitmap
+//////////////////////////////////////////////////////////////////////////////////
+
+ImageCachedPrimitiveSharedPtr Image::drawBitmap(
+ const ImageSharedPtr& rImage,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+{
+#if defined(PROFILER)
+ ScopeTimer aTimer(TIMER_DRAWBITMAP,this);
+#endif
+
+ // TODO(P3): Implement bitmap caching
+ if( !rImage )
+ return ImageCachedPrimitiveSharedPtr();
+
+ return implDrawBitmap( *rImage,
+ viewState,
+ renderState );
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::drawBitmapModulated
+//////////////////////////////////////////////////////////////////////////////////
+
+ImageCachedPrimitiveSharedPtr Image::drawBitmapModulated(
+ const uno::Reference< rendering::XBitmap >& xBitmap,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+{
+ // TODO(P3): Implement bitmap caching
+ if( !xBitmap.is() )
+ return ImageCachedPrimitiveSharedPtr();
+
+ Image aImage( xBitmap );
+
+ // TODO(F2): Distinguish modulated and unmodulated bitmap output
+ return implDrawBitmap( aImage,viewState,renderState );
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Image::drawBitmapModulated
+//////////////////////////////////////////////////////////////////////////////////
+
+ImageCachedPrimitiveSharedPtr Image::drawBitmapModulated(
+ const ImageSharedPtr& rImage,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+{
+ // TODO(P3): Implement bitmap caching
+ if( !rImage )
+ return ImageCachedPrimitiveSharedPtr();
+
+ // TODO(F2): Distinguish modulated and unmodulated bitmap output
+ return implDrawBitmap( *rImage,viewState,renderState );
+}
+
+}
diff --git a/canvas/source/tools/image.hxx b/canvas/source/tools/image.hxx
new file mode 100644
index 000000000000..1c62c7d6276b
--- /dev/null
+++ b/canvas/source/tools/image.hxx
@@ -0,0 +1,298 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_CANVAS_IMAGE_HXX
+#define INCLUDED_CANVAS_IMAGE_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <canvas/rendering/icolorbuffer.hxx>
+#include <canvas/parametricpolypolygon.hxx>
+#include "imagecachedprimitive.hxx"
+
+#include <canvas/elapsedtime.hxx>
+
+#include "image_sysprereq.h"
+
+struct BitmapSystemData;
+class BitmapEx;
+
+namespace canvas
+{
+ class Image : public IColorBuffer
+ {
+ public:
+ /// The description of the image
+ struct Description
+ {
+ IColorBuffer::Format eFormat;
+ sal_uInt32 nWidth;
+ sal_uInt32 nHeight;
+ sal_uInt32 nStride;
+ sal_uInt8* pBuffer;
+ };
+
+ /** Create a new image with the attributes passed as argument.
+ */
+ explicit Image( const Description& desc );
+
+ /** Create a new image from the XBitmap passed as argument
+ */
+ explicit Image( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XBitmap >& xBitmap );
+
+
+ virtual ~Image();
+
+ /** Retrieve desciption of image layout
+ */
+ const Description& getDescription() const { return maDesc; }
+
+ /** Clear image with uniform color
+ */
+ void clear( sal_uInt8 a,
+ sal_uInt8 r,
+ sal_uInt8 g,
+ sal_uInt8 b );
+
+ void fillB2DPolyPolygon(
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+
+
+ // IColorBuffer interface implementation
+ // =====================================
+
+ virtual sal_uInt8* lock() const;
+ virtual void unlock() const;
+ virtual sal_uInt32 getWidth() const;
+ virtual sal_uInt32 getHeight() const;
+ virtual sal_uInt32 getStride() const;
+ virtual Format getFormat() const;
+
+
+ // High-level drawing operations (from the XCanvas interface)
+ // ==========================================================
+
+ void drawPoint( const ::com::sun::star::geometry::RealPoint2D& aPoint,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+ void drawLine( const ::com::sun::star::geometry::RealPoint2D& aStartPoint,
+ const ::com::sun::star::geometry::RealPoint2D& aEndPoint,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+ void drawBezier( const ::com::sun::star::geometry::RealBezierSegment2D& aBezierSegment,
+ const ::com::sun::star::geometry::RealPoint2D& aEndPoint,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+ ImageCachedPrimitiveSharedPtr drawPolyPolygon(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+
+ ImageCachedPrimitiveSharedPtr strokePolyPolygon(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState,
+ const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes );
+ ImageCachedPrimitiveSharedPtr strokeTexturedPolyPolygon(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState,
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::rendering::Texture >& textures,
+ const ::std::vector< ::boost::shared_ptr<Image> >& textureAnnotations,
+ const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes );
+ ImageCachedPrimitiveSharedPtr strokeTextureMappedPolyPolygon(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState,
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::rendering::Texture >& textures,
+ const ::std::vector< ::boost::shared_ptr<Image> >& textureAnnotations,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::geometry::XMapping2D >& xMapping,
+ const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes );
+ ImageCachedPrimitiveSharedPtr fillPolyPolygon(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+ ImageCachedPrimitiveSharedPtr fillTexturedPolyPolygon(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState,
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::rendering::Texture >& textures,
+ const ::std::vector< ::boost::shared_ptr<Image> >& textureAnnotations );
+ ImageCachedPrimitiveSharedPtr fillTextureMappedPolyPolygon(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState,
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::rendering::Texture >& textures,
+ const ::std::vector< ::boost::shared_ptr<Image> >& textureAnnotations,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::geometry::XMapping2D >& xMapping );
+
+ ImageCachedPrimitiveSharedPtr drawBitmap(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XBitmap >& xBitmap,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+ ImageCachedPrimitiveSharedPtr drawBitmap(
+ const ::boost::shared_ptr<Image>& rImage,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+
+ ImageCachedPrimitiveSharedPtr drawBitmapModulated(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XBitmap >& xBitmap,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+ ImageCachedPrimitiveSharedPtr drawBitmapModulated(
+ const ::boost::shared_ptr<Image>& rImage,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+
+ private:
+ void drawLinePolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly,
+ double fStrokeWidth,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+
+ ImageCachedPrimitiveSharedPtr implDrawBitmap(
+ const Image& rBitmap,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+
+ ImageCachedPrimitiveSharedPtr fillTexturedPolyPolygon(
+ const Image& rTexture,
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const ::basegfx::B2DHomMatrix& rOverallTransform,
+ const ::basegfx::B2DHomMatrix& rViewTransform,
+ const ::com::sun::star::rendering::Texture& texture );
+
+ void fillGradient( const ParametricPolyPolygon::Values& rValues,
+ const ::com::sun::star::uno::Sequence< double >& rColor1,
+ const ::com::sun::star::uno::Sequence< double >& rColor2,
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const ::basegfx::B2DHomMatrix& rOverallTransform,
+ const ::com::sun::star::rendering::Texture& texture );
+ bool fromVCLBitmap( ::BitmapEx& rBmpEx );
+
+ template<class pixel_format>
+ void drawLinePolyPolygonImpl( const ::basegfx::B2DPolyPolygon& rPoly,
+ double fStrokeWidth,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+
+ template<class pixel_format,class span_gen_type>
+ ImageCachedPrimitiveSharedPtr fillTexturedPolyPolygonImpl(
+ const Image& rTexture,
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const ::basegfx::B2DHomMatrix& rOverallTransform,
+ const ::basegfx::B2DHomMatrix& rViewTransform,
+ const ::com::sun::star::rendering::Texture& texture );
+
+ template<class pixel_format>
+ void fillGradientImpl( const ParametricPolyPolygon::Values& rValues,
+ const ::com::sun::star::uno::Sequence< double >& rUnoColor1,
+ const ::com::sun::star::uno::Sequence< double >& rUnoColor2,
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const ::basegfx::B2DHomMatrix& rOverallTransform,
+ const ::com::sun::star::rendering::Texture& texture );
+
+ template<class pixel_format>
+ ImageCachedPrimitiveSharedPtr fillPolyPolygonImpl(
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+
+ template<class pixel_format> void clearImpl( sal_uInt8 a,
+ sal_uInt8 r,
+ sal_uInt8 g,
+ sal_uInt8 b );
+
+ /** Image description
+ */
+ Description maDesc;
+
+ /** the graphics buffer is a simple array
+ where each element points to the start
+ of a scanline in consecutive order.
+ */
+ agg::rendering_buffer maRenderingBuffer;
+
+ /// Whether maRenderingBuffer is owned by the client of this object
+ bool mbBufferHasUserOwnership;
+
+#if defined(PROFILER)
+
+ enum constant
+ {
+ TIMER_FILLTEXTUREDPOLYPOLYGON,
+ TIMER_FILLB2DPOLYPOLYGON,
+ TIMER_DRAWPOLYPOLYGON,
+ TIMER_FILLPOLYPOLYGON,
+ TIMER_DRAWBITMAP,
+ TIMER_MAX
+ };
+
+ double maElapsedTime[TIMER_MAX];
+
+ struct ScopeTimer
+ {
+ ScopeTimer( constant aConstant, Image *pImage ) :
+ maConstant(aConstant),mpImage(pImage)
+ {}
+
+ ~ScopeTimer()
+ {
+ mpImage->maElapsedTime[maConstant] += maTimer.getElapsedTime();
+ }
+
+ constant maConstant;
+ Image* mpImage;
+ ::canvas::tools::ElapsedTime maTimer;
+ };
+
+#endif
+ };
+
+ typedef ::boost::shared_ptr< Image > ImageSharedPtr;
+
+}
+
+#endif /* INCLUDED_CANVAS_IMAGE_HXX */
diff --git a/canvas/source/tools/image_sysprereq.h b/canvas/source/tools/image_sysprereq.h
new file mode 100644
index 000000000000..ad81259c75c7
--- /dev/null
+++ b/canvas/source/tools/image_sysprereq.h
@@ -0,0 +1,102 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if defined __GNUC__
+#pragma GCC system_header
+#elif defined __SUNPRO_CC
+#pragma disable_warn
+#elif defined _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <agg2/agg_rendering_buffer.h>
+
+#ifdef CANVAS_IMAGE_CXX
+
+//////////////////////////////////////////////////////////////////////////////////
+// includes from antigrain [i would love to write this stuff by myself]
+//////////////////////////////////////////////////////////////////////////////////
+
+#include <agg2/agg_rendering_buffer.h>
+#include <agg2/agg_pixfmt_rgb.h>
+#include <agg2/agg_pixfmt_rgba.h>
+#include <agg2/agg_renderer_base.h>
+#include <agg2/agg_color_rgba.h>
+#include <agg2/agg_rasterizer_outline_aa.h>
+#include <agg2/agg_rasterizer_scanline_aa.h>
+#include <agg2/agg_scanline_p.h>
+#include <agg2/agg_scanline_u.h>
+#include <agg2/agg_renderer_scanline.h>
+#include <agg2/agg_renderer_outline_aa.h>
+#include <agg2/agg_renderer_primitives.h>
+#include <agg2/agg_path_storage.h>
+#if AGG_VERSION == 2300
+#include <agg2/agg_span_pattern.h>
+#endif
+#include <agg2/agg_span_pattern_rgba.h>
+#if AGG_VERSION >= 2400
+#include <agg2/agg_span_image_filter_rgb.h>
+#include <agg2/agg_span_image_filter_rgba.h>
+#else
+#include <agg2/agg_span_pattern_resample_rgb.h>
+#include <agg2/agg_span_pattern_resample_rgba.h>
+#endif
+#include <agg2/agg_span_interpolator_linear.h>
+#include <agg2/agg_span_gradient.h>
+#if AGG_VERSION == 2300
+#include <agg2/agg_span_image_resample_rgb.h>
+#include <agg2/agg_span_image_resample_rgba.h>
+#endif
+#if AGG_VERSION >= 2400
+#include <agg2/agg_span_allocator.h>
+#endif
+#include <agg2/agg_image_filters.h>
+#if AGG_VERSION >= 2400
+#include <agg2/agg_image_accessors.h>
+#endif
+#include <agg2/agg_dda_line.h>
+#include <agg2/agg_scanline_storage_aa.h>
+#include <agg2/agg_scanline_storage_bin.h>
+#include <agg2/agg_scanline_bin.h>
+#include <agg2/agg_path_storage_integer.h>
+#include <agg2/agg_conv_contour.h>
+#include <agg2/agg_conv_curve.h>
+#include <agg2/agg_conv_stroke.h>
+#include <agg2/agg_conv_transform.h>
+#include <agg2/agg_trans_affine.h>
+#include <agg2/agg_font_cache_manager.h>
+#include <agg2/agg_bitset_iterator.h>
+#include <agg2/agg_path_storage.h>
+
+#endif // CANVAS_IMAGE_CXX
+
+#if defined __SUNPRO_CC
+#pragma enable_warn
+#elif defined _MSC_VER
+#pragma warning(pop)
+#endif
+
diff --git a/canvas/source/tools/imagecachedprimitive.hxx b/canvas/source/tools/imagecachedprimitive.hxx
new file mode 100644
index 000000000000..dfcf2bc6a831
--- /dev/null
+++ b/canvas/source/tools/imagecachedprimitive.hxx
@@ -0,0 +1,57 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_CANVAS_IMAGECACHEDPRIMITIVE_HXX
+#define INCLUDED_CANVAS_IMAGECACHEDPRIMITIVE_HXX
+
+#include <canvas/rendering/icachedprimitive.hxx>
+
+#include <boost/shared_ptr.hpp>
+
+
+namespace canvas
+{
+ /** Objects with this interface are returned from every Image
+ render operation.
+
+ These objects can be used to implement the
+ rendering::XCachedPrimitive interface, which in turn caches
+ render state and objects to facilitate quick redraws.
+
+ Derived from ICachedPrimitive, to add the setImage() method
+ (which, strictly speaking, is a technicality, because Image
+ cannot create objects with a shared_ptr to itself).
+ */
+ struct ImageCachedPrimitive : public ICachedPrimitive
+ {
+ virtual void setImage( const ::boost::shared_ptr< class Image >& rTargetImage ) = 0;
+ };
+
+ typedef ::boost::shared_ptr< ImageCachedPrimitive > ImageCachedPrimitiveSharedPtr;
+}
+
+#endif /* INCLUDED_CANVAS_IMAGECACHEDPRIMITIVE_HXX */
diff --git a/canvas/source/tools/makefile.mk b/canvas/source/tools/makefile.mk
new file mode 100644
index 000000000000..9d9e5ba002bf
--- /dev/null
+++ b/canvas/source/tools/makefile.mk
@@ -0,0 +1,101 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=canvas
+TARGET=canvastools
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Common ----------------------------------------------------------
+
+.IF "$(verbose)"!="" || "$(VERBOSE)"!=""
+CDEFS+= -DVERBOSE
+.ENDIF
+.IF "$(profiler)"!="" || "$(PROFILER)"!=""
+CDEFS+= -DPROFILER
+.ENDIF
+
+#CFLAGS +:= /Ox /Ot # THIS IS IMPORTANT
+
+
+.IF "$(L10N_framework)"==""
+SLOFILES = \
+ $(SLO)$/cachedprimitivebase.obj \
+ $(SLO)$/canvascustomspritehelper.obj \
+ $(SLO)$/canvastools.obj \
+ $(SLO)$/elapsedtime.obj \
+ $(SLO)$/parametricpolypolygon.obj \
+ $(SLO)$/prioritybooster.obj \
+ $(SLO)$/propertysethelper.obj \
+ $(SLO)$/spriteredrawmanager.obj \
+ $(SLO)$/surface.obj \
+ $(SLO)$/surfaceproxy.obj \
+ $(SLO)$/surfaceproxymanager.obj \
+ $(SLO)$/pagemanager.obj \
+ $(SLO)$/page.obj \
+ $(SLO)$/verifyinput.obj
+
+SHL1TARGET= $(TARGET)$(DLLPOSTFIX)
+SHL1IMPLIB= i$(TARGET)
+SHL1STDLIBS= $(SALLIB) $(CPPULIB) $(BASEGFXLIB) $(CPPUHELPERLIB) $(COMPHELPERLIB) $(VCLLIB) $(TKLIB) $(TOOLSLIB)
+
+.IF "$(ENABLE_AGG)"=="YES"
+ SLOFILES += $(SLO)$/bitmap.obj \
+ $(SLO)$/image.obj
+
+ .IF "$(AGG_VERSION)"!=""
+ CDEFS += -DAGG_VERSION=$(AGG_VERSION)
+ .ENDIF
+ SHL1STDLIBS += $(AGGLIB)
+.ENDIF
+
+SHL1LIBS= $(SLB)$/$(TARGET).lib
+
+SHL1DEF= $(MISC)$/$(SHL1TARGET).def
+DEF1NAME =$(SHL1TARGET)
+DEF1DEPN =$(MISC)$/$(SHL1TARGET).flt \
+ $(LIB1TARGET)
+
+DEF1DES =Canvastools
+DEFLIB1NAME =$(TARGET)
+
+.IF "$(GUI)" == "WNT"
+SHL1STDLIBS += $(WINMMLIB) $(KERNEL32LIB)
+.ENDIF
+.ENDIF
+
+# ==========================================================================
+
+.INCLUDE : target.mk
+
+$(MISC)$/$(SHL1TARGET).flt : makefile.mk $(TARGET).flt
+ @$(TYPE) $(TARGET).flt > $@
diff --git a/canvas/source/tools/page.cxx b/canvas/source/tools/page.cxx
new file mode 100644
index 000000000000..5035c0e81916
--- /dev/null
+++ b/canvas/source/tools/page.cxx
@@ -0,0 +1,152 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include <boost/bind.hpp>
+#include "page.hxx"
+
+namespace canvas
+{
+ Page::Page( const IRenderModuleSharedPtr &rRenderModule ) :
+ mpRenderModule(rRenderModule),
+ mpSurface(rRenderModule->createSurface(::basegfx::B2ISize()))
+ {
+ }
+
+ void Page::validate()
+ {
+ if(!(isValid()))
+ {
+ ::std::for_each( mpFragments.begin(),
+ mpFragments.end(),
+ ::boost::mem_fn(&PageFragment::refresh));
+ }
+ }
+
+ bool Page::isValid() const
+ {
+ return mpSurface && mpSurface->isValid();
+ }
+
+ FragmentSharedPtr Page::allocateSpace( const ::basegfx::B2ISize& rSize )
+ {
+ SurfaceRect rect(rSize);
+ if(insert(rect))
+ {
+ FragmentSharedPtr pFragment(new PageFragment(rect,this));
+ mpFragments.push_back(pFragment);
+ return pFragment;
+ }
+
+ return FragmentSharedPtr();
+ }
+
+ bool Page::nakedFragment( const FragmentSharedPtr& pFragment )
+ {
+ SurfaceRect rect(pFragment->getSize());
+ if(insert(rect))
+ {
+ pFragment->setPage(this);
+ mpFragments.push_back(pFragment);
+ return true;
+ }
+
+ return false;
+ }
+
+ void Page::free( const FragmentSharedPtr& pFragment )
+ {
+ // the fragment passes as argument is no longer
+ // dedicated to this page. either it is about to
+ // be relocated to some other page or it will
+ // currently be deleted. in either case, simply
+ // remove the reference from our internal storage.
+ FragmentContainer_t::iterator it(
+ std::remove(
+ mpFragments.begin(),mpFragments.end(),pFragment));
+ mpFragments.erase(it,mpFragments.end());
+ }
+
+ bool Page::insert( SurfaceRect& r )
+ {
+ const FragmentContainer_t::const_iterator aEnd(mpFragments.end());
+ FragmentContainer_t::const_iterator it(mpFragments.begin());
+ while(it != aEnd)
+ {
+ const SurfaceRect &rect = (*it)->getRect();
+ const sal_Int32 x = rect.maPos.getX();
+ const sal_Int32 y = rect.maPos.getY();
+ // to avoid interpolation artifacts from other textures,
+ // one pixel gap between them
+ const sal_Int32 w = rect.maSize.getX()+1;
+ const sal_Int32 h = rect.maSize.getY()+1;
+
+ // probe location to the right
+ r.maPos.setX(x+w);
+ r.maPos.setY(y);
+ if(isValidLocation(r))
+ return true;
+
+ // probe location at bottom
+ r.maPos.setX(x);
+ r.maPos.setY(y+h);
+ if(isValidLocation(r))
+ return true;
+
+ ++it;
+ }
+
+ r.maPos.setX(0);
+ r.maPos.setY(0);
+
+ return isValidLocation(r);
+ }
+
+ bool Page::isValidLocation( const SurfaceRect& r ) const
+ {
+ // the rectangle passed as argument has a valid
+ // location if and only if there's no intersection
+ // with existing areas.
+ SurfaceRect aBoundary(mpRenderModule->getPageSize()-basegfx::B2IVector(1,1));
+ if( !r.inside(aBoundary) )
+ return false;
+
+ const FragmentContainer_t::const_iterator aEnd(mpFragments.end());
+ FragmentContainer_t::const_iterator it(mpFragments.begin());
+ while(it != aEnd)
+ {
+ if(r.intersection((*it)->getRect()))
+ return false;
+
+ ++it;
+ }
+
+ return true;
+ }
+}
diff --git a/canvas/source/tools/page.hxx b/canvas/source/tools/page.hxx
new file mode 100644
index 000000000000..51b770ad4ade
--- /dev/null
+++ b/canvas/source/tools/page.hxx
@@ -0,0 +1,157 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_CANVAS_PAGE_HXX
+#define INCLUDED_CANVAS_PAGE_HXX
+
+#include <basegfx/vector/b2isize.hxx>
+#include <basegfx/range/b2irectangle.hxx>
+#include <canvas/rendering/icolorbuffer.hxx>
+#include <canvas/rendering/irendermodule.hxx>
+#include <canvas/rendering/isurface.hxx>
+
+#include <list>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include "surfacerect.hxx"
+
+namespace canvas
+{
+ class PageFragment;
+
+ typedef ::boost::shared_ptr< PageFragment > FragmentSharedPtr;
+
+ /** One page of IRenderModule-provided texture space
+ */
+ class Page
+ {
+ public:
+ Page( const IRenderModuleSharedPtr& rRenderModule );
+
+ FragmentSharedPtr allocateSpace( const ::basegfx::B2ISize& rSize );
+ bool nakedFragment( const FragmentSharedPtr& pFragment );
+ void free( const FragmentSharedPtr& pFragment );
+ const ISurfaceSharedPtr& getSurface() const { return mpSurface; }
+ bool isValid() const;
+ void validate();
+
+ private:
+ typedef std::list<FragmentSharedPtr> FragmentContainer_t;
+
+ IRenderModuleSharedPtr mpRenderModule;
+ ISurfaceSharedPtr mpSurface;
+ FragmentContainer_t mpFragments;
+
+ bool insert( SurfaceRect& r );
+ bool isValidLocation( const SurfaceRect& r ) const;
+ };
+
+ typedef ::boost::shared_ptr< Page > PageSharedPtr;
+
+
+ /** A part of a page, which gets allocated to a surface
+ */
+ class PageFragment
+ {
+ public:
+ PageFragment( const SurfaceRect& r,
+ Page* pPage ) :
+ mpPage(pPage),
+ maRect(r),
+ mpBuffer(),
+ maSourceOffset()
+ {
+ }
+
+ /// Creates a 'naked' fragment.
+ PageFragment( const ::basegfx::B2ISize& rSize ) :
+ mpPage(NULL),
+ maRect(rSize),
+ mpBuffer(),
+ maSourceOffset()
+ {
+ }
+
+ bool isNaked() const { return (mpPage == NULL); }
+ const SurfaceRect& getRect() const { return maRect; }
+ const ::basegfx::B2IPoint& getPos() const { return maRect.maPos; }
+ const ::basegfx::B2ISize& getSize() const { return maRect.maSize; }
+ void setColorBuffer( const IColorBufferSharedPtr& pColorBuffer ) { mpBuffer=pColorBuffer; }
+ void setSourceOffset( const ::basegfx::B2IPoint& rOffset ) { maSourceOffset=rOffset; }
+ void setPage( Page* pPage ) { mpPage=pPage; }
+
+ void free( const FragmentSharedPtr& pFragment )
+ {
+ if(mpPage)
+ mpPage->free(pFragment);
+
+ mpPage=NULL;
+ }
+
+ bool select( bool bRefresh )
+ {
+ // request was made to select this fragment,
+ // but this fragment has not been located on any
+ // of the available pages, we need to hurry now.
+ if(!(mpPage))
+ return false;
+
+ ISurfaceSharedPtr pSurface(mpPage->getSurface());
+
+ // select this surface before wiping the contents
+ // since a specific implementation could trigger
+ // a rendering operation here...
+ if(!(pSurface->selectTexture()))
+ return false;
+
+ // call refresh() if requested, otherwise we're up to date...
+ return bRefresh ? refresh() : true;
+ }
+
+ bool refresh()
+ {
+ if(!(mpPage))
+ return false;
+
+ ISurfaceSharedPtr pSurface(mpPage->getSurface());
+
+ return pSurface->update( maRect.maPos,
+ ::basegfx::B2IRectangle(
+ maSourceOffset,
+ maSourceOffset + maRect.maSize ),
+ *mpBuffer );
+ }
+
+ private:
+ Page* mpPage;
+ SurfaceRect maRect;
+ IColorBufferSharedPtr mpBuffer;
+ ::basegfx::B2IPoint maSourceOffset;
+ };
+}
+
+#endif
diff --git a/canvas/source/tools/pagemanager.cxx b/canvas/source/tools/pagemanager.cxx
new file mode 100644
index 000000000000..b867b432857c
--- /dev/null
+++ b/canvas/source/tools/pagemanager.cxx
@@ -0,0 +1,216 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include <boost/bind.hpp>
+#include "pagemanager.hxx"
+
+namespace canvas
+{
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // PageManager
+ //////////////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // PageManager::allocateSpace
+ //////////////////////////////////////////////////////////////////////////////////
+
+ FragmentSharedPtr PageManager::allocateSpace( const ::basegfx::B2ISize& rSize )
+ {
+ // we are asked to find a location for the requested size.
+ // first we try to satisfy the request from the
+ // remaining space in the existing pages.
+ const PageContainer_t::iterator aEnd(maPages.end());
+ PageContainer_t::iterator it(maPages.begin());
+ while(it != aEnd)
+ {
+ FragmentSharedPtr pFragment((*it)->allocateSpace(rSize));
+ if(pFragment)
+ {
+ // the page created a new fragment, since we maybe want
+ // to consolidate sparse pages we keep a reference to
+ // the fragment.
+ maFragments.push_back(pFragment);
+ return pFragment;
+ }
+
+ ++it;
+ }
+
+ // otherwise try to create a new page and allocate space there...
+ PageSharedPtr pPage(new Page(mpRenderModule));
+ if(pPage->isValid())
+ {
+ maPages.push_back(pPage);
+ FragmentSharedPtr pFragment(pPage->allocateSpace(rSize));
+ maFragments.push_back(pFragment);
+ return pFragment;
+ }
+
+ // the rendermodule failed to create a new page [maybe out
+ // of videomemory], and all other pages could not take
+ // the new request. we decide to create a 'naked' fragment
+ // which will receive its location later.
+ FragmentSharedPtr pFragment(new PageFragment(rSize));
+ maFragments.push_back(pFragment);
+ return pFragment;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // PageManager::free
+ //////////////////////////////////////////////////////////////////////////////////
+
+ void PageManager::free( const FragmentSharedPtr& pFragment )
+ {
+ // erase the reference to the given fragment from our
+ // internal container.
+ FragmentContainer_t::iterator it(
+ std::remove(
+ maFragments.begin(),maFragments.end(),pFragment));
+ maFragments.erase(it,maFragments.end());
+
+ // let the fragment itself know about it...
+ // we need to pass 'this' as argument since the fragment
+ // needs to pass this to the page and can't create
+ // shared_ptr from itself...
+ pFragment->free(pFragment);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // PageManager::nakedFragment
+ //////////////////////////////////////////////////////////////////////////////////
+
+ void PageManager::nakedFragment( const FragmentSharedPtr& pFragment )
+ {
+ if(maPages.empty())
+ return;
+
+ // okay, one last chance is left, we try all available
+ // pages again. maybe some other fragment was deleted
+ // and we can exploit the space.
+ while(!(relocate(pFragment)))
+ {
+ // no way, we need to free up some space...
+ // TODO(F1): this is a heuristic, could
+ // be designed as a policy.
+ const FragmentContainer_t::const_iterator aEnd(maFragments.end());
+ FragmentContainer_t::const_iterator candidate(maFragments.begin());
+ while(candidate != aEnd)
+ {
+ if(!((*candidate)->isNaked()))
+ break;
+ ++candidate;
+ }
+
+ const ::basegfx::B2ISize& rSize((*candidate)->getSize());
+ sal_uInt32 nMaxArea(rSize.getX()*rSize.getY());
+
+ FragmentContainer_t::const_iterator it(candidate);
+ while(it != aEnd)
+ {
+ if(!((*it)->isNaked()))
+ {
+ const ::basegfx::B2ISize& rCandidateSize((*it)->getSize());
+ const sal_uInt32 nArea(rCandidateSize.getX()*rCandidateSize.getY());
+ if(nArea > nMaxArea)
+ {
+ candidate=it;
+ nMaxArea=nArea;
+ }
+ }
+
+ ++it;
+ }
+
+ // this does not erase the candidate,
+ // but makes it 'naked'...
+ (*candidate)->free(*candidate);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // PageManager::relocate
+ //////////////////////////////////////////////////////////////////////////////////
+
+ bool PageManager::relocate( const FragmentSharedPtr& pFragment )
+ {
+ // the fragment passed as argument is assumed to
+ // be naked, that is it is not located on any page.
+ // we try all available pages again, maybe some
+ // other fragment was deleted and we can exploit the space.
+ const PageContainer_t::iterator aEnd(maPages.end());
+ PageContainer_t::iterator it(maPages.begin());
+ while(it != aEnd)
+ {
+ // if the page at hand takes the fragment, we immediatelly
+ // call select() to pull the information from the associated
+ // image to the hardware surface.
+ if((*it)->nakedFragment(pFragment))
+ {
+ // dirty, since newly allocated.
+ pFragment->select(true);
+ return true;
+ }
+
+ ++it;
+ }
+
+ return false;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // PageManager::validatePages
+ //////////////////////////////////////////////////////////////////////////////////
+
+ void PageManager::validatePages()
+ {
+ ::std::for_each( maPages.begin(),
+ maPages.end(),
+ ::boost::mem_fn(&Page::validate));
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // PageManager::getPageSize
+ //////////////////////////////////////////////////////////////////////////////////
+
+ ::basegfx::B2ISize PageManager::getPageSize() const
+ {
+ return mpRenderModule->getPageSize();
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // PageManager::getRenderModule
+ //////////////////////////////////////////////////////////////////////////////////
+
+ canvas::IRenderModuleSharedPtr PageManager::getRenderModule() const
+ {
+ return mpRenderModule;
+ }
+}
diff --git a/canvas/source/tools/pagemanager.hxx b/canvas/source/tools/pagemanager.hxx
new file mode 100644
index 000000000000..bf20b1d61e43
--- /dev/null
+++ b/canvas/source/tools/pagemanager.hxx
@@ -0,0 +1,94 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_CANVAS_PAGEMANAGER_HXX
+#define INCLUDED_CANVAS_PAGEMANAGER_HXX
+
+#include <basegfx/vector/b2isize.hxx>
+#include <canvas/rendering/irendermodule.hxx>
+#include <canvas/rendering/isurface.hxx>
+
+#include "page.hxx"
+
+namespace canvas
+{
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // PageManager
+ //////////////////////////////////////////////////////////////////////////////////
+
+ class PageManager
+ {
+ public:
+ PageManager( const canvas::IRenderModuleSharedPtr pRenderModule ) :
+ mpRenderModule(pRenderModule)
+ {
+ }
+
+ // returns the maximum size of a hardware
+ // accelerated page, e.g. OpenGL texture.
+ ::basegfx::B2ISize getPageSize() const;
+
+ canvas::IRenderModuleSharedPtr getRenderModule() const;
+
+ FragmentSharedPtr allocateSpace( const ::basegfx::B2ISize& rSize );
+ void free( const FragmentSharedPtr& pFragment );
+
+ void nakedFragment( const FragmentSharedPtr& pFragment );
+
+ void validatePages();
+
+ private:
+ // the pagemanager needs access to the rendermodule
+ // since we query for system resources from it.
+ canvas::IRenderModuleSharedPtr mpRenderModule;
+
+ // here we collect all fragments that will be created
+ // since we need them for relocation purposes.
+ typedef std::list<FragmentSharedPtr> FragmentContainer_t;
+ FragmentContainer_t maFragments;
+
+ // this is the container holding all created pages,
+ // behind the scenes these are real hardware surfaces.
+ typedef std::list<PageSharedPtr> PageContainer_t;
+ PageContainer_t maPages;
+
+ bool relocate( const FragmentSharedPtr& pFragment );
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // PageManagerSharedPtr
+ //////////////////////////////////////////////////////////////////////////////////
+
+ typedef ::boost::shared_ptr< PageManager > PageManagerSharedPtr;
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // End of file
+ //////////////////////////////////////////////////////////////////////////////////
+}
+
+#endif
diff --git a/canvas/source/tools/parametricpolypolygon.cxx b/canvas/source/tools/parametricpolypolygon.cxx
new file mode 100644
index 000000000000..368f04a572e3
--- /dev/null
+++ b/canvas/source/tools/parametricpolypolygon.cxx
@@ -0,0 +1,290 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include <canvas/debug.hxx>
+#include <canvas/canvastools.hxx>
+
+#include <rtl/math.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/tools/tools.hxx>
+
+#include <limits>
+
+#include <canvas/parametricpolypolygon.hxx>
+
+
+using namespace ::com::sun::star;
+
+namespace canvas
+{
+ uno::Sequence<rtl::OUString> ParametricPolyPolygon::getAvailableServiceNames()
+ {
+ uno::Sequence<rtl::OUString> aRet(3);
+ aRet[0] = rtl::OUString::createFromAscii("LinearGradient");
+ aRet[1] = rtl::OUString::createFromAscii("EllipticalGradient");
+ aRet[2] = rtl::OUString::createFromAscii("RectangularGradient");
+
+ return aRet;
+ }
+
+ ParametricPolyPolygon* ParametricPolyPolygon::create(
+ const uno::Reference< rendering::XGraphicDevice >& rDevice,
+ const ::rtl::OUString& rServiceName,
+ const uno::Sequence< uno::Any >& rArgs )
+ {
+ uno::Sequence< uno::Sequence< double > > colorSequence(2);
+ uno::Sequence< double > colorStops(2);
+ double fAspectRatio=1.0;
+
+ // defaults
+ uno::Sequence< rendering::RGBColor > rgbColors(1);
+ rgbColors[0] = rendering::RGBColor(0,0,0);
+ colorSequence[0] = rDevice->getDeviceColorSpace()->convertFromRGB(rgbColors);
+ rgbColors[0] = rendering::RGBColor(1,1,1);
+ colorSequence[1] = rDevice->getDeviceColorSpace()->convertFromRGB(rgbColors);
+ colorStops[0] = 0;
+ colorStops[1] = 1;
+
+ // extract args
+ for( sal_Int32 i=0; i<rArgs.getLength(); ++i )
+ {
+ beans::PropertyValue aProp;
+ if( (rArgs[i] >>= aProp) )
+ {
+ if( aProp.Name.equalsAscii("Colors") )
+ {
+ aProp.Value >>= colorSequence;
+ }
+ else if( aProp.Name.equalsAscii("Stops") )
+ {
+ aProp.Value >>= colorStops;
+ }
+ else if( aProp.Name.equalsAscii("AspectRatio") )
+ {
+ aProp.Value >>= fAspectRatio;
+ }
+ }
+ }
+
+ if( rServiceName.equalsAscii("LinearGradient") )
+ {
+ return createLinearHorizontalGradient(rDevice, colorSequence, colorStops);
+ }
+ else if( rServiceName.equalsAscii("EllipticalGradient") )
+ {
+ return createEllipticalGradient(rDevice, colorSequence, colorStops, fAspectRatio);
+ }
+ else if( rServiceName.equalsAscii("RectangularGradient") )
+ {
+ return createRectangularGradient(rDevice, colorSequence, colorStops, fAspectRatio);
+ }
+ else if( rServiceName.equalsAscii("VerticalLineHatch") )
+ {
+ // TODO: NYI
+ }
+ else if( rServiceName.equalsAscii("OrthogonalLinesHatch") )
+ {
+ // TODO: NYI
+ }
+ else if( rServiceName.equalsAscii("ThreeCrossingLinesHatch") )
+ {
+ // TODO: NYI
+ }
+ else if( rServiceName.equalsAscii("FourCrossingLinesHatch") )
+ {
+ // TODO: NYI
+ }
+
+ return NULL;
+ }
+
+ ParametricPolyPolygon* ParametricPolyPolygon::createLinearHorizontalGradient(
+ const uno::Reference< rendering::XGraphicDevice >& rDevice,
+ const uno::Sequence< uno::Sequence< double > >& colors,
+ const uno::Sequence< double >& stops )
+ {
+ // TODO(P2): hold gradient brush statically, and only setup
+ // the colors
+ return new ParametricPolyPolygon( rDevice, GRADIENT_LINEAR, colors, stops );
+ }
+
+ ParametricPolyPolygon* ParametricPolyPolygon::createEllipticalGradient(
+ const uno::Reference< rendering::XGraphicDevice >& rDevice,
+ const uno::Sequence< uno::Sequence< double > >& colors,
+ const uno::Sequence< double >& stops,
+ double fAspectRatio )
+ {
+ // TODO(P2): hold gradient polygon statically, and only setup
+ // the colors
+ return new ParametricPolyPolygon(
+ rDevice,
+ ::basegfx::tools::createPolygonFromCircle(
+ ::basegfx::B2DPoint(0,0), 1 ),
+ GRADIENT_ELLIPTICAL,
+ colors, stops, fAspectRatio );
+ }
+
+ ParametricPolyPolygon* ParametricPolyPolygon::createRectangularGradient( const uno::Reference< rendering::XGraphicDevice >& rDevice,
+ const uno::Sequence< uno::Sequence< double > >& colors,
+ const uno::Sequence< double >& stops,
+ double fAspectRatio )
+ {
+ // TODO(P2): hold gradient polygon statically, and only setup
+ // the colors
+ return new ParametricPolyPolygon(
+ rDevice,
+ ::basegfx::tools::createPolygonFromRect(
+ ::basegfx::B2DRectangle( -1, -1, 1, 1 ) ),
+ GRADIENT_RECTANGULAR,
+ colors, stops, fAspectRatio );
+ }
+
+ void SAL_CALL ParametricPolyPolygon::disposing()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ mxDevice.clear();
+ }
+
+ uno::Reference< rendering::XPolyPolygon2D > SAL_CALL ParametricPolyPolygon::getOutline( double /*t*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO(F1): outline NYI
+ return uno::Reference< rendering::XPolyPolygon2D >();
+ }
+
+ uno::Sequence< double > SAL_CALL ParametricPolyPolygon::getColor( double /*t*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO(F1): color NYI
+ return uno::Sequence< double >();
+ }
+
+ uno::Sequence< double > SAL_CALL ParametricPolyPolygon::getPointColor( const geometry::RealPoint2D& /*point*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO(F1): point color NYI
+ return uno::Sequence< double >();
+ }
+
+ uno::Reference< rendering::XColorSpace > SAL_CALL ParametricPolyPolygon::getColorSpace() throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return mxDevice.is() ? mxDevice->getDeviceColorSpace() : uno::Reference< rendering::XColorSpace >();
+ }
+
+#define IMPLEMENTATION_NAME "Canvas::ParametricPolyPolygon"
+#define SERVICE_NAME "com.sun.star.rendering.ParametricPolyPolygon"
+
+ ::rtl::OUString SAL_CALL ParametricPolyPolygon::getImplementationName( ) throw (uno::RuntimeException)
+ {
+ return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) );
+ }
+
+ sal_Bool SAL_CALL ParametricPolyPolygon::supportsService( const ::rtl::OUString& ServiceName ) throw (uno::RuntimeException)
+ {
+ return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) );
+ }
+
+ uno::Sequence< ::rtl::OUString > SAL_CALL ParametricPolyPolygon::getSupportedServiceNames( ) throw (uno::RuntimeException)
+ {
+ uno::Sequence< ::rtl::OUString > aRet(1);
+ aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) );
+
+ return aRet;
+ }
+
+ ParametricPolyPolygon::~ParametricPolyPolygon()
+ {
+ }
+
+ ParametricPolyPolygon::ParametricPolyPolygon( const uno::Reference< rendering::XGraphicDevice >& rDevice,
+ const ::basegfx::B2DPolygon& rGradientPoly,
+ GradientType eType,
+ const uno::Sequence< uno::Sequence< double > >& rColors,
+ const uno::Sequence< double >& rStops ) :
+ ParametricPolyPolygon_Base( m_aMutex ),
+ mxDevice( rDevice ),
+ maValues( rGradientPoly,
+ rColors,
+ rStops,
+ 1.0,
+ eType )
+ {
+ }
+
+ ParametricPolyPolygon::ParametricPolyPolygon( const uno::Reference< rendering::XGraphicDevice >& rDevice,
+ const ::basegfx::B2DPolygon& rGradientPoly,
+ GradientType eType,
+ const uno::Sequence< uno::Sequence< double > >& rColors,
+ const uno::Sequence< double >& rStops,
+ double nAspectRatio ) :
+ ParametricPolyPolygon_Base( m_aMutex ),
+ mxDevice( rDevice ),
+ maValues( rGradientPoly,
+ rColors,
+ rStops,
+ nAspectRatio,
+ eType )
+ {
+ }
+
+ ParametricPolyPolygon::ParametricPolyPolygon( const uno::Reference< rendering::XGraphicDevice >& rDevice,
+ GradientType eType,
+ const uno::Sequence< uno::Sequence< double > >& rColors,
+ const uno::Sequence< double >& rStops ) :
+ ParametricPolyPolygon_Base( m_aMutex ),
+ mxDevice( rDevice ),
+ maValues( ::basegfx::B2DPolygon(),
+ rColors,
+ rStops,
+ 1.0,
+ eType )
+ {
+ }
+
+ ParametricPolyPolygon::Values ParametricPolyPolygon::getValues() const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return maValues;
+ }
+
+}
diff --git a/canvas/source/tools/prioritybooster.cxx b/canvas/source/tools/prioritybooster.cxx
new file mode 100644
index 000000000000..984003ebc984
--- /dev/null
+++ b/canvas/source/tools/prioritybooster.cxx
@@ -0,0 +1,83 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+
+#ifdef WNT
+# if defined _MSC_VER
+# pragma warning(push,1)
+# endif
+
+# include <windows.h>
+
+# if defined _MSC_VER
+# pragma warning(pop)
+# endif
+#endif
+
+#include "osl/diagnose.h"
+#include "canvas/prioritybooster.hxx"
+
+
+namespace canvas
+{
+ namespace tools
+ {
+ struct PriorityBooster_Impl
+ {
+ int mnOldPriority;
+ };
+
+ PriorityBooster::PriorityBooster( sal_Int32 nDelta ) :
+ mpImpl( new PriorityBooster_Impl )
+ {
+#ifdef WNT
+ HANDLE aCurrThread = GetCurrentThread();
+ mpImpl->mnOldPriority = GetThreadPriority( aCurrThread );
+
+ if ( 0 == SetThreadPriority( aCurrThread, mpImpl->mnOldPriority + nDelta ) )
+ {
+ OSL_ENSURE( false,
+ "PriorityBooster::PriorityBooster(): Was not able to modify thread priority" );
+ }
+#else
+ nDelta = 0; // #i55991# placate gcc warning
+#endif
+ }
+
+ PriorityBooster::~PriorityBooster()
+ {
+#ifdef WNT
+ SetThreadPriority( GetCurrentThread(),
+ mpImpl->mnOldPriority );
+#endif
+ }
+ } // namespace tools
+
+} // namespace canvas
diff --git a/canvas/source/tools/propertysethelper.cxx b/canvas/source/tools/propertysethelper.cxx
new file mode 100644
index 000000000000..c95eae045ee5
--- /dev/null
+++ b/canvas/source/tools/propertysethelper.cxx
@@ -0,0 +1,187 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include <canvas/propertysethelper.hxx>
+
+using namespace ::com::sun::star;
+
+namespace canvas
+{
+ namespace
+ {
+ void throwUnknown( const ::rtl::OUString& aPropertyName )
+ {
+ throw beans::UnknownPropertyException(
+ ::rtl::OUString::createFromAscii("PropertySetHelper: property ") +
+ aPropertyName +
+ ::rtl::OUString::createFromAscii(" not found."),
+ uno::Reference< uno::XInterface >()
+ );
+ }
+
+ void throwVeto( const ::rtl::OUString& aPropertyName )
+ {
+ throw beans::PropertyVetoException(
+ ::rtl::OUString::createFromAscii("PropertySetHelper: property ") +
+ aPropertyName +
+ ::rtl::OUString::createFromAscii(" access was vetoed."),
+ uno::Reference< uno::XInterface >() );
+ }
+
+ struct EntryComparator
+ {
+ bool operator()( const PropertySetHelper::MapType::MapEntry& rLHS,
+ const PropertySetHelper::MapType::MapEntry& rRHS )
+ {
+ return strcmp( rLHS.maKey,
+ rRHS.maKey ) < 0;
+ }
+ };
+ }
+
+ PropertySetHelper::PropertySetHelper() :
+ mpMap(),
+ maMapEntries()
+ {
+ }
+
+ PropertySetHelper::PropertySetHelper( const InputMap& rMap ) :
+ mpMap(),
+ maMapEntries()
+ {
+ initProperties(rMap);
+ }
+
+ void PropertySetHelper::initProperties( const InputMap& rMap )
+ {
+ mpMap.reset();
+ maMapEntries = rMap;
+
+ std::sort( maMapEntries.begin(),
+ maMapEntries.end(),
+ EntryComparator() );
+
+ if( !maMapEntries.empty() )
+ mpMap.reset( new MapType(&maMapEntries[0],
+ maMapEntries.size(),
+ true) );
+ }
+
+ void PropertySetHelper::addProperties( const InputMap& rMap )
+ {
+ InputMap aMerged( getPropertyMap() );
+ aMerged.insert( aMerged.end(),
+ rMap.begin(),
+ rMap.end() );
+
+ initProperties( aMerged );
+ }
+
+ bool PropertySetHelper::isPropertyName( const ::rtl::OUString& aPropertyName ) const
+ {
+ if( !mpMap.get() )
+ return false;
+
+ Callbacks aDummy;
+ return mpMap->lookup( aPropertyName,
+ aDummy );
+ }
+
+ uno::Reference< beans::XPropertySetInfo > PropertySetHelper::getPropertySetInfo() const
+ {
+ // we're a stealth property set
+ return uno::Reference< beans::XPropertySetInfo >();
+ }
+
+ void PropertySetHelper::setPropertyValue( const ::rtl::OUString& aPropertyName,
+ const uno::Any& aValue )
+ {
+ Callbacks aCallbacks;
+ if( !mpMap.get() ||
+ !mpMap->lookup( aPropertyName,
+ aCallbacks ) )
+ {
+ throwUnknown( aPropertyName );
+ }
+
+ if( aCallbacks.setter.empty() )
+ throwVeto( aPropertyName );
+
+ aCallbacks.setter(aValue);
+ }
+
+ uno::Any PropertySetHelper::getPropertyValue( const ::rtl::OUString& aPropertyName ) const
+ {
+ Callbacks aCallbacks;
+ if( !mpMap.get() ||
+ !mpMap->lookup( aPropertyName,
+ aCallbacks ) )
+ {
+ throwUnknown( aPropertyName );
+ }
+
+ if( !aCallbacks.getter.empty() )
+ return aCallbacks.getter();
+
+ // TODO(Q1): subtlety, empty getter method silently returns
+ // the empty any
+ return uno::Any();
+ }
+
+ void PropertySetHelper::addPropertyChangeListener( const ::rtl::OUString& aPropertyName,
+ const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ )
+ {
+ // check validity of property, but otherwise ignore the
+ // request
+ if( !isPropertyName( aPropertyName ) )
+ throwUnknown( aPropertyName );
+ }
+
+ void PropertySetHelper::removePropertyChangeListener( const ::rtl::OUString& /*aPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ )
+ {
+ // ignore request, no listener added in the first place
+ }
+
+ void PropertySetHelper::addVetoableChangeListener( const ::rtl::OUString& aPropertyName,
+ const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/ )
+ {
+ // check validity of property, but otherwise ignore the
+ // request
+ if( !isPropertyName( aPropertyName ) )
+ throwUnknown( aPropertyName );
+ }
+
+ void PropertySetHelper::removeVetoableChangeListener( const ::rtl::OUString& /*aPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/ )
+ {
+ // ignore request, no listener added in the first place
+ }
+}
diff --git a/canvas/source/tools/spriteredrawmanager.cxx b/canvas/source/tools/spriteredrawmanager.cxx
new file mode 100644
index 000000000000..7027a9d263df
--- /dev/null
+++ b/canvas/source/tools/spriteredrawmanager.cxx
@@ -0,0 +1,520 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/spriteredrawmanager.hxx>
+
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/vector/b2dsize.hxx>
+#include <basegfx/range/rangeexpander.hxx>
+
+#include <algorithm>
+#include <functional>
+#include <boost/bind.hpp>
+
+
+namespace canvas
+{
+ namespace
+ {
+ /** Helper class to condense sprite updates into a single action
+
+ This class tracks the sprite changes over the recorded
+ change list, and generates a single update action from
+ that (note that per screen update, several moves,
+ visibility changes and content updates might happen)
+ */
+ class SpriteTracer
+ {
+ public:
+ SpriteTracer( const Sprite::Reference& rAffectedSprite ) :
+ mpAffectedSprite(rAffectedSprite),
+ maMoveStartArea(),
+ maMoveEndArea(),
+ mbIsMove( false ),
+ mbIsGenericUpdate( false )
+ {
+ }
+
+ void operator()( const SpriteRedrawManager::SpriteChangeRecord& rSpriteRecord )
+ {
+ // only deal with change events from the currently
+ // affected sprite
+ if( rSpriteRecord.mpAffectedSprite == mpAffectedSprite )
+ {
+ switch( rSpriteRecord.meChangeType )
+ {
+ case SpriteRedrawManager::SpriteChangeRecord::move:
+ if( !mbIsMove )
+ {
+ // no move yet - this must be the first one
+ maMoveStartArea = ::basegfx::B2DRectangle(
+ rSpriteRecord.maOldPos,
+ rSpriteRecord.maOldPos + rSpriteRecord.maUpdateArea.getRange() );
+ mbIsMove = true;
+ }
+
+ maMoveEndArea = rSpriteRecord.maUpdateArea;
+ break;
+
+ case SpriteRedrawManager::SpriteChangeRecord::update:
+ // update end update area of the
+ // sprite. Thus, every update() action
+ // _after_ the last move will correctly
+ // update the final repaint area. And this
+ // does not interfere with subsequent
+ // moves, because moves always perform a
+ // hard set of maMoveEndArea to their
+ // stored value
+ maMoveEndArea.expand( rSpriteRecord.maUpdateArea );
+ mbIsGenericUpdate = true;
+ break;
+
+ default:
+ ENSURE_OR_THROW( false,
+ "Unexpected case in SpriteUpdater::operator()" );
+ break;
+ }
+ }
+ }
+
+ void commit( SpriteRedrawManager::SpriteConnectedRanges& rUpdateCollector ) const
+ {
+ if( mbIsMove )
+ {
+ if( !maMoveStartArea.isEmpty() ||
+ !maMoveEndArea.isEmpty() )
+ {
+ // if mbIsGenericUpdate is false, this is a
+ // pure move (i.e. no other update
+ // operations). Pass that information on to
+ // the SpriteInfo
+ const bool bIsPureMove( !mbIsGenericUpdate );
+
+ // ignore the case that start and end update
+ // area overlap - the b2dconnectedranges
+ // handle that, anyway. doing it this way
+ // ensures that we have both old and new area
+ // stored
+
+ // round all given range up to enclosing
+ // integer rectangle - since the whole thing
+ // here is about
+
+ // first, draw the new sprite position
+ rUpdateCollector.addRange(
+ ::basegfx::unotools::b2DSurroundingIntegerRangeFromB2DRange( maMoveEndArea ),
+ SpriteRedrawManager::SpriteInfo(
+ mpAffectedSprite,
+ maMoveEndArea,
+ true,
+ bIsPureMove ) );
+
+ // then, clear the old place (looks smoother
+ // this way)
+ rUpdateCollector.addRange(
+ ::basegfx::unotools::b2DSurroundingIntegerRangeFromB2DRange( maMoveStartArea ),
+ SpriteRedrawManager::SpriteInfo(
+ Sprite::Reference(),
+ maMoveStartArea,
+ true,
+ bIsPureMove ) );
+ }
+ }
+ else if( mbIsGenericUpdate &&
+ !maMoveEndArea.isEmpty() )
+ {
+ rUpdateCollector.addRange(
+ ::basegfx::unotools::b2DSurroundingIntegerRangeFromB2DRange( maMoveEndArea ),
+ SpriteRedrawManager::SpriteInfo(
+ mpAffectedSprite,
+ maMoveEndArea,
+ true ) );
+ }
+ }
+
+ private:
+ Sprite::Reference mpAffectedSprite;
+ ::basegfx::B2DRectangle maMoveStartArea;
+ ::basegfx::B2DRectangle maMoveEndArea;
+
+ /// True, if at least one move was encountered
+ bool mbIsMove;
+
+ /// True, if at least one generic update was encountered
+ bool mbIsGenericUpdate;
+ };
+
+
+ /** SpriteChecker functor, which for every sprite checks the
+ given update vector for necessary screen updates
+ */
+ class SpriteUpdater
+ {
+ public:
+ /** Generate update area list
+
+ @param rUpdater
+ Reference to an updater object, which will receive the
+ update areas.
+
+ @param rChangeContainer
+ Container with all sprite change requests
+
+ */
+ SpriteUpdater( SpriteRedrawManager::SpriteConnectedRanges& rUpdater,
+ const SpriteRedrawManager::VectorOfChangeRecords& rChangeContainer ) :
+ mrUpdater( rUpdater ),
+ mrChangeContainer( rChangeContainer )
+ {
+ }
+
+ /** Call this method for every sprite on your screen
+
+ This method scans the change container, collecting all
+ update info for the given sprite into one or two
+ update operations, which in turn are inserted into the
+ connected ranges processor.
+
+ @param rSprite
+ Current sprite to collect update info for.
+ */
+ void operator()( const Sprite::Reference& rSprite )
+ {
+ const SpriteTracer aSpriteTracer(
+ ::std::for_each( mrChangeContainer.begin(),
+ mrChangeContainer.end(),
+ SpriteTracer( rSprite ) ) );
+
+ aSpriteTracer.commit( mrUpdater );
+ }
+
+ private:
+ SpriteRedrawManager::SpriteConnectedRanges& mrUpdater;
+ const SpriteRedrawManager::VectorOfChangeRecords& mrChangeContainer;
+ };
+ }
+
+ void SpriteRedrawManager::setupUpdateAreas( SpriteConnectedRanges& rUpdateAreas ) const
+ {
+ // TODO(T3): This is NOT thread safe at all. This only works
+ // under the assumption that NOBODY changes ANYTHING
+ // concurrently, while this method is on the stack. We should
+ // really rework the canvas::Sprite interface, in such a way
+ // that it dumps ALL its state with a single, atomic
+ // call. Then, we store that state locally. This prolly goes
+ // in line with the problem of having sprite state available
+ // for the frame before the last frame; plus, it avoids
+ // frequent locks of the object mutices
+ SpriteComparator aSpriteComparator;
+
+ // put all sprites that have changed content into update areas
+ ListOfSprites::const_iterator aCurrSprite( maSprites.begin() );
+ const ListOfSprites::const_iterator aEndSprite ( maSprites.end() );
+ while( aCurrSprite != aEndSprite )
+ {
+ if( (*aCurrSprite)->isContentChanged() )
+ const_cast<SpriteRedrawManager*>(this)->updateSprite( *aCurrSprite,
+ (*aCurrSprite)->getPosPixel(),
+ (*aCurrSprite)->getUpdateArea() );
+ ++aCurrSprite;
+ }
+
+ // sort sprites after prio
+ VectorOfSprites aSortedSpriteVector;
+ ::std::copy( maSprites.begin(),
+ maSprites.end(),
+ ::std::back_insert_iterator< VectorOfSprites >(aSortedSpriteVector) );
+ ::std::sort( aSortedSpriteVector.begin(),
+ aSortedSpriteVector.end(),
+ aSpriteComparator );
+
+ // extract all referenced sprites from the maChangeRecords
+ // (copy sprites, make the list unique, regarding the
+ // sprite pointer). This assumes that, until this scope
+ // ends, nobody changes the maChangeRecords vector!
+ VectorOfSprites aUpdatableSprites;
+ VectorOfChangeRecords::const_iterator aCurrRecord( maChangeRecords.begin() );
+ const VectorOfChangeRecords::const_iterator aEndRecords( maChangeRecords.end() );
+ while( aCurrRecord != aEndRecords )
+ {
+ const Sprite::Reference& rSprite( aCurrRecord->getSprite() );
+ if( rSprite.is() )
+ aUpdatableSprites.push_back( rSprite );
+ ++aCurrRecord;
+ }
+
+ VectorOfSprites::iterator aBegin( aUpdatableSprites.begin() );
+ VectorOfSprites::iterator aEnd ( aUpdatableSprites.end() );
+ ::std::sort( aBegin,
+ aEnd,
+ aSpriteComparator );
+
+ aEnd = ::std::unique( aBegin, aEnd );
+
+ // for each unique sprite, check the change event vector,
+ // calculate the update operation from that, and add the
+ // result to the aUpdateArea.
+ ::std::for_each( aBegin,
+ aEnd,
+ SpriteUpdater( rUpdateAreas,
+ maChangeRecords) );
+
+ // TODO(P2): Implement your own output iterator adapter, to
+ // avoid that totally superfluous temp aUnchangedSprites
+ // vector.
+
+ // add all sprites to rUpdateAreas, that are _not_ already
+ // contained in the uniquified vector of changed ones
+ // (i.e. the difference between aSortedSpriteVector and
+ // aUpdatableSprites).
+ VectorOfSprites aUnchangedSprites;
+ ::std::set_difference( aSortedSpriteVector.begin(),
+ aSortedSpriteVector.end(),
+ aBegin, aEnd,
+ ::std::back_insert_iterator< VectorOfSprites >(aUnchangedSprites) );
+
+ // add each remaining unchanged sprite to connected ranges,
+ // marked as "don't need update"
+ VectorOfSprites::const_iterator aCurr( aUnchangedSprites.begin() );
+ const VectorOfSprites::const_iterator aEnd2( aUnchangedSprites.end() );
+ while( aCurr != aEnd2 )
+ {
+ const ::basegfx::B2DRange& rUpdateArea( (*aCurr)->getUpdateArea() );
+ rUpdateAreas.addRange(
+ ::basegfx::unotools::b2DSurroundingIntegerRangeFromB2DRange( rUpdateArea ),
+ SpriteInfo(*aCurr,
+ rUpdateArea,
+ false) );
+ ++aCurr;
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 0
+ bool impIsEqualB2DRange(const basegfx::B2DRange& rRangeA, const basegfx::B2DRange& rRangeB, double fSmallValue)
+ {
+ return fabs(rRangeB.getMinX() - rRangeA.getMinX()) <= fSmallValue
+ && fabs(rRangeB.getMinY() - rRangeA.getMinY()) <= fSmallValue
+ && fabs(rRangeB.getMaxX() - rRangeA.getMaxX()) <= fSmallValue
+ && fabs(rRangeB.getMaxY() - rRangeA.getMaxY()) <= fSmallValue;
+ }
+
+ bool impIsEqualB2DVector(const basegfx::B2DVector& rVecA, const basegfx::B2DVector& rVecB, double fSmallValue)
+ {
+ return fabs(rVecB.getX() - rVecA.getX()) <= fSmallValue
+ && fabs(rVecB.getY() - rVecA.getY()) <= fSmallValue;
+ }
+#endif
+
+ bool SpriteRedrawManager::isAreaUpdateScroll( ::basegfx::B2DRectangle& o_rMoveStart,
+ ::basegfx::B2DRectangle& o_rMoveEnd,
+ const UpdateArea& rUpdateArea,
+ ::std::size_t nNumSprites ) const
+ {
+ // check for a solitary move, which consists of exactly two
+ // pure-move entries, the first with valid, the second with
+ // invalid sprite (see SpriteTracer::commit()). Note that we
+ // cannot simply store some flag in SpriteTracer::commit()
+ // above and just check that here, since during the connected
+ // range calculations, other sprites might get merged into the
+ // same region (thus spoiling the scrolling move
+ // optimization).
+ if( nNumSprites != 2 )
+ return false;
+
+ const SpriteConnectedRanges::ComponentListType::const_iterator aFirst(
+ rUpdateArea.maComponentList.begin() );
+ SpriteConnectedRanges::ComponentListType::const_iterator aSecond(
+ aFirst ); ++aSecond;
+
+ if( !aFirst->second.isPureMove() ||
+ !aSecond->second.isPureMove() ||
+ !aFirst->second.getSprite().is() ||
+ // use _true_ update area, not the rounded version
+ !aFirst->second.getSprite()->isAreaUpdateOpaque( aFirst->second.getUpdateArea() ) ||
+ aSecond->second.getSprite().is() )
+ {
+ // either no move update, or incorrect sprite, or sprite
+ // content not fully opaque over update region.
+ return false;
+ }
+
+ o_rMoveStart = aSecond->second.getUpdateArea();
+ o_rMoveEnd = aFirst->second.getUpdateArea();
+
+#if OSL_DEBUG_LEVEL > 0
+ ::basegfx::B2DRectangle aTotalBounds( o_rMoveStart );
+ aTotalBounds.expand( o_rMoveEnd );
+
+ OSL_POSTCOND(impIsEqualB2DRange(rUpdateArea.maTotalBounds, basegfx::unotools::b2DSurroundingIntegerRangeFromB2DRange(aTotalBounds), 0.5),
+ "SpriteRedrawManager::isAreaUpdateScroll(): sprite area and total area mismatch");
+ OSL_POSTCOND(impIsEqualB2DVector(o_rMoveStart.getRange(), o_rMoveEnd.getRange(), 0.5),
+ "SpriteRedrawManager::isAreaUpdateScroll(): scroll start and end area have mismatching size");
+#endif
+
+ return true;
+ }
+
+ bool SpriteRedrawManager::isAreaUpdateNotOpaque( const ::basegfx::B2DRectangle& rUpdateRect,
+ const AreaComponent& rComponent ) const
+ {
+ const Sprite::Reference& pAffectedSprite( rComponent.second.getSprite() );
+
+ if( !pAffectedSprite.is() )
+ return true; // no sprite, no opaque update!
+
+ return !pAffectedSprite->isAreaUpdateOpaque( rUpdateRect );
+ }
+
+ bool SpriteRedrawManager::isAreaUpdateOpaque( const UpdateArea& rUpdateArea,
+ ::std::size_t nNumSprites ) const
+ {
+ // check whether the sprites in the update area's list will
+ // fully cover the given area _and_ do that in an opaque way
+ // (i.e. no alpha, no non-rectangular sprite content).
+
+ // TODO(P1): Come up with a smarter early-exit criterion here
+ // (though, I think, the case that _lots_ of sprites _fully_
+ // cover a rectangular area _without_ any holes is extremely
+ // improbable)
+
+ // avoid checking large number of sprites (and probably fail,
+ // anyway). Note: the case nNumSprites < 1 should normally not
+ // happen, as handleArea() calls backgroundPaint() then.
+ if( nNumSprites > 3 || nNumSprites < 1 )
+ return false;
+
+ const SpriteConnectedRanges::ComponentListType::const_iterator aBegin(
+ rUpdateArea.maComponentList.begin() );
+ const SpriteConnectedRanges::ComponentListType::const_iterator aEnd(
+ rUpdateArea.maComponentList.end() );
+
+ // now, calc the _true_ update area, by merging all sprite's
+ // true update areas into one rectangle
+ ::basegfx::B2DRange aTrueArea( aBegin->second.getUpdateArea() );
+ ::std::for_each( aBegin,
+ aEnd,
+ ::boost::bind( ::basegfx::B2DRangeExpander(aTrueArea),
+ ::boost::bind( &SpriteInfo::getUpdateArea,
+ ::boost::bind( ::std::select2nd<AreaComponent>(),
+ _1 ) ) ) );
+
+ // and check whether _any_ of the sprites tells that its area
+ // update will not be opaque.
+ return (::std::find_if( aBegin,
+ aEnd,
+ ::boost::bind( &SpriteRedrawManager::isAreaUpdateNotOpaque,
+ this,
+ ::boost::cref(aTrueArea),
+ _1 ) ) == aEnd );
+ }
+
+ bool SpriteRedrawManager::areSpritesChanged( const UpdateArea& rUpdateArea ) const
+ {
+ // check whether SpriteInfo::needsUpdate returns false for
+ // all elements of this area's contained sprites
+ //
+ // if not a single changed sprite found - just ignore this
+ // component (return false)
+ const SpriteConnectedRanges::ComponentListType::const_iterator aEnd(
+ rUpdateArea.maComponentList.end() );
+ return (::std::find_if( rUpdateArea.maComponentList.begin(),
+ aEnd,
+ ::boost::bind( &SpriteInfo::needsUpdate,
+ ::boost::bind(
+ ::std::select2nd<SpriteConnectedRanges::ComponentType>(),
+ _1 ) ) ) != aEnd );
+ }
+
+ SpriteRedrawManager::SpriteRedrawManager() :
+ maSprites(),
+ maChangeRecords()
+ {
+ }
+
+ void SpriteRedrawManager::disposing()
+ {
+ // drop all references
+ maChangeRecords.clear();
+
+ // dispose all sprites - the spritecanvas, and by delegation,
+ // this object, is the owner of the sprites. After all, a
+ // sprite without a canvas to render into makes not terribly
+ // much sense.
+
+ // TODO(Q3): Once boost 1.33 is in, change back to for_each
+ // with ::boost::mem_fn. For the time being, explicit loop due
+ // to cdecl declaration of all UNO methods.
+ ListOfSprites::reverse_iterator aCurr( maSprites.rbegin() );
+ ListOfSprites::reverse_iterator aEnd( maSprites.rend() );
+ while( aCurr != aEnd )
+ (*aCurr++)->dispose();
+
+ maSprites.clear();
+ }
+
+ void SpriteRedrawManager::clearChangeRecords()
+ {
+ maChangeRecords.clear();
+ }
+
+ void SpriteRedrawManager::showSprite( const Sprite::Reference& rSprite )
+ {
+ maSprites.push_back( rSprite );
+ }
+
+ void SpriteRedrawManager::hideSprite( const Sprite::Reference& rSprite )
+ {
+ maSprites.remove( rSprite );
+ }
+
+ void SpriteRedrawManager::moveSprite( const Sprite::Reference& rSprite,
+ const ::basegfx::B2DPoint& rOldPos,
+ const ::basegfx::B2DPoint& rNewPos,
+ const ::basegfx::B2DVector& rSpriteSize )
+ {
+ maChangeRecords.push_back( SpriteChangeRecord( rSprite,
+ rOldPos,
+ rNewPos,
+ rSpriteSize ) );
+ }
+
+ void SpriteRedrawManager::updateSprite( const Sprite::Reference& rSprite,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DRange& rUpdateArea )
+ {
+ maChangeRecords.push_back( SpriteChangeRecord( rSprite,
+ rPos,
+ rUpdateArea ) );
+ }
+
+}
diff --git a/canvas/source/tools/surface.cxx b/canvas/source/tools/surface.cxx
new file mode 100644
index 000000000000..aaef28ba489f
--- /dev/null
+++ b/canvas/source/tools/surface.cxx
@@ -0,0 +1,496 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include "surface.hxx"
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <boost/bind.hpp>
+
+namespace canvas
+{
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Surface::Surface
+ //////////////////////////////////////////////////////////////////////////////////
+
+ Surface::Surface( const PageManagerSharedPtr& rPageManager,
+ const IColorBufferSharedPtr& rColorBuffer,
+ const ::basegfx::B2IPoint& rPos,
+ const ::basegfx::B2ISize& rSize ) :
+ mpColorBuffer(rColorBuffer),
+ mpPageManager(rPageManager),
+ mpFragment(),
+ maSourceOffset(rPos),
+ maSize(rSize),
+ mbIsDirty(true)
+ {
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Surface::~Surface
+ //////////////////////////////////////////////////////////////////////////////////
+
+ Surface::~Surface()
+ {
+ if(mpFragment)
+ mpPageManager->free(mpFragment);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Surface::getUVCoords
+ //////////////////////////////////////////////////////////////////////////////////
+
+ void Surface::setColorBufferDirty()
+ {
+ mbIsDirty=true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Surface::getUVCoords
+ //////////////////////////////////////////////////////////////////////////////////
+
+ basegfx::B2DRectangle Surface::getUVCoords() const
+ {
+ ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize());
+ ::basegfx::B2IPoint aDestOffset;
+ if( mpFragment )
+ aDestOffset = mpFragment->getPos();
+
+ const double pw( aPageSize.getX() );
+ const double ph( aPageSize.getY() );
+ const double ox( aDestOffset.getX() );
+ const double oy( aDestOffset.getY() );
+ const double sx( maSize.getX() );
+ const double sy( maSize.getY() );
+
+ return ::basegfx::B2DRectangle( ox/pw,
+ oy/ph,
+ (ox+sx)/pw,
+ (oy+sy)/ph );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Surface::getUVCoords
+ //////////////////////////////////////////////////////////////////////////////////
+
+ basegfx::B2DRectangle Surface::getUVCoords( const ::basegfx::B2IPoint& rPos,
+ const ::basegfx::B2ISize& rSize ) const
+ {
+ ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize());
+
+ const double pw( aPageSize.getX() );
+ const double ph( aPageSize.getY() );
+ const double ox( rPos.getX() );
+ const double oy( rPos.getY() );
+ const double sx( rSize.getX() );
+ const double sy( rSize.getY() );
+
+ return ::basegfx::B2DRectangle( ox/pw,
+ oy/ph,
+ (ox+sx)/pw,
+ (oy+sy)/ph );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Surface::draw
+ //////////////////////////////////////////////////////////////////////////////////
+
+ bool Surface::draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule());
+
+ RenderModuleGuard aGuard( pRenderModule );
+
+ prepareRendering();
+
+ // convert size to normalized device coordinates
+ const ::basegfx::B2DRectangle& rUV( getUVCoords() );
+
+ const double u1(rUV.getMinX());
+ const double v1(rUV.getMinY());
+ const double u2(rUV.getMaxX());
+ const double v2(rUV.getMaxY());
+
+ // concat transforms
+ // 1) offset of surface subarea
+ // 2) surface transform
+ // 3) translation to output position [rPos]
+ // 4) scale to normalized device coordinates
+ // 5) flip y-axis
+ // 6) translate to account for viewport transform
+ basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(
+ maSourceOffset.getX(), maSourceOffset.getY()));
+ aTransform = aTransform * rTransform;
+ aTransform.translate(::basegfx::fround(rPos.getX()),
+ ::basegfx::fround(rPos.getY()));
+
+ /*
+ ######################################
+ ######################################
+ ######################################
+
+ Y
+ ^+1
+ |
+ 2 | 3
+ x------------x
+ | | |
+ | | |
+ ------|-----O------|------>X
+ -1 | | | +1
+ | | |
+ x------------x
+ 1 | 0
+ |
+ |-1
+
+ ######################################
+ ######################################
+ ######################################
+ */
+
+ const ::basegfx::B2DPoint& p0(aTransform * ::basegfx::B2DPoint(maSize.getX(),maSize.getY()));
+ const ::basegfx::B2DPoint& p1(aTransform * ::basegfx::B2DPoint(0.0,maSize.getY()));
+ const ::basegfx::B2DPoint& p2(aTransform * ::basegfx::B2DPoint(0.0,0.0));
+ const ::basegfx::B2DPoint& p3(aTransform * ::basegfx::B2DPoint(maSize.getX(),0.0));
+
+ canvas::Vertex vertex;
+ vertex.r = 1.0f;
+ vertex.g = 1.0f;
+ vertex.b = 1.0f;
+ vertex.a = static_cast<float>(fAlpha);
+ vertex.z = 0.0f;
+
+ {
+ pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_QUAD );
+
+ // issue an endPrimitive() when leaving the scope
+ const ::comphelper::ScopeGuard aScopeGuard(
+ boost::bind( &::canvas::IRenderModule::endPrimitive,
+ ::boost::ref(pRenderModule) ) );
+
+ vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2);
+ vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY());
+ pRenderModule->pushVertex(vertex);
+
+ vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2);
+ vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY());
+ pRenderModule->pushVertex(vertex);
+
+ vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1);
+ vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY());
+ pRenderModule->pushVertex(vertex);
+
+ vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1);
+ vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY());
+ pRenderModule->pushVertex(vertex);
+ }
+
+ return !(pRenderModule->isError());
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Surface::drawRectangularArea
+ //////////////////////////////////////////////////////////////////////////////////
+
+ bool Surface::drawRectangularArea(
+ double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DRectangle& rArea,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ if( rArea.isEmpty() )
+ return true; // immediate exit for empty area
+
+ IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule());
+
+ RenderModuleGuard aGuard( pRenderModule );
+
+ prepareRendering();
+
+ // these positions are relative to the texture
+ ::basegfx::B2IPoint aPos1(
+ ::basegfx::fround(rArea.getMinimum().getX()),
+ ::basegfx::fround(rArea.getMinimum().getY()));
+ ::basegfx::B2IPoint aPos2(
+ ::basegfx::fround(rArea.getMaximum().getX()),
+ ::basegfx::fround(rArea.getMaximum().getY()) );
+
+ // clip the positions to the area this surface covers
+ aPos1.setX(::std::max(aPos1.getX(),maSourceOffset.getX()));
+ aPos1.setY(::std::max(aPos1.getY(),maSourceOffset.getY()));
+ aPos2.setX(::std::min(aPos2.getX(),maSourceOffset.getX()+maSize.getX()));
+ aPos2.setY(::std::min(aPos2.getY(),maSourceOffset.getY()+maSize.getY()));
+
+ // if the resulting area is empty, return immediately
+ ::basegfx::B2IVector aSize(aPos2 - aPos1);
+ if(aSize.getX() <= 0 || aSize.getY() <= 0)
+ return true;
+
+ ::basegfx::B2IPoint aDestOffset;
+ if( mpFragment )
+ aDestOffset = mpFragment->getPos();
+
+ // convert size to normalized device coordinates
+ const ::basegfx::B2DRectangle& rUV(
+ getUVCoords(aPos1 - maSourceOffset + aDestOffset,
+ aSize) );
+ const double u1(rUV.getMinX());
+ const double v1(rUV.getMinY());
+ const double u2(rUV.getMaxX());
+ const double v2(rUV.getMaxY());
+
+ // concatenate transforms
+ // 1) offset of surface subarea
+ // 2) surface transform
+ // 3) translation to output position [rPos]
+ basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(aPos1.getX(), aPos1.getY()));
+ aTransform = aTransform * rTransform;
+ aTransform.translate(::basegfx::fround(rPos.getX()),
+ ::basegfx::fround(rPos.getY()));
+
+
+ /*
+ ######################################
+ ######################################
+ ######################################
+
+ Y
+ ^+1
+ |
+ 2 | 3
+ x------------x
+ | | |
+ | | |
+ ------|-----O------|------>X
+ -1 | | | +1
+ | | |
+ x------------x
+ 1 | 0
+ |
+ |-1
+
+ ######################################
+ ######################################
+ ######################################
+ */
+
+ const ::basegfx::B2DPoint& p0(aTransform * ::basegfx::B2DPoint(aSize.getX(),aSize.getY()));
+ const ::basegfx::B2DPoint& p1(aTransform * ::basegfx::B2DPoint(0.0, aSize.getY()));
+ const ::basegfx::B2DPoint& p2(aTransform * ::basegfx::B2DPoint(0.0, 0.0));
+ const ::basegfx::B2DPoint& p3(aTransform * ::basegfx::B2DPoint(aSize.getX(),0.0));
+
+ canvas::Vertex vertex;
+ vertex.r = 1.0f;
+ vertex.g = 1.0f;
+ vertex.b = 1.0f;
+ vertex.a = static_cast<float>(fAlpha);
+ vertex.z = 0.0f;
+
+ {
+ pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_QUAD );
+
+ // issue an endPrimitive() when leaving the scope
+ const ::comphelper::ScopeGuard aScopeGuard(
+ boost::bind( &::canvas::IRenderModule::endPrimitive,
+ ::boost::ref(pRenderModule) ) );
+
+ vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2);
+ vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY());
+ pRenderModule->pushVertex(vertex);
+
+ vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2);
+ vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY());
+ pRenderModule->pushVertex(vertex);
+
+ vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1);
+ vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY());
+ pRenderModule->pushVertex(vertex);
+
+ vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1);
+ vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY());
+ pRenderModule->pushVertex(vertex);
+ }
+
+ return !(pRenderModule->isError());
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Surface::drawWithClip
+ //////////////////////////////////////////////////////////////////////////////////
+
+ bool Surface::drawWithClip( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DPolygon& rClipPoly,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule());
+
+ RenderModuleGuard aGuard( pRenderModule );
+
+ prepareRendering();
+
+ // untransformed surface rectangle, relative to the whole
+ // image (note: this surface might actually only be a tile of
+ // the whole image, with non-zero maSourceOffset)
+ const double x1(maSourceOffset.getX());
+ const double y1(maSourceOffset.getY());
+ const double w(maSize.getX());
+ const double h(maSize.getY());
+ const double x2(x1+w);
+ const double y2(y1+h);
+ const ::basegfx::B2DRectangle aSurfaceClipRect(x1,y1,x2,y2);
+
+ // concatenate transforms
+ // we use 'fround' here to avoid rounding errors. the vertices will
+ // be transformed by the overall transform and uv coordinates will
+ // be calculated from the result, and this is why we need to use
+ // integer coordinates here...
+ basegfx::B2DHomMatrix aTransform;
+ aTransform = aTransform * rTransform;
+ aTransform.translate(::basegfx::fround(rPos.getX()),
+ ::basegfx::fround(rPos.getY()));
+
+ /*
+ ######################################
+ ######################################
+ ######################################
+
+ Y
+ ^+1
+ |
+ 2 | 3
+ x------------x
+ | | |
+ | | |
+ ------|-----O------|------>X
+ -1 | | | +1
+ | | |
+ x------------x
+ 1 | 0
+ |
+ |-1
+
+ ######################################
+ ######################################
+ ######################################
+ */
+
+ // uv coordinates that map the surface rectangle
+ // to the destination rectangle.
+ const ::basegfx::B2DRectangle& rUV( getUVCoords() );
+
+ basegfx::B2DPolygon rTriangleList(basegfx::tools::clipTriangleListOnRange(rClipPoly,
+ aSurfaceClipRect));
+
+ // Push vertices to backend renderer
+ if(const sal_uInt32 nVertexCount = rTriangleList.count())
+ {
+ canvas::Vertex vertex;
+ vertex.r = 1.0f;
+ vertex.g = 1.0f;
+ vertex.b = 1.0f;
+ vertex.a = static_cast<float>(fAlpha);
+ vertex.z = 0.0f;
+
+#if defined(TRIANGLE_LOG) && defined(DBG_UTIL)
+ OSL_TRACE( "Surface::draw(): numvertices %d numtriangles %d\n",
+ nVertexCount,
+ nVertexCount/3 );
+#endif
+
+ pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_TRIANGLE );
+
+ // issue an endPrimitive() when leaving the scope
+ const ::comphelper::ScopeGuard aScopeGuard(
+ boost::bind( &::canvas::IRenderModule::endPrimitive,
+ ::boost::ref(pRenderModule) ) );
+
+ for(sal_uInt32 nIndex=0; nIndex<nVertexCount; ++nIndex)
+ {
+ const basegfx::B2DPoint &aPoint = rTriangleList.getB2DPoint(nIndex);
+ basegfx::B2DPoint aTransformedPoint(aTransform * aPoint);
+ const double tu(((aPoint.getX()-aSurfaceClipRect.getMinX())*rUV.getWidth()/w)+rUV.getMinX());
+ const double tv(((aPoint.getY()-aSurfaceClipRect.getMinY())*rUV.getHeight()/h)+rUV.getMinY());
+ vertex.u=static_cast<float>(tu);
+ vertex.v=static_cast<float>(tv);
+ vertex.x=static_cast<float>(aTransformedPoint.getX());
+ vertex.y=static_cast<float>(aTransformedPoint.getY());
+ pRenderModule->pushVertex(vertex);
+ }
+ }
+
+ return !(pRenderModule->isError());
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Surface::prepareRendering
+ //////////////////////////////////////////////////////////////////////////////////
+
+ void Surface::prepareRendering()
+ {
+ mpPageManager->validatePages();
+
+ // clients requested to draw from this surface, therefore one
+ // of the above implemented concrete rendering operations
+ // was triggered. we therefore need to ask the pagemanager
+ // to allocate some space for the fragment we're dedicated to.
+ if(!(mpFragment))
+ {
+ mpFragment = mpPageManager->allocateSpace(maSize);
+ if( mpFragment )
+ {
+ mpFragment->setColorBuffer(mpColorBuffer);
+ mpFragment->setSourceOffset(maSourceOffset);
+ }
+ }
+
+ if( mpFragment )
+ {
+ // now we need to 'select' the fragment, which will in turn
+ // pull informations from the image on demand.
+ // in case this fragment is still not located on any of the
+ // available pages ['naked'], we force the page manager to
+ // do it now, no way to defer this any longer...
+ if(!(mpFragment->select(mbIsDirty)))
+ mpPageManager->nakedFragment(mpFragment);
+
+ }
+ mbIsDirty=false;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // End of file
+ //////////////////////////////////////////////////////////////////////////////////
+}
+
diff --git a/canvas/source/tools/surface.hxx b/canvas/source/tools/surface.hxx
new file mode 100644
index 000000000000..9acda579803a
--- /dev/null
+++ b/canvas/source/tools/surface.hxx
@@ -0,0 +1,162 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_CANVAS_SURFACE_HXX
+#define INCLUDED_CANVAS_SURFACE_HXX
+
+#include <basegfx/point/b2ipoint.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/vector/b2isize.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <canvas/rendering/irendermodule.hxx>
+#include <canvas/rendering/icolorbuffer.hxx>
+#include <canvas/rendering/isurface.hxx>
+
+#include "surfacerect.hxx"
+#include "pagemanager.hxx"
+
+namespace canvas
+{
+ //////////////////////////////////////////////////////////////////////////////////
+ // Surface
+ //////////////////////////////////////////////////////////////////////////////////
+
+ /** surfaces denote occupied areas withing pages.
+
+ pages encapsulate the hardware buffers that
+ contain image data which can be used for texturing.
+ surfaces are areas within those pages.
+ */
+ class Surface
+ {
+ public:
+
+ Surface( const PageManagerSharedPtr& rPageManager,
+ const IColorBufferSharedPtr& rColorBuffer,
+ const ::basegfx::B2IPoint& rPos,
+ const ::basegfx::B2ISize& rSize );
+ ~Surface();
+
+ void setColorBufferDirty();
+
+ /** Render the surface content to screen.
+
+ @param fAlpha
+ Overall alpha for content
+
+ @param rPos
+ Output position
+
+ @param rTransform
+ Output transformation (does not affect output position)
+ */
+ bool draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DHomMatrix& rTransform );
+
+ /** Render the surface content to screen.
+
+ @param fAlpha
+ Overall alpha for content
+
+ @param rPos
+ Output position
+
+ @param rArea
+ Subset of the surface to render. Coordinate system are
+ surface area pixel, given area will be clipped to the
+ surface bounds.
+
+ @param rTransform
+ Output transformation (does not affect output position)
+ */
+ bool drawRectangularArea(
+ double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DRange& rArea,
+ const ::basegfx::B2DHomMatrix& rTransform );
+
+ /** Render the surface content to screen.
+
+ @param fAlpha
+ Overall alpha for content
+
+ @param rPos
+ Output position
+
+ @param rClipPoly
+ Clip polygon for the surface. The clip polygon is also
+ subject to the output transformation.
+
+ @param rTransform
+ Output transformation (does not affect output position)
+ */
+ bool drawWithClip( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DPolygon& rClipPoly,
+ const ::basegfx::B2DHomMatrix& rTransform );
+
+ // private attributes
+ private:
+ IColorBufferSharedPtr mpColorBuffer;
+
+ // invoking any of the above defined 'draw' methods
+ // will forward primitive commands to the rendermodule.
+ PageManagerSharedPtr mpPageManager;
+
+ FragmentSharedPtr mpFragment;
+
+ // the offset of this surface with regard to the source
+ // image. if the source image had to be tiled into multiple
+ // surfaces, this offset denotes the relative pixel distance
+ // from the source image's upper, left corner
+ ::basegfx::B2IPoint maSourceOffset;
+
+ // the size in pixels of this surface. please note that
+ // this size is likely to be smaller than the size of
+ // the colorbuffer we're associated with since we
+ // maybe represent only a part of it.
+ ::basegfx::B2ISize maSize;
+
+ bool mbIsDirty;
+
+ // private methods
+ private:
+ bool refresh( canvas::IColorBuffer& rBuffer ) const;
+ void prepareRendering();
+
+ basegfx::B2DRectangle getUVCoords() const;
+ basegfx::B2DRectangle getUVCoords( const ::basegfx::B2IPoint& rPos,
+ const ::basegfx::B2ISize& rSize ) const;
+ };
+
+ typedef ::boost::shared_ptr< Surface > SurfaceSharedPtr;
+}
+
+#endif
diff --git a/canvas/source/tools/surfaceproxy.cxx b/canvas/source/tools/surfaceproxy.cxx
new file mode 100644
index 000000000000..f4c31d4a2dc6
--- /dev/null
+++ b/canvas/source/tools/surfaceproxy.cxx
@@ -0,0 +1,182 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include <boost/bind.hpp>
+#include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
+#include <basegfx/polygon/b2dpolygontriangulator.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include "surfaceproxy.hxx"
+
+namespace canvas
+{
+ //////////////////////////////////////////////////////////////////////////////////
+ // SurfaceProxy::SurfaceProxy
+ //////////////////////////////////////////////////////////////////////////////////
+
+ SurfaceProxy::SurfaceProxy( const canvas::IColorBufferSharedPtr& pBuffer,
+ const PageManagerSharedPtr& pPageManager ) :
+ mpPageManager( pPageManager ),
+ maSurfaceList(),
+ mpBuffer( pBuffer )
+ {
+ const ::basegfx::B2ISize aImageSize(mpBuffer->getWidth(),mpBuffer->getHeight());
+ const ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize());
+ const sal_Int32 aPageSizeX(aPageSize.getX());
+ const sal_Int32 aPageSizeY(aPageSize.getY());
+ const sal_Int32 aImageSizeX(aImageSize.getX());
+ const sal_Int32 aImageSizeY(aImageSize.getY());
+
+ // see if the size of the colorbuffer is larger than the size
+ // of a single page. if this is the case we divide the
+ // colorbuffer into as many surfaces as we need to get the
+ // whole area distributed. otherwise (the colorbuffer is
+ // smaller than the size of a single page) we search for free
+ // pages or create a new one.
+ // the incoming image is too large to fit into a single
+ // page. strategy: we split the image into rectangular
+ // areas that are as large as the maximum page size
+ // dictates and follow the strategy for fitting images.
+ size_t dwNumSurfaces(0);
+ for(sal_Int32 y=0; y<aImageSizeY; y+=aPageSizeY)
+ for(sal_Int32 x=0; x<aImageSizeX; x+=aPageSizeX)
+ ++dwNumSurfaces;
+ maSurfaceList.reserve(dwNumSurfaces);
+
+ for(sal_Int32 y=0; y<aImageSizeY; y+=aPageSizeY)
+ {
+ for(sal_Int32 x=0; x<aImageSizeX; x+=aPageSizeX)
+ {
+ // the current surface is located at the position [x,y]
+ // and has the size [min(restx,pagesizex),min(resty,pagesizey)
+ ::basegfx::B2IPoint aOffset(x,y);
+ ::basegfx::B2ISize aSize( ::std::min( aImageSize.getX()-x,
+ aPageSize.getX() ),
+ ::std::min( aImageSize.getY()-y,
+ aPageSize.getY() ) );
+
+ maSurfaceList.push_back(
+ SurfaceSharedPtr(
+ new Surface(
+ mpPageManager,
+ mpBuffer,
+ aOffset,
+ aSize)));
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // SurfaceProxy::setColorBufferDirty
+ //////////////////////////////////////////////////////////////////////////////////
+
+ void SurfaceProxy::setColorBufferDirty()
+ {
+ ::std::for_each( maSurfaceList.begin(),
+ maSurfaceList.end(),
+ ::boost::mem_fn(&Surface::setColorBufferDirty));
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // SurfaceProxy::draw
+ //////////////////////////////////////////////////////////////////////////////////
+
+ bool SurfaceProxy::draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ ::std::for_each( maSurfaceList.begin(),
+ maSurfaceList.end(),
+ ::boost::bind( &Surface::draw,
+ _1,
+ fAlpha,
+ ::boost::cref(rPos),
+ ::boost::cref(rTransform)));
+
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // SurfaceProxy::draw
+ //////////////////////////////////////////////////////////////////////////////////
+
+ bool SurfaceProxy::draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DRange& rArea,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ ::std::for_each( maSurfaceList.begin(),
+ maSurfaceList.end(),
+ ::boost::bind(&Surface::drawRectangularArea,
+ _1,
+ fAlpha,
+ ::boost::cref(rPos),
+ ::boost::cref(rArea),
+ ::boost::cref(rTransform)));
+
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // SurfaceProxy::draw
+ //////////////////////////////////////////////////////////////////////////////////
+
+ bool SurfaceProxy::draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DPolyPolygon& rClipPoly,
+ const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ const ::basegfx::B2DPolygon& rTriangulatedPolygon(
+ ::basegfx::triangulator::triangulate(rClipPoly));
+
+#if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0
+ // dump polygons
+ OSL_TRACE( "Original clip polygon: %s\n"
+ "Triangulated polygon: %s\n",
+ rtl::OUStringToOString(
+ basegfx::tools::exportToSvgD( rClipPoly ),
+ RTL_TEXTENCODING_ASCII_US).getStr(),
+ rtl::OUStringToOString(
+ basegfx::tools::exportToSvgD(
+ basegfx::B2DPolyPolygon(rTriangulatedPolygon) ),
+ RTL_TEXTENCODING_ASCII_US).getStr() );
+#endif
+
+ ::std::for_each( maSurfaceList.begin(),
+ maSurfaceList.end(),
+ ::boost::bind(&Surface::drawWithClip,
+ _1,
+ fAlpha,
+ ::boost::cref(rPos),
+ ::boost::cref(rTriangulatedPolygon),
+ ::boost::cref(rTransform)));
+
+ return true;
+ }
+}
diff --git a/canvas/source/tools/surfaceproxy.hxx b/canvas/source/tools/surfaceproxy.hxx
new file mode 100644
index 000000000000..7e42096c541b
--- /dev/null
+++ b/canvas/source/tools/surfaceproxy.hxx
@@ -0,0 +1,134 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_CANVAS_SURFACEPROXY_HXX
+#define INCLUDED_CANVAS_SURFACEPROXY_HXX
+
+#include <canvas/rendering/isurfaceproxy.hxx>
+#include <canvas/rendering/icolorbuffer.hxx>
+
+#include "pagemanager.hxx"
+#include "surface.hxx"
+
+namespace canvas
+{
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // SurfaceProxy
+ //////////////////////////////////////////////////////////////////////////////////
+
+ /** Definition of the surface proxy class.
+
+ Surface proxies are the connection between *one* source image
+ and *one or more* hardware surfaces (or textures). in a
+ logical structure surface proxies represent soley this
+ dependeny plus some simple cache management.
+ */
+ class SurfaceProxy : public ISurfaceProxy
+ {
+ public:
+
+ SurfaceProxy( const canvas::IColorBufferSharedPtr& pBuffer,
+ const PageManagerSharedPtr &pPageManager );
+
+ // ISurfaceProxy interface
+ virtual void setColorBufferDirty();
+
+ /** Render the surface content to screen.
+
+ @param fAlpha
+ Overall alpha for content
+
+ @param rPos
+ Output position
+
+ @param rTransform
+ Output transformation (does not affect output position)
+ */
+ virtual bool draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DHomMatrix& rTransform );
+
+ /** Render the surface content to screen.
+
+ @param fAlpha
+ Overall alpha for content
+
+ @param rPos
+ Output position
+
+ @param rArea
+ Subset of the surface to render. Coordinate system are
+ surface area pixel, given area will be clipped to the
+ surface bounds.
+
+ @param rTransform
+ Output transformation (does not affect output position)
+ */
+ virtual bool draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DRange& rArea,
+ const ::basegfx::B2DHomMatrix& rTransform );
+
+ /** Render the surface content to screen.
+
+ @param fAlpha
+ Overall alpha for content
+
+ @param rPos
+ Output position
+
+ @param rClipPoly
+ Clip polygon for the surface. The clip polygon is also
+ subject to the output transformation.
+
+ @param rTransform
+ Output transformation (does not affect output position)
+ */
+ virtual bool draw( double fAlpha,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DPolyPolygon& rClipPoly,
+ const ::basegfx::B2DHomMatrix& rTransform );
+
+ private:
+ PageManagerSharedPtr mpPageManager;
+
+ // the pagemanager will distribute the image
+ // to one or more surfaces, this is why we
+ // need a list here.
+ std::vector<SurfaceSharedPtr> maSurfaceList;
+
+ // pointer to the source of image data
+ // which always is stored in system memory,
+ // 32bit rgba and can have any size.
+ canvas::IColorBufferSharedPtr mpBuffer;
+ };
+
+ typedef ::boost::shared_ptr< SurfaceProxy > SurfaceProxySharedPtr;
+}
+
+#endif
diff --git a/canvas/source/tools/surfaceproxymanager.cxx b/canvas/source/tools/surfaceproxymanager.cxx
new file mode 100644
index 000000000000..dcc2ff574b57
--- /dev/null
+++ b/canvas/source/tools/surfaceproxymanager.cxx
@@ -0,0 +1,86 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include <canvas/rendering/isurfaceproxymanager.hxx>
+#include <canvas/rendering/isurfaceproxy.hxx>
+#include "surfaceproxy.hxx"
+
+namespace canvas
+{
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // SurfaceProxyManager
+ //////////////////////////////////////////////////////////////////////////////////
+
+ class SurfaceProxyManager : public ISurfaceProxyManager
+ {
+ public:
+
+ SurfaceProxyManager( const IRenderModuleSharedPtr pRenderModule ) :
+ mpPageManager( new PageManager(pRenderModule) )
+ {
+ }
+
+ /** the whole idea is build around the concept that you create
+ some arbitrary buffer which contains the image data and
+ tell the texture manager about it. from there on you can
+ draw this image using any kind of graphics api you want.
+ in the technical sense we allocate some space in local
+ videomemory or AGP memory which will be filled on demand,
+ which means if there exists any rendering operation that
+ needs to read from this memory location. this method
+ creates a logical hardware surface object which uses the
+ given color buffer as the image source. internally this
+ texture may be distributed to several real hardware
+ surfaces.
+ */
+ virtual ISurfaceProxySharedPtr createSurfaceProxy( const IColorBufferSharedPtr& pBuffer ) const
+ {
+ // not much to do for now, simply allocate a new surface
+ // proxy from our internal pool and initialize this thing
+ // properly. we *don't* create a hardware surface for now.
+ return SurfaceProxySharedPtr(new SurfaceProxy(pBuffer,mpPageManager));
+ }
+
+ private:
+ PageManagerSharedPtr mpPageManager;
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // createSurfaceProxyManager
+ //////////////////////////////////////////////////////////////////////////////////
+
+ ISurfaceProxyManagerSharedPtr createSurfaceProxyManager( const IRenderModuleSharedPtr& rRenderModule )
+ {
+ return ISurfaceProxyManagerSharedPtr(
+ new SurfaceProxyManager(
+ rRenderModule));
+ }
+}
diff --git a/canvas/source/tools/surfacerect.hxx b/canvas/source/tools/surfacerect.hxx
new file mode 100644
index 000000000000..cbeaa5e144d7
--- /dev/null
+++ b/canvas/source/tools/surfacerect.hxx
@@ -0,0 +1,135 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_CANVAS_SURFACERECT_HXX
+#define INCLUDED_CANVAS_SURFACERECT_HXX
+
+#include <basegfx/point/b2ipoint.hxx>
+#include <basegfx/vector/b2isize.hxx>
+
+namespace canvas
+{
+ //////////////////////////////////////////////////////////////////////////////////
+ // SurfaceRect
+ //////////////////////////////////////////////////////////////////////////////////
+
+ struct SurfaceRect
+ {
+ ::basegfx::B2IPoint maPos;
+ ::basegfx::B2ISize maSize;
+ ::basegfx::B2IPoint maBackup;
+ bool bEnabled;
+
+ explicit SurfaceRect( const ::basegfx::B2ISize &rSize ) :
+ maPos(),
+ maSize(rSize),
+ maBackup(),
+ bEnabled(true)
+ {
+ }
+
+ // coordinates contained in this rectangle are
+ // constrained to the following rules:
+ // 1) p.x >= pos.x
+ // 2) p.x <= pos.x+size.x
+ // 3) p.y >= pos.y
+ // 4) p.y <= pos.y+size.y
+ // in other words, 'size' means the number of pixels
+ // this rectangle encloses plus one. for example with pos[0,0]
+ // and size[512,512], p[512,512] would return inside.
+ // a size of [0,0] therefore denotes a one-by-one rectangle.
+ bool pointInside( sal_Int32 px, sal_Int32 py ) const
+ {
+ const sal_Int32 x1(maPos.getX());
+ const sal_Int32 y1(maPos.getY());
+ const sal_Int32 x2(maPos.getX()+maSize.getX());
+ const sal_Int32 y2(maPos.getY()+maSize.getY());
+ if(px < x1) return false;
+ if(px >= x2) return false;
+ if(py < y1) return false;
+ if(py >= y2) return false;
+ return true;
+ }
+
+ // returns true if the horizontal line intersects the rect.
+ bool hLineIntersect( sal_Int32 lx1, sal_Int32 lx2, sal_Int32 ly ) const
+ {
+ const sal_Int32 x1(maPos.getX());
+ const sal_Int32 y1(maPos.getY());
+ const sal_Int32 x2(maPos.getX()+maSize.getX());
+ const sal_Int32 y2(maPos.getY()+maSize.getY());
+ if(ly < y1) return false;
+ if(ly >= y2) return false;
+ if((lx1 < x1) && (lx2 < x1)) return false;
+ if((lx1 >= x2) && (lx2 >= x2)) return false;
+ return true;
+ }
+
+ //! Returns true if the vertical line intersects the rect.
+ bool vLineIntersect( sal_Int32 lx, sal_Int32 ly1, sal_Int32 ly2 ) const
+ {
+ const sal_Int32 x1(maPos.getX());
+ const sal_Int32 y1(maPos.getY());
+ const sal_Int32 x2(maPos.getX()+maSize.getX());
+ const sal_Int32 y2(maPos.getY()+maSize.getY());
+ if(lx < x1) return false;
+ if(lx >= x2) return false;
+ if((ly1 < y1) && (ly2 < y1)) return false;
+ if((ly1 >= y2) && (ly2 >= y2)) return false;
+ return true;
+ }
+
+ // returns true if the passed rect intersects this one.
+ bool intersection( const SurfaceRect& r ) const
+ {
+ const sal_Int32 x1(maPos.getX());
+ const sal_Int32 y1(maPos.getY());
+ const sal_Int32 x2(maPos.getX()+maSize.getX());
+ const sal_Int32 y2(maPos.getY()+maSize.getY());
+ if(r.hLineIntersect(x1,x2,y1)) return true;
+ if(r.hLineIntersect(x1,x2,y2)) return true;
+ if(r.vLineIntersect(x1,y1,y2)) return true;
+ if(r.vLineIntersect(x2,y1,y2)) return true;
+ return false;
+ }
+
+ bool inside( const SurfaceRect& r ) const
+ {
+ const sal_Int32 x1(maPos.getX());
+ const sal_Int32 y1(maPos.getY());
+ const sal_Int32 x2(maPos.getX()+maSize.getX());
+ const sal_Int32 y2(maPos.getY()+maSize.getY());
+ if(!(r.pointInside(x1,y1))) return false;
+ if(!(r.pointInside(x2,y1))) return false;
+ if(!(r.pointInside(x2,y2))) return false;
+ if(!(r.pointInside(x1,y2))) return false;
+ return true;
+ }
+ };
+}
+
+#endif
diff --git a/canvas/source/tools/verifyinput.cxx b/canvas/source/tools/verifyinput.cxx
new file mode 100644
index 000000000000..42ab1c7aee19
--- /dev/null
+++ b/canvas/source/tools/verifyinput.cxx
@@ -0,0 +1,926 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_canvas.hxx"
+
+#include <com/sun/star/geometry/AffineMatrix2D.hpp>
+#include <com/sun/star/geometry/Matrix2D.hpp>
+#include <com/sun/star/geometry/RealPoint2D.hpp>
+#include <com/sun/star/geometry/RealSize2D.hpp>
+#include <com/sun/star/geometry/IntegerPoint2D.hpp>
+#include <com/sun/star/geometry/IntegerSize2D.hpp>
+#include <com/sun/star/geometry/RealRectangle2D.hpp>
+#include <com/sun/star/geometry/RealBezierSegment2D.hpp>
+#include <com/sun/star/rendering/RenderState.hpp>
+#include <com/sun/star/rendering/ViewState.hpp>
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/rendering/CompositeOperation.hpp>
+#include <com/sun/star/rendering/TexturingMode.hpp>
+#include <com/sun/star/util/Endianness.hpp>
+#include <com/sun/star/rendering/PathCapType.hpp>
+#include <com/sun/star/rendering/PathJoinType.hpp>
+#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
+#include <com/sun/star/rendering/FloatingPointBitmapFormat.hpp>
+#include <com/sun/star/rendering/FloatingPointBitmapLayout.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/range/b2irange.hxx>
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+#include <canvas/verifyinput.hxx>
+#include <canvas/canvastools.hxx>
+
+
+using namespace ::com::sun::star;
+
+namespace canvas
+{
+ namespace tools
+ {
+ void verifyInput( const geometry::RealPoint2D& rPoint,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos )
+ {
+ (void)pStr; (void)xIf; (void)nArgPos;
+
+#if OSL_DEBUG_LEVEL > 0
+ if( !::rtl::math::isFinite( rPoint.X ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): point X value contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+
+ if( !::rtl::math::isFinite( rPoint.Y ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): point X value contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+#else
+ if( !::rtl::math::isFinite( rPoint.X ) ||
+ !::rtl::math::isFinite( rPoint.Y ) )
+ {
+ throw lang::IllegalArgumentException();
+ }
+#endif
+ }
+
+ void verifyInput( const geometry::RealSize2D& rSize,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos )
+ {
+ (void)pStr; (void)xIf; (void)nArgPos;
+
+#if OSL_DEBUG_LEVEL > 0
+ if( !::rtl::math::isFinite( rSize.Width ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): size.Width value contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+
+ if( !::rtl::math::isFinite( rSize.Height ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): size.Height value contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+#else
+ if( !::rtl::math::isFinite( rSize.Width ) ||
+ !::rtl::math::isFinite( rSize.Height ) )
+ {
+ throw lang::IllegalArgumentException();
+ }
+#endif
+ }
+
+ void verifyInput( const geometry::RealBezierSegment2D& rSegment,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos )
+ {
+ (void)pStr; (void)xIf; (void)nArgPos;
+
+#if OSL_DEBUG_LEVEL > 0
+ if( !::rtl::math::isFinite( rSegment.Px ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bezier segment's Px value contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+
+ if( !::rtl::math::isFinite( rSegment.Py ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bezier segment's Py value contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+
+ if( !::rtl::math::isFinite( rSegment.C1x ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bezier segment's C1x value contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+
+ if( !::rtl::math::isFinite( rSegment.C1y ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bezier segment's C1y value contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+
+ if( !::rtl::math::isFinite( rSegment.C2x ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bezier segment's C2x value contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+
+ if( !::rtl::math::isFinite( rSegment.C2y ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bezier segment's C2y value contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+#else
+ if( !::rtl::math::isFinite( rSegment.Px ) ||
+ !::rtl::math::isFinite( rSegment.Py ) ||
+ !::rtl::math::isFinite( rSegment.C1x ) ||
+ !::rtl::math::isFinite( rSegment.C1y ) ||
+ !::rtl::math::isFinite( rSegment.C2x ) ||
+ !::rtl::math::isFinite( rSegment.C2y ) )
+ {
+ throw lang::IllegalArgumentException();
+ }
+#endif
+ }
+
+ void verifyInput( const geometry::RealRectangle2D& rRect,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos )
+ {
+ (void)pStr; (void)xIf; (void)nArgPos;
+
+#if OSL_DEBUG_LEVEL > 0
+ if( !::rtl::math::isFinite( rRect.X1 ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): rectangle point X1 contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+
+ if( !::rtl::math::isFinite( rRect.Y1 ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): rectangle point Y1 contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+
+ if( !::rtl::math::isFinite( rRect.X2 ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): rectangle point X2 contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+
+ if( !::rtl::math::isFinite( rRect.Y2 ) )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): rectangle point Y2 contains infinite or NAN"),
+ xIf,
+ nArgPos );
+ }
+#else
+ if( !::rtl::math::isFinite( rRect.X1 ) ||
+ !::rtl::math::isFinite( rRect.Y1 ) ||
+ !::rtl::math::isFinite( rRect.X2 ) ||
+ !::rtl::math::isFinite( rRect.Y2 ) )
+ {
+ throw lang::IllegalArgumentException();
+ }
+#endif
+ }
+
+ void verifyInput( const geometry::AffineMatrix2D& matrix,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos )
+ {
+ (void)pStr; (void)xIf; (void)nArgPos;
+
+#if OSL_DEBUG_LEVEL > 0
+ const sal_Int32 nBinaryState(
+ 100000 * !::rtl::math::isFinite( matrix.m00 ) +
+ 10000 * !::rtl::math::isFinite( matrix.m01 ) +
+ 1000 * !::rtl::math::isFinite( matrix.m02 ) +
+ 100 * !::rtl::math::isFinite( matrix.m10 ) +
+ 10 * !::rtl::math::isFinite( matrix.m11 ) +
+ 1 * !::rtl::math::isFinite( matrix.m12 ) );
+
+ if( nBinaryState )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): AffineMatrix2D contains infinite or NAN value(s) at the following positions (m00-m12): ") +
+ ::rtl::OUString::valueOf(nBinaryState),
+ xIf,
+ nArgPos );
+ }
+#else
+ if( !::rtl::math::isFinite( matrix.m00 ) ||
+ !::rtl::math::isFinite( matrix.m01 ) ||
+ !::rtl::math::isFinite( matrix.m02 ) ||
+ !::rtl::math::isFinite( matrix.m10 ) ||
+ !::rtl::math::isFinite( matrix.m11 ) ||
+ !::rtl::math::isFinite( matrix.m12 ) )
+ {
+ throw lang::IllegalArgumentException();
+ }
+#endif
+ }
+
+ void verifyInput( const geometry::Matrix2D& matrix,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos )
+ {
+ (void)pStr; (void)xIf; (void)nArgPos;
+
+#if OSL_DEBUG_LEVEL > 0
+ const sal_Int32 nBinaryState(
+ 1000 * !::rtl::math::isFinite( matrix.m00 ) +
+ 100 * !::rtl::math::isFinite( matrix.m01 ) +
+ 10 * !::rtl::math::isFinite( matrix.m10 ) +
+ 1 * !::rtl::math::isFinite( matrix.m11 ) );
+
+ if( nBinaryState )
+ {
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): Matrix2D contains infinite or NAN value(s) at the following positions (m00-m11): ") +
+ ::rtl::OUString::valueOf(nBinaryState),
+ xIf,
+ nArgPos );
+ }
+#else
+ if( !::rtl::math::isFinite( matrix.m00 ) ||
+ !::rtl::math::isFinite( matrix.m01 ) ||
+ !::rtl::math::isFinite( matrix.m10 ) ||
+ !::rtl::math::isFinite( matrix.m11 ) )
+ {
+ throw lang::IllegalArgumentException();
+ }
+#endif
+ }
+
+ void verifyInput( const rendering::ViewState& viewState,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos )
+ {
+ verifyInput( viewState.AffineTransform,
+ pStr, xIf, nArgPos );
+ }
+
+ void verifyInput( const rendering::RenderState& renderState,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos,
+ sal_Int32 nMinColorComponents )
+ {
+ verifyInput( renderState.AffineTransform,
+ pStr, xIf, nArgPos );
+
+ if( renderState.DeviceColor.getLength() < nMinColorComponents )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): render state's device color has too few components (") +
+ ::rtl::OUString::valueOf(nMinColorComponents) +
+ ::rtl::OUString::createFromAscii(" expected, ") +
+ ::rtl::OUString::valueOf(renderState.DeviceColor.getLength()) +
+ ::rtl::OUString::createFromAscii(" provided)"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( renderState.CompositeOperation < rendering::CompositeOperation::CLEAR ||
+ renderState.CompositeOperation > rendering::CompositeOperation::SATURATE )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): render state's CompositeOperation value out of range (") +
+ ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(renderState.CompositeOperation)) +
+ ::rtl::OUString::createFromAscii(" not known)"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+ }
+
+ void verifyInput( const rendering::Texture& texture,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos )
+ {
+ verifyInput( texture.AffineTransform,
+ pStr, xIf, nArgPos );
+
+ if( !::rtl::math::isFinite( texture.Alpha ) ||
+ texture.Alpha < 0.0 ||
+ texture.Alpha > 1.0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): textures' alpha value out of range (is ") +
+ ::rtl::OUString::valueOf(texture.Alpha) +
+ ::rtl::OUString::createFromAscii(")"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( texture.NumberOfHatchPolygons < 0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): textures' NumberOfHatchPolygons is negative"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( texture.RepeatModeX < rendering::TexturingMode::NONE ||
+ texture.RepeatModeX > rendering::TexturingMode::REPEAT )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): textures' RepeatModeX value is out of range (") +
+ ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(texture.RepeatModeX)) +
+ ::rtl::OUString::createFromAscii(" not known)"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( texture.RepeatModeY < rendering::TexturingMode::NONE ||
+ texture.RepeatModeY > rendering::TexturingMode::REPEAT )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): textures' RepeatModeY value is out of range (") +
+ ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(texture.RepeatModeY)) +
+ ::rtl::OUString::createFromAscii(" not known)"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+ }
+
+ namespace
+ {
+ struct VerifyDashValue
+ {
+ VerifyDashValue( const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos ) :
+ mpStr( pStr ),
+ mrIf( xIf ),
+ mnArgPos( nArgPos )
+ {
+ }
+
+ void operator()( const double& rVal )
+ {
+ if( !::rtl::math::isFinite( rVal ) || rVal < 0.0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(mpStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): one of stroke attributes' DashArray value out of range (is ") +
+ ::rtl::OUString::valueOf(rVal) +
+ ::rtl::OUString::createFromAscii(")"),
+ mrIf,
+ mnArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+ }
+
+ const char* mpStr;
+ const uno::Reference< uno::XInterface >& mrIf;
+ sal_Int16 mnArgPos;
+ };
+ }
+
+ void verifyInput( const rendering::StrokeAttributes& strokeAttributes,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos )
+ {
+ if( !::rtl::math::isFinite( strokeAttributes.StrokeWidth ) ||
+ strokeAttributes.StrokeWidth < 0.0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): stroke attributes' StrokeWidth value out of range (is ") +
+ ::rtl::OUString::valueOf(strokeAttributes.StrokeWidth) +
+ ::rtl::OUString::createFromAscii(")"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( !::rtl::math::isFinite( strokeAttributes.MiterLimit ) ||
+ strokeAttributes.MiterLimit < 0.0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): stroke attributes' MiterLimit value out of range (is ") +
+ ::rtl::OUString::valueOf(strokeAttributes.MiterLimit) +
+ ::rtl::OUString::createFromAscii(")"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ ::std::for_each( strokeAttributes.DashArray.getConstArray(),
+ strokeAttributes.DashArray.getConstArray() + strokeAttributes.DashArray.getLength(),
+ VerifyDashValue( pStr, xIf, nArgPos ) );
+
+ ::std::for_each( strokeAttributes.LineArray.getConstArray(),
+ strokeAttributes.LineArray.getConstArray() + strokeAttributes.LineArray.getLength(),
+ VerifyDashValue( pStr, xIf, nArgPos ) );
+
+ if( strokeAttributes.StartCapType < rendering::PathCapType::BUTT ||
+ strokeAttributes.StartCapType > rendering::PathCapType::SQUARE )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): stroke attributes' StartCapType value is out of range (") +
+ ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(strokeAttributes.StartCapType)) +
+ ::rtl::OUString::createFromAscii(" not known)"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( strokeAttributes.EndCapType < rendering::PathCapType::BUTT ||
+ strokeAttributes.EndCapType > rendering::PathCapType::SQUARE )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): stroke attributes' StartCapType value is out of range (") +
+ ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(strokeAttributes.EndCapType)) +
+ ::rtl::OUString::createFromAscii(" not known)"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( strokeAttributes.JoinType < rendering::PathJoinType::NONE ||
+ strokeAttributes.JoinType > rendering::PathJoinType::BEVEL )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): stroke attributes' JoinType value is out of range (") +
+ ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(strokeAttributes.JoinType)) +
+ ::rtl::OUString::createFromAscii(" not known)"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+ }
+
+ void verifyInput( const rendering::IntegerBitmapLayout& bitmapLayout,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos )
+ {
+ (void)pStr; (void)xIf; (void)nArgPos;
+
+ if( bitmapLayout.ScanLines < 0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ScanLines is negative"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( bitmapLayout.ScanLineBytes < 0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ScanLineBytes is negative"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( !bitmapLayout.ColorSpace.is() )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ColorSpace is invalid"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+ else
+ {
+ if( bitmapLayout.ColorSpace->getBitsPerPixel() < 0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ColorSpace getBitsPerPixel() is negative"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( bitmapLayout.ColorSpace->getEndianness() < util::Endianness::LITTLE ||
+ bitmapLayout.ColorSpace->getEndianness() > util::Endianness::BIG )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ColorSpace getEndianness() value is out of range (") +
+ ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(bitmapLayout.ColorSpace->getEndianness())) +
+ ::rtl::OUString::createFromAscii(" not known)"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+ }
+ }
+
+ void verifyInput( const rendering::FloatingPointBitmapLayout& bitmapLayout,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos )
+ {
+ (void)pStr; (void)xIf; (void)nArgPos;
+
+ if( bitmapLayout.ScanLines < 0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ScanLines is negative"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( bitmapLayout.ScanLineBytes < 0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ScanLineBytes is negative"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( !bitmapLayout.ColorSpace.is() )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ColorSpace is invalid"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( bitmapLayout.NumComponents < 0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's NumComponents is negative"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( bitmapLayout.Endianness < util::Endianness::LITTLE ||
+ bitmapLayout.Endianness > util::Endianness::BIG )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's Endianness value is out of range (") +
+ ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(bitmapLayout.Endianness)) +
+ ::rtl::OUString::createFromAscii(" not known)"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( bitmapLayout.Format < rendering::FloatingPointBitmapFormat::HALFFLOAT ||
+ bitmapLayout.Format > rendering::FloatingPointBitmapFormat::DOUBLE )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's Format value is out of range (") +
+ ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(bitmapLayout.Format)) +
+ ::rtl::OUString::createFromAscii(" not known)"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+ }
+
+ void verifyInput( const rendering::FontInfo& /*fontInfo*/,
+ const char* /*pStr*/,
+ const uno::Reference< uno::XInterface >& /*xIf*/,
+ ::sal_Int16 /*nArgPos*/ )
+ {
+ // TODO(E3): Implement FontDescription checks, once the
+ // Panose stuff is ready.
+ }
+
+ void verifyInput( const rendering::FontRequest& fontRequest,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf,
+ ::sal_Int16 nArgPos )
+ {
+ verifyInput( fontRequest.FontDescription,
+ pStr, xIf, nArgPos );
+
+ if( !::rtl::math::isFinite( fontRequest.CellSize ) )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): font request's CellSize value contains infinite or NAN"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( !::rtl::math::isFinite( fontRequest.ReferenceAdvancement ) )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): font request's ReferenceAdvancement value contains infinite or NAN"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( fontRequest.CellSize != 0.0 &&
+ fontRequest.ReferenceAdvancement != 0.0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyInput(): font request's CellSize and ReferenceAdvancement are mutually exclusive, one of them must be 0.0"),
+ xIf,
+ nArgPos );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+ }
+
+ void verifyIndexRange( const geometry::IntegerRectangle2D& rect,
+ const geometry::IntegerSize2D& size )
+ {
+ const ::basegfx::B2IRange aRect(
+ ::basegfx::unotools::b2IRectangleFromIntegerRectangle2D(
+ rect ) );
+
+ if( aRect.getMinX() < 0 ||
+ aRect.getMaxX() > size.Width ||
+ aRect.getMinY() < 0 ||
+ aRect.getMaxY() > size.Height )
+ {
+ throw ::com::sun::star::lang::IndexOutOfBoundsException();
+ }
+ }
+
+ void verifyIndexRange( const geometry::IntegerPoint2D& pos,
+ const geometry::IntegerSize2D& size )
+ {
+ if( pos.X < 0 ||
+ pos.X > size.Width ||
+ pos.Y < 0 ||
+ pos.Y > size.Height )
+ {
+ throw ::com::sun::star::lang::IndexOutOfBoundsException();
+ }
+ }
+
+ void verifyBitmapSize( const geometry::IntegerSize2D& size,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf )
+ {
+ (void)pStr; (void)xIf;
+
+ if( size.Width <= 0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyBitmapSize(): size has 0 or negative width (value: ") +
+ ::rtl::OUString::valueOf(size.Width) +
+ ::rtl::OUString::createFromAscii(")"),
+ xIf,
+ 0 );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( size.Height <= 0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifyBitmapSize(): size has 0 or negative height (value: ") +
+ ::rtl::OUString::valueOf(size.Height) +
+ ::rtl::OUString::createFromAscii(")"),
+ xIf,
+ 0 );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+ }
+
+ void verifySpriteSize( const geometry::RealSize2D& size,
+ const char* pStr,
+ const uno::Reference< uno::XInterface >& xIf )
+ {
+ (void)pStr; (void)xIf;
+
+ if( size.Width <= 0.0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifySpriteSize(): size has 0 or negative width (value: ") +
+ ::rtl::OUString::valueOf(size.Width) +
+ ::rtl::OUString::createFromAscii(")"),
+ xIf,
+ 0 );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+
+ if( size.Height <= 0.0 )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ throw lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(pStr) +
+ ::rtl::OUString::createFromAscii(": verifySpriteSize(): size has 0 or negative height (value: ") +
+ ::rtl::OUString::valueOf(size.Height) +
+ ::rtl::OUString::createFromAscii(")"),
+ xIf,
+ 0 );
+#else
+ throw lang::IllegalArgumentException();
+#endif
+ }
+ }
+
+
+ } // namespace tools
+
+} // namespace canvas