Bump version to 5.0-14
[LibreOffice.git] / cppcanvas / source / mtfrenderer / transparencygroupaction.cxx
blobcd274b33320770e624dce772fc0ccb643916323f
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 <sal/config.h>
22 #include <utility>
24 #include <tools/gen.hxx>
26 #include <canvas/debug.hxx>
27 #include <canvas/verbosetrace.hxx>
28 #include <canvas/canvastools.hxx>
30 #include <com/sun/star/rendering/XBitmap.hpp>
31 #include <com/sun/star/rendering/XCanvas.hpp>
33 #include <rtl/math.hxx>
35 #include <vcl/metaact.hxx>
36 #include <vcl/bitmapex.hxx>
37 #include <vcl/canvastools.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/outdev.hxx>
40 #include <vcl/virdev.hxx>
41 #include <vcl/gdimtf.hxx>
42 #include <vcl/gradient.hxx>
44 #include <basegfx/range/b2drange.hxx>
45 #include <basegfx/point/b2dpoint.hxx>
46 #include <basegfx/vector/b2dsize.hxx>
47 #include <basegfx/numeric/ftools.hxx>
48 #include <basegfx/matrix/b2dhommatrix.hxx>
49 #include <basegfx/tuple/b2dtuple.hxx>
50 #include <basegfx/tools/canvastools.hxx>
52 #include <boost/utility.hpp>
54 #include "transparencygroupaction.hxx"
55 #include "outdevstate.hxx"
56 #include "mtftools.hxx"
57 #include "cppcanvas/vclfactory.hxx"
60 using namespace ::com::sun::star;
62 namespace cppcanvas
64 namespace internal
66 // free support functions
67 // ======================
68 namespace
70 class TransparencyGroupAction : public Action, private ::boost::noncopyable
72 public:
73 /** Create new transparency group action.
75 @param rGroupMtf
76 Metafile that groups all actions to be rendered
77 transparent.
79 @param rAlphaGradient
80 VCL gradient, to be rendered into the action's alpha
81 channel.
83 @param rParms
84 Render parameters
86 @param rDstPoint
87 Left, top edge of destination, in current state
88 coordinate system
90 @param rDstSize
91 Size of the transparency group object, in current
92 state coordinate system.
94 TransparencyGroupAction( MtfAutoPtr&& rGroupMtf,
95 GradientAutoPtr&& rAlphaGradient,
96 const Renderer::Parameters& rParms,
97 const ::basegfx::B2DPoint& rDstPoint,
98 const ::basegfx::B2DVector& rDstSize,
99 const CanvasSharedPtr& rCanvas,
100 const OutDevState& rState );
102 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
103 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
104 const Subset& rSubset ) const SAL_OVERRIDE;
106 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
107 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
108 const Subset& rSubset ) const SAL_OVERRIDE;
110 virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
112 private:
113 MtfAutoPtr mpGroupMtf;
114 GradientAutoPtr mpAlphaGradient;
116 const Renderer::Parameters maParms;
118 const ::basegfx::B2DSize maDstSize;
120 mutable uno::Reference< rendering::XBitmap > mxBufferBitmap; // contains last rendered version
121 mutable ::basegfx::B2DHomMatrix maLastTransformation; // contains last active transformation
122 mutable Subset maLastSubset; // contains last effective subset
124 // transformation for
125 // mxBufferBitmap content
126 CanvasSharedPtr mpCanvas;
127 rendering::RenderState maState;
128 const double mnAlpha;
132 /** Setup transformation such that the next render call is
133 moved rPoint away, and scaled according to the ratio
134 given by src and dst size.
136 void implSetupTransform( rendering::RenderState& rRenderState,
137 const ::basegfx::B2DPoint& rDstPoint )
139 ::basegfx::B2DHomMatrix aLocalTransformation;
141 aLocalTransformation.translate( rDstPoint.getX(),
142 rDstPoint.getY() );
143 ::canvas::tools::appendToRenderState( rRenderState,
144 aLocalTransformation );
147 TransparencyGroupAction::TransparencyGroupAction( MtfAutoPtr&& rGroupMtf,
148 GradientAutoPtr&& rAlphaGradient,
149 const Renderer::Parameters& rParms,
150 const ::basegfx::B2DPoint& rDstPoint,
151 const ::basegfx::B2DVector& rDstSize,
152 const CanvasSharedPtr& rCanvas,
153 const OutDevState& rState ) :
154 mpGroupMtf( std::move(rGroupMtf) ),
155 mpAlphaGradient( std::move(rAlphaGradient) ),
156 maParms( rParms ),
157 maDstSize( rDstSize ),
158 mxBufferBitmap(),
159 maLastTransformation(),
160 mpCanvas( rCanvas ),
161 maState(),
162 mnAlpha( 1.0 )
164 tools::initRenderState(maState,rState);
165 implSetupTransform( maState, rDstPoint );
167 // correct clip (which is relative to original transform)
168 tools::modifyClip( maState,
169 rState,
170 rCanvas,
171 rDstPoint,
172 NULL,
173 NULL );
175 maLastSubset.mnSubsetBegin = 0;
176 maLastSubset.mnSubsetEnd = -1;
179 // TODO(P3): The whole float transparency handling is a mess,
180 // this should be refactored. What's more, the old idea of
181 // having only internal 'metaactions', and not the original
182 // GDIMetaFile now looks a lot less attractive. Try to move
183 // into the direction of having a direct GDIMetaFile2XCanvas
184 // renderer, and maybe a separate metafile XCanvas
185 // implementation.
186 bool TransparencyGroupAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
187 const Subset& rSubset ) const
189 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TransparencyGroupAction::renderSubset()" );
190 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TransparencyGroupAction: 0x" << std::hex << this );
192 // determine overall transformation matrix (render, view,
193 // and passed transformation)
194 ::basegfx::B2DHomMatrix aTransform;
195 ::canvas::tools::getRenderStateTransform( aTransform, maState );
196 aTransform = rTransformation * aTransform;
198 ::basegfx::B2DHomMatrix aTotalTransform;
199 ::canvas::tools::getViewStateTransform( aTotalTransform, mpCanvas->getViewState() );
200 aTotalTransform = aTotalTransform * aTransform;
202 // since pure translational changes to the transformation
203 // does not matter, remove them before comparing
204 aTotalTransform.set( 0, 2, 0.0 );
205 aTotalTransform.set( 1, 2, 0.0 );
207 // determine total scaling factor of the
208 // transformation matrix - need to make the bitmap
209 // large enough
210 ::basegfx::B2DTuple aScale;
211 ::basegfx::B2DTuple aTranslate;
212 double nRotate;
213 double nShearX;
214 if( !aTotalTransform.decompose( aScale,
215 aTranslate,
216 nRotate,
217 nShearX ) )
219 SAL_WARN( "cppcanvas.emf", "TransparencyGroupAction::renderSubset(): non-decomposable transformation" );
220 return false;
223 // if there's no buffer bitmap, or as soon as the
224 // total transformation changes, we've got to
225 // re-render the bitmap
226 if( !mxBufferBitmap.is() ||
227 aTotalTransform != maLastTransformation ||
228 rSubset.mnSubsetBegin != maLastSubset.mnSubsetBegin ||
229 rSubset.mnSubsetEnd != maLastSubset.mnSubsetEnd )
231 DBG_TESTSOLARMUTEX();
233 // output size of metafile
234 ::Size aOutputSizePixel( ::basegfx::fround( aScale.getX() * maDstSize.getX() ),
235 ::basegfx::fround( aScale.getY() * maDstSize.getY() ) );
237 // pixel size of cache bitmap: round up to nearest int
238 ::Size aBitmapSizePixel( static_cast<sal_Int32>( aScale.getX() * maDstSize.getX() )+1,
239 static_cast<sal_Int32>( aScale.getY() * maDstSize.getY() )+1 );
241 ::Point aEmptyPoint;
243 // render our content into an appropriately sized
244 // VirtualDevice with alpha channel
245 ScopedVclPtrInstance<VirtualDevice> aVDev(
246 *::Application::GetDefaultDevice(), 0, 0 );
247 aVDev->SetOutputSizePixel( aBitmapSizePixel );
248 aVDev->SetMapMode();
250 if( rSubset.mnSubsetBegin != 0 ||
251 rSubset.mnSubsetEnd != -1 )
253 // true subset - extract referenced
254 // metaactions from mpGroupMtf
255 GDIMetaFile aMtf;
256 MetaAction* pCurrAct;
257 int nCurrActionIndex;
259 // extract subset actions
260 for( nCurrActionIndex=0,
261 pCurrAct=mpGroupMtf->FirstAction();
262 pCurrAct;
263 ++nCurrActionIndex, pCurrAct = mpGroupMtf->NextAction() )
265 switch( pCurrAct->GetType() )
267 case MetaActionType::PUSH:
268 case MetaActionType::POP:
269 case MetaActionType::CLIPREGION:
270 case MetaActionType::ISECTRECTCLIPREGION:
271 case MetaActionType::ISECTREGIONCLIPREGION:
272 case MetaActionType::MOVECLIPREGION:
273 case MetaActionType::LINECOLOR:
274 case MetaActionType::FILLCOLOR:
275 case MetaActionType::TEXTCOLOR:
276 case MetaActionType::TEXTFILLCOLOR:
277 case MetaActionType::TEXTLINECOLOR:
278 case MetaActionType::TEXTALIGN:
279 case MetaActionType::FONT:
280 case MetaActionType::RASTEROP:
281 case MetaActionType::REFPOINT:
282 case MetaActionType::LAYOUTMODE:
283 // state-changing action - copy as-is
284 aMtf.AddAction( pCurrAct->Clone() );
285 break;
287 case MetaActionType::GRADIENT:
288 case MetaActionType::HATCH:
289 case MetaActionType::EPS:
290 case MetaActionType::COMMENT:
291 case MetaActionType::POINT:
292 case MetaActionType::PIXEL:
293 case MetaActionType::LINE:
294 case MetaActionType::RECT:
295 case MetaActionType::ROUNDRECT:
296 case MetaActionType::ELLIPSE:
297 case MetaActionType::ARC:
298 case MetaActionType::PIE:
299 case MetaActionType::CHORD:
300 case MetaActionType::POLYLINE:
301 case MetaActionType::POLYGON:
302 case MetaActionType::POLYPOLYGON:
303 case MetaActionType::BMP:
304 case MetaActionType::BMPSCALE:
305 case MetaActionType::BMPSCALEPART:
306 case MetaActionType::BMPEX:
307 case MetaActionType::BMPEXSCALE:
308 case MetaActionType::BMPEXSCALEPART:
309 case MetaActionType::MASK:
310 case MetaActionType::MASKSCALE:
311 case MetaActionType::MASKSCALEPART:
312 case MetaActionType::GRADIENTEX:
313 case MetaActionType::WALLPAPER:
314 case MetaActionType::Transparent:
315 case MetaActionType::FLOATTRANSPARENT:
316 case MetaActionType::TEXT:
317 case MetaActionType::TEXTARRAY:
318 case MetaActionType::TEXTLINE:
319 case MetaActionType::TEXTRECT:
320 case MetaActionType::STRETCHTEXT:
321 // output-generating action - only
322 // copy, if we're within the
323 // requested subset
324 if( rSubset.mnSubsetBegin <= nCurrActionIndex &&
325 rSubset.mnSubsetEnd > nCurrActionIndex )
327 aMtf.AddAction( pCurrAct->Clone() );
329 break;
331 default:
332 SAL_WARN( "cppcanvas.emf", "Unknown meta action type encountered" );
333 break;
337 aVDev->DrawTransparent( aMtf,
338 aEmptyPoint,
339 aOutputSizePixel,
340 *mpAlphaGradient );
342 else
344 // no subsetting - render whole mtf
345 aVDev->DrawTransparent( *mpGroupMtf,
346 aEmptyPoint,
347 aOutputSizePixel,
348 *mpAlphaGradient );
352 // update buffered bitmap and transformation
353 BitmapSharedPtr aBmp( VCLFactory::createBitmap(
354 mpCanvas,
355 aVDev->GetBitmapEx(
356 aEmptyPoint,
357 aBitmapSizePixel ) ) );
358 mxBufferBitmap = aBmp->getUNOBitmap();
359 maLastTransformation = aTotalTransform;
360 maLastSubset = rSubset;
363 // determine target transformation (we can't simply pass
364 // aTotalTransform as assembled above, since we must take
365 // the canvas' view state as is, it might contain clipping
366 // (which, in turn, is relative to the view
367 // transformation))
369 // given that aTotalTransform is the identity
370 // transformation, we could simply render our bitmap
371 // as-is. Now, since the mxBufferBitmap content already
372 // accounts for scale changes in the overall
373 // transformation, we must factor this out
374 // before. Generally, the transformation matrix should be
375 // structured like this:
376 // Translation*Rotation*Shear*Scale. Thus, to neutralize
377 // the contained scaling, we've got to right-multiply with
378 // the inverse.
379 ::basegfx::B2DHomMatrix aScaleCorrection;
380 aScaleCorrection.scale( 1/aScale.getX(), 1/aScale.getY() );
381 aTransform = aTransform * aScaleCorrection;
383 rendering::RenderState aLocalState( maState );
384 ::canvas::tools::setRenderStateTransform(aLocalState, aTransform);
386 #if OSL_DEBUG_LEVEL > 2
387 aLocalState.Clip.clear();
388 aLocalState.DeviceColor =
389 vcl::unotools::colorToDoubleSequence(
390 ::Color( 0x80FF0000 ),
391 mpCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
393 if( maState.Clip.is() )
394 mpCanvas->getUNOCanvas()->fillPolyPolygon( maState.Clip,
395 mpCanvas->getViewState(),
396 aLocalState );
398 aLocalState.DeviceColor = maState.DeviceColor;
399 #endif
401 if( ::rtl::math::approxEqual(mnAlpha, 1.0) )
403 // no further alpha changes necessary -> draw directly
404 mpCanvas->getUNOCanvas()->drawBitmap( mxBufferBitmap,
405 mpCanvas->getViewState(),
406 aLocalState );
408 else
410 // add alpha modulation value to DeviceColor
411 uno::Sequence<rendering::ARGBColor> aCols(1);
412 aCols[0] = rendering::ARGBColor( mnAlpha, 1.0, 1.0, 1.0);
413 aLocalState.DeviceColor =
414 mpCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace()->convertFromARGB(
415 aCols);
417 mpCanvas->getUNOCanvas()->drawBitmapModulated( mxBufferBitmap,
418 mpCanvas->getViewState(),
419 aLocalState );
422 return true;
425 // TODO(P3): The whole float transparency handling is a mess,
426 // this should be refactored. What's more, the old idea of
427 // having only internal 'metaactions', and not the original
428 // GDIMetaFile now looks a lot less attractive. Try to move
429 // into the direction of having a direct GDIMetaFile2XCanvas
430 // renderer, and maybe a separate metafile XCanvas
431 // implementation.
432 bool TransparencyGroupAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
434 Subset aSubset;
436 aSubset.mnSubsetBegin = 0;
437 aSubset.mnSubsetEnd = -1;
439 return renderSubset( rTransformation, aSubset );
442 ::basegfx::B2DRange TransparencyGroupAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
444 rendering::RenderState aLocalState( maState );
445 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
447 return tools::calcDevicePixelBounds(
448 ::basegfx::B2DRange( 0,0,
449 maDstSize.getX(),
450 maDstSize.getY() ),
451 mpCanvas->getViewState(),
452 aLocalState );
455 ::basegfx::B2DRange TransparencyGroupAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
456 const Subset& rSubset ) const
458 // TODO(F3): Currently, the bounds for
459 // TransparencyGroupAction subsets equal those of the
460 // full set, although this action is able to render
461 // true subsets.
463 // polygon only contains a single action, empty bounds
464 // if subset requests different range
465 if( rSubset.mnSubsetBegin != 0 ||
466 rSubset.mnSubsetEnd != 1 )
467 return ::basegfx::B2DRange();
469 return getBounds( rTransformation );
472 sal_Int32 TransparencyGroupAction::getActionCount() const
474 return mpGroupMtf.get() ? mpGroupMtf->GetActionSize() : 0;
479 ActionSharedPtr TransparencyGroupActionFactory::createTransparencyGroupAction( MtfAutoPtr&& rGroupMtf,
480 GradientAutoPtr&& rAlphaGradient,
481 const Renderer::Parameters& rParms,
482 const ::basegfx::B2DPoint& rDstPoint,
483 const ::basegfx::B2DVector& rDstSize,
484 const CanvasSharedPtr& rCanvas,
485 const OutDevState& rState )
487 return ActionSharedPtr( new TransparencyGroupAction(std::move(rGroupMtf),
488 std::move(rAlphaGradient),
489 rParms,
490 rDstPoint,
491 rDstSize,
492 rCanvas,
493 rState ) );
499 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */