fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / canvas / source / vcl / spritehelper.cxx
blob541115884f292b1cfe5bfa4417ff3cd986cf6df0
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 #include <canvas/debug.hxx>
22 #include <tools/diagnose_ex.h>
23 #include <canvas/verbosetrace.hxx>
25 #include <rtl/math.hxx>
27 #include <vcl/outdev.hxx>
28 #include <vcl/bitmap.hxx>
29 #include <vcl/alpha.hxx>
30 #include <vcl/bitmapex.hxx>
31 #include <vcl/canvastools.hxx>
33 #include <basegfx/matrix/b2dhommatrix.hxx>
34 #include <basegfx/point/b2dpoint.hxx>
35 #include <basegfx/tools/canvastools.hxx>
36 #include <basegfx/polygon/b2dpolygon.hxx>
37 #include <basegfx/polygon/b2dpolygontools.hxx>
38 #include <basegfx/polygon/b2dpolypolygontools.hxx>
39 #include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
40 #include <basegfx/polygon/b2dpolygontriangulator.hxx>
41 #include <basegfx/polygon/b2dpolygonclipper.hxx>
42 #include <basegfx/numeric/ftools.hxx>
44 #include <canvas/canvastools.hxx>
46 #include "spritehelper.hxx"
48 using namespace ::com::sun::star;
51 namespace vclcanvas
53 SpriteHelper::SpriteHelper() :
54 mpBackBuffer(),
55 mpBackBufferMask(),
56 maContent(),
57 mbShowSpriteBounds(false)
61 void SpriteHelper::init( const geometry::RealSize2D& rSpriteSize,
62 const ::canvas::SpriteSurface::Reference& rOwningSpriteCanvas,
63 const BackBufferSharedPtr& rBackBuffer,
64 const BackBufferSharedPtr& rBackBufferMask,
65 bool bShowSpriteBounds )
67 ENSURE_OR_THROW( rOwningSpriteCanvas.get() && rBackBuffer && rBackBufferMask,
68 "SpriteHelper::init(): Invalid sprite canvas or back buffer" );
70 mpBackBuffer = rBackBuffer;
71 mpBackBufferMask = rBackBufferMask;
72 mbShowSpriteBounds = bShowSpriteBounds;
74 init( rSpriteSize, rOwningSpriteCanvas );
77 void SpriteHelper::disposing()
79 mpBackBuffer.reset();
80 mpBackBufferMask.reset();
82 // forward to parent
83 CanvasCustomSpriteHelper::disposing();
86 void SpriteHelper::redraw( OutputDevice& rTargetSurface,
87 const ::basegfx::B2DPoint& rPos,
88 bool& io_bSurfacesDirty,
89 bool bBufferedUpdate ) const
91 (void)bBufferedUpdate; // not used on every platform
93 if( !mpBackBuffer ||
94 !mpBackBufferMask )
96 return; // we're disposed
99 // log output pos in device pixel
100 VERBOSE_TRACE( "SpriteHelper::redraw(): output pos is (%f, %f)",
101 rPos.getX(),
102 rPos.getY() );
104 const double fAlpha( getAlpha() );
106 if( isActive() &&
107 !::basegfx::fTools::equalZero( fAlpha ) )
109 const Point aEmptyPoint;
110 const ::basegfx::B2DVector& rOrigOutputSize( getSizePixel() );
112 // might get changed below (e.g. adapted for
113 // transformations). IMPORTANT: both position and size are
114 // rounded to integer values. From now on, only those
115 // rounded values are used, to keep clip and content in
116 // sync.
117 ::Size aOutputSize( ::vcl::unotools::sizeFromB2DSize( rOrigOutputSize ) );
118 ::Point aOutPos( ::vcl::unotools::pointFromB2DPoint( rPos ) );
121 // TODO(F3): Support for alpha-VDev
123 // Do we have to update our bitmaps (necessary if virdev
124 // was painted to, or transformation changed)?
125 const bool bNeedBitmapUpdate( io_bSurfacesDirty ||
126 hasTransformChanged() ||
127 maContent->IsEmpty() );
129 // updating content of sprite cache - surface is no
130 // longer dirty in relation to our cache
131 io_bSurfacesDirty = false;
132 transformUpdated();
134 if( bNeedBitmapUpdate )
136 Bitmap aBmp( mpBackBuffer->getOutDev().GetBitmap( aEmptyPoint,
137 aOutputSize ) );
139 if( isContentFullyOpaque() )
141 // optimized case: content canvas is fully
142 // opaque. Note: since we retrieved aBmp directly
143 // from an OutDev, it's already a 'display bitmap'
144 // on windows.
145 maContent = BitmapEx( aBmp );
147 else
149 // sprite content might contain alpha, create
150 // BmpEx, then.
151 Bitmap aMask( mpBackBufferMask->getOutDev().GetBitmap( aEmptyPoint,
152 aOutputSize ) );
154 // bitmasks are much faster than alphamasks on some platforms
155 // so convert to bitmask if useful
156 #ifndef MACOSX
157 if( aMask.GetBitCount() != 1 )
159 OSL_FAIL("CanvasCustomSprite::redraw(): Mask bitmap is not "
160 "monochrome (performance!)");
161 aMask.MakeMono(255);
163 #endif
165 // Note: since we retrieved aBmp and aMask
166 // directly from an OutDev, it's already a
167 // 'display bitmap' on windows.
168 maContent = BitmapEx( aBmp, aMask );
172 ::basegfx::B2DHomMatrix aTransform( getTransformation() );
174 // check whether matrix is "easy" to handle - pure
175 // translations or scales are handled by OutputDevice
176 // alone
177 const bool bIdentityTransform( aTransform.isIdentity() );
179 // make transformation absolute (put sprite to final
180 // output position). Need to happen here, as we also have
181 // to translate the clip polygon
182 aTransform.translate( aOutPos.X(),
183 aOutPos.Y() );
185 if( !bIdentityTransform )
187 if( !::basegfx::fTools::equalZero( aTransform.get(0,1) ) ||
188 !::basegfx::fTools::equalZero( aTransform.get(1,0) ) )
190 // "complex" transformation, employ affine
191 // transformator
193 // modify output position, to account for the fact
194 // that transformBitmap() always normalizes its output
195 // bitmap into the smallest enclosing box.
196 ::basegfx::B2DRectangle aDestRect;
197 ::canvas::tools::calcTransformedRectBounds( aDestRect,
198 ::basegfx::B2DRectangle(0,
200 rOrigOutputSize.getX(),
201 rOrigOutputSize.getY()),
202 aTransform );
204 aOutPos.X() = ::basegfx::fround( aDestRect.getMinX() );
205 aOutPos.Y() = ::basegfx::fround( aDestRect.getMinY() );
207 // TODO(P3): Use optimized bitmap transformation here.
209 // actually re-create the bitmap ONLY if necessary
210 if( bNeedBitmapUpdate )
211 maContent = tools::transformBitmap( *maContent,
212 aTransform,
213 uno::Sequence<double>(),
214 tools::MODULATE_NONE );
216 aOutputSize = maContent->GetSizePixel();
218 else
220 // relatively 'simplistic' transformation -
221 // retrieve scale and translational offset
222 aOutputSize.setWidth (
223 ::basegfx::fround( rOrigOutputSize.getX() * aTransform.get(0,0) ) );
224 aOutputSize.setHeight(
225 ::basegfx::fround( rOrigOutputSize.getY() * aTransform.get(1,1) ) );
227 aOutPos.X() = ::basegfx::fround( aTransform.get(0,2) );
228 aOutPos.Y() = ::basegfx::fround( aTransform.get(1,2) );
232 // transformBitmap() might return empty bitmaps, for tiny
233 // scales.
234 if( !!(*maContent) )
236 // when true, fast path for slide transition has
237 // already redrawn the sprite.
238 bool bSpriteRedrawn( false );
240 rTargetSurface.Push( PUSH_CLIPREGION );
242 // apply clip (if any)
243 if( getClip().is() )
245 ::basegfx::B2DPolyPolygon aClipPoly(
246 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(
247 getClip() ));
249 if( aClipPoly.count() )
251 // aTransform already contains the
252 // translational component, moving the clip to
253 // the final sprite output position.
254 aClipPoly.transform( aTransform );
256 #if ! defined WNT && ! defined MACOSX
257 // non-Windows only - bAtLeastOnePolygon is
258 // only used in non-WNT code below
260 // check whether maybe the clip consists
261 // solely out of rectangular polygons. If this
262 // is the case, enforce using the triangle
263 // clip region setup - non-optimized X11
264 // drivers tend to perform abyssmally on
265 // XPolygonRegion, which is used internally,
266 // when filling complex polypolygons.
267 bool bAtLeastOnePolygon( false );
268 const sal_Int32 nPolygons( aClipPoly.count() );
270 for( sal_Int32 i=0; i<nPolygons; ++i )
272 if( !::basegfx::tools::isRectangle(
273 aClipPoly.getB2DPolygon(i)) )
275 bAtLeastOnePolygon = true;
276 break;
279 #endif
281 if( mbShowSpriteBounds )
283 // Paint green sprite clip area
284 rTargetSurface.SetLineColor( Color( 0,255,0 ) );
285 rTargetSurface.SetFillColor();
287 rTargetSurface.DrawPolyPolygon(PolyPolygon(aClipPoly)); // #i76339#
290 #if ! defined WNT && ! defined MACOSX
291 // as a matter of fact, this fast path only
292 // performs well for X11 - under Windows, the
293 // clip via SetTriangleClipRegion is faster.
294 if( bAtLeastOnePolygon &&
295 bBufferedUpdate &&
296 ::rtl::math::approxEqual(fAlpha, 1.0) &&
297 !maContent->IsTransparent() )
299 // fast path for slide transitions
300 // (buffered, no alpha, no mask (because
301 // full slide is contained in the sprite))
303 // XOR bitmap onto backbuffer, clear area
304 // that should be _visible_ with black,
305 // XOR bitmap again on top of that -
306 // result: XOR cancels out where no black
307 // has been rendered, and yields the
308 // original bitmap, where black is
309 // underneath.
310 rTargetSurface.Push( PUSH_RASTEROP );
311 rTargetSurface.SetRasterOp( ROP_XOR );
312 rTargetSurface.DrawBitmap( aOutPos,
313 aOutputSize,
314 maContent->GetBitmap() );
316 rTargetSurface.SetLineColor();
317 rTargetSurface.SetFillColor( COL_BLACK );
318 rTargetSurface.SetRasterOp( ROP_0 );
319 rTargetSurface.DrawPolyPolygon(PolyPolygon(aClipPoly)); // #i76339#
321 rTargetSurface.SetRasterOp( ROP_XOR );
322 rTargetSurface.DrawBitmap( aOutPos,
323 aOutputSize,
324 maContent->GetBitmap() );
326 rTargetSurface.Pop();
328 bSpriteRedrawn = true;
330 else
331 #endif
333 Region aClipRegion( aClipPoly );
334 rTargetSurface.SetClipRegion( aClipRegion );
339 if( !bSpriteRedrawn )
341 if( ::rtl::math::approxEqual(fAlpha, 1.0) )
343 // no alpha modulation -> just copy to output
344 if( maContent->IsTransparent() )
345 rTargetSurface.DrawBitmapEx( aOutPos, aOutputSize, *maContent );
346 else
347 rTargetSurface.DrawBitmap( aOutPos, aOutputSize, maContent->GetBitmap() );
349 else
351 // TODO(P3): Switch to OutputDevice::DrawTransparent()
352 // here
354 // draw semi-transparent
355 sal_uInt8 nColor( static_cast<sal_uInt8>( ::basegfx::fround( 255.0*(1.0 - fAlpha) + .5) ) );
356 AlphaMask aAlpha( maContent->GetSizePixel(),
357 &nColor );
359 // mask out fully transparent areas
360 if( maContent->IsTransparent() )
361 aAlpha.Replace( maContent->GetMask(), 255 );
363 // alpha-blend to output
364 rTargetSurface.DrawBitmapEx( aOutPos, aOutputSize,
365 BitmapEx( maContent->GetBitmap(),
366 aAlpha ) );
370 rTargetSurface.Pop();
372 if( mbShowSpriteBounds )
374 ::PolyPolygon aMarkerPoly(
375 ::canvas::tools::getBoundMarksPolyPolygon(
376 ::basegfx::B2DRectangle(aOutPos.X(),
377 aOutPos.Y(),
378 aOutPos.X() + aOutputSize.Width()-1,
379 aOutPos.Y() + aOutputSize.Height()-1) ) );
381 // Paint little red sprite area markers
382 rTargetSurface.SetLineColor( COL_RED );
383 rTargetSurface.SetFillColor();
385 for( int i=0; i<aMarkerPoly.Count(); ++i )
387 rTargetSurface.DrawPolyLine( aMarkerPoly.GetObject((sal_uInt16)i) );
390 // paint sprite prio
391 Font aVCLFont;
392 aVCLFont.SetHeight( std::min(long(20),aOutputSize.Height()) );
393 aVCLFont.SetColor( COL_RED );
395 rTargetSurface.SetTextAlign(ALIGN_TOP);
396 rTargetSurface.SetTextColor( COL_RED );
397 rTargetSurface.SetFont( aVCLFont );
399 OUString text( ::rtl::math::doubleToUString( getPriority(),
400 rtl_math_StringFormat_F,
401 2,'.',NULL,' ') );
403 rTargetSurface.DrawText( aOutPos+Point(2,2), text );
404 VERBOSE_TRACE( "SpriteHelper::redraw(): sprite %X has prio %f\n",
405 this, getPriority() );
411 ::basegfx::B2DPolyPolygon SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference< rendering::XPolyPolygon2D >& xPoly ) const
413 return ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPoly );
418 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */