office-gobmx/basebmp/source/bitmapdevice.cxx

1461 lines
59 KiB
C++

/*************************************************************************
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: bitmapdevice.cxx,v $
*
* $Revision: 1.10 $
*
* last change: $Author: thb $ $Date: 2006-06-08 13:14:02 $
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
*
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2005 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library 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 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
************************************************************************/
#include "basebmp/bitmapdevice.hxx"
#include "basebmp/packedpixeliterator.hxx"
#include "basebmp/pixeliterator.hxx"
#include "basebmp/paletteimageaccessor.hxx"
#include "basebmp/color.hxx"
#include "basebmp/accessor.hxx"
#include "basebmp/accessoradapters.hxx"
#include "basebmp/scanlineformats.hxx"
#include "basebmp/linerenderer.hxx"
#include "basebmp/compositeiterator.hxx"
#include <rtl/alloc.h>
#include <rtl/memory.h>
#include <osl/diagnose.h>
#include <basegfx/tools/tools.hxx>
#include <basegfx/range/b2irange.hxx>
#include <basegfx/range/b2drange.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolygonclipper.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/polygon/b2dpolypolygonrasterconverter.hxx>
#include <basegfx/point/b2ipoint.hxx>
#include <basegfx/vector/b2ivector.hxx>
#include <vigra/basicimage.hxx>
#include <vigra/imageiterator.hxx>
#include <vigra/resizeimage.hxx>
#include <vigra/copyimage.hxx>
#include <vigra/tuple.hxx>
namespace basebmp
{
namespace
{
// Common accessor and iterator types
//------------------------------------------------------------------------
typedef PaletteImageAccessor<Color,sal_uInt8> PaletteAccessor;
typedef PackedPixelIterator< sal_uInt8,
1,
true > MaskIterator;
typedef StandardAccessor< sal_uInt8 > MaskAccessor;
typedef PixelIterator< sal_uInt8 > AlphaMaskIterator;
typedef vigra::AccessorTraits< sal_uInt8 >::default_accessor AlphaMaskAccessor;
typedef PixelIterator<Color> ThirtyTwoBitPixelIterator;
typedef vigra::AccessorTraits<Color>::default_accessor ThirtyTwoBitAccessor;
// metafunctions to retrieve correct POD from/to basebmp::Color
//------------------------------------------------------------------------
/// type-safe conversion between color and pod
template< typename DataType > struct GreyScaleFromColor
{
typedef DataType value_type;
DataType operator()( Color c ) { return c.getGrayscale(); }
};
/// type-safe conversion between pod and color
template< typename DataType > struct ColorFromGreyScale
{
typedef DataType value_type;
Color operator()( DataType c ) { return Color(c,c,c); }
};
/// Get converter from color to given data type
template< typename DataType > struct fromColorConverter;
template<> struct fromColorConverter< sal_uInt8 >
{
typedef GreyScaleFromColor<sal_uInt8> type;
};
template<> struct fromColorConverter< Color >
{
typedef std::identity<Color> type;
};
/// Get converter from given data type to Color
template< typename DataType > struct toColorConverter;
template<> struct toColorConverter< sal_uInt8 >
{
typedef ColorFromGreyScale<sal_uInt8> type;
};
template<> struct toColorConverter< Color >
{
typedef std::identity<Color> type;
};
// Polygon scanline conversion
//------------------------------------------------------------------------
template< class DestIterator, class DestAccessor > class Renderer :
public basegfx::B2DPolyPolygonRasterConverter
{
private:
basegfx::B2IRange bounds_;
typename DestAccessor::value_type fillColor_;
typename DestAccessor::value_type clearColor_;
DestIterator begin_;
DestAccessor accessor_;
public:
Renderer(const basegfx::B2DPolyPolygon& rPolyPolyRaster,
typename DestAccessor::value_type fillColor,
const basegfx::B2IRange& bounds,
DestIterator begin,
DestIterator end,
DestAccessor accessor ) :
B2DPolyPolygonRasterConverter(rPolyPolyRaster,
basegfx::B2DRange(bounds) ),
bounds_(bounds),
fillColor_( fillColor ),
begin_( begin ),
accessor_( accessor )
{
}
virtual void span(const double& rfXLeft,
const double& rfXRight,
sal_Int32 nY,
bool bOn )
{
if( !bOn ||
nY < bounds_.getMinY() ||
nY >= bounds_.getMaxY() ||
rfXLeft >= bounds_.getMaxX() ||
rfXRight < bounds_.getMinX() )
{
return;
}
// clip span to bitmap bounds
const sal_Int32 nStartX( std::max( bounds_.getMinX(),
std::min( bounds_.getMaxX()-1,
basegfx::fround( rfXLeft ))));
const sal_Int32 nEndX ( std::max( bounds_.getMinX(),
std::min( bounds_.getMaxX(),
basegfx::fround( rfXRight ))));
DestIterator currIter( begin_ + vigra::Diff2D(0,nY) );
typename DestIterator::row_iterator rowIter( currIter.rowIterator() + nStartX);
typename DestIterator::row_iterator rowEnd( currIter.rowIterator() + nEndX );
// TODO(P2): Provide specialized span fill methods on the
// iterator/accessor
while( rowIter != rowEnd )
accessor_.set(fillColor_, rowIter++);
}
};
template< class DestIterator, class DestAccessor >
std::auto_ptr< Renderer< DestIterator, DestAccessor > > makeRenderer(
const basegfx::B2DPolyPolygon& rPolyPolyRaster,
typename DestAccessor::value_type fillColor,
const basegfx::B2IRange& outRange,
vigra::triple<DestIterator, DestIterator, DestAccessor> dest )
{
basegfx::B2IRange aBmpRange(0,0,
dest.second.x - dest.first.x,
dest.second.y - dest.first.y );
aBmpRange.intersect( outRange );
return std::auto_ptr< Renderer< DestIterator, DestAccessor > >(
new Renderer< DestIterator, DestAccessor >(rPolyPolyRaster,
fillColor,
aBmpRange,
dest.first,
dest.second,
dest.third));
}
// Actual BitmapDevice implementation (templatized by accessor and iterator)
//--------------------------------------------------------------------------
template< class DestIterator,
class DestAccessor > class BitmapRenderer : public BitmapDevice
{
public:
typedef BitmapRenderer<MaskIterator,
MaskAccessor> MaskBitmap;
typedef BitmapRenderer<AlphaMaskIterator,
AlphaMaskAccessor> AlphaMaskBitmap;
typedef typename colorLookup<DestAccessor>::type ColorLookupFunctor;
typedef typename fromColorConverter<
typename DestAccessor::value_type>::type FromColorFunctor;
typedef typename toColorConverter<
typename DestAccessor::value_type>::type ToColorFunctor;
typedef typename rawAccessor<DestAccessor>::type RawAccessor;
typedef typename xorAccessor<DestAccessor>::type XorAccessor;
typedef typename xorAccessor<RawAccessor>::type RawXorAccessor;
typedef typename maskedAccessor<DestAccessor,
MaskAccessor,
DestIterator,
MaskIterator>::type MaskedAccessor;
typedef typename maskedAccessor<RawAccessor,
MaskAccessor,
DestIterator,
MaskIterator>::type RawMaskedAccessor;
typedef typename maskedAccessor<XorAccessor,
MaskAccessor,
DestIterator,
MaskIterator>::type MaskedXorAccessor;
typedef typename maskedAccessor<RawXorAccessor,
MaskAccessor,
DestIterator,
MaskIterator>::type RawMaskedXorAccessor;
typedef DestIterator dest_iterator;
typedef DestAccessor dest_accessor;
typedef CompositeIterator2D< DestIterator,
MaskIterator > composite_iterator_type;
DestIterator maBegin;
DestIterator maEnd;
ColorLookupFunctor maColorLookup;
FromColorFunctor maFromColorConverter;
ToColorFunctor maToColorConverter;
DestAccessor maAccessor;
RawAccessor maRawAccessor;
XorAccessor maXorAccessor;
RawXorAccessor maRawXorAccessor;
MaskedAccessor maMaskedAccessor;
MaskedXorAccessor maMaskedXorAccessor;
RawMaskedAccessor maRawMaskedAccessor;
RawMaskedXorAccessor maRawMaskedXorAccessor;
int mnWidth;
int mnHeight;
BitmapRenderer( const basegfx::B2IVector& rSize,
bool bTopDown,
sal_Int32 nScanlineFormat,
sal_Int32 nScanlineStride,
DestIterator begin,
DestIterator end,
DestAccessor accessor,
const RawMemorySharedArray& rMem,
const PaletteMemorySharedVector& rPalette ) :
BitmapDevice( rSize, bTopDown, nScanlineFormat, nScanlineStride, rMem, rPalette ),
maBegin( begin ),
maEnd( end ),
maColorLookup(),
maFromColorConverter(),
maToColorConverter(),
maAccessor( accessor ),
maRawAccessor( accessor ),
maXorAccessor( accessor ),
maRawXorAccessor( maRawAccessor ),
maMaskedAccessor( accessor ),
maMaskedXorAccessor( maXorAccessor ),
maRawMaskedAccessor( maRawAccessor ),
maRawMaskedXorAccessor( maRawXorAccessor ),
mnWidth( maEnd.x - maBegin.x ),
mnHeight( maEnd.y - maBegin.y )
{}
private:
boost::shared_ptr<BitmapRenderer> getCompatibleBitmap( const BitmapDeviceSharedPtr& bmp ) const
{
return boost::dynamic_pointer_cast< BitmapRenderer >( bmp );
}
virtual bool isCompatibleBitmap( const BitmapDeviceSharedPtr& bmp ) const
{
// TODO(P1): dynamic_cast usually called twice for
// compatible formats
return getCompatibleBitmap(bmp).get() != NULL;
}
boost::shared_ptr<MaskBitmap> getCompatibleMask( const BitmapDeviceSharedPtr& bmp ) const
{
return boost::dynamic_pointer_cast<MaskBitmap>( bmp );
}
virtual bool isCompatibleClipMask( const BitmapDeviceSharedPtr& bmp ) const
{
// TODO(P1): dynamic_cast usually called twice for
// compatible formats
return getCompatibleMask( bmp ).get() != NULL;
}
boost::shared_ptr<AlphaMaskBitmap> getCompatibleAlphaMask( const BitmapDeviceSharedPtr& bmp ) const
{
return boost::dynamic_pointer_cast<AlphaMaskBitmap>( bmp );
}
virtual bool isCompatibleAlphaMask( const BitmapDeviceSharedPtr& bmp ) const
{
// TODO(P1): dynamic_cast usually called twice for
// compatible formats
return getCompatibleAlphaMask( bmp ).get() != NULL;
}
virtual void clear_i( Color fillColor )
{
const typename dest_iterator::value_type colorIndex( maColorLookup(
maAccessor,
maFromColorConverter(
fillColor)));
DestIterator currIter( maBegin );
const DestIterator endIter ( maBegin + vigra::Diff2D(0,mnHeight) );
while( currIter != endIter )
{
typename DestIterator::row_iterator rowIter( currIter.rowIterator() );
const typename DestIterator::row_iterator rowEnd( rowIter + mnWidth );
// TODO(P2): Provide specialized span fill methods on the
// iterator/accessor
while( rowIter != rowEnd )
maRawAccessor.set(colorIndex, rowIter++);
++currIter.y;
}
}
virtual void setPixel_i( const basegfx::B2IPoint& rPt,
Color lineColor,
DrawMode drawMode )
{
const DestIterator pixel( maBegin +
vigra::Diff2D(rPt.getX(),
rPt.getY()) );
if( drawMode == DrawMode_XOR )
maXorAccessor.set( maFromColorConverter(
lineColor),
pixel );
else
maAccessor.set( maFromColorConverter(
lineColor),
pixel );
}
virtual void setPixel_i( const basegfx::B2IPoint& rPt,
Color lineColor,
DrawMode drawMode,
const BitmapDeviceSharedPtr& rClip )
{
boost::shared_ptr<MaskBitmap> pMask( getCompatibleMask(rClip) );
OSL_ASSERT( pMask );
const vigra::Diff2D offset(rPt.getX(),
rPt.getY());
const composite_iterator_type aIter(
maBegin + offset,
pMask->maBegin + offset );
if( drawMode == DrawMode_XOR )
maMaskedXorAccessor.set( maFromColorConverter(
lineColor),
aIter );
else
maMaskedAccessor.set( maFromColorConverter(
lineColor),
aIter );
}
virtual Color getPixel_i(const basegfx::B2IPoint& rPt )
{
const DestIterator pixel( maBegin +
vigra::Diff2D(rPt.getX(),
rPt.getY()) );
return maToColorConverter(maAccessor(pixel));
}
virtual sal_uInt32 getPixelData_i( const basegfx::B2IPoint& rPt )
{
const DestIterator pixel( maBegin +
vigra::Diff2D(rPt.getX(),
rPt.getY()) );
// xxx TODO
return 0; // return maRawAccessor(pixel);
}
template< typename Range, typename Col, typename RawAccessor >
void implRenderLine2( const basegfx::B2DPoint& rPt1,
const basegfx::B2DPoint& rPt2,
Col col,
const Range& range,
const RawAccessor& rawAcc )
{
renderLine( basegfx::fround(rPt1),
basegfx::fround(rPt2),
col,
range.first,
range.second,
rawAcc );
}
template< typename Range, typename Accessor, typename RawAccessor >
void implRenderLine( const basegfx::B2DPoint& rPt1,
const basegfx::B2DPoint& rPt2,
Color col,
const Range& range,
const Accessor& acc,
const RawAccessor& rawAcc )
{
implRenderLine2( rPt1,rPt2,
maColorLookup( acc,
maFromColorConverter(
col)),
range,
rawAcc );
}
template< typename Range, typename RawAccessor, typename XorAccessor >
void implDrawLine( const basegfx::B2DPoint& rPt1,
const basegfx::B2DPoint& rPt2,
Color col,
const Range& range,
const RawAccessor& rawAcc,
const XorAccessor& xorAcc,
DrawMode drawMode )
{
if( drawMode == DrawMode_XOR )
implRenderLine( rPt1, rPt2, col,
range, maAccessor, xorAcc );
else
implRenderLine( rPt1, rPt2, col,
range, maAccessor, rawAcc );
}
virtual void drawLine_i(const basegfx::B2DPoint& rPt1,
const basegfx::B2DPoint& rPt2,
Color lineColor,
DrawMode drawMode )
{
implDrawLine(rPt1,rPt2,lineColor,
std::make_pair(maBegin,maEnd),
maRawAccessor,maRawXorAccessor,drawMode);
}
vigra::pair<composite_iterator_type,composite_iterator_type>
getMaskedRange( const BitmapDeviceSharedPtr& rClip ) const
{
boost::shared_ptr<MaskBitmap> pMask( getCompatibleMask(rClip) );
OSL_ASSERT( pMask );
return std::make_pair(
composite_iterator_type(
maBegin,
pMask->maBegin ),
composite_iterator_type(
maEnd,
pMask->maEnd ));
}
virtual void drawLine_i(const basegfx::B2DPoint& rPt1,
const basegfx::B2DPoint& rPt2,
Color lineColor,
DrawMode drawMode,
const BitmapDeviceSharedPtr& rClip )
{
implDrawLine(rPt1,rPt2,lineColor,
getMaskedRange(rClip),
maRawMaskedAccessor,maRawMaskedXorAccessor,drawMode);
}
template< typename Range, typename RawAccessor >
void implDrawPolygon( const basegfx::B2DPolygon& rPoly,
Color col,
const Range& range,
const RawAccessor& acc )
{
basegfx::B2DPolygon aPoly( rPoly );
if( rPoly.areControlVectorsUsed() )
aPoly = basegfx::tools::adaptiveSubdivideByCount( rPoly );
const typename dest_iterator::value_type colorIndex( maColorLookup(
maAccessor,
maFromColorConverter(
col)));
const sal_uInt32 nVertices( aPoly.count() );
for( sal_uInt32 i=1; i<nVertices; ++i )
implRenderLine2( aPoly.getB2DPoint(i-1),
aPoly.getB2DPoint(i),
colorIndex,
range,
acc );
if( nVertices > 1 && aPoly.isClosed() )
implRenderLine2( aPoly.getB2DPoint(nVertices-1),
aPoly.getB2DPoint(0),
colorIndex,
range,
acc );
}
virtual void drawPolygon_i(const basegfx::B2DPolygon& rPoly,
Color lineColor,
DrawMode drawMode )
{
if( drawMode == DrawMode_XOR )
implDrawPolygon( rPoly, lineColor,
std::make_pair(maBegin,
maEnd),
maRawXorAccessor );
else
implDrawPolygon( rPoly, lineColor,
std::make_pair(maBegin,
maEnd),
maRawAccessor );
}
virtual void drawPolygon_i(const basegfx::B2DPolygon& rPoly,
Color lineColor,
DrawMode drawMode,
const BitmapDeviceSharedPtr& rClip )
{
if( drawMode == DrawMode_XOR )
implDrawPolygon( rPoly, lineColor,
getMaskedRange(rClip),
maRawMaskedXorAccessor );
else
implDrawPolygon( rPoly, lineColor,
getMaskedRange(rClip),
maRawMaskedAccessor );
}
template< typename Range, typename RawAccessor >
void implFillPolyPolygon( const basegfx::B2DPolyPolygon& rPoly,
Color col,
const Range& range,
const RawAccessor& acc,
const basegfx::B2IRange& rBounds )
{
basegfx::B2DPolyPolygon aPoly( rPoly );
if( rPoly.areControlVectorsUsed() )
aPoly = basegfx::tools::adaptiveSubdivideByCount( rPoly );
makeRenderer( aPoly,
maColorLookup( maAccessor,
maFromColorConverter(
col)),
rBounds,
vigra::make_triple(
range.first,
range.second,
acc) )->rasterConvert(
basegfx::FillRule_NONZERO_WINDING_NUMBER );
}
virtual void fillPolyPolygon_i(const basegfx::B2DPolyPolygon& rPoly,
Color fillColor,
DrawMode drawMode,
const basegfx::B2IRange& rBounds )
{
if( drawMode == DrawMode_XOR )
implFillPolyPolygon( rPoly, fillColor,
std::make_pair(maBegin,maEnd),
maRawXorAccessor,
rBounds );
else
implFillPolyPolygon( rPoly, fillColor,
std::make_pair(maBegin,maEnd),
maRawAccessor,
rBounds );
}
virtual void fillPolyPolygon_i(const basegfx::B2DPolyPolygon& rPoly,
Color fillColor,
DrawMode drawMode,
const basegfx::B2IRange& rBounds,
const BitmapDeviceSharedPtr& rClip )
{
if( drawMode == DrawMode_XOR )
implFillPolyPolygon( rPoly, fillColor,
getMaskedRange(rClip),
maRawMaskedXorAccessor,
rBounds );
else
implFillPolyPolygon( rPoly, fillColor,
getMaskedRange(rClip),
maRawMaskedAccessor,
rBounds );
}
template< typename Range, typename RawAccessor >
void implDrawBitmap(const BitmapDeviceSharedPtr& rSrcBitmap,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IRange& rDstRect,
const Range& range,
const RawAccessor& acc)
{
boost::shared_ptr<BitmapRenderer> pSrcBmp( getCompatibleBitmap(rSrcBitmap) );
OSL_ASSERT( pSrcBmp );
// since resizeImageNoInterpolation() internally copyies
// to a temporary buffer, also works with *this == rSrcBitmap
vigra::resizeImageNoInterpolation(
vigra::make_triple(
pSrcBmp->maBegin + vigra::Diff2D(rSrcRect.getMinX(),
rSrcRect.getMinY()),
pSrcBmp->maBegin + vigra::Diff2D(rSrcRect.getMaxX(),
rSrcRect.getMaxY()),
pSrcBmp->maRawAccessor),
vigra::make_triple(
range.first + vigra::Diff2D(rDstRect.getMinX(),
rDstRect.getMinY()),
range.first + vigra::Diff2D(rDstRect.getMaxX(),
rDstRect.getMaxY()),
acc));
}
virtual void drawBitmap_i(const BitmapDeviceSharedPtr& rSrcBitmap,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IRange& rDstRect,
DrawMode drawMode )
{
if( drawMode == DrawMode_XOR )
implDrawBitmap(rSrcBitmap, rSrcRect, rDstRect,
std::make_pair(maBegin,maEnd),
maRawXorAccessor);
else
implDrawBitmap(rSrcBitmap, rSrcRect, rDstRect,
std::make_pair(maBegin,maEnd),
maRawAccessor);
}
virtual void drawBitmap_i(const BitmapDeviceSharedPtr& rSrcBitmap,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IRange& rDstRect,
DrawMode drawMode,
const BitmapDeviceSharedPtr& rClip )
{
if( drawMode == DrawMode_XOR )
implDrawBitmap(rSrcBitmap, rSrcRect, rDstRect,
getMaskedRange(rClip),
maRawMaskedXorAccessor);
else
implDrawBitmap(rSrcBitmap, rSrcRect, rDstRect,
getMaskedRange(rClip),
maRawMaskedAccessor);
}
template< typename Range, typename Accessor >
void implDrawMaskedColor(Color rSrcColor,
const BitmapDeviceSharedPtr& rAlphaMask,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IPoint& rDstPoint,
const Range& range,
const Accessor& acc)
{
boost::shared_ptr<AlphaMaskBitmap> pAlpha( getCompatibleAlphaMask(rAlphaMask) );
OSL_ASSERT( pAlpha );
vigra::copyImage( pAlpha->maBegin + vigra::Diff2D(rSrcRect.getMinX(),
rSrcRect.getMinY()),
pAlpha->maBegin + vigra::Diff2D(rSrcRect.getMaxX(),
rSrcRect.getMaxY()),
pAlpha->maAccessor,
range.first + vigra::Diff2D(rDstPoint.getX(),
rDstPoint.getY()),
ConstantColorBlendAccessorAdapter<
Accessor,
typename DestAccessor::value_type>(
acc,
maFromColorConverter(rSrcColor)) );
}
virtual void drawMaskedColor_i(Color aSrcColor,
const BitmapDeviceSharedPtr& rAlphaMask,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IPoint& rDstPoint )
{
implDrawMaskedColor(aSrcColor, rAlphaMask, rSrcRect, rDstPoint,
std::make_pair(maBegin,maEnd),
maAccessor);
}
virtual void drawMaskedColor_i(Color aSrcColor,
const BitmapDeviceSharedPtr& rAlphaMask,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IPoint& rDstPoint,
const BitmapDeviceSharedPtr& rClip )
{
implDrawMaskedColor(aSrcColor, rAlphaMask, rSrcRect, rDstPoint,
getMaskedRange(rClip),
maMaskedAccessor);
}
// must work with *this == rSrcBitmap!
virtual void drawMaskedBitmap_i(const BitmapDeviceSharedPtr& rSrcBitmap,
const BitmapDeviceSharedPtr& rMask,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IRange& rDstRect,
DrawMode drawMode )
{
OSL_ENSURE( false, "Method not yet implemented!" );
}
virtual void drawMaskedBitmap_i(const BitmapDeviceSharedPtr& rSrcBitmap,
const BitmapDeviceSharedPtr& rMask,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IRange& rDstRect,
DrawMode drawMode,
const BitmapDeviceSharedPtr& rClip )
{
OSL_ENSURE( false, "Method not yet implemented!" );
}
};
} // namespace
struct ImplBitmapDevice
{
/// Bitmap memory plus deleter
RawMemorySharedArray mpMem;
/// Palette memory plus deleter (might be NULL)
PaletteMemorySharedVector mpPalette;
basegfx::B2IRange maBounds;
basegfx::B2DRange maFloatBounds;
sal_Int32 mnScanlineFormat;
sal_Int32 mnScanlineStride;
};
BitmapDevice::BitmapDevice( const basegfx::B2IVector& rSize,
bool bTopDown,
sal_Int32 nScanlineFormat,
sal_Int32 nScanlineStride,
const RawMemorySharedArray& rMem,
const PaletteMemorySharedVector& rPalette ) :
mpImpl( new ImplBitmapDevice )
{
mpImpl->mpMem = rMem;
mpImpl->mpPalette = rPalette;
mpImpl->maBounds = basegfx::B2IRange( 0,0,rSize.getX(),rSize.getY() );
mpImpl->maFloatBounds = basegfx::B2DRange( 0,0,rSize.getX(),rSize.getY() );
mpImpl->mnScanlineFormat = nScanlineFormat;
mpImpl->mnScanlineStride = bTopDown ? nScanlineStride : -nScanlineStride;
}
BitmapDevice::~BitmapDevice()
{
// outline, because of internal ImplBitmapDevice
}
basegfx::B2IVector BitmapDevice::getSize() const
{
return basegfx::B2IVector( mpImpl->maBounds.getWidth(),
mpImpl->maBounds.getHeight() );
}
bool BitmapDevice::isTopDown() const
{
return mpImpl->mnScanlineStride >= 0;
}
sal_Int32 BitmapDevice::getScanlineFormat() const
{
return mpImpl->mnScanlineFormat;
}
sal_Int32 BitmapDevice::getScanlineStride() const
{
return mpImpl->mnScanlineStride;
}
RawMemorySharedArray BitmapDevice::getBuffer() const
{
return mpImpl->mpMem;
}
PaletteMemorySharedVector BitmapDevice::getPalette() const
{
return mpImpl->mpPalette;
}
const sal_Int32 BitmapDevice::getPaletteEntryCount() const
{
return mpImpl->mpPalette ? mpImpl->mpPalette->size() : 0;
}
void BitmapDevice::clear( Color fillColor )
{
clear_i( fillColor );
}
void BitmapDevice::setPixel( const basegfx::B2IPoint& rPt,
Color lineColor,
DrawMode drawMode )
{
if( mpImpl->maBounds.isInside(rPt) )
setPixel_i(rPt,lineColor,drawMode);
}
void BitmapDevice::setPixel( const basegfx::B2IPoint& rPt,
Color lineColor,
DrawMode drawMode,
const BitmapDeviceSharedPtr& rClip )
{
if( !rClip )
setPixel(rPt,lineColor,drawMode);
if( mpImpl->maBounds.isInside(rPt) )
{
if( isCompatibleClipMask( rClip ) )
setPixel_i(rPt,lineColor,drawMode,rClip);
else
OSL_ENSURE( false, "Generic output not yet implemented!" );
}
}
Color BitmapDevice::getPixel( const basegfx::B2IPoint& rPt )
{
if( mpImpl->maBounds.isInside(rPt) )
return getPixel_i(rPt);
return Color();
}
sal_uInt32 BitmapDevice::getPixelData( const basegfx::B2IPoint& rPt )
{
if( mpImpl->maBounds.isInside(rPt) )
return getPixelData_i(rPt);
return 0;
}
void BitmapDevice::drawLine( const basegfx::B2IPoint& rPt1,
const basegfx::B2IPoint& rPt2,
Color lineColor,
DrawMode drawMode )
{
basegfx::B2DPoint aPt1( rPt1 );
basegfx::B2DPoint aPt2( rPt2 );
if( basegfx::tools::liangBarskyClip2D(aPt1,aPt2,mpImpl->maFloatBounds) )
{
drawLine_i( aPt1, aPt2,
lineColor,
drawMode );
}
}
void BitmapDevice::drawLine( const basegfx::B2IPoint& rPt1,
const basegfx::B2IPoint& rPt2,
Color lineColor,
DrawMode drawMode,
const BitmapDeviceSharedPtr& rClip )
{
if( !rClip )
drawLine(rPt1,rPt2,lineColor,drawMode);
basegfx::B2DPoint aPt1( rPt1 );
basegfx::B2DPoint aPt2( rPt2 );
if( basegfx::tools::liangBarskyClip2D(aPt1,aPt2,mpImpl->maFloatBounds) )
{
if( isCompatibleClipMask( rClip ) )
drawLine_i( aPt1, aPt2,
lineColor,
drawMode,
rClip );
else
OSL_ENSURE( false, "Generic output not yet implemented!" );
}
}
void BitmapDevice::drawPolygon( const basegfx::B2DPolygon& rPoly,
Color lineColor,
DrawMode drawMode )
{
basegfx::B2DPolyPolygon aPoly(
basegfx::tools::clipPolygonOnRange( rPoly,
mpImpl->maFloatBounds,
true,
true ));
const sal_uInt32 numPolies( aPoly.count() );
for( sal_uInt32 i=0; i<numPolies; ++i )
if( aPoly.getB2DPolygon(i).count() )
drawPolygon_i( aPoly.getB2DPolygon(i), lineColor, drawMode );
}
void BitmapDevice::drawPolygon( const basegfx::B2DPolygon& rPoly,
Color lineColor,
DrawMode drawMode,
const BitmapDeviceSharedPtr& rClip )
{
if( !rClip )
drawPolygon(rPoly,lineColor,drawMode);
basegfx::B2DPolyPolygon aPoly(
basegfx::tools::clipPolygonOnRange( rPoly,
mpImpl->maFloatBounds,
true,
true ));
const sal_uInt32 numPolies( aPoly.count() );
for( sal_uInt32 i=0; i<numPolies; ++i )
if( aPoly.getB2DPolygon(i).count() )
if( isCompatibleClipMask( rClip ) )
drawPolygon_i( aPoly.getB2DPolygon(i), lineColor, drawMode, rClip );
else
OSL_ENSURE( false, "Generic output not yet implemented!" );
}
void BitmapDevice::fillPolyPolygon( const basegfx::B2DPolyPolygon& rPoly,
Color fillColor,
DrawMode drawMode )
{
fillPolyPolygon_i( rPoly, fillColor, drawMode, mpImpl->maBounds );
}
void BitmapDevice::fillPolyPolygon( const basegfx::B2DPolyPolygon& rPoly,
Color fillColor,
DrawMode drawMode,
const BitmapDeviceSharedPtr& rClip )
{
if( !rClip )
fillPolyPolygon(rPoly,fillColor,drawMode);
if( isCompatibleClipMask( rClip ) )
fillPolyPolygon_i( rPoly, fillColor, drawMode, mpImpl->maBounds, rClip );
else
OSL_ENSURE( false, "Generic output not yet implemented!" );
}
namespace
{
void assertImagePoint( const basegfx::B2IPoint& rPt,
const basegfx::B2IRange& rPermittedRange )
{
OSL_ASSERT( rPermittedRange.isInside(rPt) );
}
void assertImageRange( const basegfx::B2IRange& rRange,
const basegfx::B2IRange& rPermittedRange )
{
#if OSL_DEBUG_LEVEL > 0
basegfx::B2IRange aRange( rRange );
aRange.intersect( rPermittedRange );
OSL_ASSERT( aRange == rRange );
#endif
}
// TODO(Q3): Move canvas/canvastools.hxx clipBlit() down
// to basegfx, and use here!
bool clipAreaImpl( ::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();
return true;
}
// TODO(Q3): Move canvas/canvastools.hxx clipBlit() down
// to basegfx, and use here!
bool clipAreaImpl( ::basegfx::B2IRange& io_rDestArea,
::basegfx::B2IRange& io_rSourceArea,
const ::basegfx::B2IRange& rDestBounds,
const ::basegfx::B2IRange& rSourceBounds )
{
// extract inherent scale
const double nScaleX( io_rDestArea.getWidth() / (double)io_rSourceArea.getWidth() );
const double nScaleY( io_rDestArea.getHeight() / (double)io_rSourceArea.getHeight() );
// extract range origins
const basegfx::B2IPoint aDestTopLeft(
io_rDestArea.getMinimum() );
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( basegfx::fround(aDestTopLeft.getX() + nScaleX*aUpperLeftOffset.getX()),
basegfx::fround(aDestTopLeft.getY() + nScaleY*aUpperLeftOffset.getY()),
basegfx::fround(aDestTopLeft.getX() + nScaleX*aLowerRightOffset.getX()),
basegfx::fround(aDestTopLeft.getY() + nScaleY*aLowerRightOffset.getY()) );
// 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()-aDestTopLeft );
const ::basegfx::B2IVector aDestLowerRightOffset(
aLocalDestArea.getMaximum()-aDestTopLeft );
io_rSourceArea = ::basegfx::B2IRange( basegfx::fround(aSourceTopLeft.getX() + aDestUpperLeftOffset.getX()/nScaleX),
basegfx::fround(aSourceTopLeft.getY() + aDestUpperLeftOffset.getY()/nScaleY),
basegfx::fround(aSourceTopLeft.getX() + aDestLowerRightOffset.getX()/nScaleX),
basegfx::fround(aSourceTopLeft.getY() + aDestLowerRightOffset.getY()/nScaleY) );
io_rDestArea = aLocalDestArea;
// final source area clip (chopping round-offs)
io_rSourceArea.intersect( rSourceBounds );
if( io_rSourceArea.isEmpty() )
return false;
return true;
}
}
void BitmapDevice::drawBitmap( const BitmapDeviceSharedPtr& rSrcBitmap,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IRange& rDstRect,
DrawMode drawMode )
{
const basegfx::B2IVector& rSrcSize( rSrcBitmap->getSize() );
const basegfx::B2IRange aSrcBounds( 0,0,rSrcSize.getX(),rSrcSize.getY() );
basegfx::B2IRange aSrcRange( rSrcRect );
basegfx::B2IRange aDestRange( rDstRect );
if( clipAreaImpl( aDestRange,
aSrcRange,
mpImpl->maBounds,
aSrcBounds ))
{
assertImageRange(aDestRange,mpImpl->maBounds);
assertImageRange(aSrcRange,aSrcBounds);
if( isCompatibleBitmap( rSrcBitmap ) )
drawBitmap_i( rSrcBitmap, aSrcRange, aDestRange, drawMode );
else
OSL_ENSURE( false, "Generic output not yet implemented!" );
}
}
void BitmapDevice::drawBitmap( const BitmapDeviceSharedPtr& rSrcBitmap,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IRange& rDstRect,
DrawMode drawMode,
const BitmapDeviceSharedPtr& rClip )
{
if( !rClip )
drawBitmap(rSrcBitmap,rSrcRect,rDstRect,drawMode);
const basegfx::B2IVector& rSrcSize( rSrcBitmap->getSize() );
const basegfx::B2IRange aSrcBounds( 0,0,rSrcSize.getX(),rSrcSize.getY() );
basegfx::B2IRange aSrcRange( rSrcRect );
basegfx::B2IRange aDestRange( rDstRect );
if( clipAreaImpl( aDestRange,
aSrcRange,
mpImpl->maBounds,
aSrcBounds ))
{
assertImageRange(aDestRange,mpImpl->maBounds);
assertImageRange(aSrcRange,aSrcBounds);
if( isCompatibleBitmap( rSrcBitmap ) &&
isCompatibleClipMask( rClip ) )
{
drawBitmap_i( rSrcBitmap, aSrcRange, aDestRange, drawMode, rClip );
}
else
{
OSL_ENSURE( false, "Generic output not yet implemented!" );
}
}
}
void BitmapDevice::drawMaskedColor( Color rSrcColor,
const BitmapDeviceSharedPtr& rAlphaMask,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IPoint& rDstPoint )
{
const basegfx::B2IVector& rSrcSize( rAlphaMask->getSize() );
const basegfx::B2IRange aSrcBounds( 0,0,rSrcSize.getX(),rSrcSize.getY() );
basegfx::B2IRange aSrcRange( rSrcRect );
basegfx::B2IPoint aDestPoint( rDstPoint );
if( clipAreaImpl( aSrcRange,
aDestPoint,
aSrcBounds,
mpImpl->maBounds ))
{
assertImagePoint(aDestPoint,mpImpl->maBounds);
assertImageRange(aSrcRange,aSrcBounds);
if( isCompatibleAlphaMask( rAlphaMask ) )
drawMaskedColor_i( rSrcColor, rAlphaMask, aSrcRange, aDestPoint );
else
OSL_ENSURE( false, "Generic output not yet implemented!" );
}
}
void BitmapDevice::drawMaskedColor( Color aSrcColor,
const BitmapDeviceSharedPtr& rAlphaMask,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IPoint& rDstPoint,
const BitmapDeviceSharedPtr& rClip )
{
if( !rClip )
drawMaskedColor(aSrcColor,rAlphaMask,rSrcRect,rDstPoint);
const basegfx::B2IVector& rSrcSize( rAlphaMask->getSize() );
const basegfx::B2IRange aSrcBounds( 0,0,rSrcSize.getX(),rSrcSize.getY() );
basegfx::B2IRange aSrcRange( rSrcRect );
basegfx::B2IPoint aDestPoint( rDstPoint );
if( clipAreaImpl( aSrcRange,
aDestPoint,
aSrcBounds,
mpImpl->maBounds ))
{
assertImagePoint(aDestPoint,mpImpl->maBounds);
assertImageRange(aSrcRange,aSrcBounds);
if( isCompatibleAlphaMask( rAlphaMask ) &&
isCompatibleClipMask( rClip ) )
{
drawMaskedColor_i( aSrcColor, rAlphaMask, aSrcRange, aDestPoint, rClip );
}
else
{
OSL_ENSURE( false, "Generic output not yet implemented!" );
}
}
}
void BitmapDevice::drawMaskedBitmap( const BitmapDeviceSharedPtr& rSrcBitmap,
const BitmapDeviceSharedPtr& rMask,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IRange& rDstRect,
DrawMode drawMode )
{
OSL_ASSERT( rMask->getSize() == rSrcBitmap->getSize() );
const basegfx::B2IVector& rSrcSize( rSrcBitmap->getSize() );
const basegfx::B2IRange aSrcBounds( 0,0,rSrcSize.getX(),rSrcSize.getY() );
basegfx::B2IRange aSrcRange( rSrcRect );
basegfx::B2IRange aDestRange( rDstRect );
if( clipAreaImpl( aDestRange,
aSrcRange,
mpImpl->maBounds,
aSrcBounds ))
{
assertImageRange(aDestRange,mpImpl->maBounds);
assertImageRange(aSrcRange,aSrcBounds);
if( isCompatibleBitmap( rSrcBitmap ) &&
isCompatibleClipMask( rMask ) )
{
drawMaskedBitmap_i( rSrcBitmap, rMask, aSrcRange, aDestRange, drawMode );
}
else
{
OSL_ENSURE( false, "Generic output not yet implemented!" );
}
}
}
void BitmapDevice::drawMaskedBitmap( const BitmapDeviceSharedPtr& rSrcBitmap,
const BitmapDeviceSharedPtr& rMask,
const basegfx::B2IRange& rSrcRect,
const basegfx::B2IRange& rDstRect,
DrawMode drawMode,
const BitmapDeviceSharedPtr& rClip )
{
if( !rClip )
drawMaskedBitmap(rSrcBitmap,rMask,rSrcRect,rDstRect,drawMode);
OSL_ASSERT( rMask->getSize() == rSrcBitmap->getSize() );
const basegfx::B2IVector& rSrcSize( rSrcBitmap->getSize() );
const basegfx::B2IRange aSrcBounds( 0,0,rSrcSize.getX(),rSrcSize.getY() );
basegfx::B2IRange aSrcRange( rSrcRect );
basegfx::B2IRange aDestRange( rDstRect );
if( clipAreaImpl( aDestRange,
aSrcRange,
mpImpl->maBounds,
aSrcBounds ))
{
assertImageRange(aDestRange,mpImpl->maBounds);
assertImageRange(aSrcRange,aSrcBounds);
if( isCompatibleBitmap( rSrcBitmap ) &&
isCompatibleClipMask( rMask ) &&
isCompatibleClipMask( rClip ) )
{
drawMaskedBitmap_i( rSrcBitmap, rMask, aSrcRange, aDestRange, drawMode, rClip );
}
else
{
OSL_ENSURE( false, "Generic output not yet implemented!" );
}
}
}
//----------------------------------------------------------------------------------
typedef BitmapRenderer<MaskIterator,
MaskAccessor > OneBitMsbMaskRenderer;
typedef BitmapRenderer<MaskIterator,PaletteAccessor> OneBitMsbPaletteRenderer;
typedef BitmapRenderer<AlphaMaskIterator,
AlphaMaskAccessor > EightBitGrayRenderer;
typedef BitmapRenderer<ThirtyTwoBitPixelIterator,
ThirtyTwoBitAccessor> ThirtyTwoBitTrueColorRenderer;
namespace
{
BitmapDeviceSharedPtr createBitmapDeviceImpl( const basegfx::B2IVector& rSize,
bool bTopDown,
sal_Int32 nScanlineFormat,
boost::shared_array< sal_uInt8 > pMem,
PaletteMemorySharedVector pPal )
{
sal_Int32 nScanlineStride(0);
// HACK: 1bpp and 32bpp only, currently
if( nScanlineFormat == Format::ONE_BIT_MSB_PAL
|| nScanlineFormat == Format::ONE_BIT_MSB_GRAY )
nScanlineStride = (rSize.getX() + 7) >> 3;
else if( nScanlineFormat == Format::EIGHT_BIT_GRAY )
nScanlineStride = rSize.getX();
else if( nScanlineFormat == Format::THIRTYTWO_BIT_TC_MASK )
nScanlineStride = 4*rSize.getX();
nScanlineStride *= bTopDown ? 1 : -1;
const std::size_t nMemSize(
(nScanlineStride < 0 ? -nScanlineStride : nScanlineStride)*rSize.getY() );
if( !pMem )
{
pMem.reset(
reinterpret_cast<sal_uInt8*>(rtl_allocateMemory( nMemSize )),
&rtl_freeMemory );
rtl_zeroMemory(pMem.get(),nMemSize);
}
sal_uInt8* pFirstScanline = nScanlineStride < 0 ?
pMem.get() + nMemSize : pMem.get();
switch( nScanlineFormat )
{
case Format::ONE_BIT_MSB_GRAY:
{
return BitmapDeviceSharedPtr(
new OneBitMsbMaskRenderer(
rSize,
bTopDown,
nScanlineFormat,
nScanlineStride,
MaskIterator(pFirstScanline,
nScanlineStride),
MaskIterator(pFirstScanline,
nScanlineStride)
+ vigra::Diff2D(rSize.getX(),
rSize.getY()),
MaskAccessor(),
pMem,
pPal ));
}
case Format::ONE_BIT_MSB_PAL:
{
if( !pPal )
{
boost::shared_ptr< std::vector<Color> > pLocalPal(
new std::vector<Color>(2) );
pLocalPal->at(0) = Color(0x00000000);
pLocalPal->at(1) = Color(0xFFFFFFFF);
pPal = pLocalPal;
}
return BitmapDeviceSharedPtr(
new OneBitMsbPaletteRenderer(
rSize,
bTopDown,
nScanlineFormat,
nScanlineStride,
MaskIterator(pFirstScanline,
nScanlineStride),
MaskIterator(pFirstScanline,
nScanlineStride)
+ vigra::Diff2D(rSize.getX(),
rSize.getY()),
PaletteAccessor( &pPal->at(0),
pPal->size() ),
pMem,
pPal ));
}
case Format::EIGHT_BIT_GRAY:
{
return BitmapDeviceSharedPtr(
new EightBitGrayRenderer(
rSize,
bTopDown,
nScanlineFormat,
nScanlineStride,
AlphaMaskIterator(pFirstScanline,
nScanlineStride),
AlphaMaskIterator(pFirstScanline,
nScanlineStride)
+ vigra::Diff2D(rSize.getX(),
rSize.getY()),
AlphaMaskAccessor(),
pMem,
pPal ));
}
case Format::THIRTYTWO_BIT_TC_MASK:
{
return BitmapDeviceSharedPtr(
new ThirtyTwoBitTrueColorRenderer(
rSize,
bTopDown,
nScanlineFormat,
nScanlineStride,
ThirtyTwoBitPixelIterator(reinterpret_cast<Color*>(pFirstScanline),
nScanlineStride),
ThirtyTwoBitPixelIterator(reinterpret_cast<Color*>(pFirstScanline),
nScanlineStride)
+ vigra::Diff2D(rSize.getX(),
rSize.getY()),
ThirtyTwoBitAccessor(),
pMem,
pPal ));
}
default:
// TODO(F3): other formats not yet implemented
return BitmapDeviceSharedPtr();
}
}
} // namespace
BitmapDeviceSharedPtr createBitmapDevice( const basegfx::B2IVector& rSize,
bool bTopDown,
sal_Int32 nScanlineFormat )
{
return createBitmapDeviceImpl( rSize,
bTopDown,
nScanlineFormat,
boost::shared_array< sal_uInt8 >(),
PaletteMemorySharedVector() );
}
BitmapDeviceSharedPtr createBitmapDevice( const basegfx::B2IVector& rSize,
bool bTopDown,
sal_Int32 nScanlineFormat,
const RawMemorySharedArray& rMem,
const PaletteMemorySharedVector& rPalette )
{
return createBitmapDeviceImpl( rSize,
bTopDown,
nScanlineFormat,
rMem,
rPalette );
}
BitmapDeviceSharedPtr cloneBitmapDevice( const basegfx::B2IVector& rSize,
const BitmapDeviceSharedPtr& rProto )
{
return createBitmapDeviceImpl( rSize,
rProto->isTopDown(),
rProto->getScanlineFormat(),
boost::shared_array< sal_uInt8 >(),
rProto->getPalette() );
}
} // namespace basebmp