LCOV - code coverage report
Current view: top level - vcl/source/outdev - gradient.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 180 596 30.2 %
Date: 2015-06-13 12:38:46 Functions: 12 17 70.6 %
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/settings.hxx>
      24             : #include <vcl/outdev.hxx>
      25             : #include <vcl/virdev.hxx>
      26             : #include <vcl/window.hxx>
      27             : 
      28             : #include "salgdi.hxx"
      29             : 
      30             : #define GRADIENT_DEFAULT_STEPCOUNT  0
      31             : 
      32      165877 : void OutputDevice::DrawGradient( const Rectangle& rRect,
      33             :                                  const Gradient& rGradient )
      34             : {
      35      165877 :     assert_if_double_buffered_window();
      36             : 
      37             :     // Convert rectangle to a tools::PolyPolygon by first converting to a Polygon
      38      165877 :     Polygon aPolygon ( rRect );
      39      331754 :     tools::PolyPolygon aPolyPoly ( aPolygon );
      40             : 
      41      331754 :     DrawGradient ( aPolyPoly, rGradient );
      42      165877 : }
      43             : 
      44      165881 : void OutputDevice::DrawGradient( const tools::PolyPolygon& rPolyPoly,
      45             :                                  const Gradient& rGradient )
      46             : {
      47      165881 :     assert_if_double_buffered_window();
      48             : 
      49      165881 :     if ( mnDrawMode & DrawModeFlags::NoGradient )
      50           0 :         return;     // nothing to draw!
      51             : 
      52      165881 :     if ( mbInitClipRegion )
      53      160829 :         InitClipRegion();
      54             : 
      55      165881 :     if ( mbOutputClipped )
      56       10036 :         return;
      57             : 
      58      155845 :     if ( rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize() )
      59             :     {
      60      155845 :         if ( mnDrawMode & ( DrawModeFlags::BlackGradient | DrawModeFlags::WhiteGradient | DrawModeFlags::SettingsGradient) )
      61             :         {
      62           0 :             Color aColor = GetSingleColorGradientFill();
      63             : 
      64           0 :             Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR );
      65           0 :             SetLineColor( aColor );
      66           0 :             SetFillColor( aColor );
      67           0 :             DrawPolyPolygon( rPolyPoly );
      68           0 :             Pop();
      69           0 :             return;
      70             :         }
      71             : 
      72      155845 :         Gradient aGradient( rGradient );
      73             : 
      74      155845 :         if ( mnDrawMode & ( DrawModeFlags::GrayGradient | DrawModeFlags::GhostedGradient ) )
      75             :         {
      76           9 :             SetGrayscaleColors( aGradient );
      77             :         }
      78             : 
      79      155845 :         DrawGradientToMetafile( rPolyPoly, rGradient );
      80             : 
      81      155845 :         if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
      82          12 :             return;
      83             : 
      84             :         // Clip and then draw the gradient
      85      155833 :         if( !Rectangle( PixelToLogic( Point() ), GetOutputSize() ).IsEmpty() )
      86             :         {
      87      155833 :             const Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
      88             : 
      89             :             // convert rectangle to pixels
      90      155833 :             Rectangle aRect( ImplLogicToDevicePixel( aBoundRect ) );
      91      155833 :             aRect.Justify();
      92             : 
      93             :             // do nothing if the rectangle is empty
      94      155833 :             if ( !aRect.IsEmpty() )
      95             :             {
      96      155833 :                 tools::PolyPolygon aClixPolyPoly( ImplLogicToDevicePixel( rPolyPoly ) );
      97      155833 :                 bool bDrawn = false;
      98             : 
      99      155833 :                 if( !mpGraphics && !AcquireGraphics() )
     100           0 :                     return;
     101             : 
     102             :                 // secure clip region
     103      155833 :                 Push( PushFlags::CLIPREGION );
     104      155833 :                 IntersectClipRegion( aBoundRect );
     105             : 
     106      155833 :                 if( mbInitClipRegion )
     107      155833 :                     InitClipRegion();
     108             : 
     109             :                 // try to draw gradient natively
     110      155833 :                 bDrawn = mpGraphics->DrawGradient( aClixPolyPoly, aGradient, this );
     111             : 
     112      155833 :                 if( !bDrawn && !mbOutputClipped )
     113             :                 {
     114             :                     // draw gradients without border
     115       78545 :                     if( mbLineColor || mbInitLineColor )
     116             :                     {
     117       78539 :                         mpGraphics->SetLineColor();
     118       78539 :                         mbInitLineColor = true;
     119             :                     }
     120             : 
     121       78545 :                     mbInitFillColor = true;
     122             : 
     123             :                     // calculate step count if necessary
     124       78545 :                     if ( !aGradient.GetSteps() )
     125       78541 :                         aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
     126             : 
     127       78545 :                     if ( rPolyPoly.IsRect() )
     128             :                     {
     129             :                         // because we draw with no border line, we have to expand gradient
     130             :                         // rect to avoid missing lines on the right and bottom edge
     131       78545 :                         aRect.Left()--;
     132       78545 :                         aRect.Top()--;
     133       78545 :                         aRect.Right()++;
     134       78545 :                         aRect.Bottom()++;
     135             :                     }
     136             : 
     137             :                     // if the clipping polypolygon is a rectangle, then it's the same size as the bounding of the
     138             :                     // polypolygon, so pass in a NULL for the clipping parameter
     139       78545 :                     if( aGradient.GetStyle() == GradientStyle_LINEAR || rGradient.GetStyle() == GradientStyle_AXIAL )
     140       78545 :                         DrawLinearGradient( aRect, aGradient, aClixPolyPoly.IsRect() ? NULL : &aClixPolyPoly );
     141             :                     else
     142           0 :                         DrawComplexGradient( aRect, aGradient, aClixPolyPoly.IsRect() ? NULL : &aClixPolyPoly );
     143             :                 }
     144             : 
     145      155833 :                 Pop();
     146             :             }
     147      155833 :         }
     148             :     }
     149             : 
     150      155833 :     if( mpAlphaVDev )
     151           0 :         mpAlphaVDev->DrawPolyPolygon( rPolyPoly );
     152             : }
     153             : 
     154           4 : void OutputDevice::ClipAndDrawGradientMetafile ( const Gradient &rGradient, const tools::PolyPolygon &rPolyPoly )
     155             : {
     156           4 :     const Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
     157           4 :     const bool  bOldOutput = IsOutputEnabled();
     158             : 
     159           4 :     EnableOutput( false );
     160           4 :     Push( PushFlags::RASTEROP );
     161           4 :     SetRasterOp( ROP_XOR );
     162           4 :     DrawGradient( aBoundRect, rGradient );
     163           4 :     SetFillColor( COL_BLACK );
     164           4 :     SetRasterOp( ROP_0 );
     165           4 :     DrawPolyPolygon( rPolyPoly );
     166           4 :     SetRasterOp( ROP_XOR );
     167           4 :     DrawGradient( aBoundRect, rGradient );
     168           4 :     Pop();
     169           4 :     EnableOutput( bOldOutput );
     170           4 : }
     171             : 
     172      155845 : void OutputDevice::DrawGradientToMetafile ( const tools::PolyPolygon& rPolyPoly,
     173             :                                             const Gradient& rGradient )
     174             : {
     175      155845 :     assert_if_double_buffered_window();
     176             : 
     177      155845 :     if ( !mpMetaFile )
     178      155833 :         return;
     179             : 
     180          12 :     if ( rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize() )
     181             :     {
     182          12 :         Gradient aGradient( rGradient );
     183             : 
     184          12 :         if ( mnDrawMode & ( DrawModeFlags::GrayGradient | DrawModeFlags::GhostedGradient ) )
     185             :         {
     186           0 :             SetGrayscaleColors( aGradient );
     187             :         }
     188             : 
     189          12 :         const Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
     190             : 
     191          12 :         if ( rPolyPoly.IsRect() )
     192             :         {
     193           8 :             mpMetaFile->AddAction( new MetaGradientAction( aBoundRect, aGradient ) );
     194             :         }
     195             :         else
     196             :         {
     197           4 :             mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_BEGIN" ) );
     198           4 :             mpMetaFile->AddAction( new MetaGradientExAction( rPolyPoly, rGradient ) );
     199             : 
     200           4 :             ClipAndDrawGradientMetafile ( rGradient, rPolyPoly );
     201             : 
     202           4 :             mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_END" ) );
     203             :         }
     204             : 
     205          12 :         if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
     206          12 :             return;
     207             : 
     208             :         // Clip and then draw the gradient
     209           0 :         if( !Rectangle( PixelToLogic( Point() ), GetOutputSize() ).IsEmpty() )
     210             :         {
     211             :             // convert rectangle to pixels
     212           0 :             Rectangle aRect( ImplLogicToDevicePixel( aBoundRect ) );
     213           0 :             aRect.Justify();
     214             : 
     215             :             // do nothing if the rectangle is empty
     216           0 :             if ( !aRect.IsEmpty() )
     217             :             {
     218           0 :                 if( !mbOutputClipped )
     219             :                 {
     220             :                     // calculate step count if necessary
     221           0 :                     if ( !aGradient.GetSteps() )
     222           0 :                         aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
     223             : 
     224           0 :                     if ( rPolyPoly.IsRect() )
     225             :                     {
     226             :                         // because we draw with no border line, we have to expand gradient
     227             :                         // rect to avoid missing lines on the right and bottom edge
     228           0 :                         aRect.Left()--;
     229           0 :                         aRect.Top()--;
     230           0 :                         aRect.Right()++;
     231           0 :                         aRect.Bottom()++;
     232             :                     }
     233             : 
     234             :                     // if the clipping polypolygon is a rectangle, then it's the same size as the bounding of the
     235             :                     // polypolygon, so pass in a NULL for the clipping parameter
     236           0 :                     if( aGradient.GetStyle() == GradientStyle_LINEAR || rGradient.GetStyle() == GradientStyle_AXIAL )
     237           0 :                         DrawLinearGradientToMetafile( aRect, aGradient );
     238             :                     else
     239           0 :                         DrawComplexGradientToMetafile( aRect, aGradient );
     240             :                 }
     241             :             }
     242           0 :         }
     243             :     }
     244             : }
     245             : 
     246             : namespace
     247             : {
     248     4100385 :     inline sal_uInt8 GetGradientColorValue( long nValue )
     249             :     {
     250     4100385 :         if ( nValue < 0 )
     251           0 :             return 0;
     252     4100385 :         else if ( nValue > 0xFF )
     253           0 :             return 0xFF;
     254             :         else
     255     4100385 :             return (sal_uInt8)nValue;
     256             :     }
     257             : }
     258             : 
     259       78545 : void OutputDevice::DrawLinearGradient( const Rectangle& rRect,
     260             :                                        const Gradient& rGradient,
     261             :                                        const tools::PolyPolygon* pClixPolyPoly )
     262             : {
     263       78545 :     assert_if_double_buffered_window();
     264             : 
     265             :     // get BoundRect of rotated rectangle
     266       78545 :     Rectangle aRect;
     267       78545 :     Point     aCenter;
     268       78545 :     sal_uInt16    nAngle = rGradient.GetAngle() % 3600;
     269             : 
     270       78545 :     rGradient.GetBoundRect( rRect, aRect, aCenter );
     271             : 
     272       78545 :     bool bLinear = (rGradient.GetStyle() == GradientStyle_LINEAR);
     273       78545 :     double fBorder = rGradient.GetBorder() * aRect.GetHeight() / 100.0;
     274       78545 :     if ( !bLinear )
     275             :     {
     276           0 :         fBorder /= 2.0;
     277             :     }
     278       78545 :     Rectangle aMirrorRect = aRect; // used in style axial
     279       78545 :     aMirrorRect.Top() = ( aRect.Top() + aRect.Bottom() ) / 2;
     280       78545 :     if ( !bLinear )
     281             :     {
     282           0 :         aRect.Bottom() = aMirrorRect.Top();
     283             :     }
     284             : 
     285             :     // colour-intensities of start- and finish; change if needed
     286             :     long    nFactor;
     287       78545 :     Color   aStartCol   = rGradient.GetStartColor();
     288       78545 :     Color   aEndCol     = rGradient.GetEndColor();
     289       78545 :     long    nStartRed   = aStartCol.GetRed();
     290       78545 :     long    nStartGreen = aStartCol.GetGreen();
     291       78545 :     long    nStartBlue  = aStartCol.GetBlue();
     292       78545 :     long    nEndRed     = aEndCol.GetRed();
     293       78545 :     long    nEndGreen   = aEndCol.GetGreen();
     294       78545 :     long    nEndBlue    = aEndCol.GetBlue();
     295       78545 :             nFactor     = rGradient.GetStartIntensity();
     296       78545 :             nStartRed   = (nStartRed   * nFactor) / 100;
     297       78545 :             nStartGreen = (nStartGreen * nFactor) / 100;
     298       78545 :             nStartBlue  = (nStartBlue  * nFactor) / 100;
     299       78545 :             nFactor     = rGradient.GetEndIntensity();
     300       78545 :             nEndRed     = (nEndRed   * nFactor) / 100;
     301       78545 :             nEndGreen   = (nEndGreen * nFactor) / 100;
     302       78545 :             nEndBlue    = (nEndBlue  * nFactor) / 100;
     303             : 
     304             :     // gradient style axial has exchanged start and end colors
     305       78545 :     if ( !bLinear)
     306             :     {
     307           0 :         long nTempColor = nStartRed;
     308           0 :         nStartRed = nEndRed;
     309           0 :         nEndRed = nTempColor;
     310           0 :         nTempColor = nStartGreen;
     311           0 :         nStartGreen = nEndGreen;
     312           0 :         nEndGreen = nTempColor;
     313           0 :         nTempColor = nStartBlue;
     314           0 :         nStartBlue = nEndBlue;
     315           0 :         nEndBlue = nTempColor;
     316             :     }
     317             : 
     318             :     sal_uInt8   nRed;
     319             :     sal_uInt8   nGreen;
     320             :     sal_uInt8   nBlue;
     321             : 
     322             :     // Create border
     323       78545 :     Rectangle aBorderRect = aRect;
     324       78545 :     Polygon     aPoly( 4 );
     325       78545 :     if (fBorder > 0.0)
     326             :     {
     327           0 :         nRed        = (sal_uInt8)nStartRed;
     328           0 :         nGreen      = (sal_uInt8)nStartGreen;
     329           0 :         nBlue       = (sal_uInt8)nStartBlue;
     330             : 
     331           0 :         mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     332             : 
     333           0 :         aBorderRect.Bottom() = (long)( aBorderRect.Top() + fBorder );
     334           0 :         aRect.Top() = aBorderRect.Bottom();
     335           0 :         aPoly[0] = aBorderRect.TopLeft();
     336           0 :         aPoly[1] = aBorderRect.TopRight();
     337           0 :         aPoly[2] = aBorderRect.BottomRight();
     338           0 :         aPoly[3] = aBorderRect.BottomLeft();
     339           0 :         aPoly.Rotate( aCenter, nAngle );
     340             : 
     341           0 :         ImplDrawPolygon( aPoly, pClixPolyPoly );
     342             : 
     343           0 :         if ( !bLinear)
     344             :         {
     345           0 :             aBorderRect = aMirrorRect;
     346           0 :             aBorderRect.Top() = (long) ( aBorderRect.Bottom() - fBorder );
     347           0 :             aMirrorRect.Bottom() = aBorderRect.Top();
     348           0 :             aPoly[0] = aBorderRect.TopLeft();
     349           0 :             aPoly[1] = aBorderRect.TopRight();
     350           0 :             aPoly[2] = aBorderRect.BottomRight();
     351           0 :             aPoly[3] = aBorderRect.BottomLeft();
     352           0 :             aPoly.Rotate( aCenter, nAngle );
     353             : 
     354           0 :             ImplDrawPolygon( aPoly, pClixPolyPoly );
     355             :         }
     356             :     }
     357             : 
     358             :     // calculate step count
     359       78545 :     bool    bMtf = false;
     360       78545 :     long    nStepCount  = GetGradientSteps( rGradient, aRect, bMtf );
     361             : 
     362             :     // minimal three steps and maximal as max color steps
     363       78545 :     long   nAbsRedSteps   = std::abs( nEndRed   - nStartRed );
     364       78545 :     long   nAbsGreenSteps = std::abs( nEndGreen - nStartGreen );
     365       78545 :     long   nAbsBlueSteps  = std::abs( nEndBlue  - nStartBlue );
     366       78545 :     long   nMaxColorSteps = std::max( nAbsRedSteps , nAbsGreenSteps );
     367       78545 :     nMaxColorSteps = std::max( nMaxColorSteps, nAbsBlueSteps );
     368       78545 :     long nSteps = std::min( nStepCount, nMaxColorSteps );
     369       78545 :     if ( nSteps < 3)
     370             :     {
     371          25 :         nSteps = 3;
     372             :     }
     373             : 
     374       78545 :     double fScanInc = ((double)aRect.GetHeight()) / (double) nSteps;
     375       78545 :     double fGradientLine = (double)aRect.Top();
     376       78545 :     double fMirrorGradientLine = (double) aMirrorRect.Bottom();
     377             : 
     378       78545 :     const double fStepsMinus1 = ((double)nSteps) - 1.0;
     379       78545 :     if ( !bLinear)
     380             :     {
     381           0 :         nSteps -= 1; // draw middle polygons as one polygon after loop to avoid gap
     382             :     }
     383     1445340 :     for ( long i = 0; i < nSteps; i++ )
     384             :     {
     385             :         // linear interpolation of color
     386     1366795 :         const double fAlpha = ((double)i) / fStepsMinus1;
     387     1366795 :         double fTempColor = ((double)nStartRed) * (1.0-fAlpha) + ((double)nEndRed) * fAlpha;
     388     1366795 :         nRed = GetGradientColorValue((long)fTempColor);
     389     1366795 :         fTempColor = ((double)nStartGreen) * (1.0-fAlpha) + ((double)nEndGreen) * fAlpha;
     390     1366795 :         nGreen = GetGradientColorValue((long)fTempColor);
     391     1366795 :         fTempColor = ((double)nStartBlue) * (1.0-fAlpha) + ((double)nEndBlue) * fAlpha;
     392     1366795 :         nBlue = GetGradientColorValue((long)fTempColor);
     393             : 
     394     1366795 :         mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     395             : 
     396             :         // Polygon for this color step
     397     1366795 :         aRect.Top() = (long)( fGradientLine + ((double) i) * fScanInc );
     398     1366795 :         aRect.Bottom() = (long)( fGradientLine + ( ((double) i) + 1.0 ) * fScanInc );
     399     1366795 :         aPoly[0] = aRect.TopLeft();
     400     1366795 :         aPoly[1] = aRect.TopRight();
     401     1366795 :         aPoly[2] = aRect.BottomRight();
     402     1366795 :         aPoly[3] = aRect.BottomLeft();
     403     1366795 :         aPoly.Rotate( aCenter, nAngle );
     404             : 
     405     1366795 :         ImplDrawPolygon( aPoly, pClixPolyPoly );
     406             : 
     407     1366795 :         if ( !bLinear )
     408             :         {
     409           0 :             aMirrorRect.Bottom() = (long)( fMirrorGradientLine - ((double) i) * fScanInc );
     410           0 :             aMirrorRect.Top() = (long)( fMirrorGradientLine - (((double) i) + 1.0)* fScanInc );
     411           0 :             aPoly[0] = aMirrorRect.TopLeft();
     412           0 :             aPoly[1] = aMirrorRect.TopRight();
     413           0 :             aPoly[2] = aMirrorRect.BottomRight();
     414           0 :             aPoly[3] = aMirrorRect.BottomLeft();
     415           0 :             aPoly.Rotate( aCenter, nAngle );
     416             : 
     417           0 :             ImplDrawPolygon( aPoly, pClixPolyPoly );
     418             :         }
     419             :     }
     420       78545 :     if ( !bLinear)
     421             :     {
     422             :         // draw middle polygon with end color
     423           0 :         nRed = GetGradientColorValue(nEndRed);
     424           0 :         nGreen = GetGradientColorValue(nEndGreen);
     425           0 :         nBlue = GetGradientColorValue(nEndBlue);
     426             : 
     427           0 :         mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     428             : 
     429           0 :         aRect.Top() = (long)( fGradientLine + ((double)nSteps) * fScanInc );
     430           0 :         aRect.Bottom() = (long)( fMirrorGradientLine - ((double) nSteps) * fScanInc );
     431           0 :         aPoly[0] = aRect.TopLeft();
     432           0 :         aPoly[1] = aRect.TopRight();
     433           0 :         aPoly[2] = aRect.BottomRight();
     434           0 :         aPoly[3] = aRect.BottomLeft();
     435           0 :         aPoly.Rotate( aCenter, nAngle );
     436             : 
     437           0 :         ImplDrawPolygon( aPoly, pClixPolyPoly );
     438       78545 :     }
     439       78545 : }
     440             : 
     441     7951709 : void OutputDevice::assert_if_double_buffered_window() const
     442             : {
     443             : #ifndef NDEBUG
     444             :     const vcl::Window *pWindow = dynamic_cast<const vcl::Window*>(this);
     445             :     assert(!pWindow || !pWindow->SupportsDoubleBuffering());
     446             : #endif
     447     7951709 : }
     448             : 
     449           0 : void OutputDevice::DrawComplexGradient( const Rectangle& rRect,
     450             :                                         const Gradient& rGradient,
     451             :                                         const tools::PolyPolygon* pClixPolyPoly )
     452             : {
     453           0 :     assert_if_double_buffered_window();
     454             : 
     455             :     // Determine if we output via Polygon or PolyPolygon
     456             :     // For all rasteroperations other then Overpaint always use PolyPolygon,
     457             :     // as we will get wrong results if we output multiple times on top of each other.
     458             :     // Also for printers always use PolyPolygon, as not all printers
     459             :     // can print polygons on top of each other.
     460             : 
     461           0 :     std::unique_ptr<tools::PolyPolygon> xPolyPoly;
     462           0 :     Rectangle       aRect;
     463           0 :     Point           aCenter;
     464           0 :     Color           aStartCol( rGradient.GetStartColor() );
     465           0 :     Color           aEndCol( rGradient.GetEndColor() );
     466           0 :     long            nStartRed = ( (long) aStartCol.GetRed() * rGradient.GetStartIntensity() ) / 100;
     467           0 :     long            nStartGreen = ( (long) aStartCol.GetGreen() * rGradient.GetStartIntensity() ) / 100;
     468           0 :     long            nStartBlue = ( (long) aStartCol.GetBlue() * rGradient.GetStartIntensity() ) / 100;
     469           0 :     long            nEndRed = ( (long) aEndCol.GetRed() * rGradient.GetEndIntensity() ) / 100;
     470           0 :     long            nEndGreen = ( (long) aEndCol.GetGreen() * rGradient.GetEndIntensity() ) / 100;
     471           0 :     long            nEndBlue = ( (long) aEndCol.GetBlue() * rGradient.GetEndIntensity() ) / 100;
     472           0 :     long            nRedSteps = nEndRed - nStartRed;
     473           0 :     long            nGreenSteps = nEndGreen - nStartGreen;
     474           0 :     long            nBlueSteps = nEndBlue   - nStartBlue;
     475           0 :     sal_uInt16      nAngle = rGradient.GetAngle() % 3600;
     476             : 
     477           0 :     rGradient.GetBoundRect( rRect, aRect, aCenter );
     478             : 
     479           0 :     if ( UsePolyPolygonForComplexGradient() )
     480           0 :         xPolyPoly.reset(new tools::PolyPolygon( 2 ));
     481             : 
     482           0 :     bool bMtf = false;
     483           0 :     bool bComplex = true;
     484           0 :     long nStepCount = GetGradientSteps( rGradient, rRect, bMtf, bComplex );
     485             : 
     486             :     // at least three steps and at most the number of colour differences
     487           0 :     long nSteps = std::max( nStepCount, 2L );
     488           0 :     long nCalcSteps  = std::abs( nRedSteps );
     489           0 :     long nTempSteps = std::abs( nGreenSteps );
     490           0 :     if ( nTempSteps > nCalcSteps )
     491           0 :         nCalcSteps = nTempSteps;
     492           0 :     nTempSteps = std::abs( nBlueSteps );
     493           0 :     if ( nTempSteps > nCalcSteps )
     494           0 :         nCalcSteps = nTempSteps;
     495           0 :     if ( nCalcSteps < nSteps )
     496           0 :         nSteps = nCalcSteps;
     497           0 :     if ( !nSteps )
     498           0 :         nSteps = 1;
     499             : 
     500             :     // determine output limits and stepsizes for all directions
     501           0 :     Polygon aPoly;
     502           0 :     double  fScanLeft = aRect.Left();
     503           0 :     double  fScanTop = aRect.Top();
     504           0 :     double  fScanRight = aRect.Right();
     505           0 :     double  fScanBottom = aRect.Bottom();
     506           0 :     double fScanIncX = (double) aRect.GetWidth() / (double) nSteps * 0.5;
     507           0 :     double fScanIncY = (double) aRect.GetHeight() / (double) nSteps * 0.5;
     508             : 
     509             :     // all gradients are rendered as nested rectangles which shrink
     510             :     // equally in each dimension - except for 'square' gradients
     511             :     // which shrink to a central vertex but are not per-se square.
     512           0 :     if( rGradient.GetStyle() != GradientStyle_SQUARE )
     513             :     {
     514           0 :         fScanIncY = std::min( fScanIncY, fScanIncX );
     515           0 :         fScanIncX = fScanIncY;
     516             :     }
     517           0 :     sal_uInt8   nRed = (sal_uInt8) nStartRed, nGreen = (sal_uInt8) nStartGreen, nBlue = (sal_uInt8) nStartBlue;
     518           0 :     bool    bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
     519             : 
     520           0 :     mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     521             : 
     522           0 :     if( xPolyPoly )
     523             :     {
     524           0 :         xPolyPoly->Insert( aPoly = rRect );
     525           0 :         xPolyPoly->Insert( aPoly );
     526             :     }
     527             :     else
     528             :     {
     529             :         // extend rect, to avoid missing bounding line
     530           0 :         Rectangle aExtRect( rRect );
     531             : 
     532           0 :         aExtRect.Left() -= 1;
     533           0 :         aExtRect.Top() -= 1;
     534           0 :         aExtRect.Right() += 1;
     535           0 :         aExtRect.Bottom() += 1;
     536             : 
     537           0 :         ImplDrawPolygon( aPoly = aExtRect, pClixPolyPoly );
     538             :     }
     539             : 
     540             :     // loop to output Polygone/PolyPolygone sequentially
     541           0 :     for( long i = 1; i < nSteps; i++ )
     542             :     {
     543             :         // calculate new Polygon
     544           0 :         aRect.Left() = (long)( fScanLeft += fScanIncX );
     545           0 :         aRect.Top() = (long)( fScanTop += fScanIncY );
     546           0 :         aRect.Right() = (long)( fScanRight -= fScanIncX );
     547           0 :         aRect.Bottom() = (long)( fScanBottom -= fScanIncY );
     548             : 
     549           0 :         if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) )
     550           0 :             break;
     551             : 
     552           0 :         if( rGradient.GetStyle() == GradientStyle_RADIAL || rGradient.GetStyle() == GradientStyle_ELLIPTICAL )
     553           0 :             aPoly = Polygon( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
     554             :         else
     555           0 :             aPoly = Polygon( aRect );
     556             : 
     557           0 :         aPoly.Rotate( aCenter, nAngle );
     558             : 
     559             :         // adapt colour accordingly
     560           0 :         const long nStepIndex = ( ( xPolyPoly ) ? i : ( i + 1 ) );
     561           0 :         nRed = GetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) / nSteps ) );
     562           0 :         nGreen = GetGradientColorValue( nStartGreen + ( ( nGreenSteps * nStepIndex ) / nSteps ) );
     563           0 :         nBlue = GetGradientColorValue( nStartBlue + ( ( nBlueSteps * nStepIndex ) / nSteps ) );
     564             : 
     565             :         // either slow tools::PolyPolygon output or fast Polygon-Paiting
     566           0 :         if( xPolyPoly )
     567             :         {
     568           0 :             bPaintLastPolygon = true; // #107349# Paint last polygon only if loop has generated any output
     569             : 
     570           0 :             xPolyPoly->Replace( xPolyPoly->GetObject( 1 ), 0 );
     571           0 :             xPolyPoly->Replace( aPoly, 1 );
     572             : 
     573           0 :             ImplDrawPolyPolygon( *xPolyPoly, pClixPolyPoly );
     574             : 
     575             :             // #107349# Set fill color _after_ geometry painting:
     576             :             // xPolyPoly's geometry is the band from last iteration's
     577             :             // aPoly to current iteration's aPoly. The window outdev
     578             :             // path (see else below), on the other hand, paints the
     579             :             // full aPoly. Thus, here, we're painting the band before
     580             :             // the one painted in the window outdev path below. To get
     581             :             // matching colors, have to delay color setting here.
     582           0 :             mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     583             :         }
     584             :         else
     585             :         {
     586             :             // #107349# Set fill color _before_ geometry painting
     587           0 :             mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     588             : 
     589           0 :             ImplDrawPolygon( aPoly, pClixPolyPoly );
     590             :         }
     591             :     }
     592             : 
     593             :     // we should draw last inner Polygon if we output PolyPolygon
     594           0 :     if( xPolyPoly )
     595             :     {
     596           0 :         const Polygon& rPoly = xPolyPoly->GetObject( 1 );
     597             : 
     598           0 :         if( !rPoly.GetBoundRect().IsEmpty() )
     599             :         {
     600             :             // #107349# Paint last polygon with end color only if loop
     601             :             // has generated output. Otherwise, the current
     602             :             // (i.e. start) color is taken, to generate _any_ output.
     603           0 :             if( bPaintLastPolygon )
     604             :             {
     605           0 :                 nRed = GetGradientColorValue( nEndRed );
     606           0 :                 nGreen = GetGradientColorValue( nEndGreen );
     607           0 :                 nBlue = GetGradientColorValue( nEndBlue );
     608             :             }
     609             : 
     610           0 :             mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     611           0 :             ImplDrawPolygon( rPoly, pClixPolyPoly );
     612             :         }
     613           0 :     }
     614           0 : }
     615             : 
     616           0 : void OutputDevice::DrawLinearGradientToMetafile( const Rectangle& rRect,
     617             :                                                  const Gradient& rGradient )
     618             : {
     619           0 :     assert_if_double_buffered_window();
     620             : 
     621             :     // get BoundRect of rotated rectangle
     622           0 :     Rectangle aRect;
     623           0 :     Point     aCenter;
     624           0 :     sal_uInt16    nAngle = rGradient.GetAngle() % 3600;
     625             : 
     626           0 :     rGradient.GetBoundRect( rRect, aRect, aCenter );
     627             : 
     628           0 :     bool bLinear = (rGradient.GetStyle() == GradientStyle_LINEAR);
     629           0 :     double fBorder = rGradient.GetBorder() * aRect.GetHeight() / 100.0;
     630           0 :     if ( !bLinear )
     631             :     {
     632           0 :         fBorder /= 2.0;
     633             :     }
     634           0 :     Rectangle aMirrorRect = aRect; // used in style axial
     635           0 :     aMirrorRect.Top() = ( aRect.Top() + aRect.Bottom() ) / 2;
     636           0 :     if ( !bLinear )
     637             :     {
     638           0 :         aRect.Bottom() = aMirrorRect.Top();
     639             :     }
     640             : 
     641             :     // colour-intensities of start- and finish; change if needed
     642             :     long    nFactor;
     643           0 :     Color   aStartCol   = rGradient.GetStartColor();
     644           0 :     Color   aEndCol     = rGradient.GetEndColor();
     645           0 :     long    nStartRed   = aStartCol.GetRed();
     646           0 :     long    nStartGreen = aStartCol.GetGreen();
     647           0 :     long    nStartBlue  = aStartCol.GetBlue();
     648           0 :     long    nEndRed     = aEndCol.GetRed();
     649           0 :     long    nEndGreen   = aEndCol.GetGreen();
     650           0 :     long    nEndBlue    = aEndCol.GetBlue();
     651           0 :             nFactor     = rGradient.GetStartIntensity();
     652           0 :             nStartRed   = (nStartRed   * nFactor) / 100;
     653           0 :             nStartGreen = (nStartGreen * nFactor) / 100;
     654           0 :             nStartBlue  = (nStartBlue  * nFactor) / 100;
     655           0 :             nFactor     = rGradient.GetEndIntensity();
     656           0 :             nEndRed     = (nEndRed   * nFactor) / 100;
     657           0 :             nEndGreen   = (nEndGreen * nFactor) / 100;
     658           0 :             nEndBlue    = (nEndBlue  * nFactor) / 100;
     659             : 
     660             :     // gradient style axial has exchanged start and end colors
     661           0 :     if ( !bLinear)
     662             :     {
     663           0 :         long nTempColor = nStartRed;
     664           0 :         nStartRed = nEndRed;
     665           0 :         nEndRed = nTempColor;
     666           0 :         nTempColor = nStartGreen;
     667           0 :         nStartGreen = nEndGreen;
     668           0 :         nEndGreen = nTempColor;
     669           0 :         nTempColor = nStartBlue;
     670           0 :         nStartBlue = nEndBlue;
     671           0 :         nEndBlue = nTempColor;
     672             :     }
     673             : 
     674             :     sal_uInt8   nRed;
     675             :     sal_uInt8   nGreen;
     676             :     sal_uInt8   nBlue;
     677             : 
     678             :     // Create border
     679           0 :     Rectangle aBorderRect = aRect;
     680           0 :     Polygon     aPoly( 4 );
     681           0 :     if (fBorder > 0.0)
     682             :     {
     683           0 :         nRed        = (sal_uInt8)nStartRed;
     684           0 :         nGreen      = (sal_uInt8)nStartGreen;
     685           0 :         nBlue       = (sal_uInt8)nStartBlue;
     686             : 
     687           0 :         mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
     688             : 
     689           0 :         aBorderRect.Bottom() = (long)( aBorderRect.Top() + fBorder );
     690           0 :         aRect.Top() = aBorderRect.Bottom();
     691           0 :         aPoly[0] = aBorderRect.TopLeft();
     692           0 :         aPoly[1] = aBorderRect.TopRight();
     693           0 :         aPoly[2] = aBorderRect.BottomRight();
     694           0 :         aPoly[3] = aBorderRect.BottomLeft();
     695           0 :         aPoly.Rotate( aCenter, nAngle );
     696             : 
     697           0 :         mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
     698             : 
     699           0 :         if ( !bLinear)
     700             :         {
     701           0 :             aBorderRect = aMirrorRect;
     702           0 :             aBorderRect.Top() = (long) ( aBorderRect.Bottom() - fBorder );
     703           0 :             aMirrorRect.Bottom() = aBorderRect.Top();
     704           0 :             aPoly[0] = aBorderRect.TopLeft();
     705           0 :             aPoly[1] = aBorderRect.TopRight();
     706           0 :             aPoly[2] = aBorderRect.BottomRight();
     707           0 :             aPoly[3] = aBorderRect.BottomLeft();
     708           0 :             aPoly.Rotate( aCenter, nAngle );
     709             : 
     710           0 :             mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
     711             :         }
     712             :     }
     713             : 
     714           0 :     bool    bMtf = true;
     715           0 :     long    nStepCount  = GetGradientSteps( rGradient, aRect, bMtf );
     716             : 
     717             :     // minimal three steps and maximal as max color steps
     718           0 :     long   nAbsRedSteps   = std::abs( nEndRed   - nStartRed );
     719           0 :     long   nAbsGreenSteps = std::abs( nEndGreen - nStartGreen );
     720           0 :     long   nAbsBlueSteps  = std::abs( nEndBlue  - nStartBlue );
     721           0 :     long   nMaxColorSteps = std::max( nAbsRedSteps , nAbsGreenSteps );
     722           0 :     nMaxColorSteps = std::max( nMaxColorSteps, nAbsBlueSteps );
     723           0 :     long nSteps = std::min( nStepCount, nMaxColorSteps );
     724           0 :     if ( nSteps < 3)
     725             :     {
     726           0 :         nSteps = 3;
     727             :     }
     728             : 
     729           0 :     double fScanInc = ((double)aRect.GetHeight()) / (double) nSteps;
     730           0 :     double fGradientLine = (double)aRect.Top();
     731           0 :     double fMirrorGradientLine = (double) aMirrorRect.Bottom();
     732             : 
     733           0 :     const double fStepsMinus1 = ((double)nSteps) - 1.0;
     734           0 :     if ( !bLinear)
     735             :     {
     736           0 :         nSteps -= 1; // draw middle polygons as one polygon after loop to avoid gap
     737             :     }
     738           0 :     for ( long i = 0; i < nSteps; i++ )
     739             :     {
     740             :         // linear interpolation of color
     741           0 :         double fAlpha = ((double)i) / fStepsMinus1;
     742           0 :         double fTempColor = ((double)nStartRed) * (1.0-fAlpha) + ((double)nEndRed) * fAlpha;
     743           0 :         nRed = GetGradientColorValue((long)fTempColor);
     744           0 :         fTempColor = ((double)nStartGreen) * (1.0-fAlpha) + ((double)nEndGreen) * fAlpha;
     745           0 :         nGreen = GetGradientColorValue((long)fTempColor);
     746           0 :         fTempColor = ((double)nStartBlue) * (1.0-fAlpha) + ((double)nEndBlue) * fAlpha;
     747           0 :         nBlue = GetGradientColorValue((long)fTempColor);
     748             : 
     749           0 :         mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
     750             : 
     751             :         // Polygon for this color step
     752           0 :         aRect.Top() = (long)( fGradientLine + ((double) i) * fScanInc );
     753           0 :         aRect.Bottom() = (long)( fGradientLine + ( ((double) i) + 1.0 ) * fScanInc );
     754           0 :         aPoly[0] = aRect.TopLeft();
     755           0 :         aPoly[1] = aRect.TopRight();
     756           0 :         aPoly[2] = aRect.BottomRight();
     757           0 :         aPoly[3] = aRect.BottomLeft();
     758           0 :         aPoly.Rotate( aCenter, nAngle );
     759             : 
     760           0 :         mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
     761             : 
     762           0 :         if ( !bLinear )
     763             :         {
     764           0 :             aMirrorRect.Bottom() = (long)( fMirrorGradientLine - ((double) i) * fScanInc );
     765           0 :             aMirrorRect.Top() = (long)( fMirrorGradientLine - (((double) i) + 1.0)* fScanInc );
     766           0 :             aPoly[0] = aMirrorRect.TopLeft();
     767           0 :             aPoly[1] = aMirrorRect.TopRight();
     768           0 :             aPoly[2] = aMirrorRect.BottomRight();
     769           0 :             aPoly[3] = aMirrorRect.BottomLeft();
     770           0 :             aPoly.Rotate( aCenter, nAngle );
     771             : 
     772           0 :             mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
     773             :         }
     774             :     }
     775           0 :     if ( !bLinear)
     776             :     {
     777             :         // draw middle polygon with end color
     778           0 :         nRed = GetGradientColorValue(nEndRed);
     779           0 :         nGreen = GetGradientColorValue(nEndGreen);
     780           0 :         nBlue = GetGradientColorValue(nEndBlue);
     781             : 
     782           0 :         mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
     783             : 
     784           0 :         aRect.Top() = (long)( fGradientLine + ((double)nSteps) * fScanInc );
     785           0 :         aRect.Bottom() = (long)( fMirrorGradientLine - ((double) nSteps) * fScanInc );
     786           0 :         aPoly[0] = aRect.TopLeft();
     787           0 :         aPoly[1] = aRect.TopRight();
     788           0 :         aPoly[2] = aRect.BottomRight();
     789           0 :         aPoly[3] = aRect.BottomLeft();
     790           0 :         aPoly.Rotate( aCenter, nAngle );
     791             : 
     792           0 :         mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
     793           0 :     }
     794           0 : }
     795             : 
     796           0 : void OutputDevice::DrawComplexGradientToMetafile( const Rectangle& rRect,
     797             :                                                   const Gradient& rGradient )
     798             : {
     799           0 :     assert_if_double_buffered_window();
     800             : 
     801             :     // Determine if we output via Polygon or PolyPolygon
     802             :     // For all rasteroperations other then Overpaint always use PolyPolygon,
     803             :     // as we will get wrong results if we output multiple times on top of each other.
     804             :     // Also for printers always use PolyPolygon, as not all printers
     805             :     // can print polygons on top of each other.
     806             : 
     807           0 :     std::unique_ptr<tools::PolyPolygon> xPolyPoly;
     808           0 :     Rectangle       aRect;
     809           0 :     Point           aCenter;
     810           0 :     Color           aStartCol( rGradient.GetStartColor() );
     811           0 :     Color           aEndCol( rGradient.GetEndColor() );
     812           0 :     long            nStartRed = ( (long) aStartCol.GetRed() * rGradient.GetStartIntensity() ) / 100;
     813           0 :     long            nStartGreen = ( (long) aStartCol.GetGreen() * rGradient.GetStartIntensity() ) / 100;
     814           0 :     long            nStartBlue = ( (long) aStartCol.GetBlue() * rGradient.GetStartIntensity() ) / 100;
     815           0 :     long            nEndRed = ( (long) aEndCol.GetRed() * rGradient.GetEndIntensity() ) / 100;
     816           0 :     long            nEndGreen = ( (long) aEndCol.GetGreen() * rGradient.GetEndIntensity() ) / 100;
     817           0 :     long            nEndBlue = ( (long) aEndCol.GetBlue() * rGradient.GetEndIntensity() ) / 100;
     818           0 :     long            nRedSteps = nEndRed - nStartRed;
     819           0 :     long            nGreenSteps = nEndGreen - nStartGreen;
     820           0 :     long            nBlueSteps = nEndBlue   - nStartBlue;
     821           0 :     sal_uInt16      nAngle = rGradient.GetAngle() % 3600;
     822             : 
     823           0 :     rGradient.GetBoundRect( rRect, aRect, aCenter );
     824             : 
     825           0 :     xPolyPoly.reset(new tools::PolyPolygon( 2 ));
     826             : 
     827             :     // last parameter - true if complex gradient, false if linear
     828           0 :     long nStepCount = GetGradientSteps( rGradient, rRect, true, true );
     829             : 
     830             :     // at least three steps and at most the number of colour differences
     831           0 :     long nSteps = std::max( nStepCount, 2L );
     832           0 :     long nCalcSteps  = std::abs( nRedSteps );
     833           0 :     long nTempSteps = std::abs( nGreenSteps );
     834           0 :     if ( nTempSteps > nCalcSteps )
     835           0 :         nCalcSteps = nTempSteps;
     836           0 :     nTempSteps = std::abs( nBlueSteps );
     837           0 :     if ( nTempSteps > nCalcSteps )
     838           0 :         nCalcSteps = nTempSteps;
     839           0 :     if ( nCalcSteps < nSteps )
     840           0 :         nSteps = nCalcSteps;
     841           0 :     if ( !nSteps )
     842           0 :         nSteps = 1;
     843             : 
     844             :     // determine output limits and stepsizes for all directions
     845           0 :     Polygon aPoly;
     846           0 :     double  fScanLeft = aRect.Left();
     847           0 :     double  fScanTop = aRect.Top();
     848           0 :     double  fScanRight = aRect.Right();
     849           0 :     double  fScanBottom = aRect.Bottom();
     850           0 :     double fScanIncX = (double) aRect.GetWidth() / (double) nSteps * 0.5;
     851           0 :     double fScanIncY = (double) aRect.GetHeight() / (double) nSteps * 0.5;
     852             : 
     853             :     // all gradients are rendered as nested rectangles which shrink
     854             :     // equally in each dimension - except for 'square' gradients
     855             :     // which shrink to a central vertex but are not per-se square.
     856           0 :     if( rGradient.GetStyle() != GradientStyle_SQUARE )
     857             :     {
     858           0 :         fScanIncY = std::min( fScanIncY, fScanIncX );
     859           0 :         fScanIncX = fScanIncY;
     860             :     }
     861           0 :     sal_uInt8   nRed = (sal_uInt8) nStartRed, nGreen = (sal_uInt8) nStartGreen, nBlue = (sal_uInt8) nStartBlue;
     862           0 :     bool    bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
     863             : 
     864           0 :     mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
     865             : 
     866           0 :     xPolyPoly->Insert( aPoly = rRect );
     867           0 :     xPolyPoly->Insert( aPoly );
     868             : 
     869             :     // loop to output Polygone/PolyPolygone sequentially
     870           0 :     for( long i = 1; i < nSteps; i++ )
     871             :     {
     872             :         // calculate new Polygon
     873           0 :         aRect.Left() = (long)( fScanLeft += fScanIncX );
     874           0 :         aRect.Top() = (long)( fScanTop += fScanIncY );
     875           0 :         aRect.Right() = (long)( fScanRight -= fScanIncX );
     876           0 :         aRect.Bottom() = (long)( fScanBottom -= fScanIncY );
     877             : 
     878           0 :         if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) )
     879           0 :             break;
     880             : 
     881           0 :         if( rGradient.GetStyle() == GradientStyle_RADIAL || rGradient.GetStyle() == GradientStyle_ELLIPTICAL )
     882           0 :             aPoly = Polygon( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
     883             :         else
     884           0 :             aPoly = Polygon( aRect );
     885             : 
     886           0 :         aPoly.Rotate( aCenter, nAngle );
     887             : 
     888             :         // adapt colour accordingly
     889           0 :         const long nStepIndex = ( ( xPolyPoly ) ? i : ( i + 1 ) );
     890           0 :         nRed = GetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) / nSteps ) );
     891           0 :         nGreen = GetGradientColorValue( nStartGreen + ( ( nGreenSteps * nStepIndex ) / nSteps ) );
     892           0 :         nBlue = GetGradientColorValue( nStartBlue + ( ( nBlueSteps * nStepIndex ) / nSteps ) );
     893             : 
     894           0 :         bPaintLastPolygon = true; // #107349# Paint last polygon only if loop has generated any output
     895             : 
     896           0 :         xPolyPoly->Replace( xPolyPoly->GetObject( 1 ), 0 );
     897           0 :         xPolyPoly->Replace( aPoly, 1 );
     898             : 
     899           0 :         mpMetaFile->AddAction( new MetaPolyPolygonAction( *xPolyPoly ) );
     900             : 
     901             :         // #107349# Set fill color _after_ geometry painting:
     902             :         // xPolyPoly's geometry is the band from last iteration's
     903             :         // aPoly to current iteration's aPoly. The window outdev
     904             :         // path (see else below), on the other hand, paints the
     905             :         // full aPoly. Thus, here, we're painting the band before
     906             :         // the one painted in the window outdev path below. To get
     907             :         // matching colors, have to delay color setting here.
     908           0 :         mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
     909             :     }
     910             : 
     911           0 :     const Polygon& rPoly = xPolyPoly->GetObject( 1 );
     912             : 
     913           0 :     if( !rPoly.GetBoundRect().IsEmpty() )
     914             :     {
     915             :         // #107349# Paint last polygon with end color only if loop
     916             :         // has generated output. Otherwise, the current
     917             :         // (i.e. start) color is taken, to generate _any_ output.
     918           0 :         if( bPaintLastPolygon )
     919             :         {
     920           0 :             nRed = GetGradientColorValue( nEndRed );
     921           0 :             nGreen = GetGradientColorValue( nEndGreen );
     922           0 :             nBlue = GetGradientColorValue( nEndBlue );
     923             :         }
     924             : 
     925           0 :         mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
     926           0 :         mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) );
     927           0 :     }
     928           0 : }
     929             : 
     930       78541 : long OutputDevice::GetGradientStepCount( long nMinRect )
     931             : {
     932       78541 :     long nInc = (nMinRect < 50) ? 2 : 4;
     933             : 
     934       78541 :     return nInc;
     935             : }
     936             : 
     937       78545 : long OutputDevice::GetGradientSteps( const Gradient& rGradient, const Rectangle& rRect, bool bMtf, bool bComplex )
     938             : {
     939             :     // calculate step count
     940       78545 :     long nStepCount  = rGradient.GetSteps();
     941             :     long nMinRect;
     942             : 
     943             :     // generate nStepCount, if not passed
     944       78545 :     if (bComplex)
     945           0 :         nMinRect = std::min( rRect.GetWidth(), rRect.GetHeight() );
     946             :     else
     947       78545 :         nMinRect = rRect.GetHeight();
     948             : 
     949       78545 :     if ( !nStepCount )
     950             :     {
     951             :         long nInc;
     952             : 
     953       78541 :         nInc = GetGradientStepCount (nMinRect);
     954       78541 :         if ( !nInc || bMtf )
     955           0 :             nInc = 1;
     956       78541 :         nStepCount = nMinRect / nInc;
     957             :     }
     958             : 
     959       78545 :     return nStepCount;
     960             : }
     961             : 
     962           0 : Color OutputDevice::GetSingleColorGradientFill()
     963             : {
     964           0 :     Color aColor;
     965             : 
     966             :     // we should never call on this function if any of these aren't set!
     967             :     assert( mnDrawMode & ( DrawModeFlags::BlackGradient | DrawModeFlags::WhiteGradient | DrawModeFlags::SettingsGradient) );
     968             : 
     969           0 :     if ( mnDrawMode & DrawModeFlags::BlackGradient )
     970           0 :         aColor = Color( COL_BLACK );
     971           0 :     else if ( mnDrawMode & DrawModeFlags::WhiteGradient )
     972           0 :         aColor = Color( COL_WHITE );
     973           0 :     else if ( mnDrawMode & DrawModeFlags::SettingsGradient )
     974           0 :         aColor = GetSettings().GetStyleSettings().GetWindowColor();
     975             : 
     976           0 :     if ( mnDrawMode & DrawModeFlags::GhostedGradient )
     977             :     {
     978           0 :         aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
     979           0 :                         ( aColor.GetGreen() >> 1 ) | 0x80,
     980           0 :                         ( aColor.GetBlue() >> 1 ) | 0x80 );
     981             :     }
     982             : 
     983           0 :     return aColor;
     984             : }
     985             : 
     986           9 : void OutputDevice::SetGrayscaleColors( Gradient &rGradient )
     987             : {
     988             :     // this should only be called with the drawing mode is for grayscale or ghosted gradients
     989             :     assert ( mnDrawMode & ( DrawModeFlags::GrayGradient | DrawModeFlags::GhostedGradient ) );
     990             : 
     991           9 :     Color aStartCol( rGradient.GetStartColor() );
     992           9 :     Color aEndCol( rGradient.GetEndColor() );
     993             : 
     994           9 :     if ( mnDrawMode & DrawModeFlags::GrayGradient )
     995             :     {
     996           9 :         sal_uInt8 cStartLum = aStartCol.GetLuminance(), cEndLum = aEndCol.GetLuminance();
     997           9 :         aStartCol = Color( cStartLum, cStartLum, cStartLum );
     998           9 :         aEndCol = Color( cEndLum, cEndLum, cEndLum );
     999             :     }
    1000             : 
    1001           9 :     if ( mnDrawMode & DrawModeFlags::GhostedGradient )
    1002             :     {
    1003           0 :         aStartCol = Color( ( aStartCol.GetRed() >> 1 ) | 0x80,
    1004           0 :                            ( aStartCol.GetGreen() >> 1 ) | 0x80,
    1005           0 :                            ( aStartCol.GetBlue() >> 1 ) | 0x80 );
    1006             : 
    1007           0 :         aEndCol = Color( ( aEndCol.GetRed() >> 1 ) | 0x80,
    1008           0 :                          ( aEndCol.GetGreen() >> 1 ) | 0x80,
    1009           0 :                          ( aEndCol.GetBlue() >> 1 ) | 0x80 );
    1010             :     }
    1011             : 
    1012           9 :     rGradient.SetStartColor( aStartCol );
    1013           9 :     rGradient.SetEndColor( aEndCol );
    1014           9 : }
    1015             : 
    1016           0 : void OutputDevice::AddGradientActions( const Rectangle& rRect, const Gradient& rGradient,
    1017             :                                        GDIMetaFile& rMtf )
    1018             : {
    1019             : 
    1020           0 :     Rectangle aRect( rRect );
    1021             : 
    1022           0 :     aRect.Justify();
    1023             : 
    1024             :     // do nothing if the rectangle is empty
    1025           0 :     if ( !aRect.IsEmpty() )
    1026             :     {
    1027           0 :         Gradient        aGradient( rGradient );
    1028           0 :         GDIMetaFile*    pOldMtf = mpMetaFile;
    1029             : 
    1030           0 :         mpMetaFile = &rMtf;
    1031           0 :         mpMetaFile->AddAction( new MetaPushAction( PushFlags::ALL ) );
    1032           0 :         mpMetaFile->AddAction( new MetaISectRectClipRegionAction( aRect ) );
    1033           0 :         mpMetaFile->AddAction( new MetaLineColorAction( Color(), false ) );
    1034             : 
    1035             :         // because we draw with no border line, we have to expand gradient
    1036             :         // rect to avoid missing lines on the right and bottom edge
    1037           0 :         aRect.Left()--;
    1038           0 :         aRect.Top()--;
    1039           0 :         aRect.Right()++;
    1040           0 :         aRect.Bottom()++;
    1041             : 
    1042             :         // calculate step count if necessary
    1043           0 :         if ( !aGradient.GetSteps() )
    1044           0 :             aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
    1045             : 
    1046           0 :         if( aGradient.GetStyle() == GradientStyle_LINEAR || aGradient.GetStyle() == GradientStyle_AXIAL )
    1047           0 :             DrawLinearGradientToMetafile( aRect, aGradient );
    1048             :         else
    1049           0 :             DrawComplexGradientToMetafile( aRect, aGradient );
    1050             : 
    1051           0 :         mpMetaFile->AddAction( new MetaPopAction() );
    1052           0 :         mpMetaFile = pOldMtf;
    1053             :     }
    1054         801 : }
    1055             : 
    1056             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11