Bump for 3.6-28
[LibreOffice.git] / cppcanvas / source / mtfrenderer / transparencygroupaction.cxx
blob69b5173f589e4921493e18940158d8c84d5bb466
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;
70 namespace cppcanvas
72 namespace internal
74 // free support functions
75 // ======================
76 namespace
78 class TransparencyGroupAction : public Action, private ::boost::noncopyable
80 public:
81 /** Create new transparency group action.
83 @param rGroupMtf
84 Metafile that groups all actions to be rendered
85 transparent.
87 @param rAlphaGradient
88 VCL gradient, to be rendered into the action's alpha
89 channel.
91 @param rParms
92 Render parameters
94 @param rDstPoint
95 Left, top edge of destination, in current state
96 coordinate system
98 @param rDstSize
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;
120 private:
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(),
150 rDstPoint.getY() );
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 ),
165 maParms( rParms ),
166 maDstSize( rDstSize ),
167 mxBufferBitmap(),
168 maLastTransformation(),
169 mpCanvas( rCanvas ),
170 maState(),
171 mnAlpha( 1.0 )
173 tools::initRenderState(maState,rState);
174 implSetupTransform( maState, rDstPoint );
176 // correct clip (which is relative to original transform)
177 tools::modifyClip( maState,
178 rState,
179 rCanvas,
180 rDstPoint,
181 NULL,
182 NULL );
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
195 // implementation.
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
219 // large enough
220 ::basegfx::B2DTuple aScale;
221 ::basegfx::B2DTuple aTranslate;
222 double nRotate;
223 double nShearX;
224 if( !aTotalTransform.decompose( aScale,
225 aTranslate,
226 nRotate,
227 nShearX ) )
229 OSL_FAIL( "TransparencyGroupAction::renderSubset(): non-decomposable transformation" );
230 return false;
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 );
251 ::Point aEmptyPoint;
253 // render our content into an appropriately sized
254 // VirtualDevice with alpha channel
255 VirtualDevice aVDev(
256 *::Application::GetDefaultDevice(), 0, 0 );
257 aVDev.SetOutputSizePixel( aBitmapSizePixel );
258 aVDev.SetMapMode();
260 if( rSubset.mnSubsetBegin != 0 ||
261 rSubset.mnSubsetEnd != -1 )
263 // true subset - extract referenced
264 // metaactions from mpGroupMtf
265 GDIMetaFile aMtf;
266 MetaAction* pCurrAct;
267 int nCurrActionIndex;
269 // extract subset actions
270 for( nCurrActionIndex=0,
271 pCurrAct=mpGroupMtf->FirstAction();
272 pCurrAct;
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() );
295 break;
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
334 // requested subset
335 if( rSubset.mnSubsetBegin <= nCurrActionIndex &&
336 rSubset.mnSubsetEnd > nCurrActionIndex )
338 aMtf.AddAction( pCurrAct->Clone() );
340 break;
342 default:
343 OSL_FAIL( "Unknown meta action type encountered" );
344 break;
348 aVDev.DrawTransparent( aMtf,
349 aEmptyPoint,
350 aOutputSizePixel,
351 *mpAlphaGradient );
353 else
355 // no subsetting - render whole mtf
356 aVDev.DrawTransparent( *mpGroupMtf,
357 aEmptyPoint,
358 aOutputSizePixel,
359 *mpAlphaGradient );
363 // update buffered bitmap and transformation
364 BitmapSharedPtr aBmp( VCLFactory::getInstance().createBitmap(
365 mpCanvas,
366 aVDev.GetBitmapEx(
367 aEmptyPoint,
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
378 // transformation))
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
389 // the inverse.
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(),
407 aLocalState );
409 aLocalState.DeviceColor = maState.DeviceColor;
410 #endif
412 if( ::rtl::math::approxEqual(mnAlpha, 1.0) )
414 // no further alpha changes necessary -> draw directly
415 mpCanvas->getUNOCanvas()->drawBitmap( mxBufferBitmap,
416 mpCanvas->getViewState(),
417 aLocalState );
419 else
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(
426 aCols);
428 mpCanvas->getUNOCanvas()->drawBitmapModulated( mxBufferBitmap,
429 mpCanvas->getViewState(),
430 aLocalState );
433 return true;
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
442 // implementation.
443 bool TransparencyGroupAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
445 Subset aSubset;
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,
460 maDstSize.getX(),
461 maDstSize.getY() ),
462 mpCanvas->getViewState(),
463 aLocalState );
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
472 // true subsets.
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,
500 rAlphaGradient,
501 rParms,
502 rDstPoint,
503 rDstSize,
504 rCanvas,
505 rState ) );
507 SAL_WNODEPRECATED_DECLARATIONS_POP
512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */