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