fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / slideshow / source / engine / shapes / viewshape.cxx
blob2653c975327074f3c51d0303a97c24ee1f4f0c09
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 // must be first
22 #include <canvas/debug.hxx>
23 #include <tools/diagnose_ex.h>
25 #include <math.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"
48 #include "tools.hxx"
50 #include <boost/bind.hpp>
53 using namespace ::com::sun::star;
55 namespace slideshow
57 namespace internal
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.
81 if( rAttr )
83 if( rAttr->isFillColorValid() )
85 // convert RGBColor to RGBA32 integer. Note
86 // that getIntegerColor() also truncates
87 // out-of-range values appropriately
88 aParms.maFillColor =
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
96 aParms.maLineColor =
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
104 aParms.maTextColor =
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
114 aParms.maFillColor =
115 aParms.maLineColor =
116 aParms.maTextColor =
117 rAttr->getDimColor().getIntegerColor();
119 if( rAttr->isFontFamilyValid() )
121 aParms.maFontName =
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
130 // of scaling.
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 >(
142 ::basegfx::fround(
143 ::std::max( 0.0,
144 ::std::min( 11.0,
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,
162 *rMtf.get(),
163 aParms );
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,
199 rTransform);
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(),
211 aRenderState );
212 rDestinationCanvas->getUNOCanvas()->drawLine( geometry::RealPoint2D(1.0,0.0),
213 geometry::RealPoint2D(0.0,1.0),
214 rDestinationCanvas->getViewState(),
215 aRenderState );
217 catch( uno::Exception& )
219 DBG_UNHANDLED_EXCEPTION();
221 #endif
222 if( pClip )
223 pRenderer->setClip( *pClip );
224 else
225 pRenderer->setClip();
227 if( rSubsets.empty() )
229 return pRenderer->draw();
231 else
233 // render subsets of whole metafile
236 bool bRet(true);
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() ) )
243 bRet = false;
245 ++aIter;
248 return bRet;
252 namespace
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
264 // overall bounds.
266 ::basegfx::B2DRectangle aBoundsPixel;
267 ::canvas::tools::calcTransformedRectBounds( aBoundsPixel,
268 rUntransformedArea,
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 );
275 return aBoundsPixel;
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,
289 pAttr ) );
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,
298 int nUpdateFlags,
299 const ShapeAttributeLayerSharedPtr& pAttr,
300 const VectorOfDocTreeNodes& rSubsets,
301 double nPrio,
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).
308 if( !bIsVisible ||
309 rUnitBounds.isEmpty() ||
310 rOrigBounds.isEmpty() ||
311 rBounds.isEmpty() )
313 // shape is invisible or has zero size, no need to
314 // update anything.
315 if( mpSprite )
316 mpSprite->hide();
318 return true;
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,
342 rCanvasTransform,
343 pAttr ) );
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,
350 rCanvasTransform,
351 pAttr ) );
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(
361 aLogShapeBounds,
362 ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0),
363 aNonTranslationalShapeTransformation ) ) );
365 // create (or resize) sprite with sprite's pixel size, if
366 // not done already
367 const ::basegfx::B2DSize& rSpriteSizePixel(rSpriteBoundsPixel.getRange());
368 if( !mpSprite )
370 mpSprite.reset(
371 new AnimatedSprite( mpViewLayer,
372 rSpriteSizePixel,
373 nPrio ));
375 else
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",
385 mpSprite.get() );
388 // always show the sprite (might have been hidden before)
389 mpSprite->show();
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
411 // pixel cut off)
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
421 // at the origin.
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(),
436 pAttr ) );
439 // process flags
440 // =============
442 bool bRedrawRequired( mbForceUpdate || (nUpdateFlags & FORCE) );
444 if( mbForceUpdate || (nUpdateFlags & ALPHA) )
446 mpSprite->setAlpha( (pAttr && pAttr->isAlphaValid()) ?
447 ::basegfx::clamp(pAttr->getAlpha(),
448 0.0,
449 1.0) :
450 1.0 );
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
473 // coordinate space
474 aClipPoly.transform( aViewTransform );
476 mpSprite->clip( aClipPoly );
478 else
479 mpSprite->clip();
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 )
496 return true;
499 // sprite needs repaint - output to sprite canvas
500 // ==============================================
502 ::cppcanvas::CanvasSharedPtr pContentCanvas( mpSprite->getContentCanvas() );
504 return draw( pContentCanvas,
505 rMtf,
506 pAttr,
507 aShapeTransformation,
508 NULL, // clipping is done via Sprite::clip()
509 rSubsets );
512 bool ViewShape::render( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
513 const GDIMetaFileSharedPtr& rMtf,
514 const ::basegfx::B2DRectangle& rBounds,
515 const ::basegfx::B2DRectangle& rUpdateBounds,
516 int nUpdateFlags,
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).
525 if( !bIsVisible )
527 VERBOSE_TRACE( "ViewShape::render(): skipping shape %p", this );
529 // shape is invisible, no need to update anything.
530 return true;
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 )
550 return true;
552 VERBOSE_TRACE( "ViewShape::render(): rendering shape %p at position (%f,%f)",
553 this,
554 rBounds.getMinX(),
555 rBounds.getMinY() );
558 // shape needs repaint - setup all that's needed
561 boost::optional<basegfx::B2DPolyPolygon> aClip;
563 if( pAttr )
565 // setup clip poly
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 -
572 // see above)
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
582 // alpha
585 const ::basegfx::B2DHomMatrix aTransform(
586 getShapeTransformation( rBounds,
587 pAttr ) );
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
593 // overall bounds.
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,
601 rUpdateBounds,
602 aCanvasTransform );
604 // pixel size of cache bitmap: round up to
605 // nearest int
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(
623 rDestinationCanvas,
624 aBmpSize ) );
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
636 // draw() below.
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,
672 rMtf,
673 pAttr,
674 aTransform,
675 !aClip ? NULL : &(*aClip),
676 rSubsets ) )
678 return false;
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 );
704 return true;
709 // retrieve shape transformation, _with_ shape translation
710 // to actual page position.
711 const ::basegfx::B2DHomMatrix aTransform(
712 getShapeTransformation( rBounds,
713 pAttr ) );
715 return draw( rDestinationCanvas,
716 rMtf,
717 pAttr,
718 aTransform,
719 !aClip ? NULL : &(*aClip),
720 rSubsets );
726 ViewShape::ViewShape( const ViewLayerSharedPtr& rViewLayer ) :
727 mpViewLayer( rViewLayer ),
728 maRenderers(),
729 mpSprite(),
730 mbAnimationMode( false ),
731 mbForceUpdate( true )
733 ENSURE_OR_THROW( mpViewLayer, "ViewShape::ViewShape(): Invalid View" );
736 ViewLayerSharedPtr ViewShape::getViewLayer() const
738 return mpViewLayer;
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() );
748 // already there?
749 if( (aIter=::std::find_if( maRenderers.begin(),
750 aEnd,
751 ::boost::bind(
752 ::std::equal_to< ::cppcanvas::CanvasSharedPtr >(),
753 ::boost::cref( rDestinationCanvas ),
754 ::boost::bind(
755 &RendererCacheEntry::getDestinationCanvas,
756 _1 ) ) ) ) == aEnd )
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
768 // invalid!
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;
777 return aIter;
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
792 // detect that)
793 if( prefetch( *aIter,
794 rDestinationCanvas,
795 rMtf,
796 rAttr ) )
798 return aIter->mpRenderer;
800 else
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.
811 maRenderers.clear();
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,
830 nYBorder );
833 bool ViewShape::enterAnimationMode()
835 mbForceUpdate = true;
836 mbAnimationMode = true;
838 return true;
841 void ViewShape::leaveAnimationMode()
843 mpSprite.reset();
844 mbAnimationMode = false;
845 mbForceUpdate = true;
848 bool ViewShape::update( const GDIMetaFileSharedPtr& rMtf,
849 const RenderArgs& rArgs,
850 int nUpdateFlags,
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,
858 rMtf,
859 rArgs.maOrigBounds,
860 rArgs.maBounds,
861 rArgs.maUnitBounds,
862 nUpdateFlags,
863 rArgs.mrAttr,
864 rArgs.mrSubsets,
865 rArgs.mnShapePriority,
866 bIsVisible );
867 else
868 return render( mpViewLayer->getCanvas(),
869 rMtf,
870 rArgs.maBounds,
871 rArgs.maUpdateBounds,
872 nUpdateFlags,
873 rArgs.mrAttr,
874 rArgs.mrSubsets,
875 bIsVisible );
881 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */