LCOV - code coverage report
Current view: top level - vcl/source/outdev - hatch.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 161 214 75.2 %
Date: 2015-06-13 12:38:46 Functions: 8 8 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 <tools/line.hxx>
      21             : 
      22             : #include <vcl/hatch.hxx>
      23             : #include <vcl/salbtype.hxx>
      24             : #include <vcl/settings.hxx>
      25             : #include <vcl/outdev.hxx>
      26             : #include <vcl/virdev.hxx>
      27             : #include <vcl/window.hxx>
      28             : 
      29             : #include "../gdi/pdfwriter_impl.hxx"
      30             : 
      31             : #include <boost/scoped_array.hpp>
      32             : 
      33             : #define HATCH_MAXPOINTS             1024
      34             : 
      35       31792 : extern "C" int SAL_CALL HatchCmpFnc( const void* p1, const void* p2 )
      36             : {
      37       31792 :     const long nX1 = static_cast<Point const *>(p1)->X();
      38       31792 :     const long nX2 = static_cast<Point const *>(p2)->X();
      39       31792 :     const long nY1 = static_cast<Point const *>(p1)->Y();
      40       31792 :     const long nY2 = static_cast<Point const *>(p2)->Y();
      41             : 
      42       31792 :     return ( nX1 > nX2 ? 1 : nX1 == nX2 ? nY1 > nY2 ? 1: nY1 == nY2 ? 0 : -1 : -1 );
      43             : }
      44             : 
      45         585 : void OutputDevice::DrawHatch( const tools::PolyPolygon& rPolyPoly, const Hatch& rHatch )
      46             : {
      47         585 :     assert_if_double_buffered_window();
      48             : 
      49         585 :     Hatch aHatch( rHatch );
      50             : 
      51         585 :     if ( mnDrawMode & ( DrawModeFlags::BlackLine | DrawModeFlags::WhiteLine |
      52             :                         DrawModeFlags::GrayLine | DrawModeFlags::GhostedLine |
      53         585 :                         DrawModeFlags::SettingsLine ) )
      54             :     {
      55           0 :         Color aColor( rHatch.GetColor() );
      56             : 
      57           0 :         if ( mnDrawMode & DrawModeFlags::BlackLine )
      58           0 :             aColor = Color( COL_BLACK );
      59           0 :         else if ( mnDrawMode & DrawModeFlags::WhiteLine )
      60           0 :             aColor = Color( COL_WHITE );
      61           0 :         else if ( mnDrawMode & DrawModeFlags::GrayLine )
      62             :         {
      63           0 :             const sal_uInt8 cLum = aColor.GetLuminance();
      64           0 :             aColor = Color( cLum, cLum, cLum );
      65             :         }
      66           0 :         else if( mnDrawMode & DrawModeFlags::SettingsLine )
      67             :         {
      68           0 :             aColor = GetSettings().GetStyleSettings().GetFontColor();
      69             :         }
      70             : 
      71           0 :         if ( mnDrawMode & DrawModeFlags::GhostedLine )
      72             :         {
      73           0 :             aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
      74           0 :                             ( aColor.GetGreen() >> 1 ) | 0x80,
      75           0 :                             ( aColor.GetBlue() >> 1 ) | 0x80);
      76             :         }
      77             : 
      78           0 :         aHatch.SetColor( aColor );
      79             :     }
      80             : 
      81         585 :     if( mpMetaFile )
      82          15 :         mpMetaFile->AddAction( new MetaHatchAction( rPolyPoly, aHatch ) );
      83             : 
      84         585 :     if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
      85          15 :         return;
      86             : 
      87         570 :     if( !mpGraphics && !AcquireGraphics() )
      88           0 :         return;
      89             : 
      90         570 :     if( mbInitClipRegion )
      91           0 :         InitClipRegion();
      92             : 
      93         570 :     if( mbOutputClipped )
      94           0 :         return;
      95             : 
      96         570 :     if( rPolyPoly.Count() )
      97             :     {
      98         570 :         tools::PolyPolygon     aPolyPoly( LogicToPixel( rPolyPoly ) );
      99         570 :         GDIMetaFile*    pOldMetaFile = mpMetaFile;
     100         570 :         bool            bOldMap = mbMap;
     101             : 
     102         570 :         aPolyPoly.Optimize( PolyOptimizeFlags::NO_SAME );
     103         570 :         aHatch.SetDistance( ImplLogicWidthToDevicePixel( aHatch.GetDistance() ) );
     104             : 
     105         570 :         mpMetaFile = NULL;
     106         570 :         EnableMapMode( false );
     107         570 :         Push( PushFlags::LINECOLOR );
     108         570 :         SetLineColor( aHatch.GetColor() );
     109         570 :         InitLineColor();
     110         570 :         DrawHatch( aPolyPoly, aHatch, false );
     111         570 :         Pop();
     112         570 :         EnableMapMode( bOldMap );
     113         570 :         mpMetaFile = pOldMetaFile;
     114             :     }
     115             : 
     116         570 :     if( mpAlphaVDev )
     117           0 :         mpAlphaVDev->DrawHatch( rPolyPoly, rHatch );
     118             : }
     119             : 
     120          14 : void OutputDevice::AddHatchActions( const tools::PolyPolygon& rPolyPoly, const Hatch& rHatch,
     121             :                                     GDIMetaFile& rMtf )
     122             : {
     123             : 
     124          14 :     tools::PolyPolygon aPolyPoly( rPolyPoly );
     125          14 :     aPolyPoly.Optimize( PolyOptimizeFlags::NO_SAME | PolyOptimizeFlags::CLOSE );
     126             : 
     127          14 :     if( aPolyPoly.Count() )
     128             :     {
     129          14 :         GDIMetaFile* pOldMtf = mpMetaFile;
     130             : 
     131          14 :         mpMetaFile = &rMtf;
     132          14 :         mpMetaFile->AddAction( new MetaPushAction( PushFlags::ALL ) );
     133          14 :         mpMetaFile->AddAction( new MetaLineColorAction( rHatch.GetColor(), true ) );
     134          14 :         DrawHatch( aPolyPoly, rHatch, true );
     135          14 :         mpMetaFile->AddAction( new MetaPopAction() );
     136          14 :         mpMetaFile = pOldMtf;
     137          14 :     }
     138          14 : }
     139             : 
     140         584 : void OutputDevice::DrawHatch( const tools::PolyPolygon& rPolyPoly, const Hatch& rHatch, bool bMtf )
     141             : {
     142         584 :     assert_if_double_buffered_window();
     143             : 
     144         584 :     if(rPolyPoly.Count())
     145             :     {
     146             :         // #i115630# DrawHatch does not work with beziers included in the polypolygon, take care of that
     147         584 :         bool bIsCurve(false);
     148             : 
     149        1168 :         for(sal_uInt16 a(0); !bIsCurve && a < rPolyPoly.Count(); a++)
     150             :         {
     151         584 :             if(rPolyPoly[a].HasFlags())
     152             :             {
     153           0 :                 bIsCurve = true;
     154             :             }
     155             :         }
     156             : 
     157         584 :         if(bIsCurve)
     158             :         {
     159             :             OSL_ENSURE(false, "DrawHatch does *not* support curves, falling back to AdaptiveSubdivide()...");
     160           0 :             tools::PolyPolygon aPolyPoly;
     161             : 
     162           0 :             rPolyPoly.AdaptiveSubdivide(aPolyPoly);
     163           0 :             DrawHatch(aPolyPoly, rHatch, bMtf);
     164             :         }
     165             :         else
     166             :         {
     167         584 :             Rectangle   aRect( rPolyPoly.GetBoundRect() );
     168         584 :             const long  nLogPixelWidth = ImplDevicePixelToLogicWidth( 1 );
     169         584 :             const long  nWidth = ImplDevicePixelToLogicWidth( std::max( ImplLogicWidthToDevicePixel( rHatch.GetDistance() ), 3L ) );
     170         584 :             boost::scoped_array<Point> pPtBuffer(new Point[ HATCH_MAXPOINTS ]);
     171         584 :             Point       aPt1, aPt2, aEndPt1;
     172         584 :             Size        aInc;
     173             : 
     174             :             // Single hatch
     175         584 :             aRect.Left() -= nLogPixelWidth; aRect.Top() -= nLogPixelWidth; aRect.Right() += nLogPixelWidth; aRect.Bottom() += nLogPixelWidth;
     176         584 :             CalcHatchValues( aRect, nWidth, rHatch.GetAngle(), aPt1, aPt2, aInc, aEndPt1 );
     177       32402 :             do
     178             :             {
     179       32402 :                 DrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer.get(), bMtf );
     180       32402 :                 aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height();
     181       32402 :                 aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height();
     182             :             }
     183       32402 :             while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) );
     184             : 
     185         584 :             if( ( rHatch.GetStyle() == HATCH_DOUBLE ) || ( rHatch.GetStyle() == HATCH_TRIPLE ) )
     186             :             {
     187             :                 // Double hatch
     188           4 :                 CalcHatchValues( aRect, nWidth, rHatch.GetAngle() + 900, aPt1, aPt2, aInc, aEndPt1 );
     189         208 :                 do
     190             :                 {
     191         208 :                     DrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer.get(), bMtf );
     192         208 :                     aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height();
     193         208 :                     aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height();
     194             :                 }
     195         208 :                 while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) );
     196             : 
     197           4 :                 if( rHatch.GetStyle() == HATCH_TRIPLE )
     198             :                 {
     199             :                     // Triple hatch
     200           0 :                     CalcHatchValues( aRect, nWidth, rHatch.GetAngle() + 450, aPt1, aPt2, aInc, aEndPt1 );
     201           0 :                     do
     202             :                     {
     203           0 :                         DrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer.get(), bMtf );
     204           0 :                         aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height();
     205           0 :                         aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height();
     206             :                     }
     207           0 :                     while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) );
     208             :                 }
     209         584 :             }
     210             :         }
     211             :     }
     212         584 : }
     213             : 
     214         588 : void OutputDevice::CalcHatchValues( const Rectangle& rRect, long nDist, sal_uInt16 nAngle10,
     215             :                                     Point& rPt1, Point& rPt2, Size& rInc, Point& rEndPt1 )
     216             : {
     217         588 :     Point   aRef;
     218         588 :     long    nAngle = nAngle10 % 1800;
     219         588 :     long    nOffset = 0;
     220             : 
     221         588 :     if( nAngle > 900 )
     222           4 :         nAngle -= 1800;
     223             : 
     224         588 :     aRef = ( !IsRefPoint() ? rRect.TopLeft() : GetRefPoint() );
     225             : 
     226         588 :     if( 0 == nAngle )
     227             :     {
     228         574 :         rInc = Size( 0, nDist );
     229         574 :         rPt1 = rRect.TopLeft();
     230         574 :         rPt2 = rRect.TopRight();
     231         574 :         rEndPt1 = rRect.BottomLeft();
     232             : 
     233         574 :         if( aRef.Y() <= rRect.Top() )
     234         574 :             nOffset = ( ( rRect.Top() - aRef.Y() ) % nDist );
     235             :         else
     236           0 :             nOffset = ( nDist - ( ( aRef.Y() - rRect.Top() ) % nDist ) );
     237             : 
     238         574 :         rPt1.Y() -= nOffset;
     239         574 :         rPt2.Y() -= nOffset;
     240             :     }
     241          14 :     else if( 900 == nAngle )
     242             :     {
     243           6 :         rInc = Size( nDist, 0 );
     244           6 :         rPt1 = rRect.TopLeft();
     245           6 :         rPt2 = rRect.BottomLeft();
     246           6 :         rEndPt1 = rRect.TopRight();
     247             : 
     248           6 :         if( aRef.X() <= rRect.Left() )
     249           6 :             nOffset = ( rRect.Left() - aRef.X() ) % nDist;
     250             :         else
     251           0 :             nOffset = nDist - ( ( aRef.X() - rRect.Left() ) % nDist );
     252             : 
     253           6 :         rPt1.X() -= nOffset;
     254           6 :         rPt2.X() -= nOffset;
     255             :     }
     256           8 :     else if( nAngle >= -450 && nAngle <= 450 )
     257             :     {
     258           8 :         const double    fAngle = F_PI1800 * labs( nAngle );
     259           8 :         const double    fTan = tan( fAngle );
     260           8 :         const long      nYOff = FRound( ( rRect.Right() - rRect.Left() ) * fTan );
     261             :         long            nPY;
     262             : 
     263           8 :         rInc = Size( 0, nDist = FRound( nDist / cos( fAngle ) ) );
     264             : 
     265           8 :         if( nAngle > 0 )
     266             :         {
     267           4 :             rPt1 = rRect.TopLeft();
     268           4 :             rPt2 = Point( rRect.Right(), rRect.Top() - nYOff );
     269           4 :             rEndPt1 = Point( rRect.Left(), rRect.Bottom() + nYOff );
     270           4 :             nPY = FRound( aRef.Y() - ( ( rPt1.X() - aRef.X() ) * fTan ) );
     271             :         }
     272             :         else
     273             :         {
     274           4 :             rPt1 = rRect.TopRight();
     275           4 :             rPt2 = Point( rRect.Left(), rRect.Top() - nYOff );
     276           4 :             rEndPt1 = Point( rRect.Right(), rRect.Bottom() + nYOff );
     277           4 :             nPY = FRound( aRef.Y() + ( ( rPt1.X() - aRef.X() ) * fTan ) );
     278             :         }
     279             : 
     280           8 :         if( nPY <= rPt1.Y() )
     281           4 :             nOffset = ( rPt1.Y() - nPY ) % nDist;
     282             :         else
     283           4 :             nOffset = nDist - ( ( nPY - rPt1.Y() ) % nDist );
     284             : 
     285           8 :         rPt1.Y() -= nOffset;
     286           8 :         rPt2.Y() -= nOffset;
     287             :     }
     288             :     else
     289             :     {
     290           0 :         const double fAngle = F_PI1800 * labs( nAngle );
     291           0 :         const double fTan = tan( fAngle );
     292           0 :         const long   nXOff = FRound( ( rRect.Bottom() - rRect.Top() ) / fTan );
     293             :         long         nPX;
     294             : 
     295           0 :         rInc = Size( nDist = FRound( nDist / sin( fAngle ) ), 0 );
     296             : 
     297           0 :         if( nAngle > 0 )
     298             :         {
     299           0 :             rPt1 = rRect.TopLeft();
     300           0 :             rPt2 = Point( rRect.Left() - nXOff, rRect.Bottom() );
     301           0 :             rEndPt1 = Point( rRect.Right() + nXOff, rRect.Top() );
     302           0 :             nPX = FRound( aRef.X() - ( ( rPt1.Y() - aRef.Y() ) / fTan ) );
     303             :         }
     304             :         else
     305             :         {
     306           0 :             rPt1 = rRect.BottomLeft();
     307           0 :             rPt2 = Point( rRect.Left() - nXOff, rRect.Top() );
     308           0 :             rEndPt1 = Point( rRect.Right() + nXOff, rRect.Bottom() );
     309           0 :             nPX = FRound( aRef.X() + ( ( rPt1.Y() - aRef.Y() ) / fTan ) );
     310             :         }
     311             : 
     312           0 :         if( nPX <= rPt1.X() )
     313           0 :             nOffset = ( rPt1.X() - nPX ) % nDist;
     314             :         else
     315           0 :             nOffset = nDist - ( ( nPX - rPt1.X() ) % nDist );
     316             : 
     317           0 :         rPt1.X() -= nOffset;
     318           0 :         rPt2.X() -= nOffset;
     319             :     }
     320         588 : }
     321             : 
     322       32610 : void OutputDevice::DrawHatchLine( const Line& rLine, const tools::PolyPolygon& rPolyPoly,
     323             :                                       Point* pPtBuffer, bool bMtf )
     324             : {
     325       32610 :     assert_if_double_buffered_window();
     326             : 
     327             :     double  fX, fY;
     328       32610 :     long    nAdd, nPCounter = 0;
     329             : 
     330       65220 :     for( long nPoly = 0, nPolyCount = rPolyPoly.Count(); nPoly < nPolyCount; nPoly++ )
     331             :     {
     332       32610 :         const Polygon& rPoly = rPolyPoly[ (sal_uInt16) nPoly ];
     333             : 
     334       32610 :         if( rPoly.GetSize() > 1 )
     335             :         {
     336       32610 :             Line    aCurSegment( rPoly[ 0 ], Point() );
     337             : 
     338      163792 :             for( long i = 1, nCount = rPoly.GetSize(); i <= nCount; i++ )
     339             :             {
     340      131182 :                 aCurSegment.SetEnd( rPoly[ (sal_uInt16)( i % nCount ) ] );
     341      131182 :                 nAdd = 0;
     342             : 
     343      131182 :                 if( rLine.Intersection( aCurSegment, fX, fY ) )
     344             :                 {
     345      126220 :                     if( ( fabs( fX - aCurSegment.GetStart().X() ) <= 0.0000001 ) &&
     346       62632 :                         ( fabs( fY - aCurSegment.GetStart().Y() ) <= 0.0000001 ) )
     347             :                     {
     348           4 :                         const Line      aPrevSegment( rPoly[ (sal_uInt16)( ( i > 1 ) ? ( i - 2 ) : ( nCount - 1 ) ) ], aCurSegment.GetStart() );
     349           4 :                         const double    fPrevDistance = rLine.GetDistance( aPrevSegment.GetStart() );
     350           4 :                         const double    fCurDistance = rLine.GetDistance( aCurSegment.GetEnd() );
     351             : 
     352           4 :                         if( ( fPrevDistance <= 0.0 && fCurDistance > 0.0 ) ||
     353           0 :                             ( fPrevDistance > 0.0 && fCurDistance < 0.0 ) )
     354             :                         {
     355           0 :                             nAdd = 1;
     356             :                         }
     357             :                     }
     358      126212 :                     else if( ( fabs( fX - aCurSegment.GetEnd().X() ) <= 0.0000001 ) &&
     359       62628 :                              ( fabs( fY - aCurSegment.GetEnd().Y() ) <= 0.0000001 ) )
     360             :                     {
     361           4 :                         const Line aNextSegment( aCurSegment.GetEnd(), rPoly[ (sal_uInt16)( ( i + 1 ) % nCount ) ] );
     362             : 
     363           8 :                         if( ( fabs( rLine.GetDistance( aNextSegment.GetEnd() ) ) <= 0.0000001 ) &&
     364           4 :                             ( rLine.GetDistance( aCurSegment.GetStart() ) > 0.0 ) )
     365             :                         {
     366           4 :                             nAdd = 1;
     367             :                         }
     368             :                     }
     369             :                     else
     370       63580 :                         nAdd = 1;
     371             : 
     372       63588 :                     if( nAdd )
     373       63584 :                         pPtBuffer[ nPCounter++ ] = Point( FRound( fX ), FRound( fY ) );
     374             :                 }
     375             : 
     376      131182 :                 aCurSegment.SetStart( aCurSegment.GetEnd() );
     377             :             }
     378             :         }
     379             :     }
     380             : 
     381       32610 :     if( nPCounter > 1 )
     382             :     {
     383       31792 :         qsort( pPtBuffer, nPCounter, sizeof( Point ), HatchCmpFnc );
     384             : 
     385       31792 :         if( nPCounter & 1 )
     386           0 :             nPCounter--;
     387             : 
     388       31792 :         if( bMtf )
     389             :         {
     390        1430 :             for( long i = 0; i < nPCounter; i += 2 )
     391         715 :                 mpMetaFile->AddAction( new MetaLineAction( pPtBuffer[ i ], pPtBuffer[ i + 1 ] ) );
     392             :         }
     393             :         else
     394             :         {
     395       62154 :             for( long i = 0; i < nPCounter; i += 2 )
     396             :             {
     397       31077 :                 if( mpPDFWriter )
     398             :                 {
     399           0 :                     mpPDFWriter->drawLine( pPtBuffer[ i ], pPtBuffer[ i+1 ] );
     400             :                 }
     401             :                 else
     402             :                 {
     403       31077 :                     const Point aPt1( ImplLogicToDevicePixel( pPtBuffer[ i ] ) );
     404       31077 :                     const Point aPt2( ImplLogicToDevicePixel( pPtBuffer[ i + 1 ] ) );
     405       31077 :                     mpGraphics->DrawLine( aPt1.X(), aPt1.Y(), aPt2.X(), aPt2.Y(), this );
     406             :                 }
     407             :             }
     408             :         }
     409             :     }
     410       33411 : }
     411             : 
     412             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11