/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
namespace vclcanvas
{ namespace
{ /** Sprite redraw at original position
Used to repaint the whole canvas (background and all sprites)
*/ void spriteRedraw( OutputDevice& rOutDev, const ::canvas::Sprite::Reference& rSprite )
{ // downcast to derived vclcanvas::Sprite interface, which // provides the actual redraw methods.
::boost::polymorphic_downcast< Sprite* >(rSprite.get())->redraw(rOutDev, true);
}
// clip output to actual update region (otherwise a) // wouldn't save much render time, and b) will clutter // scrolled sprite content outside this area)
rOutDev.EnableMapMode( false );
rOutDev.SetAntialiasing( AntialiasingFlags::Enable );
rOutDev.SetClipRegion(vcl::Region(aRequestedArea));
// repaint affected sprite directly to output device (at // the actual screen output position)
::boost::polymorphic_downcast< Sprite* >(
rSprite.get() )->redraw( rOutDev, false ); // rendering // directly to // frontbuffer
}
// we're double-buffered, thus no need for paint area-limiting // clips. besides that, will interfere with animations (as for // Window-invalidate repaints, only parts of the window will // be redrawn otherwise) const vcl::Region aFullWindowRegion( ::tools::Rectangle(aEmptyPoint,
aOutDevSize) );
pTargetWindow->ExpandPaintClipRegion(aFullWindowRegion);
}
// TODO(P1): Might be worthwhile to track areas of background // changes, too. if( !bUpdateAll && !io_bSurfaceDirty )
{ if( mbShowFrameInfo )
{ // also repaint background below frame counter (fake // that as a sprite vanishing in this area)
mpRedrawManager->updateSprite( ::canvas::Sprite::Reference(),
::basegfx::B2DPoint(),
::basegfx::B2DRectangle( 0.0, 0.0,
FPS_BOUNDS.Right(),
FPS_BOUNDS.Bottom() ) );
}
// background has not changed, so we're free to optimize // repaint to areas where a sprite has changed
// process each independent area of overlapping sprites // separately.
mpRedrawManager->forEachSpriteArea( *this );
} else
{ // background has changed, so we currently have no choice // but repaint everything (or caller requested that)
// repaint all active sprites on top of background into // VDev.
OutputDevice& rTmpOutDev( *maVDev );
mpRedrawManager->forEachSprite(
[&rTmpOutDev]( const ::canvas::Sprite::Reference& rSprite )
{ spriteRedraw( rTmpOutDev, rSprite ); }
);
// log time immediately after surface flip
SAL_INFO("canvas.vcl", "SpriteCanvasHelper::updateScreen(): flip done at " <<
aElapsedTime.getElapsedTime() ); #endif
// sync output with screen, to ensure that we don't queue up // render requests (calling code might rely on timing, // i.e. assume that things are visible on screen after // updateScreen() returns). if( pTargetWindow )
{ // commit to screen
pTargetWindow->GetOutDev()->Flush();
}
// round rectangles to integer pixel. Note: have to be // extremely careful here, to avoid off-by-one errors for // the destination area: otherwise, the next scroll update // would copy pixel that are not supposed to be part of // the sprite.
::basegfx::B2IRange aSourceRect(
::canvas::tools::spritePixelAreaFromB2DRange( rMoveStart ) ); const ::basegfx::B2IRange aDestRect(
::canvas::tools::spritePixelAreaFromB2DRange( rMoveEnd ) );
::basegfx::B2IPoint aDestPos( aDestRect.getMinimum() );
// Since strictly speaking, this scroll algorithm is plain // buggy, the scrolled area might actually lie _below_ another // window - we've made this feature configurable via // mbIsUnsafeScrolling.
// clip to output bounds (cannot properly scroll stuff // _outside_ our screen area) if( !mbIsUnsafeScrolling ||
!::canvas::tools::clipScrollArea( aSourceRect,
aDestPos,
aUnscrollableAreas,
aOutputBounds ) )
{ // fully clipped scroll area: cannot simply scroll // then. Perform normal opaque update (can use that, since // one of the preconditions for scrollable update is // opaque sprite content)
ENSURE_OR_THROW( aFirst->second.getSprite().is(), "VCLCanvas::scrollUpdate(): no sprite" );
// repaint uncovered areas from sprite. Need to actually // clip here, since we're only repainting _parts_ of the // sprite
rOutDev.Push( vcl::PushFlags::CLIPREGION );
// repaint uncovered areas from backbuffer - take the // _rounded_ rectangles from above, to have the update // consistent with the scroll above.
std::vector< ::basegfx::B2DRange > aUncoveredAreas;
::basegfx::computeSetDifference( aUncoveredAreas,
rUpdateArea.maTotalBounds,
::basegfx::B2DRange( aDestRect ) );
// no need to clip output to actual update region - there will // always be ALL sprites contained in the rectangular update // area contained in rTotalArea (that's the way // B2DConnectedRanges work). If rTotalArea appears to be // smaller than the sprite - then this sprite carries a clip, // and the update will be constrained to that rect.
// limit size of update VDev to target outdev's size const Size aTargetSizePixel( rOutDev.GetOutputSizePixel() );
// round output position towards zero. Don't want to truncate // a fraction of a sprite pixel... Clip position at origin, // otherwise, truncation of size below might leave visible // areas uncovered by VDev. const ::Point aOutputPosition(
std::max( sal_Int32( 0 ), static_cast< sal_Int32 >(rRequestedArea.getMinX()) ),
std::max( sal_Int32( 0 ), static_cast< sal_Int32 >(rRequestedArea.getMinY()) ) ); // round output size towards +infty. Don't want to truncate a // fraction of a sprite pixel... Limit coverage of VDev to // output device's area (i.e. not only to total size, but to // cover _only_ the visible parts). const ::Size aOutputSize(
std::max( sal_Int32( 0 ),
std::min( static_cast< sal_Int32 >(aTargetSizePixel.Width() - aOutputPosition.X()),
::canvas::tools::roundUp( rRequestedArea.getMaxX() - aOutputPosition.X() ))),
std::max( sal_Int32( 0 ),
std::min( static_cast< sal_Int32 >(aTargetSizePixel.Height() - aOutputPosition.Y()),
::canvas::tools::roundUp( rRequestedArea.getMaxY() - aOutputPosition.Y() ))));
// early exit for empty output area. if( aOutputSize.Width() == 0 &&
aOutputSize.Height() == 0 )
{ return;
}
const Point aEmptyPoint(0,0); const Size aCurrOutputSize( maVDev->GetOutputSizePixel() );
// adapt maVDev's size to the area that actually needs the // repaint. if( aCurrOutputSize.Width() < aOutputSize.Width() ||
aCurrOutputSize.Height() < aOutputSize.Height() )
{ // TODO(P1): Come up with a clever tactic to reduce maVDev // from time to time. Reduction with threshold (say, if // maVDev is more than twice too large) is not wise, as // this might then toggle within the same updateScreen(), // but for different disjunct sprite areas.
maVDev->SetOutputSizePixel( aOutputSize );
}
// repaint all affected sprites on top of background into // VDev. for( constauto& rSprite : rSortedUpdateSprites )
{ if( rSprite.is() )
{
Sprite* pSprite = ::boost::polymorphic_downcast< Sprite* >( rSprite.get() );
// calc relative sprite position in rUpdateArea (which // need not be the whole screen!) const ::basegfx::B2DPoint aSpriteScreenPos( pSprite->getPosPixel() ); const ::basegfx::B2DPoint aSpriteRenderPos(
aSpriteScreenPos - vcl::unotools::b2DPointFromPoint(aOutputPosition)
);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.