Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / cppcanvas / source / mtfrenderer / transparencygroupaction.cxx
blob8254320de9781cbdaa180392a154289f182e5b3e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <tools/gen.hxx>
22 #include <canvas/debug.hxx>
23 #include <canvas/verbosetrace.hxx>
24 #include <canvas/canvastools.hxx>
26 #include <com/sun/star/rendering/XBitmap.hpp>
27 #include <com/sun/star/rendering/XCanvas.hpp>
29 #include <rtl/math.hxx>
31 #include <vcl/metaact.hxx>
32 #include <vcl/bitmapex.hxx>
33 #include <vcl/canvastools.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/outdev.hxx>
36 #include <vcl/virdev.hxx>
37 #include <vcl/gdimtf.hxx>
38 #include <vcl/gradient.hxx>
40 #include <basegfx/range/b2drange.hxx>
41 #include <basegfx/point/b2dpoint.hxx>
42 #include <basegfx/vector/b2dsize.hxx>
43 #include <basegfx/numeric/ftools.hxx>
44 #include <basegfx/matrix/b2dhommatrix.hxx>
45 #include <basegfx/tuple/b2dtuple.hxx>
46 #include <basegfx/tools/canvastools.hxx>
48 #include <boost/utility.hpp>
50 #include "transparencygroupaction.hxx"
51 #include "outdevstate.hxx"
52 #include "mtftools.hxx"
53 #include "cppcanvas/vclfactory.hxx"
56 using namespace ::com::sun::star;
58 namespace cppcanvas
60 namespace internal
62 // free support functions
63 // ======================
64 namespace
66 class TransparencyGroupAction : public Action, private ::boost::noncopyable
68 public:
69 /** Create new transparency group action.
71 @param rGroupMtf
72 Metafile that groups all actions to be rendered
73 transparent.
75 @param rAlphaGradient
76 VCL gradient, to be rendered into the action's alpha
77 channel.
79 @param rParms
80 Render parameters
82 @param rDstPoint
83 Left, top edge of destination, in current state
84 coordinate system
86 @param rDstSize
87 Size of the transparency group object, in current
88 state coordinate system.
90 TransparencyGroupAction( MtfAutoPtr& rGroupMtf,
91 GradientAutoPtr& rAlphaGradient,
92 const Renderer::Parameters& rParms,
93 const ::basegfx::B2DPoint& rDstPoint,
94 const ::basegfx::B2DVector& rDstSize,
95 const CanvasSharedPtr& rCanvas,
96 const OutDevState& rState );
98 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
99 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
100 const Subset& rSubset ) const;
102 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
103 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
104 const Subset& rSubset ) const;
106 virtual sal_Int32 getActionCount() const;
108 private:
109 MtfAutoPtr mpGroupMtf;
110 GradientAutoPtr mpAlphaGradient;
112 const Renderer::Parameters maParms;
114 const ::basegfx::B2DSize maDstSize;
116 mutable uno::Reference< rendering::XBitmap > mxBufferBitmap; // contains last rendered version
117 mutable ::basegfx::B2DHomMatrix maLastTransformation; // contains last active transformation
118 mutable Subset maLastSubset; // contains last effective subset
120 // transformation for
121 // mxBufferBitmap content
122 CanvasSharedPtr mpCanvas;
123 rendering::RenderState maState;
124 const double mnAlpha;
128 /** Setup transformation such that the next render call is
129 moved rPoint away, and scaled according to the ratio
130 given by src and dst size.
132 void implSetupTransform( rendering::RenderState& rRenderState,
133 const ::basegfx::B2DPoint& rDstPoint )
135 ::basegfx::B2DHomMatrix aLocalTransformation;
137 aLocalTransformation.translate( rDstPoint.getX(),
138 rDstPoint.getY() );
139 ::canvas::tools::appendToRenderState( rRenderState,
140 aLocalTransformation );
143 SAL_WNODEPRECATED_DECLARATIONS_PUSH
144 TransparencyGroupAction::TransparencyGroupAction( MtfAutoPtr& rGroupMtf,
145 GradientAutoPtr& rAlphaGradient,
146 const Renderer::Parameters& rParms,
147 const ::basegfx::B2DPoint& rDstPoint,
148 const ::basegfx::B2DVector& rDstSize,
149 const CanvasSharedPtr& rCanvas,
150 const OutDevState& rState ) :
151 mpGroupMtf( rGroupMtf ),
152 mpAlphaGradient( rAlphaGradient ),
153 maParms( rParms ),
154 maDstSize( rDstSize ),
155 mxBufferBitmap(),
156 maLastTransformation(),
157 mpCanvas( rCanvas ),
158 maState(),
159 mnAlpha( 1.0 )
161 tools::initRenderState(maState,rState);
162 implSetupTransform( maState, rDstPoint );
164 // correct clip (which is relative to original transform)
165 tools::modifyClip( maState,
166 rState,
167 rCanvas,
168 rDstPoint,
169 NULL,
170 NULL );
172 maLastSubset.mnSubsetBegin = 0;
173 maLastSubset.mnSubsetEnd = -1;
175 SAL_WNODEPRECATED_DECLARATIONS_POP
177 // TODO(P3): The whole float transparency handling is a mess,
178 // this should be refactored. What's more, the old idea of
179 // having only internal 'metaactions', and not the original
180 // GDIMetaFile now looks a lot less attractive. Try to move
181 // into the direction of having a direct GDIMetaFile2XCanvas
182 // renderer, and maybe a separate metafile XCanvas
183 // implementation.
184 bool TransparencyGroupAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
185 const Subset& rSubset ) const
187 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TransparencyGroupAction::renderSubset()" );
188 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TransparencyGroupAction: 0x" << std::hex << this );
190 // determine overall transformation matrix (render, view,
191 // and passed transformation)
192 ::basegfx::B2DHomMatrix aTransform;
193 ::canvas::tools::getRenderStateTransform( aTransform, maState );
194 aTransform = rTransformation * aTransform;
196 ::basegfx::B2DHomMatrix aTotalTransform;
197 ::canvas::tools::getViewStateTransform( aTotalTransform, mpCanvas->getViewState() );
198 aTotalTransform = aTotalTransform * aTransform;
200 // since pure translational changes to the transformation
201 // does not matter, remove them before comparing
202 aTotalTransform.set( 0, 2, 0.0 );
203 aTotalTransform.set( 1, 2, 0.0 );
205 // determine total scaling factor of the
206 // transformation matrix - need to make the bitmap
207 // large enough
208 ::basegfx::B2DTuple aScale;
209 ::basegfx::B2DTuple aTranslate;
210 double nRotate;
211 double nShearX;
212 if( !aTotalTransform.decompose( aScale,
213 aTranslate,
214 nRotate,
215 nShearX ) )
217 SAL_WARN( "cppcanvas.emf", "TransparencyGroupAction::renderSubset(): non-decomposable transformation" );
218 return false;
221 // if there's no buffer bitmap, or as soon as the
222 // total transformation changes, we've got to
223 // re-render the bitmap
224 if( !mxBufferBitmap.is() ||
225 aTotalTransform != maLastTransformation ||
226 rSubset.mnSubsetBegin != maLastSubset.mnSubsetBegin ||
227 rSubset.mnSubsetEnd != maLastSubset.mnSubsetEnd )
229 DBG_TESTSOLARMUTEX();
231 // output size of metafile
232 ::Size aOutputSizePixel( ::basegfx::fround( aScale.getX() * maDstSize.getX() ),
233 ::basegfx::fround( aScale.getY() * maDstSize.getY() ) );
235 // pixel size of cache bitmap: round up to nearest int
236 ::Size aBitmapSizePixel( static_cast<sal_Int32>( aScale.getX() * maDstSize.getX() )+1,
237 static_cast<sal_Int32>( aScale.getY() * maDstSize.getY() )+1 );
239 ::Point aEmptyPoint;
241 // render our content into an appropriately sized
242 // VirtualDevice with alpha channel
243 VirtualDevice aVDev(
244 *::Application::GetDefaultDevice(), 0, 0 );
245 aVDev.SetOutputSizePixel( aBitmapSizePixel );
246 aVDev.SetMapMode();
248 if( rSubset.mnSubsetBegin != 0 ||
249 rSubset.mnSubsetEnd != -1 )
251 // true subset - extract referenced
252 // metaactions from mpGroupMtf
253 GDIMetaFile aMtf;
254 MetaAction* pCurrAct;
255 int nCurrActionIndex;
257 // extract subset actions
258 for( nCurrActionIndex=0,
259 pCurrAct=mpGroupMtf->FirstAction();
260 pCurrAct;
261 ++nCurrActionIndex, pCurrAct = mpGroupMtf->NextAction() )
263 switch( pCurrAct->GetType() )
265 case META_PUSH_ACTION:
266 case META_POP_ACTION:
267 case META_CLIPREGION_ACTION:
268 case META_ISECTRECTCLIPREGION_ACTION:
269 case META_ISECTREGIONCLIPREGION_ACTION:
270 case META_MOVECLIPREGION_ACTION:
271 case META_LINECOLOR_ACTION:
272 case META_FILLCOLOR_ACTION:
273 case META_TEXTCOLOR_ACTION:
274 case META_TEXTFILLCOLOR_ACTION:
275 case META_TEXTLINECOLOR_ACTION:
276 case META_TEXTALIGN_ACTION:
277 case META_FONT_ACTION:
278 case META_RASTEROP_ACTION:
279 case META_REFPOINT_ACTION:
280 case META_LAYOUTMODE_ACTION:
281 // state-changing action - copy as-is
282 aMtf.AddAction( pCurrAct->Clone() );
283 break;
285 case META_GRADIENT_ACTION:
286 case META_HATCH_ACTION:
287 case META_EPS_ACTION:
288 case META_COMMENT_ACTION:
289 case META_POINT_ACTION:
290 case META_PIXEL_ACTION:
291 case META_LINE_ACTION:
292 case META_RECT_ACTION:
293 case META_ROUNDRECT_ACTION:
294 case META_ELLIPSE_ACTION:
295 case META_ARC_ACTION:
296 case META_PIE_ACTION:
297 case META_CHORD_ACTION:
298 case META_POLYLINE_ACTION:
299 case META_POLYGON_ACTION:
300 case META_POLYPOLYGON_ACTION:
301 case META_BMP_ACTION:
302 case META_BMPSCALE_ACTION:
303 case META_BMPSCALEPART_ACTION:
304 case META_BMPEX_ACTION:
305 case META_BMPEXSCALE_ACTION:
306 case META_BMPEXSCALEPART_ACTION:
307 case META_MASK_ACTION:
308 case META_MASKSCALE_ACTION:
309 case META_MASKSCALEPART_ACTION:
310 case META_GRADIENTEX_ACTION:
311 case META_WALLPAPER_ACTION:
312 case META_TRANSPARENT_ACTION:
313 case META_FLOATTRANSPARENT_ACTION:
314 case META_TEXT_ACTION:
315 case META_TEXTARRAY_ACTION:
316 case META_TEXTLINE_ACTION:
317 case META_TEXTRECT_ACTION:
318 case META_STRETCHTEXT_ACTION:
319 // output-generating action - only
320 // copy, if we're within the
321 // requested subset
322 if( rSubset.mnSubsetBegin <= nCurrActionIndex &&
323 rSubset.mnSubsetEnd > nCurrActionIndex )
325 aMtf.AddAction( pCurrAct->Clone() );
327 break;
329 default:
330 SAL_WARN( "cppcanvas.emf", "Unknown meta action type encountered" );
331 break;
335 aVDev.DrawTransparent( aMtf,
336 aEmptyPoint,
337 aOutputSizePixel,
338 *mpAlphaGradient );
340 else
342 // no subsetting - render whole mtf
343 aVDev.DrawTransparent( *mpGroupMtf,
344 aEmptyPoint,
345 aOutputSizePixel,
346 *mpAlphaGradient );
350 // update buffered bitmap and transformation
351 BitmapSharedPtr aBmp( VCLFactory::getInstance().createBitmap(
352 mpCanvas,
353 aVDev.GetBitmapEx(
354 aEmptyPoint,
355 aBitmapSizePixel ) ) );
356 mxBufferBitmap = aBmp->getUNOBitmap();
357 maLastTransformation = aTotalTransform;
358 maLastSubset = rSubset;
361 // determine target transformation (we can't simply pass
362 // aTotalTransform as assembled above, since we must take
363 // the canvas' view state as is, it might contain clipping
364 // (which, in turn, is relative to the view
365 // transformation))
367 // given that aTotalTransform is the identity
368 // transformation, we could simply render our bitmap
369 // as-is. Now, since the mxBufferBitmap content already
370 // accounts for scale changes in the overall
371 // transformation, we must factor this out
372 // before. Generally, the transformation matrix should be
373 // structured like this:
374 // Translation*Rotation*Shear*Scale. Thus, to neutralize
375 // the contained scaling, we've got to right-multiply with
376 // the inverse.
377 ::basegfx::B2DHomMatrix aScaleCorrection;
378 aScaleCorrection.scale( 1/aScale.getX(), 1/aScale.getY() );
379 aTransform = aTransform * aScaleCorrection;
381 rendering::RenderState aLocalState( maState );
382 ::canvas::tools::setRenderStateTransform(aLocalState, aTransform);
384 #if OSL_DEBUG_LEVEL > 2
385 aLocalState.Clip.clear();
386 aLocalState.DeviceColor =
387 ::vcl::unotools::colorToDoubleSequence(
388 ::Color( 0x80FF0000 ),
389 mpCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
391 if( maState.Clip.is() )
392 mpCanvas->getUNOCanvas()->fillPolyPolygon( maState.Clip,
393 mpCanvas->getViewState(),
394 aLocalState );
396 aLocalState.DeviceColor = maState.DeviceColor;
397 #endif
399 if( ::rtl::math::approxEqual(mnAlpha, 1.0) )
401 // no further alpha changes necessary -> draw directly
402 mpCanvas->getUNOCanvas()->drawBitmap( mxBufferBitmap,
403 mpCanvas->getViewState(),
404 aLocalState );
406 else
408 // add alpha modulation value to DeviceColor
409 uno::Sequence<rendering::ARGBColor> aCols(1);
410 aCols[0] = rendering::ARGBColor( mnAlpha, 1.0, 1.0, 1.0);
411 aLocalState.DeviceColor =
412 mpCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace()->convertFromARGB(
413 aCols);
415 mpCanvas->getUNOCanvas()->drawBitmapModulated( mxBufferBitmap,
416 mpCanvas->getViewState(),
417 aLocalState );
420 return true;
423 // TODO(P3): The whole float transparency handling is a mess,
424 // this should be refactored. What's more, the old idea of
425 // having only internal 'metaactions', and not the original
426 // GDIMetaFile now looks a lot less attractive. Try to move
427 // into the direction of having a direct GDIMetaFile2XCanvas
428 // renderer, and maybe a separate metafile XCanvas
429 // implementation.
430 bool TransparencyGroupAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
432 Subset aSubset;
434 aSubset.mnSubsetBegin = 0;
435 aSubset.mnSubsetEnd = -1;
437 return renderSubset( rTransformation, aSubset );
440 ::basegfx::B2DRange TransparencyGroupAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
442 rendering::RenderState aLocalState( maState );
443 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
445 return tools::calcDevicePixelBounds(
446 ::basegfx::B2DRange( 0,0,
447 maDstSize.getX(),
448 maDstSize.getY() ),
449 mpCanvas->getViewState(),
450 aLocalState );
453 ::basegfx::B2DRange TransparencyGroupAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
454 const Subset& rSubset ) const
456 // TODO(F3): Currently, the bounds for
457 // TransparencyGroupAction subsets equal those of the
458 // full set, although this action is able to render
459 // true subsets.
461 // polygon only contains a single action, empty bounds
462 // if subset requests different range
463 if( rSubset.mnSubsetBegin != 0 ||
464 rSubset.mnSubsetEnd != 1 )
465 return ::basegfx::B2DRange();
467 return getBounds( rTransformation );
470 sal_Int32 TransparencyGroupAction::getActionCount() const
472 return mpGroupMtf.get() ? mpGroupMtf->GetActionSize() : 0;
477 SAL_WNODEPRECATED_DECLARATIONS_PUSH
478 ActionSharedPtr TransparencyGroupActionFactory::createTransparencyGroupAction( MtfAutoPtr& rGroupMtf,
479 GradientAutoPtr& rAlphaGradient,
480 const Renderer::Parameters& rParms,
481 const ::basegfx::B2DPoint& rDstPoint,
482 const ::basegfx::B2DVector& rDstSize,
483 const CanvasSharedPtr& rCanvas,
484 const OutDevState& rState )
486 return ActionSharedPtr( new TransparencyGroupAction(rGroupMtf,
487 rAlphaGradient,
488 rParms,
489 rDstPoint,
490 rDstSize,
491 rCanvas,
492 rState ) );
494 SAL_WNODEPRECATED_DECLARATIONS_POP
499 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */