1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <tools/gen.hxx>
32 #include <canvas/debug.hxx>
33 #include <canvas/verbosetrace.hxx>
34 #include <canvas/canvastools.hxx>
36 #include <rtl/logfile.hxx>
38 #include <com/sun/star/rendering/XBitmap.hpp>
39 #include <com/sun/star/rendering/XCanvas.hpp>
41 #include <rtl/math.hxx>
43 #include <vcl/metaact.hxx>
44 #include <vcl/bitmapex.hxx>
45 #include <vcl/canvastools.hxx>
46 #include <vcl/svapp.hxx>
47 #include <vcl/outdev.hxx>
48 #include <vcl/virdev.hxx>
49 #include <vcl/gdimtf.hxx>
50 #include <vcl/gradient.hxx>
52 #include <basegfx/range/b2drange.hxx>
53 #include <basegfx/point/b2dpoint.hxx>
54 #include <basegfx/vector/b2dsize.hxx>
55 #include <basegfx/numeric/ftools.hxx>
56 #include <basegfx/matrix/b2dhommatrix.hxx>
57 #include <basegfx/tuple/b2dtuple.hxx>
58 #include <basegfx/tools/canvastools.hxx>
60 #include <boost/utility.hpp>
62 #include "transparencygroupaction.hxx"
63 #include "outdevstate.hxx"
64 #include "mtftools.hxx"
65 #include "cppcanvas/vclfactory.hxx"
68 using namespace ::com::sun::star
;
74 // free support functions
75 // ======================
78 class TransparencyGroupAction
: public Action
, private ::boost::noncopyable
81 /** Create new transparency group action.
84 Metafile that groups all actions to be rendered
88 VCL gradient, to be rendered into the action's alpha
95 Left, top edge of destination, in current state
99 Size of the transparency group object, in current
100 state coordinate system.
102 TransparencyGroupAction( MtfAutoPtr
& rGroupMtf
,
103 GradientAutoPtr
& rAlphaGradient
,
104 const Renderer::Parameters
& rParms
,
105 const ::basegfx::B2DPoint
& rDstPoint
,
106 const ::basegfx::B2DVector
& rDstSize
,
107 const CanvasSharedPtr
& rCanvas
,
108 const OutDevState
& rState
);
110 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const;
111 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
112 const Subset
& rSubset
) const;
114 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const;
115 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
116 const Subset
& rSubset
) const;
118 virtual sal_Int32
getActionCount() const;
121 MtfAutoPtr mpGroupMtf
;
122 GradientAutoPtr mpAlphaGradient
;
124 const Renderer::Parameters maParms
;
126 const ::basegfx::B2DSize maDstSize
;
128 mutable uno::Reference
< rendering::XBitmap
> mxBufferBitmap
; // contains last rendered version
129 mutable ::basegfx::B2DHomMatrix maLastTransformation
; // contains last active transformation
130 mutable Subset maLastSubset
; // contains last effective subset
132 // transformation for
133 // mxBufferBitmap content
134 CanvasSharedPtr mpCanvas
;
135 rendering::RenderState maState
;
136 const double mnAlpha
;
140 /** Setup transformation such that the next render call is
141 moved rPoint away, and scaled according to the ratio
142 given by src and dst size.
144 void implSetupTransform( rendering::RenderState
& rRenderState
,
145 const ::basegfx::B2DPoint
& rDstPoint
)
147 ::basegfx::B2DHomMatrix aLocalTransformation
;
149 aLocalTransformation
.translate( rDstPoint
.getX(),
151 ::canvas::tools::appendToRenderState( rRenderState
,
152 aLocalTransformation
);
155 SAL_WNODEPRECATED_DECLARATIONS_PUSH
156 TransparencyGroupAction::TransparencyGroupAction( MtfAutoPtr
& rGroupMtf
,
157 GradientAutoPtr
& rAlphaGradient
,
158 const Renderer::Parameters
& rParms
,
159 const ::basegfx::B2DPoint
& rDstPoint
,
160 const ::basegfx::B2DVector
& rDstSize
,
161 const CanvasSharedPtr
& rCanvas
,
162 const OutDevState
& rState
) :
163 mpGroupMtf( rGroupMtf
),
164 mpAlphaGradient( rAlphaGradient
),
166 maDstSize( rDstSize
),
168 maLastTransformation(),
173 tools::initRenderState(maState
,rState
);
174 implSetupTransform( maState
, rDstPoint
);
176 // correct clip (which is relative to original transform)
177 tools::modifyClip( maState
,
184 maLastSubset
.mnSubsetBegin
= 0;
185 maLastSubset
.mnSubsetEnd
= -1;
187 SAL_WNODEPRECATED_DECLARATIONS_POP
189 // TODO(P3): The whole float transparency handling is a mess,
190 // this should be refactored. What's more, the old idea of
191 // having only internal 'metaactions', and not the original
192 // GDIMetaFile now looks a lot less attractive. Try to move
193 // into the direction of having a direct GDIMetaFile2XCanvas
194 // renderer, and maybe a separate metafile XCanvas
196 bool TransparencyGroupAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
197 const Subset
& rSubset
) const
199 RTL_LOGFILE_CONTEXT( aLog
, "::cppcanvas::internal::TransparencyGroupAction::renderSubset()" );
200 RTL_LOGFILE_CONTEXT_TRACE1( aLog
, "::cppcanvas::internal::TransparencyGroupAction: 0x%X", this );
202 // determine overall transformation matrix (render, view,
203 // and passed transformation)
204 ::basegfx::B2DHomMatrix aTransform
;
205 ::canvas::tools::getRenderStateTransform( aTransform
, maState
);
206 aTransform
= rTransformation
* aTransform
;
208 ::basegfx::B2DHomMatrix aTotalTransform
;
209 ::canvas::tools::getViewStateTransform( aTotalTransform
, mpCanvas
->getViewState() );
210 aTotalTransform
= aTotalTransform
* aTransform
;
212 // since pure translational changes to the transformation
213 // does not matter, remove them before comparing
214 aTotalTransform
.set( 0, 2, 0.0 );
215 aTotalTransform
.set( 1, 2, 0.0 );
217 // determine total scaling factor of the
218 // transformation matrix - need to make the bitmap
220 ::basegfx::B2DTuple aScale
;
221 ::basegfx::B2DTuple aTranslate
;
224 if( !aTotalTransform
.decompose( aScale
,
229 OSL_FAIL( "TransparencyGroupAction::renderSubset(): non-decomposable transformation" );
233 // if there's no buffer bitmap, or as soon as the
234 // total transformation changes, we've got to
235 // re-render the bitmap
236 if( !mxBufferBitmap
.is() ||
237 aTotalTransform
!= maLastTransformation
||
238 rSubset
.mnSubsetBegin
!= maLastSubset
.mnSubsetBegin
||
239 rSubset
.mnSubsetEnd
!= maLastSubset
.mnSubsetEnd
)
241 DBG_TESTSOLARMUTEX();
243 // output size of metafile
244 ::Size
aOutputSizePixel( ::basegfx::fround( aScale
.getX() * maDstSize
.getX() ),
245 ::basegfx::fround( aScale
.getY() * maDstSize
.getY() ) );
247 // pixel size of cache bitmap: round up to nearest int
248 ::Size
aBitmapSizePixel( static_cast<sal_Int32
>( aScale
.getX() * maDstSize
.getX() )+1,
249 static_cast<sal_Int32
>( aScale
.getY() * maDstSize
.getY() )+1 );
253 // render our content into an appropriately sized
254 // VirtualDevice with alpha channel
256 *::Application::GetDefaultDevice(), 0, 0 );
257 aVDev
.SetOutputSizePixel( aBitmapSizePixel
);
260 if( rSubset
.mnSubsetBegin
!= 0 ||
261 rSubset
.mnSubsetEnd
!= -1 )
263 // true subset - extract referenced
264 // metaactions from mpGroupMtf
266 MetaAction
* pCurrAct
;
267 int nCurrActionIndex
;
269 // extract subset actions
270 for( nCurrActionIndex
=0,
271 pCurrAct
=mpGroupMtf
->FirstAction();
273 ++nCurrActionIndex
, pCurrAct
= mpGroupMtf
->NextAction() )
275 switch( pCurrAct
->GetType() )
277 case META_PUSH_ACTION
:
278 case META_POP_ACTION
:
279 case META_CLIPREGION_ACTION
:
280 case META_ISECTRECTCLIPREGION_ACTION
:
281 case META_ISECTREGIONCLIPREGION_ACTION
:
282 case META_MOVECLIPREGION_ACTION
:
283 case META_LINECOLOR_ACTION
:
284 case META_FILLCOLOR_ACTION
:
285 case META_TEXTCOLOR_ACTION
:
286 case META_TEXTFILLCOLOR_ACTION
:
287 case META_TEXTLINECOLOR_ACTION
:
288 case META_TEXTALIGN_ACTION
:
289 case META_FONT_ACTION
:
290 case META_RASTEROP_ACTION
:
291 case META_REFPOINT_ACTION
:
292 case META_LAYOUTMODE_ACTION
:
293 // state-changing action - copy as-is
294 aMtf
.AddAction( pCurrAct
->Clone() );
297 case META_GRADIENT_ACTION
:
298 case META_HATCH_ACTION
:
299 case META_EPS_ACTION
:
300 case META_COMMENT_ACTION
:
301 case META_POINT_ACTION
:
302 case META_PIXEL_ACTION
:
303 case META_LINE_ACTION
:
304 case META_RECT_ACTION
:
305 case META_ROUNDRECT_ACTION
:
306 case META_ELLIPSE_ACTION
:
307 case META_ARC_ACTION
:
308 case META_PIE_ACTION
:
309 case META_CHORD_ACTION
:
310 case META_POLYLINE_ACTION
:
311 case META_POLYGON_ACTION
:
312 case META_POLYPOLYGON_ACTION
:
313 case META_BMP_ACTION
:
314 case META_BMPSCALE_ACTION
:
315 case META_BMPSCALEPART_ACTION
:
316 case META_BMPEX_ACTION
:
317 case META_BMPEXSCALE_ACTION
:
318 case META_BMPEXSCALEPART_ACTION
:
319 case META_MASK_ACTION
:
320 case META_MASKSCALE_ACTION
:
321 case META_MASKSCALEPART_ACTION
:
322 case META_GRADIENTEX_ACTION
:
323 case META_WALLPAPER_ACTION
:
324 case META_TRANSPARENT_ACTION
:
325 case META_FLOATTRANSPARENT_ACTION
:
326 case META_TEXT_ACTION
:
327 case META_TEXTARRAY_ACTION
:
328 case META_TEXTLINE_ACTION
:
329 case META_TEXTRECT_ACTION
:
330 case META_STRETCHTEXT_ACTION
:
331 case META_RENDERGRAPHIC_ACTION
:
332 // output-generating action - only
333 // copy, if we're within the
335 if( rSubset
.mnSubsetBegin
<= nCurrActionIndex
&&
336 rSubset
.mnSubsetEnd
> nCurrActionIndex
)
338 aMtf
.AddAction( pCurrAct
->Clone() );
343 OSL_FAIL( "Unknown meta action type encountered" );
348 aVDev
.DrawTransparent( aMtf
,
355 // no subsetting - render whole mtf
356 aVDev
.DrawTransparent( *mpGroupMtf
,
363 // update buffered bitmap and transformation
364 BitmapSharedPtr
aBmp( VCLFactory::getInstance().createBitmap(
368 aBitmapSizePixel
) ) );
369 mxBufferBitmap
= aBmp
->getUNOBitmap();
370 maLastTransformation
= aTotalTransform
;
371 maLastSubset
= rSubset
;
374 // determine target transformation (we can't simply pass
375 // aTotalTransform as assembled above, since we must take
376 // the canvas' view state as is, it might contain clipping
377 // (which, in turn, is relative to the view
380 // given that aTotalTransform is the identity
381 // transformation, we could simply render our bitmap
382 // as-is. Now, since the mxBufferBitmap content already
383 // accounts for scale changes in the overall
384 // transformation, we must factor this out
385 // before. Generally, the transformation matrix should be
386 // structured like this:
387 // Translation*Rotation*Shear*Scale. Thus, to neutralize
388 // the contained scaling, we've got to right-multiply with
390 ::basegfx::B2DHomMatrix aScaleCorrection
;
391 aScaleCorrection
.scale( 1/aScale
.getX(), 1/aScale
.getY() );
392 aTransform
= aTransform
* aScaleCorrection
;
394 rendering::RenderState
aLocalState( maState
);
395 ::canvas::tools::setRenderStateTransform(aLocalState
, aTransform
);
397 #if OSL_DEBUG_LEVEL > 2
398 aLocalState
.Clip
.clear();
399 aLocalState
.DeviceColor
=
400 ::vcl::unotools::colorToDoubleSequence(
401 ::Color( 0x80FF0000 ),
402 mpCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
404 if( maState
.Clip
.is() )
405 mpCanvas
->getUNOCanvas()->fillPolyPolygon( maState
.Clip
,
406 mpCanvas
->getViewState(),
409 aLocalState
.DeviceColor
= maState
.DeviceColor
;
412 if( ::rtl::math::approxEqual(mnAlpha
, 1.0) )
414 // no further alpha changes necessary -> draw directly
415 mpCanvas
->getUNOCanvas()->drawBitmap( mxBufferBitmap
,
416 mpCanvas
->getViewState(),
421 // add alpha modulation value to DeviceColor
422 uno::Sequence
<rendering::ARGBColor
> aCols(1);
423 aCols
[0] = rendering::ARGBColor( mnAlpha
, 1.0, 1.0, 1.0);
424 aLocalState
.DeviceColor
=
425 mpCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace()->convertFromARGB(
428 mpCanvas
->getUNOCanvas()->drawBitmapModulated( mxBufferBitmap
,
429 mpCanvas
->getViewState(),
436 // TODO(P3): The whole float transparency handling is a mess,
437 // this should be refactored. What's more, the old idea of
438 // having only internal 'metaactions', and not the original
439 // GDIMetaFile now looks a lot less attractive. Try to move
440 // into the direction of having a direct GDIMetaFile2XCanvas
441 // renderer, and maybe a separate metafile XCanvas
443 bool TransparencyGroupAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
447 aSubset
.mnSubsetBegin
= 0;
448 aSubset
.mnSubsetEnd
= -1;
450 return renderSubset( rTransformation
, aSubset
);
453 ::basegfx::B2DRange
TransparencyGroupAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
455 rendering::RenderState
aLocalState( maState
);
456 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
458 return tools::calcDevicePixelBounds(
459 ::basegfx::B2DRange( 0,0,
462 mpCanvas
->getViewState(),
466 ::basegfx::B2DRange
TransparencyGroupAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
467 const Subset
& rSubset
) const
469 // TODO(F3): Currently, the bounds for
470 // TransparencyGroupAction subsets equal those of the
471 // full set, although this action is able to render
474 // polygon only contains a single action, empty bounds
475 // if subset requests different range
476 if( rSubset
.mnSubsetBegin
!= 0 ||
477 rSubset
.mnSubsetEnd
!= 1 )
478 return ::basegfx::B2DRange();
480 return getBounds( rTransformation
);
483 sal_Int32
TransparencyGroupAction::getActionCount() const
485 return mpGroupMtf
.get() ? mpGroupMtf
->GetActionSize() : 0;
490 SAL_WNODEPRECATED_DECLARATIONS_PUSH
491 ActionSharedPtr
TransparencyGroupActionFactory::createTransparencyGroupAction( MtfAutoPtr
& rGroupMtf
,
492 GradientAutoPtr
& rAlphaGradient
,
493 const Renderer::Parameters
& rParms
,
494 const ::basegfx::B2DPoint
& rDstPoint
,
495 const ::basegfx::B2DVector
& rDstSize
,
496 const CanvasSharedPtr
& rCanvas
,
497 const OutDevState
& rState
)
499 return ActionSharedPtr( new TransparencyGroupAction(rGroupMtf
,
507 SAL_WNODEPRECATED_DECLARATIONS_POP
512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */