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 .
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
;
62 // free support functions
63 // ======================
66 class TransparencyGroupAction
: public Action
, private ::boost::noncopyable
69 /** Create new transparency group action.
72 Metafile that groups all actions to be rendered
76 VCL gradient, to be rendered into the action's alpha
83 Left, top edge of destination, in current state
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;
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(),
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
),
154 maDstSize( rDstSize
),
156 maLastTransformation(),
161 tools::initRenderState(maState
,rState
);
162 implSetupTransform( maState
, rDstPoint
);
164 // correct clip (which is relative to original transform)
165 tools::modifyClip( maState
,
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
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
208 ::basegfx::B2DTuple aScale
;
209 ::basegfx::B2DTuple aTranslate
;
212 if( !aTotalTransform
.decompose( aScale
,
217 SAL_WARN( "cppcanvas.emf", "TransparencyGroupAction::renderSubset(): non-decomposable transformation" );
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 );
241 // render our content into an appropriately sized
242 // VirtualDevice with alpha channel
244 *::Application::GetDefaultDevice(), 0, 0 );
245 aVDev
.SetOutputSizePixel( aBitmapSizePixel
);
248 if( rSubset
.mnSubsetBegin
!= 0 ||
249 rSubset
.mnSubsetEnd
!= -1 )
251 // true subset - extract referenced
252 // metaactions from mpGroupMtf
254 MetaAction
* pCurrAct
;
255 int nCurrActionIndex
;
257 // extract subset actions
258 for( nCurrActionIndex
=0,
259 pCurrAct
=mpGroupMtf
->FirstAction();
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() );
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
322 if( rSubset
.mnSubsetBegin
<= nCurrActionIndex
&&
323 rSubset
.mnSubsetEnd
> nCurrActionIndex
)
325 aMtf
.AddAction( pCurrAct
->Clone() );
330 SAL_WARN( "cppcanvas.emf", "Unknown meta action type encountered" );
335 aVDev
.DrawTransparent( aMtf
,
342 // no subsetting - render whole mtf
343 aVDev
.DrawTransparent( *mpGroupMtf
,
350 // update buffered bitmap and transformation
351 BitmapSharedPtr
aBmp( VCLFactory::getInstance().createBitmap(
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
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
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(),
396 aLocalState
.DeviceColor
= maState
.DeviceColor
;
399 if( ::rtl::math::approxEqual(mnAlpha
, 1.0) )
401 // no further alpha changes necessary -> draw directly
402 mpCanvas
->getUNOCanvas()->drawBitmap( mxBufferBitmap
,
403 mpCanvas
->getViewState(),
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(
415 mpCanvas
->getUNOCanvas()->drawBitmapModulated( mxBufferBitmap
,
416 mpCanvas
->getViewState(),
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
430 bool TransparencyGroupAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
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,
449 mpCanvas
->getViewState(),
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
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
,
494 SAL_WNODEPRECATED_DECLARATIONS_POP
499 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */