1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <canvas/debug.hxx>
22 #include <tools/diagnose_ex.h>
24 #include <rtl/math.hxx>
26 #include <com/sun/star/geometry/RealSize2D.hpp>
27 #include <com/sun/star/geometry/RealPoint2D.hpp>
28 #include <com/sun/star/geometry/RealRectangle2D.hpp>
29 #include <com/sun/star/rendering/RenderState.hpp>
30 #include <com/sun/star/rendering/XCanvas.hpp>
31 #include <com/sun/star/rendering/XBitmap.hpp>
32 #include <com/sun/star/rendering/XPolyPolygon2D.hpp>
33 #include <com/sun/star/geometry/RealBezierSegment2D.hpp>
34 #include <com/sun/star/rendering/XIntegerBitmap.hpp>
36 #include <vcl/salbtype.hxx>
37 #include <vcl/bmpacc.hxx>
38 #include <vcl/bitmapex.hxx>
39 #include <vcl/metric.hxx>
40 #include <vcl/canvastools.hxx>
42 #include <basegfx/point/b2dpoint.hxx>
43 #include <basegfx/tuple/b2dtuple.hxx>
44 #include <basegfx/polygon/b2dpolygontools.hxx>
45 #include <basegfx/range/b2drectangle.hxx>
46 #include <basegfx/matrix/b2dhommatrix.hxx>
47 #include <basegfx/tools/canvastools.hxx>
48 #include <basegfx/numeric/ftools.hxx>
50 #include <canvas/canvastools.hxx>
52 #include "impltools.hxx"
53 #include "canvasbitmap.hxx"
58 using namespace ::com::sun::star
;
64 ::BitmapEx
bitmapExFromXBitmap( const uno::Reference
< rendering::XBitmap
>& xBitmap
)
66 // TODO(F3): CanvasCustomSprite should also be tunnelled
67 // through (also implements XIntegerBitmap interface)
68 CanvasBitmap
* pBitmapImpl
= dynamic_cast< CanvasBitmap
* >( xBitmap
.get() );
72 return pBitmapImpl
->getBitmap();
76 SpriteCanvas
* pCanvasImpl
= dynamic_cast< SpriteCanvas
* >( xBitmap
.get() );
77 if( pCanvasImpl
&& pCanvasImpl
->getBackBuffer() )
79 // TODO(F3): mind the plain Canvas impl. Consolidate with CWS canvas05
80 const ::OutputDevice
& rDev( pCanvasImpl
->getBackBuffer()->getOutDev() );
81 const ::Point aEmptyPoint
;
82 return rDev
.GetBitmapEx( aEmptyPoint
,
83 rDev
.GetOutputSizePixel() );
86 // TODO(F2): add support for floating point bitmap formats
87 uno::Reference
< rendering::XIntegerReadOnlyBitmap
> xIntBmp(
88 xBitmap
, uno::UNO_QUERY_THROW
);
90 ::BitmapEx aBmpEx
= vcl::unotools::bitmapExFromXBitmap( xIntBmp
);
94 // TODO(F1): extract pixel from XBitmap interface
95 ENSURE_OR_THROW( false,
96 "bitmapExFromXBitmap(): could not extract bitmap" );
102 bool setupFontTransform( ::Point
& o_rPoint
,
103 vcl::Font
& io_rVCLFont
,
104 const rendering::ViewState
& rViewState
,
105 const rendering::RenderState
& rRenderState
,
106 ::OutputDevice
& rOutDev
)
108 ::basegfx::B2DHomMatrix aMatrix
;
110 ::canvas::tools::mergeViewAndRenderTransform(aMatrix
,
114 ::basegfx::B2DTuple aScale
;
115 ::basegfx::B2DTuple aTranslate
;
116 double nRotate
, nShearX
;
118 aMatrix
.decompose( aScale
, aTranslate
, nRotate
, nShearX
);
120 // query font metric _before_ tampering with width and height
121 if( !::rtl::math::approxEqual(aScale
.getX(), aScale
.getY()) )
123 // retrieve true font width
124 const sal_Int32
nFontWidth( rOutDev
.GetFontMetric( io_rVCLFont
).GetWidth() );
126 const sal_Int32
nScaledFontWidth( ::basegfx::fround(nFontWidth
* aScale
.getX()) );
128 if( !nScaledFontWidth
)
130 // scale is smaller than one pixel - disable text
135 io_rVCLFont
.SetWidth( nScaledFontWidth
);
138 if( !::rtl::math::approxEqual(aScale
.getY(), 1.0) )
140 const sal_Int32
nFontHeight( io_rVCLFont
.GetHeight() );
141 io_rVCLFont
.SetHeight( ::basegfx::fround(nFontHeight
* aScale
.getY()) );
144 io_rVCLFont
.SetOrientation( static_cast< short >( ::basegfx::fround(-fmod(nRotate
, 2*M_PI
)*(1800.0/M_PI
)) ) );
146 // TODO(F2): Missing functionality in VCL: shearing
147 o_rPoint
.X() = ::basegfx::fround(aTranslate
.getX());
148 o_rPoint
.Y() = ::basegfx::fround(aTranslate
.getY());
153 bool isRectangle( const ::tools::PolyPolygon
& rPolyPoly
)
155 // exclude some cheap cases first
156 if( rPolyPoly
.Count() != 1 )
159 const ::Polygon
& rPoly( rPolyPoly
[0] );
161 sal_uInt16
nCount( rPoly
.GetSize() );
165 // delegate to basegfx
166 return ::basegfx::tools::isRectangle( rPoly
.getB2DPolygon() );
170 // VCL-Canvas related
173 ::Point
mapRealPoint2D( const geometry::RealPoint2D
& rPoint
,
174 const rendering::ViewState
& rViewState
,
175 const rendering::RenderState
& rRenderState
)
177 ::basegfx::B2DPoint
aPoint( ::basegfx::unotools::b2DPointFromRealPoint2D(rPoint
) );
179 ::basegfx::B2DHomMatrix aMatrix
;
180 aPoint
*= ::canvas::tools::mergeViewAndRenderTransform(aMatrix
,
184 return vcl::unotools::pointFromB2DPoint( aPoint
);
187 ::tools::PolyPolygon
mapPolyPolygon( const ::basegfx::B2DPolyPolygon
& rPoly
,
188 const rendering::ViewState
& rViewState
,
189 const rendering::RenderState
& rRenderState
)
191 ::basegfx::B2DHomMatrix aMatrix
;
192 ::canvas::tools::mergeViewAndRenderTransform(aMatrix
,
196 ::basegfx::B2DPolyPolygon
aTemp( rPoly
);
198 aTemp
.transform( aMatrix
);
200 return ::tools::PolyPolygon( aTemp
);
203 ::BitmapEx
transformBitmap( const BitmapEx
& rBitmap
,
204 const ::basegfx::B2DHomMatrix
& rTransform
,
205 const uno::Sequence
< double >& rDeviceColor
,
206 ModulationMode eModulationMode
)
208 SAL_INFO( "canvas.vcl", "::vclcanvas::tools::transformBitmap()" );
209 SAL_INFO( "canvas.vcl", "::vclcanvas::tools::transformBitmap: 0x" << std::hex
<< &rBitmap
);
211 // calc transformation and size of bitmap to be
212 // generated. Note, that the translational components are
213 // deleted from the transformation; this can be handled by
214 // an offset when painting the bitmap
215 const Size
aBmpSize( rBitmap
.GetSizePixel() );
216 ::basegfx::B2DRectangle aDestRect
;
218 bool bCopyBack( false );
220 // calc effective transformation for bitmap
221 const ::basegfx::B2DRectangle
aSrcRect( 0, 0,
224 ::canvas::tools::calcTransformedRectBounds( aDestRect
,
228 // re-center bitmap, such that it's left, top border is
229 // aligned with (0,0). The method takes the given
230 // rectangle, and calculates a transformation that maps
231 // this rectangle unscaled to the origin.
232 ::basegfx::B2DHomMatrix aLocalTransform
;
233 ::canvas::tools::calcRectToOriginTransform( aLocalTransform
,
237 const bool bModulateColors( eModulationMode
== MODULATE_WITH_DEVICECOLOR
&&
238 rDeviceColor
.getLength() > 2 );
239 const double nRedModulation( bModulateColors
? rDeviceColor
[0] : 1.0 );
240 const double nGreenModulation( bModulateColors
? rDeviceColor
[1] : 1.0 );
241 const double nBlueModulation( bModulateColors
? rDeviceColor
[2] : 1.0 );
242 const double nAlphaModulation( bModulateColors
&& rDeviceColor
.getLength() > 3 ?
243 rDeviceColor
[3] : 1.0 );
245 Bitmap
aSrcBitmap( rBitmap
.GetBitmap() );
248 // differentiate mask and alpha channel (on-off
249 // vs. multi-level transparency)
250 if( rBitmap
.IsTransparent() )
252 if( rBitmap
.IsAlpha() )
253 aSrcAlpha
= rBitmap
.GetAlpha().GetBitmap();
255 aSrcAlpha
= rBitmap
.GetMask();
258 Bitmap::ScopedReadAccess
pReadAccess( aSrcBitmap
);
259 Bitmap::ScopedReadAccess
pAlphaReadAccess( rBitmap
.IsTransparent() ?
260 aSrcAlpha
.AcquireReadAccess() :
261 (BitmapReadAccess
*)NULL
,
264 if( pReadAccess
.get() == NULL
||
265 (pAlphaReadAccess
.get() == NULL
&& rBitmap
.IsTransparent()) )
267 // TODO(E2): Error handling!
268 ENSURE_OR_THROW( false,
269 "transformBitmap(): could not access source bitmap" );
272 // mapping table, to translate pAlphaReadAccess' pixel
273 // values into destination alpha values (needed e.g. for
274 // paletted 1-bit masks).
275 sal_uInt8 aAlphaMap
[256];
277 if( rBitmap
.IsTransparent() )
279 if( rBitmap
.IsAlpha() )
281 // source already has alpha channel - 1:1 mapping,
282 // i.e. aAlphaMap[0]=0,...,aAlphaMap[255]=255.
284 sal_uInt8
* pCur
=aAlphaMap
;
285 sal_uInt8
* const pEnd
=&aAlphaMap
[256];
291 // mask transparency - determine used palette colors
292 const BitmapColor
& rCol0( pAlphaReadAccess
->GetPaletteColor( 0 ) );
293 const BitmapColor
& rCol1( pAlphaReadAccess
->GetPaletteColor( 1 ) );
295 // shortcut for true luminance calculation
296 // (assumes that palette is grey-level)
297 aAlphaMap
[0] = rCol0
.GetRed();
298 aAlphaMap
[1] = rCol1
.GetRed();
301 // else: mapping table is not used
303 const Size
aDestBmpSize( ::basegfx::fround( aDestRect
.getWidth() ),
304 ::basegfx::fround( aDestRect
.getHeight() ) );
306 if( aDestBmpSize
.Width() == 0 || aDestBmpSize
.Height() == 0 )
309 Bitmap
aDstBitmap( aDestBmpSize
, aSrcBitmap
.GetBitCount(), &pReadAccess
->GetPalette() );
310 Bitmap
aDstAlpha( AlphaMask( aDestBmpSize
).GetBitmap() );
313 // just to be on the safe side: let the
314 // ScopedAccessors get destructed before
315 // copy-constructing the resulting bitmap. This will
316 // rule out the possibility that cached accessor data
317 // is not yet written back.
318 Bitmap::ScopedWriteAccess
pWriteAccess( aDstBitmap
);
319 Bitmap::ScopedWriteAccess
pAlphaWriteAccess( aDstAlpha
);
322 if( pWriteAccess
.get() != NULL
&&
323 pAlphaWriteAccess
.get() != NULL
&&
324 rTransform
.isInvertible() )
326 // we're doing inverse mapping here, i.e. mapping
327 // points from the destination bitmap back to the
329 ::basegfx::B2DHomMatrix
aTransform( aLocalTransform
);
332 // for the time being, always read as ARGB
333 for( int y
=0; y
<aDestBmpSize
.Height(); ++y
)
335 if( bModulateColors
)
337 // TODO(P2): Have different branches for
338 // alpha-only modulation (color
339 // modulations eq. 1.0)
341 // modulate all color channels with given
344 // differentiate mask and alpha channel (on-off
345 // vs. multi-level transparency)
346 if( rBitmap
.IsTransparent() )
348 // Handling alpha and mask just the same...
349 for( int x
=0; x
<aDestBmpSize
.Width(); ++x
)
351 ::basegfx::B2DPoint
aPoint(x
,y
);
352 aPoint
*= aTransform
;
354 const int nSrcX( ::basegfx::fround( aPoint
.getX() ) );
355 const int nSrcY( ::basegfx::fround( aPoint
.getY() ) );
356 if( nSrcX
< 0 || nSrcX
>= aBmpSize
.Width() ||
357 nSrcY
< 0 || nSrcY
>= aBmpSize
.Height() )
359 pAlphaWriteAccess
->SetPixel( y
, x
, BitmapColor(255) );
363 // modulate alpha with
364 // nAlphaModulation. This is a
365 // little bit verbose, formula
366 // is 255 - (255-pixAlpha)*nAlphaModulation
367 // (invert 'alpha' pixel value,
368 // to get the standard alpha
369 // channel behaviour)
370 const sal_uInt8 cMappedAlphaIdx
= aAlphaMap
[ pAlphaReadAccess
->GetPixelIndex( nSrcY
, nSrcX
) ];
371 const sal_uInt8 cModulatedAlphaIdx
= 255U - static_cast<sal_uInt8
>( nAlphaModulation
* (255U - cMappedAlphaIdx
) + .5 );
372 pAlphaWriteAccess
->SetPixelIndex( y
, x
, cModulatedAlphaIdx
);
373 BitmapColor
aColor( pReadAccess
->GetPixel( nSrcY
, nSrcX
) );
376 static_cast<sal_uInt8
>(
378 aColor
.GetRed() + .5 ));
380 static_cast<sal_uInt8
>(
382 aColor
.GetGreen() + .5 ));
384 static_cast<sal_uInt8
>(
386 aColor
.GetBlue() + .5 ));
388 pWriteAccess
->SetPixel( y
, x
,
395 for( int x
=0; x
<aDestBmpSize
.Width(); ++x
)
397 ::basegfx::B2DPoint
aPoint(x
,y
);
398 aPoint
*= aTransform
;
400 const int nSrcX( ::basegfx::fround( aPoint
.getX() ) );
401 const int nSrcY( ::basegfx::fround( aPoint
.getY() ) );
402 if( nSrcX
< 0 || nSrcX
>= aBmpSize
.Width() ||
403 nSrcY
< 0 || nSrcY
>= aBmpSize
.Height() )
405 pAlphaWriteAccess
->SetPixel( y
, x
, BitmapColor(255) );
409 // modulate alpha with
410 // nAlphaModulation. This is a
411 // little bit verbose, formula
412 // is 255 - 255*nAlphaModulation
413 // (invert 'alpha' pixel value,
414 // to get the standard alpha
415 // channel behaviour)
416 pAlphaWriteAccess
->SetPixel( y
, x
,
419 static_cast<sal_uInt8
>(
420 nAlphaModulation
*255.0
423 BitmapColor
aColor( pReadAccess
->GetPixel( nSrcY
,
427 static_cast<sal_uInt8
>(
429 aColor
.GetRed() + .5 ));
431 static_cast<sal_uInt8
>(
433 aColor
.GetGreen() + .5 ));
435 static_cast<sal_uInt8
>(
437 aColor
.GetBlue() + .5 ));
439 pWriteAccess
->SetPixel( y
, x
,
447 // differentiate mask and alpha channel (on-off
448 // vs. multi-level transparency)
449 if( rBitmap
.IsTransparent() )
451 // Handling alpha and mask just the same...
452 for( int x
=0; x
<aDestBmpSize
.Width(); ++x
)
454 ::basegfx::B2DPoint
aPoint(x
,y
);
455 aPoint
*= aTransform
;
457 const int nSrcX( ::basegfx::fround( aPoint
.getX() ) );
458 const int nSrcY( ::basegfx::fround( aPoint
.getY() ) );
459 if( nSrcX
< 0 || nSrcX
>= aBmpSize
.Width() ||
460 nSrcY
< 0 || nSrcY
>= aBmpSize
.Height() )
462 pAlphaWriteAccess
->SetPixelIndex( y
, x
, 255 );
466 const sal_uInt8 cAlphaIdx
= pAlphaReadAccess
->GetPixelIndex( nSrcY
, nSrcX
);
467 pAlphaWriteAccess
->SetPixelIndex( y
, x
, aAlphaMap
[ cAlphaIdx
] );
468 pWriteAccess
->SetPixel( y
, x
, pReadAccess
->GetPixel( nSrcY
, nSrcX
) );
474 for( int x
=0; x
<aDestBmpSize
.Width(); ++x
)
476 ::basegfx::B2DPoint
aPoint(x
,y
);
477 aPoint
*= aTransform
;
479 const int nSrcX( ::basegfx::fround( aPoint
.getX() ) );
480 const int nSrcY( ::basegfx::fround( aPoint
.getY() ) );
481 if( nSrcX
< 0 || nSrcX
>= aBmpSize
.Width() ||
482 nSrcY
< 0 || nSrcY
>= aBmpSize
.Height() )
484 pAlphaWriteAccess
->SetPixel( y
, x
, BitmapColor(255) );
488 pAlphaWriteAccess
->SetPixel( y
, x
, BitmapColor(0) );
489 pWriteAccess
->SetPixel( y
, x
, pReadAccess
->GetPixel( nSrcY
,
501 // TODO(E2): Error handling!
502 ENSURE_OR_THROW( false,
503 "transformBitmap(): could not access bitmap" );
508 return BitmapEx( aDstBitmap
, AlphaMask( aDstAlpha
) );
515 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */