LCOV - code coverage report
Current view: top level - vcl/source/outdev - polygon.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 135 225 60.0 %
Date: 2015-06-13 12:38:46 Functions: 9 10 90.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             : #include <sal/types.h>
      20             : 
      21             : #include <basegfx/matrix/b2dhommatrix.hxx>
      22             : #include <basegfx/polygon/b2dpolygontools.hxx>
      23             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      24             : #include <boost/scoped_array.hpp>
      25             : #include <tools/poly.hxx>
      26             : #include <vcl/outdev.hxx>
      27             : #include <vcl/virdev.hxx>
      28             : #include <vcl/window.hxx>
      29             : 
      30             : #include "salgdi.hxx"
      31             : 
      32             : #define OUTDEV_POLYPOLY_STACKBUF        32
      33             : 
      34      326484 : void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon& rPolyPoly )
      35             : {
      36      326484 :     assert_if_double_buffered_window();
      37             : 
      38      326484 :     if( mpMetaFile )
      39           5 :         mpMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) );
      40             : 
      41      326484 :     sal_uInt16 nPoly = rPolyPoly.Count();
      42             : 
      43      326484 :     if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || !nPoly || ImplIsRecordLayout() )
      44           5 :         return;
      45             : 
      46             :     // we need a graphics
      47      326479 :     if ( !mpGraphics && !AcquireGraphics() )
      48           0 :             return;
      49             : 
      50      326479 :     if ( mbInitClipRegion )
      51         632 :         InitClipRegion();
      52             : 
      53      326479 :     if ( mbOutputClipped )
      54           0 :         return;
      55             : 
      56      326479 :     if ( mbInitLineColor )
      57        5840 :         InitLineColor();
      58             : 
      59      326479 :     if ( mbInitFillColor )
      60        9180 :         InitFillColor();
      61             : 
      62             :     // use b2dpolygon drawing if possible
      63      652976 :     if((mnAntialiasing & AntialiasingFlags::EnableB2dDraw) &&
      64      326497 :        mpGraphics->supportsOperation(OutDevSupport_B2DDraw) &&
      65      979437 :        ROP_OVERPAINT == GetRasterOp() &&
      66           0 :        (IsLineColor() || IsFillColor()))
      67             :     {
      68           0 :         const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
      69           0 :         basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPoly.getB2DPolyPolygon());
      70           0 :         bool bSuccess(true);
      71             : 
      72             :         // transform the polygon and ensure closed
      73           0 :         aB2DPolyPolygon.transform(aTransform);
      74           0 :         aB2DPolyPolygon.setClosed(true);
      75             : 
      76           0 :         if(IsFillColor())
      77             :         {
      78           0 :             bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this);
      79             :         }
      80             : 
      81           0 :         if(bSuccess && IsLineColor())
      82             :         {
      83           0 :             const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
      84             : 
      85           0 :             if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline)
      86             :             {
      87           0 :                 aB2DPolyPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon);
      88             :             }
      89             : 
      90           0 :             for(sal_uInt32 a(0); bSuccess && a < aB2DPolyPolygon.count(); a++)
      91             :             {
      92             :                 bSuccess = mpGraphics->DrawPolyLine( aB2DPolyPolygon.getB2DPolygon(a),
      93             :                                                      0.0,
      94             :                                                      aB2DLineWidth,
      95             :                                                      basegfx::B2DLineJoin::NONE,
      96             :                                                      css::drawing::LineCap_BUTT,
      97           0 :                                                      this);
      98           0 :             }
      99             :         }
     100             : 
     101           0 :         if(bSuccess)
     102             :         {
     103           0 :             return;
     104           0 :         }
     105             :     }
     106             : 
     107      326479 :     if ( nPoly == 1 )
     108             :     {
     109             :         // #100127# Map to DrawPolygon
     110      323382 :         Polygon aPoly = rPolyPoly.GetObject( 0 );
     111      323382 :         if( aPoly.GetSize() >= 2 )
     112             :         {
     113      323382 :             GDIMetaFile* pOldMF = mpMetaFile;
     114      323382 :             mpMetaFile = NULL;
     115             : 
     116      323382 :             DrawPolygon( aPoly );
     117             : 
     118      323382 :             mpMetaFile = pOldMF;
     119      323382 :         }
     120             :     }
     121             :     else
     122             :     {
     123             :         // #100127# moved real tools::PolyPolygon draw to separate method,
     124             :         // have to call recursively, avoiding duplicate
     125             :         // ImplLogicToDevicePixel calls
     126        3097 :         ImplDrawPolyPolygon( nPoly, ImplLogicToDevicePixel( rPolyPoly ) );
     127             :     }
     128      326479 :     if( mpAlphaVDev )
     129        5656 :         mpAlphaVDev->DrawPolyPolygon( rPolyPoly );
     130             : }
     131             : 
     132        1011 : void OutputDevice::DrawPolygon( const basegfx::B2DPolygon& rB2DPolygon)
     133             : {
     134        1011 :     assert_if_double_buffered_window();
     135             : 
     136             :     // AW: Do NOT paint empty polygons
     137        1011 :     if(rB2DPolygon.count())
     138             :     {
     139        1011 :         basegfx::B2DPolyPolygon aPP( rB2DPolygon );
     140        1011 :         DrawPolyPolygon( aPP );
     141             :     }
     142        1011 : }
     143             : 
     144      337036 : void OutputDevice::DrawPolygon( const Polygon& rPoly )
     145             : {
     146      337036 :     assert_if_double_buffered_window();
     147             : 
     148      337036 :     if( mpMetaFile )
     149           6 :         mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) );
     150             : 
     151      337036 :     sal_uInt16 nPoints = rPoly.GetSize();
     152             : 
     153      337036 :     if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || (nPoints < 2) || ImplIsRecordLayout() )
     154           0 :         return;
     155             : 
     156             :     // we need a graphics
     157      337036 :     if ( !mpGraphics && !AcquireGraphics() )
     158           0 :         return;
     159             : 
     160      337036 :     if ( mbInitClipRegion )
     161         436 :         InitClipRegion();
     162             : 
     163      337036 :     if ( mbOutputClipped )
     164           0 :         return;
     165             : 
     166      337036 :     if ( mbInitLineColor )
     167        7821 :         InitLineColor();
     168             : 
     169      337036 :     if ( mbInitFillColor )
     170        7636 :         InitFillColor();
     171             : 
     172             :     // use b2dpolygon drawing if possible
     173      680566 :     if((mnAntialiasing & AntialiasingFlags::EnableB2dDraw) &&
     174      343530 :        mpGraphics->supportsOperation(OutDevSupport_B2DDraw) &&
     175     1011108 :        ROP_OVERPAINT == GetRasterOp() &&
     176           0 :        (IsLineColor() || IsFillColor()))
     177             :     {
     178           0 :         const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
     179           0 :         basegfx::B2DPolygon aB2DPolygon(rPoly.getB2DPolygon());
     180           0 :         bool bSuccess(true);
     181             : 
     182             :         // transform the polygon and ensure closed
     183           0 :         aB2DPolygon.transform(aTransform);
     184           0 :         aB2DPolygon.setClosed(true);
     185             : 
     186           0 :         if(IsFillColor())
     187             :         {
     188           0 :             bSuccess = mpGraphics->DrawPolyPolygon(basegfx::B2DPolyPolygon(aB2DPolygon), 0.0, this);
     189             :         }
     190             : 
     191           0 :         if(bSuccess && IsLineColor())
     192             :         {
     193           0 :             const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
     194             : 
     195           0 :             if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline)
     196             :             {
     197           0 :                 aB2DPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon);
     198             :             }
     199             : 
     200             :             bSuccess = mpGraphics->DrawPolyLine( aB2DPolygon,
     201             :                                                  0.0,
     202             :                                                  aB2DLineWidth,
     203             :                                                  basegfx::B2DLineJoin::NONE,
     204             :                                                  css::drawing::LineCap_BUTT,
     205           0 :                                                  this);
     206             :         }
     207             : 
     208           0 :         if(bSuccess)
     209             :         {
     210           0 :             return;
     211           0 :         }
     212             :     }
     213             : 
     214      337036 :     Polygon aPoly = ImplLogicToDevicePixel( rPoly );
     215      337036 :     const SalPoint* pPtAry = reinterpret_cast<const SalPoint*>(aPoly.GetConstPointAry());
     216             : 
     217             :     // #100127# Forward beziers to sal, if any
     218      337036 :     if( aPoly.HasFlags() )
     219             :     {
     220        4409 :         const sal_uInt8* pFlgAry = aPoly.GetConstFlagAry();
     221        4409 :         if( !mpGraphics->DrawPolygonBezier( nPoints, pPtAry, pFlgAry, this ) )
     222             :         {
     223        4409 :             aPoly = Polygon::SubdivideBezier(aPoly);
     224        4409 :             pPtAry = reinterpret_cast<const SalPoint*>(aPoly.GetConstPointAry());
     225        4409 :             mpGraphics->DrawPolygon( aPoly.GetSize(), pPtAry, this );
     226             :         }
     227             :     }
     228             :     else
     229             :     {
     230      332627 :         mpGraphics->DrawPolygon( nPoints, pPtAry, this );
     231             :     }
     232      337036 :     if( mpAlphaVDev )
     233        5656 :         mpAlphaVDev->DrawPolygon( rPoly );
     234             : }
     235             : 
     236             : // Caution: This method is nearly the same as
     237             : // OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency),
     238             : // so when changes are made here do not forget to make changes there, too
     239             : 
     240       51158 : void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly )
     241             : {
     242       51158 :     assert_if_double_buffered_window();
     243             : 
     244       51158 :     if( mpMetaFile )
     245        1849 :         mpMetaFile->AddAction( new MetaPolyPolygonAction( tools::PolyPolygon( rB2DPolyPoly ) ) );
     246             : 
     247             :     // call helper
     248       51158 :     ImplDrawPolyPolygonWithB2DPolyPolygon(rB2DPolyPoly);
     249       51158 : }
     250             : 
     251       51158 : void OutputDevice::ImplDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyPolygon& rB2DPolyPoly)
     252             : {
     253             :     // Do not paint empty PolyPolygons
     254       51158 :     if(!rB2DPolyPoly.count() || !IsDeviceOutputNecessary())
     255        3698 :         return;
     256             : 
     257             :     // we need a graphics
     258       49309 :     if( !mpGraphics && !AcquireGraphics() )
     259           0 :         return;
     260             : 
     261       49309 :     if( mbInitClipRegion )
     262           9 :         InitClipRegion();
     263             : 
     264       49309 :     if( mbOutputClipped )
     265           0 :         return;
     266             : 
     267       49309 :     if( mbInitLineColor )
     268         318 :         InitLineColor();
     269             : 
     270       49309 :     if( mbInitFillColor )
     271       45446 :         InitFillColor();
     272             : 
     273       98618 :     if((mnAntialiasing & AntialiasingFlags::EnableB2dDraw) &&
     274       49309 :        mpGraphics->supportsOperation(OutDevSupport_B2DDraw) &&
     275      147927 :        ROP_OVERPAINT == GetRasterOp() &&
     276           0 :        (IsLineColor() || IsFillColor()))
     277             :     {
     278           0 :         const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation());
     279           0 :         basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly);
     280           0 :         bool bSuccess(true);
     281             : 
     282             :         // transform the polygon and ensure closed
     283           0 :         aB2DPolyPolygon.transform(aTransform);
     284           0 :         aB2DPolyPolygon.setClosed(true);
     285             : 
     286           0 :         if(IsFillColor())
     287             :         {
     288           0 :             bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this);
     289             :         }
     290             : 
     291           0 :         if(bSuccess && IsLineColor())
     292             :         {
     293           0 :             const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
     294             : 
     295           0 :             if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline)
     296             :             {
     297           0 :                 aB2DPolyPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon);
     298             :             }
     299             : 
     300           0 :             for(sal_uInt32 a(0);bSuccess && a < aB2DPolyPolygon.count(); a++)
     301             :             {
     302             :                 bSuccess = mpGraphics->DrawPolyLine( aB2DPolyPolygon.getB2DPolygon(a),
     303             :                                                      0.0,
     304             :                                                      aB2DLineWidth,
     305             :                                                      basegfx::B2DLineJoin::NONE,
     306             :                                                      css::drawing::LineCap_BUTT,
     307           0 :                                                      this);
     308           0 :             }
     309             :         }
     310             : 
     311           0 :         if(bSuccess)
     312             :         {
     313           0 :             return;
     314           0 :         }
     315             :     }
     316             : 
     317             :     // fallback to old polygon drawing if needed
     318       49309 :     const tools::PolyPolygon aToolsPolyPolygon( rB2DPolyPoly );
     319       98618 :     const tools::PolyPolygon aPixelPolyPolygon = ImplLogicToDevicePixel( aToolsPolyPolygon );
     320       98618 :     ImplDrawPolyPolygon( aPixelPolyPolygon.Count(), aPixelPolyPolygon );
     321             : }
     322             : 
     323             : // #100127# Extracted from OutputDevice::DrawPolyPolygon()
     324       55258 : void OutputDevice::ImplDrawPolyPolygon( sal_uInt16 nPoly, const tools::PolyPolygon& rPolyPoly )
     325             : {
     326             :     // AW: This crashes on empty PolyPolygons, avoid that
     327       55258 :     if(!nPoly)
     328       55258 :         return;
     329             : 
     330             :     sal_uInt32 aStackAry1[OUTDEV_POLYPOLY_STACKBUF];
     331             :     PCONSTSALPOINT aStackAry2[OUTDEV_POLYPOLY_STACKBUF];
     332             :     sal_uInt8* aStackAry3[OUTDEV_POLYPOLY_STACKBUF];
     333             :     sal_uInt32* pPointAry;
     334             :     PCONSTSALPOINT*     pPointAryAry;
     335             :     const sal_uInt8** pFlagAryAry;
     336       55258 :     sal_uInt16 i = 0;
     337       55258 :     sal_uInt16 j = 0;
     338       55258 :     sal_uInt16 last = 0;
     339       55258 :     bool bHaveBezier = false;
     340       55258 :     if ( nPoly > OUTDEV_POLYPOLY_STACKBUF )
     341             :     {
     342         110 :         pPointAry       = new sal_uInt32[nPoly];
     343         110 :         pPointAryAry    = new PCONSTSALPOINT[nPoly];
     344         110 :         pFlagAryAry     = new const sal_uInt8*[nPoly];
     345             :     }
     346             :     else
     347             :     {
     348       55148 :         pPointAry       = aStackAry1;
     349       55148 :         pPointAryAry    = aStackAry2;
     350       55148 :         pFlagAryAry     = const_cast<const sal_uInt8**>(aStackAry3);
     351             :     }
     352             : 
     353       73457 :     do
     354             :     {
     355       73457 :         const Polygon& rPoly = rPolyPoly.GetObject( i );
     356       73457 :         sal_uInt16 nSize = rPoly.GetSize();
     357       73457 :         if ( nSize )
     358             :         {
     359       73457 :             pPointAry[j] = nSize;
     360       73457 :             pPointAryAry[j] = reinterpret_cast<PCONSTSALPOINT>(rPoly.GetConstPointAry());
     361       73457 :             pFlagAryAry[j] = rPoly.GetConstFlagAry();
     362       73457 :             last = i;
     363             : 
     364       73457 :             if( pFlagAryAry[j] )
     365       11922 :                 bHaveBezier = true;
     366             : 
     367       73457 :             ++j;
     368             :         }
     369       73457 :         ++i;
     370             :     }
     371             :     while ( i < nPoly );
     372             : 
     373       55258 :     if ( j == 1 )
     374             :     {
     375             :         // #100127# Forward beziers to sal, if any
     376       49016 :         if( bHaveBezier )
     377             :         {
     378        5131 :             if( !mpGraphics->DrawPolygonBezier( *pPointAry, *pPointAryAry, *pFlagAryAry, this ) )
     379             :             {
     380        5131 :                 Polygon aPoly = Polygon::SubdivideBezier( rPolyPoly.GetObject( last ) );
     381        5131 :                 mpGraphics->DrawPolygon( aPoly.GetSize(), reinterpret_cast<const SalPoint*>(aPoly.GetConstPointAry()), this );
     382             :             }
     383             :         }
     384             :         else
     385             :         {
     386       43885 :             mpGraphics->DrawPolygon( *pPointAry, *pPointAryAry, this );
     387             :         }
     388             :     }
     389             :     else
     390             :     {
     391             :         // #100127# Forward beziers to sal, if any
     392        6242 :         if( bHaveBezier )
     393             :         {
     394        2852 :             if( !mpGraphics->DrawPolyPolygonBezier( j, pPointAry, pPointAryAry, pFlagAryAry, this ) )
     395             :             {
     396        2852 :                 tools::PolyPolygon aPolyPoly = tools::PolyPolygon::SubdivideBezier( rPolyPoly );
     397        2852 :                 ImplDrawPolyPolygon( aPolyPoly.Count(), aPolyPoly );
     398             :             }
     399             :         }
     400             :         else
     401             :         {
     402        3390 :             mpGraphics->DrawPolyPolygon( j, pPointAry, pPointAryAry, this );
     403             :         }
     404             :     }
     405             : 
     406       55258 :     if ( pPointAry != aStackAry1 )
     407             :     {
     408         110 :         delete[] pPointAry;
     409         110 :         delete[] pPointAryAry;
     410         110 :         delete[] pFlagAryAry;
     411             :     }
     412             : }
     413             : 
     414     1374408 : void OutputDevice::ImplDrawPolygon( const Polygon& rPoly, const tools::PolyPolygon* pClipPolyPoly )
     415             : {
     416     1374408 :     if( pClipPolyPoly )
     417             :     {
     418           0 :         ImplDrawPolyPolygon( rPoly, pClipPolyPoly );
     419             :     }
     420             :     else
     421             :     {
     422     1374408 :         sal_uInt16 nPoints = rPoly.GetSize();
     423             : 
     424     1374408 :         if ( nPoints < 2 )
     425     1374408 :             return;
     426             : 
     427     1374408 :         const SalPoint* pPtAry = reinterpret_cast<const SalPoint*>(rPoly.GetConstPointAry());
     428     1374408 :         mpGraphics->DrawPolygon( nPoints, pPtAry, this );
     429             :     }
     430             : }
     431             : 
     432           0 : void OutputDevice::ImplDrawPolyPolygon( const tools::PolyPolygon& rPolyPoly, const tools::PolyPolygon* pClipPolyPoly )
     433             : {
     434             :     tools::PolyPolygon* pPolyPoly;
     435             : 
     436           0 :     if( pClipPolyPoly )
     437             :     {
     438           0 :         pPolyPoly = new tools::PolyPolygon;
     439           0 :         rPolyPoly.GetIntersection( *pClipPolyPoly, *pPolyPoly );
     440             :     }
     441             :     else
     442             :     {
     443           0 :         pPolyPoly = const_cast<tools::PolyPolygon*>(&rPolyPoly);
     444             :     }
     445           0 :     if( pPolyPoly->Count() == 1 )
     446             :     {
     447           0 :         const Polygon rPoly = pPolyPoly->GetObject( 0 );
     448           0 :         sal_uInt16 nSize = rPoly.GetSize();
     449             : 
     450           0 :         if( nSize >= 2 )
     451             :         {
     452           0 :             const SalPoint* pPtAry = reinterpret_cast<const SalPoint*>(rPoly.GetConstPointAry());
     453           0 :             mpGraphics->DrawPolygon( nSize, pPtAry, this );
     454           0 :         }
     455             :     }
     456           0 :     else if( pPolyPoly->Count() )
     457             :     {
     458           0 :         sal_uInt16 nCount = pPolyPoly->Count();
     459           0 :         boost::scoped_array<sal_uInt32> pPointAry(new sal_uInt32[nCount]);
     460           0 :         boost::scoped_array<PCONSTSALPOINT> pPointAryAry(new PCONSTSALPOINT[nCount]);
     461           0 :         sal_uInt16 i = 0;
     462           0 :         do
     463             :         {
     464           0 :             const Polygon& rPoly = pPolyPoly->GetObject( i );
     465           0 :             sal_uInt16 nSize = rPoly.GetSize();
     466           0 :             if ( nSize )
     467             :             {
     468           0 :                 pPointAry[i] = nSize;
     469           0 :                 pPointAryAry[i] = reinterpret_cast<PCONSTSALPOINT>(rPoly.GetConstPointAry());
     470           0 :                 i++;
     471             :             }
     472             :             else
     473           0 :                 nCount--;
     474             :         }
     475             :         while( i < nCount );
     476             : 
     477           0 :         if( nCount == 1 )
     478           0 :             mpGraphics->DrawPolygon( pPointAry[0], pPointAryAry[0], this );
     479             :         else
     480           0 :             mpGraphics->DrawPolyPolygon( nCount, pPointAry.get(), pPointAryAry.get(), this );
     481             :     }
     482             : 
     483           0 :     if( pClipPolyPoly )
     484           0 :         delete pPolyPoly;
     485         801 : }
     486             : 
     487             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11