update dev300-m58
[ooovba.git] / cppcanvas / source / mtfrenderer / transparencygroupaction.cxx
blob76b2a6d03ad5d9b7c77efee4f909884c224efb2f
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: transparencygroupaction.cxx,v $
10 * $Revision: 1.12 $
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_cppcanvas.hxx"
34 #include <tools/gen.hxx>
36 #include <canvas/debug.hxx>
37 #include <canvas/verbosetrace.hxx>
38 #include <canvas/canvastools.hxx>
40 #include <rtl/logfile.hxx>
42 #include <com/sun/star/rendering/XBitmap.hpp>
43 #include <com/sun/star/rendering/XCanvas.hpp>
45 #include <rtl/math.hxx>
47 #include <vcl/metaact.hxx>
48 #include <vcl/bitmapex.hxx>
49 #include <vcl/canvastools.hxx>
50 #include <vcl/svapp.hxx>
51 #include <vcl/outdev.hxx>
52 #include <vcl/virdev.hxx>
53 #include <vcl/virdev.hxx>
54 #include <vcl/gdimtf.hxx>
55 #include <vcl/gradient.hxx>
57 #include <canvas/canvastools.hxx>
59 #include <basegfx/range/b2drange.hxx>
60 #include <basegfx/point/b2dpoint.hxx>
61 #include <basegfx/vector/b2dsize.hxx>
62 #include <basegfx/numeric/ftools.hxx>
63 #include <basegfx/matrix/b2dhommatrix.hxx>
64 #include <basegfx/tuple/b2dtuple.hxx>
65 #include <basegfx/tools/canvastools.hxx>
67 #include <boost/utility.hpp>
69 #include "transparencygroupaction.hxx"
70 #include "outdevstate.hxx"
71 #include "mtftools.hxx"
72 #include "cppcanvas/vclfactory.hxx"
75 using namespace ::com::sun::star;
77 namespace cppcanvas
79 namespace internal
81 // free support functions
82 // ======================
83 namespace
85 class TransparencyGroupAction : public Action, private ::boost::noncopyable
87 public:
88 /** Create new transparency group action.
90 @param rGroupMtf
91 Metafile that groups all actions to be rendered
92 transparent
94 @param rParms
95 Render parameters
97 @param rDstPoint
98 Left, top edge of destination, in current state
99 coordinate system
101 @param rDstSize
102 Size of the transparency group object, in current
103 state coordinate system.
105 @param nAlpha
106 Alpha value, must be in the range [0,1]
108 TransparencyGroupAction( MtfAutoPtr& rGroupMtf,
109 const Renderer::Parameters& rParms,
110 const ::basegfx::B2DPoint& rDstPoint,
111 const ::basegfx::B2DVector& rDstSize,
112 double nAlpha,
113 const CanvasSharedPtr& rCanvas,
114 const OutDevState& rState );
116 /** Create new transparency group action.
118 @param rGroupMtf
119 Metafile that groups all actions to be rendered
120 transparent.
122 @param rAlphaGradient
123 VCL gradient, to be rendered into the action's alpha
124 channel.
126 @param rParms
127 Render parameters
129 @param rDstPoint
130 Left, top edge of destination, in current state
131 coordinate system
133 @param rDstSize
134 Size of the transparency group object, in current
135 state coordinate system.
137 TransparencyGroupAction( MtfAutoPtr& rGroupMtf,
138 GradientAutoPtr& rAlphaGradient,
139 const Renderer::Parameters& rParms,
140 const ::basegfx::B2DPoint& rDstPoint,
141 const ::basegfx::B2DVector& rDstSize,
142 const CanvasSharedPtr& rCanvas,
143 const OutDevState& rState );
145 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
146 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation,
147 const Subset& rSubset ) const;
149 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
150 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
151 const Subset& rSubset ) const;
153 virtual sal_Int32 getActionCount() const;
155 private:
156 MtfAutoPtr mpGroupMtf;
157 GradientAutoPtr mpAlphaGradient;
159 const Renderer::Parameters maParms;
161 const ::basegfx::B2DSize maDstSize;
163 mutable uno::Reference< rendering::XBitmap > mxBufferBitmap; // contains last rendered version
164 mutable ::basegfx::B2DHomMatrix maLastTransformation; // contains last active transformation
165 mutable Subset maLastSubset; // contains last effective subset
167 // transformation for
168 // mxBufferBitmap content
169 CanvasSharedPtr mpCanvas;
170 rendering::RenderState maState;
171 const double mnAlpha;
175 /** Setup transformation such that the next render call is
176 moved rPoint away, and scaled according to the ratio
177 given by src and dst size.
179 void implSetupTransform( rendering::RenderState& rRenderState,
180 const ::basegfx::B2DPoint& rDstPoint )
182 ::basegfx::B2DHomMatrix aLocalTransformation;
184 aLocalTransformation.translate( rDstPoint.getX(),
185 rDstPoint.getY() );
186 ::canvas::tools::appendToRenderState( rRenderState,
187 aLocalTransformation );
190 TransparencyGroupAction::TransparencyGroupAction( MtfAutoPtr& rGroupMtf,
191 const Renderer::Parameters& rParms,
192 const ::basegfx::B2DPoint& rDstPoint,
193 const ::basegfx::B2DVector& rDstSize,
194 double nAlpha,
195 const CanvasSharedPtr& rCanvas,
196 const OutDevState& rState ) :
197 mpGroupMtf( rGroupMtf ),
198 mpAlphaGradient(),
199 maParms( rParms ),
200 maDstSize( rDstSize ),
201 mxBufferBitmap(),
202 maLastTransformation(),
203 mpCanvas( rCanvas ),
204 maState(),
205 mnAlpha( nAlpha )
207 tools::initRenderState(maState,rState);
208 implSetupTransform( maState, rDstPoint );
210 // correct clip (which is relative to original transform)
211 tools::modifyClip( maState,
212 rState,
213 rCanvas,
214 rDstPoint,
215 NULL,
216 NULL );
218 maLastSubset.mnSubsetBegin = 0;
219 maLastSubset.mnSubsetEnd = -1;
222 TransparencyGroupAction::TransparencyGroupAction( MtfAutoPtr& rGroupMtf,
223 GradientAutoPtr& rAlphaGradient,
224 const Renderer::Parameters& rParms,
225 const ::basegfx::B2DPoint& rDstPoint,
226 const ::basegfx::B2DVector& rDstSize,
227 const CanvasSharedPtr& rCanvas,
228 const OutDevState& rState ) :
229 mpGroupMtf( rGroupMtf ),
230 mpAlphaGradient( rAlphaGradient ),
231 maParms( rParms ),
232 maDstSize( rDstSize ),
233 mxBufferBitmap(),
234 maLastTransformation(),
235 mpCanvas( rCanvas ),
236 maState(),
237 mnAlpha( 1.0 )
239 tools::initRenderState(maState,rState);
240 implSetupTransform( maState, rDstPoint );
242 // correct clip (which is relative to original transform)
243 tools::modifyClip( maState,
244 rState,
245 rCanvas,
246 rDstPoint,
247 NULL,
248 NULL );
250 maLastSubset.mnSubsetBegin = 0;
251 maLastSubset.mnSubsetEnd = -1;
254 // TODO(P3): The whole float transparency handling is a mess,
255 // this should be refactored. What's more, the old idea of
256 // having only internal 'metaactions', and not the original
257 // GDIMetaFile now looks a lot less attractive. Try to move
258 // into the direction of having a direct GDIMetaFile2XCanvas
259 // renderer, and maybe a separate metafile XCanvas
260 // implementation.
261 bool TransparencyGroupAction::render( const ::basegfx::B2DHomMatrix& rTransformation,
262 const Subset& rSubset ) const
264 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TransparencyGroupAction::render()" );
265 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TransparencyGroupAction: 0x%X", this );
267 // determine overall transformation matrix (render, view,
268 // and passed transformation)
269 ::basegfx::B2DHomMatrix aTransform;
270 ::canvas::tools::getRenderStateTransform( aTransform, maState );
271 aTransform = rTransformation * aTransform;
273 ::basegfx::B2DHomMatrix aTotalTransform;
274 ::canvas::tools::getViewStateTransform( aTotalTransform, mpCanvas->getViewState() );
275 aTotalTransform = aTotalTransform * aTransform;
277 // since pure translational changes to the transformation
278 // does not matter, remove them before comparing
279 aTotalTransform.set( 0, 2, 0.0 );
280 aTotalTransform.set( 1, 2, 0.0 );
282 // if there's no buffer bitmap, or as soon as the
283 // total transformation changes, we've got to
284 // re-render the bitmap
285 if( !mxBufferBitmap.is() ||
286 aTotalTransform != maLastTransformation ||
287 rSubset.mnSubsetBegin != maLastSubset.mnSubsetBegin ||
288 rSubset.mnSubsetEnd != maLastSubset.mnSubsetEnd )
290 DBG_TESTSOLARMUTEX();
292 // determine total scaling factor of the
293 // transformation matrix - need to make the bitmap
294 // large enough
295 ::basegfx::B2DTuple aScale;
296 ::basegfx::B2DTuple aTranslate;
297 double nRotate;
298 double nShearX;
299 if( !aTotalTransform.decompose( aScale,
300 aTranslate,
301 nRotate,
302 nShearX ) )
304 OSL_ENSURE( false,
305 "TransparencyGroupAction::render(): non-decomposable transformation" );
306 return false;
309 // output size of metafile
310 ::Size aOutputSizePixel( ::basegfx::fround( aScale.getX() * maDstSize.getX() ),
311 ::basegfx::fround( aScale.getY() * maDstSize.getY() ) );
313 // pixel size of cache bitmap: round up to nearest int
314 ::Size aBitmapSizePixel( static_cast<sal_Int32>( aScale.getX() * maDstSize.getX() )+1,
315 static_cast<sal_Int32>( aScale.getY() * maDstSize.getY() )+1 );
317 ::Point aEmptyPoint;
319 // render our content into an appropriately sized
320 // VirtualDevice with alpha channel
321 VirtualDevice aVDev(
322 *::Application::GetDefaultDevice(), 0, 0 );
323 aVDev.SetOutputSizePixel( aBitmapSizePixel );
324 aVDev.SetMapMode();
326 if( rSubset.mnSubsetBegin != 0 ||
327 rSubset.mnSubsetEnd != -1 )
329 // true subset - extract referenced
330 // metaactions from mpGroupMtf
331 GDIMetaFile aMtf;
332 MetaAction* pCurrAct;
333 int nCurrActionIndex;
335 // extract subset actions
336 for( nCurrActionIndex=0,
337 pCurrAct=mpGroupMtf->FirstAction();
338 pCurrAct;
339 ++nCurrActionIndex, pCurrAct = mpGroupMtf->NextAction() )
341 switch( pCurrAct->GetType() )
343 case META_PUSH_ACTION:
344 case META_POP_ACTION:
345 case META_CLIPREGION_ACTION:
346 case META_ISECTRECTCLIPREGION_ACTION:
347 case META_ISECTREGIONCLIPREGION_ACTION:
348 case META_MOVECLIPREGION_ACTION:
349 case META_LINECOLOR_ACTION:
350 case META_FILLCOLOR_ACTION:
351 case META_TEXTCOLOR_ACTION:
352 case META_TEXTFILLCOLOR_ACTION:
353 case META_TEXTLINECOLOR_ACTION:
354 case META_TEXTALIGN_ACTION:
355 case META_FONT_ACTION:
356 case META_RASTEROP_ACTION:
357 case META_REFPOINT_ACTION:
358 case META_LAYOUTMODE_ACTION:
359 // state-changing action - copy as-is
360 aMtf.AddAction( pCurrAct->Clone() );
361 break;
363 case META_GRADIENT_ACTION:
364 case META_HATCH_ACTION:
365 case META_EPS_ACTION:
366 case META_COMMENT_ACTION:
367 case META_POINT_ACTION:
368 case META_PIXEL_ACTION:
369 case META_LINE_ACTION:
370 case META_RECT_ACTION:
371 case META_ROUNDRECT_ACTION:
372 case META_ELLIPSE_ACTION:
373 case META_ARC_ACTION:
374 case META_PIE_ACTION:
375 case META_CHORD_ACTION:
376 case META_POLYLINE_ACTION:
377 case META_POLYGON_ACTION:
378 case META_POLYPOLYGON_ACTION:
379 case META_BMP_ACTION:
380 case META_BMPSCALE_ACTION:
381 case META_BMPSCALEPART_ACTION:
382 case META_BMPEX_ACTION:
383 case META_BMPEXSCALE_ACTION:
384 case META_BMPEXSCALEPART_ACTION:
385 case META_MASK_ACTION:
386 case META_MASKSCALE_ACTION:
387 case META_MASKSCALEPART_ACTION:
388 case META_GRADIENTEX_ACTION:
389 case META_WALLPAPER_ACTION:
390 case META_TRANSPARENT_ACTION:
391 case META_FLOATTRANSPARENT_ACTION:
392 case META_TEXT_ACTION:
393 case META_TEXTARRAY_ACTION:
394 case META_TEXTLINE_ACTION:
395 case META_TEXTRECT_ACTION:
396 case META_STRETCHTEXT_ACTION:
397 // output-generating action - only
398 // copy, if we're within the
399 // requested subset
400 if( rSubset.mnSubsetBegin <= nCurrActionIndex &&
401 rSubset.mnSubsetEnd > nCurrActionIndex )
403 aMtf.AddAction( pCurrAct->Clone() );
405 break;
407 default:
408 OSL_ENSURE( false,
409 "Unknown meta action type encountered" );
410 break;
414 aVDev.DrawTransparent( aMtf,
415 aEmptyPoint,
416 aOutputSizePixel,
417 *mpAlphaGradient );
419 else
421 // no subsetting - render whole mtf
422 aVDev.DrawTransparent( *mpGroupMtf,
423 aEmptyPoint,
424 aOutputSizePixel,
425 *mpAlphaGradient );
429 // update buffered bitmap and transformation
430 BitmapSharedPtr aBmp( VCLFactory::getInstance().createBitmap(
431 mpCanvas,
432 aVDev.GetBitmapEx(
433 aEmptyPoint,
434 aBitmapSizePixel ) ) );
435 mxBufferBitmap = aBmp->getUNOBitmap();
436 maLastTransformation = aTotalTransform;
437 maLastSubset = rSubset;
440 // determine target transformation (we can't simply pass
441 // aTotalTransform as assembled above, since we must take
442 // the canvas' view state as is, it might contain clipping
443 // (which, in turn, is relative to the view
444 // transformation))
446 // given that aTotalTransform is the identity
447 // transformation, we could simply render our bitmap
448 // as-is. Now, since the mxBufferBitmap content already
449 // accounts for scale changes in the overall
450 // transformation, we must factor this out
451 // before. Generally, the transformation matrix should be
452 // structured like this:
453 // Translation*Rotation*Shear*Scale. Thus, to neutralize
454 // the contained scaling, we've got to right-multiply with
455 // the inverse.
456 ::basegfx::B2ISize aBmpSize(
457 ::basegfx::unotools::b2ISizeFromIntegerSize2D( mxBufferBitmap->getSize() ) );
459 ::basegfx::B2DHomMatrix aScaleCorrection;
460 aScaleCorrection.scale( (double)maDstSize.getX() / aBmpSize.getX(),
461 (double)maDstSize.getY() / aBmpSize.getY() );
462 aTransform = aTransform * aScaleCorrection;
464 rendering::RenderState aLocalState( maState );
465 ::canvas::tools::setRenderStateTransform(aLocalState, aTransform);
467 #ifdef SPECIAL_DEBUG
468 aLocalState.Clip.clear();
469 aLocalState.DeviceColor =
470 ::vcl::unotools::colorToDoubleSequence(
471 ::Color( 0x80FF0000 ),
472 mpCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
474 if( maState.Clip.is() )
475 mpCanvas->getUNOCanvas()->fillPolyPolygon( maState.Clip,
476 mpCanvas->getViewState(),
477 aLocalState );
479 aLocalState.DeviceColor = maState.DeviceColor;
480 #endif
482 if( ::rtl::math::approxEqual(mnAlpha, 1.0) )
484 // no further alpha changes necessary -> draw directly
485 mpCanvas->getUNOCanvas()->drawBitmap( mxBufferBitmap,
486 mpCanvas->getViewState(),
487 aLocalState );
489 else
491 // add alpha modulation value to DeviceColor
492 uno::Sequence<rendering::ARGBColor> aCols(1);
493 aCols[0] = rendering::ARGBColor( mnAlpha, 1.0, 1.0, 1.0);
494 aLocalState.DeviceColor =
495 mpCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace()->convertFromARGB(
496 aCols);
498 mpCanvas->getUNOCanvas()->drawBitmapModulated( mxBufferBitmap,
499 mpCanvas->getViewState(),
500 aLocalState );
503 return true;
506 // TODO(P3): The whole float transparency handling is a mess,
507 // this should be refactored. What's more, the old idea of
508 // having only internal 'metaactions', and not the original
509 // GDIMetaFile now looks a lot less attractive. Try to move
510 // into the direction of having a direct GDIMetaFile2XCanvas
511 // renderer, and maybe a separate metafile XCanvas
512 // implementation.
513 bool TransparencyGroupAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
515 Subset aSubset;
517 aSubset.mnSubsetBegin = 0;
518 aSubset.mnSubsetEnd = -1;
520 return render( rTransformation, aSubset );
523 ::basegfx::B2DRange TransparencyGroupAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
525 rendering::RenderState aLocalState( maState );
526 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
528 return tools::calcDevicePixelBounds(
529 ::basegfx::B2DRange( 0,0,
530 maDstSize.getX(),
531 maDstSize.getY() ),
532 mpCanvas->getViewState(),
533 aLocalState );
536 ::basegfx::B2DRange TransparencyGroupAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
537 const Subset& rSubset ) const
539 // TODO(F3): Currently, the bounds for
540 // TransparencyGroupAction subsets equal those of the
541 // full set, although this action is able to render
542 // true subsets.
544 // polygon only contains a single action, empty bounds
545 // if subset requests different range
546 if( rSubset.mnSubsetBegin != 0 ||
547 rSubset.mnSubsetEnd != 1 )
548 return ::basegfx::B2DRange();
550 return getBounds( rTransformation );
553 sal_Int32 TransparencyGroupAction::getActionCount() const
555 return mpGroupMtf.get() ? mpGroupMtf->GetActionCount() : 0;
560 ActionSharedPtr TransparencyGroupActionFactory::createTransparencyGroupAction( MtfAutoPtr& rGroupMtf,
561 const Renderer::Parameters& rParms,
562 const ::basegfx::B2DPoint& rDstPoint,
563 const ::basegfx::B2DVector& rDstSize,
564 double nAlpha,
565 const CanvasSharedPtr& rCanvas,
566 const OutDevState& rState )
568 return ActionSharedPtr( new TransparencyGroupAction(rGroupMtf,
569 rParms,
570 rDstPoint,
571 rDstSize,
572 nAlpha,
573 rCanvas,
574 rState ) );
577 ActionSharedPtr TransparencyGroupActionFactory::createTransparencyGroupAction( MtfAutoPtr& rGroupMtf,
578 GradientAutoPtr& rAlphaGradient,
579 const Renderer::Parameters& rParms,
580 const ::basegfx::B2DPoint& rDstPoint,
581 const ::basegfx::B2DVector& rDstSize,
582 const CanvasSharedPtr& rCanvas,
583 const OutDevState& rState )
585 return ActionSharedPtr( new TransparencyGroupAction(rGroupMtf,
586 rAlphaGradient,
587 rParms,
588 rDstPoint,
589 rDstSize,
590 rCanvas,
591 rState ) );