LCOV - code coverage report
Current view: top level - vcl/source/outdev - gradient.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 142 376 37.8 %
Date: 2014-11-03 Functions: 8 12 66.7 %
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/poly.hxx>
      21             : 
      22             : #include <vcl/gradient.hxx>
      23             : #include <vcl/virdev.hxx>
      24             : #include <vcl/outdev.hxx>
      25             : #include <vcl/settings.hxx>
      26             : 
      27             : #include "salgdi.hxx"
      28             : 
      29             : #define GRADIENT_DEFAULT_STEPCOUNT  0
      30             : 
      31      278091 : void OutputDevice::DrawGradient( const Rectangle& rRect,
      32             :                                  const Gradient& rGradient )
      33             : {
      34             :     // Convert rectangle to a tools::PolyPolygon by first converting to a Polygon
      35      278091 :     Polygon aPolygon ( rRect );
      36      556182 :     tools::PolyPolygon aPolyPoly ( aPolygon );
      37             : 
      38      556182 :     DrawGradient ( aPolyPoly, rGradient );
      39      278091 : }
      40             : 
      41      278103 : void OutputDevice::DrawGradient( const tools::PolyPolygon& rPolyPoly,
      42             :                                  const Gradient& rGradient )
      43             : {
      44      278103 :     if ( mnDrawMode & DRAWMODE_NOGRADIENT )
      45           0 :         return;     // nothing to draw!
      46             : 
      47      278103 :     if ( mbInitClipRegion )
      48      268483 :         InitClipRegion();
      49             : 
      50      278103 :     if ( mbOutputClipped )
      51       19132 :         return;
      52             : 
      53      258971 :     if ( rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize() )
      54             :     {
      55      258971 :         if ( mnDrawMode & ( DRAWMODE_BLACKGRADIENT | DRAWMODE_WHITEGRADIENT | DRAWMODE_SETTINGSGRADIENT) )
      56             :         {
      57           0 :             Color aColor = GetSingleColorGradientFill();
      58             : 
      59           0 :             Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR );
      60           0 :             SetLineColor( aColor );
      61           0 :             SetFillColor( aColor );
      62           0 :             DrawPolyPolygon( rPolyPoly );
      63           0 :             Pop();
      64           0 :             return;
      65             :         }
      66             : 
      67      258971 :         Gradient aGradient( rGradient );
      68             : 
      69      258971 :         if ( mnDrawMode & ( DRAWMODE_GRAYGRADIENT | DRAWMODE_GHOSTEDGRADIENT ) )
      70             :         {
      71           0 :             SetGrayscaleColors( aGradient );
      72             :         }
      73             : 
      74      258971 :         if( mpMetaFile )
      75             :         {
      76          24 :             const Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
      77             : 
      78          24 :             if ( rPolyPoly.IsRect() )
      79             :             {
      80          12 :                 mpMetaFile->AddAction( new MetaGradientAction( aBoundRect, aGradient ) );
      81             :             }
      82             :             else
      83             :             {
      84          12 :                 mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_BEGIN" ) );
      85          12 :                 mpMetaFile->AddAction( new MetaGradientExAction( rPolyPoly, rGradient ) );
      86             : 
      87          12 :                 Push( PushFlags::CLIPREGION );
      88          12 :                 IntersectClipRegion(vcl::Region(rPolyPoly));
      89          12 :                 DrawGradient( aBoundRect, rGradient );
      90          12 :                 Pop();
      91             : 
      92          12 :                 mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_END" ) );
      93             :             }
      94             :         }
      95             : 
      96      258971 :         if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
      97          24 :             return;
      98             : 
      99             :         // Clip and then draw the gradient
     100      258947 :         if( !Rectangle( PixelToLogic( Point() ), GetOutputSize() ).IsEmpty() )
     101             :         {
     102      258947 :             const Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
     103             : 
     104             :             // convert rectangle to pixels
     105      258947 :             Rectangle aRect( ImplLogicToDevicePixel( aBoundRect ) );
     106      258947 :             aRect.Justify();
     107             : 
     108             :             // do nothing if the rectangle is empty
     109      258947 :             if ( !aRect.IsEmpty() )
     110             :             {
     111      258947 :                 if( !mpGraphics && !AcquireGraphics() )
     112           0 :                     return;
     113             : 
     114             :                 // secure clip region
     115      258947 :                 Push( PushFlags::CLIPREGION );
     116      258947 :                 IntersectClipRegion( aBoundRect );
     117             : 
     118      258947 :                 if( mbInitClipRegion )
     119      258947 :                     InitClipRegion();
     120             : 
     121      258947 :                 if( !mbOutputClipped )
     122             :                 {
     123      138190 :                     tools::PolyPolygon aClipPolyPoly( ImplLogicToDevicePixel( rPolyPoly ) );
     124             : 
     125             :                     // draw gradients without border
     126      138190 :                     if( mbLineColor || mbInitLineColor )
     127             :                     {
     128      138164 :                         mpGraphics->SetLineColor();
     129      138164 :                         mbInitLineColor = true;
     130             :                     }
     131             : 
     132      138190 :                     mbInitFillColor = true;
     133             : 
     134             :                     // calculate step count if necessary
     135      138190 :                     if ( !aGradient.GetSteps() )
     136      138190 :                         aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
     137             : 
     138      138190 :                     if ( rPolyPoly.IsRect() )
     139             :                     {
     140             :                         // because we draw with no border line, we have to expand gradient
     141             :                         // rect to avoid missing lines on the right and bottom edge
     142      138190 :                         aRect.Left()--;
     143      138190 :                         aRect.Top()--;
     144      138190 :                         aRect.Right()++;
     145      138190 :                         aRect.Bottom()++;
     146             :                     }
     147             : 
     148             :                     // if the clipping polypolygon is a rectangle, then it's the same size as the bounding of the
     149             :                     // polypolygon, so pass in a NULL for the clipping parameter
     150      138190 :                     if( aGradient.GetStyle() == GradientStyle_LINEAR || rGradient.GetStyle() == GradientStyle_AXIAL )
     151      138190 :                         DrawLinearGradient( aRect, aGradient, false, aClipPolyPoly.IsRect() ? NULL : &aClipPolyPoly );
     152             :                     else
     153           0 :                         DrawComplexGradient( aRect, aGradient, false, aClipPolyPoly.IsRect() ? NULL : &aClipPolyPoly );
     154             :                 }
     155             : 
     156      258947 :                 Pop();
     157             :             }
     158      258947 :         }
     159             :     }
     160             : 
     161      258947 :     if( mpAlphaVDev )
     162           0 :         mpAlphaVDev->DrawPolyPolygon( rPolyPoly );
     163             : }
     164             : 
     165             : namespace
     166             : {
     167     8654772 :     inline sal_uInt8 GetGradientColorValue( long nValue )
     168             :     {
     169     8654772 :         if ( nValue < 0 )
     170           0 :             return 0;
     171     8654772 :         else if ( nValue > 0xFF )
     172           0 :             return 0xFF;
     173             :         else
     174     8654772 :             return (sal_uInt8)nValue;
     175             :     }
     176             : }
     177             : 
     178      138190 : void OutputDevice::DrawLinearGradient( const Rectangle& rRect,
     179             :                                        const Gradient& rGradient,
     180             :                                        bool bMtf, const tools::PolyPolygon* pClipPolyPoly )
     181             : {
     182             :     // get BoundRect of rotated rectangle
     183      138190 :     Rectangle aRect;
     184      138190 :     Point     aCenter;
     185      138190 :     sal_uInt16    nAngle = rGradient.GetAngle() % 3600;
     186             : 
     187      138190 :     rGradient.GetBoundRect( rRect, aRect, aCenter );
     188             : 
     189      138190 :     bool bLinear = (rGradient.GetStyle() == GradientStyle_LINEAR);
     190      138190 :     double fBorder = rGradient.GetBorder() * aRect.GetHeight() / 100.0;
     191      138190 :     if ( !bLinear )
     192             :     {
     193           0 :         fBorder /= 2.0;
     194             :     }
     195      138190 :     Rectangle aMirrorRect = aRect; // used in style axial
     196      138190 :     aMirrorRect.Top() = ( aRect.Top() + aRect.Bottom() ) / 2;
     197      138190 :     if ( !bLinear )
     198             :     {
     199           0 :         aRect.Bottom() = aMirrorRect.Top();
     200             :     }
     201             : 
     202             :     // colour-intensities of start- and finish; change if needed
     203             :     long    nFactor;
     204      138190 :     Color   aStartCol   = rGradient.GetStartColor();
     205      138190 :     Color   aEndCol     = rGradient.GetEndColor();
     206      138190 :     long    nStartRed   = aStartCol.GetRed();
     207      138190 :     long    nStartGreen = aStartCol.GetGreen();
     208      138190 :     long    nStartBlue  = aStartCol.GetBlue();
     209      138190 :     long    nEndRed     = aEndCol.GetRed();
     210      138190 :     long    nEndGreen   = aEndCol.GetGreen();
     211      138190 :     long    nEndBlue    = aEndCol.GetBlue();
     212      138190 :             nFactor     = rGradient.GetStartIntensity();
     213      138190 :             nStartRed   = (nStartRed   * nFactor) / 100;
     214      138190 :             nStartGreen = (nStartGreen * nFactor) / 100;
     215      138190 :             nStartBlue  = (nStartBlue  * nFactor) / 100;
     216      138190 :             nFactor     = rGradient.GetEndIntensity();
     217      138190 :             nEndRed     = (nEndRed   * nFactor) / 100;
     218      138190 :             nEndGreen   = (nEndGreen * nFactor) / 100;
     219      138190 :             nEndBlue    = (nEndBlue  * nFactor) / 100;
     220             : 
     221             :     // gradient style axial has exchanged start and end colors
     222      138190 :     if ( !bLinear)
     223             :     {
     224           0 :         long nTempColor = nStartRed;
     225           0 :         nStartRed = nEndRed;
     226           0 :         nEndRed = nTempColor;
     227           0 :         nTempColor = nStartGreen;
     228           0 :         nStartGreen = nEndGreen;
     229           0 :         nEndGreen = nTempColor;
     230           0 :         nTempColor = nStartBlue;
     231           0 :         nStartBlue = nEndBlue;
     232           0 :         nEndBlue = nTempColor;
     233             :     }
     234             : 
     235             :     sal_uInt8   nRed;
     236             :     sal_uInt8   nGreen;
     237             :     sal_uInt8   nBlue;
     238             : 
     239             :     // Create border
     240      138190 :     Rectangle aBorderRect = aRect;
     241      138190 :     Polygon     aPoly( 4 );
     242      138190 :     if (fBorder > 0.0)
     243             :     {
     244           0 :         nRed        = (sal_uInt8)nStartRed;
     245           0 :         nGreen      = (sal_uInt8)nStartGreen;
     246           0 :         nBlue       = (sal_uInt8)nStartBlue;
     247           0 :         if ( bMtf )
     248           0 :             mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
     249             :         else
     250           0 :             mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     251             : 
     252           0 :         aBorderRect.Bottom() = (long)( aBorderRect.Top() + fBorder );
     253           0 :         aRect.Top() = aBorderRect.Bottom();
     254           0 :         aPoly[0] = aBorderRect.TopLeft();
     255           0 :         aPoly[1] = aBorderRect.TopRight();
     256           0 :         aPoly[2] = aBorderRect.BottomRight();
     257           0 :         aPoly[3] = aBorderRect.BottomLeft();
     258           0 :         aPoly.Rotate( aCenter, nAngle );
     259           0 :         if ( bMtf )
     260           0 :             mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
     261             :         else
     262           0 :             ImplDrawPolygon( aPoly, pClipPolyPoly );
     263           0 :         if ( !bLinear)
     264             :         {
     265           0 :             aBorderRect = aMirrorRect;
     266           0 :             aBorderRect.Top() = (long) ( aBorderRect.Bottom() - fBorder );
     267           0 :             aMirrorRect.Bottom() = aBorderRect.Top();
     268           0 :             aPoly[0] = aBorderRect.TopLeft();
     269           0 :             aPoly[1] = aBorderRect.TopRight();
     270           0 :             aPoly[2] = aBorderRect.BottomRight();
     271           0 :             aPoly[3] = aBorderRect.BottomLeft();
     272           0 :             aPoly.Rotate( aCenter, nAngle );
     273           0 :             if ( bMtf )
     274           0 :                 mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
     275             :             else
     276           0 :                 ImplDrawPolygon( aPoly, pClipPolyPoly );
     277             :         }
     278             :     }
     279             : 
     280             :     // calculate step count
     281      138190 :     long    nStepCount  = GetGradientSteps( rGradient, aRect, bMtf );
     282             : 
     283             :     // minimal three steps and maximal as max color steps
     284      138190 :     long   nAbsRedSteps   = std::abs( nEndRed   - nStartRed );
     285      138190 :     long   nAbsGreenSteps = std::abs( nEndGreen - nStartGreen );
     286      138190 :     long   nAbsBlueSteps  = std::abs( nEndBlue  - nStartBlue );
     287      138190 :     long   nMaxColorSteps = std::max( nAbsRedSteps , nAbsGreenSteps );
     288      138190 :     nMaxColorSteps = std::max( nMaxColorSteps, nAbsBlueSteps );
     289      138190 :     long nSteps = std::min( nStepCount, nMaxColorSteps );
     290      138190 :     if ( nSteps < 3)
     291             :     {
     292          42 :         nSteps = 3;
     293             :     }
     294             : 
     295      138190 :     double fScanInc = ((double)aRect.GetHeight()) / (double) nSteps;
     296      138190 :     double fGradientLine = (double)aRect.Top();
     297      138190 :     double fMirrorGradientLine = (double) aMirrorRect.Bottom();
     298             : 
     299      138190 :     double fAlpha = 0.0;
     300      138190 :     const double fStepsMinus1 = ((double)nSteps) - 1.0;
     301             :     double fTempColor;
     302      138190 :     if ( !bLinear)
     303             :     {
     304           0 :         nSteps -= 1; // draw middle polygons as one polygon after loop to avoid gap
     305             :     }
     306     3023114 :     for ( long i = 0; i < nSteps; i++ )
     307             :     {
     308             :         // linear interpolation of color
     309     2884924 :         fAlpha = ((double)i) / fStepsMinus1;
     310     2884924 :         fTempColor = ((double)nStartRed) * (1.0-fAlpha) + ((double)nEndRed) * fAlpha;
     311     2884924 :         nRed = GetGradientColorValue((long)fTempColor);
     312     2884924 :         fTempColor = ((double)nStartGreen) * (1.0-fAlpha) + ((double)nEndGreen) * fAlpha;
     313     2884924 :         nGreen = GetGradientColorValue((long)fTempColor);
     314     2884924 :         fTempColor = ((double)nStartBlue) * (1.0-fAlpha) + ((double)nEndBlue) * fAlpha;
     315     2884924 :         nBlue = GetGradientColorValue((long)fTempColor);
     316     2884924 :         if ( bMtf )
     317           0 :             mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
     318             :         else
     319     2884924 :             mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     320             : 
     321             :         // Polygon for this color step
     322     2884924 :         aRect.Top() = (long)( fGradientLine + ((double) i) * fScanInc );
     323     2884924 :         aRect.Bottom() = (long)( fGradientLine + ( ((double) i) + 1.0 ) * fScanInc );
     324     2884924 :         aPoly[0] = aRect.TopLeft();
     325     2884924 :         aPoly[1] = aRect.TopRight();
     326     2884924 :         aPoly[2] = aRect.BottomRight();
     327     2884924 :         aPoly[3] = aRect.BottomLeft();
     328     2884924 :         aPoly.Rotate( aCenter, nAngle );
     329     2884924 :         if ( bMtf )
     330           0 :             mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
     331             :         else
     332     2884924 :             ImplDrawPolygon( aPoly, pClipPolyPoly );
     333     2884924 :         if ( !bLinear )
     334             :         {
     335           0 :             aMirrorRect.Bottom() = (long)( fMirrorGradientLine - ((double) i) * fScanInc );
     336           0 :             aMirrorRect.Top() = (long)( fMirrorGradientLine - (((double) i) + 1.0)* fScanInc );
     337           0 :             aPoly[0] = aMirrorRect.TopLeft();
     338           0 :             aPoly[1] = aMirrorRect.TopRight();
     339           0 :             aPoly[2] = aMirrorRect.BottomRight();
     340           0 :             aPoly[3] = aMirrorRect.BottomLeft();
     341           0 :             aPoly.Rotate( aCenter, nAngle );
     342           0 :             if ( bMtf )
     343           0 :                 mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
     344             :             else
     345           0 :                 ImplDrawPolygon( aPoly, pClipPolyPoly );
     346             :         }
     347             :     }
     348      138190 :     if ( !bLinear)
     349             :     {
     350             :         // draw middle polygon with end color
     351           0 :         nRed = GetGradientColorValue(nEndRed);
     352           0 :         nGreen = GetGradientColorValue(nEndGreen);
     353           0 :         nBlue = GetGradientColorValue(nEndBlue);
     354           0 :         if ( bMtf )
     355           0 :             mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
     356             :         else
     357           0 :             mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     358             : 
     359           0 :         aRect.Top() = (long)( fGradientLine + ((double)nSteps) * fScanInc );
     360           0 :         aRect.Bottom() = (long)( fMirrorGradientLine - ((double) nSteps) * fScanInc );
     361           0 :         aPoly[0] = aRect.TopLeft();
     362           0 :         aPoly[1] = aRect.TopRight();
     363           0 :         aPoly[2] = aRect.BottomRight();
     364           0 :         aPoly[3] = aRect.BottomLeft();
     365           0 :         aPoly.Rotate( aCenter, nAngle );
     366           0 :         if ( bMtf )
     367           0 :             mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
     368             :         else
     369           0 :             ImplDrawPolygon( aPoly, pClipPolyPoly );
     370      138190 :     }
     371      138190 : }
     372             : 
     373           0 : void OutputDevice::DrawComplexGradient( const Rectangle& rRect,
     374             :                                             const Gradient& rGradient,
     375             :                                             bool bMtf, const tools::PolyPolygon* pClipPolyPoly )
     376             : {
     377             :     // Determine if we output via Polygon or PolyPolygon
     378             :     // For all rasteroperations other then Overpaint always use PolyPolygon,
     379             :     // as we will get wrong results if we output multiple times on top of each other.
     380             :     // Also for printers always use PolyPolygon, as not all printers
     381             :     // can print polygons on top of each other.
     382             : 
     383           0 :     boost::scoped_ptr<tools::PolyPolygon> pPolyPoly;
     384           0 :     Rectangle       aRect;
     385           0 :     Point           aCenter;
     386           0 :     Color           aStartCol( rGradient.GetStartColor() );
     387           0 :     Color           aEndCol( rGradient.GetEndColor() );
     388           0 :     long            nStartRed = ( (long) aStartCol.GetRed() * rGradient.GetStartIntensity() ) / 100;
     389           0 :     long            nStartGreen = ( (long) aStartCol.GetGreen() * rGradient.GetStartIntensity() ) / 100;
     390           0 :     long            nStartBlue = ( (long) aStartCol.GetBlue() * rGradient.GetStartIntensity() ) / 100;
     391           0 :     long            nEndRed = ( (long) aEndCol.GetRed() * rGradient.GetEndIntensity() ) / 100;
     392           0 :     long            nEndGreen = ( (long) aEndCol.GetGreen() * rGradient.GetEndIntensity() ) / 100;
     393           0 :     long            nEndBlue = ( (long) aEndCol.GetBlue() * rGradient.GetEndIntensity() ) / 100;
     394           0 :     long            nRedSteps = nEndRed - nStartRed;
     395           0 :     long            nGreenSteps = nEndGreen - nStartGreen;
     396           0 :     long            nBlueSteps = nEndBlue   - nStartBlue;
     397           0 :     sal_uInt16      nAngle = rGradient.GetAngle() % 3600;
     398             : 
     399           0 :     rGradient.GetBoundRect( rRect, aRect, aCenter );
     400             : 
     401           0 :     if ( UsePolyPolygonForComplexGradient() || bMtf )
     402           0 :         pPolyPoly.reset(new tools::PolyPolygon( 2 ));
     403             : 
     404             :     // last parameter - true if complex gradient, false if linear
     405           0 :     long nStepCount = GetGradientSteps( rGradient, rRect, bMtf, true );
     406             : 
     407             :     // at least three steps and at most the number of colour differences
     408           0 :     long nSteps = std::max( nStepCount, 2L );
     409           0 :     long nCalcSteps  = std::abs( nRedSteps );
     410           0 :     long nTempSteps = std::abs( nGreenSteps );
     411           0 :     if ( nTempSteps > nCalcSteps )
     412           0 :         nCalcSteps = nTempSteps;
     413           0 :     nTempSteps = std::abs( nBlueSteps );
     414           0 :     if ( nTempSteps > nCalcSteps )
     415           0 :         nCalcSteps = nTempSteps;
     416           0 :     if ( nCalcSteps < nSteps )
     417           0 :         nSteps = nCalcSteps;
     418           0 :     if ( !nSteps )
     419           0 :         nSteps = 1;
     420             : 
     421             :     // determine output limits and stepsizes for all directions
     422           0 :     Polygon aPoly;
     423           0 :     double  fScanLeft = aRect.Left();
     424           0 :     double  fScanTop = aRect.Top();
     425           0 :     double  fScanRight = aRect.Right();
     426           0 :     double  fScanBottom = aRect.Bottom();
     427           0 :     double fScanIncX = (double) aRect.GetWidth() / (double) nSteps * 0.5;
     428           0 :     double fScanIncY = (double) aRect.GetHeight() / (double) nSteps * 0.5;
     429             : 
     430             :     // all gradients are rendered as nested rectangles which shrink
     431             :     // equally in each dimension - except for 'square' gradients
     432             :     // which shrink to a central vertex but are not per-se square.
     433           0 :     if( rGradient.GetStyle() != GradientStyle_SQUARE )
     434             :     {
     435           0 :         fScanIncY = std::min( fScanIncY, fScanIncX );
     436           0 :         fScanIncX = fScanIncY;
     437             :     }
     438           0 :     sal_uInt8   nRed = (sal_uInt8) nStartRed, nGreen = (sal_uInt8) nStartGreen, nBlue = (sal_uInt8) nStartBlue;
     439           0 :     bool    bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
     440             : 
     441           0 :     if( bMtf )
     442           0 :         mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
     443             :     else
     444           0 :         mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     445             : 
     446           0 :     if( pPolyPoly )
     447             :     {
     448           0 :         pPolyPoly->Insert( aPoly = rRect );
     449           0 :         pPolyPoly->Insert( aPoly );
     450             :     }
     451             :     else
     452             :     {
     453             :         // extend rect, to avoid missing bounding line
     454           0 :         Rectangle aExtRect( rRect );
     455             : 
     456           0 :         aExtRect.Left() -= 1;
     457           0 :         aExtRect.Top() -= 1;
     458           0 :         aExtRect.Right() += 1;
     459           0 :         aExtRect.Bottom() += 1;
     460             : 
     461           0 :         ImplDrawPolygon( aPoly = aExtRect, pClipPolyPoly );
     462             :     }
     463             : 
     464             :     // loop to output Polygone/PolyPolygone sequentially
     465           0 :     for( long i = 1; i < nSteps; i++ )
     466             :     {
     467             :         // calculate new Polygon
     468           0 :         aRect.Left() = (long)( fScanLeft += fScanIncX );
     469           0 :         aRect.Top() = (long)( fScanTop += fScanIncY );
     470           0 :         aRect.Right() = (long)( fScanRight -= fScanIncX );
     471           0 :         aRect.Bottom() = (long)( fScanBottom -= fScanIncY );
     472             : 
     473           0 :         if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) )
     474           0 :             break;
     475             : 
     476           0 :         if( rGradient.GetStyle() == GradientStyle_RADIAL || rGradient.GetStyle() == GradientStyle_ELLIPTICAL )
     477           0 :             aPoly = Polygon( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
     478             :         else
     479           0 :             aPoly = Polygon( aRect );
     480             : 
     481           0 :         aPoly.Rotate( aCenter, nAngle );
     482             : 
     483             :         // adapt colour accordingly
     484           0 :         const long nStepIndex = ( ( pPolyPoly ) ? i : ( i + 1 ) );
     485           0 :         nRed = GetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) / nSteps ) );
     486           0 :         nGreen = GetGradientColorValue( nStartGreen + ( ( nGreenSteps * nStepIndex ) / nSteps ) );
     487           0 :         nBlue = GetGradientColorValue( nStartBlue + ( ( nBlueSteps * nStepIndex ) / nSteps ) );
     488             : 
     489             :         // either slow tools::PolyPolygon output or fast Polygon-Paiting
     490           0 :         if( pPolyPoly )
     491             :         {
     492           0 :             bPaintLastPolygon = true; // #107349# Paint last polygon only if loop has generated any output
     493             : 
     494           0 :             pPolyPoly->Replace( pPolyPoly->GetObject( 1 ), 0 );
     495           0 :             pPolyPoly->Replace( aPoly, 1 );
     496             : 
     497           0 :             if( bMtf )
     498           0 :                 mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) );
     499             :             else
     500           0 :                 ImplDrawPolyPolygon( *pPolyPoly, pClipPolyPoly );
     501             : 
     502             :             // #107349# Set fill color _after_ geometry painting:
     503             :             // pPolyPoly's geometry is the band from last iteration's
     504             :             // aPoly to current iteration's aPoly. The window outdev
     505             :             // path (see else below), on the other hand, paints the
     506             :             // full aPoly. Thus, here, we're painting the band before
     507             :             // the one painted in the window outdev path below. To get
     508             :             // matching colors, have to delay color setting here.
     509           0 :             if( bMtf )
     510           0 :                 mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
     511             :             else
     512           0 :                 mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     513             :         }
     514             :         else
     515             :         {
     516             :             // #107349# Set fill color _before_ geometry painting
     517           0 :             if( bMtf )
     518           0 :                 mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
     519             :             else
     520           0 :                 mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     521             : 
     522           0 :             ImplDrawPolygon( aPoly, pClipPolyPoly );
     523             :         }
     524             :     }
     525             : 
     526             :     // we should draw last inner Polygon if we output PolyPolygon
     527           0 :     if( pPolyPoly )
     528             :     {
     529           0 :         const Polygon& rPoly = pPolyPoly->GetObject( 1 );
     530             : 
     531           0 :         if( !rPoly.GetBoundRect().IsEmpty() )
     532             :         {
     533             :             // #107349# Paint last polygon with end color only if loop
     534             :             // has generated output. Otherwise, the current
     535             :             // (i.e. start) color is taken, to generate _any_ output.
     536           0 :             if( bPaintLastPolygon )
     537             :             {
     538           0 :                 nRed = GetGradientColorValue( nEndRed );
     539           0 :                 nGreen = GetGradientColorValue( nEndGreen );
     540           0 :                 nBlue = GetGradientColorValue( nEndBlue );
     541             :             }
     542             : 
     543           0 :             if( bMtf )
     544             :             {
     545           0 :                 mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
     546           0 :                 mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) );
     547             :             }
     548             :             else
     549             :             {
     550           0 :                 mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     551           0 :                    ImplDrawPolygon( rPoly, pClipPolyPoly );
     552             :             }
     553             :         }
     554           0 :     }
     555           0 : }
     556             : 
     557      138190 : long OutputDevice::GetGradientStepCount( long nMinRect )
     558             : {
     559      138190 :     long nInc = (nMinRect < 50) ? 2 : 4;
     560             : 
     561      138190 :     return nInc;
     562             : }
     563             : 
     564      138190 : long OutputDevice::GetGradientSteps( const Gradient& rGradient, const Rectangle& rRect, bool bMtf, bool bComplex )
     565             : {
     566             :     // calculate step count
     567      138190 :     long nStepCount  = rGradient.GetSteps();
     568             :     long nMinRect;
     569             : 
     570             :     // generate nStepCount, if not passed
     571      138190 :     if (bComplex)
     572           0 :         nMinRect = std::min( rRect.GetWidth(), rRect.GetHeight() );
     573             :     else
     574      138190 :         nMinRect = rRect.GetHeight();
     575             : 
     576      138190 :     if ( !nStepCount )
     577             :     {
     578             :         long nInc;
     579             : 
     580      138190 :         nInc = GetGradientStepCount (nMinRect);
     581      138190 :         if ( !nInc || bMtf )
     582           0 :             nInc = 1;
     583      138190 :         nStepCount = nMinRect / nInc;
     584             :     }
     585             : 
     586      138190 :     return nStepCount;
     587             : }
     588             : 
     589           0 : Color OutputDevice::GetSingleColorGradientFill()
     590             : {
     591           0 :     Color aColor;
     592             : 
     593             :     // we should never call on this function if any of these aren't set!
     594             :     assert( mnDrawMode & ( DRAWMODE_BLACKGRADIENT | DRAWMODE_WHITEGRADIENT | DRAWMODE_SETTINGSGRADIENT) );
     595             : 
     596           0 :     if ( mnDrawMode & DRAWMODE_BLACKGRADIENT )
     597           0 :         aColor = Color( COL_BLACK );
     598           0 :     else if ( mnDrawMode & DRAWMODE_WHITEGRADIENT )
     599           0 :         aColor = Color( COL_WHITE );
     600           0 :     else if ( mnDrawMode & DRAWMODE_SETTINGSGRADIENT )
     601           0 :         aColor = GetSettings().GetStyleSettings().GetWindowColor();
     602             : 
     603           0 :     if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT )
     604             :     {
     605           0 :         aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
     606           0 :                         ( aColor.GetGreen() >> 1 ) | 0x80,
     607           0 :                         ( aColor.GetBlue() >> 1 ) | 0x80 );
     608             :     }
     609             : 
     610           0 :     return aColor;
     611             : }
     612             : 
     613           0 : void OutputDevice::SetGrayscaleColors( Gradient &rGradient )
     614             : {
     615             :     // this should only be called with the drawing mode is for grayscale or ghosted gradients
     616             :     assert ( mnDrawMode & ( DRAWMODE_GRAYGRADIENT | DRAWMODE_GHOSTEDGRADIENT ) );
     617             : 
     618           0 :     Color aStartCol( rGradient.GetStartColor() );
     619           0 :     Color aEndCol( rGradient.GetEndColor() );
     620             : 
     621           0 :     if ( mnDrawMode & DRAWMODE_GRAYGRADIENT )
     622             :     {
     623           0 :         sal_uInt8 cStartLum = aStartCol.GetLuminance(), cEndLum = aEndCol.GetLuminance();
     624           0 :         aStartCol = Color( cStartLum, cStartLum, cStartLum );
     625           0 :         aEndCol = Color( cEndLum, cEndLum, cEndLum );
     626             :     }
     627             : 
     628           0 :     if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT )
     629             :     {
     630           0 :         aStartCol = Color( ( aStartCol.GetRed() >> 1 ) | 0x80,
     631           0 :                            ( aStartCol.GetGreen() >> 1 ) | 0x80,
     632           0 :                            ( aStartCol.GetBlue() >> 1 ) | 0x80 );
     633             : 
     634           0 :         aEndCol = Color( ( aEndCol.GetRed() >> 1 ) | 0x80,
     635           0 :                          ( aEndCol.GetGreen() >> 1 ) | 0x80,
     636           0 :                          ( aEndCol.GetBlue() >> 1 ) | 0x80 );
     637             :     }
     638             : 
     639           0 :     rGradient.SetStartColor( aStartCol );
     640           0 :     rGradient.SetEndColor( aEndCol );
     641           0 : }
     642             : 
     643           0 : void OutputDevice::AddGradientActions( const Rectangle& rRect, const Gradient& rGradient,
     644             :                                        GDIMetaFile& rMtf )
     645             : {
     646             : 
     647           0 :     Rectangle aRect( rRect );
     648             : 
     649           0 :     aRect.Justify();
     650             : 
     651             :     // do nothing if the rectangle is empty
     652           0 :     if ( !aRect.IsEmpty() )
     653             :     {
     654           0 :         Gradient        aGradient( rGradient );
     655           0 :         GDIMetaFile*    pOldMtf = mpMetaFile;
     656             : 
     657           0 :         mpMetaFile = &rMtf;
     658           0 :         mpMetaFile->AddAction( new MetaPushAction( PushFlags::ALL ) );
     659           0 :         mpMetaFile->AddAction( new MetaISectRectClipRegionAction( aRect ) );
     660           0 :         mpMetaFile->AddAction( new MetaLineColorAction( Color(), false ) );
     661             : 
     662             :         // because we draw with no border line, we have to expand gradient
     663             :         // rect to avoid missing lines on the right and bottom edge
     664           0 :         aRect.Left()--;
     665           0 :         aRect.Top()--;
     666           0 :         aRect.Right()++;
     667           0 :         aRect.Bottom()++;
     668             : 
     669             :         // calculate step count if necessary
     670           0 :         if ( !aGradient.GetSteps() )
     671           0 :             aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
     672             : 
     673           0 :         if( aGradient.GetStyle() == GradientStyle_LINEAR || aGradient.GetStyle() == GradientStyle_AXIAL )
     674           0 :             DrawLinearGradient( aRect, aGradient, true, NULL );
     675             :         else
     676           0 :             DrawComplexGradient( aRect, aGradient, true, NULL );
     677             : 
     678           0 :         mpMetaFile->AddAction( new MetaPopAction() );
     679           0 :         mpMetaFile = pOldMtf;
     680             :     }
     681        1233 : }
     682             : 
     683             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10