/* -*- 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "spritehelper.hxx" using namespace ::com::sun::star; namespace vclcanvas { SpriteHelper::SpriteHelper() : mbShowSpriteBounds(false) { } void SpriteHelper::init( const geometry::RealSize2D& rSpriteSize, const ::canvas::SpriteSurface::Reference& rOwningSpriteCanvas, const BackBufferSharedPtr& rBackBuffer, const BackBufferSharedPtr& rBackBufferMask, bool bShowSpriteBounds ) { ENSURE_OR_THROW( rOwningSpriteCanvas && rBackBuffer && rBackBufferMask, "SpriteHelper::init(): Invalid sprite canvas or back buffer" ); mpBackBuffer = rBackBuffer; mpBackBufferMask = rBackBufferMask; mbShowSpriteBounds = bShowSpriteBounds; init( rSpriteSize, rOwningSpriteCanvas ); } void SpriteHelper::disposing() { mpBackBuffer.reset(); mpBackBufferMask.reset(); // forward to parent CanvasCustomSpriteHelper::disposing(); } void SpriteHelper::redraw( OutputDevice& rTargetSurface, const ::basegfx::B2DPoint& rPos, bool& io_bSurfacesDirty, bool /*bBufferedUpdate*/ ) const { if( !mpBackBuffer || !mpBackBufferMask ) { return; // we're disposed } // log output pos in device pixel SAL_INFO("canvas.vcl", "SpriteHelper::redraw(): output pos is (" << rPos.getX() << "," << rPos.getY() << ")"); const double fAlpha( getAlpha() ); if( !isActive() || ::basegfx::fTools::equalZero( fAlpha ) ) return; const ::basegfx::B2DVector& rOrigOutputSize( getSizePixel() ); // might get changed below (e.g. adapted for // transformations). IMPORTANT: both position and size are // rounded to integer values. From now on, only those // rounded values are used, to keep clip and content in // sync. ::Size aOutputSize( vcl::unotools::sizeFromB2DSize( rOrigOutputSize ) ); ::Point aOutPos( vcl::unotools::pointFromB2DPoint( rPos ) ); // TODO(F3): Support for alpha-VDev // Do we have to update our bitmaps (necessary if virdev // was painted to, or transformation changed)? const bool bNeedBitmapUpdate( io_bSurfacesDirty || hasTransformChanged() || maContent->IsEmpty() ); // updating content of sprite cache - surface is no // longer dirty in relation to our cache io_bSurfacesDirty = false; transformUpdated(); if( bNeedBitmapUpdate ) { const Point aEmptyPoint; BitmapEx aBmp( mpBackBuffer->getOutDev().GetBitmapEx( aEmptyPoint, aOutputSize ) ); if( isContentFullyOpaque() ) { // optimized case: content canvas is fully // opaque. Note: since we retrieved aBmp directly // from an OutDev, it's already a 'display bitmap' // on windows. maContent = aBmp; } else { // sprite content might contain alpha, create // BmpEx, then. BitmapEx aMask( mpBackBufferMask->getOutDev().GetBitmapEx( aEmptyPoint, aOutputSize ) ); AlphaMask aAlpha( aMask.GetBitmap() ); aAlpha.Invert(); // Note: since we retrieved aBmp and aMask // directly from an OutDev, it's already a // 'display bitmap' on windows. maContent = BitmapEx( aBmp.GetBitmap(), aAlpha ); } } ::basegfx::B2DHomMatrix aTransform( getTransformation() ); rTargetSurface.Push( vcl::PushFlags::CLIPREGION ); // apply clip (if any) if( getClip().is() ) { ::basegfx::B2DPolyPolygon aClipPoly( ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( getClip() )); if( aClipPoly.count() ) { // Move the clip to the final sprite output position. ::basegfx::B2DHomMatrix aClipTransform( aTransform ); aClipTransform.translate( aOutPos.X(), aOutPos.Y() ); aClipPoly.transform( aClipTransform ); if( mbShowSpriteBounds ) { // Paint green sprite clip area rTargetSurface.SetLineColor( COL_LIGHTGREEN ); rTargetSurface.SetFillColor(); rTargetSurface.DrawPolyPolygon(::tools::PolyPolygon(aClipPoly)); // #i76339# } vcl::Region aClipRegion( aClipPoly ); rTargetSurface.SetClipRegion( aClipRegion ); } } ::basegfx::B2DHomMatrix aSizeTransform, aMoveTransform; aSizeTransform.scale( aOutputSize.Width(), aOutputSize.Height() ); aMoveTransform.translate( aOutPos.X(), aOutPos.Y() ); aTransform = aMoveTransform * aTransform * aSizeTransform; rTargetSurface.DrawTransformedBitmapEx( aTransform, *maContent, fAlpha ); rTargetSurface.Pop(); if( !mbShowSpriteBounds ) return; ::tools::PolyPolygon aMarkerPoly( ::canvas::tools::getBoundMarksPolyPolygon( ::basegfx::B2DRectangle(aOutPos.X(), aOutPos.Y(), aOutPos.X() + aOutputSize.Width()-1, aOutPos.Y() + aOutputSize.Height()-1) ) ); // Paint little red sprite area markers rTargetSurface.SetLineColor( COL_RED ); rTargetSurface.SetFillColor(); for( int i=0; i(i)) ); } // paint sprite prio vcl::Font aVCLFont; aVCLFont.SetFontHeight( std::min(::tools::Long(20),aOutputSize.Height()) ); aVCLFont.SetColor( COL_RED ); rTargetSurface.SetTextAlign(ALIGN_TOP); rTargetSurface.SetTextColor( COL_RED ); rTargetSurface.SetFont( aVCLFont ); OUString text( ::rtl::math::doubleToUString( getPriority(), rtl_math_StringFormat_F, 2,'.',nullptr,' ') ); rTargetSurface.DrawText( aOutPos+Point(2,2), text ); SAL_INFO( "canvas.vcl", "sprite " << this << " has prio " << getPriority()); } ::basegfx::B2DPolyPolygon SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference< rendering::XPolyPolygon2D >& xPoly ) const { return ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPoly ); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */