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