Update ooo320-m1
[ooovba.git] / canvas / source / vcl / spritehelper.cxx
blobbdaca2770f034bda184bbce998a6fea6724e2b04
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: spritehelper.cxx,v $
10 * $Revision: 1.13 $
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_canvas.hxx"
34 #include <canvas/debug.hxx>
35 #include <tools/diagnose_ex.h>
36 #include <canvas/verbosetrace.hxx>
38 #include <rtl/math.hxx>
40 #include <vcl/outdev.hxx>
41 #include <vcl/bitmap.hxx>
42 #include <vcl/alpha.hxx>
43 #include <vcl/bitmapex.hxx>
44 #include <vcl/canvastools.hxx>
46 #include <basegfx/matrix/b2dhommatrix.hxx>
47 #include <basegfx/point/b2dpoint.hxx>
48 #include <basegfx/tools/canvastools.hxx>
49 #include <basegfx/polygon/b2dpolygon.hxx>
50 #include <basegfx/polygon/b2dpolygontools.hxx>
51 #include <basegfx/polygon/b2dpolypolygontools.hxx>
52 #include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
53 #include <basegfx/polygon/b2dpolygontriangulator.hxx>
54 #include <basegfx/polygon/b2dpolygonclipper.hxx>
55 #include <basegfx/numeric/ftools.hxx>
57 #include <canvas/canvastools.hxx>
59 #include "spritehelper.hxx"
61 using namespace ::com::sun::star;
64 namespace vclcanvas
66 SpriteHelper::SpriteHelper() :
67 mpBackBuffer(),
68 mpBackBufferMask(),
69 maContent(),
70 mbShowSpriteBounds(false)
74 void SpriteHelper::init( const geometry::RealSize2D& rSpriteSize,
75 const ::canvas::SpriteSurface::Reference& rOwningSpriteCanvas,
76 const BackBufferSharedPtr& rBackBuffer,
77 const BackBufferSharedPtr& rBackBufferMask,
78 bool bShowSpriteBounds )
80 ENSURE_OR_THROW( rOwningSpriteCanvas.get() && rBackBuffer && rBackBufferMask,
81 "SpriteHelper::init(): Invalid sprite canvas or back buffer" );
83 mpBackBuffer = rBackBuffer;
84 mpBackBufferMask = rBackBufferMask;
85 mbShowSpriteBounds = bShowSpriteBounds;
87 init( rSpriteSize, rOwningSpriteCanvas );
90 void SpriteHelper::disposing()
92 mpBackBuffer.reset();
93 mpBackBufferMask.reset();
95 // forward to parent
96 CanvasCustomSpriteHelper::disposing();
99 void SpriteHelper::redraw( OutputDevice& rTargetSurface,
100 const ::basegfx::B2DPoint& rPos,
101 bool& io_bSurfacesDirty,
102 bool bBufferedUpdate ) const
104 (void)bBufferedUpdate; // not used on every platform
106 if( !mpBackBuffer ||
107 !mpBackBufferMask )
109 return; // we're disposed
112 // log output pos in device pixel
113 VERBOSE_TRACE( "SpriteHelper::redraw(): output pos is (%f, %f)",
114 rPos.getX(),
115 rPos.getY() );
117 const double fAlpha( getAlpha() );
119 if( isActive() &&
120 !::basegfx::fTools::equalZero( fAlpha ) )
122 const Point aEmptyPoint;
123 const ::basegfx::B2DVector& rOrigOutputSize( getSizePixel() );
125 // might get changed below (e.g. adapted for
126 // transformations). IMPORTANT: both position and size are
127 // rounded to integer values. From now on, only those
128 // rounded values are used, to keep clip and content in
129 // sync.
130 ::Size aOutputSize( ::vcl::unotools::sizeFromB2DSize( rOrigOutputSize ) );
131 ::Point aOutPos( ::vcl::unotools::pointFromB2DPoint( rPos ) );
134 // TODO(F3): Support for alpha-VDev
136 // Do we have to update our bitmaps (necessary if virdev
137 // was painted to, or transformation changed)?
138 const bool bNeedBitmapUpdate( io_bSurfacesDirty ||
139 hasTransformChanged() ||
140 maContent->IsEmpty() );
142 // updating content of sprite cache - surface is no
143 // longer dirty in relation to our cache
144 io_bSurfacesDirty = false;
145 transformUpdated();
147 if( bNeedBitmapUpdate )
149 Bitmap aBmp( mpBackBuffer->getOutDev().GetBitmap( aEmptyPoint,
150 aOutputSize ) );
152 if( isContentFullyOpaque() )
154 // optimized case: content canvas is fully
155 // opaque. Note: since we retrieved aBmp directly
156 // from an OutDev, it's already a 'display bitmap'
157 // on windows.
158 maContent = BitmapEx( aBmp );
160 else
162 // sprite content might contain alpha, create
163 // BmpEx, then.
164 Bitmap aMask( mpBackBufferMask->getOutDev().GetBitmap( aEmptyPoint,
165 aOutputSize ) );
167 // bitmasks are much faster than alphamasks on some platforms
168 // so convert to bitmask if useful
169 #ifndef QUARTZ
170 if( aMask.GetBitCount() != 1 )
172 OSL_ENSURE(false,
173 "CanvasCustomSprite::redraw(): Mask bitmap is not "
174 "monochrome (performance!)");
175 aMask.MakeMono(255);
177 #endif
179 // Note: since we retrieved aBmp and aMask
180 // directly from an OutDev, it's already a
181 // 'display bitmap' on windows.
182 maContent = BitmapEx( aBmp, aMask );
186 ::basegfx::B2DHomMatrix aTransform( getTransformation() );
188 // check whether matrix is "easy" to handle - pure
189 // translations or scales are handled by OutputDevice
190 // alone
191 const bool bIdentityTransform( aTransform.isIdentity() );
193 // make transformation absolute (put sprite to final
194 // output position). Need to happen here, as we also have
195 // to translate the clip polygon
196 aTransform.translate( aOutPos.X(),
197 aOutPos.Y() );
199 if( !bIdentityTransform )
201 if( !::basegfx::fTools::equalZero( aTransform.get(0,1) ) ||
202 !::basegfx::fTools::equalZero( aTransform.get(1,0) ) )
204 // "complex" transformation, employ affine
205 // transformator
207 // modify output position, to account for the fact
208 // that transformBitmap() always normalizes its output
209 // bitmap into the smallest enclosing box.
210 ::basegfx::B2DRectangle aDestRect;
211 ::canvas::tools::calcTransformedRectBounds( aDestRect,
212 ::basegfx::B2DRectangle(0,
214 rOrigOutputSize.getX(),
215 rOrigOutputSize.getY()),
216 aTransform );
218 aOutPos.X() = ::basegfx::fround( aDestRect.getMinX() );
219 aOutPos.Y() = ::basegfx::fround( aDestRect.getMinY() );
221 // TODO(P3): Use optimized bitmap transformation here.
223 // actually re-create the bitmap ONLY if necessary
224 if( bNeedBitmapUpdate )
225 maContent = tools::transformBitmap( *maContent,
226 aTransform,
227 uno::Sequence<double>(),
228 tools::MODULATE_NONE );
230 aOutputSize = maContent->GetSizePixel();
232 else
234 // relatively 'simplistic' transformation -
235 // retrieve scale and translational offset
236 aOutputSize.setWidth (
237 ::basegfx::fround( rOrigOutputSize.getX() * aTransform.get(0,0) ) );
238 aOutputSize.setHeight(
239 ::basegfx::fround( rOrigOutputSize.getY() * aTransform.get(1,1) ) );
241 aOutPos.X() = ::basegfx::fround( aTransform.get(0,2) );
242 aOutPos.Y() = ::basegfx::fround( aTransform.get(1,2) );
246 // transformBitmap() might return empty bitmaps, for tiny
247 // scales.
248 if( !!(*maContent) )
250 // when true, fast path for slide transition has
251 // already redrawn the sprite.
252 bool bSpriteRedrawn( false );
254 rTargetSurface.Push( PUSH_CLIPREGION );
256 // apply clip (if any)
257 if( getClip().is() )
259 ::basegfx::B2DPolyPolygon aClipPoly(
260 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(
261 getClip() ));
263 if( aClipPoly.count() )
265 // aTransform already contains the
266 // translational component, moving the clip to
267 // the final sprite output position.
268 aClipPoly.transform( aTransform );
270 #if ! defined WNT && ! defined QUARTZ
271 // non-Windows only - bAtLeastOnePolygon is
272 // only used in non-WNT code below
274 // check whether maybe the clip consists
275 // solely out of rectangular polygons. If this
276 // is the case, enforce using the triangle
277 // clip region setup - non-optimized X11
278 // drivers tend to perform abyssmally on
279 // XPolygonRegion, which is used internally,
280 // when filling complex polypolygons.
281 bool bAtLeastOnePolygon( false );
282 const sal_Int32 nPolygons( aClipPoly.count() );
284 for( sal_Int32 i=0; i<nPolygons; ++i )
286 if( !::basegfx::tools::isRectangle(
287 aClipPoly.getB2DPolygon(i)) )
289 bAtLeastOnePolygon = true;
290 break;
293 #endif
295 if( mbShowSpriteBounds )
297 // Paint green sprite clip area
298 rTargetSurface.SetLineColor( Color( 0,255,0 ) );
299 rTargetSurface.SetFillColor();
301 rTargetSurface.DrawPolyPolygon(PolyPolygon(aClipPoly)); // #i76339#
304 #if ! defined WNT && ! defined QUARTZ
305 // as a matter of fact, this fast path only
306 // performs well for X11 - under Windows, the
307 // clip via SetTriangleClipRegion is faster.
308 if( bAtLeastOnePolygon &&
309 bBufferedUpdate &&
310 ::rtl::math::approxEqual(fAlpha, 1.0) &&
311 !maContent->IsTransparent() )
313 // fast path for slide transitions
314 // (buffered, no alpha, no mask (because
315 // full slide is contained in the sprite))
317 // XOR bitmap onto backbuffer, clear area
318 // that should be _visible_ with black,
319 // XOR bitmap again on top of that -
320 // result: XOR cancels out where no black
321 // has been rendered, and yields the
322 // original bitmap, where black is
323 // underneath.
324 rTargetSurface.Push( PUSH_RASTEROP );
325 rTargetSurface.SetRasterOp( ROP_XOR );
326 rTargetSurface.DrawBitmap( aOutPos,
327 aOutputSize,
328 maContent->GetBitmap() );
330 rTargetSurface.SetLineColor();
331 rTargetSurface.SetFillColor( COL_BLACK );
332 rTargetSurface.SetRasterOp( ROP_0 );
333 rTargetSurface.DrawPolyPolygon(PolyPolygon(aClipPoly)); // #i76339#
335 rTargetSurface.SetRasterOp( ROP_XOR );
336 rTargetSurface.DrawBitmap( aOutPos,
337 aOutputSize,
338 maContent->GetBitmap() );
340 rTargetSurface.Pop();
342 bSpriteRedrawn = true;
344 else
345 #endif
347 // redraw is direcly on the front buffer,
348 // or using alpha blending - cannot use
349 // XOR, thus, employing the still somewhat
350 // speedier triangle clip method
351 ::basegfx::B2DPolygon aTriangulatedClip(::basegfx::triangulator::triangulate(aClipPoly));
353 // restrict the clipping area to the visible portion of the output device.
354 Size aSize(rTargetSurface.GetOutputSizePixel());
355 ::basegfx::B2DRange aOutputRect(::basegfx::B2DPoint(0,0),::basegfx::B2DPoint(aSize.Width(),aSize.Height()));
356 ::basegfx::B2DPolygon aClippedClip(::basegfx::tools::clipTriangleListOnRange(aTriangulatedClip,aOutputRect));
358 // #i76339#
359 const Polygon aPoly(aClippedClip);
360 const PolyPolygon aPolyPoly(aPoly);
361 rTargetSurface.SetTriangleClipRegion(aPolyPoly);
366 if( !bSpriteRedrawn )
368 if( ::rtl::math::approxEqual(fAlpha, 1.0) )
370 // no alpha modulation -> just copy to output
371 if( maContent->IsTransparent() )
372 rTargetSurface.DrawBitmapEx( aOutPos, aOutputSize, *maContent );
373 else
374 rTargetSurface.DrawBitmap( aOutPos, aOutputSize, maContent->GetBitmap() );
376 else
378 // TODO(P3): Switch to OutputDevice::DrawTransparent()
379 // here
381 // draw semi-transparent
382 BYTE nColor( static_cast<UINT8>( ::basegfx::fround( 255.0*(1.0 - fAlpha) + .5) ) );
383 AlphaMask aAlpha( maContent->GetSizePixel(),
384 &nColor );
386 // mask out fully transparent areas
387 if( maContent->IsTransparent() )
388 aAlpha.Replace( maContent->GetMask(), 255 );
390 // alpha-blend to output
391 rTargetSurface.DrawBitmapEx( aOutPos, aOutputSize,
392 BitmapEx( maContent->GetBitmap(),
393 aAlpha ) );
397 rTargetSurface.Pop();
399 if( mbShowSpriteBounds )
401 ::PolyPolygon aMarkerPoly(
402 ::canvas::tools::getBoundMarksPolyPolygon(
403 ::basegfx::B2DRectangle(aOutPos.X(),
404 aOutPos.Y(),
405 aOutPos.X() + aOutputSize.Width()-1,
406 aOutPos.Y() + aOutputSize.Height()-1) ) );
408 // Paint little red sprite area markers
409 rTargetSurface.SetLineColor( COL_RED );
410 rTargetSurface.SetFillColor();
412 for( int i=0; i<aMarkerPoly.Count(); ++i )
414 rTargetSurface.DrawPolyLine( aMarkerPoly.GetObject((USHORT)i) );
417 // paint sprite prio
418 Font aVCLFont;
419 aVCLFont.SetHeight( std::min(long(20),aOutputSize.Height()) );
420 aVCLFont.SetColor( COL_RED );
422 rTargetSurface.SetTextAlign(ALIGN_TOP);
423 rTargetSurface.SetTextColor( COL_RED );
424 rTargetSurface.SetFont( aVCLFont );
426 ::rtl::OUString text( ::rtl::math::doubleToUString( getPriority(),
427 rtl_math_StringFormat_F,
428 2,'.',NULL,' ') );
430 rTargetSurface.DrawText( aOutPos+Point(2,2), text );
432 #if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0
433 OSL_TRACE( "SpriteHelper::redraw(): sprite %X has prio %f\n",
434 this, getPriority() );
435 #endif
441 ::basegfx::B2DPolyPolygon SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference< rendering::XPolyPolygon2D >& xPoly ) const
443 return ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPoly );