LCOV - code coverage report
Current view: top level - drawinglayer/source/processor2d - vclhelperbufferdevice.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 134 143 93.7 %
Date: 2014-11-03 Functions: 15 15 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <vclhelperbufferdevice.hxx>
      21             : #include <basegfx/range/b2drange.hxx>
      22             : #include <vcl/bitmapex.hxx>
      23             : #include <basegfx/matrix/b2dhommatrix.hxx>
      24             : #include <tools/stream.hxx>
      25             : #include <vcl/timer.hxx>
      26             : #include <comphelper/broadcasthelper.hxx>
      27             : #include <vcl/lazydelete.hxx>
      28             : #include <vcl/dibtools.hxx>
      29             : 
      30             : 
      31             : // buffered VDev usage
      32             : 
      33             : namespace
      34             : {
      35             :     typedef ::std::vector< VirtualDevice* > aBuffers;
      36             : 
      37             :     class VDevBuffer : public Timer, protected comphelper::OBaseMutex
      38             :     {
      39             :     private:
      40             :         // available buffers
      41             :         aBuffers            maFreeBuffers;
      42             : 
      43             :         // allocated/used buffers (remembered to allow deleteing them in destructor)
      44             :         aBuffers            maUsedBuffers;
      45             : 
      46             :     public:
      47             :         VDevBuffer();
      48             :         virtual ~VDevBuffer();
      49             : 
      50             :         VirtualDevice* alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, sal_Int32 nBits);
      51             :         void free(VirtualDevice& rDevice);
      52             : 
      53             :         // Timer virtuals
      54             :         virtual void Timeout() SAL_OVERRIDE;
      55             :     };
      56             : 
      57          22 :     VDevBuffer::VDevBuffer()
      58             :     :   Timer(),
      59             :         maFreeBuffers(),
      60          22 :         maUsedBuffers()
      61             :     {
      62          22 :         SetTimeout(10L * 1000L); // ten seconds
      63          22 :     }
      64             : 
      65          66 :     VDevBuffer::~VDevBuffer()
      66             :     {
      67          22 :         ::osl::MutexGuard aGuard(m_aMutex);
      68          22 :         Stop();
      69             : 
      70          93 :         while(!maFreeBuffers.empty())
      71             :         {
      72          49 :             delete *(maFreeBuffers.end() - 1);
      73          49 :             maFreeBuffers.pop_back();
      74             :         }
      75             : 
      76          44 :         while(!maUsedBuffers.empty())
      77             :         {
      78           0 :             delete *(maUsedBuffers.end() - 1);
      79           0 :             maUsedBuffers.pop_back();
      80          22 :         }
      81          44 :     }
      82             : 
      83        9635 :     VirtualDevice* VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, sal_Int32 nBits)
      84             :     {
      85        9635 :         ::osl::MutexGuard aGuard(m_aMutex);
      86        9635 :         VirtualDevice* pRetval = 0;
      87             : 
      88        9635 :         if (nBits == 0)
      89        5868 :             nBits = rOutDev.GetBitCount();
      90             : 
      91        9635 :         if(!maFreeBuffers.empty())
      92             :         {
      93        9587 :             bool bOkay(false);
      94        9587 :             aBuffers::iterator aFound(maFreeBuffers.end());
      95             : 
      96       50622 :             for(aBuffers::iterator a(maFreeBuffers.begin()); a != maFreeBuffers.end(); ++a)
      97             :             {
      98             :                 OSL_ENSURE(*a, "Empty pointer in VDevBuffer (!)");
      99             : 
     100       41035 :                 if(nBits == (*a)->GetBitCount())
     101             :                 {
     102             :                     // candidate is valid due to bit depth
     103       24233 :                     if(aFound != maFreeBuffers.end())
     104             :                     {
     105             :                         // already found
     106       14667 :                         if(bOkay)
     107             :                         {
     108             :                             // found is valid
     109       12381 :                             const bool bCandidateOkay((*a)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*a)->GetOutputHeightPixel() >= rSizePixel.getHeight());
     110             : 
     111       12381 :                             if(bCandidateOkay)
     112             :                             {
     113             :                                 // found and candidate are valid
     114       10804 :                                 const sal_uLong aSquare((*aFound)->GetOutputWidthPixel() * (*aFound)->GetOutputHeightPixel());
     115       10804 :                                 const sal_uLong aCandidateSquare((*a)->GetOutputWidthPixel() * (*a)->GetOutputHeightPixel());
     116             : 
     117       10804 :                                 if(aCandidateSquare < aSquare)
     118             :                                 {
     119             :                                     // candidate is valid and smaller, use it
     120        5318 :                                     aFound = a;
     121             :                                 }
     122             :                             }
     123             :                             else
     124             :                             {
     125             :                                 // found is valid, candidate is not. Keep found
     126             :                             }
     127             :                         }
     128             :                         else
     129             :                         {
     130             :                             // found is invalid, use candidate
     131        2286 :                             aFound = a;
     132        2286 :                             bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight();
     133             :                         }
     134             :                     }
     135             :                     else
     136             :                     {
     137             :                         // none yet, use candidate
     138        9566 :                         aFound = a;
     139        9566 :                         bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight();
     140             :                     }
     141             :                 }
     142             :             }
     143             : 
     144        9587 :             if(aFound != maFreeBuffers.end())
     145             :             {
     146        9566 :                 pRetval = *aFound;
     147        9566 :                 maFreeBuffers.erase(aFound);
     148             : 
     149        9566 :                 if(bOkay)
     150             :                 {
     151        8775 :                     if(bClear)
     152             :                     {
     153        4124 :                         pRetval->Erase(Rectangle(0, 0, rSizePixel.getWidth(), rSizePixel.getHeight()));
     154             :                     }
     155             :                 }
     156             :                 else
     157             :                 {
     158         791 :                     pRetval->SetOutputSizePixel(rSizePixel, bClear);
     159             :                 }
     160             :             }
     161             :         }
     162             : 
     163             :         // no success yet, create new buffer
     164        9635 :         if(!pRetval)
     165             :         {
     166          69 :             pRetval = new VirtualDevice(rOutDev, nBits);
     167          69 :             pRetval->SetOutputSizePixel(rSizePixel, bClear);
     168             :         }
     169             :         else
     170             :         {
     171             :             // reused, reset some values
     172        9566 :             pRetval->SetMapMode();
     173             :         }
     174             : 
     175             :         // remember allocated buffer
     176        9635 :         maUsedBuffers.push_back(pRetval);
     177             : 
     178        9635 :         return pRetval;
     179             :     }
     180             : 
     181        9635 :     void VDevBuffer::free(VirtualDevice& rDevice)
     182             :     {
     183        9635 :         ::osl::MutexGuard aGuard(m_aMutex);
     184        9635 :         const aBuffers::iterator aUsedFound(::std::find(maUsedBuffers.begin(), maUsedBuffers.end(), &rDevice));
     185             :         OSL_ENSURE(aUsedFound != maUsedBuffers.end(), "OOps, non-registered buffer freed (!)");
     186             : 
     187        9635 :         maUsedBuffers.erase(aUsedFound);
     188        9635 :         maFreeBuffers.push_back(&rDevice);
     189             :         SAL_WARN_IF(maFreeBuffers.size() > 1000, "drawinglayer", "excessive cached buffers, "
     190             :             << maFreeBuffers.size() << " entries!");
     191        9635 :         Start();
     192        9635 :     }
     193             : 
     194           9 :     void VDevBuffer::Timeout()
     195             :     {
     196           9 :         ::osl::MutexGuard aGuard(m_aMutex);
     197             : 
     198          38 :         while(!maFreeBuffers.empty())
     199             :         {
     200          20 :             delete *(maFreeBuffers.end() - 1);
     201          20 :             maFreeBuffers.pop_back();
     202           9 :         }
     203           9 :     }
     204             : }
     205             : 
     206             : 
     207             : // support for rendering Bitmap and BitmapEx contents
     208             : 
     209             : namespace drawinglayer
     210             : {
     211             :     // static global VDev buffer for the VclProcessor2D's (VclMetafileProcessor2D and VclPixelProcessor2D)
     212       19270 :     VDevBuffer& getVDevBuffer()
     213             :     {
     214             :         // secure global instance with Vcl's safe desroyer of external (seen by
     215             :         // library base) stuff, the remembered VDevs need to be deleted before
     216             :         // Vcl's deinit
     217       19270 :         static vcl::DeleteOnDeinit< VDevBuffer > aVDevBuffer(new VDevBuffer());
     218       19270 :         return *aVDevBuffer.get();
     219             :     }
     220             : 
     221        5226 :     impBufferDevice::impBufferDevice(
     222             :         OutputDevice& rOutDev,
     223             :         const basegfx::B2DRange& rRange,
     224             :         bool bAddOffsetToMapping)
     225             :     :   mrOutDev(rOutDev),
     226             :         mpContent(0),
     227             :         mpMask(0),
     228        5226 :         mpAlpha(0)
     229             :     {
     230        5226 :         basegfx::B2DRange aRangePixel(rRange);
     231        5226 :         aRangePixel.transform(mrOutDev.GetViewTransformation());
     232             :         const Rectangle aRectPixel(
     233       10452 :             (sal_Int32)floor(aRangePixel.getMinX()), (sal_Int32)floor(aRangePixel.getMinY()),
     234       15678 :             (sal_Int32)ceil(aRangePixel.getMaxX()), (sal_Int32)ceil(aRangePixel.getMaxY()));
     235        5226 :         const Point aEmptyPoint;
     236        5226 :         maDestPixel = Rectangle(aEmptyPoint, mrOutDev.GetOutputSizePixel());
     237        5226 :         maDestPixel.Intersection(aRectPixel);
     238             : 
     239        5226 :         if(isVisible())
     240             :         {
     241             : #ifdef IOS
     242             :             // Exact mechanism unknown, but for some reason SmartArt
     243             :             // rendering, especially shadows, is broken on iOS unless
     244             :             // we pass 'true' here. Are virtual devices always de
     245             :             // facto cleared when created on other platforms?
     246             :             mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 0);
     247             : #else
     248        5120 :             mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, 0);
     249             : #endif
     250             : 
     251             :             // #i93485# assert when copying from window to VDev is used
     252             :             OSL_ENSURE(mrOutDev.GetOutDevType() != OUTDEV_WINDOW,
     253             :                 "impBufferDevice render helper: Copying from Window to VDev, this should be avoided (!)");
     254             : 
     255        5120 :             const bool bWasEnabledSrc(mrOutDev.IsMapModeEnabled());
     256        5120 :             mrOutDev.EnableMapMode(false);
     257        5120 :             mpContent->DrawOutDev(aEmptyPoint, maDestPixel.GetSize(), maDestPixel.TopLeft(), maDestPixel.GetSize(), mrOutDev);
     258        5120 :             mrOutDev.EnableMapMode(bWasEnabledSrc);
     259             : 
     260        5120 :             MapMode aNewMapMode(mrOutDev.GetMapMode());
     261             : 
     262        5120 :             if(bAddOffsetToMapping)
     263             :             {
     264        5120 :                 const Point aLogicTopLeft(mrOutDev.PixelToLogic(maDestPixel.TopLeft()));
     265        5120 :                 aNewMapMode.SetOrigin(Point(-aLogicTopLeft.X(), -aLogicTopLeft.Y()));
     266             :             }
     267             : 
     268        5120 :             mpContent->SetMapMode(aNewMapMode);
     269             : 
     270             :             // copy AA flag for new target
     271        5120 :             mpContent->SetAntialiasing(mrOutDev.GetAntialiasing());
     272             :         }
     273        5226 :     }
     274             : 
     275        5226 :     impBufferDevice::~impBufferDevice()
     276             :     {
     277        5226 :         if(mpContent)
     278             :         {
     279        5120 :             getVDevBuffer().free(*mpContent);
     280             :         }
     281             : 
     282        5226 :         if(mpMask)
     283             :         {
     284        3767 :             getVDevBuffer().free(*mpMask);
     285             :         }
     286             : 
     287        5226 :         if(mpAlpha)
     288             :         {
     289         748 :             getVDevBuffer().free(*mpAlpha);
     290             :         }
     291        5226 :     }
     292             : 
     293        5120 :     void impBufferDevice::paint(double fTrans)
     294             :     {
     295        5120 :         if(isVisible())
     296             :         {
     297        5120 :             const Point aEmptyPoint;
     298        5120 :             const Size aSizePixel(maDestPixel.GetSize());
     299        5120 :             const bool bWasEnabledDst(mrOutDev.IsMapModeEnabled());
     300             :             static bool bDoSaveForVisualControl(false);
     301             : 
     302        5120 :             mrOutDev.EnableMapMode(false);
     303        5120 :             mpContent->EnableMapMode(false);
     304        5120 :             Bitmap aContent(mpContent->GetBitmap(aEmptyPoint, aSizePixel));
     305             : 
     306        5120 :             if(bDoSaveForVisualControl)
     307             :             {
     308           0 :                 SvFileStream aNew( "c:\\content.bmp", STREAM_WRITE|STREAM_TRUNC);
     309           0 :                 WriteDIB(aContent, aNew, false, true);
     310             :             }
     311             : 
     312        5120 :             if(mpAlpha)
     313             :             {
     314         748 :                 mpAlpha->EnableMapMode(false);
     315         748 :                 const AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel));
     316             : 
     317         748 :                 if(bDoSaveForVisualControl)
     318             :                 {
     319           0 :                     SvFileStream aNew( "c:\\transparence.bmp", STREAM_WRITE|STREAM_TRUNC);
     320           0 :                     WriteDIB(aAlphaMask.GetBitmap(), aNew, false, true);
     321             :                 }
     322             : 
     323         748 :                 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
     324             :             }
     325        4372 :             else if(mpMask)
     326             :             {
     327        3767 :                 mpMask->EnableMapMode(false);
     328        3767 :                 const Bitmap aMask(mpMask->GetBitmap(aEmptyPoint, aSizePixel));
     329             : 
     330        3767 :                 if(bDoSaveForVisualControl)
     331             :                 {
     332           0 :                     SvFileStream aNew( "c:\\mask.bmp", STREAM_WRITE|STREAM_TRUNC);
     333           0 :                     WriteDIB(aMask, aNew, false, true);
     334             :                 }
     335             : 
     336        3767 :                 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask));
     337             :             }
     338         605 :             else if(0.0 != fTrans)
     339             :             {
     340         605 :                 sal_uInt8 nMaskValue((sal_uInt8)basegfx::fround(fTrans * 255.0));
     341         605 :                 const AlphaMask aAlphaMask(aSizePixel, &nMaskValue);
     342         605 :                 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
     343             :             }
     344             :             else
     345             :             {
     346           0 :                 mrOutDev.DrawBitmap(maDestPixel.TopLeft(), aContent);
     347             :             }
     348             : 
     349        5120 :             mrOutDev.EnableMapMode(bWasEnabledDst);
     350             :         }
     351        5120 :     }
     352             : 
     353        5120 :     VirtualDevice& impBufferDevice::getContent()
     354             :     {
     355             :         assert(mpContent && "impBufferDevice: No content, check isVisible() before accessing (!)");
     356        5120 :         return *mpContent;
     357             :     }
     358             : 
     359        3767 :     VirtualDevice& impBufferDevice::getMask()
     360             :     {
     361             :         assert(mpContent && "impBufferDevice: No content, check isVisible() before accessing (!)");
     362        3767 :         if (!mpMask)
     363             :         {
     364        3767 :             mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 1);
     365        3767 :             mpMask->SetMapMode(mpContent->GetMapMode());
     366             : 
     367             :             // do NOT copy AA flag for mask!
     368             :         }
     369             : 
     370        3767 :         return *mpMask;
     371             :     }
     372             : 
     373         748 :     VirtualDevice& impBufferDevice::getTransparence()
     374             :     {
     375             :         OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
     376         748 :         if(!mpAlpha)
     377             :         {
     378         748 :             mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 0);
     379         748 :             mpAlpha->SetMapMode(mpContent->GetMapMode());
     380             : 
     381             :             // copy AA flag for new target; masking needs to be smooth
     382         748 :             mpAlpha->SetAntialiasing(mpContent->GetAntialiasing());
     383             :         }
     384             : 
     385         748 :         return *mpAlpha;
     386             :     }
     387        1143 : } // end of namespace drawinglayer
     388             : 
     389             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10