xref: /AOO41X/main/slideshow/source/engine/shapes/viewshape.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_slideshow.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir // must be first
32*cdf0e10cSrcweir #include <canvas/debug.hxx>
33*cdf0e10cSrcweir #include <tools/diagnose_ex.h>
34*cdf0e10cSrcweir 
35*cdf0e10cSrcweir #include <math.h>
36*cdf0e10cSrcweir 
37*cdf0e10cSrcweir #include <rtl/logfile.hxx>
38*cdf0e10cSrcweir #include <rtl/math.hxx>
39*cdf0e10cSrcweir 
40*cdf0e10cSrcweir #include <com/sun/star/rendering/XCanvas.hpp>
41*cdf0e10cSrcweir #include <com/sun/star/rendering/XIntegerBitmap.hpp>
42*cdf0e10cSrcweir #include <com/sun/star/rendering/PanoseLetterForm.hpp>
43*cdf0e10cSrcweir #include <com/sun/star/awt/FontSlant.hpp>
44*cdf0e10cSrcweir 
45*cdf0e10cSrcweir #include <cppuhelper/exc_hlp.hxx>
46*cdf0e10cSrcweir #include <comphelper/anytostring.hxx>
47*cdf0e10cSrcweir 
48*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
49*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx>
50*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx>
51*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrixtools.hxx>
52*cdf0e10cSrcweir 
53*cdf0e10cSrcweir #include <canvas/verbosetrace.hxx>
54*cdf0e10cSrcweir #include <canvas/canvastools.hxx>
55*cdf0e10cSrcweir #include <cppcanvas/vclfactory.hxx>
56*cdf0e10cSrcweir #include <cppcanvas/basegfxfactory.hxx>
57*cdf0e10cSrcweir 
58*cdf0e10cSrcweir #include "viewshape.hxx"
59*cdf0e10cSrcweir #include "tools.hxx"
60*cdf0e10cSrcweir 
61*cdf0e10cSrcweir #include <boost/bind.hpp>
62*cdf0e10cSrcweir 
63*cdf0e10cSrcweir 
64*cdf0e10cSrcweir using namespace ::com::sun::star;
65*cdf0e10cSrcweir 
66*cdf0e10cSrcweir namespace slideshow
67*cdf0e10cSrcweir {
68*cdf0e10cSrcweir     namespace internal
69*cdf0e10cSrcweir     {
70*cdf0e10cSrcweir 
71*cdf0e10cSrcweir         // TODO(F2): Provide sensible setup for mtf-related attributes (fill mode,
72*cdf0e10cSrcweir         // char rotation etc.). Do that via mtf argument at this object
73*cdf0e10cSrcweir 
74*cdf0e10cSrcweir         bool ViewShape::prefetch( RendererCacheEntry&					io_rCacheEntry,
75*cdf0e10cSrcweir                                   const ::cppcanvas::CanvasSharedPtr&	rDestinationCanvas,
76*cdf0e10cSrcweir                                   const GDIMetaFileSharedPtr&			rMtf,
77*cdf0e10cSrcweir                                   const ShapeAttributeLayerSharedPtr&	rAttr ) const
78*cdf0e10cSrcweir         {
79*cdf0e10cSrcweir             RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::prefetch()" );
80*cdf0e10cSrcweir             ENSURE_OR_RETURN_FALSE( rMtf,
81*cdf0e10cSrcweir                                "ViewShape::prefetch(): no valid metafile!" );
82*cdf0e10cSrcweir 
83*cdf0e10cSrcweir             if( rMtf != io_rCacheEntry.mpMtf ||
84*cdf0e10cSrcweir                 rDestinationCanvas != io_rCacheEntry.getDestinationCanvas() )
85*cdf0e10cSrcweir             {
86*cdf0e10cSrcweir                 // buffered renderer invalid, re-create
87*cdf0e10cSrcweir                 ::cppcanvas::Renderer::Parameters aParms;
88*cdf0e10cSrcweir 
89*cdf0e10cSrcweir                 // rendering attribute override parameter struct.  For
90*cdf0e10cSrcweir                 // every valid attribute, the corresponding struct
91*cdf0e10cSrcweir                 // member is filled, which in the metafile renderer
92*cdf0e10cSrcweir                 // forces rendering with the given attribute.
93*cdf0e10cSrcweir                 if( rAttr )
94*cdf0e10cSrcweir                 {
95*cdf0e10cSrcweir                     if( rAttr->isFillColorValid() )
96*cdf0e10cSrcweir                     {
97*cdf0e10cSrcweir                         // convert RGBColor to RGBA32 integer. Note
98*cdf0e10cSrcweir                         // that getIntegerColor() also truncates
99*cdf0e10cSrcweir                         // out-of-range values appropriately
100*cdf0e10cSrcweir                         aParms.maFillColor =
101*cdf0e10cSrcweir                             rAttr->getFillColor().getIntegerColor();
102*cdf0e10cSrcweir                     }
103*cdf0e10cSrcweir                     if( rAttr->isLineColorValid() )
104*cdf0e10cSrcweir                     {
105*cdf0e10cSrcweir                         // convert RGBColor to RGBA32 integer. Note
106*cdf0e10cSrcweir                         // that getIntegerColor() also truncates
107*cdf0e10cSrcweir                         // out-of-range values appropriately
108*cdf0e10cSrcweir                         aParms.maLineColor =
109*cdf0e10cSrcweir                             rAttr->getLineColor().getIntegerColor();
110*cdf0e10cSrcweir                     }
111*cdf0e10cSrcweir                     if( rAttr->isCharColorValid() )
112*cdf0e10cSrcweir                     {
113*cdf0e10cSrcweir                         // convert RGBColor to RGBA32 integer. Note
114*cdf0e10cSrcweir                         // that getIntegerColor() also truncates
115*cdf0e10cSrcweir                         // out-of-range values appropriately
116*cdf0e10cSrcweir                         aParms.maTextColor =
117*cdf0e10cSrcweir                             rAttr->getCharColor().getIntegerColor();
118*cdf0e10cSrcweir                     }
119*cdf0e10cSrcweir                     if( rAttr->isDimColorValid() )
120*cdf0e10cSrcweir                     {
121*cdf0e10cSrcweir                         // convert RGBColor to RGBA32 integer. Note
122*cdf0e10cSrcweir                         // that getIntegerColor() also truncates
123*cdf0e10cSrcweir                         // out-of-range values appropriately
124*cdf0e10cSrcweir 
125*cdf0e10cSrcweir                         // dim color overrides all other colors
126*cdf0e10cSrcweir                         aParms.maFillColor =
127*cdf0e10cSrcweir                         aParms.maLineColor =
128*cdf0e10cSrcweir                         aParms.maTextColor =
129*cdf0e10cSrcweir                             rAttr->getDimColor().getIntegerColor();
130*cdf0e10cSrcweir                     }
131*cdf0e10cSrcweir                     if( rAttr->isFontFamilyValid() )
132*cdf0e10cSrcweir                     {
133*cdf0e10cSrcweir                         aParms.maFontName =
134*cdf0e10cSrcweir                             rAttr->getFontFamily();
135*cdf0e10cSrcweir                     }
136*cdf0e10cSrcweir                     if( rAttr->isCharScaleValid() )
137*cdf0e10cSrcweir                     {
138*cdf0e10cSrcweir                         ::basegfx::B2DHomMatrix aMatrix;
139*cdf0e10cSrcweir 
140*cdf0e10cSrcweir                         // enlarge text by given scale factor. Do that
141*cdf0e10cSrcweir                         // with the middle of the shape as the center
142*cdf0e10cSrcweir                         // of scaling.
143*cdf0e10cSrcweir                         aMatrix.translate( -0.5, -0.5 );
144*cdf0e10cSrcweir                         aMatrix.scale( rAttr->getCharScale(),
145*cdf0e10cSrcweir                                        rAttr->getCharScale() );
146*cdf0e10cSrcweir                         aMatrix.translate( 0.5, 0.5 );
147*cdf0e10cSrcweir 
148*cdf0e10cSrcweir                         aParms.maTextTransformation = aMatrix;
149*cdf0e10cSrcweir                     }
150*cdf0e10cSrcweir                     if( rAttr->isCharWeightValid() )
151*cdf0e10cSrcweir                     {
152*cdf0e10cSrcweir                         aParms.maFontWeight =
153*cdf0e10cSrcweir                             static_cast< sal_Int8 >(
154*cdf0e10cSrcweir                                 ::basegfx::fround(
155*cdf0e10cSrcweir                                     ::std::max( 0.0,
156*cdf0e10cSrcweir                                                 ::std::min( 11.0,
157*cdf0e10cSrcweir                                                             rAttr->getCharWeight() / 20.0 ) ) ) );
158*cdf0e10cSrcweir                     }
159*cdf0e10cSrcweir                     if( rAttr->isCharPostureValid() )
160*cdf0e10cSrcweir                     {
161*cdf0e10cSrcweir                         aParms.maFontLetterForm =
162*cdf0e10cSrcweir                             rAttr->getCharPosture() == awt::FontSlant_NONE ?
163*cdf0e10cSrcweir                             rendering::PanoseLetterForm::ANYTHING :
164*cdf0e10cSrcweir                             rendering::PanoseLetterForm::OBLIQUE_CONTACT;
165*cdf0e10cSrcweir                     }
166*cdf0e10cSrcweir                     if( rAttr->isUnderlineModeValid() )
167*cdf0e10cSrcweir                     {
168*cdf0e10cSrcweir                         aParms.maFontUnderline =
169*cdf0e10cSrcweir                             rAttr->getUnderlineMode();
170*cdf0e10cSrcweir                     }
171*cdf0e10cSrcweir                 }
172*cdf0e10cSrcweir 
173*cdf0e10cSrcweir                 io_rCacheEntry.mpRenderer = ::cppcanvas::VCLFactory::getInstance().createRenderer( rDestinationCanvas,
174*cdf0e10cSrcweir                                                                                                    *rMtf.get(),
175*cdf0e10cSrcweir                                                                                                    aParms );
176*cdf0e10cSrcweir 
177*cdf0e10cSrcweir                 io_rCacheEntry.mpMtf      		   = rMtf;
178*cdf0e10cSrcweir                 io_rCacheEntry.mpDestinationCanvas = rDestinationCanvas;
179*cdf0e10cSrcweir 
180*cdf0e10cSrcweir                 // also invalidate alpha compositing bitmap (created
181*cdf0e10cSrcweir                 // new renderer, which possibly generates different
182*cdf0e10cSrcweir                 // output). Do NOT invalidate, if we're incidentally
183*cdf0e10cSrcweir                 // rendering INTO it.
184*cdf0e10cSrcweir                 if( rDestinationCanvas != io_rCacheEntry.mpLastBitmapCanvas )
185*cdf0e10cSrcweir                 {
186*cdf0e10cSrcweir                     io_rCacheEntry.mpLastBitmapCanvas.reset();
187*cdf0e10cSrcweir                     io_rCacheEntry.mpLastBitmap.reset();
188*cdf0e10cSrcweir                 }
189*cdf0e10cSrcweir             }
190*cdf0e10cSrcweir 
191*cdf0e10cSrcweir             return io_rCacheEntry.mpRenderer;
192*cdf0e10cSrcweir         }
193*cdf0e10cSrcweir 
194*cdf0e10cSrcweir         bool ViewShape::draw( const ::cppcanvas::CanvasSharedPtr&	rDestinationCanvas,
195*cdf0e10cSrcweir                               const GDIMetaFileSharedPtr&			rMtf,
196*cdf0e10cSrcweir                               const ShapeAttributeLayerSharedPtr&	rAttr,
197*cdf0e10cSrcweir                               const ::basegfx::B2DHomMatrix&		rTransform,
198*cdf0e10cSrcweir                               const ::basegfx::B2DPolyPolygon*		pClip,
199*cdf0e10cSrcweir                               const VectorOfDocTreeNodes&			rSubsets ) const
200*cdf0e10cSrcweir         {
201*cdf0e10cSrcweir             RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::draw()" );
202*cdf0e10cSrcweir 
203*cdf0e10cSrcweir             ::cppcanvas::RendererSharedPtr pRenderer(
204*cdf0e10cSrcweir                 getRenderer( rDestinationCanvas, rMtf, rAttr ) );
205*cdf0e10cSrcweir 
206*cdf0e10cSrcweir             ENSURE_OR_RETURN_FALSE( pRenderer, "ViewShape::draw(): Invalid renderer" );
207*cdf0e10cSrcweir 
208*cdf0e10cSrcweir             pRenderer->setTransformation( rTransform );
209*cdf0e10cSrcweir #if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0
210*cdf0e10cSrcweir             rendering::RenderState aRenderState;
211*cdf0e10cSrcweir             ::canvas::tools::initRenderState(aRenderState);
212*cdf0e10cSrcweir             ::canvas::tools::setRenderStateTransform(aRenderState,
213*cdf0e10cSrcweir                                                      rTransform);
214*cdf0e10cSrcweir             aRenderState.DeviceColor.realloc(4);
215*cdf0e10cSrcweir             aRenderState.DeviceColor[0] = 1.0;
216*cdf0e10cSrcweir             aRenderState.DeviceColor[1] = 0.0;
217*cdf0e10cSrcweir             aRenderState.DeviceColor[2] = 0.0;
218*cdf0e10cSrcweir             aRenderState.DeviceColor[3] = 1.0;
219*cdf0e10cSrcweir 
220*cdf0e10cSrcweir             try
221*cdf0e10cSrcweir             {
222*cdf0e10cSrcweir                 rDestinationCanvas->getUNOCanvas()->drawLine( geometry::RealPoint2D(0.0,0.0),
223*cdf0e10cSrcweir                                                               geometry::RealPoint2D(1.0,1.0),
224*cdf0e10cSrcweir                                                               rDestinationCanvas->getViewState(),
225*cdf0e10cSrcweir                                                               aRenderState );
226*cdf0e10cSrcweir                 rDestinationCanvas->getUNOCanvas()->drawLine( geometry::RealPoint2D(1.0,0.0),
227*cdf0e10cSrcweir                                                               geometry::RealPoint2D(0.0,1.0),
228*cdf0e10cSrcweir                                                               rDestinationCanvas->getViewState(),
229*cdf0e10cSrcweir                                                               aRenderState );
230*cdf0e10cSrcweir             }
231*cdf0e10cSrcweir             catch( uno::Exception& )
232*cdf0e10cSrcweir             {
233*cdf0e10cSrcweir                 DBG_UNHANDLED_EXCEPTION();
234*cdf0e10cSrcweir             }
235*cdf0e10cSrcweir #endif
236*cdf0e10cSrcweir             if( pClip )
237*cdf0e10cSrcweir                 pRenderer->setClip( *pClip );
238*cdf0e10cSrcweir             else
239*cdf0e10cSrcweir                 pRenderer->setClip();
240*cdf0e10cSrcweir 
241*cdf0e10cSrcweir             if( rSubsets.empty() )
242*cdf0e10cSrcweir             {
243*cdf0e10cSrcweir                 return pRenderer->draw();
244*cdf0e10cSrcweir             }
245*cdf0e10cSrcweir             else
246*cdf0e10cSrcweir             {
247*cdf0e10cSrcweir                 // render subsets of whole metafile
248*cdf0e10cSrcweir                 // --------------------------------
249*cdf0e10cSrcweir 
250*cdf0e10cSrcweir                 bool bRet(true);
251*cdf0e10cSrcweir                 VectorOfDocTreeNodes::const_iterator 		aIter( rSubsets.begin() );
252*cdf0e10cSrcweir                 const VectorOfDocTreeNodes::const_iterator	aEnd ( rSubsets.end() );
253*cdf0e10cSrcweir                 while( aIter != aEnd )
254*cdf0e10cSrcweir                 {
255*cdf0e10cSrcweir                     if( !pRenderer->drawSubset( aIter->getStartIndex(),
256*cdf0e10cSrcweir                                                 aIter->getEndIndex() ) )
257*cdf0e10cSrcweir                         bRet = false;
258*cdf0e10cSrcweir 
259*cdf0e10cSrcweir                     ++aIter;
260*cdf0e10cSrcweir                 }
261*cdf0e10cSrcweir 
262*cdf0e10cSrcweir                 return bRet;
263*cdf0e10cSrcweir             }
264*cdf0e10cSrcweir         }
265*cdf0e10cSrcweir 
266*cdf0e10cSrcweir         namespace
267*cdf0e10cSrcweir         {
268*cdf0e10cSrcweir             /// Convert untransformed shape update area to device pixel.
269*cdf0e10cSrcweir             ::basegfx::B2DRectangle shapeArea2AreaPixel( const ::basegfx::B2DHomMatrix&	rCanvasTransformation,
270*cdf0e10cSrcweir                                                          const ::basegfx::B2DRectangle&	rUntransformedArea		)
271*cdf0e10cSrcweir             {
272*cdf0e10cSrcweir                 // convert area to pixel, and add anti-aliasing border
273*cdf0e10cSrcweir 
274*cdf0e10cSrcweir                 // TODO(P1): Should the view transform some
275*cdf0e10cSrcweir                 // day contain rotation/shear, transforming
276*cdf0e10cSrcweir                 // the original bounds with the total
277*cdf0e10cSrcweir                 // transformation might result in smaller
278*cdf0e10cSrcweir                 // overall bounds.
279*cdf0e10cSrcweir 
280*cdf0e10cSrcweir                 ::basegfx::B2DRectangle aBoundsPixel;
281*cdf0e10cSrcweir                 ::canvas::tools::calcTransformedRectBounds( aBoundsPixel,
282*cdf0e10cSrcweir                                                             rUntransformedArea,
283*cdf0e10cSrcweir                                                             rCanvasTransformation );
284*cdf0e10cSrcweir 
285*cdf0e10cSrcweir                 // add antialiasing border around the shape (AA
286*cdf0e10cSrcweir                 // touches pixel _outside_ the nominal bound rect)
287*cdf0e10cSrcweir                 aBoundsPixel.grow( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE );
288*cdf0e10cSrcweir 
289*cdf0e10cSrcweir                 return aBoundsPixel;
290*cdf0e10cSrcweir             }
291*cdf0e10cSrcweir 
292*cdf0e10cSrcweir             /// Convert shape unit rect to device pixel.
293*cdf0e10cSrcweir             ::basegfx::B2DRectangle calcUpdateAreaPixel( const ::basegfx::B2DRectangle& 		rUnitBounds,
294*cdf0e10cSrcweir                                                          const ::basegfx::B2DHomMatrix& 		rShapeTransformation,
295*cdf0e10cSrcweir                                                          const ::basegfx::B2DHomMatrix&			rCanvasTransformation,
296*cdf0e10cSrcweir                                                          const ShapeAttributeLayerSharedPtr&	pAttr					)
297*cdf0e10cSrcweir             {
298*cdf0e10cSrcweir                 // calc update area for whole shape (including
299*cdf0e10cSrcweir                 // character scaling)
300*cdf0e10cSrcweir                 return shapeArea2AreaPixel( rCanvasTransformation,
301*cdf0e10cSrcweir                                             getShapeUpdateArea( rUnitBounds,
302*cdf0e10cSrcweir                                                                 rShapeTransformation,
303*cdf0e10cSrcweir                                                                 pAttr ) );
304*cdf0e10cSrcweir             }
305*cdf0e10cSrcweir         }
306*cdf0e10cSrcweir 
307*cdf0e10cSrcweir         bool ViewShape::renderSprite( const ViewLayerSharedPtr&             rViewLayer,
308*cdf0e10cSrcweir                                       const GDIMetaFileSharedPtr&			rMtf,
309*cdf0e10cSrcweir                                       const ::basegfx::B2DRectangle&		rOrigBounds,
310*cdf0e10cSrcweir                                       const ::basegfx::B2DRectangle&		rBounds,
311*cdf0e10cSrcweir                                       const ::basegfx::B2DRectangle&		rUnitBounds,
312*cdf0e10cSrcweir                                       int									nUpdateFlags,
313*cdf0e10cSrcweir                                       const ShapeAttributeLayerSharedPtr&	pAttr,
314*cdf0e10cSrcweir                                       const VectorOfDocTreeNodes&			rSubsets,
315*cdf0e10cSrcweir                                       double                                nPrio,
316*cdf0e10cSrcweir                                       bool 									bIsVisible ) const
317*cdf0e10cSrcweir         {
318*cdf0e10cSrcweir             RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::renderSprite()" );
319*cdf0e10cSrcweir 
320*cdf0e10cSrcweir             // TODO(P1): For multiple views, it might pay off to reorg Shape and ViewShape,
321*cdf0e10cSrcweir             // in that all the common setup steps here are refactored to Shape (would then
322*cdf0e10cSrcweir             // have to be performed only _once_ per Shape paint).
323*cdf0e10cSrcweir 
324*cdf0e10cSrcweir             if( !bIsVisible ||
325*cdf0e10cSrcweir                 rUnitBounds.isEmpty() ||
326*cdf0e10cSrcweir                 rOrigBounds.isEmpty() ||
327*cdf0e10cSrcweir                 rBounds.isEmpty() )
328*cdf0e10cSrcweir             {
329*cdf0e10cSrcweir                 // shape is invisible or has zero size, no need to
330*cdf0e10cSrcweir                 // update anything.
331*cdf0e10cSrcweir                 if( mpSprite )
332*cdf0e10cSrcweir                     mpSprite->hide();
333*cdf0e10cSrcweir 
334*cdf0e10cSrcweir                 return true;
335*cdf0e10cSrcweir             }
336*cdf0e10cSrcweir 
337*cdf0e10cSrcweir 
338*cdf0e10cSrcweir             // calc sprite position, size and content transformation
339*cdf0e10cSrcweir             // =====================================================
340*cdf0e10cSrcweir 
341*cdf0e10cSrcweir             // the shape transformation for a sprite is always a
342*cdf0e10cSrcweir             // simple scale-up to the nominal shape size. Everything
343*cdf0e10cSrcweir             // else is handled via the sprite transformation
344*cdf0e10cSrcweir             ::basegfx::B2DHomMatrix aNonTranslationalShapeTransformation;
345*cdf0e10cSrcweir             aNonTranslationalShapeTransformation.scale( rOrigBounds.getWidth(),
346*cdf0e10cSrcweir                                                         rOrigBounds.getHeight() );
347*cdf0e10cSrcweir             ::basegfx::B2DHomMatrix aShapeTransformation( aNonTranslationalShapeTransformation );
348*cdf0e10cSrcweir             aShapeTransformation.translate( rOrigBounds.getMinX(),
349*cdf0e10cSrcweir                                             rOrigBounds.getMinY() );
350*cdf0e10cSrcweir 
351*cdf0e10cSrcweir             const ::basegfx::B2DHomMatrix& rCanvasTransform(
352*cdf0e10cSrcweir                 rViewLayer->getSpriteTransformation() );
353*cdf0e10cSrcweir 
354*cdf0e10cSrcweir             // area actually needed for the sprite
355*cdf0e10cSrcweir             const ::basegfx::B2DRectangle& rSpriteBoundsPixel(
356*cdf0e10cSrcweir                 calcUpdateAreaPixel( rUnitBounds,
357*cdf0e10cSrcweir                                      aShapeTransformation,
358*cdf0e10cSrcweir                                      rCanvasTransform,
359*cdf0e10cSrcweir                                      pAttr ) );
360*cdf0e10cSrcweir 
361*cdf0e10cSrcweir             // actual area for the shape (without subsetting, but
362*cdf0e10cSrcweir             // including char scaling)
363*cdf0e10cSrcweir             const ::basegfx::B2DRectangle& rShapeBoundsPixel(
364*cdf0e10cSrcweir                 calcUpdateAreaPixel( ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0),
365*cdf0e10cSrcweir                                      aShapeTransformation,
366*cdf0e10cSrcweir                                      rCanvasTransform,
367*cdf0e10cSrcweir                                      pAttr ) );
368*cdf0e10cSrcweir 
369*cdf0e10cSrcweir             // nominal area for the shape (without subsetting, without
370*cdf0e10cSrcweir             // char scaling). NOTE: to cancel the shape translation,
371*cdf0e10cSrcweir             // contained in rSpriteBoundsPixel, this is _without_ any
372*cdf0e10cSrcweir             // translational component (fixed along with #121921#).
373*cdf0e10cSrcweir             ::basegfx::B2DRectangle		   aLogShapeBounds;
374*cdf0e10cSrcweir             const ::basegfx::B2DRectangle& rNominalShapeBoundsPixel(
375*cdf0e10cSrcweir                 shapeArea2AreaPixel( rCanvasTransform,
376*cdf0e10cSrcweir                                      ::canvas::tools::calcTransformedRectBounds(
377*cdf0e10cSrcweir                                          aLogShapeBounds,
378*cdf0e10cSrcweir                                          ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0),
379*cdf0e10cSrcweir                                          aNonTranslationalShapeTransformation ) ) );
380*cdf0e10cSrcweir 
381*cdf0e10cSrcweir             // create (or resize) sprite with sprite's pixel size, if
382*cdf0e10cSrcweir             // not done already
383*cdf0e10cSrcweir             const ::basegfx::B2DSize& rSpriteSizePixel(rSpriteBoundsPixel.getRange());
384*cdf0e10cSrcweir             if( !mpSprite )
385*cdf0e10cSrcweir             {
386*cdf0e10cSrcweir                 mpSprite.reset(
387*cdf0e10cSrcweir                     new AnimatedSprite( mpViewLayer,
388*cdf0e10cSrcweir                                         rSpriteSizePixel,
389*cdf0e10cSrcweir                                         nPrio ));
390*cdf0e10cSrcweir             }
391*cdf0e10cSrcweir             else
392*cdf0e10cSrcweir             {
393*cdf0e10cSrcweir                 // TODO(F2): when the sprite _actually_ gets resized,
394*cdf0e10cSrcweir                 // content needs a repaint!
395*cdf0e10cSrcweir                 mpSprite->resize( rSpriteSizePixel );
396*cdf0e10cSrcweir             }
397*cdf0e10cSrcweir 
398*cdf0e10cSrcweir             ENSURE_OR_RETURN_FALSE( mpSprite, "ViewShape::renderSprite(): No sprite" );
399*cdf0e10cSrcweir 
400*cdf0e10cSrcweir             VERBOSE_TRACE( "ViewShape::renderSprite(): Rendering sprite 0x%X",
401*cdf0e10cSrcweir                            mpSprite.get() );
402*cdf0e10cSrcweir 
403*cdf0e10cSrcweir 
404*cdf0e10cSrcweir             // always show the sprite (might have been hidden before)
405*cdf0e10cSrcweir             mpSprite->show();
406*cdf0e10cSrcweir 
407*cdf0e10cSrcweir             // determine center of sprite output position in pixel
408*cdf0e10cSrcweir             // (assumption here: all shape transformations have the
409*cdf0e10cSrcweir             // shape center as the pivot point). From that, subtract
410*cdf0e10cSrcweir             // distance of rSpriteBoundsPixel's left, top edge from
411*cdf0e10cSrcweir             // rShapeBoundsPixel's center. This moves the sprite at
412*cdf0e10cSrcweir             // the appropriate output position within the virtual
413*cdf0e10cSrcweir             // rShapeBoundsPixel area.
414*cdf0e10cSrcweir             ::basegfx::B2DPoint aSpritePosPixel( rBounds.getCenter() );
415*cdf0e10cSrcweir             aSpritePosPixel *= rCanvasTransform;
416*cdf0e10cSrcweir             aSpritePosPixel -= rShapeBoundsPixel.getCenter() - rSpriteBoundsPixel.getMinimum();
417*cdf0e10cSrcweir 
418*cdf0e10cSrcweir             // the difference between rShapeBoundsPixel and
419*cdf0e10cSrcweir             // rSpriteBoundsPixel upper, left corner is: the offset we
420*cdf0e10cSrcweir             // have to move sprite output to the right, top (to make
421*cdf0e10cSrcweir             // the desired subset content visible at all)
422*cdf0e10cSrcweir             const ::basegfx::B2DSize& rSpriteCorrectionOffset(
423*cdf0e10cSrcweir                 rSpriteBoundsPixel.getMinimum() - rNominalShapeBoundsPixel.getMinimum() );
424*cdf0e10cSrcweir 
425*cdf0e10cSrcweir             // offset added top, left for anti-aliasing (otherwise,
426*cdf0e10cSrcweir             // shapes fully filling the sprite will have anti-aliased
427*cdf0e10cSrcweir             // pixel cut off)
428*cdf0e10cSrcweir             const ::basegfx::B2DSize aAAOffset(
429*cdf0e10cSrcweir                 ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE,
430*cdf0e10cSrcweir                 ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE );
431*cdf0e10cSrcweir 
432*cdf0e10cSrcweir             // set pixel output offset to sprite: we always leave
433*cdf0e10cSrcweir             // ANTIALIASING_EXTRA_SIZE room atop and to the left, and,
434*cdf0e10cSrcweir             // what's more, for subsetted shapes, we _have_ to cancel
435*cdf0e10cSrcweir             // the effect of the shape renderer outputting the subset
436*cdf0e10cSrcweir             // at its absolute position inside the shape, instead of
437*cdf0e10cSrcweir             // at the origin.
438*cdf0e10cSrcweir             // NOTE: As for now, sprites are always positioned on
439*cdf0e10cSrcweir             // integer pixel positions on screen, have to round to
440*cdf0e10cSrcweir             // nearest integer here, too (fixed along with #121921#)
441*cdf0e10cSrcweir             mpSprite->setPixelOffset(
442*cdf0e10cSrcweir                 aAAOffset - ::basegfx::B2DSize(
443*cdf0e10cSrcweir                     ::basegfx::fround( rSpriteCorrectionOffset.getX() ),
444*cdf0e10cSrcweir                     ::basegfx::fround( rSpriteCorrectionOffset.getY() ) ) );
445*cdf0e10cSrcweir 
446*cdf0e10cSrcweir             // always set sprite position and transformation, since
447*cdf0e10cSrcweir             // they do not relate directly to the update flags
448*cdf0e10cSrcweir             // (e.g. sprite position changes when sprite size changes)
449*cdf0e10cSrcweir             mpSprite->movePixel( aSpritePosPixel );
450*cdf0e10cSrcweir             mpSprite->transform( getSpriteTransformation( rSpriteSizePixel,
451*cdf0e10cSrcweir                                                           rOrigBounds.getRange(),
452*cdf0e10cSrcweir                                                           pAttr ) );
453*cdf0e10cSrcweir 
454*cdf0e10cSrcweir 
455*cdf0e10cSrcweir             // process flags
456*cdf0e10cSrcweir             // =============
457*cdf0e10cSrcweir 
458*cdf0e10cSrcweir             bool bRedrawRequired( mbForceUpdate || (nUpdateFlags & FORCE) );
459*cdf0e10cSrcweir 
460*cdf0e10cSrcweir             if( mbForceUpdate || (nUpdateFlags & ALPHA) )
461*cdf0e10cSrcweir             {
462*cdf0e10cSrcweir                 mpSprite->setAlpha( (pAttr && pAttr->isAlphaValid()) ?
463*cdf0e10cSrcweir                                     ::basegfx::clamp(pAttr->getAlpha(),
464*cdf0e10cSrcweir                                                      0.0,
465*cdf0e10cSrcweir                                                      1.0) :
466*cdf0e10cSrcweir                                     1.0 );
467*cdf0e10cSrcweir             }
468*cdf0e10cSrcweir             if( mbForceUpdate || (nUpdateFlags & CLIP) )
469*cdf0e10cSrcweir             {
470*cdf0e10cSrcweir                 if( pAttr && pAttr->isClipValid() )
471*cdf0e10cSrcweir                 {
472*cdf0e10cSrcweir                     ::basegfx::B2DPolyPolygon aClipPoly( pAttr->getClip() );
473*cdf0e10cSrcweir 
474*cdf0e10cSrcweir                     // extract linear part of canvas view transformation
475*cdf0e10cSrcweir                     // (linear means: without translational components)
476*cdf0e10cSrcweir                     ::basegfx::B2DHomMatrix aViewTransform(
477*cdf0e10cSrcweir                         mpViewLayer->getTransformation() );
478*cdf0e10cSrcweir                     aViewTransform.set( 0, 2, 0.0 );
479*cdf0e10cSrcweir                     aViewTransform.set( 1, 2, 0.0 );
480*cdf0e10cSrcweir 
481*cdf0e10cSrcweir                     // make the clip 2*ANTIALIASING_EXTRA_SIZE larger
482*cdf0e10cSrcweir                     // such that it's again centered over the sprite.
483*cdf0e10cSrcweir                     aViewTransform.scale(rSpriteSizePixel.getX()/
484*cdf0e10cSrcweir                                          (rSpriteSizePixel.getX()-2*::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE),
485*cdf0e10cSrcweir                                          rSpriteSizePixel.getY()/
486*cdf0e10cSrcweir                                          (rSpriteSizePixel.getY()-2*::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE));
487*cdf0e10cSrcweir 
488*cdf0e10cSrcweir                     // transform clip polygon from view to device
489*cdf0e10cSrcweir                     // coordinate space
490*cdf0e10cSrcweir                     aClipPoly.transform( aViewTransform );
491*cdf0e10cSrcweir 
492*cdf0e10cSrcweir                     mpSprite->clip( aClipPoly );
493*cdf0e10cSrcweir                 }
494*cdf0e10cSrcweir                 else
495*cdf0e10cSrcweir                     mpSprite->clip();
496*cdf0e10cSrcweir             }
497*cdf0e10cSrcweir             if( mbForceUpdate || (nUpdateFlags & CONTENT) )
498*cdf0e10cSrcweir             {
499*cdf0e10cSrcweir                 bRedrawRequired = true;
500*cdf0e10cSrcweir 
501*cdf0e10cSrcweir                 // TODO(P1): maybe provide some appearance change methods at
502*cdf0e10cSrcweir                 // the Renderer interface
503*cdf0e10cSrcweir 
504*cdf0e10cSrcweir                 // force the renderer to be regenerated below, for the
505*cdf0e10cSrcweir                 // different attributes to take effect
506*cdf0e10cSrcweir                 invalidateRenderer();
507*cdf0e10cSrcweir             }
508*cdf0e10cSrcweir 
509*cdf0e10cSrcweir             mbForceUpdate = false;
510*cdf0e10cSrcweir 
511*cdf0e10cSrcweir             if( !bRedrawRequired )
512*cdf0e10cSrcweir                 return true;
513*cdf0e10cSrcweir 
514*cdf0e10cSrcweir 
515*cdf0e10cSrcweir             // sprite needs repaint - output to sprite canvas
516*cdf0e10cSrcweir             // ==============================================
517*cdf0e10cSrcweir 
518*cdf0e10cSrcweir             ::cppcanvas::CanvasSharedPtr pContentCanvas( mpSprite->getContentCanvas() );
519*cdf0e10cSrcweir 
520*cdf0e10cSrcweir             return draw( pContentCanvas,
521*cdf0e10cSrcweir                          rMtf,
522*cdf0e10cSrcweir                          pAttr,
523*cdf0e10cSrcweir                          aShapeTransformation,
524*cdf0e10cSrcweir                          NULL, // clipping is done via Sprite::clip()
525*cdf0e10cSrcweir                          rSubsets );
526*cdf0e10cSrcweir         }
527*cdf0e10cSrcweir 
528*cdf0e10cSrcweir         bool ViewShape::render( const ::cppcanvas::CanvasSharedPtr&	rDestinationCanvas,
529*cdf0e10cSrcweir                                 const GDIMetaFileSharedPtr&			rMtf,
530*cdf0e10cSrcweir                                 const ::basegfx::B2DRectangle&		rBounds,
531*cdf0e10cSrcweir                                 const ::basegfx::B2DRectangle&		rUpdateBounds,
532*cdf0e10cSrcweir                                 int									nUpdateFlags,
533*cdf0e10cSrcweir                                 const ShapeAttributeLayerSharedPtr&	pAttr,
534*cdf0e10cSrcweir                                 const VectorOfDocTreeNodes&			rSubsets,
535*cdf0e10cSrcweir                                 bool 								bIsVisible ) const
536*cdf0e10cSrcweir         {
537*cdf0e10cSrcweir             RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::render()" );
538*cdf0e10cSrcweir 
539*cdf0e10cSrcweir             // TODO(P1): For multiple views, it might pay off to reorg Shape and ViewShape,
540*cdf0e10cSrcweir             // in that all the common setup steps here are refactored to Shape (would then
541*cdf0e10cSrcweir             // have to be performed only _once_ per Shape paint).
542*cdf0e10cSrcweir 
543*cdf0e10cSrcweir             if( !bIsVisible )
544*cdf0e10cSrcweir             {
545*cdf0e10cSrcweir                 VERBOSE_TRACE( "ViewShape::render(): skipping shape %X", this );
546*cdf0e10cSrcweir 
547*cdf0e10cSrcweir                 // shape is invisible, no need to update anything.
548*cdf0e10cSrcweir                 return true;
549*cdf0e10cSrcweir             }
550*cdf0e10cSrcweir 
551*cdf0e10cSrcweir             // since we have no sprite here, _any_ update request
552*cdf0e10cSrcweir             // translates into a required redraw.
553*cdf0e10cSrcweir             bool bRedrawRequired( mbForceUpdate || nUpdateFlags != 0 );
554*cdf0e10cSrcweir 
555*cdf0e10cSrcweir             if( (nUpdateFlags & CONTENT) )
556*cdf0e10cSrcweir             {
557*cdf0e10cSrcweir                 // TODO(P1): maybe provide some appearance change methods at
558*cdf0e10cSrcweir                 // the Renderer interface
559*cdf0e10cSrcweir 
560*cdf0e10cSrcweir                 // force the renderer to be regenerated below, for the
561*cdf0e10cSrcweir                 // different attributes to take effect
562*cdf0e10cSrcweir                 invalidateRenderer();
563*cdf0e10cSrcweir             }
564*cdf0e10cSrcweir 
565*cdf0e10cSrcweir             mbForceUpdate = false;
566*cdf0e10cSrcweir 
567*cdf0e10cSrcweir             if( !bRedrawRequired )
568*cdf0e10cSrcweir                 return true;
569*cdf0e10cSrcweir 
570*cdf0e10cSrcweir             VERBOSE_TRACE( "ViewShape::render(): rendering shape %X at position (%f,%f)",
571*cdf0e10cSrcweir                            this,
572*cdf0e10cSrcweir                            rBounds.getMinX(),
573*cdf0e10cSrcweir                            rBounds.getMinY() );
574*cdf0e10cSrcweir 
575*cdf0e10cSrcweir 
576*cdf0e10cSrcweir             // shape needs repaint - setup all that's needed
577*cdf0e10cSrcweir             // ---------------------------------------------
578*cdf0e10cSrcweir 
579*cdf0e10cSrcweir             boost::optional<basegfx::B2DPolyPolygon> aClip;
580*cdf0e10cSrcweir 
581*cdf0e10cSrcweir             if( pAttr )
582*cdf0e10cSrcweir             {
583*cdf0e10cSrcweir                 // setup clip poly
584*cdf0e10cSrcweir                 if( pAttr->isClipValid() )
585*cdf0e10cSrcweir                     aClip.reset( pAttr->getClip() );
586*cdf0e10cSrcweir 
587*cdf0e10cSrcweir                 // emulate global shape alpha by first rendering into
588*cdf0e10cSrcweir                 // a temp bitmap, and then to screen (this would have
589*cdf0e10cSrcweir                 // been much easier if we'd be currently a sprite -
590*cdf0e10cSrcweir                 // see above)
591*cdf0e10cSrcweir                 if( pAttr->isAlphaValid() )
592*cdf0e10cSrcweir                 {
593*cdf0e10cSrcweir                     const double nAlpha( pAttr->getAlpha() );
594*cdf0e10cSrcweir 
595*cdf0e10cSrcweir                     if( !::basegfx::fTools::equalZero( nAlpha ) &&
596*cdf0e10cSrcweir                         !::rtl::math::approxEqual(nAlpha, 1.0) )
597*cdf0e10cSrcweir                     {
598*cdf0e10cSrcweir                         // render with global alpha - have to prepare
599*cdf0e10cSrcweir                         // a bitmap, and render that with modulated
600*cdf0e10cSrcweir                         // alpha
601*cdf0e10cSrcweir                         // -------------------------------------------
602*cdf0e10cSrcweir 
603*cdf0e10cSrcweir                         const ::basegfx::B2DHomMatrix aTransform(
604*cdf0e10cSrcweir                             getShapeTransformation( rBounds,
605*cdf0e10cSrcweir                                                     pAttr ) );
606*cdf0e10cSrcweir 
607*cdf0e10cSrcweir                         // TODO(P1): Should the view transform some
608*cdf0e10cSrcweir                         // day contain rotation/shear, transforming
609*cdf0e10cSrcweir                         // the original bounds with the total
610*cdf0e10cSrcweir                         // transformation might result in smaller
611*cdf0e10cSrcweir                         // overall bounds.
612*cdf0e10cSrcweir 
613*cdf0e10cSrcweir                         // determine output rect of _shape update
614*cdf0e10cSrcweir                         // area_ in device pixel
615*cdf0e10cSrcweir                         const ::basegfx::B2DHomMatrix aCanvasTransform(
616*cdf0e10cSrcweir                             rDestinationCanvas->getTransformation() );
617*cdf0e10cSrcweir                         ::basegfx::B2DRectangle aTmpRect;
618*cdf0e10cSrcweir                         ::canvas::tools::calcTransformedRectBounds( aTmpRect,
619*cdf0e10cSrcweir                                                                     rUpdateBounds,
620*cdf0e10cSrcweir                                                                     aCanvasTransform );
621*cdf0e10cSrcweir 
622*cdf0e10cSrcweir                         // pixel size of cache bitmap: round up to
623*cdf0e10cSrcweir                         // nearest int
624*cdf0e10cSrcweir                         const ::basegfx::B2ISize aBmpSize( static_cast<sal_Int32>( aTmpRect.getWidth() )+1,
625*cdf0e10cSrcweir                                                            static_cast<sal_Int32>( aTmpRect.getHeight() )+1 );
626*cdf0e10cSrcweir 
627*cdf0e10cSrcweir                         // try to fetch temporary surface for alpha
628*cdf0e10cSrcweir                         // compositing (to achieve the global alpha
629*cdf0e10cSrcweir                         // blend effect, have to first render shape as
630*cdf0e10cSrcweir                         // a whole, then blit that surface with global
631*cdf0e10cSrcweir                         // alpha to the destination)
632*cdf0e10cSrcweir                         const RendererCacheVector::iterator aCompositingSurface(
633*cdf0e10cSrcweir                             getCacheEntry( rDestinationCanvas ) );
634*cdf0e10cSrcweir 
635*cdf0e10cSrcweir                         if( !aCompositingSurface->mpLastBitmapCanvas ||
636*cdf0e10cSrcweir                             aCompositingSurface->mpLastBitmapCanvas->getSize() != aBmpSize )
637*cdf0e10cSrcweir                         {
638*cdf0e10cSrcweir                             // create a bitmap of appropriate size
639*cdf0e10cSrcweir                             ::cppcanvas::BitmapSharedPtr pBitmap(
640*cdf0e10cSrcweir                                 ::cppcanvas::BaseGfxFactory::getInstance().createAlphaBitmap(
641*cdf0e10cSrcweir                                     rDestinationCanvas,
642*cdf0e10cSrcweir                                     aBmpSize ) );
643*cdf0e10cSrcweir 
644*cdf0e10cSrcweir                             ENSURE_OR_THROW(pBitmap,
645*cdf0e10cSrcweir                                              "ViewShape::render(): Could not create compositing surface");
646*cdf0e10cSrcweir 
647*cdf0e10cSrcweir                             aCompositingSurface->mpDestinationCanvas = rDestinationCanvas;
648*cdf0e10cSrcweir                             aCompositingSurface->mpLastBitmap		 = pBitmap;
649*cdf0e10cSrcweir                             aCompositingSurface->mpLastBitmapCanvas	 = pBitmap->getBitmapCanvas();
650*cdf0e10cSrcweir                         }
651*cdf0e10cSrcweir 
652*cdf0e10cSrcweir                         // buffer aCompositingSurface iterator content
653*cdf0e10cSrcweir                         // - said one might get invalidated during
654*cdf0e10cSrcweir                         // draw() below.
655*cdf0e10cSrcweir                         ::cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas(
656*cdf0e10cSrcweir                             aCompositingSurface->mpLastBitmapCanvas );
657*cdf0e10cSrcweir 
658*cdf0e10cSrcweir                         ::cppcanvas::BitmapSharedPtr pBitmap(
659*cdf0e10cSrcweir                             aCompositingSurface->mpLastBitmap);
660*cdf0e10cSrcweir 
661*cdf0e10cSrcweir                         // setup bitmap canvas transformation -
662*cdf0e10cSrcweir                         // which happens to be the destination
663*cdf0e10cSrcweir                         // canvas transformation without any
664*cdf0e10cSrcweir                         // translational components.
665*cdf0e10cSrcweir                         //
666*cdf0e10cSrcweir                         // But then, the render transformation as
667*cdf0e10cSrcweir                         // calculated by getShapeTransformation()
668*cdf0e10cSrcweir                         // above outputs the shape at its real
669*cdf0e10cSrcweir                         // destination position. Thus, we have to
670*cdf0e10cSrcweir                         // offset the output back to the origin,
671*cdf0e10cSrcweir                         // for which we simply plug in the
672*cdf0e10cSrcweir                         // negative position of the left, top edge
673*cdf0e10cSrcweir                         // of the shape's bound rect in device
674*cdf0e10cSrcweir                         // pixel into aLinearTransform below.
675*cdf0e10cSrcweir                         ::basegfx::B2DHomMatrix aAdjustedCanvasTransform( aCanvasTransform );
676*cdf0e10cSrcweir                         aAdjustedCanvasTransform.translate( -aTmpRect.getMinX(),
677*cdf0e10cSrcweir                                                             -aTmpRect.getMinY() );
678*cdf0e10cSrcweir 
679*cdf0e10cSrcweir                         pBitmapCanvas->setTransformation( aAdjustedCanvasTransform );
680*cdf0e10cSrcweir 
681*cdf0e10cSrcweir                         // TODO(P2): If no update flags, or only
682*cdf0e10cSrcweir                         // alpha_update is set, we can save us the
683*cdf0e10cSrcweir                         // rendering into the bitmap (uh, it's not
684*cdf0e10cSrcweir                         // _that_ easy - for a forced redraw,
685*cdf0e10cSrcweir                         // e.g. when ending an animation, we always
686*cdf0e10cSrcweir                         // get UPDATE_FORCE here).
687*cdf0e10cSrcweir 
688*cdf0e10cSrcweir                         // render into this bitmap
689*cdf0e10cSrcweir                         if( !draw( pBitmapCanvas,
690*cdf0e10cSrcweir                                    rMtf,
691*cdf0e10cSrcweir                                    pAttr,
692*cdf0e10cSrcweir                                    aTransform,
693*cdf0e10cSrcweir                                    !aClip ? NULL : &(*aClip),
694*cdf0e10cSrcweir                                    rSubsets ) )
695*cdf0e10cSrcweir                         {
696*cdf0e10cSrcweir                             return false;
697*cdf0e10cSrcweir                         }
698*cdf0e10cSrcweir 
699*cdf0e10cSrcweir                         // render bitmap to screen, with given global
700*cdf0e10cSrcweir                         // alpha. Since the bitmap already contains
701*cdf0e10cSrcweir                         // pixel-equivalent output, we have to use the
702*cdf0e10cSrcweir                         // inverse view transformation, adjusted with
703*cdf0e10cSrcweir                         // the final shape output position (note:
704*cdf0e10cSrcweir                         // cannot simply change the view
705*cdf0e10cSrcweir                         // transformation here, as that would affect a
706*cdf0e10cSrcweir                         // possibly set clip!)
707*cdf0e10cSrcweir                         ::basegfx::B2DHomMatrix aBitmapTransform( aCanvasTransform );
708*cdf0e10cSrcweir                         OSL_ENSURE( aBitmapTransform.isInvertible(),
709*cdf0e10cSrcweir                                     "ViewShape::render(): View transformation is singular!" );
710*cdf0e10cSrcweir 
711*cdf0e10cSrcweir                         aBitmapTransform.invert();
712*cdf0e10cSrcweir 
713*cdf0e10cSrcweir                         const basegfx::B2DHomMatrix aTranslation(basegfx::tools::createTranslateB2DHomMatrix(
714*cdf0e10cSrcweir                             aTmpRect.getMinX(), aTmpRect.getMinY()));
715*cdf0e10cSrcweir 
716*cdf0e10cSrcweir                         aBitmapTransform = aBitmapTransform * aTranslation;
717*cdf0e10cSrcweir                         pBitmap->setTransformation( aBitmapTransform );
718*cdf0e10cSrcweir 
719*cdf0e10cSrcweir                         // finally, render bitmap alpha-modulated
720*cdf0e10cSrcweir                         pBitmap->drawAlphaModulated( nAlpha );
721*cdf0e10cSrcweir 
722*cdf0e10cSrcweir                         return true;
723*cdf0e10cSrcweir                     }
724*cdf0e10cSrcweir                 }
725*cdf0e10cSrcweir             }
726*cdf0e10cSrcweir 
727*cdf0e10cSrcweir             // retrieve shape transformation, _with_ shape translation
728*cdf0e10cSrcweir             // to actual page position.
729*cdf0e10cSrcweir             const ::basegfx::B2DHomMatrix aTransform(
730*cdf0e10cSrcweir                 getShapeTransformation( rBounds,
731*cdf0e10cSrcweir                                         pAttr ) );
732*cdf0e10cSrcweir 
733*cdf0e10cSrcweir             return draw( rDestinationCanvas,
734*cdf0e10cSrcweir                          rMtf,
735*cdf0e10cSrcweir                          pAttr,
736*cdf0e10cSrcweir                          aTransform,
737*cdf0e10cSrcweir                          !aClip ? NULL : &(*aClip),
738*cdf0e10cSrcweir                          rSubsets );
739*cdf0e10cSrcweir         }
740*cdf0e10cSrcweir 
741*cdf0e10cSrcweir 
742*cdf0e10cSrcweir         // -------------------------------------------------------------------------------------
743*cdf0e10cSrcweir 
744*cdf0e10cSrcweir         ViewShape::ViewShape( const ViewLayerSharedPtr& rViewLayer ) :
745*cdf0e10cSrcweir             mpViewLayer( rViewLayer ),
746*cdf0e10cSrcweir             maRenderers(),
747*cdf0e10cSrcweir             mpSprite(),
748*cdf0e10cSrcweir             mbAnimationMode( false ),
749*cdf0e10cSrcweir             mbForceUpdate( true )
750*cdf0e10cSrcweir         {
751*cdf0e10cSrcweir             ENSURE_OR_THROW( mpViewLayer, "ViewShape::ViewShape(): Invalid View" );
752*cdf0e10cSrcweir         }
753*cdf0e10cSrcweir 
754*cdf0e10cSrcweir         ViewLayerSharedPtr ViewShape::getViewLayer() const
755*cdf0e10cSrcweir         {
756*cdf0e10cSrcweir             return mpViewLayer;
757*cdf0e10cSrcweir         }
758*cdf0e10cSrcweir 
759*cdf0e10cSrcweir         ViewShape::RendererCacheVector::iterator ViewShape::getCacheEntry( const ::cppcanvas::CanvasSharedPtr&	rDestinationCanvas ) const
760*cdf0e10cSrcweir         {
761*cdf0e10cSrcweir             // lookup destination canvas - is there already a renderer
762*cdf0e10cSrcweir             // created for that target?
763*cdf0e10cSrcweir             RendererCacheVector::iterator 		aIter;
764*cdf0e10cSrcweir             const RendererCacheVector::iterator aEnd( maRenderers.end() );
765*cdf0e10cSrcweir 
766*cdf0e10cSrcweir             // already there?
767*cdf0e10cSrcweir             if( (aIter=::std::find_if( maRenderers.begin(),
768*cdf0e10cSrcweir                                        aEnd,
769*cdf0e10cSrcweir                                        ::boost::bind(
770*cdf0e10cSrcweir                                            ::std::equal_to< ::cppcanvas::CanvasSharedPtr >(),
771*cdf0e10cSrcweir                                            ::boost::cref( rDestinationCanvas ),
772*cdf0e10cSrcweir                                            ::boost::bind(
773*cdf0e10cSrcweir                                                &RendererCacheEntry::getDestinationCanvas,
774*cdf0e10cSrcweir                                                _1 ) ) ) ) == aEnd )
775*cdf0e10cSrcweir             {
776*cdf0e10cSrcweir                 if( maRenderers.size() >= MAX_RENDER_CACHE_ENTRIES )
777*cdf0e10cSrcweir                 {
778*cdf0e10cSrcweir                     // cache size exceeded - prune entries. For now,
779*cdf0e10cSrcweir                     // simply remove the first one, which of course
780*cdf0e10cSrcweir                     // breaks for more complex access schemes. But in
781*cdf0e10cSrcweir                     // general, this leads to most recently used
782*cdf0e10cSrcweir                     // entries to reside at the end of the vector.
783*cdf0e10cSrcweir                     maRenderers.erase( maRenderers.begin() );
784*cdf0e10cSrcweir 
785*cdf0e10cSrcweir                     // ATTENTION: after this, both aIter and aEnd are
786*cdf0e10cSrcweir                     // invalid!
787*cdf0e10cSrcweir                 }
788*cdf0e10cSrcweir 
789*cdf0e10cSrcweir                 // not yet in cache - add default-constructed cache
790*cdf0e10cSrcweir                 // entry, to have something to return
791*cdf0e10cSrcweir                 maRenderers.push_back( RendererCacheEntry() );
792*cdf0e10cSrcweir                 aIter = maRenderers.end()-1;
793*cdf0e10cSrcweir             }
794*cdf0e10cSrcweir 
795*cdf0e10cSrcweir             return aIter;
796*cdf0e10cSrcweir         }
797*cdf0e10cSrcweir 
798*cdf0e10cSrcweir         ::cppcanvas::RendererSharedPtr ViewShape::getRenderer( const ::cppcanvas::CanvasSharedPtr&	rDestinationCanvas,
799*cdf0e10cSrcweir                                                                const GDIMetaFileSharedPtr&			rMtf,
800*cdf0e10cSrcweir                                                                const ShapeAttributeLayerSharedPtr&	rAttr ) const
801*cdf0e10cSrcweir         {
802*cdf0e10cSrcweir             // lookup destination canvas - is there already a renderer
803*cdf0e10cSrcweir             // created for that target?
804*cdf0e10cSrcweir             const RendererCacheVector::iterator aIter(
805*cdf0e10cSrcweir                 getCacheEntry( rDestinationCanvas ) );
806*cdf0e10cSrcweir 
807*cdf0e10cSrcweir             // now we have a valid entry, either way. call prefetch()
808*cdf0e10cSrcweir             // on it, nevertheless - maybe the metafile changed, and
809*cdf0e10cSrcweir             // the renderer still needs an update (prefetch() will
810*cdf0e10cSrcweir             // detect that)
811*cdf0e10cSrcweir             if( prefetch( *aIter,
812*cdf0e10cSrcweir                           rDestinationCanvas,
813*cdf0e10cSrcweir                           rMtf,
814*cdf0e10cSrcweir                           rAttr ) )
815*cdf0e10cSrcweir             {
816*cdf0e10cSrcweir                 return aIter->mpRenderer;
817*cdf0e10cSrcweir             }
818*cdf0e10cSrcweir             else
819*cdf0e10cSrcweir             {
820*cdf0e10cSrcweir                 // prefetch failed - renderer is invalid
821*cdf0e10cSrcweir                 return ::cppcanvas::RendererSharedPtr();
822*cdf0e10cSrcweir             }
823*cdf0e10cSrcweir         }
824*cdf0e10cSrcweir 
825*cdf0e10cSrcweir         void ViewShape::invalidateRenderer() const
826*cdf0e10cSrcweir         {
827*cdf0e10cSrcweir             // simply clear the cache. Subsequent getRenderer() calls
828*cdf0e10cSrcweir             // will regenerate the Renderers.
829*cdf0e10cSrcweir             maRenderers.clear();
830*cdf0e10cSrcweir         }
831*cdf0e10cSrcweir 
832*cdf0e10cSrcweir         ::basegfx::B2DSize ViewShape::getAntialiasingBorder() const
833*cdf0e10cSrcweir         {
834*cdf0e10cSrcweir             ENSURE_OR_THROW( mpViewLayer->getCanvas(),
835*cdf0e10cSrcweir                               "ViewShape::getAntialiasingBorder(): Invalid ViewLayer canvas" );
836*cdf0e10cSrcweir 
837*cdf0e10cSrcweir             const ::basegfx::B2DHomMatrix& rViewTransform(
838*cdf0e10cSrcweir                 mpViewLayer->getTransformation() );
839*cdf0e10cSrcweir 
840*cdf0e10cSrcweir             // TODO(F1): As a quick shortcut (did not want to invert
841*cdf0e10cSrcweir             // whole matrix here), taking only scale components of
842*cdf0e10cSrcweir             // view transformation matrix. This will be wrong when
843*cdf0e10cSrcweir             // e.g. shearing is involved.
844*cdf0e10cSrcweir             const double nXBorder( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE / rViewTransform.get(0,0) );
845*cdf0e10cSrcweir             const double nYBorder( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE / rViewTransform.get(1,1) );
846*cdf0e10cSrcweir 
847*cdf0e10cSrcweir             return ::basegfx::B2DSize( nXBorder,
848*cdf0e10cSrcweir                                        nYBorder );
849*cdf0e10cSrcweir         }
850*cdf0e10cSrcweir 
851*cdf0e10cSrcweir         bool ViewShape::enterAnimationMode()
852*cdf0e10cSrcweir         {
853*cdf0e10cSrcweir             mbForceUpdate   = true;
854*cdf0e10cSrcweir             mbAnimationMode = true;
855*cdf0e10cSrcweir 
856*cdf0e10cSrcweir             return true;
857*cdf0e10cSrcweir         }
858*cdf0e10cSrcweir 
859*cdf0e10cSrcweir         void ViewShape::leaveAnimationMode()
860*cdf0e10cSrcweir         {
861*cdf0e10cSrcweir             mpSprite.reset();
862*cdf0e10cSrcweir             mbAnimationMode = false;
863*cdf0e10cSrcweir             mbForceUpdate   = true;
864*cdf0e10cSrcweir         }
865*cdf0e10cSrcweir 
866*cdf0e10cSrcweir         bool ViewShape::update( const GDIMetaFileSharedPtr&	rMtf,
867*cdf0e10cSrcweir                                 const RenderArgs&			rArgs,
868*cdf0e10cSrcweir                                 int							nUpdateFlags,
869*cdf0e10cSrcweir                                 bool						bIsVisible ) const
870*cdf0e10cSrcweir         {
871*cdf0e10cSrcweir             RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::update()" );
872*cdf0e10cSrcweir             ENSURE_OR_RETURN_FALSE( mpViewLayer->getCanvas(), "ViewShape::update(): Invalid layer canvas" );
873*cdf0e10cSrcweir 
874*cdf0e10cSrcweir             // Shall we render to a sprite, or to a plain canvas?
875*cdf0e10cSrcweir             if( isBackgroundDetached() )
876*cdf0e10cSrcweir                 return renderSprite( mpViewLayer,
877*cdf0e10cSrcweir                                      rMtf,
878*cdf0e10cSrcweir                                      rArgs.maOrigBounds,
879*cdf0e10cSrcweir                                      rArgs.maBounds,
880*cdf0e10cSrcweir                                      rArgs.maUnitBounds,
881*cdf0e10cSrcweir                                      nUpdateFlags,
882*cdf0e10cSrcweir                                      rArgs.mrAttr,
883*cdf0e10cSrcweir                                      rArgs.mrSubsets,
884*cdf0e10cSrcweir                                      rArgs.mnShapePriority,
885*cdf0e10cSrcweir                                      bIsVisible );
886*cdf0e10cSrcweir             else
887*cdf0e10cSrcweir                 return render( mpViewLayer->getCanvas(),
888*cdf0e10cSrcweir                                rMtf,
889*cdf0e10cSrcweir                                rArgs.maBounds,
890*cdf0e10cSrcweir                                rArgs.maUpdateBounds,
891*cdf0e10cSrcweir                                nUpdateFlags,
892*cdf0e10cSrcweir                                rArgs.mrAttr,
893*cdf0e10cSrcweir                                rArgs.mrSubsets,
894*cdf0e10cSrcweir                                bIsVisible );
895*cdf0e10cSrcweir         }
896*cdf0e10cSrcweir 
897*cdf0e10cSrcweir     }
898*cdf0e10cSrcweir }
899