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