1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <canvas/debug.hxx>
23 #include <tools/diagnose_ex.h>
27 #include <rtl/math.hxx>
29 #include <com/sun/star/rendering/XCanvas.hpp>
30 #include <com/sun/star/rendering/XIntegerBitmap.hpp>
31 #include <com/sun/star/rendering/PanoseLetterForm.hpp>
32 #include <com/sun/star/awt/FontSlant.hpp>
34 #include <cppuhelper/exc_hlp.hxx>
35 #include <comphelper/anytostring.hxx>
37 #include <basegfx/polygon/b2dpolygontools.hxx>
38 #include <basegfx/numeric/ftools.hxx>
39 #include <basegfx/matrix/b2dhommatrix.hxx>
40 #include <basegfx/matrix/b2dhommatrixtools.hxx>
42 #include <canvas/verbosetrace.hxx>
43 #include <canvas/canvastools.hxx>
44 #include <cppcanvas/vclfactory.hxx>
45 #include <cppcanvas/basegfxfactory.hxx>
47 #include "viewshape.hxx"
50 #include <boost/bind.hpp>
53 using namespace ::com::sun::star
;
60 // TODO(F2): Provide sensible setup for mtf-related attributes (fill mode,
61 // char rotation etc.). Do that via mtf argument at this object
63 bool ViewShape::prefetch( RendererCacheEntry
& io_rCacheEntry
,
64 const ::cppcanvas::CanvasSharedPtr
& rDestinationCanvas
,
65 const GDIMetaFileSharedPtr
& rMtf
,
66 const ShapeAttributeLayerSharedPtr
& rAttr
)
68 ENSURE_OR_RETURN_FALSE( rMtf
,
69 "ViewShape::prefetch(): no valid metafile!" );
71 if( rMtf
!= io_rCacheEntry
.mpMtf
||
72 rDestinationCanvas
!= io_rCacheEntry
.getDestinationCanvas() )
74 // buffered renderer invalid, re-create
75 ::cppcanvas::Renderer::Parameters aParms
;
77 // rendering attribute override parameter struct. For
78 // every valid attribute, the corresponding struct
79 // member is filled, which in the metafile renderer
80 // forces rendering with the given attribute.
83 if( rAttr
->isFillColorValid() )
85 // convert RGBColor to RGBA32 integer. Note
86 // that getIntegerColor() also truncates
87 // out-of-range values appropriately
89 rAttr
->getFillColor().getIntegerColor();
91 if( rAttr
->isLineColorValid() )
93 // convert RGBColor to RGBA32 integer. Note
94 // that getIntegerColor() also truncates
95 // out-of-range values appropriately
97 rAttr
->getLineColor().getIntegerColor();
99 if( rAttr
->isCharColorValid() )
101 // convert RGBColor to RGBA32 integer. Note
102 // that getIntegerColor() also truncates
103 // out-of-range values appropriately
105 rAttr
->getCharColor().getIntegerColor();
107 if( rAttr
->isDimColorValid() )
109 // convert RGBColor to RGBA32 integer. Note
110 // that getIntegerColor() also truncates
111 // out-of-range values appropriately
113 // dim color overrides all other colors
117 rAttr
->getDimColor().getIntegerColor();
119 if( rAttr
->isFontFamilyValid() )
122 rAttr
->getFontFamily();
124 if( rAttr
->isCharScaleValid() )
126 ::basegfx::B2DHomMatrix aMatrix
;
128 // enlarge text by given scale factor. Do that
129 // with the middle of the shape as the center
131 aMatrix
.translate( -0.5, -0.5 );
132 aMatrix
.scale( rAttr
->getCharScale(),
133 rAttr
->getCharScale() );
134 aMatrix
.translate( 0.5, 0.5 );
136 aParms
.maTextTransformation
= aMatrix
;
138 if( rAttr
->isCharWeightValid() )
140 aParms
.maFontWeight
=
141 static_cast< sal_Int8
>(
145 rAttr
->getCharWeight() / 20.0 ) ) ) );
147 if( rAttr
->isCharPostureValid() )
149 aParms
.maFontLetterForm
=
150 rAttr
->getCharPosture() == awt::FontSlant_NONE
?
151 rendering::PanoseLetterForm::ANYTHING
:
152 rendering::PanoseLetterForm::OBLIQUE_CONTACT
;
154 if( rAttr
->isUnderlineModeValid() )
156 aParms
.maFontUnderline
=
157 rAttr
->getUnderlineMode();
161 io_rCacheEntry
.mpRenderer
= ::cppcanvas::VCLFactory::createRenderer( rDestinationCanvas
,
165 io_rCacheEntry
.mpMtf
= rMtf
;
166 io_rCacheEntry
.mpDestinationCanvas
= rDestinationCanvas
;
168 // also invalidate alpha compositing bitmap (created
169 // new renderer, which possibly generates different
170 // output). Do NOT invalidate, if we're incidentally
171 // rendering INTO it.
172 if( rDestinationCanvas
!= io_rCacheEntry
.mpLastBitmapCanvas
)
174 io_rCacheEntry
.mpLastBitmapCanvas
.reset();
175 io_rCacheEntry
.mpLastBitmap
.reset();
179 return static_cast< bool >(io_rCacheEntry
.mpRenderer
);
182 bool ViewShape::draw( const ::cppcanvas::CanvasSharedPtr
& rDestinationCanvas
,
183 const GDIMetaFileSharedPtr
& rMtf
,
184 const ShapeAttributeLayerSharedPtr
& rAttr
,
185 const ::basegfx::B2DHomMatrix
& rTransform
,
186 const ::basegfx::B2DPolyPolygon
* pClip
,
187 const VectorOfDocTreeNodes
& rSubsets
) const
189 ::cppcanvas::RendererSharedPtr
pRenderer(
190 getRenderer( rDestinationCanvas
, rMtf
, rAttr
) );
192 ENSURE_OR_RETURN_FALSE( pRenderer
, "ViewShape::draw(): Invalid renderer" );
194 pRenderer
->setTransformation( rTransform
);
195 #if OSL_DEBUG_LEVEL >= 2
196 rendering::RenderState aRenderState
;
197 ::canvas::tools::initRenderState(aRenderState
);
198 ::canvas::tools::setRenderStateTransform(aRenderState
,
200 aRenderState
.DeviceColor
.realloc(4);
201 aRenderState
.DeviceColor
[0] = 1.0;
202 aRenderState
.DeviceColor
[1] = 0.0;
203 aRenderState
.DeviceColor
[2] = 0.0;
204 aRenderState
.DeviceColor
[3] = 1.0;
208 rDestinationCanvas
->getUNOCanvas()->drawLine( geometry::RealPoint2D(0.0,0.0),
209 geometry::RealPoint2D(1.0,1.0),
210 rDestinationCanvas
->getViewState(),
212 rDestinationCanvas
->getUNOCanvas()->drawLine( geometry::RealPoint2D(1.0,0.0),
213 geometry::RealPoint2D(0.0,1.0),
214 rDestinationCanvas
->getViewState(),
217 catch( uno::Exception
& )
219 DBG_UNHANDLED_EXCEPTION();
223 pRenderer
->setClip( *pClip
);
225 pRenderer
->setClip();
227 if( rSubsets
.empty() )
229 return pRenderer
->draw();
233 // render subsets of whole metafile
237 VectorOfDocTreeNodes::const_iterator
aIter( rSubsets
.begin() );
238 const VectorOfDocTreeNodes::const_iterator
aEnd ( rSubsets
.end() );
239 while( aIter
!= aEnd
)
241 if( !pRenderer
->drawSubset( aIter
->getStartIndex(),
242 aIter
->getEndIndex() ) )
254 /// Convert untransformed shape update area to device pixel.
255 ::basegfx::B2DRectangle
shapeArea2AreaPixel( const ::basegfx::B2DHomMatrix
& rCanvasTransformation
,
256 const ::basegfx::B2DRectangle
& rUntransformedArea
)
258 // convert area to pixel, and add anti-aliasing border
260 // TODO(P1): Should the view transform some
261 // day contain rotation/shear, transforming
262 // the original bounds with the total
263 // transformation might result in smaller
266 ::basegfx::B2DRectangle aBoundsPixel
;
267 ::canvas::tools::calcTransformedRectBounds( aBoundsPixel
,
269 rCanvasTransformation
);
271 // add antialiasing border around the shape (AA
272 // touches pixel _outside_ the nominal bound rect)
273 aBoundsPixel
.grow( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
);
278 /// Convert shape unit rect to device pixel.
279 ::basegfx::B2DRectangle
calcUpdateAreaPixel( const ::basegfx::B2DRectangle
& rUnitBounds
,
280 const ::basegfx::B2DHomMatrix
& rShapeTransformation
,
281 const ::basegfx::B2DHomMatrix
& rCanvasTransformation
,
282 const ShapeAttributeLayerSharedPtr
& pAttr
)
284 // calc update area for whole shape (including
285 // character scaling)
286 return shapeArea2AreaPixel( rCanvasTransformation
,
287 getShapeUpdateArea( rUnitBounds
,
288 rShapeTransformation
,
293 bool ViewShape::renderSprite( const ViewLayerSharedPtr
& rViewLayer
,
294 const GDIMetaFileSharedPtr
& rMtf
,
295 const ::basegfx::B2DRectangle
& rOrigBounds
,
296 const ::basegfx::B2DRectangle
& rBounds
,
297 const ::basegfx::B2DRectangle
& rUnitBounds
,
299 const ShapeAttributeLayerSharedPtr
& pAttr
,
300 const VectorOfDocTreeNodes
& rSubsets
,
302 bool bIsVisible
) const
304 // TODO(P1): For multiple views, it might pay off to reorg Shape and ViewShape,
305 // in that all the common setup steps here are refactored to Shape (would then
306 // have to be performed only _once_ per Shape paint).
309 rUnitBounds
.isEmpty() ||
310 rOrigBounds
.isEmpty() ||
313 // shape is invisible or has zero size, no need to
322 // calc sprite position, size and content transformation
323 // =====================================================
325 // the shape transformation for a sprite is always a
326 // simple scale-up to the nominal shape size. Everything
327 // else is handled via the sprite transformation
328 ::basegfx::B2DHomMatrix aNonTranslationalShapeTransformation
;
329 aNonTranslationalShapeTransformation
.scale( rOrigBounds
.getWidth(),
330 rOrigBounds
.getHeight() );
331 ::basegfx::B2DHomMatrix
aShapeTransformation( aNonTranslationalShapeTransformation
);
332 aShapeTransformation
.translate( rOrigBounds
.getMinX(),
333 rOrigBounds
.getMinY() );
335 const ::basegfx::B2DHomMatrix
& rCanvasTransform(
336 rViewLayer
->getSpriteTransformation() );
338 // area actually needed for the sprite
339 const ::basegfx::B2DRectangle
& rSpriteBoundsPixel(
340 calcUpdateAreaPixel( rUnitBounds
,
341 aShapeTransformation
,
345 // actual area for the shape (without subsetting, but
346 // including char scaling)
347 const ::basegfx::B2DRectangle
& rShapeBoundsPixel(
348 calcUpdateAreaPixel( ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0),
349 aShapeTransformation
,
353 // nominal area for the shape (without subsetting, without
354 // char scaling). NOTE: to cancel the shape translation,
355 // contained in rSpriteBoundsPixel, this is _without_ any
356 // translational component.
357 ::basegfx::B2DRectangle aLogShapeBounds
;
358 const ::basegfx::B2DRectangle
& rNominalShapeBoundsPixel(
359 shapeArea2AreaPixel( rCanvasTransform
,
360 ::canvas::tools::calcTransformedRectBounds(
362 ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0),
363 aNonTranslationalShapeTransformation
) ) );
365 // create (or resize) sprite with sprite's pixel size, if
367 const ::basegfx::B2DSize
& rSpriteSizePixel(rSpriteBoundsPixel
.getRange());
371 new AnimatedSprite( mpViewLayer
,
377 // TODO(F2): when the sprite _actually_ gets resized,
378 // content needs a repaint!
379 mpSprite
->resize( rSpriteSizePixel
);
382 ENSURE_OR_RETURN_FALSE( mpSprite
, "ViewShape::renderSprite(): No sprite" );
384 VERBOSE_TRACE( "ViewShape::renderSprite(): Rendering sprite 0x%p",
388 // always show the sprite (might have been hidden before)
391 // determine center of sprite output position in pixel
392 // (assumption here: all shape transformations have the
393 // shape center as the pivot point). From that, subtract
394 // distance of rSpriteBoundsPixel's left, top edge from
395 // rShapeBoundsPixel's center. This moves the sprite at
396 // the appropriate output position within the virtual
397 // rShapeBoundsPixel area.
398 ::basegfx::B2DPoint
aSpritePosPixel( rBounds
.getCenter() );
399 aSpritePosPixel
*= rCanvasTransform
;
400 aSpritePosPixel
-= rShapeBoundsPixel
.getCenter() - rSpriteBoundsPixel
.getMinimum();
402 // the difference between rShapeBoundsPixel and
403 // rSpriteBoundsPixel upper, left corner is: the offset we
404 // have to move sprite output to the right, top (to make
405 // the desired subset content visible at all)
406 const ::basegfx::B2DSize
& rSpriteCorrectionOffset(
407 rSpriteBoundsPixel
.getMinimum() - rNominalShapeBoundsPixel
.getMinimum() );
409 // offset added top, left for anti-aliasing (otherwise,
410 // shapes fully filling the sprite will have anti-aliased
412 const ::basegfx::B2DSize
aAAOffset(
413 ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
,
414 ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
);
416 // set pixel output offset to sprite: we always leave
417 // ANTIALIASING_EXTRA_SIZE room atop and to the left, and,
418 // what's more, for subsetted shapes, we _have_ to cancel
419 // the effect of the shape renderer outputting the subset
420 // at its absolute position inside the shape, instead of
422 // NOTE: As for now, sprites are always positioned on
423 // integer pixel positions on screen, have to round to
424 // nearest integer here, too
425 mpSprite
->setPixelOffset(
426 aAAOffset
- ::basegfx::B2DSize(
427 ::basegfx::fround( rSpriteCorrectionOffset
.getX() ),
428 ::basegfx::fround( rSpriteCorrectionOffset
.getY() ) ) );
430 // always set sprite position and transformation, since
431 // they do not relate directly to the update flags
432 // (e.g. sprite position changes when sprite size changes)
433 mpSprite
->movePixel( aSpritePosPixel
);
434 mpSprite
->transform( getSpriteTransformation( rSpriteSizePixel
,
435 rOrigBounds
.getRange(),
442 bool bRedrawRequired( mbForceUpdate
|| (nUpdateFlags
& FORCE
) );
444 if( mbForceUpdate
|| (nUpdateFlags
& ALPHA
) )
446 mpSprite
->setAlpha( (pAttr
&& pAttr
->isAlphaValid()) ?
447 ::basegfx::clamp(pAttr
->getAlpha(),
452 if( mbForceUpdate
|| (nUpdateFlags
& CLIP
) )
454 if( pAttr
&& pAttr
->isClipValid() )
456 ::basegfx::B2DPolyPolygon
aClipPoly( pAttr
->getClip() );
458 // extract linear part of canvas view transformation
459 // (linear means: without translational components)
460 ::basegfx::B2DHomMatrix
aViewTransform(
461 mpViewLayer
->getTransformation() );
462 aViewTransform
.set( 0, 2, 0.0 );
463 aViewTransform
.set( 1, 2, 0.0 );
465 // make the clip 2*ANTIALIASING_EXTRA_SIZE larger
466 // such that it's again centered over the sprite.
467 aViewTransform
.scale(rSpriteSizePixel
.getX()/
468 (rSpriteSizePixel
.getX()-2*::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
),
469 rSpriteSizePixel
.getY()/
470 (rSpriteSizePixel
.getY()-2*::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
));
472 // transform clip polygon from view to device
474 aClipPoly
.transform( aViewTransform
);
476 mpSprite
->clip( aClipPoly
);
481 if( mbForceUpdate
|| (nUpdateFlags
& CONTENT
) )
483 bRedrawRequired
= true;
485 // TODO(P1): maybe provide some appearance change methods at
486 // the Renderer interface
488 // force the renderer to be regenerated below, for the
489 // different attributes to take effect
490 invalidateRenderer();
493 mbForceUpdate
= false;
495 if( !bRedrawRequired
)
499 // sprite needs repaint - output to sprite canvas
500 // ==============================================
502 ::cppcanvas::CanvasSharedPtr
pContentCanvas( mpSprite
->getContentCanvas() );
504 return draw( pContentCanvas
,
507 aShapeTransformation
,
508 NULL
, // clipping is done via Sprite::clip()
512 bool ViewShape::render( const ::cppcanvas::CanvasSharedPtr
& rDestinationCanvas
,
513 const GDIMetaFileSharedPtr
& rMtf
,
514 const ::basegfx::B2DRectangle
& rBounds
,
515 const ::basegfx::B2DRectangle
& rUpdateBounds
,
517 const ShapeAttributeLayerSharedPtr
& pAttr
,
518 const VectorOfDocTreeNodes
& rSubsets
,
519 bool bIsVisible
) const
521 // TODO(P1): For multiple views, it might pay off to reorg Shape and ViewShape,
522 // in that all the common setup steps here are refactored to Shape (would then
523 // have to be performed only _once_ per Shape paint).
527 VERBOSE_TRACE( "ViewShape::render(): skipping shape %p", this );
529 // shape is invisible, no need to update anything.
533 // since we have no sprite here, _any_ update request
534 // translates into a required redraw.
535 bool bRedrawRequired( mbForceUpdate
|| nUpdateFlags
!= 0 );
537 if( (nUpdateFlags
& CONTENT
) )
539 // TODO(P1): maybe provide some appearance change methods at
540 // the Renderer interface
542 // force the renderer to be regenerated below, for the
543 // different attributes to take effect
544 invalidateRenderer();
547 mbForceUpdate
= false;
549 if( !bRedrawRequired
)
552 VERBOSE_TRACE( "ViewShape::render(): rendering shape %p at position (%f,%f)",
558 // shape needs repaint - setup all that's needed
561 boost::optional
<basegfx::B2DPolyPolygon
> aClip
;
566 if( pAttr
->isClipValid() )
567 aClip
.reset( pAttr
->getClip() );
569 // emulate global shape alpha by first rendering into
570 // a temp bitmap, and then to screen (this would have
571 // been much easier if we'd be currently a sprite -
573 if( pAttr
->isAlphaValid() )
575 const double nAlpha( pAttr
->getAlpha() );
577 if( !::basegfx::fTools::equalZero( nAlpha
) &&
578 !::rtl::math::approxEqual(nAlpha
, 1.0) )
580 // render with global alpha - have to prepare
581 // a bitmap, and render that with modulated
585 const ::basegfx::B2DHomMatrix
aTransform(
586 getShapeTransformation( rBounds
,
589 // TODO(P1): Should the view transform some
590 // day contain rotation/shear, transforming
591 // the original bounds with the total
592 // transformation might result in smaller
595 // determine output rect of _shape update
596 // area_ in device pixel
597 const ::basegfx::B2DHomMatrix
aCanvasTransform(
598 rDestinationCanvas
->getTransformation() );
599 ::basegfx::B2DRectangle aTmpRect
;
600 ::canvas::tools::calcTransformedRectBounds( aTmpRect
,
604 // pixel size of cache bitmap: round up to
606 const ::basegfx::B2ISize
aBmpSize( static_cast<sal_Int32
>( aTmpRect
.getWidth() )+1,
607 static_cast<sal_Int32
>( aTmpRect
.getHeight() )+1 );
609 // try to fetch temporary surface for alpha
610 // compositing (to achieve the global alpha
611 // blend effect, have to first render shape as
612 // a whole, then blit that surface with global
613 // alpha to the destination)
614 const RendererCacheVector::iterator
aCompositingSurface(
615 getCacheEntry( rDestinationCanvas
) );
617 if( !aCompositingSurface
->mpLastBitmapCanvas
||
618 aCompositingSurface
->mpLastBitmapCanvas
->getSize() != aBmpSize
)
620 // create a bitmap of appropriate size
621 ::cppcanvas::BitmapSharedPtr
pBitmap(
622 ::cppcanvas::BaseGfxFactory::createAlphaBitmap(
626 ENSURE_OR_THROW(pBitmap
,
627 "ViewShape::render(): Could not create compositing surface");
629 aCompositingSurface
->mpDestinationCanvas
= rDestinationCanvas
;
630 aCompositingSurface
->mpLastBitmap
= pBitmap
;
631 aCompositingSurface
->mpLastBitmapCanvas
= pBitmap
->getBitmapCanvas();
634 // buffer aCompositingSurface iterator content
635 // - said one might get invalidated during
637 ::cppcanvas::BitmapCanvasSharedPtr
pBitmapCanvas(
638 aCompositingSurface
->mpLastBitmapCanvas
);
640 ::cppcanvas::BitmapSharedPtr
pBitmap(
641 aCompositingSurface
->mpLastBitmap
);
643 // setup bitmap canvas transformation -
644 // which happens to be the destination
645 // canvas transformation without any
646 // translational components.
648 // But then, the render transformation as
649 // calculated by getShapeTransformation()
650 // above outputs the shape at its real
651 // destination position. Thus, we have to
652 // offset the output back to the origin,
653 // for which we simply plug in the
654 // negative position of the left, top edge
655 // of the shape's bound rect in device
656 // pixel into aLinearTransform below.
657 ::basegfx::B2DHomMatrix
aAdjustedCanvasTransform( aCanvasTransform
);
658 aAdjustedCanvasTransform
.translate( -aTmpRect
.getMinX(),
659 -aTmpRect
.getMinY() );
661 pBitmapCanvas
->setTransformation( aAdjustedCanvasTransform
);
663 // TODO(P2): If no update flags, or only
664 // alpha_update is set, we can save us the
665 // rendering into the bitmap (uh, it's not
666 // _that_ easy - for a forced redraw,
667 // e.g. when ending an animation, we always
668 // get UPDATE_FORCE here).
670 // render into this bitmap
671 if( !draw( pBitmapCanvas
,
675 !aClip
? NULL
: &(*aClip
),
681 // render bitmap to screen, with given global
682 // alpha. Since the bitmap already contains
683 // pixel-equivalent output, we have to use the
684 // inverse view transformation, adjusted with
685 // the final shape output position (note:
686 // cannot simply change the view
687 // transformation here, as that would affect a
688 // possibly set clip!)
689 ::basegfx::B2DHomMatrix
aBitmapTransform( aCanvasTransform
);
690 OSL_ENSURE( aBitmapTransform
.isInvertible(),
691 "ViewShape::render(): View transformation is singular!" );
693 aBitmapTransform
.invert();
695 const basegfx::B2DHomMatrix
aTranslation(basegfx::tools::createTranslateB2DHomMatrix(
696 aTmpRect
.getMinX(), aTmpRect
.getMinY()));
698 aBitmapTransform
= aBitmapTransform
* aTranslation
;
699 pBitmap
->setTransformation( aBitmapTransform
);
701 // finally, render bitmap alpha-modulated
702 pBitmap
->drawAlphaModulated( nAlpha
);
709 // retrieve shape transformation, _with_ shape translation
710 // to actual page position.
711 const ::basegfx::B2DHomMatrix
aTransform(
712 getShapeTransformation( rBounds
,
715 return draw( rDestinationCanvas
,
719 !aClip
? NULL
: &(*aClip
),
726 ViewShape::ViewShape( const ViewLayerSharedPtr
& rViewLayer
) :
727 mpViewLayer( rViewLayer
),
730 mbAnimationMode( false ),
731 mbForceUpdate( true )
733 ENSURE_OR_THROW( mpViewLayer
, "ViewShape::ViewShape(): Invalid View" );
736 ViewLayerSharedPtr
ViewShape::getViewLayer() const
741 ViewShape::RendererCacheVector::iterator
ViewShape::getCacheEntry( const ::cppcanvas::CanvasSharedPtr
& rDestinationCanvas
) const
743 // lookup destination canvas - is there already a renderer
744 // created for that target?
745 RendererCacheVector::iterator aIter
;
746 const RendererCacheVector::iterator
aEnd( maRenderers
.end() );
749 if( (aIter
=::std::find_if( maRenderers
.begin(),
752 ::std::equal_to
< ::cppcanvas::CanvasSharedPtr
>(),
753 ::boost::cref( rDestinationCanvas
),
755 &RendererCacheEntry::getDestinationCanvas
,
758 if( maRenderers
.size() >= MAX_RENDER_CACHE_ENTRIES
)
760 // cache size exceeded - prune entries. For now,
761 // simply remove the first one, which of course
762 // breaks for more complex access schemes. But in
763 // general, this leads to most recently used
764 // entries to reside at the end of the vector.
765 maRenderers
.erase( maRenderers
.begin() );
767 // ATTENTION: after this, both aIter and aEnd are
771 // not yet in cache - add default-constructed cache
772 // entry, to have something to return
773 maRenderers
.push_back( RendererCacheEntry() );
774 aIter
= maRenderers
.end()-1;
780 ::cppcanvas::RendererSharedPtr
ViewShape::getRenderer( const ::cppcanvas::CanvasSharedPtr
& rDestinationCanvas
,
781 const GDIMetaFileSharedPtr
& rMtf
,
782 const ShapeAttributeLayerSharedPtr
& rAttr
) const
784 // lookup destination canvas - is there already a renderer
785 // created for that target?
786 const RendererCacheVector::iterator
aIter(
787 getCacheEntry( rDestinationCanvas
) );
789 // now we have a valid entry, either way. call prefetch()
790 // on it, nevertheless - maybe the metafile changed, and
791 // the renderer still needs an update (prefetch() will
793 if( prefetch( *aIter
,
798 return aIter
->mpRenderer
;
802 // prefetch failed - renderer is invalid
803 return ::cppcanvas::RendererSharedPtr();
807 void ViewShape::invalidateRenderer() const
809 // simply clear the cache. Subsequent getRenderer() calls
810 // will regenerate the Renderers.
814 ::basegfx::B2DSize
ViewShape::getAntialiasingBorder() const
816 ENSURE_OR_THROW( mpViewLayer
->getCanvas(),
817 "ViewShape::getAntialiasingBorder(): Invalid ViewLayer canvas" );
819 const ::basegfx::B2DHomMatrix
& rViewTransform(
820 mpViewLayer
->getTransformation() );
822 // TODO(F1): As a quick shortcut (did not want to invert
823 // whole matrix here), taking only scale components of
824 // view transformation matrix. This will be wrong when
825 // e.g. shearing is involved.
826 const double nXBorder( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
/ rViewTransform
.get(0,0) );
827 const double nYBorder( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE
/ rViewTransform
.get(1,1) );
829 return ::basegfx::B2DSize( nXBorder
,
833 bool ViewShape::enterAnimationMode()
835 mbForceUpdate
= true;
836 mbAnimationMode
= true;
841 void ViewShape::leaveAnimationMode()
844 mbAnimationMode
= false;
845 mbForceUpdate
= true;
848 bool ViewShape::update( const GDIMetaFileSharedPtr
& rMtf
,
849 const RenderArgs
& rArgs
,
851 bool bIsVisible
) const
853 ENSURE_OR_RETURN_FALSE( mpViewLayer
->getCanvas(), "ViewShape::update(): Invalid layer canvas" );
855 // Shall we render to a sprite, or to a plain canvas?
856 if( isBackgroundDetached() )
857 return renderSprite( mpViewLayer
,
865 rArgs
.mnShapePriority
,
868 return render( mpViewLayer
->getCanvas(),
871 rArgs
.maUpdateBounds
,
881 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */