/*************************************************************************
 *
 * 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.
 *
 ************************************************************************/

// FIXME: in vigra
#if defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x580)
#include <math.h> // needed for fabs, hypot
#endif
#include "basebmp/bitmapdevice.hxx"

#include "basebmp/compositeiterator.hxx"
#include "basebmp/iteratortraits.hxx"

#include "basebmp/accessor.hxx"
#include "basebmp/accessortraits.hxx"
#include "basebmp/accessoradapters.hxx"
#include "basebmp/colorblendaccessoradapter.hxx"

#include "basebmp/color.hxx"
#include "basebmp/colormisc.hxx"
#include "basebmp/colortraits.hxx"

#include "basebmp/greylevelformats.hxx"
#include "basebmp/paletteformats.hxx"
#include "basebmp/rgbmaskpixelformats.hxx"
#include "basebmp/rgb24pixelformats.hxx"

#include "basebmp/scanlineformats.hxx"
#include "basebmp/fillimage.hxx"
#include "basebmp/scaleimage.hxx"
#include "basebmp/clippedlinerenderer.hxx"
#include "basebmp/polypolygonrenderer.hxx"
#include "basebmp/genericcolorimageaccessor.hxx"

#include "basebmp/tools.hxx"
#include "intconversion.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/b2dpolypolygontools.hxx>
#include <basegfx/point/b2ipoint.hxx>
#include <basegfx/vector/b2ivector.hxx>

#include <vigra/iteratortraits.hxx>
#include <vigra/rgbvalue.hxx>
#include <vigra/copyimage.hxx>
#include <vigra/tuple.hxx>


namespace vigra
{

/// componentwise xor of an RGBValue (missing from rgbvalue.hxx)
template< class Value, unsigned int RedIndex, unsigned int BlueIndex, unsigned int GreenIndex >
inline RGBValue<Value, RedIndex, GreenIndex, BlueIndex>
operator^( RGBValue<Value, RedIndex, GreenIndex, BlueIndex> const& lhs,
           RGBValue<Value, RedIndex, GreenIndex, BlueIndex> const& rhs )
{
    RGBValue<Value, RedIndex, GreenIndex, BlueIndex> res(
        lhs[0] ^ rhs[0],
        lhs[1] ^ rhs[1],
        lhs[2] ^ rhs[2]);
    return res;
}
}

namespace basebmp
{

namespace
{
    /** Create the type for an accessor that takes the (mask,bitmap)
        input value generated from a JoinImageAccessorAdapter, and
        pipe that through a mask functor.

        @tpl DestAccessor
        Destination bitmap accessor

        @tpl JoinedAccessor
        Input accessor, is expected to generate a std::pair as the
        value type

        @tpl MaskFunctorMode
        Either FastMask or NoFastMask, depending on whether the mask
        is guaranteed to contain only 0s and 1s.
     */
    template< class    DestAccessor,
              class    JoinedAccessor,
              bool     polarity,
              typename MaskFunctorMode > struct masked_input_splitting_accessor
    {
        typedef BinarySetterFunctionAccessorAdapter< 
            DestAccessor,
            BinaryFunctorSplittingWrapper< 
                typename outputMaskFunctorSelector< 
                         typename JoinedAccessor::value_type::first_type,
                         typename JoinedAccessor::value_type::second_type,
                         polarity,
                         MaskFunctorMode >::type > > type;
    };



    // Actual BitmapDevice implementation (templatized by accessor and iterator)
    //--------------------------------------------------------------------------

    /** Implementation of the BitmapDevice interface

        @tpl DestIterator
        Iterator to access bitmap memory

        @tpl RawAccessor
        Raw accessor, to access pixel values directly

        @tpl AccessorSelector
        Accessor adapter selector, which, when applying the nested
        template metafunction wrap_accessor to one of the raw bitmap
        accessors, yields a member type named 'type', which is a
        wrapped accessor that map color values.

        @tpl Masks
        Traits template, containing nested traits
        clipmask_format_traits and alphamask_format_traits, which
        determine what specialized formats are to be used for clip and
        alpha masks. With those mask formats, clipping and alpha
        blending is handled natively.
     */
    template< class DestIterator, 
              class RawAccessor, 
              class AccessorSelector,
              class Masks > class BitmapRenderer : 
                  public BitmapDevice
    {
    public:
        typedef DestIterator                                               dest_iterator_type;
        typedef RawAccessor                                                raw_accessor_type;
        typedef AccessorSelector                                           accessor_selector;

        typedef typename Masks::clipmask_format_traits::iterator_type      mask_iterator_type;
        typedef typename Masks::clipmask_format_traits::raw_accessor_type  mask_rawaccessor_type;
        typedef typename Masks::clipmask_format_traits::accessor_selector  mask_accessorselector_type;

        typedef typename Masks::alphamask_format_traits::iterator_type     alphamask_iterator_type;
        typedef typename Masks::alphamask_format_traits::raw_accessor_type alphamask_rawaccessor_type;
        typedef typename Masks::alphamask_format_traits::accessor_selector alphamask_accessorselector_type;

        typedef typename AccessorSelector::template wrap_accessor< 
            raw_accessor_type >::type                                      dest_accessor_type;

        typedef AccessorTraits< dest_accessor_type >                       accessor_traits;
        typedef CompositeIterator2D< dest_iterator_type, 
                                     mask_iterator_type >                  composite_iterator_type;
        typedef CompositeIterator2D< vigra::Diff2D, 
                                     vigra::Diff2D >                       generic_composite_iterator_type;

        typedef BitmapRenderer<mask_iterator_type,
                               mask_rawaccessor_type,
                               mask_accessorselector_type,
                               Masks>                                      mask_bitmap_type;
        typedef BitmapRenderer<alphamask_iterator_type,
                               alphamask_rawaccessor_type,
                               alphamask_accessorselector_type,
                               Masks>                                      alphamask_bitmap_type;

        // -------------------------------------------------------

        typedef AccessorTraits< raw_accessor_type >                        raw_accessor_traits;
        typedef typename uInt32Converter<
            typename raw_accessor_type::value_type>::to                    to_uint32_functor;

        // -------------------------------------------------------

        typedef typename raw_accessor_traits::xor_accessor                 raw_xor_accessor_type;
        typedef AccessorTraits<raw_xor_accessor_type>                      raw_xor_accessor_traits;
        typedef typename accessor_selector::template wrap_accessor< 
            raw_xor_accessor_type >::type                                  xor_accessor_type;
        typedef AccessorTraits<xor_accessor_type>                          xor_accessor_traits;

        // -------------------------------------------------------

        typedef typename raw_accessor_traits::template masked_accessor< 
            mask_rawaccessor_type,
            dest_iterator_type,
            mask_iterator_type,
            Masks::clipmask_polarity>::type                                raw_maskedaccessor_type;
        typedef typename accessor_selector::template wrap_accessor< 
            raw_maskedaccessor_type >::type                                masked_accessor_type;
        typedef typename AccessorTraits<
            raw_maskedaccessor_type>::xor_accessor                         raw_maskedxor_accessor_type;
        typedef typename accessor_selector::template wrap_accessor< 
            raw_maskedxor_accessor_type >::type                            masked_xoraccessor_type;

        // -------------------------------------------------------

        // ((iter,mask),mask) special case (e.g. for clipped
        // drawMaskedColor())
        typedef AccessorTraits< raw_maskedaccessor_type >                  raw_maskedaccessor_traits;
        typedef typename raw_maskedaccessor_traits::template masked_accessor< 
            mask_rawaccessor_type,
            composite_iterator_type,
            mask_iterator_type,
            Masks::clipmask_polarity>::type                                raw_maskedmask_accessor_type;

        typedef CompositeIterator2D< 
            composite_iterator_type,
            mask_iterator_type>                                            composite_composite_mask_iterator_type;
        
        // -------------------------------------------------------

        typedef ConstantColorBlendSetterAccessorAdapter< 
            dest_accessor_type,
            typename alphamask_rawaccessor_type::value_type,
            Masks::alphamask_polarity>                                     colorblend_accessor_type;
        typedef AccessorTraits<colorblend_accessor_type>                   colorblend_accessor_traits;
        typedef typename colorblend_accessor_traits::template masked_accessor< 
            mask_rawaccessor_type,
            dest_iterator_type,
            mask_iterator_type,
            Masks::clipmask_polarity>::type                                masked_colorblend_accessor_type;

        // -------------------------------------------------------

        typedef ConstantColorBlendSetterAccessorAdapter< 
            dest_accessor_type,
            Color,
            Masks::alphamask_polarity>                                     colorblend_generic_accessor_type;
        typedef AccessorTraits<colorblend_generic_accessor_type>           colorblend_generic_accessor_traits;
        typedef typename colorblend_generic_accessor_traits::template masked_accessor< 
            mask_rawaccessor_type,
            dest_iterator_type,
            mask_iterator_type,
            Masks::clipmask_polarity>::type                                masked_colorblend_generic_accessor_type;

        // -------------------------------------------------------

        typedef JoinImageAccessorAdapter< dest_accessor_type,
                                          mask_rawaccessor_type >          joined_image_accessor_type;
        typedef JoinImageAccessorAdapter< GenericColorImageAccessor,
                                          GenericColorImageAccessor >      joined_generic_image_accessor_type;

        // -------------------------------------------------------

        dest_iterator_type                      maBegin;
        typename accessor_traits::color_lookup  maColorLookup;
        to_uint32_functor                       maToUInt32Converter;    
        dest_accessor_type                      maAccessor;
        colorblend_accessor_type                maColorBlendAccessor;
        colorblend_generic_accessor_type        maGenericColorBlendAccessor;
        raw_accessor_type                       maRawAccessor;
        xor_accessor_type                       maXorAccessor;
        raw_xor_accessor_type                   maRawXorAccessor;
        masked_accessor_type                    maMaskedAccessor;
        masked_colorblend_accessor_type         maMaskedColorBlendAccessor;
        masked_colorblend_generic_accessor_type maGenericMaskedColorBlendAccessor;
        masked_xoraccessor_type                 maMaskedXorAccessor;
        raw_maskedaccessor_type                 maRawMaskedAccessor;
        raw_maskedxor_accessor_type             maRawMaskedXorAccessor;
        raw_maskedmask_accessor_type            maRawMaskedMaskAccessor;

        // -------------------------------------------------------

        BitmapRenderer( const basegfx::B2IRange&         rBounds,
                        sal_Int32                        nScanlineFormat,
                        sal_Int32                        nScanlineStride,
                        sal_uInt8*                       pFirstScanline,
                        dest_iterator_type               begin, 
                        raw_accessor_type                rawAccessor,
                        dest_accessor_type               accessor,
                        const RawMemorySharedArray&      rMem,
                        const PaletteMemorySharedVector& rPalette ) :
            BitmapDevice( rBounds, nScanlineFormat, 
                          nScanlineStride, pFirstScanline, rMem, rPalette ),
            maBegin( begin ),
            maColorLookup(),
            maToUInt32Converter(),
            maAccessor( accessor ),
            maColorBlendAccessor( accessor ),
            maGenericColorBlendAccessor( accessor ),
            maRawAccessor( rawAccessor ),
            maXorAccessor( accessor ),
            maRawXorAccessor( rawAccessor ),
            maMaskedAccessor( accessor ),
            maMaskedColorBlendAccessor( maColorBlendAccessor ),
            maGenericMaskedColorBlendAccessor( maGenericColorBlendAccessor ),
            maMaskedXorAccessor( accessor ),
            maRawMaskedAccessor( rawAccessor ),
            maRawMaskedXorAccessor( rawAccessor ),
            maRawMaskedMaskAccessor( rawAccessor )
        {}

    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<mask_bitmap_type> getCompatibleClipMask( const BitmapDeviceSharedPtr& bmp ) const
        {
            boost::shared_ptr<mask_bitmap_type> pMask( boost::dynamic_pointer_cast<mask_bitmap_type>( bmp ));

            if( !pMask )
                return pMask;

            if( pMask->getSize() != getSize() )
                pMask.reset();

            return pMask;
        }

        virtual bool isCompatibleClipMask( const BitmapDeviceSharedPtr& bmp ) const
        {
            // TODO(P1): dynamic_cast usually called twice for
            // compatible formats
            return boost::dynamic_pointer_cast<mask_bitmap_type>( bmp ).get() != NULL;
        }

        boost::shared_ptr<alphamask_bitmap_type> getCompatibleAlphaMask( const BitmapDeviceSharedPtr& bmp ) const
        {
            return boost::dynamic_pointer_cast<alphamask_bitmap_type>( 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 basegfx::B2IRange&  rBounds )
        {
            fillImage(destIterRange(maBegin,
                                    maRawAccessor,
                                    rBounds), 
                      maColorLookup( 
                          maAccessor,
                          fillColor) );
        }

        virtual void setPixel_i( const basegfx::B2IPoint& rPt, 
                                 Color                    pixelColor, 
                                 DrawMode                 drawMode )
        {
            const DestIterator pixel( maBegin + 
                                      vigra::Diff2D(rPt.getX(),
                                                    rPt.getY()) );
            if( drawMode == DrawMode_XOR )
                maXorAccessor.set( pixelColor, 
                                   pixel );
            else
                maAccessor.set( pixelColor, 
                                pixel );
        }

        virtual void setPixel_i( const basegfx::B2IPoint&     rPt, 
                                 Color                        pixelColor, 
                                 DrawMode                     drawMode, 
                                 const BitmapDeviceSharedPtr& rClip )
        {
            boost::shared_ptr<mask_bitmap_type> pMask( getCompatibleClipMask(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( pixelColor,
                                         aIter );
            else
                maMaskedAccessor.set( pixelColor,
                                      aIter );
        }

        virtual Color getPixel_i(const basegfx::B2IPoint& rPt )
        {
            const DestIterator pixel( maBegin + 
                                      vigra::Diff2D(rPt.getX(),
                                                    rPt.getY()) );
            return maAccessor(pixel);
        }

        virtual sal_uInt32 getPixelData_i( const basegfx::B2IPoint& rPt )
        {
            const DestIterator pixel( maBegin + 
                                      vigra::Diff2D(rPt.getX(),
                                                    rPt.getY()) );
            return maToUInt32Converter(maRawAccessor(pixel));
        }

        template< typename Iterator, typename Col, typename RawAcc >
        void implRenderLine2( const basegfx::B2IPoint& rPt1,
                              const basegfx::B2IPoint& rPt2,
                              const basegfx::B2IRange& rBounds,
                              Col                      col,
                              const Iterator&          begin,
                              const RawAcc&            rawAcc )
        {
            renderClippedLine( rPt1, 
                               rPt2,
                               rBounds,
                               col,
                               begin,
                               rawAcc );
        }

        template< typename Iterator, typename Accessor, typename RawAcc >
        void implRenderLine( const basegfx::B2IPoint& rPt1,
                             const basegfx::B2IPoint& rPt2,
                             const basegfx::B2IRange& rBounds,
                             Color                    col,
                             const Iterator&          begin,
                             const Accessor&          acc,
                             const RawAcc&            rawAcc )
        {
            implRenderLine2( rPt1,rPt2,rBounds,
                             maColorLookup( acc,
                                            col ),
                             begin,
                             rawAcc );
        }
    
        template< typename Iterator, typename RawAcc, typename XorAcc >
        void implDrawLine( const basegfx::B2IPoint& rPt1,
                           const basegfx::B2IPoint& rPt2,
                           const basegfx::B2IRange& rBounds,
                           Color                    col,
                           const Iterator&          begin, 
                           const RawAcc&            rawAcc,
                           const XorAcc&            xorAcc, 
                           DrawMode                 drawMode )
        {
            if( drawMode == DrawMode_XOR )
                implRenderLine( rPt1, rPt2, rBounds, col,
                                begin, maAccessor, xorAcc );
            else
                implRenderLine( rPt1, rPt2, rBounds, col,
                                begin, maAccessor, rawAcc );
        }

        virtual void drawLine_i(const basegfx::B2IPoint& rPt1, 
                                const basegfx::B2IPoint& rPt2, 
                                const basegfx::B2IRange& rBounds,
                                Color                    lineColor, 
                                DrawMode                 drawMode )
        {
            implDrawLine(rPt1,rPt2,rBounds,lineColor,
                         maBegin,
                         maRawAccessor,maRawXorAccessor,drawMode);
        }

        composite_iterator_type getMaskedIter( const BitmapDeviceSharedPtr& rClip ) const
        {
            boost::shared_ptr<mask_bitmap_type> pMask( getCompatibleClipMask(rClip) );
            OSL_ASSERT( pMask );

            return composite_iterator_type( maBegin, 
                                            pMask->maBegin );
        }

        virtual void drawLine_i(const basegfx::B2IPoint&     rPt1, 
                                const basegfx::B2IPoint&     rPt2, 
                                const basegfx::B2IRange&     rBounds,
                                Color                        lineColor, 
                                DrawMode                     drawMode, 
                                const BitmapDeviceSharedPtr& rClip )
        {
            implDrawLine(rPt1,rPt2,rBounds,lineColor,
                         getMaskedIter(rClip),
                         maRawMaskedAccessor,
                         maRawMaskedXorAccessor,drawMode);
        }

        template< typename Iterator, typename RawAcc >
        void implDrawPolygon( const basegfx::B2DPolygon& rPoly, 
                              const basegfx::B2IRange&   rBounds,
                              Color                      col,
                              const Iterator&            begin, 
                              const RawAcc&              acc )
        {
            basegfx::B2DPolygon aPoly( rPoly );
            if( rPoly.areControlPointsUsed() )
                aPoly = basegfx::tools::adaptiveSubdivideByCount( rPoly );

            const typename dest_iterator_type::value_type colorIndex( maColorLookup( 
                                                                          maAccessor,
                                                                          col));
            const sal_uInt32                              nVertices( aPoly.count() );
            for( sal_uInt32 i=1; i<nVertices; ++i )
                implRenderLine2( basegfx::fround(aPoly.getB2DPoint(i-1)), 
                                 basegfx::fround(aPoly.getB2DPoint(i)), 
                                 rBounds,
                                 colorIndex,
                                 begin,
                                 acc );

            if( nVertices > 1 && aPoly.isClosed() )
                implRenderLine2( basegfx::fround(aPoly.getB2DPoint(nVertices-1)), 
                                 basegfx::fround(aPoly.getB2DPoint(0)), 
                                 rBounds,
                                 colorIndex,
                                 begin,
                                 acc );
        }

        virtual void drawPolygon_i(const basegfx::B2DPolygon& rPoly, 
                                   const basegfx::B2IRange&   rBounds,
                                   Color                      lineColor, 
                                   DrawMode                   drawMode )
        {
            if( drawMode == DrawMode_XOR )
                implDrawPolygon( rPoly, rBounds, lineColor, 
                                 maBegin, 
                                 maRawXorAccessor );
            else
                implDrawPolygon( rPoly, rBounds, lineColor, 
                                 maBegin, 
                                 maRawAccessor );
        }

        virtual void drawPolygon_i(const basegfx::B2DPolygon&   rPoly, 
                                   const basegfx::B2IRange&     rBounds,
                                   Color                        lineColor, 
                                   DrawMode                     drawMode, 
                                   const BitmapDeviceSharedPtr& rClip )
        {
            if( drawMode == DrawMode_XOR )
                implDrawPolygon( rPoly, rBounds, lineColor, 
                                 getMaskedIter(rClip),
                                 maRawMaskedXorAccessor );
            else
                implDrawPolygon( rPoly, rBounds, lineColor, 
                                 getMaskedIter(rClip),
                                 maRawMaskedAccessor );
        }

        template< typename Iterator, typename RawAcc >
        void implFillPolyPolygon( const basegfx::B2DPolyPolygon& rPoly, 
                                  Color                          col,
                                  const Iterator&                begin, 
                                  const RawAcc&                  acc,
                                  const basegfx::B2IRange&       rBounds )
        {
            basegfx::B2DPolyPolygon aPoly( rPoly );
            if( rPoly.areControlPointsUsed() )
                aPoly = basegfx::tools::adaptiveSubdivideByCount( rPoly );

            renderClippedPolyPolygon( begin, 
                                      acc,
                                      maColorLookup( maAccessor,
                                                     col),
                                      rBounds,
                                      aPoly,
                                      basegfx::FillRule_EVEN_ODD );
        }

        virtual void fillPolyPolygon_i(const basegfx::B2DPolyPolygon& rPoly, 
                                       Color                          fillColor, 
                                       DrawMode                       drawMode,
                                       const basegfx::B2IRange&       rBounds )
        {
            if( drawMode == DrawMode_XOR )
                implFillPolyPolygon( rPoly, fillColor, 
                                     maBegin,
                                     maRawXorAccessor,
                                     rBounds );
            else
                implFillPolyPolygon( rPoly, fillColor, 
                                     maBegin,
                                     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, 
                                     getMaskedIter(rClip),
                                     maRawMaskedXorAccessor,
                                     rBounds );
            else
                implFillPolyPolygon( rPoly, fillColor, 
                                     getMaskedIter(rClip),
                                     maRawMaskedAccessor,
                                     rBounds );
        }

        template< typename Iterator, typename RawAcc >
        void implDrawBitmap(const BitmapDeviceSharedPtr& rSrcBitmap,
                            const basegfx::B2IRange&     rSrcRect,
                            const basegfx::B2IRange&     rDstRect,
                            const Iterator&              begin,
                            const RawAcc&                acc)
        {
            boost::shared_ptr<BitmapRenderer> pSrcBmp( getCompatibleBitmap(rSrcBitmap) );
            OSL_ASSERT( pSrcBmp );

            scaleImage(
                srcIterRange(pSrcBmp->maBegin,
                             pSrcBmp->maRawAccessor,
                             rSrcRect),
                destIterRange(begin,
                              acc,
                              rDstRect),
                rSrcBitmap.get() == this );
        }

        template< typename Iterator, typename Acc >
        void implDrawBitmapGeneric(const BitmapDeviceSharedPtr& rSrcBitmap,
                                   const basegfx::B2IRange&     rSrcRect,
                                   const basegfx::B2IRange&     rDstRect,
                                   const Iterator&              begin,
                                   const Acc&                   acc)
        {
            GenericColorImageAccessor aSrcAcc( rSrcBitmap );
 
            scaleImage(
                srcIterRange(vigra::Diff2D(),
                             aSrcAcc,
                             rSrcRect),
                destIterRange(begin,
                              acc,
                              rDstRect));
        }

        virtual void drawBitmap_i(const BitmapDeviceSharedPtr& rSrcBitmap,
                                  const basegfx::B2IRange&     rSrcRect,
                                  const basegfx::B2IRange&     rDstRect, 
                                  DrawMode                     drawMode )
        {
            if( isCompatibleBitmap( rSrcBitmap ) )
            {
                if( drawMode == DrawMode_XOR )
                    implDrawBitmap(rSrcBitmap, rSrcRect, rDstRect,
                                   maBegin,
                                   maRawXorAccessor);
                else
                    implDrawBitmap(rSrcBitmap, rSrcRect, rDstRect,
                                   maBegin,
                                   maRawAccessor);
            }
            else
            {
                if( drawMode == DrawMode_XOR )
                    implDrawBitmapGeneric(rSrcBitmap, rSrcRect, rDstRect,
                                          maBegin,
                                          maXorAccessor);
                else
                    implDrawBitmapGeneric(rSrcBitmap, rSrcRect, rDstRect,
                                          maBegin,
                                          maAccessor);
            }
        }

        virtual void drawBitmap_i(const BitmapDeviceSharedPtr& rSrcBitmap,
                                  const basegfx::B2IRange&     rSrcRect,
                                  const basegfx::B2IRange&     rDstRect, 
                                  DrawMode                     drawMode, 
                                  const BitmapDeviceSharedPtr& rClip )
        {
            if( isCompatibleBitmap( rSrcBitmap ) )
            {
                if( drawMode == DrawMode_XOR )
                    implDrawBitmap(rSrcBitmap, rSrcRect, rDstRect,
                                   getMaskedIter(rClip),
                                   maRawMaskedXorAccessor);
                else
                    implDrawBitmap(rSrcBitmap, rSrcRect, rDstRect,
                                   getMaskedIter(rClip),
                                   maRawMaskedAccessor);
            }
            else
            {
                if( drawMode == DrawMode_XOR )
                    implDrawBitmapGeneric(rSrcBitmap, rSrcRect, rDstRect,
                                          getMaskedIter(rClip),
                                          maMaskedXorAccessor);
                else
                    implDrawBitmapGeneric(rSrcBitmap, rSrcRect, rDstRect,
                                          getMaskedIter(rClip),
                                          maMaskedAccessor);
            }
        }

        virtual void drawMaskedColor_i(Color                        aSrcColor,
                                       const BitmapDeviceSharedPtr& rAlphaMask,
                                       const basegfx::B2IRange&     rSrcRect,
                                       const basegfx::B2IPoint&     rDstPoint )
        {
            boost::shared_ptr<mask_bitmap_type>      pMask( getCompatibleClipMask(rAlphaMask) );
            boost::shared_ptr<alphamask_bitmap_type> pAlpha( getCompatibleAlphaMask(rAlphaMask) );

            if( pAlpha )
            {
                maColorBlendAccessor.setColor( aSrcColor );

                vigra::copyImage( srcIterRange(pAlpha->maBegin,
                                               pAlpha->maRawAccessor,
                                               rSrcRect),
                                  destIter(maBegin,
                                           maColorBlendAccessor,
                                           rDstPoint) );
            }
            else if( pMask )
            {
                const composite_iterator_type aBegin(
                    maBegin + vigra::Diff2D(rDstPoint.getX(),
                                            rDstPoint.getY()),
                    pMask->maBegin + topLeft(rSrcRect) );
                            
                fillImage(aBegin,
                          aBegin + vigra::Diff2D(rSrcRect.getWidth(),
                                                 rSrcRect.getHeight()), 
                          maRawMaskedAccessor,
                          maColorLookup( 
                              maAccessor,
                              aSrcColor) );
            }
            else
            {
                GenericColorImageAccessor aSrcAcc( rAlphaMask );
                maGenericColorBlendAccessor.setColor( aSrcColor );

                vigra::copyImage( srcIterRange(vigra::Diff2D(),
                                               aSrcAcc,
                                               rSrcRect),
                                  destIter(maBegin,
                                           maGenericColorBlendAccessor,
                                           rDstPoint) );
            }
        }

        virtual void drawMaskedColor_i(Color                        aSrcColor,
                                       const BitmapDeviceSharedPtr& rAlphaMask,
                                       const basegfx::B2IRange&     rSrcRect,
                                       const basegfx::B2IPoint&     rDstPoint, 
                                       const BitmapDeviceSharedPtr& rClip )
        {
            boost::shared_ptr<mask_bitmap_type>      pMask( getCompatibleClipMask(rAlphaMask) );
            boost::shared_ptr<alphamask_bitmap_type> pAlpha( getCompatibleAlphaMask(rAlphaMask) );

            if( pAlpha )
            {
                const composite_iterator_type aBegin( getMaskedIter(rClip) );
                maMaskedColorBlendAccessor.get1stWrappedAccessor().setColor( 
                    aSrcColor );

                vigra::copyImage( srcIterRange(pAlpha->maBegin,
                                               pAlpha->maRawAccessor,
                                               rSrcRect),
                                  destIter(aBegin,
                                           maMaskedColorBlendAccessor,
                                           rDstPoint) );
            }
            else if( pMask )
            {
                boost::shared_ptr<mask_bitmap_type> pClipMask( getCompatibleClipMask(rClip) );
                OSL_ASSERT( pClipMask );

                // setup a ((iter,mask),clipMask) composite composite
                // iterator, to pass both masks (clip and alpha mask)
                // to the algorithm
                const composite_composite_mask_iterator_type aBegin(
                    composite_iterator_type(
                        maBegin + vigra::Diff2D(rDstPoint.getX(),
                                                rDstPoint.getY()),
                        pMask->maBegin + topLeft(rSrcRect)),
                    pClipMask->maBegin + vigra::Diff2D(rDstPoint.getX(),
                                                       rDstPoint.getY()) );
                            
                fillImage(aBegin,
                          aBegin + vigra::Diff2D(rSrcRect.getWidth(),
                                                 rSrcRect.getHeight()), 
                          maRawMaskedMaskAccessor,
                          maColorLookup( 
                              maAccessor,
                              aSrcColor) );
            }
            else
            {
                GenericColorImageAccessor aSrcAcc( rAlphaMask );
                const composite_iterator_type aBegin( getMaskedIter(rClip) );
                maGenericMaskedColorBlendAccessor.get1stWrappedAccessor().setColor( 
                    aSrcColor );

                vigra::copyImage( srcIterRange(vigra::Diff2D(),
                                               aSrcAcc,
                                               rSrcRect),
                                  destIter(aBegin,
                                           maGenericMaskedColorBlendAccessor,
                                           rDstPoint) );
            }
        }

        template< typename Iterator, typename Acc >
        void implDrawMaskedBitmap(const BitmapDeviceSharedPtr& rSrcBitmap,
                                  const BitmapDeviceSharedPtr& rMask,
                                  const basegfx::B2IRange&     rSrcRect,
                                  const basegfx::B2IRange&     rDstRect,
                                  const Iterator&              begin,
                                  const Acc&                   acc)
        {
            boost::shared_ptr<BitmapRenderer>   pSrcBmp( getCompatibleBitmap(rSrcBitmap) );
            boost::shared_ptr<mask_bitmap_type> pMask( getCompatibleClipMask(rMask) );
            OSL_ASSERT( pMask && pSrcBmp );

            scaleImage(
                srcIterRange(composite_iterator_type(
                                 pSrcBmp->maBegin,
                                 pMask->maBegin),
                             joined_image_accessor_type(
                                 pSrcBmp->maAccessor,
                                 pMask->maRawAccessor),
                             rSrcRect),
                destIterRange(begin,
                              typename masked_input_splitting_accessor<
                                       Acc,
                                       joined_image_accessor_type,
                                       Masks::clipmask_polarity,
                                       FastMask >::type(acc),
                              rDstRect),
                rSrcBitmap.get() == this);
        }

        template< typename Iterator, typename Acc >
        void implDrawMaskedBitmapGeneric(const BitmapDeviceSharedPtr& rSrcBitmap,
                                         const BitmapDeviceSharedPtr& rMask,
                                         const basegfx::B2IRange&     rSrcRect,
                                         const basegfx::B2IRange&     rDstRect,
                                         const Iterator&              begin,
                                         const Acc&                   acc)
        {
            GenericColorImageAccessor aSrcAcc( rSrcBitmap );
            GenericColorImageAccessor aMaskAcc( rMask );

            const vigra::Diff2D aTopLeft(rSrcRect.getMinX(),
                                         rSrcRect.getMinY());
            const vigra::Diff2D aBottomRight(rSrcRect.getMaxX(),
                                             rSrcRect.getMaxY());
            scaleImage(
                vigra::make_triple(
                    generic_composite_iterator_type(
                        aTopLeft,aTopLeft),
                    generic_composite_iterator_type(
                        aBottomRight,aBottomRight),
                    joined_generic_image_accessor_type(
                        aSrcAcc,
                        aMaskAcc)),
                destIterRange(begin,
                              typename masked_input_splitting_accessor<
                                       Acc,
                                       joined_generic_image_accessor_type,
                                       Masks::clipmask_polarity,
                                       NoFastMask >::type(acc),
                              rDstRect));
        }

        virtual void drawMaskedBitmap_i(const BitmapDeviceSharedPtr& rSrcBitmap,
                                        const BitmapDeviceSharedPtr& rMask,
                                        const basegfx::B2IRange&     rSrcRect,
                                        const basegfx::B2IRange&     rDstRect, 
                                        DrawMode                     drawMode )
        {
            if( isCompatibleClipMask(rMask) &&
                isCompatibleBitmap(rSrcBitmap) )
            {
                if( drawMode == DrawMode_XOR )
                    implDrawMaskedBitmap(rSrcBitmap, rMask,
                                         rSrcRect, rDstRect,
                                         maBegin,
                                         maXorAccessor);
                else
                    implDrawMaskedBitmap(rSrcBitmap, rMask,
                                         rSrcRect, rDstRect,
                                         maBegin,
                                         maAccessor);
            }
            else
            {
                if( drawMode == DrawMode_XOR )
                    implDrawMaskedBitmapGeneric(rSrcBitmap, rMask,
                                                rSrcRect, rDstRect,
                                                maBegin,
                                                maXorAccessor);
                else
                    implDrawMaskedBitmapGeneric(rSrcBitmap, rMask,
                                                rSrcRect, rDstRect,
                                                maBegin,
                                                maAccessor);
            }
        }

        virtual void drawMaskedBitmap_i(const BitmapDeviceSharedPtr& rSrcBitmap,
                                        const BitmapDeviceSharedPtr& rMask,
                                        const basegfx::B2IRange&     rSrcRect,
                                        const basegfx::B2IRange&     rDstRect, 
                                        DrawMode                     drawMode, 
                                        const BitmapDeviceSharedPtr& rClip )
        {
            if( isCompatibleClipMask(rMask) &&
                isCompatibleBitmap(rSrcBitmap) )
            {
                if( drawMode == DrawMode_XOR )
                    implDrawMaskedBitmap(rSrcBitmap, rMask,
                                         rSrcRect, rDstRect,
                                         getMaskedIter(rClip),
                                         maMaskedXorAccessor);
                else
                    implDrawMaskedBitmap(rSrcBitmap, rMask,
                                         rSrcRect, rDstRect,
                                         getMaskedIter(rClip),
                                         maMaskedAccessor);
            }
            else
            {
                if( drawMode == DrawMode_XOR )
                    implDrawMaskedBitmapGeneric(rSrcBitmap, rMask,
                                                rSrcRect, rDstRect,
                                                getMaskedIter(rClip),
                                                maMaskedXorAccessor);
                else
                    implDrawMaskedBitmapGeneric(rSrcBitmap, rMask,
                                                rSrcRect, rDstRect,
                                                getMaskedIter(rClip),
                                                maMaskedAccessor);
            }
        }
    };
} // namespace

struct ImplBitmapDevice
{
    /** Bitmap memory plus deleter. 

        Always points to the start of the mem
     */
    RawMemorySharedArray      mpMem;

    /// Palette memory plus deleter (might be NULL)
    PaletteMemorySharedVector mpPalette;

    /** Bounds of the device. 

        maBounds.getWidth()/getHeight() yield the true size of the
        device (i.e. the rectangle given by maBounds covers the device
        area under the excluding-bottommost-and-rightmost-pixels fill
        rule)
     */
    basegfx::B2IRange         maBounds;

    /** Bounds of the device. 

        maBounds.getWidth()/getHeight() yield the true size of the
        device minus 1 (i.e. the rectangle given by maBounds covers
        the device area under the
        including-the-bottommost-and-rightmost-pixels fill rule).

        The member is used to clip line stroking against the device
        bounds.
     */
    basegfx::B2IRange         maLineClipRect;

    /// Scanline format, as provided at the constructor
    sal_Int32                 mnScanlineFormat;

    /// Scanline stride. Negative for bottom-to-top formats
    sal_Int32                 mnScanlineStride;
    
    /// raw ptr to 0th scanline. used for cloning a generic renderer
    sal_uInt8*                mpFirstScanline;

    /** (Optional) device sharing the same memory, and used for input
        clip masks/alpha masks/bitmaps that don't match our exact
        bitmap format.

        This is to avoid the combinatorical explosion when dealing
        with n bitmap formats, which could be combined with n clip
        masks, alpha masks and bitmap masks (yielding a total of n^4
        combinations). Since each BitmapRenderer is specialized for
        one specific combination of said formats, a lot of duplicate
        code would be generated, most of which probably never
        used. Therefore, only the most common combinations are
        specialized templates, the remainder gets handled by this
        generic renderer (via runtime polymorphism).
     */
    BitmapDeviceSharedPtr     mpGenericRenderer;
};


BitmapDevice::BitmapDevice( const basegfx::B2IRange&         rBounds,
                            sal_Int32                        nScanlineFormat,
                            sal_Int32                        nScanlineStride,
                            sal_uInt8*                       pFirstScanline,
                            const RawMemorySharedArray&      rMem,
                            const PaletteMemorySharedVector& rPalette ) :
    mpImpl( new ImplBitmapDevice )
{
    mpImpl->mpMem = rMem;
    mpImpl->mpPalette = rPalette;
    mpImpl->maBounds = rBounds;
    mpImpl->maLineClipRect = basegfx::B2IRange( rBounds.getMinX(),
                                                rBounds.getMinY(),
                                                rBounds.getMaxX()-1,
                                                rBounds.getMaxY()-1 );
    mpImpl->mnScanlineFormat = nScanlineFormat;
    mpImpl->mnScanlineStride = nScanlineStride;
    mpImpl->mpFirstScanline  = pFirstScanline;
}
    
BitmapDevice::~BitmapDevice()
{
    // outline, because of internal ImplBitmapDevice
}

basegfx::B2IVector BitmapDevice::getSize() const
{
    
    return basegfx::B2IVector(
        mpImpl->maBounds.getMaxX() - mpImpl->maBounds.getMinX(),
        mpImpl->maBounds.getMaxY() - mpImpl->maBounds.getMinY() );
}

bool BitmapDevice::isTopDown() const
{
    return mpImpl->mnScanlineStride >= 0;
}

sal_Int32 BitmapDevice::getScanlineFormat() const
{
    return mpImpl->mnScanlineFormat;
}

sal_Int32 BitmapDevice::getScanlineStride() const
{
    return mpImpl->mnScanlineStride < 0 ? 
        -mpImpl->mnScanlineStride : mpImpl->mnScanlineStride;
}

RawMemorySharedArray BitmapDevice::getBuffer() const
{
    return mpImpl->mpMem;
}

PaletteMemorySharedVector BitmapDevice::getPalette() const
{
    return mpImpl->mpPalette;
}

sal_Int32 BitmapDevice::getPaletteEntryCount() const
{
    return mpImpl->mpPalette ? mpImpl->mpPalette->size() : 0;
}

void BitmapDevice::clear( Color fillColor )
{
    clear_i( fillColor, mpImpl->maBounds );
}

void BitmapDevice::setPixel( const basegfx::B2IPoint& rPt, 
                             Color                    lineColor, 
                             DrawMode                 drawMode )
{
    if( mpImpl->maLineClipRect.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);
        return;
    }

    if( mpImpl->maLineClipRect.isInside(rPt) )
    {
        if( isCompatibleClipMask( rClip ) )
            setPixel_i(rPt,lineColor,drawMode,rClip);
        else
            getGenericRenderer()->setPixel( rPt, lineColor, drawMode, rClip );
    }
}

Color BitmapDevice::getPixel( const basegfx::B2IPoint& rPt )
{
    if( mpImpl->maLineClipRect.isInside(rPt) )
        return getPixel_i(rPt);

    return Color();
}

sal_uInt32 BitmapDevice::getPixelData( const basegfx::B2IPoint& rPt )
{
    if( mpImpl->maLineClipRect.isInside(rPt) )
        return getPixelData_i(rPt);

    return 0;
}

void BitmapDevice::drawLine( const basegfx::B2IPoint& rPt1, 
                             const basegfx::B2IPoint& rPt2, 
                             Color                    lineColor, 
                             DrawMode                 drawMode )
{
    drawLine_i( rPt1, 
                rPt2,
                mpImpl->maLineClipRect,
                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);
        return;
    }

    if( isCompatibleClipMask( rClip ) )
        drawLine_i( rPt1, 
                    rPt2,
                    mpImpl->maLineClipRect,
                    lineColor,
                    drawMode,
                    rClip );
    else
        getGenericRenderer()->drawLine( rPt1, rPt2, lineColor, 
                                        drawMode, rClip );
}

void BitmapDevice::drawPolygon( const basegfx::B2DPolygon& rPoly, 
                                Color                      lineColor, 
                                DrawMode                   drawMode )
{
    const sal_uInt32 numVertices( rPoly.count() );
    if( numVertices )
        drawPolygon_i( rPoly,
                       mpImpl->maLineClipRect,
                       lineColor, drawMode );
}

void BitmapDevice::drawPolygon( const basegfx::B2DPolygon&   rPoly, 
                                Color                        lineColor, 
                                DrawMode                     drawMode, 
                                const BitmapDeviceSharedPtr& rClip )
{
    if( !rClip )
    {
        drawPolygon(rPoly,lineColor,drawMode);
        return;
    }

    const sal_uInt32 numVertices( rPoly.count() );
    if( numVertices )
    {
        if( isCompatibleClipMask( rClip ) )
            drawPolygon_i( rPoly,
                           mpImpl->maLineClipRect,
                           lineColor, drawMode, rClip );
        else
            getGenericRenderer()->drawPolygon( rPoly, lineColor, 
                                               drawMode, rClip );
    }
}

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);
        return;
    }

    if( isCompatibleClipMask( rClip ) )
        fillPolyPolygon_i( rPoly, fillColor, drawMode, mpImpl->maBounds, rClip );
    else
        getGenericRenderer()->fillPolyPolygon( rPoly, fillColor, 
                                               drawMode, rClip );
}


namespace
{
    void assertImagePoint( const basegfx::B2IPoint& rPt,
                           const basegfx::B2IRange& rPermittedRange )
    {
        (void)rPt; (void)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 );
#else
        (void)rRange; (void)rPermittedRange;
#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);

        drawBitmap_i( rSrcBitmap, aSrcRange, aDestRange, drawMode );
    }
}

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);
        return;
    }

    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( isCompatibleClipMask( rClip ) )
        {
            drawBitmap_i( rSrcBitmap, aSrcRange, aDestRange, drawMode, rClip );
        }
        else
        {
            getGenericRenderer()->drawBitmap( rSrcBitmap, rSrcRect, 
                                              rDstRect, drawMode, rClip );
        }
    }
}

void BitmapDevice::drawMaskedColor( Color                        aSrcColor,
                                    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( rAlphaMask.get() == this )
        {
            // src == dest, copy rAlphaMask beforehand
            // ---------------------------------------------------

            const basegfx::B2ITuple aSize( aSrcRange.getWidth(),
                                           aSrcRange.getHeight() );
            BitmapDeviceSharedPtr pAlphaCopy( 
                cloneBitmapDevice( aSize,
                                   shared_from_this()) );
            basegfx::B2ITuple aGcc3WorkaroundTemporary;
            const basegfx::B2IRange aAlphaRange( aGcc3WorkaroundTemporary,
                                                 aSize );
            pAlphaCopy->drawBitmap(rAlphaMask,
                                   aSrcRange,
                                   aAlphaRange,
                                   DrawMode_PAINT);
            drawMaskedColor_i( aSrcColor, pAlphaCopy, aAlphaRange, aDestPoint );
        }
        else
        {
            drawMaskedColor_i( aSrcColor, rAlphaMask, aSrcRange, aDestPoint );
        }
    }
}

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);
        return;
    }

    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( isCompatibleClipMask( rClip ) )
        {
            if( rAlphaMask.get() == this )
            {
                // src == dest, copy rAlphaMask beforehand
                // ---------------------------------------------------

                const basegfx::B2ITuple aSize( aSrcRange.getWidth(),
                                               aSrcRange.getHeight() );
                BitmapDeviceSharedPtr pAlphaCopy( 
                    cloneBitmapDevice( aSize,
                                       shared_from_this()) );
                basegfx::B2ITuple aGcc3WorkaroundTemporary;
                const basegfx::B2IRange aAlphaRange( aGcc3WorkaroundTemporary,
                                                     aSize );
                pAlphaCopy->drawBitmap(rAlphaMask,
                                       aSrcRange,
                                       aAlphaRange,
                                       DrawMode_PAINT);
                drawMaskedColor_i( aSrcColor, pAlphaCopy, aAlphaRange, aDestPoint, rClip );
            }
            else
            {
                drawMaskedColor_i( aSrcColor, rAlphaMask, aSrcRange, aDestPoint, rClip );
            }
        }
        else
        {
            getGenericRenderer()->drawMaskedColor( aSrcColor, rAlphaMask,
                                                   rSrcRect, rDstPoint, rClip );
        }
    }
}

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);

        drawMaskedBitmap_i( rSrcBitmap, rMask, aSrcRange, aDestRange, drawMode );
    }
}

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);
        return;
    }

    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( isCompatibleClipMask( rClip ) )
        {
            drawMaskedBitmap_i( rSrcBitmap, rMask, aSrcRange, aDestRange, drawMode, rClip );
        }
        else
        {
            getGenericRenderer()->drawMaskedBitmap( rSrcBitmap, rMask, rSrcRect, 
                                                    rDstRect, drawMode, rClip );
        }
    }
}


//----------------------------------------------------------------------------------

/** Standard clip and alpha masks
 */
struct StdMasks
{
    typedef PixelFormatTraits_GREY1_MSB   clipmask_format_traits;
    typedef PixelFormatTraits_GREY8       alphamask_format_traits;

    /// Clipmask: 0 means opaque
    static const bool clipmask_polarity  = false;

    /// Alpha mask: 0 means fully transparent
    static const bool alphamask_polarity = true;
};

#if 0
/** Clip and alpha masks for the generic renderer (of course, those
    need to be generic, too)
 */
struct MaskTraitsGeneric
{
    typedef PixelFormatTraits_GenericInteger   clipmask_format_traits;
    typedef PixelFormatTraits_GenericInteger   alphamask_format_traits;
};
#endif

//----------------------------------------------------------------------------------

// Some compilers don't like the nested template wrap_accessor
// reference in the parameter list - being slightly less type safe,
// then.
#ifndef BASEBMP_NO_NESTED_TEMPLATE_PARAMETER

/// Produces a specialized renderer for the given pixel format
template< class FormatTraits, class MaskTraits >
BitmapDeviceSharedPtr createRenderer(
    const basegfx::B2IRange&                                     rBounds,
    sal_Int32                                                    nScanlineFormat,
    sal_Int32                                                    nScanlineStride,
    sal_uInt8*                                                   pFirstScanline,
    typename FormatTraits::raw_accessor_type const&              rRawAccessor,
    typename FormatTraits::accessor_selector::template wrap_accessor<
          typename FormatTraits::raw_accessor_type>::type const& rAccessor,
    boost::shared_array< sal_uInt8 >                             pMem,
    const PaletteMemorySharedVector&                             pPal )

#else

template< class FormatTraits, class MaskTraits, class Accessor >
BitmapDeviceSharedPtr createRenderer(
    const basegfx::B2IRange&                                     rBounds,
    sal_Int32                                                    nScanlineFormat,
    sal_Int32                                                    nScanlineStride,
    sal_uInt8*                                                   pFirstScanline,
    typename FormatTraits::raw_accessor_type const&              rRawAccessor,
    Accessor const&                                              rAccessor,
    boost::shared_array< sal_uInt8 >                             pMem,
    const PaletteMemorySharedVector&                             pPal )

#endif
{
    typedef typename FormatTraits::iterator_type                Iterator;
    typedef BitmapRenderer< Iterator,
                            typename FormatTraits::raw_accessor_type,
                            typename FormatTraits::accessor_selector,
                            MaskTraits >                        Renderer;

    return BitmapDeviceSharedPtr( 
        new Renderer( rBounds,
                      nScanlineFormat,
                      nScanlineStride,
                      pFirstScanline,
                      Iterator(
                          reinterpret_cast<typename Iterator::value_type*>(
                              pFirstScanline),
                          nScanlineStride),
                      rRawAccessor,
                      rAccessor,
                      pMem,
                      pPal ));
}

/// Create standard grey level palette
PaletteMemorySharedVector createStandardPalette( 
    const PaletteMemorySharedVector& pPal,
    sal_Int32                        nNumEntries )
{
    if( pPal || nNumEntries <= 0 )
        return pPal;

    boost::shared_ptr< std::vector<Color> > pLocalPal(
        new std::vector<Color>(nNumEntries) );
    
    const sal_Int32 nIncrement( 0x00FFFFFF/nNumEntries );
    --nNumEntries;
    for( sal_Int32 i=0, c=0; i<nNumEntries; ++i,c+=nIncrement )
        pLocalPal->at(i) = Color(0xFF000000 | c);
    
    pLocalPal->at(nNumEntries) = Color(0xFFFFFFFF);
    
    return pLocalPal;
}

template< class FormatTraits, class MaskTraits >
BitmapDeviceSharedPtr createRenderer(
    const basegfx::B2IRange&                rBounds,
    sal_Int32                               nScanlineFormat,
    sal_Int32                               nScanlineStride,
    sal_uInt8*                              pFirstScanline,
    boost::shared_array< sal_uInt8 >        pMem,
    const PaletteMemorySharedVector&        pPal )
{
    return createRenderer<FormatTraits,
                          MaskTraits>(rBounds,
                                      nScanlineFormat,
                                      nScanlineStride,
                                      pFirstScanline,
                                      typename FormatTraits::raw_accessor_type(),
                                      typename FormatTraits::accessor_selector::template
                                      wrap_accessor<
                                          typename FormatTraits::raw_accessor_type>::type(),
                                      pMem,
                                      pPal);
}

template< class FormatTraits, class MaskTraits >
BitmapDeviceSharedPtr createRenderer(
    const basegfx::B2IRange&                rBounds,
    sal_Int32                               nScanlineFormat,
    sal_Int32                               nScanlineStride,
    sal_uInt8*                              pFirstScanline,
    boost::shared_array< sal_uInt8 >        pMem,
    PaletteMemorySharedVector               pPal,
    int                                     nBitsPerPixel )
{
    pPal = createStandardPalette(pPal,
                                 1UL << nBitsPerPixel);

    OSL_ASSERT(pPal);
    return createRenderer<FormatTraits,
                          MaskTraits>(rBounds,
                                      nScanlineFormat,
                                      nScanlineStride,
                                      pFirstScanline,
                                      typename FormatTraits::raw_accessor_type(),
                                      typename FormatTraits::accessor_selector::template 
                                          wrap_accessor<
                                      typename FormatTraits::raw_accessor_type>::type(
                                          &pPal->at(0),
                                          pPal->size()),
                                      pMem,
                                      pPal);
}

//----------------------------------------------------------------------------------

// TODO(Q3): consolidate with canvas/canvastools.hxx! Best move this
// to o3tl or sal/bithacks.hxx ...

/** Compute the next highest power of 2 of a 32-bit value

	Code devised by Sean Anderson, in good ole HAKMEM
	tradition.

    @return 1 << (lg(x - 1) + 1)
*/
inline sal_uInt32 nextPow2( sal_uInt32 x )
{
    --x;
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;

    return ++x;
}

//----------------------------------------------------------------------------------

namespace
{
BitmapDeviceSharedPtr createBitmapDeviceImpl( const basegfx::B2IVector&        rSize,
                                              bool                             bTopDown,
                                              sal_Int32                        nScanlineFormat,
                                              boost::shared_array< sal_uInt8 > pMem,
                                              PaletteMemorySharedVector        pPal,
                                              const basegfx::B2IRange*         pSubset )
{
    if( nScanlineFormat <= Format::NONE || 
        nScanlineFormat >  Format::MAX )
        return BitmapDeviceSharedPtr();

    static const sal_uInt8 bitsPerPixel[] = 
    {
        0,  // NONE                   
        1,  // ONE_BIT_MSB_GREY       
        1,  // ONE_BIT_LSB_GREY       
        1,  // ONE_BIT_MSB_PAL        
        1,  // ONE_BIT_LSB_PAL        
        4,  // FOUR_BIT_MSB_GREY      
        4,  // FOUR_BIT_LSB_GREY      
        4,  // FOUR_BIT_MSB_PAL       
        4,  // FOUR_BIT_LSB_PAL       
        8,  // EIGHT_BIT_PAL          
        8,  // EIGHT_BIT_GREY         
        16, // SIXTEEN_BIT_LSB_TC_MASK    
        16, // SIXTEEN_BIT_MSB_TC_MASK    
        24, // TWENTYFOUR_BIT_TC_MASK 
        32, // THIRTYTWO_BIT_TC_MASK  
        32, // THIRTYTWO_BIT_TC_MASK_ARGB
    };

    sal_Int32  nScanlineStride(0);

    // round up to full 8 bit, divide by 8
    nScanlineStride = (rSize.getX()*bitsPerPixel[nScanlineFormat] + 7) >> 3;

    // rounded up to next full power-of-two number of bytes
    const sal_uInt32 bytesPerPixel = nextPow2(
        (bitsPerPixel[nScanlineFormat] + 7) >> 3);

    // now make nScanlineStride a multiple of bytesPerPixel
    nScanlineStride = (nScanlineStride + bytesPerPixel - 1) / bytesPerPixel * bytesPerPixel;

    // factor in bottom-up scanline order case
    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 + nScanlineStride : pMem.get();

    // shrink render area to given subset, if given
    basegfx::B2IRange aBounds(0,0,rSize.getX(),rSize.getY());
    if( pSubset )
        aBounds.intersect( *pSubset );

    switch( nScanlineFormat )
    {
        // ----------------------------------------------------------------------
        // one bit formats

        case Format::ONE_BIT_MSB_GREY:
            return createRenderer<PixelFormatTraits_GREY1_MSB,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal );

        case Format::ONE_BIT_LSB_GREY:
            return createRenderer<PixelFormatTraits_GREY1_LSB,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal );

        case Format::ONE_BIT_MSB_PAL:
            return createRenderer<PixelFormatTraits_PAL1_MSB,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal,
                bitsPerPixel[nScanlineFormat] );

        case Format::ONE_BIT_LSB_PAL:
            return createRenderer<PixelFormatTraits_PAL1_LSB,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal,
                bitsPerPixel[nScanlineFormat] );


        // ----------------------------------------------------------------------
        // four bit formats

        case Format::FOUR_BIT_MSB_GREY:
            return createRenderer<PixelFormatTraits_GREY4_MSB,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal );

        case Format::FOUR_BIT_LSB_GREY:
            return createRenderer<PixelFormatTraits_GREY4_LSB,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal );

        case Format::FOUR_BIT_MSB_PAL:
            return createRenderer<PixelFormatTraits_PAL4_MSB,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal,
                bitsPerPixel[nScanlineFormat] );

        case Format::FOUR_BIT_LSB_PAL:
            return createRenderer<PixelFormatTraits_PAL4_LSB,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal,
                bitsPerPixel[nScanlineFormat] );


        // ----------------------------------------------------------------------
        // eight bit formats

        case Format::EIGHT_BIT_GREY:
            return createRenderer<PixelFormatTraits_GREY8,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal );

        case Format::EIGHT_BIT_PAL:
            return createRenderer<PixelFormatTraits_PAL8,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal,
                bitsPerPixel[nScanlineFormat] );


        // ----------------------------------------------------------------------
        // sixteen bit formats

        case Format::SIXTEEN_BIT_LSB_TC_MASK:
            return createRenderer<PixelFormatTraits_RGB16_565_LSB,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal );

        case Format::SIXTEEN_BIT_MSB_TC_MASK:
            return createRenderer<PixelFormatTraits_RGB16_565_MSB,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal );


        // ----------------------------------------------------------------------
        // twentyfour bit formats
        case Format::TWENTYFOUR_BIT_TC_MASK:
            return createRenderer<PixelFormatTraits_BGR24,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal );


        // ----------------------------------------------------------------------
        // thirtytwo bit formats

        case Format::THIRTYTWO_BIT_TC_MASK:
            return createRenderer<PixelFormatTraits_RGB32_888,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal );

        case Format::THIRTYTWO_BIT_TC_MASK_ARGB:
            return createRenderer<PixelFormatTraits_BGR32_888,StdMasks>(
                aBounds, nScanlineFormat, nScanlineStride,
                pFirstScanline, pMem, pPal );
    }

    // 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(),
                                   NULL );
}

BitmapDeviceSharedPtr createBitmapDevice( const basegfx::B2IVector&        rSize,
                                          bool                             bTopDown,
                                          sal_Int32                        nScanlineFormat,
                                          const PaletteMemorySharedVector& rPalette )
{
    return createBitmapDeviceImpl( rSize, 
                                   bTopDown, 
                                   nScanlineFormat, 
                                   boost::shared_array< sal_uInt8 >(),
                                   rPalette,
                                   NULL );
}

BitmapDeviceSharedPtr createBitmapDevice( const basegfx::B2IVector&        rSize,
                                          bool                             bTopDown,
                                          sal_Int32                        nScanlineFormat,
                                          const RawMemorySharedArray&      rMem,
                                          const PaletteMemorySharedVector& rPalette )
{
    return createBitmapDeviceImpl( rSize, 
                                   bTopDown, 
                                   nScanlineFormat, 
                                   rMem,
                                   rPalette,
                                   NULL );
}

BitmapDeviceSharedPtr subsetBitmapDevice( const BitmapDeviceSharedPtr&     rProto,
                                          const basegfx::B2IRange&         rSubset )
{
    return createBitmapDeviceImpl( rProto->getSize(),
                                   rProto->isTopDown(), 
                                   rProto->getScanlineFormat(), 
                                   rProto->getBuffer(),
                                   rProto->getPalette(),
                                   &rSubset );
}

BitmapDeviceSharedPtr cloneBitmapDevice( const basegfx::B2IVector&        rSize,
                                         const BitmapDeviceSharedPtr&     rProto )
{
    return createBitmapDeviceImpl( rSize, 
                                   rProto->isTopDown(), 
                                   rProto->getScanlineFormat(), 
                                   boost::shared_array< sal_uInt8 >(),
                                   rProto->getPalette(),
                                   NULL );
}

//----------------------------------------------------------------------------------

/// Clone our device, with GenericImageAccessor to handle all formats
BitmapDeviceSharedPtr BitmapDevice::getGenericRenderer() const
{
#if 0
    // xxx TODO
    typedef BitmapRenderer< PixelFormatTraits_GenericInteger::iterator_type,
                            PixelFormatTraits_GenericInteger::raw_accessor_type,
                            PixelFormatTraits_GenericInteger::accessor_selector,
                            MaskTraitsGeneric >                        
            Renderer;

    if( !mpImpl->mpGenericRenderer )
    {
        mpImpl->mpGenericRenderer.reset(
            new Renderer(
                mpImpl->maBounds, 
                isTopDown(), 
                getScanlineFormat(), 
                getScanlineStride(),
                mpImpl->mpFirstScanline,
                PixelFormatTraits_GenericInteger::iterator_type(),
                GenericIntegerImageRawAccessor<Color>(
                    const_cast<BitmapDevice*>(this)->shared_from_this()),
                GenericIntegerImageAccessor<Color>(
                    const_cast<BitmapDevice*>(this)->shared_from_this()),
                getBuffer(), 
                getPalette() ));
    }
#endif

    return mpImpl->mpGenericRenderer;
}

} // namespace basebmp