merge the formfield patch from ooo-build
[ooovba.git] / slideshow / source / engine / shapes / viewshape.cxx
blob61e07ed689aea78932d31babd254a97c363cad83
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: viewshape.cxx,v $
10 * $Revision: 1.5 $
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"
34 // must be first
35 #include <canvas/debug.hxx>
36 #include <tools/diagnose_ex.h>
38 #include <math.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"
61 #include "tools.hxx"
62 #include "lerp.hxx"
64 #include <boost/bind.hpp>
67 using namespace ::com::sun::star;
69 namespace slideshow
71 namespace internal
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.
96 if( rAttr )
98 if( rAttr->isFillColorValid() )
100 // convert RGBColor to RGBA32 integer. Note
101 // that getIntegerColor() also truncates
102 // out-of-range values appropriately
103 aParms.maFillColor =
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
111 aParms.maLineColor =
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
119 aParms.maTextColor =
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
129 aParms.maFillColor =
130 aParms.maLineColor =
131 aParms.maTextColor =
132 rAttr->getDimColor().getIntegerColor();
134 if( rAttr->isFontFamilyValid() )
136 aParms.maFontName =
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
145 // of scaling.
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 >(
157 ::basegfx::fround(
158 ::std::max( 0.0,
159 ::std::min( 11.0,
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,
177 *rMtf.get(),
178 aParms );
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,
216 rTransform);
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(),
228 aRenderState );
229 rDestinationCanvas->getUNOCanvas()->drawLine( geometry::RealPoint2D(1.0,0.0),
230 geometry::RealPoint2D(0.0,1.0),
231 rDestinationCanvas->getViewState(),
232 aRenderState );
234 catch( uno::Exception& )
236 DBG_UNHANDLED_EXCEPTION();
238 #endif
239 if( pClip )
240 pRenderer->setClip( *pClip );
241 else
242 pRenderer->setClip();
244 if( rSubsets.empty() )
246 return pRenderer->draw();
248 else
250 // render subsets of whole metafile
251 // --------------------------------
253 bool bRet(true);
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() ) )
260 bRet = false;
262 ++aIter;
265 return bRet;
269 namespace
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
281 // overall bounds.
283 ::basegfx::B2DRectangle aBoundsPixel;
284 ::canvas::tools::calcTransformedRectBounds( aBoundsPixel,
285 rUntransformedArea,
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 );
292 return aBoundsPixel;
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,
306 pAttr ) );
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,
315 int nUpdateFlags,
316 const ShapeAttributeLayerSharedPtr& pAttr,
317 const VectorOfDocTreeNodes& rSubsets,
318 double nPrio,
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).
327 if( !bIsVisible ||
328 rUnitBounds.isEmpty() ||
329 rOrigBounds.isEmpty() ||
330 rBounds.isEmpty() )
332 // shape is invisible or has zero size, no need to
333 // update anything.
334 if( mpSprite )
335 mpSprite->hide();
337 return true;
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,
361 rCanvasTransform,
362 pAttr ) );
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,
369 rCanvasTransform,
370 pAttr ) );
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(
380 aLogShapeBounds,
381 ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0),
382 aNonTranslationalShapeTransformation ) ) );
384 // create (or resize) sprite with sprite's pixel size, if
385 // not done already
386 const ::basegfx::B2DSize& rSpriteSizePixel(rSpriteBoundsPixel.getRange());
387 if( !mpSprite )
389 mpSprite.reset(
390 new AnimatedSprite( mpViewLayer,
391 rSpriteSizePixel,
392 nPrio ));
394 else
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",
404 mpSprite.get() );
407 // always show the sprite (might have been hidden before)
408 mpSprite->show();
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
430 // pixel cut off)
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
440 // at the origin.
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(),
455 pAttr ) );
458 // process flags
459 // =============
461 bool bRedrawRequired( mbForceUpdate || (nUpdateFlags & FORCE) );
463 if( mbForceUpdate || (nUpdateFlags & ALPHA) )
465 mpSprite->setAlpha( (pAttr && pAttr->isAlphaValid()) ?
466 ::canvas::tools::clamp(pAttr->getAlpha(),
467 0.0,
468 1.0) :
469 1.0 );
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
492 // coordinate space
493 aClipPoly.transform( aViewTransform );
495 mpSprite->clip( aClipPoly );
497 else
498 mpSprite->clip();
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 )
515 return true;
518 // sprite needs repaint - output to sprite canvas
519 // ==============================================
521 ::cppcanvas::CanvasSharedPtr pContentCanvas( mpSprite->getContentCanvas() );
523 return draw( pContentCanvas,
524 rMtf,
525 pAttr,
526 aShapeTransformation,
527 NULL, // clipping is done via Sprite::clip()
528 rSubsets );
531 bool ViewShape::render( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
532 const GDIMetaFileSharedPtr& rMtf,
533 const ::basegfx::B2DRectangle& rBounds,
534 const ::basegfx::B2DRectangle& rUpdateBounds,
535 int nUpdateFlags,
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).
546 if( !bIsVisible )
548 VERBOSE_TRACE( "ViewShape::render(): skipping shape %X", this );
550 // shape is invisible, no need to update anything.
551 return true;
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 )
571 return true;
573 VERBOSE_TRACE( "ViewShape::render(): rendering shape %X at position (%f,%f)",
574 this,
575 rBounds.getMinX(),
576 rBounds.getMinY() );
579 // shape needs repaint - setup all that's needed
580 // ---------------------------------------------
582 boost::optional<basegfx::B2DPolyPolygon> aClip;
584 if( pAttr )
586 // setup clip poly
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 -
593 // see above)
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
603 // alpha
604 // -------------------------------------------
606 const ::basegfx::B2DHomMatrix aTransform(
607 getShapeTransformation( rBounds,
608 pAttr ) );
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
614 // overall bounds.
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,
622 rUpdateBounds,
623 aCanvasTransform );
625 // pixel size of cache bitmap: round up to
626 // nearest int
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(
644 rDestinationCanvas,
645 aBmpSize ) );
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
657 // draw() below.
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,
693 rMtf,
694 pAttr,
695 aTransform,
696 !aClip ? NULL : &(*aClip),
697 rSubsets ) )
699 return false;
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 );
726 return true;
731 // retrieve shape transformation, _with_ shape translation
732 // to actual page position.
733 const ::basegfx::B2DHomMatrix aTransform(
734 getShapeTransformation( rBounds,
735 pAttr ) );
737 return draw( rDestinationCanvas,
738 rMtf,
739 pAttr,
740 aTransform,
741 !aClip ? NULL : &(*aClip),
742 rSubsets );
746 // -------------------------------------------------------------------------------------
748 ViewShape::ViewShape( const ViewLayerSharedPtr& rViewLayer ) :
749 mpViewLayer( rViewLayer ),
750 maRenderers(),
751 mpSprite(),
752 mbAnimationMode( false ),
753 mbForceUpdate( true )
755 ENSURE_OR_THROW( mpViewLayer, "ViewShape::ViewShape(): Invalid View" );
758 ViewLayerSharedPtr ViewShape::getViewLayer() const
760 return mpViewLayer;
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() );
770 // already there?
771 if( (aIter=::std::find_if( maRenderers.begin(),
772 aEnd,
773 ::boost::bind(
774 ::std::equal_to< ::cppcanvas::CanvasSharedPtr >(),
775 ::boost::cref( rDestinationCanvas ),
776 ::boost::bind(
777 &RendererCacheEntry::getDestinationCanvas,
778 _1 ) ) ) ) == aEnd )
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
790 // invalid!
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;
799 return aIter;
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
814 // detect that)
815 if( prefetch( *aIter,
816 rDestinationCanvas,
817 rMtf,
818 rAttr ) )
820 return aIter->mpRenderer;
822 else
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.
833 maRenderers.clear();
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,
852 nYBorder );
855 bool ViewShape::enterAnimationMode()
857 mbForceUpdate = true;
858 mbAnimationMode = true;
860 return true;
863 void ViewShape::leaveAnimationMode()
865 mpSprite.reset();
866 mbAnimationMode = false;
867 mbForceUpdate = true;
870 bool ViewShape::update( const GDIMetaFileSharedPtr& rMtf,
871 const RenderArgs& rArgs,
872 int nUpdateFlags,
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,
881 rMtf,
882 rArgs.maOrigBounds,
883 rArgs.maBounds,
884 rArgs.maUnitBounds,
885 nUpdateFlags,
886 rArgs.mrAttr,
887 rArgs.mrSubsets,
888 rArgs.mnShapePriority,
889 bIsVisible );
890 else
891 return render( mpViewLayer->getCanvas(),
892 rMtf,
893 rArgs.maBounds,
894 rArgs.maUpdateBounds,
895 nUpdateFlags,
896 rArgs.mrAttr,
897 rArgs.mrSubsets,
898 bIsVisible );