xref: /AOO41X/main/canvas/source/vcl/impltools.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_canvas.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include <canvas/debug.hxx>
32*cdf0e10cSrcweir #include <tools/diagnose_ex.h>
33*cdf0e10cSrcweir 
34*cdf0e10cSrcweir #include <rtl/math.hxx>
35*cdf0e10cSrcweir #include <rtl/logfile.hxx>
36*cdf0e10cSrcweir 
37*cdf0e10cSrcweir #include <com/sun/star/geometry/RealSize2D.hpp>
38*cdf0e10cSrcweir #include <com/sun/star/geometry/RealPoint2D.hpp>
39*cdf0e10cSrcweir #include <com/sun/star/geometry/RealRectangle2D.hpp>
40*cdf0e10cSrcweir #include <com/sun/star/rendering/RenderState.hpp>
41*cdf0e10cSrcweir #include <com/sun/star/rendering/XCanvas.hpp>
42*cdf0e10cSrcweir #include <com/sun/star/rendering/XBitmap.hpp>
43*cdf0e10cSrcweir #include <com/sun/star/rendering/XPolyPolygon2D.hpp>
44*cdf0e10cSrcweir #include <com/sun/star/geometry/RealBezierSegment2D.hpp>
45*cdf0e10cSrcweir #include <com/sun/star/rendering/XIntegerBitmap.hpp>
46*cdf0e10cSrcweir 
47*cdf0e10cSrcweir #include <vcl/salbtype.hxx>
48*cdf0e10cSrcweir #include <vcl/bmpacc.hxx>
49*cdf0e10cSrcweir #include <vcl/bitmapex.hxx>
50*cdf0e10cSrcweir #include <vcl/metric.hxx>
51*cdf0e10cSrcweir #include <vcl/canvastools.hxx>
52*cdf0e10cSrcweir 
53*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx>
54*cdf0e10cSrcweir #include <basegfx/tuple/b2dtuple.hxx>
55*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
56*cdf0e10cSrcweir #include <basegfx/range/b2drectangle.hxx>
57*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx>
58*cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx>
59*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx>
60*cdf0e10cSrcweir 
61*cdf0e10cSrcweir #include <canvas/canvastools.hxx>
62*cdf0e10cSrcweir 
63*cdf0e10cSrcweir #include "impltools.hxx"
64*cdf0e10cSrcweir #include "canvasbitmap.hxx"
65*cdf0e10cSrcweir 
66*cdf0e10cSrcweir #include <numeric>
67*cdf0e10cSrcweir 
68*cdf0e10cSrcweir 
69*cdf0e10cSrcweir using namespace ::com::sun::star;
70*cdf0e10cSrcweir 
71*cdf0e10cSrcweir namespace vclcanvas
72*cdf0e10cSrcweir {
73*cdf0e10cSrcweir     namespace tools
74*cdf0e10cSrcweir     {
75*cdf0e10cSrcweir         ::BitmapEx bitmapExFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap )
76*cdf0e10cSrcweir         {
77*cdf0e10cSrcweir             // TODO(F3): CanvasCustomSprite should also be tunnelled
78*cdf0e10cSrcweir             // through (also implements XIntegerBitmap interface)
79*cdf0e10cSrcweir             CanvasBitmap* pBitmapImpl = dynamic_cast< CanvasBitmap* >( xBitmap.get() );
80*cdf0e10cSrcweir 
81*cdf0e10cSrcweir             if( pBitmapImpl )
82*cdf0e10cSrcweir             {
83*cdf0e10cSrcweir                 return pBitmapImpl->getBitmap();
84*cdf0e10cSrcweir             }
85*cdf0e10cSrcweir             else
86*cdf0e10cSrcweir             {
87*cdf0e10cSrcweir                 SpriteCanvas* pCanvasImpl = dynamic_cast< SpriteCanvas* >( xBitmap.get() );
88*cdf0e10cSrcweir                 if( pCanvasImpl && pCanvasImpl->getBackBuffer() )
89*cdf0e10cSrcweir                 {
90*cdf0e10cSrcweir                     // TODO(F3): mind the plain Canvas impl. Consolidate with CWS canvas05
91*cdf0e10cSrcweir                     const ::OutputDevice& rDev( pCanvasImpl->getBackBuffer()->getOutDev() );
92*cdf0e10cSrcweir                     const ::Point aEmptyPoint;
93*cdf0e10cSrcweir                     return rDev.GetBitmapEx( aEmptyPoint,
94*cdf0e10cSrcweir                                              rDev.GetOutputSizePixel() );
95*cdf0e10cSrcweir                 }
96*cdf0e10cSrcweir 
97*cdf0e10cSrcweir                 // TODO(F2): add support for floating point bitmap formats
98*cdf0e10cSrcweir                 uno::Reference< rendering::XIntegerReadOnlyBitmap > xIntBmp(
99*cdf0e10cSrcweir                     xBitmap, uno::UNO_QUERY_THROW );
100*cdf0e10cSrcweir 
101*cdf0e10cSrcweir                 ::BitmapEx aBmpEx = ::vcl::unotools::bitmapExFromXBitmap( xIntBmp );
102*cdf0e10cSrcweir                 if( !!aBmpEx )
103*cdf0e10cSrcweir                     return aBmpEx;
104*cdf0e10cSrcweir 
105*cdf0e10cSrcweir                 // TODO(F1): extract pixel from XBitmap interface
106*cdf0e10cSrcweir                 ENSURE_OR_THROW( false,
107*cdf0e10cSrcweir                                   "bitmapExFromXBitmap(): could not extract bitmap" );
108*cdf0e10cSrcweir             }
109*cdf0e10cSrcweir 
110*cdf0e10cSrcweir             return ::BitmapEx();
111*cdf0e10cSrcweir         }
112*cdf0e10cSrcweir 
113*cdf0e10cSrcweir         bool setupFontTransform( ::Point&						o_rPoint,
114*cdf0e10cSrcweir                                  ::Font& 						io_rVCLFont,
115*cdf0e10cSrcweir                                  const rendering::ViewState& 	rViewState,
116*cdf0e10cSrcweir                                  const rendering::RenderState& 	rRenderState,
117*cdf0e10cSrcweir                                  ::OutputDevice&				rOutDev )
118*cdf0e10cSrcweir         {
119*cdf0e10cSrcweir             ::basegfx::B2DHomMatrix aMatrix;
120*cdf0e10cSrcweir 
121*cdf0e10cSrcweir             ::canvas::tools::mergeViewAndRenderTransform(aMatrix,
122*cdf0e10cSrcweir                                                          rViewState,
123*cdf0e10cSrcweir                                                          rRenderState);
124*cdf0e10cSrcweir 
125*cdf0e10cSrcweir             ::basegfx::B2DTuple aScale;
126*cdf0e10cSrcweir             ::basegfx::B2DTuple aTranslate;
127*cdf0e10cSrcweir             double nRotate, nShearX;
128*cdf0e10cSrcweir 
129*cdf0e10cSrcweir             aMatrix.decompose( aScale, aTranslate, nRotate, nShearX );
130*cdf0e10cSrcweir 
131*cdf0e10cSrcweir             // #i72417# detecting the 180 degree rotation case manually here.
132*cdf0e10cSrcweir             if( aScale.getX() < 0.0 &&
133*cdf0e10cSrcweir                 aScale.getY() < 0.0 &&
134*cdf0e10cSrcweir                 basegfx::fTools::equalZero(nRotate) )
135*cdf0e10cSrcweir             {
136*cdf0e10cSrcweir                 aScale *= -1.0;
137*cdf0e10cSrcweir                 nRotate += M_PI;
138*cdf0e10cSrcweir             }
139*cdf0e10cSrcweir 
140*cdf0e10cSrcweir             // query font metric _before_ tampering with width and height
141*cdf0e10cSrcweir             if( !::rtl::math::approxEqual(aScale.getX(), aScale.getY()) )
142*cdf0e10cSrcweir             {
143*cdf0e10cSrcweir                 // retrieve true font width
144*cdf0e10cSrcweir                 const sal_Int32 nFontWidth( rOutDev.GetFontMetric( io_rVCLFont ).GetWidth() );
145*cdf0e10cSrcweir 
146*cdf0e10cSrcweir                 const sal_Int32 nScaledFontWidth( ::basegfx::fround(nFontWidth * aScale.getX()) );
147*cdf0e10cSrcweir 
148*cdf0e10cSrcweir                 if( !nScaledFontWidth )
149*cdf0e10cSrcweir                 {
150*cdf0e10cSrcweir                     // scale is smaller than one pixel - disable text
151*cdf0e10cSrcweir                     // output altogether
152*cdf0e10cSrcweir                     return false;
153*cdf0e10cSrcweir                 }
154*cdf0e10cSrcweir 
155*cdf0e10cSrcweir                 io_rVCLFont.SetWidth( nScaledFontWidth );
156*cdf0e10cSrcweir             }
157*cdf0e10cSrcweir 
158*cdf0e10cSrcweir             if( !::rtl::math::approxEqual(aScale.getY(), 1.0) )
159*cdf0e10cSrcweir             {
160*cdf0e10cSrcweir                 const sal_Int32 nFontHeight( io_rVCLFont.GetHeight() );
161*cdf0e10cSrcweir                 io_rVCLFont.SetHeight( ::basegfx::fround(nFontHeight * aScale.getY()) );
162*cdf0e10cSrcweir             }
163*cdf0e10cSrcweir 
164*cdf0e10cSrcweir             io_rVCLFont.SetOrientation( static_cast< short >( ::basegfx::fround(-fmod(nRotate, 2*M_PI)*(1800.0/M_PI)) ) );
165*cdf0e10cSrcweir 
166*cdf0e10cSrcweir             // TODO(F2): Missing functionality in VCL: shearing
167*cdf0e10cSrcweir             o_rPoint.X() = ::basegfx::fround(aTranslate.getX());
168*cdf0e10cSrcweir             o_rPoint.Y() = ::basegfx::fround(aTranslate.getY());
169*cdf0e10cSrcweir 
170*cdf0e10cSrcweir             return true;
171*cdf0e10cSrcweir         }
172*cdf0e10cSrcweir 
173*cdf0e10cSrcweir         bool isRectangle( const PolyPolygon& rPolyPoly )
174*cdf0e10cSrcweir         {
175*cdf0e10cSrcweir             // exclude some cheap cases first
176*cdf0e10cSrcweir             if( rPolyPoly.Count() != 1 )
177*cdf0e10cSrcweir                 return false;
178*cdf0e10cSrcweir 
179*cdf0e10cSrcweir             const ::Polygon& rPoly( rPolyPoly[0] );
180*cdf0e10cSrcweir 
181*cdf0e10cSrcweir             sal_uInt16 nCount( rPoly.GetSize() );
182*cdf0e10cSrcweir             if( nCount < 4 )
183*cdf0e10cSrcweir                 return false;
184*cdf0e10cSrcweir 
185*cdf0e10cSrcweir             // delegate to basegfx
186*cdf0e10cSrcweir             return ::basegfx::tools::isRectangle( rPoly.getB2DPolygon() );
187*cdf0e10cSrcweir         }
188*cdf0e10cSrcweir 
189*cdf0e10cSrcweir 
190*cdf0e10cSrcweir         // VCL-Canvas related
191*cdf0e10cSrcweir         //---------------------------------------------------------------------
192*cdf0e10cSrcweir 
193*cdf0e10cSrcweir         ::Point mapRealPoint2D( const geometry::RealPoint2D& 	rPoint,
194*cdf0e10cSrcweir                                 const rendering::ViewState& 	rViewState,
195*cdf0e10cSrcweir                                 const rendering::RenderState&	rRenderState )
196*cdf0e10cSrcweir         {
197*cdf0e10cSrcweir             ::basegfx::B2DPoint aPoint( ::basegfx::unotools::b2DPointFromRealPoint2D(rPoint) );
198*cdf0e10cSrcweir 
199*cdf0e10cSrcweir             ::basegfx::B2DHomMatrix aMatrix;
200*cdf0e10cSrcweir             aPoint *= ::canvas::tools::mergeViewAndRenderTransform(aMatrix,
201*cdf0e10cSrcweir                                                                    rViewState,
202*cdf0e10cSrcweir                                                                    rRenderState);
203*cdf0e10cSrcweir 
204*cdf0e10cSrcweir             return ::vcl::unotools::pointFromB2DPoint( aPoint );
205*cdf0e10cSrcweir         }
206*cdf0e10cSrcweir 
207*cdf0e10cSrcweir         ::PolyPolygon mapPolyPolygon( const ::basegfx::B2DPolyPolygon& 	rPoly,
208*cdf0e10cSrcweir                                       const rendering::ViewState& 		rViewState,
209*cdf0e10cSrcweir                                       const rendering::RenderState&		rRenderState )
210*cdf0e10cSrcweir         {
211*cdf0e10cSrcweir             ::basegfx::B2DHomMatrix aMatrix;
212*cdf0e10cSrcweir             ::canvas::tools::mergeViewAndRenderTransform(aMatrix,
213*cdf0e10cSrcweir                                                          rViewState,
214*cdf0e10cSrcweir                                                          rRenderState);
215*cdf0e10cSrcweir 
216*cdf0e10cSrcweir             ::basegfx::B2DPolyPolygon aTemp( rPoly );
217*cdf0e10cSrcweir 
218*cdf0e10cSrcweir             aTemp.transform( aMatrix );
219*cdf0e10cSrcweir 
220*cdf0e10cSrcweir             return ::PolyPolygon( aTemp );
221*cdf0e10cSrcweir         }
222*cdf0e10cSrcweir 
223*cdf0e10cSrcweir         ::BitmapEx transformBitmap( const BitmapEx& 				rBitmap,
224*cdf0e10cSrcweir                                     const ::basegfx::B2DHomMatrix& 	rTransform,
225*cdf0e10cSrcweir                                     const uno::Sequence< double >&	rDeviceColor,
226*cdf0e10cSrcweir                                     ModulationMode					eModulationMode )
227*cdf0e10cSrcweir         {
228*cdf0e10cSrcweir             RTL_LOGFILE_CONTEXT( aLog, "::vclcanvas::tools::transformBitmap()" );
229*cdf0e10cSrcweir             RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::vclcanvas::tools::transformBitmap: 0x%X", &rBitmap );
230*cdf0e10cSrcweir 
231*cdf0e10cSrcweir             // calc transformation and size of bitmap to be
232*cdf0e10cSrcweir             // generated. Note, that the translational components are
233*cdf0e10cSrcweir             // deleted from the transformation; this can be handled by
234*cdf0e10cSrcweir             // an offset when painting the bitmap
235*cdf0e10cSrcweir             const Size 					aBmpSize( rBitmap.GetSizePixel() );
236*cdf0e10cSrcweir             ::basegfx::B2DRectangle		aDestRect;
237*cdf0e10cSrcweir 
238*cdf0e10cSrcweir             bool bCopyBack( false );
239*cdf0e10cSrcweir 
240*cdf0e10cSrcweir             // calc effective transformation for bitmap
241*cdf0e10cSrcweir             const ::basegfx::B2DRectangle aSrcRect( 0, 0,
242*cdf0e10cSrcweir                                                     aBmpSize.Width(),
243*cdf0e10cSrcweir                                                     aBmpSize.Height() );
244*cdf0e10cSrcweir             ::canvas::tools::calcTransformedRectBounds( aDestRect,
245*cdf0e10cSrcweir                                                         aSrcRect,
246*cdf0e10cSrcweir                                                         rTransform );
247*cdf0e10cSrcweir 
248*cdf0e10cSrcweir             // re-center bitmap, such that it's left, top border is
249*cdf0e10cSrcweir             // aligned with (0,0). The method takes the given
250*cdf0e10cSrcweir             // rectangle, and calculates a transformation that maps
251*cdf0e10cSrcweir             // this rectangle unscaled to the origin.
252*cdf0e10cSrcweir             ::basegfx::B2DHomMatrix aLocalTransform;
253*cdf0e10cSrcweir             ::canvas::tools::calcRectToOriginTransform( aLocalTransform,
254*cdf0e10cSrcweir                                                         aSrcRect,
255*cdf0e10cSrcweir                                                         rTransform );
256*cdf0e10cSrcweir 
257*cdf0e10cSrcweir             const bool bModulateColors( eModulationMode == MODULATE_WITH_DEVICECOLOR &&
258*cdf0e10cSrcweir                                         rDeviceColor.getLength() > 2 );
259*cdf0e10cSrcweir             const double nRedModulation( bModulateColors ? rDeviceColor[0] : 1.0 );
260*cdf0e10cSrcweir             const double nGreenModulation( bModulateColors ? rDeviceColor[1] : 1.0 );
261*cdf0e10cSrcweir             const double nBlueModulation( bModulateColors ? rDeviceColor[2] : 1.0 );
262*cdf0e10cSrcweir             const double nAlphaModulation( bModulateColors && rDeviceColor.getLength() > 3 ?
263*cdf0e10cSrcweir                                            rDeviceColor[3] : 1.0 );
264*cdf0e10cSrcweir 
265*cdf0e10cSrcweir             Bitmap aSrcBitmap( rBitmap.GetBitmap() );
266*cdf0e10cSrcweir             Bitmap aSrcAlpha;
267*cdf0e10cSrcweir 
268*cdf0e10cSrcweir             // differentiate mask and alpha channel (on-off
269*cdf0e10cSrcweir             // vs. multi-level transparency)
270*cdf0e10cSrcweir             if( rBitmap.IsTransparent() )
271*cdf0e10cSrcweir             {
272*cdf0e10cSrcweir                 if( rBitmap.IsAlpha() )
273*cdf0e10cSrcweir                     aSrcAlpha = rBitmap.GetAlpha().GetBitmap();
274*cdf0e10cSrcweir                 else
275*cdf0e10cSrcweir                     aSrcAlpha = rBitmap.GetMask();
276*cdf0e10cSrcweir             }
277*cdf0e10cSrcweir 
278*cdf0e10cSrcweir             ScopedBitmapReadAccess pReadAccess( aSrcBitmap.AcquireReadAccess(),
279*cdf0e10cSrcweir                                                 aSrcBitmap );
280*cdf0e10cSrcweir             ScopedBitmapReadAccess pAlphaReadAccess( rBitmap.IsTransparent() ?
281*cdf0e10cSrcweir                                                      aSrcAlpha.AcquireReadAccess() :
282*cdf0e10cSrcweir                                                      (BitmapReadAccess*)NULL,
283*cdf0e10cSrcweir                                                      aSrcAlpha );
284*cdf0e10cSrcweir 
285*cdf0e10cSrcweir             if( pReadAccess.get() == NULL ||
286*cdf0e10cSrcweir                 (pAlphaReadAccess.get() == NULL && rBitmap.IsTransparent()) )
287*cdf0e10cSrcweir             {
288*cdf0e10cSrcweir                 // TODO(E2): Error handling!
289*cdf0e10cSrcweir                 ENSURE_OR_THROW( false,
290*cdf0e10cSrcweir                                   "transformBitmap(): could not access source bitmap" );
291*cdf0e10cSrcweir             }
292*cdf0e10cSrcweir 
293*cdf0e10cSrcweir             // mapping table, to translate pAlphaReadAccess' pixel
294*cdf0e10cSrcweir             // values into destination alpha values (needed e.g. for
295*cdf0e10cSrcweir             // paletted 1-bit masks).
296*cdf0e10cSrcweir             sal_uInt8 aAlphaMap[256];
297*cdf0e10cSrcweir 
298*cdf0e10cSrcweir             if( rBitmap.IsTransparent() )
299*cdf0e10cSrcweir             {
300*cdf0e10cSrcweir                 if( rBitmap.IsAlpha() )
301*cdf0e10cSrcweir                 {
302*cdf0e10cSrcweir                     // source already has alpha channel - 1:1 mapping,
303*cdf0e10cSrcweir                     // i.e. aAlphaMap[0]=0,...,aAlphaMap[255]=255.
304*cdf0e10cSrcweir                     ::std::iota( aAlphaMap, &aAlphaMap[256], 0 );
305*cdf0e10cSrcweir                 }
306*cdf0e10cSrcweir                 else
307*cdf0e10cSrcweir                 {
308*cdf0e10cSrcweir                     // mask transparency - determine used palette colors
309*cdf0e10cSrcweir                     const BitmapColor& rCol0( pAlphaReadAccess->GetPaletteColor( 0 ) );
310*cdf0e10cSrcweir                     const BitmapColor& rCol1( pAlphaReadAccess->GetPaletteColor( 1 ) );
311*cdf0e10cSrcweir 
312*cdf0e10cSrcweir                     // shortcut for true luminance calculation
313*cdf0e10cSrcweir                     // (assumes that palette is grey-level)
314*cdf0e10cSrcweir                     aAlphaMap[0] = rCol0.GetRed();
315*cdf0e10cSrcweir                     aAlphaMap[1] = rCol1.GetRed();
316*cdf0e10cSrcweir                 }
317*cdf0e10cSrcweir             }
318*cdf0e10cSrcweir             // else: mapping table is not used
319*cdf0e10cSrcweir 
320*cdf0e10cSrcweir             const Size aDestBmpSize( ::basegfx::fround( aDestRect.getWidth() ),
321*cdf0e10cSrcweir                                      ::basegfx::fround( aDestRect.getHeight() ) );
322*cdf0e10cSrcweir 
323*cdf0e10cSrcweir             if( aDestBmpSize.Width() == 0 || aDestBmpSize.Height() == 0 )
324*cdf0e10cSrcweir                 return BitmapEx();
325*cdf0e10cSrcweir 
326*cdf0e10cSrcweir             Bitmap aDstBitmap( aDestBmpSize, aSrcBitmap.GetBitCount(), &pReadAccess->GetPalette() );
327*cdf0e10cSrcweir             Bitmap aDstAlpha( AlphaMask( aDestBmpSize ).GetBitmap() );
328*cdf0e10cSrcweir 
329*cdf0e10cSrcweir             {
330*cdf0e10cSrcweir                 // just to be on the safe side: let the
331*cdf0e10cSrcweir                 // ScopedAccessors get destructed before
332*cdf0e10cSrcweir                 // copy-constructing the resulting bitmap. This will
333*cdf0e10cSrcweir                 // rule out the possibility that cached accessor data
334*cdf0e10cSrcweir                 // is not yet written back.
335*cdf0e10cSrcweir                 ScopedBitmapWriteAccess pWriteAccess( aDstBitmap.AcquireWriteAccess(),
336*cdf0e10cSrcweir                                                       aDstBitmap );
337*cdf0e10cSrcweir                 ScopedBitmapWriteAccess pAlphaWriteAccess( aDstAlpha.AcquireWriteAccess(),
338*cdf0e10cSrcweir                                                            aDstAlpha );
339*cdf0e10cSrcweir 
340*cdf0e10cSrcweir 
341*cdf0e10cSrcweir                 if( pWriteAccess.get() != NULL &&
342*cdf0e10cSrcweir                     pAlphaWriteAccess.get() != NULL &&
343*cdf0e10cSrcweir                     rTransform.isInvertible() )
344*cdf0e10cSrcweir                 {
345*cdf0e10cSrcweir                     // we're doing inverse mapping here, i.e. mapping
346*cdf0e10cSrcweir                     // points from the destination bitmap back to the
347*cdf0e10cSrcweir                     // source
348*cdf0e10cSrcweir                     ::basegfx::B2DHomMatrix aTransform( aLocalTransform );
349*cdf0e10cSrcweir                     aTransform.invert();
350*cdf0e10cSrcweir 
351*cdf0e10cSrcweir                     // for the time being, always read as ARGB
352*cdf0e10cSrcweir                     for( int y=0; y<aDestBmpSize.Height(); ++y )
353*cdf0e10cSrcweir                     {
354*cdf0e10cSrcweir                         if( bModulateColors )
355*cdf0e10cSrcweir                         {
356*cdf0e10cSrcweir                             // TODO(P2): Have different branches for
357*cdf0e10cSrcweir                             // alpha-only modulation (color
358*cdf0e10cSrcweir                             // modulations eq. 1.0)
359*cdf0e10cSrcweir 
360*cdf0e10cSrcweir                             // modulate all color channels with given
361*cdf0e10cSrcweir                             // values
362*cdf0e10cSrcweir 
363*cdf0e10cSrcweir                             // differentiate mask and alpha channel (on-off
364*cdf0e10cSrcweir                             // vs. multi-level transparency)
365*cdf0e10cSrcweir                             if( rBitmap.IsTransparent() )
366*cdf0e10cSrcweir                             {
367*cdf0e10cSrcweir                                 // Handling alpha and mask just the same...
368*cdf0e10cSrcweir                                 for( int x=0; x<aDestBmpSize.Width(); ++x )
369*cdf0e10cSrcweir                                 {
370*cdf0e10cSrcweir                                     ::basegfx::B2DPoint aPoint(x,y);
371*cdf0e10cSrcweir                                     aPoint *= aTransform;
372*cdf0e10cSrcweir 
373*cdf0e10cSrcweir                                     const int nSrcX( ::basegfx::fround( aPoint.getX() ) );
374*cdf0e10cSrcweir                                     const int nSrcY( ::basegfx::fround( aPoint.getY() ) );
375*cdf0e10cSrcweir                                     if( nSrcX < 0 || nSrcX >= aBmpSize.Width() ||
376*cdf0e10cSrcweir                                         nSrcY < 0 || nSrcY >= aBmpSize.Height() )
377*cdf0e10cSrcweir                                     {
378*cdf0e10cSrcweir                                         pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) );
379*cdf0e10cSrcweir                                     }
380*cdf0e10cSrcweir                                     else
381*cdf0e10cSrcweir                                     {
382*cdf0e10cSrcweir                                         // modulate alpha with
383*cdf0e10cSrcweir                                         // nAlphaModulation. This is a
384*cdf0e10cSrcweir                                         // little bit verbose, formula
385*cdf0e10cSrcweir                                         // is 255 - (255-pixAlpha)*nAlphaModulation
386*cdf0e10cSrcweir                                         // (invert 'alpha' pixel value,
387*cdf0e10cSrcweir                                         // to get the standard alpha
388*cdf0e10cSrcweir                                         // channel behaviour)
389*cdf0e10cSrcweir                                         pAlphaWriteAccess->SetPixel( y, x,
390*cdf0e10cSrcweir                                                                      BitmapColor(
391*cdf0e10cSrcweir                                                                          255U -
392*cdf0e10cSrcweir                                                                          static_cast<sal_uInt8>(
393*cdf0e10cSrcweir                                                                              nAlphaModulation*
394*cdf0e10cSrcweir                                                                              (255U
395*cdf0e10cSrcweir                                                                               - aAlphaMap[ pAlphaReadAccess->GetPixel(
396*cdf0e10cSrcweir                                                                                                nSrcY,
397*cdf0e10cSrcweir                                                                                                nSrcX ).GetIndex() ] ) + .5 ) ) );
398*cdf0e10cSrcweir 
399*cdf0e10cSrcweir                                         BitmapColor aColor( pReadAccess->GetPixel( nSrcY,
400*cdf0e10cSrcweir                                                                                    nSrcX ) );
401*cdf0e10cSrcweir 
402*cdf0e10cSrcweir                                         aColor.SetRed(
403*cdf0e10cSrcweir                                             static_cast<sal_uInt8>(
404*cdf0e10cSrcweir                                                 nRedModulation *
405*cdf0e10cSrcweir                                                 aColor.GetRed() + .5 ));
406*cdf0e10cSrcweir                                         aColor.SetGreen(
407*cdf0e10cSrcweir                                             static_cast<sal_uInt8>(
408*cdf0e10cSrcweir                                                 nGreenModulation *
409*cdf0e10cSrcweir                                                 aColor.GetGreen() + .5 ));
410*cdf0e10cSrcweir                                         aColor.SetBlue(
411*cdf0e10cSrcweir                                             static_cast<sal_uInt8>(
412*cdf0e10cSrcweir                                                 nBlueModulation *
413*cdf0e10cSrcweir                                                 aColor.GetBlue() + .5 ));
414*cdf0e10cSrcweir 
415*cdf0e10cSrcweir                                         pWriteAccess->SetPixel( y, x,
416*cdf0e10cSrcweir                                                                 aColor );
417*cdf0e10cSrcweir                                     }
418*cdf0e10cSrcweir                                 }
419*cdf0e10cSrcweir                             }
420*cdf0e10cSrcweir                             else
421*cdf0e10cSrcweir                             {
422*cdf0e10cSrcweir                                 for( int x=0; x<aDestBmpSize.Width(); ++x )
423*cdf0e10cSrcweir                                 {
424*cdf0e10cSrcweir                                     ::basegfx::B2DPoint aPoint(x,y);
425*cdf0e10cSrcweir                                     aPoint *= aTransform;
426*cdf0e10cSrcweir 
427*cdf0e10cSrcweir                                     const int nSrcX( ::basegfx::fround( aPoint.getX() ) );
428*cdf0e10cSrcweir                                     const int nSrcY( ::basegfx::fround( aPoint.getY() ) );
429*cdf0e10cSrcweir                                     if( nSrcX < 0 || nSrcX >= aBmpSize.Width() ||
430*cdf0e10cSrcweir                                         nSrcY < 0 || nSrcY >= aBmpSize.Height() )
431*cdf0e10cSrcweir                                     {
432*cdf0e10cSrcweir                                         pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) );
433*cdf0e10cSrcweir                                     }
434*cdf0e10cSrcweir                                     else
435*cdf0e10cSrcweir                                     {
436*cdf0e10cSrcweir                                         // modulate alpha with
437*cdf0e10cSrcweir                                         // nAlphaModulation. This is a
438*cdf0e10cSrcweir                                         // little bit verbose, formula
439*cdf0e10cSrcweir                                         // is 255 - 255*nAlphaModulation
440*cdf0e10cSrcweir                                         // (invert 'alpha' pixel value,
441*cdf0e10cSrcweir                                         // to get the standard alpha
442*cdf0e10cSrcweir                                         // channel behaviour)
443*cdf0e10cSrcweir                                         pAlphaWriteAccess->SetPixel( y, x,
444*cdf0e10cSrcweir                                                                      BitmapColor(
445*cdf0e10cSrcweir                                                                          255U -
446*cdf0e10cSrcweir                                                                          static_cast<sal_uInt8>(
447*cdf0e10cSrcweir                                                                              nAlphaModulation*255.0
448*cdf0e10cSrcweir                                                                              + .5 ) ) );
449*cdf0e10cSrcweir 
450*cdf0e10cSrcweir                                         BitmapColor aColor( pReadAccess->GetPixel( nSrcY,
451*cdf0e10cSrcweir                                                                                    nSrcX ) );
452*cdf0e10cSrcweir 
453*cdf0e10cSrcweir                                         aColor.SetRed(
454*cdf0e10cSrcweir                                             static_cast<sal_uInt8>(
455*cdf0e10cSrcweir                                                 nRedModulation *
456*cdf0e10cSrcweir                                                 aColor.GetRed() + .5 ));
457*cdf0e10cSrcweir                                         aColor.SetGreen(
458*cdf0e10cSrcweir                                             static_cast<sal_uInt8>(
459*cdf0e10cSrcweir                                                 nGreenModulation *
460*cdf0e10cSrcweir                                                 aColor.GetGreen() + .5 ));
461*cdf0e10cSrcweir                                         aColor.SetBlue(
462*cdf0e10cSrcweir                                             static_cast<sal_uInt8>(
463*cdf0e10cSrcweir                                                 nBlueModulation *
464*cdf0e10cSrcweir                                                 aColor.GetBlue() + .5 ));
465*cdf0e10cSrcweir 
466*cdf0e10cSrcweir                                         pWriteAccess->SetPixel( y, x,
467*cdf0e10cSrcweir                                                                 aColor );
468*cdf0e10cSrcweir                                     }
469*cdf0e10cSrcweir                                 }
470*cdf0e10cSrcweir                             }
471*cdf0e10cSrcweir                         }
472*cdf0e10cSrcweir                         else
473*cdf0e10cSrcweir                         {
474*cdf0e10cSrcweir                             // differentiate mask and alpha channel (on-off
475*cdf0e10cSrcweir                             // vs. multi-level transparency)
476*cdf0e10cSrcweir                             if( rBitmap.IsTransparent() )
477*cdf0e10cSrcweir                             {
478*cdf0e10cSrcweir                                 // Handling alpha and mask just the same...
479*cdf0e10cSrcweir                                 for( int x=0; x<aDestBmpSize.Width(); ++x )
480*cdf0e10cSrcweir                                 {
481*cdf0e10cSrcweir                                     ::basegfx::B2DPoint aPoint(x,y);
482*cdf0e10cSrcweir                                     aPoint *= aTransform;
483*cdf0e10cSrcweir 
484*cdf0e10cSrcweir                                     const int nSrcX( ::basegfx::fround( aPoint.getX() ) );
485*cdf0e10cSrcweir                                     const int nSrcY( ::basegfx::fround( aPoint.getY() ) );
486*cdf0e10cSrcweir                                     if( nSrcX < 0 || nSrcX >= aBmpSize.Width() ||
487*cdf0e10cSrcweir                                         nSrcY < 0 || nSrcY >= aBmpSize.Height() )
488*cdf0e10cSrcweir                                     {
489*cdf0e10cSrcweir                                         pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) );
490*cdf0e10cSrcweir                                     }
491*cdf0e10cSrcweir                                     else
492*cdf0e10cSrcweir                                     {
493*cdf0e10cSrcweir                                         pAlphaWriteAccess->SetPixel( y, x,
494*cdf0e10cSrcweir                                                                      aAlphaMap[
495*cdf0e10cSrcweir                                                                          pAlphaReadAccess->GetPixel( nSrcY,
496*cdf0e10cSrcweir                                                                                                      nSrcX ) ] );
497*cdf0e10cSrcweir 
498*cdf0e10cSrcweir                                         pWriteAccess->SetPixel( y, x, pReadAccess->GetPixel( nSrcY,
499*cdf0e10cSrcweir                                                                                              nSrcX ) );
500*cdf0e10cSrcweir                                     }
501*cdf0e10cSrcweir                                 }
502*cdf0e10cSrcweir                             }
503*cdf0e10cSrcweir                             else
504*cdf0e10cSrcweir                             {
505*cdf0e10cSrcweir                                 for( int x=0; x<aDestBmpSize.Width(); ++x )
506*cdf0e10cSrcweir                                 {
507*cdf0e10cSrcweir                                     ::basegfx::B2DPoint aPoint(x,y);
508*cdf0e10cSrcweir                                     aPoint *= aTransform;
509*cdf0e10cSrcweir 
510*cdf0e10cSrcweir                                     const int nSrcX( ::basegfx::fround( aPoint.getX() ) );
511*cdf0e10cSrcweir                                     const int nSrcY( ::basegfx::fround( aPoint.getY() ) );
512*cdf0e10cSrcweir                                     if( nSrcX < 0 || nSrcX >= aBmpSize.Width() ||
513*cdf0e10cSrcweir                                         nSrcY < 0 || nSrcY >= aBmpSize.Height() )
514*cdf0e10cSrcweir                                     {
515*cdf0e10cSrcweir                                         pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) );
516*cdf0e10cSrcweir                                     }
517*cdf0e10cSrcweir                                     else
518*cdf0e10cSrcweir                                     {
519*cdf0e10cSrcweir                                         pAlphaWriteAccess->SetPixel( y, x, BitmapColor(0) );
520*cdf0e10cSrcweir                                         pWriteAccess->SetPixel( y, x, pReadAccess->GetPixel( nSrcY,
521*cdf0e10cSrcweir                                                                                              nSrcX ) );
522*cdf0e10cSrcweir                                     }
523*cdf0e10cSrcweir                                 }
524*cdf0e10cSrcweir                             }
525*cdf0e10cSrcweir                         }
526*cdf0e10cSrcweir                     }
527*cdf0e10cSrcweir 
528*cdf0e10cSrcweir                     bCopyBack = true;
529*cdf0e10cSrcweir                 }
530*cdf0e10cSrcweir                 else
531*cdf0e10cSrcweir                 {
532*cdf0e10cSrcweir                     // TODO(E2): Error handling!
533*cdf0e10cSrcweir                     ENSURE_OR_THROW( false,
534*cdf0e10cSrcweir                                       "transformBitmap(): could not access bitmap" );
535*cdf0e10cSrcweir                 }
536*cdf0e10cSrcweir             }
537*cdf0e10cSrcweir 
538*cdf0e10cSrcweir             if( bCopyBack )
539*cdf0e10cSrcweir                 return BitmapEx( aDstBitmap, AlphaMask( aDstAlpha ) );
540*cdf0e10cSrcweir             else
541*cdf0e10cSrcweir                 return BitmapEx();
542*cdf0e10cSrcweir         }
543*cdf0e10cSrcweir     }
544*cdf0e10cSrcweir }
545