Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <canvas/debug.hxx>
30 : : #include <canvas/verbosetrace.hxx>
31 : : #include <canvas/canvastools.hxx>
32 : : #include <tools/diagnose_ex.h>
33 : :
34 : : #include <vcl/canvastools.hxx>
35 : :
36 : : #include <comphelper/scopeguard.hxx>
37 : :
38 : : #include <basegfx/range/b2drectangle.hxx>
39 : : #include <basegfx/tools/canvastools.hxx>
40 : :
41 : : #include <boost/cast.hpp>
42 : :
43 : : #include "cairo_spritecanvashelper.hxx"
44 : : #include "cairo_canvascustomsprite.hxx"
45 : :
46 : : using namespace ::cairo;
47 : : using namespace ::com::sun::star;
48 : :
49 : : namespace cairocanvas
50 : : {
51 : : namespace
52 : : {
53 : : /** Sprite redraw at original position
54 : :
55 : : Used to repaint the whole canvas (background and all
56 : : sprites)
57 : : */
58 : 0 : void spriteRedraw( const CairoSharedPtr& pCairo,
59 : : const ::canvas::Sprite::Reference& rSprite )
60 : : {
61 : : // downcast to derived cairocanvas::Sprite interface, which
62 : : // provides the actual redraw methods.
63 : 0 : ::boost::polymorphic_downcast< Sprite* >(rSprite.get())->redraw( pCairo, true);
64 : 0 : }
65 : :
66 : 0 : void repaintBackground( const CairoSharedPtr& pCairo,
67 : : const SurfaceSharedPtr& pBackgroundSurface,
68 : : const ::basegfx::B2DRange& rArea )
69 : : {
70 : 0 : cairo_save( pCairo.get() );
71 : : cairo_rectangle( pCairo.get(), ceil( rArea.getMinX() ), ceil( rArea.getMinY() ),
72 : 0 : floor( rArea.getWidth() ), floor( rArea.getHeight() ) );
73 : 0 : cairo_clip( pCairo.get() );
74 : 0 : cairo_set_source_surface( pCairo.get(), pBackgroundSurface->getCairoSurface().get(), 0, 0 );
75 : 0 : cairo_set_operator( pCairo.get(), CAIRO_OPERATOR_SOURCE );
76 : 0 : cairo_paint( pCairo.get() );
77 : 0 : cairo_restore( pCairo.get() );
78 : 0 : }
79 : :
80 : 0 : void opaqueUpdateSpriteArea( const ::canvas::Sprite::Reference& rSprite,
81 : : const CairoSharedPtr& pCairo,
82 : : const ::basegfx::B2IRange& rArea )
83 : : {
84 : : // clip output to actual update region (otherwise a)
85 : : // wouldn't save much render time, and b) will clutter
86 : : // scrolled sprite content outside this area)
87 : 0 : cairo_save( pCairo.get() );
88 : 0 : cairo_rectangle( pCairo.get(), rArea.getMinX(), rArea.getMinY(),
89 : 0 : sal::static_int_cast<sal_Int32>(rArea.getWidth()),
90 : 0 : sal::static_int_cast<sal_Int32>(rArea.getHeight()) );
91 : 0 : cairo_clip( pCairo.get() );
92 : :
93 : : // repaint affected sprite directly to output device (at
94 : : // the actual screen output position)
95 : : // rendering directly to device buffer
96 : 0 : ::boost::polymorphic_downcast< Sprite* >( rSprite.get() )->redraw( pCairo, false );
97 : :
98 : 0 : cairo_restore( pCairo.get() );
99 : 0 : }
100 : :
101 : : /** Repaint sprite at original position
102 : :
103 : : Used for opaque updates, which render directly to the
104 : : device buffer.
105 : : */
106 : 0 : void spriteRedrawStub( const CairoSharedPtr& pCairo,
107 : : const ::canvas::Sprite::Reference& rSprite )
108 : : {
109 : 0 : if( rSprite.is() )
110 : : {
111 : 0 : ::boost::polymorphic_downcast< Sprite* >( rSprite.get() )->redraw( pCairo, false );
112 : : }
113 : 0 : }
114 : :
115 : : /** Repaint sprite at given position
116 : :
117 : : Used for generic update, which renders into device buffer.
118 : : */
119 : 0 : void spriteRedrawStub2( const CairoSharedPtr& pCairo,
120 : : const ::canvas::Sprite::Reference& rSprite )
121 : : {
122 : 0 : if( rSprite.is() )
123 : : {
124 : 0 : ::boost::polymorphic_downcast< Sprite* >( rSprite.get() )->redraw( pCairo, true );
125 : : }
126 : 0 : }
127 : :
128 : : /** Repaint sprite at original position
129 : :
130 : : Used for opaque updates from scrollUpdate(), which render
131 : : directly to the front buffer.
132 : : */
133 : 0 : void spriteRedrawStub3( const CairoSharedPtr& pCairo,
134 : : const ::canvas::SpriteRedrawManager::AreaComponent& rComponent )
135 : : {
136 : 0 : const ::canvas::Sprite::Reference& rSprite( rComponent.second.getSprite() );
137 : :
138 : 0 : if( rSprite.is() )
139 : 0 : ::boost::polymorphic_downcast< Sprite* >( rSprite.get() )->redraw( pCairo, false );
140 : 0 : }
141 : : }
142 : :
143 : 0 : SpriteCanvasHelper::SpriteCanvasHelper() :
144 : : mpRedrawManager( NULL ),
145 : : mpOwningSpriteCanvas( NULL ),
146 : : mpCompositingSurface(),
147 : : maCompositingSurfaceSize(),
148 : 0 : mbCompositingSurfaceDirty(true)
149 : : {
150 : 0 : }
151 : :
152 : 0 : void SpriteCanvasHelper::init( ::canvas::SpriteRedrawManager& rManager,
153 : : SpriteCanvas& rDevice,
154 : : const ::basegfx::B2ISize& rSize )
155 : : {
156 : 0 : mpRedrawManager = &rManager;
157 : 0 : mpOwningSpriteCanvas = &rDevice;
158 : :
159 : 0 : CanvasHelper::init( rSize, rDevice, &rDevice );
160 : 0 : }
161 : :
162 : 0 : void SpriteCanvasHelper::disposing()
163 : : {
164 : 0 : mpCompositingSurface.reset();
165 : 0 : mpOwningSpriteCanvas = NULL;
166 : 0 : mpRedrawManager = NULL;
167 : :
168 : : // forward to base
169 : 0 : CanvasHelper::disposing();
170 : 0 : }
171 : :
172 : 0 : uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromAnimation(
173 : : const uno::Reference< rendering::XAnimation >& )
174 : : {
175 : 0 : return uno::Reference< rendering::XAnimatedSprite >();
176 : : }
177 : :
178 : 0 : uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromBitmaps(
179 : : const uno::Sequence< uno::Reference< rendering::XBitmap > >& /*animationBitmaps*/,
180 : : sal_Int8 /*interpolationMode*/ )
181 : : {
182 : 0 : return uno::Reference< rendering::XAnimatedSprite >();
183 : : }
184 : :
185 : 0 : uno::Reference< rendering::XCustomSprite > SpriteCanvasHelper::createCustomSprite( const geometry::RealSize2D& spriteSize )
186 : : {
187 : 0 : if( !mpRedrawManager )
188 : 0 : return uno::Reference< rendering::XCustomSprite >(); // we're disposed
189 : :
190 : : return uno::Reference< rendering::XCustomSprite >(
191 : : new CanvasCustomSprite( spriteSize,
192 : 0 : mpOwningSpriteCanvas ) );
193 : : }
194 : :
195 : 0 : uno::Reference< rendering::XSprite > SpriteCanvasHelper::createClonedSprite(
196 : : const uno::Reference< rendering::XSprite >& )
197 : : {
198 : 0 : return uno::Reference< rendering::XSprite >();
199 : : }
200 : :
201 : 0 : sal_Bool SpriteCanvasHelper::updateScreen( const ::basegfx::B2IRange& /*rCurrArea*/,
202 : : sal_Bool bUpdateAll,
203 : : bool& io_bSurfaceDirty )
204 : : {
205 : 0 : if( !mpRedrawManager ||
206 : 0 : !mpOwningSpriteCanvas ||
207 : 0 : !mpOwningSpriteCanvas->getWindowSurface() ||
208 : 0 : !mpOwningSpriteCanvas->getBufferSurface() )
209 : : {
210 : 0 : return sal_False; // disposed, or otherwise dysfunctional
211 : : }
212 : :
213 : : SAL_INFO("canvas.cairo", "SpriteCanvasHelper::updateScreen called");
214 : :
215 : 0 : const ::basegfx::B2ISize& rSize = mpOwningSpriteCanvas->getSizePixel();
216 : :
217 : : // force compositing surface to be available before using it
218 : : // inside forEachSpriteArea
219 : 0 : SurfaceSharedPtr pCompositingSurface = getCompositingSurface(rSize);
220 : 0 : SurfaceSharedPtr pWindowSurface = mpOwningSpriteCanvas->getWindowSurface();
221 : 0 : CairoSharedPtr pCompositingCairo = pCompositingSurface->getCairo();
222 : 0 : CairoSharedPtr pWindowCairo = pWindowSurface->getCairo();
223 : :
224 : : // TODO(P1): Might be worthwile to track areas of background
225 : : // changes, too.
226 : 0 : if( !bUpdateAll && !io_bSurfaceDirty && !mbCompositingSurfaceDirty )
227 : : {
228 : : // background has not changed, so we're free to optimize
229 : : // repaint to areas where a sprite has changed
230 : :
231 : : // process each independent area of overlapping sprites
232 : : // separately.
233 : 0 : mpRedrawManager->forEachSpriteArea( *this );
234 : : }
235 : : else
236 : : {
237 : : SAL_INFO("canvas.cairo", "SpriteCanvasHelper::updateScreen update ALL");
238 : :
239 : : // background has changed, so we currently have no choice
240 : : // but repaint everything (or caller requested that)
241 : :
242 : 0 : cairo_rectangle( pCompositingCairo.get(), 0, 0, rSize.getX(), rSize.getY() );
243 : 0 : cairo_clip( pCompositingCairo.get() );
244 : 0 : cairo_save( pCompositingCairo.get() );
245 : : cairo_set_source_surface( pCompositingCairo.get(),
246 : 0 : mpOwningSpriteCanvas->getBufferSurface()->getCairoSurface().get(),
247 : 0 : 0, 0 );
248 : 0 : cairo_set_operator( pCompositingCairo.get(), CAIRO_OPERATOR_SOURCE );
249 : 0 : cairo_paint( pCompositingCairo.get() );
250 : 0 : cairo_restore( pCompositingCairo.get() );
251 : :
252 : : // repaint all active sprites on top of background into
253 : : // VDev.
254 : : mpRedrawManager->forEachSprite(
255 : : ::boost::bind(
256 : : &spriteRedraw,
257 : : boost::cref(pCompositingCairo),
258 : 0 : _1 ) );
259 : :
260 : : // flush to screen
261 : 0 : cairo_rectangle( pWindowCairo.get(), 0, 0, rSize.getX(), rSize.getY() );
262 : 0 : cairo_clip( pWindowCairo.get() );
263 : : cairo_set_source_surface( pWindowCairo.get(),
264 : 0 : pCompositingSurface->getCairoSurface().get(),
265 : 0 : 0, 0 );
266 : 0 : cairo_set_operator( pWindowCairo.get(), CAIRO_OPERATOR_SOURCE );
267 : 0 : cairo_paint( pWindowCairo.get() );
268 : : }
269 : :
270 : : // change record vector must be cleared, for the next turn of
271 : : // rendering and sprite changing
272 : 0 : mpRedrawManager->clearChangeRecords();
273 : :
274 : 0 : mbCompositingSurfaceDirty = false;
275 : 0 : io_bSurfaceDirty = false;
276 : :
277 : : // commit to screen
278 : 0 : mpOwningSpriteCanvas->flush();
279 : :
280 : 0 : return sal_True;
281 : : }
282 : :
283 : 0 : void SpriteCanvasHelper::backgroundPaint( const ::basegfx::B2DRange& rUpdateRect )
284 : : {
285 : 0 : if( mpOwningSpriteCanvas && mpCompositingSurface )
286 : 0 : repaintBackground( mpCompositingSurface->getCairo(),
287 : : mpOwningSpriteCanvas->getBufferSurface(),
288 : 0 : rUpdateRect );
289 : 0 : }
290 : :
291 : 0 : void SpriteCanvasHelper::scrollUpdate( const ::basegfx::B2DRange& rMoveStart,
292 : : const ::basegfx::B2DRange& rMoveEnd,
293 : : const ::canvas::SpriteRedrawManager::UpdateArea& rUpdateArea )
294 : : {
295 : 0 : ENSURE_OR_THROW( mpOwningSpriteCanvas &&
296 : : mpOwningSpriteCanvas->getBufferSurface(),
297 : : "SpriteCanvasHelper::scrollUpdate(): NULL device pointer " );
298 : :
299 : : SAL_INFO("canvas.cairo", "SpriteCanvasHelper::scrollUpdate called");
300 : :
301 : 0 : const ::basegfx::B2ISize& rSize = mpOwningSpriteCanvas->getSizePixel();
302 : : const ::basegfx::B2IRange aOutputBounds( 0,0,
303 : : rSize.getX(),
304 : 0 : rSize.getY() );
305 : :
306 : 0 : SurfaceSharedPtr pCompositingSurface = getCompositingSurface(rSize);
307 : 0 : SurfaceSharedPtr pWindowSurface = mpOwningSpriteCanvas->getWindowSurface();
308 : 0 : CairoSharedPtr pCompositingCairo = pCompositingSurface->getCairo();
309 : 0 : CairoSharedPtr pWindowCairo = pWindowSurface->getCairo();
310 : :
311 : : // round rectangles to integer pixel. Note: have to be
312 : : // extremely careful here, to avoid off-by-one errors for
313 : : // the destination area: otherwise, the next scroll update
314 : : // would copy pixel that are not supposed to be part of
315 : : // the sprite.
316 : : ::basegfx::B2IRange aSourceRect(
317 : 0 : ::canvas::tools::spritePixelAreaFromB2DRange( rMoveStart ) );
318 : : const ::basegfx::B2IRange& rDestRect(
319 : 0 : ::canvas::tools::spritePixelAreaFromB2DRange( rMoveEnd ) );
320 : 0 : ::basegfx::B2IPoint aDestPos( rDestRect.getMinimum() );
321 : :
322 : 0 : ::std::vector< ::basegfx::B2IRange > aUnscrollableAreas;
323 : :
324 : : // TODO(E3): This is plain buggy (but copies the behaviour of
325 : : // the old Impress slideshow) - the scrolled area might
326 : : // actually lie _below_ another window!
327 : :
328 : : // clip to output bounds (cannot properly scroll stuff
329 : : // _outside_ our screen area)
330 : 0 : if( !::canvas::tools::clipScrollArea( aSourceRect,
331 : : aDestPos,
332 : : aUnscrollableAreas,
333 : 0 : aOutputBounds ) )
334 : : {
335 : : // fully clipped scroll area: cannot simply scroll
336 : : // then. Perform normal opaque update (can use that, since
337 : : // one of the preconditions for scrollable update is
338 : : // opaque sprite content)
339 : :
340 : : // repaint all affected sprites directly to output device
341 : : ::std::for_each( rUpdateArea.maComponentList.begin(),
342 : : rUpdateArea.maComponentList.end(),
343 : : ::boost::bind(
344 : : &spriteRedrawStub3,
345 : : boost::cref(pCompositingCairo),
346 : 0 : _1 ) );
347 : : }
348 : : else
349 : : {
350 : 0 : const ::basegfx::B2IVector aSourceUpperLeftPos( aSourceRect.getMinimum() );
351 : :
352 : : // clip dest area (which must be inside rDestBounds)
353 : 0 : ::basegfx::B2IRange aDestRect( rDestRect );
354 : 0 : aDestRect.intersect( aOutputBounds );
355 : :
356 : 0 : ::basegfx::B2ISize aScrollSize( aDestRect.getWidth(), aDestRect.getHeight() );
357 : 0 : SurfaceSharedPtr pScrollSurface( getTemporarySurface() );
358 : 0 : CairoSharedPtr pScrollCairo( pScrollSurface->getCairo() );
359 : :
360 : 0 : cairo_save( pScrollCairo.get() );
361 : : // scroll the current content of the compositing surface (and,
362 : : // thus, of the window) in temp. surface
363 : : cairo_set_source_surface( pScrollCairo.get(),
364 : 0 : pCompositingSurface->getCairoSurface().get(),
365 : 0 : aDestPos.getX() - aSourceUpperLeftPos.getX(),
366 : 0 : aDestPos.getY() - aSourceUpperLeftPos.getY() );
367 : : cairo_rectangle( pScrollCairo.get(),
368 : 0 : aDestPos.getX(), aDestPos.getY(),
369 : 0 : aScrollSize.getX(), aScrollSize.getY() );
370 : 0 : cairo_clip( pScrollCairo.get() );
371 : 0 : cairo_set_operator( pScrollCairo.get(), CAIRO_OPERATOR_SOURCE );
372 : 0 : cairo_paint( pScrollCairo.get() );
373 : 0 : cairo_restore( pScrollCairo.get() );
374 : :
375 : 0 : cairo_save( pCompositingCairo.get() );
376 : : // copy the scrolled area back onto the compositing surface
377 : : cairo_set_source_surface( pCompositingCairo.get(),
378 : 0 : pScrollSurface->getCairoSurface().get(),
379 : 0 : 0, 0 );
380 : : cairo_rectangle( pCompositingCairo.get(),
381 : 0 : aDestPos.getX(), aDestPos.getY(),
382 : 0 : aScrollSize.getX(), aScrollSize.getY() );
383 : 0 : cairo_clip( pCompositingCairo.get() );
384 : 0 : cairo_set_operator( pCompositingCairo.get(), CAIRO_OPERATOR_SOURCE );
385 : 0 : cairo_paint( pCompositingCairo.get() );
386 : 0 : cairo_restore( pCompositingCairo.get() );
387 : :
388 : : const ::canvas::SpriteRedrawManager::SpriteConnectedRanges::ComponentListType::const_iterator
389 : 0 : aFirst( rUpdateArea.maComponentList.begin() );
390 : : ::canvas::SpriteRedrawManager::SpriteConnectedRanges::ComponentListType::const_iterator
391 : 0 : aSecond( aFirst ); ++aSecond;
392 : :
393 : 0 : ENSURE_OR_THROW( aFirst->second.getSprite().is(),
394 : : "VCLCanvas::scrollUpdate(): no sprite" );
395 : :
396 : : // repaint uncovered areas from sprite. Need to actually
397 : : // clip here, since we're only repainting _parts_ of the
398 : : // sprite
399 : : ::std::for_each( aUnscrollableAreas.begin(),
400 : : aUnscrollableAreas.end(),
401 : : ::boost::bind( &opaqueUpdateSpriteArea,
402 : 0 : ::boost::cref(aFirst->second.getSprite()),
403 : : boost::cref(pCompositingCairo),
404 : 0 : _1 ) );
405 : : }
406 : :
407 : : // repaint uncovered areas from backbuffer - take the
408 : : // _rounded_ rectangles from above, to have the update
409 : : // consistent with the scroll above.
410 : 0 : ::std::vector< ::basegfx::B2DRange > aUncoveredAreas;
411 : : ::basegfx::computeSetDifference( aUncoveredAreas,
412 : : rUpdateArea.maTotalBounds,
413 : 0 : ::basegfx::B2DRange( rDestRect ) );
414 : : ::std::for_each( aUncoveredAreas.begin(),
415 : : aUncoveredAreas.end(),
416 : : ::boost::bind( &repaintBackground,
417 : : boost::cref(pCompositingCairo),
418 : : boost::cref(mpOwningSpriteCanvas->getBufferSurface()),
419 : 0 : _1 ) );
420 : :
421 : 0 : cairo_rectangle( pWindowCairo.get(), 0, 0, rSize.getX(), rSize.getY() );
422 : 0 : cairo_clip( pWindowCairo.get() );
423 : : cairo_set_source_surface( pWindowCairo.get(),
424 : 0 : pCompositingSurface->getCairoSurface().get(),
425 : 0 : 0, 0 );
426 : 0 : cairo_set_operator( pWindowCairo.get(), CAIRO_OPERATOR_SOURCE );
427 : 0 : cairo_paint( pWindowCairo.get() );
428 : 0 : }
429 : :
430 : 0 : void SpriteCanvasHelper::opaqueUpdate( const ::basegfx::B2DRange& rTotalArea,
431 : : const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites )
432 : : {
433 : 0 : ENSURE_OR_THROW( mpOwningSpriteCanvas &&
434 : : mpOwningSpriteCanvas->getBufferSurface(),
435 : : "SpriteCanvasHelper::opaqueUpdate(): NULL device pointer " );
436 : :
437 : : SAL_INFO("canvas.cairo", "SpriteCanvasHelper::opaqueUpdate called");
438 : :
439 : 0 : const ::basegfx::B2ISize& rDeviceSize = mpOwningSpriteCanvas->getSizePixel();
440 : :
441 : 0 : SurfaceSharedPtr pCompositingSurface = getCompositingSurface(rDeviceSize);
442 : 0 : SurfaceSharedPtr pWindowSurface = mpOwningSpriteCanvas->getWindowSurface();
443 : 0 : CairoSharedPtr pCompositingCairo = pCompositingSurface->getCairo();
444 : 0 : CairoSharedPtr pWindowCairo = pWindowSurface->getCairo();
445 : :
446 : 0 : cairo_rectangle( pCompositingCairo.get(), 0, 0, rDeviceSize.getX(), rDeviceSize.getY() );
447 : 0 : cairo_clip( pCompositingCairo.get() );
448 : :
449 : 0 : ::basegfx::B2DVector aPos( ceil( rTotalArea.getMinX() ), ceil( rTotalArea.getMinY() ) );
450 : 0 : ::basegfx::B2DVector aSize( floor( rTotalArea.getMaxX() - aPos.getX() ), floor( rTotalArea.getMaxY() - aPos.getY() ) );
451 : :
452 : 0 : cairo_rectangle( pCompositingCairo.get(), aPos.getX(), aPos.getY(), aSize.getX(), aSize.getY() );
453 : 0 : cairo_clip( pCompositingCairo.get() );
454 : :
455 : : // repaint all affected sprites directly to output device
456 : : ::std::for_each( rSortedUpdateSprites.begin(),
457 : : rSortedUpdateSprites.end(),
458 : : ::boost::bind(
459 : : &spriteRedrawStub,
460 : : boost::cref(pCompositingCairo),
461 : 0 : _1 ) );
462 : :
463 : : // flush to screen
464 : 0 : cairo_rectangle( pWindowCairo.get(), 0, 0, rDeviceSize.getX(), rDeviceSize.getY() );
465 : 0 : cairo_clip( pWindowCairo.get() );
466 : 0 : cairo_rectangle( pWindowCairo.get(), aPos.getX(), aPos.getY(), aSize.getX(), aSize.getY() );
467 : 0 : cairo_clip( pWindowCairo.get() );
468 : : cairo_set_source_surface( pWindowCairo.get(),
469 : 0 : pCompositingSurface->getCairoSurface().get(),
470 : 0 : 0, 0 );
471 : 0 : cairo_set_operator( pWindowCairo.get(), CAIRO_OPERATOR_SOURCE );
472 : 0 : cairo_paint( pWindowCairo.get() );
473 : 0 : }
474 : :
475 : 0 : void SpriteCanvasHelper::genericUpdate( const ::basegfx::B2DRange& rRequestedArea,
476 : : const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites )
477 : : {
478 : : // TODO
479 : : SAL_INFO("canvas.cairo", "SpriteCanvasHelper::genericUpdate called");
480 : :
481 : 0 : ENSURE_OR_THROW( mpOwningSpriteCanvas &&
482 : : mpOwningSpriteCanvas->getBufferSurface(),
483 : : "SpriteCanvasHelper::genericUpdate(): NULL device pointer " );
484 : :
485 : : // limit size of update VDev to target outdev's size
486 : 0 : const ::basegfx::B2ISize& rSize = mpOwningSpriteCanvas->getSizePixel();
487 : :
488 : 0 : SurfaceSharedPtr pCompositingSurface = getCompositingSurface(rSize);
489 : 0 : SurfaceSharedPtr pWindowSurface = mpOwningSpriteCanvas->getWindowSurface();
490 : 0 : CairoSharedPtr pCompositingCairo = pCompositingSurface->getCairo();
491 : 0 : CairoSharedPtr pWindowCairo = pWindowSurface->getCairo();
492 : :
493 : : // round output position towards zero. Don't want to truncate
494 : : // a fraction of a sprite pixel... Clip position at origin,
495 : : // otherwise, truncation of size below might leave visible
496 : : // areas uncovered by VDev.
497 : : const Point aOutputPosition(
498 : : ::std::max( sal_Int32( 0 ),
499 : 0 : static_cast< sal_Int32 >(rRequestedArea.getMinX()) ),
500 : : ::std::max( sal_Int32( 0 ),
501 : 0 : static_cast< sal_Int32 >(rRequestedArea.getMinY()) ) );
502 : : // round output size towards +infty. Don't want to truncate a
503 : : // fraction of a sprite pixel... Limit size of VDev to output
504 : : // device's area.
505 : : const Size aOutputSize(
506 : 0 : ::std::min( rSize.getX(),
507 : 0 : ::canvas::tools::roundUp( rRequestedArea.getMaxX() - aOutputPosition.X()) ),
508 : 0 : ::std::min( rSize.getY(),
509 : 0 : ::canvas::tools::roundUp( rRequestedArea.getMaxY() - aOutputPosition.Y()) ) );
510 : :
511 : 0 : cairo_rectangle( pCompositingCairo.get(), aOutputPosition.X(), aOutputPosition.Y(), aOutputSize.Width(), aOutputSize.Height() );
512 : 0 : cairo_clip( pCompositingCairo.get() );
513 : :
514 : : // paint background
515 : 0 : cairo_save( pCompositingCairo.get() );
516 : : cairo_set_source_surface( pCompositingCairo.get(),
517 : 0 : mpOwningSpriteCanvas->getBufferSurface()->getCairoSurface().get(),
518 : 0 : 0, 0 );
519 : 0 : cairo_set_operator( pCompositingCairo.get(), CAIRO_OPERATOR_SOURCE );
520 : 0 : cairo_paint( pCompositingCairo.get() );
521 : 0 : cairo_restore( pCompositingCairo.get() );
522 : :
523 : : // repaint all affected sprites on top of background into
524 : : // VDev.
525 : : ::std::for_each( rSortedUpdateSprites.begin(),
526 : : rSortedUpdateSprites.end(),
527 : : ::boost::bind( &spriteRedrawStub2,
528 : : boost::cref(pCompositingCairo),
529 : 0 : _1 ) );
530 : :
531 : : // flush to screen
532 : 0 : cairo_rectangle( pWindowCairo.get(), aOutputPosition.X(), aOutputPosition.Y(), aOutputSize.Width(), aOutputSize.Height() );
533 : 0 : cairo_clip( pWindowCairo.get() );
534 : : cairo_set_source_surface( pWindowCairo.get(),
535 : 0 : pCompositingSurface->getCairoSurface().get(),
536 : 0 : 0, 0 );
537 : 0 : cairo_set_operator( pWindowCairo.get(), CAIRO_OPERATOR_SOURCE );
538 : 0 : cairo_paint( pWindowCairo.get() );
539 : 0 : }
540 : :
541 : 0 : ::cairo::SurfaceSharedPtr SpriteCanvasHelper::getCompositingSurface( const ::basegfx::B2ISize& rNeededSize )
542 : : {
543 : 0 : if( rNeededSize.getX() > maCompositingSurfaceSize.getX() ||
544 : 0 : rNeededSize.getY() > maCompositingSurfaceSize.getY() )
545 : : {
546 : : // need to give buffer more size
547 : 0 : mpCompositingSurface.reset();
548 : : }
549 : :
550 : 0 : if( !mpCompositingSurface )
551 : : {
552 : 0 : mpCompositingSurface = createSurface( rNeededSize );
553 : 0 : maCompositingSurfaceSize = rNeededSize;
554 : 0 : mbCompositingSurfaceDirty = true;
555 : 0 : mpTemporarySurface.reset();
556 : : }
557 : :
558 : 0 : return mpCompositingSurface;
559 : : }
560 : :
561 : 0 : ::cairo::SurfaceSharedPtr SpriteCanvasHelper::getTemporarySurface()
562 : : {
563 : 0 : if ( !mpTemporarySurface )
564 : 0 : mpTemporarySurface = createSurface( maCompositingSurfaceSize );
565 : 0 : return mpTemporarySurface;
566 : : }
567 : :
568 : 0 : ::cairo::SurfaceSharedPtr SpriteCanvasHelper::createSurface( const ::basegfx::B2ISize& rNeededSize ) const
569 : : {
570 : 0 : return mpOwningSpriteCanvas->getWindowSurface()->getSimilar(
571 : : CAIRO_CONTENT_COLOR,
572 : 0 : rNeededSize.getX(), rNeededSize.getY() );
573 : : }
574 : 0 : }
575 : :
576 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|