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