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