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 .
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
;
53 SpriteHelper::SpriteHelper() :
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()
80 mpBackBufferMask
.reset();
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
96 return; // we're disposed
99 // log output pos in device pixel
100 VERBOSE_TRACE( "SpriteHelper::redraw(): output pos is (%f, %f)",
104 const double fAlpha( getAlpha() );
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
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;
134 if( bNeedBitmapUpdate
)
136 Bitmap
aBmp( mpBackBuffer
->getOutDev().GetBitmap( aEmptyPoint
,
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'
145 maContent
= BitmapEx( aBmp
);
149 // sprite content might contain alpha, create
151 Bitmap
aMask( mpBackBufferMask
->getOutDev().GetBitmap( aEmptyPoint
,
154 // bitmasks are much faster than alphamasks on some platforms
155 // so convert to bitmask if useful
157 if( aMask
.GetBitCount() != 1 )
159 OSL_FAIL("CanvasCustomSprite::redraw(): Mask bitmap is not "
160 "monochrome (performance!)");
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
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(),
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
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()),
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
,
213 uno::Sequence
<double>(),
214 tools::MODULATE_NONE
);
216 aOutputSize
= maContent
->GetSizePixel();
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
236 // when true, fast path for slide transition has
237 // already redrawn the sprite.
238 bool bSpriteRedrawn( false );
240 rTargetSurface
.Push( PushFlags::CLIPREGION
);
242 // apply clip (if any)
245 ::basegfx::B2DPolyPolygon
aClipPoly(
246 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(
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( mbShowSpriteBounds
)
258 // Paint green sprite clip area
259 rTargetSurface
.SetLineColor( Color( 0,255,0 ) );
260 rTargetSurface
.SetFillColor();
262 rTargetSurface
.DrawPolyPolygon(::tools::PolyPolygon(aClipPoly
)); // #i76339#
265 vcl::Region
aClipRegion( aClipPoly
);
266 rTargetSurface
.SetClipRegion( aClipRegion
);
270 if( !bSpriteRedrawn
)
272 if( ::rtl::math::approxEqual(fAlpha
, 1.0) )
274 // no alpha modulation -> just copy to output
275 if( maContent
->IsTransparent() )
276 rTargetSurface
.DrawBitmapEx( aOutPos
, aOutputSize
, *maContent
);
278 rTargetSurface
.DrawBitmap( aOutPos
, aOutputSize
, maContent
->GetBitmap() );
282 // TODO(P3): Switch to OutputDevice::DrawTransparent()
285 // draw semi-transparent
286 sal_uInt8
nColor( static_cast<sal_uInt8
>( ::basegfx::fround( 255.0*(1.0 - fAlpha
) + .5) ) );
287 AlphaMask
aAlpha( maContent
->GetSizePixel(),
290 // mask out fully transparent areas
291 if( maContent
->IsTransparent() )
292 aAlpha
.Replace( maContent
->GetMask(), 255 );
294 // alpha-blend to output
295 rTargetSurface
.DrawBitmapEx( aOutPos
, aOutputSize
,
296 BitmapEx( maContent
->GetBitmap(),
301 rTargetSurface
.Pop();
303 if( mbShowSpriteBounds
)
305 ::tools::PolyPolygon
aMarkerPoly(
306 ::canvas::tools::getBoundMarksPolyPolygon(
307 ::basegfx::B2DRectangle(aOutPos
.X(),
309 aOutPos
.X() + aOutputSize
.Width()-1,
310 aOutPos
.Y() + aOutputSize
.Height()-1) ) );
312 // Paint little red sprite area markers
313 rTargetSurface
.SetLineColor( COL_RED
);
314 rTargetSurface
.SetFillColor();
316 for( int i
=0; i
<aMarkerPoly
.Count(); ++i
)
318 rTargetSurface
.DrawPolyLine( aMarkerPoly
.GetObject((sal_uInt16
)i
) );
323 aVCLFont
.SetHeight( std::min(long(20),aOutputSize
.Height()) );
324 aVCLFont
.SetColor( COL_RED
);
326 rTargetSurface
.SetTextAlign(ALIGN_TOP
);
327 rTargetSurface
.SetTextColor( COL_RED
);
328 rTargetSurface
.SetFont( aVCLFont
);
330 OUString
text( ::rtl::math::doubleToUString( getPriority(),
331 rtl_math_StringFormat_F
,
334 rTargetSurface
.DrawText( aOutPos
+Point(2,2), text
);
337 "sprite " << this << " has prio " << getPriority());
343 ::basegfx::B2DPolyPolygon
SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference
< rendering::XPolyPolygon2D
>& xPoly
) const
345 return ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPoly
);
350 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */