1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: viewshape.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_slideshow.hxx"
35 #include <canvas/debug.hxx>
36 #include <tools/diagnose_ex.h>
40 #include <rtl/logfile.hxx>
41 #include <rtl/math.hxx>
43 #include <com/sun/star/rendering/XCanvas.hpp>
44 #include <com/sun/star/rendering/XIntegerBitmap.hpp>
45 #include <com/sun/star/rendering/PanoseLetterForm.hpp>
46 #include <com/sun/star/awt/FontSlant.hpp>
48 #include <cppuhelper/exc_hlp.hxx>
49 #include <comphelper/anytostring.hxx>
51 #include <basegfx/polygon/b2dpolygontools.hxx>
52 #include <basegfx/numeric/ftools.hxx>
53 #include <basegfx/matrix/b2dhommatrix.hxx>
55 #include <canvas/verbosetrace.hxx>
56 #include <canvas/canvastools.hxx>
57 #include <cppcanvas/vclfactory.hxx>
58 #include <cppcanvas/basegfxfactory.hxx>
60 #include "viewshape.hxx"
64 #include <boost/bind.hpp>
67 using namespace ::com::sun::star
;
74 // TODO(F2): Provide sensible setup for mtf-related attributes (fill mode,
75 // char rotation etc.). Do that via mtf argument at this object
77 bool ViewShape::prefetch( RendererCacheEntry
& io_rCacheEntry
,
78 const ::cppcanvas::CanvasSharedPtr
& rDestinationCanvas
,
79 const GDIMetaFileSharedPtr
& rMtf
,
80 const ShapeAttributeLayerSharedPtr
& rAttr
) const
82 RTL_LOGFILE_CONTEXT( aLog
, "::presentation::internal::ViewShape::prefetch()" );
83 ENSURE_OR_RETURN( rMtf
,
84 "ViewShape::prefetch(): no valid metafile!" );
86 if( rMtf
!= io_rCacheEntry
.mpMtf
||
87 rDestinationCanvas
!= io_rCacheEntry
.getDestinationCanvas() )
89 // buffered renderer invalid, re-create
90 ::cppcanvas::Renderer::Parameters aParms
;
92 // rendering attribute override parameter struct. For
93 // every valid attribute, the corresponding struct
94 // member is filled, which in the metafile renderer
95 // forces rendering with the given attribute.
98 if( rAttr
->isFillColorValid() )
100 // convert RGBColor to RGBA32 integer. Note
101 // that getIntegerColor() also truncates
102 // out-of-range values appropriately
104 rAttr
->getFillColor().getIntegerColor();
106 if( rAttr
->isLineColorValid() )
108 // convert RGBColor to RGBA32 integer. Note
109 // that getIntegerColor() also truncates
110 // out-of-range values appropriately
112 rAttr
->getLineColor().getIntegerColor();
114 if( rAttr
->isCharColorValid() )
116 // convert RGBColor to RGBA32 integer. Note
117 // that getIntegerColor() also truncates
118 // out-of-range values appropriately
120 rAttr
->getCharColor().getIntegerColor();
122 if( rAttr
->isDimColorValid() )
124 // convert RGBColor to RGBA32 integer. Note
125 // that getIntegerColor() also truncates
126 // out-of-range values appropriately
128 // dim color overrides all other colors
132 rAttr
->getDimColor().getIntegerColor();
134 if( rAttr
->isFontFamilyValid() )
137 rAttr
->getFontFamily();
139 if( rAttr
->isCharScaleValid() )
141 ::basegfx::B2DHomMatrix aMatrix
;
143 // enlarge text by given scale factor. Do that
144 // with the middle of the shape as the center
146 aMatrix
.translate( -0.5, -0.5 );
147 aMatrix
.scale( rAttr
->getCharScale(),
148 rAttr
->getCharScale() );
149 aMatrix
.translate( 0.5, 0.5 );
151 aParms
.maTextTransformation
= aMatrix
;
153 if( rAttr
->isCharWeightValid() )
155 aParms
.maFontWeight
=
156 static_cast< sal_Int8
>(
160 rAttr
->getCharWeight() / 20.0 ) ) ) );
162 if( rAttr
->isCharPostureValid() )
164 aParms
.maFontLetterForm
=
165 rAttr
->getCharPosture() == awt::FontSlant_NONE
?
166 rendering::PanoseLetterForm::ANYTHING
:
167 rendering::PanoseLetterForm::OBLIQUE_CONTACT
;
169 if( rAttr
->isUnderlineModeValid() )
171 aParms
.maFontUnderline
=
172 rAttr
->getUnderlineMode();
176 io_rCacheEntry
.mpRenderer
= ::cppcanvas::VCLFactory::getInstance().createRenderer( rDestinationCanvas
,
180 io_rCacheEntry
.mpMtf
= rMtf
;
181 io_rCacheEntry
.mpDestinationCanvas
= rDestinationCanvas
;
183 // also invalidate alpha compositing bitmap (created
184 // new renderer, which possibly generates different
185 // output). Do NOT invalidate, if we're incidentally
186 // rendering INTO it.
187 if( rDestinationCanvas
!= io_rCacheEntry
.mpLastBitmapCanvas
)
189 io_rCacheEntry
.mpLastBitmapCanvas
.reset();
190 io_rCacheEntry
.mpLastBitmap
.reset();
194 return io_rCacheEntry
.mpRenderer
;
197 bool ViewShape::draw( const ::cppcanvas::CanvasSharedPtr
& rDestinationCanvas
,
198 const GDIMetaFileSharedPtr
& rMtf
,
199 const ShapeAttributeLayerSharedPtr
& rAttr
,
200 const ::basegfx::B2DHomMatrix
& rTransform
,
201 const ::basegfx::B2DPolyPolygon
* pClip
,
202 const VectorOfDocTreeNodes
& rSubsets
) const
204 RTL_LOGFILE_CONTEXT( aLog
, "::presentation::internal::ViewShape::draw()" );
206 ::cppcanvas::RendererSharedPtr
pRenderer(
207 getRenderer( rDestinationCanvas
, rMtf
, rAttr
) );
209 ENSURE_OR_RETURN( pRenderer
, "ViewShape::draw(): Invalid renderer" );
211 pRenderer
->setTransformation( rTransform
);
212 #if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0
213 rendering::RenderState aRenderState
;
214 ::canvas::tools::initRenderState(aRenderState
);
215 ::canvas::tools::setRenderStateTransform(aRenderState
,
217 aRenderState
.DeviceColor
.realloc(4);
218 aRenderState
.DeviceColor
[0] = 1.0;
219 aRenderState
.DeviceColor
[1] = 0.0;
220 aRenderState
.DeviceColor
[2] = 0.0;
221 aRenderState
.DeviceColor
[3] = 1.0;
225 rDestinationCanvas
->getUNOCanvas()->drawLine( geometry::RealPoint2D(0.0,0.0),
226 geometry::RealPoint2D(1.0,1.0),
227 rDestinationCanvas
->getViewState(),
229 rDestinationCanvas
->getUNOCanvas()->drawLine( geometry::RealPoint2D(1.0,0.0),
230 geometry::RealPoint2D(0.0,1.0),
231 rDestinationCanvas
->getViewState(),
234 catch( uno::Exception
& )
236 DBG_UNHANDLED_EXCEPTION();
240 pRenderer
->setClip( *pClip
);
242 pRenderer
->setClip();
244 if( rSubsets
.empty() )
246 return pRenderer
->draw();
250 // render subsets of whole metafile
251 // --------------------------------
254 VectorOfDocTreeNodes::const_iterator
aIter( rSubsets
.begin() );
255 const VectorOfDocTreeNodes::const_iterator
aEnd ( rSubsets
.end() );
256 while( aIter
!= aEnd
)
258 if( !pRenderer
->drawSubset( aIter
->getStartIndex(),
259 aIter
->getEndIndex() ) )
271 /// Convert untransformed shape update area to device pixel.
272 ::basegfx::B2DRectangle
shapeArea2AreaPixel( const ::basegfx::B2DHomMatrix
& rCanvasTransformation
,
273 const ::basegfx::B2DRectangle
& rUntransformedArea
)
275 // convert area to pixel, and add anti-aliasing border
277 // TODO(P1): Should the view transform some
278 // day contain rotation/shear, transforming
279 // the original bounds with the total
280 // transformation might result in smaller
283 ::basegfx::B2DRectangle aBoundsPixel
;
284 ::canvas::tools::calcTransformedRectBounds( aBoundsPixel
,
286 rCanvasTransformation
);
288 // add antialiasing border around the shape (AA
289 // touches pixel _outside_ the nominal bound rect)
290 aBoundsPixel
.grow( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
);
295 /// Convert shape unit rect to device pixel.
296 ::basegfx::B2DRectangle
calcUpdateAreaPixel( const ::basegfx::B2DRectangle
& rUnitBounds
,
297 const ::basegfx::B2DHomMatrix
& rShapeTransformation
,
298 const ::basegfx::B2DHomMatrix
& rCanvasTransformation
,
299 const ShapeAttributeLayerSharedPtr
& pAttr
)
301 // calc update area for whole shape (including
302 // character scaling)
303 return shapeArea2AreaPixel( rCanvasTransformation
,
304 getShapeUpdateArea( rUnitBounds
,
305 rShapeTransformation
,
310 bool ViewShape::renderSprite( const ViewLayerSharedPtr
& rViewLayer
,
311 const GDIMetaFileSharedPtr
& rMtf
,
312 const ::basegfx::B2DRectangle
& rOrigBounds
,
313 const ::basegfx::B2DRectangle
& rBounds
,
314 const ::basegfx::B2DRectangle
& rUnitBounds
,
316 const ShapeAttributeLayerSharedPtr
& pAttr
,
317 const VectorOfDocTreeNodes
& rSubsets
,
319 bool bIsVisible
) const
321 RTL_LOGFILE_CONTEXT( aLog
, "::presentation::internal::ViewShape::renderSprite()" );
323 // TODO(P1): For multiple views, it might pay off to reorg Shape and ViewShape,
324 // in that all the common setup steps here are refactored to Shape (would then
325 // have to be performed only _once_ per Shape paint).
328 rUnitBounds
.isEmpty() ||
329 rOrigBounds
.isEmpty() ||
332 // shape is invisible or has zero size, no need to
341 // calc sprite position, size and content transformation
342 // =====================================================
344 // the shape transformation for a sprite is always a
345 // simple scale-up to the nominal shape size. Everything
346 // else is handled via the sprite transformation
347 ::basegfx::B2DHomMatrix aNonTranslationalShapeTransformation
;
348 aNonTranslationalShapeTransformation
.scale( rOrigBounds
.getWidth(),
349 rOrigBounds
.getHeight() );
350 ::basegfx::B2DHomMatrix
aShapeTransformation( aNonTranslationalShapeTransformation
);
351 aShapeTransformation
.translate( rOrigBounds
.getMinX(),
352 rOrigBounds
.getMinY() );
354 const ::basegfx::B2DHomMatrix
& rCanvasTransform(
355 rViewLayer
->getSpriteTransformation() );
357 // area actually needed for the sprite
358 const ::basegfx::B2DRectangle
& rSpriteBoundsPixel(
359 calcUpdateAreaPixel( rUnitBounds
,
360 aShapeTransformation
,
364 // actual area for the shape (without subsetting, but
365 // including char scaling)
366 const ::basegfx::B2DRectangle
& rShapeBoundsPixel(
367 calcUpdateAreaPixel( ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0),
368 aShapeTransformation
,
372 // nominal area for the shape (without subsetting, without
373 // char scaling). NOTE: to cancel the shape translation,
374 // contained in rSpriteBoundsPixel, this is _without_ any
375 // translational component (fixed along with #121921#).
376 ::basegfx::B2DRectangle aLogShapeBounds
;
377 const ::basegfx::B2DRectangle
& rNominalShapeBoundsPixel(
378 shapeArea2AreaPixel( rCanvasTransform
,
379 ::canvas::tools::calcTransformedRectBounds(
381 ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0),
382 aNonTranslationalShapeTransformation
) ) );
384 // create (or resize) sprite with sprite's pixel size, if
386 const ::basegfx::B2DSize
& rSpriteSizePixel(rSpriteBoundsPixel
.getRange());
390 new AnimatedSprite( mpViewLayer
,
396 // TODO(F2): when the sprite _actually_ gets resized,
397 // content needs a repaint!
398 mpSprite
->resize( rSpriteSizePixel
);
401 ENSURE_OR_RETURN( mpSprite
, "ViewShape::renderSprite(): No sprite" );
403 VERBOSE_TRACE( "ViewShape::renderSprite(): Rendering sprite 0x%X",
407 // always show the sprite (might have been hidden before)
410 // determine center of sprite output position in pixel
411 // (assumption here: all shape transformations have the
412 // shape center as the pivot point). From that, subtract
413 // distance of rSpriteBoundsPixel's left, top edge from
414 // rShapeBoundsPixel's center. This moves the sprite at
415 // the appropriate output position within the virtual
416 // rShapeBoundsPixel area.
417 ::basegfx::B2DPoint
aSpritePosPixel( rBounds
.getCenter() );
418 aSpritePosPixel
*= rCanvasTransform
;
419 aSpritePosPixel
-= rShapeBoundsPixel
.getCenter() - rSpriteBoundsPixel
.getMinimum();
421 // the difference between rShapeBoundsPixel and
422 // rSpriteBoundsPixel upper, left corner is: the offset we
423 // have to move sprite output to the right, top (to make
424 // the desired subset content visible at all)
425 const ::basegfx::B2DSize
& rSpriteCorrectionOffset(
426 rSpriteBoundsPixel
.getMinimum() - rNominalShapeBoundsPixel
.getMinimum() );
428 // offset added top, left for anti-aliasing (otherwise,
429 // shapes fully filling the sprite will have anti-aliased
431 const ::basegfx::B2DSize
aAAOffset(
432 ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
,
433 ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
);
435 // set pixel output offset to sprite: we always leave
436 // ANTIALIASING_EXTRA_SIZE room atop and to the left, and,
437 // what's more, for subsetted shapes, we _have_ to cancel
438 // the effect of the shape renderer outputting the subset
439 // at its absolute position inside the shape, instead of
441 // NOTE: As for now, sprites are always positioned on
442 // integer pixel positions on screen, have to round to
443 // nearest integer here, too (fixed along with #121921#)
444 mpSprite
->setPixelOffset(
445 aAAOffset
- ::basegfx::B2DSize(
446 ::basegfx::fround( rSpriteCorrectionOffset
.getX() ),
447 ::basegfx::fround( rSpriteCorrectionOffset
.getY() ) ) );
449 // always set sprite position and transformation, since
450 // they do not relate directly to the update flags
451 // (e.g. sprite position changes when sprite size changes)
452 mpSprite
->movePixel( aSpritePosPixel
);
453 mpSprite
->transform( getSpriteTransformation( rSpriteSizePixel
,
454 rOrigBounds
.getRange(),
461 bool bRedrawRequired( mbForceUpdate
|| (nUpdateFlags
& FORCE
) );
463 if( mbForceUpdate
|| (nUpdateFlags
& ALPHA
) )
465 mpSprite
->setAlpha( (pAttr
&& pAttr
->isAlphaValid()) ?
466 ::canvas::tools::clamp(pAttr
->getAlpha(),
471 if( mbForceUpdate
|| (nUpdateFlags
& CLIP
) )
473 if( pAttr
&& pAttr
->isClipValid() )
475 ::basegfx::B2DPolyPolygon
aClipPoly( pAttr
->getClip() );
477 // extract linear part of canvas view transformation
478 // (linear means: without translational components)
479 ::basegfx::B2DHomMatrix
aViewTransform(
480 mpViewLayer
->getTransformation() );
481 aViewTransform
.set( 0, 2, 0.0 );
482 aViewTransform
.set( 1, 2, 0.0 );
484 // make the clip 2*ANTIALIASING_EXTRA_SIZE larger
485 // such that it's again centered over the sprite.
486 aViewTransform
.scale(rSpriteSizePixel
.getX()/
487 (rSpriteSizePixel
.getX()-2*::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
),
488 rSpriteSizePixel
.getY()/
489 (rSpriteSizePixel
.getY()-2*::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
));
491 // transform clip polygon from view to device
493 aClipPoly
.transform( aViewTransform
);
495 mpSprite
->clip( aClipPoly
);
500 if( mbForceUpdate
|| (nUpdateFlags
& CONTENT
) )
502 bRedrawRequired
= true;
504 // TODO(P1): maybe provide some appearance change methods at
505 // the Renderer interface
507 // force the renderer to be regenerated below, for the
508 // different attributes to take effect
509 invalidateRenderer();
512 mbForceUpdate
= false;
514 if( !bRedrawRequired
)
518 // sprite needs repaint - output to sprite canvas
519 // ==============================================
521 ::cppcanvas::CanvasSharedPtr
pContentCanvas( mpSprite
->getContentCanvas() );
523 return draw( pContentCanvas
,
526 aShapeTransformation
,
527 NULL
, // clipping is done via Sprite::clip()
531 bool ViewShape::render( const ::cppcanvas::CanvasSharedPtr
& rDestinationCanvas
,
532 const GDIMetaFileSharedPtr
& rMtf
,
533 const ::basegfx::B2DRectangle
& rBounds
,
534 const ::basegfx::B2DRectangle
& rUpdateBounds
,
536 const ShapeAttributeLayerSharedPtr
& pAttr
,
537 const VectorOfDocTreeNodes
& rSubsets
,
538 bool bIsVisible
) const
540 RTL_LOGFILE_CONTEXT( aLog
, "::presentation::internal::ViewShape::render()" );
542 // TODO(P1): For multiple views, it might pay off to reorg Shape and ViewShape,
543 // in that all the common setup steps here are refactored to Shape (would then
544 // have to be performed only _once_ per Shape paint).
548 VERBOSE_TRACE( "ViewShape::render(): skipping shape %X", this );
550 // shape is invisible, no need to update anything.
554 // since we have no sprite here, _any_ update request
555 // translates into a required redraw.
556 bool bRedrawRequired( mbForceUpdate
|| nUpdateFlags
!= 0 );
558 if( (nUpdateFlags
& CONTENT
) )
560 // TODO(P1): maybe provide some appearance change methods at
561 // the Renderer interface
563 // force the renderer to be regenerated below, for the
564 // different attributes to take effect
565 invalidateRenderer();
568 mbForceUpdate
= false;
570 if( !bRedrawRequired
)
573 VERBOSE_TRACE( "ViewShape::render(): rendering shape %X at position (%f,%f)",
579 // shape needs repaint - setup all that's needed
580 // ---------------------------------------------
582 boost::optional
<basegfx::B2DPolyPolygon
> aClip
;
587 if( pAttr
->isClipValid() )
588 aClip
.reset( pAttr
->getClip() );
590 // emulate global shape alpha by first rendering into
591 // a temp bitmap, and then to screen (this would have
592 // been much easier if we'd be currently a sprite -
594 if( pAttr
->isAlphaValid() )
596 const double nAlpha( pAttr
->getAlpha() );
598 if( !::basegfx::fTools::equalZero( nAlpha
) &&
599 !::rtl::math::approxEqual(nAlpha
, 1.0) )
601 // render with global alpha - have to prepare
602 // a bitmap, and render that with modulated
604 // -------------------------------------------
606 const ::basegfx::B2DHomMatrix
aTransform(
607 getShapeTransformation( rBounds
,
610 // TODO(P1): Should the view transform some
611 // day contain rotation/shear, transforming
612 // the original bounds with the total
613 // transformation might result in smaller
616 // determine output rect of _shape update
617 // area_ in device pixel
618 const ::basegfx::B2DHomMatrix
aCanvasTransform(
619 rDestinationCanvas
->getTransformation() );
620 ::basegfx::B2DRectangle aTmpRect
;
621 ::canvas::tools::calcTransformedRectBounds( aTmpRect
,
625 // pixel size of cache bitmap: round up to
627 const ::basegfx::B2ISize
aBmpSize( static_cast<sal_Int32
>( aTmpRect
.getWidth() )+1,
628 static_cast<sal_Int32
>( aTmpRect
.getHeight() )+1 );
630 // try to fetch temporary surface for alpha
631 // compositing (to achieve the global alpha
632 // blend effect, have to first render shape as
633 // a whole, then blit that surface with global
634 // alpha to the destination)
635 const RendererCacheVector::iterator
aCompositingSurface(
636 getCacheEntry( rDestinationCanvas
) );
638 if( !aCompositingSurface
->mpLastBitmapCanvas
||
639 aCompositingSurface
->mpLastBitmapCanvas
->getSize() != aBmpSize
)
641 // create a bitmap of appropriate size
642 ::cppcanvas::BitmapSharedPtr
pBitmap(
643 ::cppcanvas::BaseGfxFactory::getInstance().createAlphaBitmap(
647 ENSURE_OR_THROW(pBitmap
,
648 "ViewShape::render(): Could not create compositing surface");
650 aCompositingSurface
->mpDestinationCanvas
= rDestinationCanvas
;
651 aCompositingSurface
->mpLastBitmap
= pBitmap
;
652 aCompositingSurface
->mpLastBitmapCanvas
= pBitmap
->getBitmapCanvas();
655 // buffer aCompositingSurface iterator content
656 // - said one might get invalidated during
658 ::cppcanvas::BitmapCanvasSharedPtr
pBitmapCanvas(
659 aCompositingSurface
->mpLastBitmapCanvas
);
661 ::cppcanvas::BitmapSharedPtr
pBitmap(
662 aCompositingSurface
->mpLastBitmap
);
664 // setup bitmap canvas transformation -
665 // which happens to be the destination
666 // canvas transformation without any
667 // translational components.
669 // But then, the render transformation as
670 // calculated by getShapeTransformation()
671 // above outputs the shape at its real
672 // destination position. Thus, we have to
673 // offset the output back to the origin,
674 // for which we simply plug in the
675 // negative position of the left, top edge
676 // of the shape's bound rect in device
677 // pixel into aLinearTransform below.
678 ::basegfx::B2DHomMatrix
aAdjustedCanvasTransform( aCanvasTransform
);
679 aAdjustedCanvasTransform
.translate( -aTmpRect
.getMinX(),
680 -aTmpRect
.getMinY() );
682 pBitmapCanvas
->setTransformation( aAdjustedCanvasTransform
);
684 // TODO(P2): If no update flags, or only
685 // alpha_update is set, we can save us the
686 // rendering into the bitmap (uh, it's not
687 // _that_ easy - for a forced redraw,
688 // e.g. when ending an animation, we always
689 // get UPDATE_FORCE here).
691 // render into this bitmap
692 if( !draw( pBitmapCanvas
,
696 !aClip
? NULL
: &(*aClip
),
702 // render bitmap to screen, with given global
703 // alpha. Since the bitmap already contains
704 // pixel-equivalent output, we have to use the
705 // inverse view transformation, adjusted with
706 // the final shape output position (note:
707 // cannot simply change the view
708 // transformation here, as that would affect a
709 // possibly set clip!)
710 ::basegfx::B2DHomMatrix
aBitmapTransform( aCanvasTransform
);
711 OSL_ENSURE( aBitmapTransform
.isInvertible(),
712 "ViewShape::render(): View transformation is singular!" );
714 aBitmapTransform
.invert();
716 ::basegfx::B2DHomMatrix aTranslation
;
717 aTranslation
.translate( aTmpRect
.getMinX(),
718 aTmpRect
.getMinY() );
720 aBitmapTransform
= aBitmapTransform
* aTranslation
;
721 pBitmap
->setTransformation( aBitmapTransform
);
723 // finally, render bitmap alpha-modulated
724 pBitmap
->drawAlphaModulated( nAlpha
);
731 // retrieve shape transformation, _with_ shape translation
732 // to actual page position.
733 const ::basegfx::B2DHomMatrix
aTransform(
734 getShapeTransformation( rBounds
,
737 return draw( rDestinationCanvas
,
741 !aClip
? NULL
: &(*aClip
),
746 // -------------------------------------------------------------------------------------
748 ViewShape::ViewShape( const ViewLayerSharedPtr
& rViewLayer
) :
749 mpViewLayer( rViewLayer
),
752 mbAnimationMode( false ),
753 mbForceUpdate( true )
755 ENSURE_OR_THROW( mpViewLayer
, "ViewShape::ViewShape(): Invalid View" );
758 ViewLayerSharedPtr
ViewShape::getViewLayer() const
763 ViewShape::RendererCacheVector::iterator
ViewShape::getCacheEntry( const ::cppcanvas::CanvasSharedPtr
& rDestinationCanvas
) const
765 // lookup destination canvas - is there already a renderer
766 // created for that target?
767 RendererCacheVector::iterator aIter
;
768 const RendererCacheVector::iterator
aEnd( maRenderers
.end() );
771 if( (aIter
=::std::find_if( maRenderers
.begin(),
774 ::std::equal_to
< ::cppcanvas::CanvasSharedPtr
>(),
775 ::boost::cref( rDestinationCanvas
),
777 &RendererCacheEntry::getDestinationCanvas
,
780 if( maRenderers
.size() >= MAX_RENDER_CACHE_ENTRIES
)
782 // cache size exceeded - prune entries. For now,
783 // simply remove the first one, which of course
784 // breaks for more complex access schemes. But in
785 // general, this leads to most recently used
786 // entries to reside at the end of the vector.
787 maRenderers
.erase( maRenderers
.begin() );
789 // ATTENTION: after this, both aIter and aEnd are
793 // not yet in cache - add default-constructed cache
794 // entry, to have something to return
795 maRenderers
.push_back( RendererCacheEntry() );
796 aIter
= maRenderers
.end()-1;
802 ::cppcanvas::RendererSharedPtr
ViewShape::getRenderer( const ::cppcanvas::CanvasSharedPtr
& rDestinationCanvas
,
803 const GDIMetaFileSharedPtr
& rMtf
,
804 const ShapeAttributeLayerSharedPtr
& rAttr
) const
806 // lookup destination canvas - is there already a renderer
807 // created for that target?
808 const RendererCacheVector::iterator
aIter(
809 getCacheEntry( rDestinationCanvas
) );
811 // now we have a valid entry, either way. call prefetch()
812 // on it, nevertheless - maybe the metafile changed, and
813 // the renderer still needs an update (prefetch() will
815 if( prefetch( *aIter
,
820 return aIter
->mpRenderer
;
824 // prefetch failed - renderer is invalid
825 return ::cppcanvas::RendererSharedPtr();
829 void ViewShape::invalidateRenderer() const
831 // simply clear the cache. Subsequent getRenderer() calls
832 // will regenerate the Renderers.
836 ::basegfx::B2DSize
ViewShape::getAntialiasingBorder() const
838 ENSURE_OR_THROW( mpViewLayer
->getCanvas(),
839 "ViewShape::getAntialiasingBorder(): Invalid ViewLayer canvas" );
841 const ::basegfx::B2DHomMatrix
& rViewTransform(
842 mpViewLayer
->getTransformation() );
844 // TODO(F1): As a quick shortcut (did not want to invert
845 // whole matrix here), taking only scale components of
846 // view transformation matrix. This will be wrong when
847 // e.g. shearing is involved.
848 const double nXBorder( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
/ rViewTransform
.get(0,0) );
849 const double nYBorder( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
/ rViewTransform
.get(1,1) );
851 return ::basegfx::B2DSize( nXBorder
,
855 bool ViewShape::enterAnimationMode()
857 mbForceUpdate
= true;
858 mbAnimationMode
= true;
863 void ViewShape::leaveAnimationMode()
866 mbAnimationMode
= false;
867 mbForceUpdate
= true;
870 bool ViewShape::update( const GDIMetaFileSharedPtr
& rMtf
,
871 const RenderArgs
& rArgs
,
873 bool bIsVisible
) const
875 RTL_LOGFILE_CONTEXT( aLog
, "::presentation::internal::ViewShape::update()" );
876 ENSURE_OR_RETURN( mpViewLayer
->getCanvas(), "ViewShape::update(): Invalid layer canvas" );
878 // Shall we render to a sprite, or to a plain canvas?
879 if( isBackgroundDetached() )
880 return renderSprite( mpViewLayer
,
888 rArgs
.mnShapePriority
,
891 return render( mpViewLayer
->getCanvas(),
894 rArgs
.maUpdateBounds
,