LCOV - code coverage report
Current view: top level - include/basebmp - clippedlinerenderer.hxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 159 165 96.4 %
Date: 2015-06-13 12:38:46 Functions: 9 33 27.3 %
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             : #ifndef INCLUDED_BASEBMP_CLIPPEDLINERENDERER_HXX
      21             : #define INCLUDED_BASEBMP_CLIPPEDLINERENDERER_HXX
      22             : 
      23             : #include <basegfx/tools/rectcliptools.hxx>
      24             : #include <basegfx/point/b2ipoint.hxx>
      25             : #include <basegfx/range/b2ibox.hxx>
      26             : 
      27             : #include <vigra/diff2d.hxx>
      28             : #include <vigra/iteratortraits.hxx>
      29             : 
      30             : namespace basebmp
      31             : {
      32             : 
      33             : // factored-out bresenham setup code, which is used from two different
      34             : // places in renderClippedLine() below. Admittedly messy for the long
      35             : // parameter list...
      36     4642123 : inline bool prepareClip( sal_Int32  a1,
      37             :                          sal_Int32  a2,
      38             :                          sal_Int32  b1,
      39             :                          sal_Int32  da,
      40             :                          sal_Int32  db,
      41             :                          sal_Int32& o_as,
      42             :                          sal_Int32& o_bs,
      43             :                          int        sa,
      44             :                          int        sb,
      45             :                          sal_Int32& io_rem,
      46             :                          int&       o_n,
      47             :                          sal_uInt32 clipCode1,
      48             :                          sal_uInt32 clipCount1,
      49             :                          sal_uInt32 clipCode2,
      50             :                          sal_uInt32 clipCount2,
      51             :                          sal_Int32  aMin,
      52             :                          sal_uInt32 aMinFlag,
      53             :                          sal_Int32  aMax,
      54             :                          sal_uInt32 aMaxFlag,
      55             :                          sal_Int32  bMin,
      56             :                          sal_uInt32 bMinFlag,
      57             :                          sal_Int32  bMax,
      58             :                          sal_uInt32 bMaxFlag,
      59             :                          bool       bRoundTowardsPt2,
      60             :                          bool&      o_bUseAlternateBresenham )
      61             : {
      62     4642123 :     int ca(0), cb(0);
      63     4642123 :     if( clipCode1 )
      64             :     {
      65        1434 :         if( clipCode1 & aMinFlag )
      66             :         {
      67        1247 :             ca = 2*db*(aMin - a1);
      68        1247 :             o_as = aMin;
      69             :         }
      70         187 :         else if( clipCode1 & aMaxFlag )
      71             :         {
      72         159 :             ca = 2*db*(a1 - aMax);
      73         159 :             o_as = aMax;
      74             :         }
      75             : 
      76        1434 :         if( clipCode1 & bMinFlag )
      77             :         {
      78          30 :             cb = 2*da*(bMin - b1);
      79          30 :             o_bs = bMin;
      80             :         }
      81        1404 :         else if( clipCode1 & bMaxFlag )
      82             :         {
      83           0 :             cb = 2*da*(b1 - bMax);
      84           0 :             o_bs = bMax;
      85             :         }
      86             : 
      87        1434 :         if( clipCount1 == 2 )
      88           2 :             clipCode1 &= (ca + da < cb + int(!bRoundTowardsPt2)) ? ~(aMinFlag|aMaxFlag) : ~(bMinFlag|bMaxFlag);
      89             : 
      90        1434 :         if( clipCode1 & (aMinFlag|aMaxFlag) )
      91             :         {
      92        1404 :             sal_Int32 da2 = 2*da;
      93             : 
      94        1404 :             if (da2 == 0)
      95           0 :                 return false; // overflow
      96             : 
      97        1404 :             cb = (ca + da - int(!bRoundTowardsPt2)) / (da2);
      98             : 
      99        1404 :             if( sb >= 0 )
     100             :             {
     101        1355 :                 o_bs = b1 + cb;
     102        1355 :                 if( o_bs > bMax )
     103         107 :                     return false; // fully clipped
     104             :             }
     105             :             else
     106             :             {
     107          49 :                 o_bs = b1 - cb;
     108          49 :                 if( o_bs < bMin )
     109           4 :                     return false; // fully clipped
     110             :             }
     111             : 
     112        1293 :             io_rem += ca - da2*cb;
     113             :         }
     114             :         else
     115             :         {
     116          30 :             sal_Int32 db2 = 2*db;
     117             : 
     118          30 :             if (db2 == 0)
     119           0 :                 return false; // overflow
     120             : 
     121          30 :             ca = (cb - da + db2 - int(bRoundTowardsPt2)) / (db2);
     122          30 :             if( sa >= 0 )
     123             :             {
     124           4 :                 o_as = a1 + ca;
     125           4 :                 if( o_as > aMax )
     126           2 :                     return false; // fully clipped
     127             :             }
     128             :             else
     129             :             {
     130          26 :                 o_as = a1 - ca;
     131          26 :                 if( o_as < aMin )
     132          20 :                     return false; // fully clipped
     133             :             }
     134             : 
     135           8 :             io_rem += db2*ca - cb;
     136             :         }
     137             :     }
     138             :     else
     139             :     {
     140     4640689 :         o_as = a1; o_bs = b1;
     141             :     }
     142             : 
     143     4641990 :     if( clipCode2 )
     144             :     {
     145      101819 :         if( clipCount2 == 2 )
     146             :         {
     147          16 :             ca = 2*db*((clipCode2 & aMinFlag) ? a1 - aMin : aMax - a1);
     148          16 :             cb = 2*da*((clipCode2 & bMinFlag) ? b1 - bMin : bMax - b1);
     149          16 :             clipCode2 &= (cb + da < ca + int(bRoundTowardsPt2)) ? ~(aMinFlag|aMaxFlag) : ~(bMinFlag|bMaxFlag);
     150             :         }
     151             : 
     152      101819 :         if( clipCode2 & (aMinFlag|aMaxFlag) )
     153       99965 :             o_n = (clipCode2 & aMinFlag) ? o_as - aMin : aMax - o_as;
     154             :         else
     155             :         {
     156        1854 :             o_n = (clipCode2 & bMinFlag) ? o_bs - bMin : bMax - o_bs;
     157        1854 :             o_bUseAlternateBresenham = true;
     158             :         }
     159             :     }
     160             :     else
     161     4540171 :         o_n = (a2 >= o_as) ? a2 - o_as : o_as - a2;
     162             : 
     163     4641990 :     return true; // at least one pixel to render
     164             : }
     165             : 
     166             : 
     167             : /** Render line to image iterators, clip against given rectangle
     168             : 
     169             :     This method renders a line from aPt1 to aPt2, clipped against
     170             :     rClipRect (the clipping will take place pixel-perfect, i.e. as if
     171             :     the original bresenham-rendered line would have been clipped each
     172             :     pixel individually. No slight shifts compared to unclipped lines).
     173             : 
     174             :     @param aPt1
     175             :     Start point of the line
     176             : 
     177             :     @param aPt2
     178             :     End point of the line
     179             : 
     180             :     @param rClipRect
     181             :     Rectangle to clip against
     182             : 
     183             :     @param color
     184             :     Color value to render the line with
     185             : 
     186             :     @param begin
     187             :     left-top image iterator
     188             : 
     189             :     @param end
     190             :     right-bottom image iterator
     191             : 
     192             :     @param acc
     193             :     Image accessor
     194             : 
     195             :     @param bRoundTowardsPt2
     196             :     Rounding mode to use. Giving false here results in line pixel tend
     197             :     towards pt1, i.e. when a pixel exactly hits the middle between two
     198             :     pixel, the pixel closer to pt1 will be chosen. Giving true here
     199             :     makes renderClippedLine() choose pt2 in those cases.
     200             :  */
     201             : template< class Iterator, class Accessor >
     202     4988816 : void renderClippedLine( basegfx::B2IPoint             aPt1,
     203             :                         basegfx::B2IPoint             aPt2,
     204             :                         const basegfx::B2IBox&        rClipRect,
     205             :                         typename Accessor::value_type color,
     206             :                         Iterator                      begin,
     207             :                         Accessor                      acc,
     208             :                         bool                          bRoundTowardsPt2=false )
     209             : {
     210             :     // Algorithm according to Steven Eker's 'Pixel-perfect line clipping',
     211             :     // Graphics Gems V, pp. 314-322
     212             :     sal_uInt32 clipCode1 = basegfx::tools::getCohenSutherlandClipFlags(aPt1,
     213     4988816 :                                                                        rClipRect);
     214             :     sal_uInt32 clipCode2 = basegfx::tools::getCohenSutherlandClipFlags(aPt2,
     215     4988816 :                                                                        rClipRect);
     216             : 
     217     4988816 :     if( clipCode1 & clipCode2 )
     218      693519 :         return; // line fully clipped away, both endpoints share a half-plane
     219             : 
     220     4642123 :     sal_uInt32 clipCount1 = basegfx::tools::getNumberOfClipPlanes(clipCode1);
     221     4642123 :     sal_uInt32 clipCount2 = basegfx::tools::getNumberOfClipPlanes(clipCode2);
     222             : 
     223     4642123 :     if( (clipCode1 != 0 && clipCode2 == 0)
     224             :         || (clipCount1 == 2 && clipCount2 == 1) )
     225             :     {
     226       23262 :         std::swap(clipCount2,clipCount1);
     227       23262 :         std::swap(clipCode2,clipCode1);
     228       23262 :         std::swap(aPt1,aPt2);
     229       23262 :         bRoundTowardsPt2 = !bRoundTowardsPt2;
     230             :     }
     231             : 
     232     4642123 :     const sal_Int32 x1 = aPt1.getX();
     233     4642123 :     const sal_Int32 x2 = aPt2.getX();
     234     4642123 :     const sal_Int32 y1 = aPt1.getY();
     235     4642123 :     const sal_Int32 y2 = aPt2.getY();
     236             : 
     237             :     // TODO(E1): This might overflow
     238     4642123 :     sal_Int32 adx = x2 - x1;
     239     4642123 :     int sx = 1;
     240     4642123 :     if( adx < 0 )
     241             :     {
     242      160250 :         adx *= -1;
     243      160250 :         sx = -1;
     244             :     }
     245             : 
     246             :     // TODO(E1): This might overflow
     247     4642123 :     sal_Int32 ady = y2 - y1;
     248     4642123 :     int sy = 1;
     249     4642123 :     if( ady < 0 )
     250             :     {
     251      875373 :         ady *= -1;
     252      875373 :         sy = -1;
     253             :     }
     254             : 
     255     4642123 :     int n  = 0;
     256     4642123 :     sal_Int32 xs = x1;
     257     4642123 :     sal_Int32 ys = y1;
     258     4642123 :     bool bUseAlternateBresenham=false;
     259             : 
     260     4642123 :     sal_Int32 nMinY(rClipRect.getMinY());
     261     4642123 :     sal_Int32 nMaxY(rClipRect.getMaxY()-1);
     262     4642123 :     sal_Int32 nMinX(rClipRect.getMinX());
     263     4642123 :     sal_Int32 nMaxX(rClipRect.getMaxX()-1);
     264             : 
     265     4642123 :     if( adx >= ady )
     266             :     {
     267             :         // semi-horizontal line
     268     2556685 :         sal_Int32 rem = 2*ady - adx - int(!bRoundTowardsPt2);
     269             : 
     270     2556685 :         if( !prepareClip(x1, x2, y1, adx, ady, xs, ys, sx, sy,
     271             :                          rem, n, clipCode1, clipCount1, clipCode2, clipCount2,
     272             :                          nMinX, basegfx::tools::RectClipFlags::LEFT,
     273             :                          nMaxX, basegfx::tools::RectClipFlags::RIGHT,
     274             :                          nMinY, basegfx::tools::RectClipFlags::TOP,
     275             :                          nMaxY, basegfx::tools::RectClipFlags::BOTTOM,
     276     2556685 :                          bRoundTowardsPt2, bUseAlternateBresenham ) )
     277          20 :             return; // line fully clipped away, no active pixel inside rect
     278             : 
     279     2556675 :         Iterator currIter( begin + vigra::Diff2D(0,ys) );
     280             :         typename vigra::IteratorTraits<Iterator>::row_iterator
     281     2610760 :             rowIter( currIter.rowIterator() + xs );
     282             : 
     283     2556675 :         adx *= 2;
     284     2556675 :         ady *= 2;
     285             : 
     286    76366951 :         if( bUseAlternateBresenham )
     287             :         {
     288        1808 :             if (rem < 0 && ady <= 0)
     289           0 :                 return; //break will never be hit under these circumstances
     290             : 
     291             :             while(true)
     292             :             {
     293        2290 :                 if (xs >= nMinX && xs <= nMaxX && ys >= nMinY && ys <= nMaxY)
     294        2290 :                     acc.set(color, rowIter);
     295             : 
     296        2290 :                 if( rem >= 0 )
     297             :                 {
     298             :                     // this is intended - we clip endpoint against y
     299             :                     // plane, so n here denotes y range to render
     300        2186 :                     if( --n < 0 )
     301        1808 :                         break;
     302             : 
     303         378 :                     ys += sy;
     304         378 :                     xs += sx;
     305         378 :                     rem -= adx;
     306             : 
     307         378 :                     currIter.y += sy;
     308         378 :                     rowIter = currIter.rowIterator() + xs;
     309             :                 }
     310             :                 else
     311             :                 {
     312         104 :                     xs += sx;
     313         104 :                     rowIter += sx;
     314             :                 }
     315             : 
     316         482 :                 rem += ady;
     317             :             }
     318             :         }
     319             :         else
     320             :         {
     321             :             while(true)
     322             :             {
     323    76364661 :                 if (xs >= nMinX && xs <= nMaxX && ys >= nMinY && ys <= nMaxY)
     324    76364661 :                     acc.set(color, rowIter);
     325             : 
     326    76364661 :                 if( --n < 0 )
     327     2554867 :                     break;
     328             : 
     329    73809794 :                 if( rem >= 0 )
     330             :                 {
     331      180248 :                     ys += sy;
     332      180248 :                     xs += sx;
     333      180248 :                     rem -= adx;
     334             : 
     335      180248 :                     currIter.y += sy;
     336      180248 :                     rowIter = currIter.rowIterator() + xs;
     337             :                 }
     338             :                 else
     339             :                 {
     340    73629546 :                     xs += sx;
     341    73629546 :                     rowIter += sx;
     342             :                 }
     343             : 
     344    73809794 :                 rem += ady;
     345             :             }
     346       54085 :         }
     347             :     }
     348             :     else
     349             :     {
     350             :         // semi-vertical line
     351     2085438 :         sal_Int32 rem = 2*adx - ady - int(!bRoundTowardsPt2);
     352             : 
     353     2085438 :         if( !prepareClip(y1, y2, x1, ady, adx, ys, xs, sy, sx,
     354             :                          rem, n, clipCode1, clipCount1, clipCode2, clipCount2,
     355             :                          nMinY, basegfx::tools::RectClipFlags::TOP,
     356             :                          nMaxY, basegfx::tools::RectClipFlags::BOTTOM,
     357             :                          nMinX, basegfx::tools::RectClipFlags::LEFT,
     358             :                          nMaxY, basegfx::tools::RectClipFlags::RIGHT,
     359     2085438 :                          bRoundTowardsPt2, bUseAlternateBresenham ) )
     360         246 :             return; // line fully clipped away, no active pixel inside rect
     361             : 
     362     2085315 :         Iterator currIter( begin + vigra::Diff2D(xs,0) );
     363             :         typename vigra::IteratorTraits<Iterator>::column_iterator
     364     2134368 :             colIter( currIter.columnIterator() + ys );
     365             : 
     366     2085315 :         adx *= 2;
     367     2085315 :         ady *= 2;
     368             : 
     369    47081919 :         if( bUseAlternateBresenham )
     370             :         {
     371          46 :             if (rem < 0 && adx <= 0)
     372           0 :                 return; //break will never be hit under these circumstances
     373             : 
     374             :             while(true)
     375             :             {
     376        1644 :                 if (xs >= nMinX && xs <= nMaxX && ys >= nMinY && ys <= nMaxY)
     377         500 :                     acc.set(color, colIter);
     378             : 
     379        1644 :                 if( rem >= 0 )
     380             :                 {
     381             :                     // this is intended - we clip endpoint against x
     382             :                     // plane, so n here denotes x range to render
     383        1050 :                     if( --n < 0 )
     384          46 :                         break;
     385             : 
     386        1004 :                     xs += sx;
     387        1004 :                     ys += sy;
     388             : 
     389        1004 :                     rem -= ady;
     390             : 
     391        1004 :                     currIter.x += sx;
     392        1004 :                     colIter = currIter.columnIterator() + ys;
     393             :                 }
     394             :                 else
     395             :                 {
     396         594 :                     ys += sy;
     397         594 :                     colIter += sy;
     398             :                 }
     399             : 
     400        1598 :                 rem += adx;
     401             :             }
     402             :         }
     403             :         else
     404             :         {
     405             :             while(true)
     406             :             {
     407    47080275 :                 if (xs >= nMinX && xs <= nMaxX && ys >= nMinY && ys <= nMaxY)
     408    47080273 :                     acc.set(color, colIter);
     409             : 
     410    47080275 :                 if( --n < 0 )
     411     2085269 :                     break;
     412             : 
     413    44995006 :                 if( rem >= 0 )
     414             :                 {
     415      224384 :                     xs += sx;
     416      224384 :                     ys += sy;
     417      224384 :                     rem -= ady;
     418             : 
     419      224384 :                     currIter.x += sx;
     420      224384 :                     colIter = currIter.columnIterator() + ys;
     421             :                 }
     422             :                 else
     423             :                 {
     424    44770622 :                     ys += sy;
     425    44770622 :                     colIter += sy;
     426             :                 }
     427             : 
     428    44995006 :                 rem += adx;
     429             :             }
     430       49053 :         }
     431             :     }
     432             : }
     433             : 
     434             : } // namespace basebmp
     435             : 
     436             : #endif /* INCLUDED_BASEBMP_CLIPPEDLINERENDERER_HXX */
     437             : 
     438             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11