LCOV - code coverage report
Current view: top level - drawinglayer/source/processor2d - vclhelperbufferdevice.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 131 140 93.6 %
Date: 2014-04-11 Functions: 13 13 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           9 :     VDevBuffer::VDevBuffer()
      58             :     :   Timer(),
      59             :         maFreeBuffers(),
      60           9 :         maUsedBuffers()
      61             :     {
      62           9 :         SetTimeout(10L * 1000L); // ten seconds
      63           9 :     }
      64             : 
      65          15 :     VDevBuffer::~VDevBuffer()
      66             :     {
      67           5 :         ::osl::MutexGuard aGuard(m_aMutex);
      68           5 :         Stop();
      69             : 
      70        4072 :         while(!maFreeBuffers.empty())
      71             :         {
      72        4062 :             delete *(maFreeBuffers.end() - 1);
      73        4062 :             maFreeBuffers.pop_back();
      74             :         }
      75             : 
      76          10 :         while(!maUsedBuffers.empty())
      77             :         {
      78           0 :             delete *(maUsedBuffers.end() - 1);
      79           0 :             maUsedBuffers.pop_back();
      80           5 :         }
      81          10 :     }
      82             : 
      83       10276 :     VirtualDevice* VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, sal_Int32 nBits)
      84             :     {
      85       10276 :         ::osl::MutexGuard aGuard(m_aMutex);
      86       10276 :         VirtualDevice* pRetval = 0;
      87             : 
      88       10276 :         if(!maFreeBuffers.empty())
      89             :         {
      90       10251 :             bool bOkay(false);
      91       10251 :             aBuffers::iterator aFound(maFreeBuffers.end());
      92             : 
      93     7429632 :             for(aBuffers::iterator a(maFreeBuffers.begin()); a != maFreeBuffers.end(); ++a)
      94             :             {
      95             :                 OSL_ENSURE(*a, "Empty pointer in VDevBuffer (!)");
      96             : 
      97     7419381 :                 if(nBits == (*a)->GetBitCount())
      98             :                 {
      99             :                     // candidate is valid due to bit depth
     100       42155 :                     if(aFound != maFreeBuffers.end())
     101             :                     {
     102             :                         // already found
     103       37341 :                         if(bOkay)
     104             :                         {
     105             :                             // found is valid
     106       32247 :                             const bool bCandidateOkay((*a)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*a)->GetOutputHeightPixel() >= rSizePixel.getHeight());
     107             : 
     108       32247 :                             if(bCandidateOkay)
     109             :                             {
     110             :                                 // found and candidate are valid
     111       19105 :                                 const sal_uLong aSquare((*aFound)->GetOutputWidthPixel() * (*aFound)->GetOutputHeightPixel());
     112       19105 :                                 const sal_uLong aCandidateSquare((*a)->GetOutputWidthPixel() * (*a)->GetOutputHeightPixel());
     113             : 
     114       19105 :                                 if(aCandidateSquare < aSquare)
     115             :                                 {
     116             :                                     // candidate is valid and smaller, use it
     117         751 :                                     aFound = a;
     118             :                                 }
     119             :                             }
     120             :                             else
     121             :                             {
     122             :                                 // found is valid, candidate is not. Keep found
     123             :                             }
     124             :                         }
     125             :                         else
     126             :                         {
     127             :                             // found is invalid, use candidate
     128        5094 :                             aFound = a;
     129        5094 :                             bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight();
     130             :                         }
     131             :                     }
     132             :                     else
     133             :                     {
     134             :                         // none yet, use candidate
     135        4814 :                         aFound = a;
     136        4814 :                         bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight();
     137             :                     }
     138             :                 }
     139             :             }
     140             : 
     141       10251 :             if(aFound != maFreeBuffers.end())
     142             :             {
     143        4814 :                 pRetval = *aFound;
     144        4814 :                 maFreeBuffers.erase(aFound);
     145             : 
     146        4814 :                 if(bOkay)
     147             :                 {
     148        4006 :                     if(bClear)
     149             :                     {
     150        4006 :                         pRetval->Erase(Rectangle(0, 0, rSizePixel.getWidth(), rSizePixel.getHeight()));
     151             :                     }
     152             :                 }
     153             :                 else
     154             :                 {
     155         808 :                     pRetval->SetOutputSizePixel(rSizePixel, bClear);
     156             :                 }
     157             :             }
     158             :         }
     159             : 
     160             :         // no success yet, create new buffer
     161       10276 :         if(!pRetval)
     162             :         {
     163        5462 :             pRetval = new VirtualDevice(rOutDev, nBits);
     164        5462 :             pRetval->SetOutputSizePixel(rSizePixel, bClear);
     165             :         }
     166             :         else
     167             :         {
     168             :             // reused, reset some values
     169        4814 :             pRetval->SetMapMode();
     170             :         }
     171             : 
     172             :         // remember allocated buffer
     173       10276 :         maUsedBuffers.push_back(pRetval);
     174             : 
     175       10276 :         return pRetval;
     176             :     }
     177             : 
     178       10276 :     void VDevBuffer::free(VirtualDevice& rDevice)
     179             :     {
     180       10276 :         ::osl::MutexGuard aGuard(m_aMutex);
     181       10276 :         const aBuffers::iterator aUsedFound(::std::find(maUsedBuffers.begin(), maUsedBuffers.end(), &rDevice));
     182             :         OSL_ENSURE(aUsedFound != maUsedBuffers.end(), "OOps, non-registered buffer freed (!)");
     183             : 
     184       10276 :         maUsedBuffers.erase(aUsedFound);
     185       10276 :         maFreeBuffers.push_back(&rDevice);
     186       10276 :         Start();
     187       10276 :     }
     188             : 
     189           7 :     void VDevBuffer::Timeout()
     190             :     {
     191           7 :         ::osl::MutexGuard aGuard(m_aMutex);
     192             : 
     193        1374 :         while(!maFreeBuffers.empty())
     194             :         {
     195        1360 :             delete *(maFreeBuffers.end() - 1);
     196        1360 :             maFreeBuffers.pop_back();
     197           7 :         }
     198           7 :     }
     199             : }
     200             : 
     201             : 
     202             : // support for rendering Bitmap and BitmapEx contents
     203             : 
     204             : namespace drawinglayer
     205             : {
     206             :     // static global VDev buffer for the VclProcessor2D's (VclMetafileProcessor2D and VclPixelProcessor2D)
     207       20552 :     VDevBuffer& getVDevBuffer()
     208             :     {
     209             :         // secure global instance with Vcl's safe desroyer of external (seen by
     210             :         // library base) stuff, the remembered VDevs need to be deleted before
     211             :         // Vcl's deinit
     212       20552 :         static vcl::DeleteOnDeinit< VDevBuffer > aVDevBuffer(new VDevBuffer());
     213       20552 :         return *aVDevBuffer.get();
     214             :     }
     215             : 
     216        5536 :     impBufferDevice::impBufferDevice(
     217             :         OutputDevice& rOutDev,
     218             :         const basegfx::B2DRange& rRange,
     219             :         bool bAddOffsetToMapping)
     220             :     :   mrOutDev(rOutDev),
     221             :         mpContent(0),
     222             :         mpMask(0),
     223        5536 :         mpAlpha(0)
     224             :     {
     225        5536 :         basegfx::B2DRange aRangePixel(rRange);
     226        5536 :         aRangePixel.transform(mrOutDev.GetViewTransformation());
     227             :         const Rectangle aRectPixel(
     228       11072 :             (sal_Int32)floor(aRangePixel.getMinX()), (sal_Int32)floor(aRangePixel.getMinY()),
     229       16608 :             (sal_Int32)ceil(aRangePixel.getMaxX()), (sal_Int32)ceil(aRangePixel.getMaxY()));
     230        5536 :         const Point aEmptyPoint;
     231        5536 :         maDestPixel = Rectangle(aEmptyPoint, mrOutDev.GetOutputSizePixel());
     232        5536 :         maDestPixel.Intersection(aRectPixel);
     233             : 
     234        5536 :         if(isVisible())
     235             :         {
     236             : #ifdef IOS
     237             :             // Exact mechanism unknown, but for some reason SmartArt
     238             :             // rendering, especially shadows, is broken on iOS unless
     239             :             // we pass 'true' here. Are virtual devices always de
     240             :             // facto cleared when created on other platforms?
     241             :             mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 0);
     242             : #else
     243        5444 :             mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, 0);
     244             : #endif
     245             : 
     246             :             // #i93485# assert when copying from window to VDev is used
     247             :             OSL_ENSURE(mrOutDev.GetOutDevType() != OUTDEV_WINDOW,
     248             :                 "impBufferDevice render helper: Copying from Window to VDev, this should be avoided (!)");
     249             : 
     250        5444 :             const bool bWasEnabledSrc(mrOutDev.IsMapModeEnabled());
     251        5444 :             mrOutDev.EnableMapMode(false);
     252        5444 :             mpContent->DrawOutDev(aEmptyPoint, maDestPixel.GetSize(), maDestPixel.TopLeft(), maDestPixel.GetSize(), mrOutDev);
     253        5444 :             mrOutDev.EnableMapMode(bWasEnabledSrc);
     254             : 
     255        5444 :             MapMode aNewMapMode(mrOutDev.GetMapMode());
     256             : 
     257        5444 :             if(bAddOffsetToMapping)
     258             :             {
     259        5444 :                 const Point aLogicTopLeft(mrOutDev.PixelToLogic(maDestPixel.TopLeft()));
     260        5444 :                 aNewMapMode.SetOrigin(Point(-aLogicTopLeft.X(), -aLogicTopLeft.Y()));
     261             :             }
     262             : 
     263        5444 :             mpContent->SetMapMode(aNewMapMode);
     264             : 
     265             :             // copy AA flag for new target
     266        5444 :             mpContent->SetAntialiasing(mrOutDev.GetAntialiasing());
     267             :         }
     268        5536 :     }
     269             : 
     270        5536 :     impBufferDevice::~impBufferDevice()
     271             :     {
     272        5536 :         if(mpContent)
     273             :         {
     274        5444 :             getVDevBuffer().free(*mpContent);
     275             :         }
     276             : 
     277        5536 :         if(mpMask)
     278             :         {
     279        3811 :             getVDevBuffer().free(*mpMask);
     280             :         }
     281             : 
     282        5536 :         if(mpAlpha)
     283             :         {
     284        1021 :             getVDevBuffer().free(*mpAlpha);
     285             :         }
     286        5536 :     }
     287             : 
     288        5444 :     void impBufferDevice::paint(double fTrans)
     289             :     {
     290        5444 :         if(isVisible())
     291             :         {
     292        5444 :             const Point aEmptyPoint;
     293        5444 :             const Size aSizePixel(maDestPixel.GetSize());
     294        5444 :             const bool bWasEnabledDst(mrOutDev.IsMapModeEnabled());
     295             :             static bool bDoSaveForVisualControl(false);
     296             : 
     297        5444 :             mrOutDev.EnableMapMode(false);
     298        5444 :             mpContent->EnableMapMode(false);
     299        5444 :             Bitmap aContent(mpContent->GetBitmap(aEmptyPoint, aSizePixel));
     300             : 
     301        5444 :             if(bDoSaveForVisualControl)
     302             :             {
     303           0 :                 SvFileStream aNew( "c:\\content.bmp", STREAM_WRITE|STREAM_TRUNC);
     304           0 :                 WriteDIB(aContent, aNew, false, true);
     305             :             }
     306             : 
     307        5444 :             if(mpAlpha)
     308             :             {
     309        1021 :                 mpAlpha->EnableMapMode(false);
     310        1021 :                 const AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel));
     311             : 
     312        1021 :                 if(bDoSaveForVisualControl)
     313             :                 {
     314           0 :                     SvFileStream aNew( "c:\\transparence.bmp", STREAM_WRITE|STREAM_TRUNC);
     315           0 :                     WriteDIB(aAlphaMask.GetBitmap(), aNew, false, true);
     316             :                 }
     317             : 
     318        1021 :                 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
     319             :             }
     320        4423 :             else if(mpMask)
     321             :             {
     322        3811 :                 mpMask->EnableMapMode(false);
     323        3811 :                 const Bitmap aMask(mpMask->GetBitmap(aEmptyPoint, aSizePixel));
     324             : 
     325        3811 :                 if(bDoSaveForVisualControl)
     326             :                 {
     327           0 :                     SvFileStream aNew( "c:\\mask.bmp", STREAM_WRITE|STREAM_TRUNC);
     328           0 :                     WriteDIB(aMask, aNew, false, true);
     329             :                 }
     330             : 
     331        3811 :                 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask));
     332             :             }
     333         612 :             else if(0.0 != fTrans)
     334             :             {
     335         612 :                 sal_uInt8 nMaskValue((sal_uInt8)basegfx::fround(fTrans * 255.0));
     336         612 :                 const AlphaMask aAlphaMask(aSizePixel, &nMaskValue);
     337         612 :                 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
     338             :             }
     339             :             else
     340             :             {
     341           0 :                 mrOutDev.DrawBitmap(maDestPixel.TopLeft(), aContent);
     342             :             }
     343             : 
     344        5444 :             mrOutDev.EnableMapMode(bWasEnabledDst);
     345             :         }
     346        5444 :     }
     347             : 
     348        5444 :     VirtualDevice& impBufferDevice::getContent()
     349             :     {
     350             :         OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
     351        5444 :         return *mpContent;
     352             :     }
     353             : 
     354        3811 :     VirtualDevice& impBufferDevice::getMask()
     355             :     {
     356             :         OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
     357        3811 :         if(!mpMask)
     358             :         {
     359        3811 :             mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 1);
     360        3811 :             mpMask->SetMapMode(mpContent->GetMapMode());
     361             : 
     362             :             // do NOT copy AA flag for mask!
     363             :         }
     364             : 
     365        3811 :         return *mpMask;
     366             :     }
     367             : 
     368        1021 :     VirtualDevice& impBufferDevice::getTransparence()
     369             :     {
     370             :         OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
     371        1021 :         if(!mpAlpha)
     372             :         {
     373        1021 :             mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 8);
     374        1021 :             mpAlpha->SetMapMode(mpContent->GetMapMode());
     375             : 
     376             :             // copy AA flag for new target; masking needs to be smooth
     377        1021 :             mpAlpha->SetAntialiasing(mpContent->GetAntialiasing());
     378             :         }
     379             : 
     380        1021 :         return *mpAlpha;
     381             :     }
     382             : } // end of namespace drawinglayer
     383             : 
     384             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10