LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/vcl/source/gdi - outdev4.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 233 706 33.0 %
Date: 2013-07-09 Functions: 11 16 68.8 %
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             : 
      21             : #include <tools/debug.hxx>
      22             : #include <tools/line.hxx>
      23             : #include <tools/poly.hxx>
      24             : 
      25             : #include <vcl/gradient.hxx>
      26             : #include <vcl/metaact.hxx>
      27             : #include <vcl/gdimtf.hxx>
      28             : #include <vcl/salbtype.hxx>
      29             : #include <vcl/hatch.hxx>
      30             : #include <vcl/window.hxx>
      31             : #include <vcl/virdev.hxx>
      32             : #include <vcl/outdev.hxx>
      33             : 
      34             : #include "pdfwriter_impl.hxx"
      35             : 
      36             : #include "window.h"
      37             : #include "salframe.hxx"
      38             : #include "salgdi.hxx"
      39             : #include "svdata.hxx"
      40             : #include "outdata.hxx"
      41             : 
      42             : #include <basegfx/polygon/b2dpolygon.hxx>
      43             : #include <basegfx/polygon/b2dpolypolygon.hxx>
      44             : #include <basegfx/matrix/b2dhommatrix.hxx>
      45             : 
      46             : #define HATCH_MAXPOINTS             1024
      47             : #define GRADIENT_DEFAULT_STEPCOUNT  0
      48             : 
      49       12257 : extern "C" int SAL_CALL ImplHatchCmpFnc( const void* p1, const void* p2 )
      50             : {
      51       12257 :     const long nX1 = ( (Point*) p1 )->X();
      52       12257 :     const long nX2 = ( (Point*) p2 )->X();
      53       12257 :     const long nY1 = ( (Point*) p1 )->Y();
      54       12257 :     const long nY2 = ( (Point*) p2 )->Y();
      55             : 
      56       12257 :     return ( nX1 > nX2 ? 1 : nX1 == nX2 ? nY1 > nY2 ? 1: nY1 == nY2 ? 0 : -1 : -1 );
      57             : }
      58             : 
      59             : DBG_NAMEEX( OutputDevice )
      60             : DBG_NAMEEX( Gradient )
      61             : 
      62     1439948 : void OutputDevice::ImplDrawPolygon( const Polygon& rPoly, const PolyPolygon* pClipPolyPoly )
      63             : {
      64     1439948 :     if( pClipPolyPoly )
      65           0 :         ImplDrawPolyPolygon( rPoly, pClipPolyPoly );
      66             :     else
      67             :     {
      68     1439948 :         sal_uInt16 nPoints = rPoly.GetSize();
      69             : 
      70     1439948 :         if ( nPoints < 2 )
      71     1439948 :             return;
      72             : 
      73     1439948 :         const SalPoint* pPtAry = (const SalPoint*)rPoly.GetConstPointAry();
      74     1439948 :         mpGraphics->DrawPolygon( nPoints, pPtAry, this );
      75             :     }
      76             : }
      77             : 
      78           0 : void OutputDevice::ImplDrawPolyPolygon( const PolyPolygon& rPolyPoly, const PolyPolygon* pClipPolyPoly )
      79             : {
      80             :     PolyPolygon* pPolyPoly;
      81             : 
      82           0 :     if( pClipPolyPoly )
      83             :     {
      84           0 :         pPolyPoly = new PolyPolygon;
      85           0 :         rPolyPoly.GetIntersection( *pClipPolyPoly, *pPolyPoly );
      86             :     }
      87             :     else
      88           0 :         pPolyPoly = (PolyPolygon*) &rPolyPoly;
      89             : 
      90           0 :     if( pPolyPoly->Count() == 1 )
      91             :     {
      92           0 :         const Polygon   rPoly = pPolyPoly->GetObject( 0 );
      93           0 :         sal_uInt16          nSize = rPoly.GetSize();
      94             : 
      95           0 :         if( nSize >= 2 )
      96             :         {
      97           0 :             const SalPoint* pPtAry = (const SalPoint*)rPoly.GetConstPointAry();
      98           0 :             mpGraphics->DrawPolygon( nSize, pPtAry, this );
      99           0 :         }
     100             :     }
     101           0 :     else if( pPolyPoly->Count() )
     102             :     {
     103           0 :         sal_uInt16              nCount = pPolyPoly->Count();
     104           0 :         sal_uInt32*         pPointAry = new sal_uInt32[nCount];
     105           0 :         PCONSTSALPOINT*     pPointAryAry = new PCONSTSALPOINT[nCount];
     106           0 :         sal_uInt16              i = 0;
     107           0 :         do
     108             :         {
     109           0 :             const Polygon&  rPoly = pPolyPoly->GetObject( i );
     110           0 :             sal_uInt16          nSize = rPoly.GetSize();
     111           0 :             if ( nSize )
     112             :             {
     113           0 :                 pPointAry[i]    = nSize;
     114           0 :                 pPointAryAry[i] = (PCONSTSALPOINT)rPoly.GetConstPointAry();
     115           0 :                 i++;
     116             :             }
     117             :             else
     118           0 :                 nCount--;
     119             :         }
     120             :         while( i < nCount );
     121             : 
     122           0 :         if( nCount == 1 )
     123           0 :             mpGraphics->DrawPolygon( *pPointAry, *pPointAryAry, this );
     124             :         else
     125           0 :             mpGraphics->DrawPolyPolygon( nCount, pPointAry, pPointAryAry, this );
     126             : 
     127           0 :         delete[] pPointAry;
     128           0 :         delete[] pPointAryAry;
     129             :     }
     130             : 
     131           0 :     if( pClipPolyPoly )
     132           0 :         delete pPolyPoly;
     133           0 : }
     134             : 
     135     4299198 : inline sal_uInt8 ImplGetGradientColorValue( long nValue )
     136             : {
     137     4299198 :     if ( nValue < 0 )
     138           0 :         return 0;
     139     4299198 :     else if ( nValue > 0xFF )
     140           0 :         return 0xFF;
     141             :     else
     142     4299198 :         return (sal_uInt8)nValue;
     143             : }
     144             : 
     145       69547 : void OutputDevice::ImplDrawLinearGradient( const Rectangle& rRect,
     146             :                                            const Gradient& rGradient,
     147             :                                            sal_Bool bMtf, const PolyPolygon* pClipPolyPoly )
     148             : {
     149             :     // rotiertes BoundRect ausrechnen
     150       69547 :     Rectangle aRect;
     151       69547 :     Point     aCenter;
     152       69547 :     sal_uInt16    nAngle = rGradient.GetAngle() % 3600;
     153             : 
     154       69547 :     rGradient.GetBoundRect( rRect, aRect, aCenter );
     155             : 
     156             :     // Rand berechnen und Rechteck neu setzen
     157       69547 :     Rectangle   aFullRect = aRect;
     158       69547 :     long        nBorder = (long)rGradient.GetBorder() * aRect.GetHeight() / 100;
     159             : 
     160             :     // Rand berechnen und Rechteck neu setzen fuer linearen Farbverlauf
     161       69547 :     bool bLinear = (rGradient.GetStyle() == GradientStyle_LINEAR);
     162       69547 :     if ( bLinear )
     163             :     {
     164       69547 :         aRect.Top() += nBorder;
     165             :     }
     166             :     // Rand berechnen und Rechteck neu setzen fuer axiale Farbverlauf
     167             :     else
     168             :     {
     169           0 :         nBorder >>= 1;
     170             : 
     171           0 :         aRect.Top()    += nBorder;
     172           0 :         aRect.Bottom() -= nBorder;
     173             :     }
     174             : 
     175             :     // Top darf nicht groesser als Bottom sein
     176       69547 :     aRect.Top() = std::min( aRect.Top(), (long)(aRect.Bottom() - 1) );
     177             : 
     178       69547 :     long nMinRect = aRect.GetHeight();
     179             : 
     180             :     // Intensitaeten von Start- und Endfarbe ggf. aendern und
     181             :     // Farbschrittweiten berechnen
     182             :     long            nFactor;
     183       69547 :     Color           aStartCol   = rGradient.GetStartColor();
     184       69547 :     Color           aEndCol     = rGradient.GetEndColor();
     185       69547 :     long            nStartRed   = aStartCol.GetRed();
     186       69547 :     long            nStartGreen = aStartCol.GetGreen();
     187       69547 :     long            nStartBlue  = aStartCol.GetBlue();
     188       69547 :     long            nEndRed     = aEndCol.GetRed();
     189       69547 :     long            nEndGreen   = aEndCol.GetGreen();
     190       69547 :     long            nEndBlue    = aEndCol.GetBlue();
     191       69547 :                     nFactor     = rGradient.GetStartIntensity();
     192       69547 :                     nStartRed   = (nStartRed   * nFactor) / 100;
     193       69547 :                     nStartGreen = (nStartGreen * nFactor) / 100;
     194       69547 :                     nStartBlue  = (nStartBlue  * nFactor) / 100;
     195       69547 :                     nFactor     = rGradient.GetEndIntensity();
     196       69547 :                     nEndRed     = (nEndRed   * nFactor) / 100;
     197       69547 :                     nEndGreen   = (nEndGreen * nFactor) / 100;
     198       69547 :                     nEndBlue    = (nEndBlue  * nFactor) / 100;
     199       69547 :     long            nRedSteps   = nEndRed   - nStartRed;
     200       69547 :     long            nGreenSteps = nEndGreen - nStartGreen;
     201       69547 :     long            nBlueSteps  = nEndBlue  - nStartBlue;
     202       69547 :     long            nStepCount = rGradient.GetSteps();
     203             : 
     204             :     // Bei nicht linearen Farbverlaeufen haben wir nur die halben Steps
     205             :     // pro Farbe
     206       69547 :     if ( !bLinear )
     207             :     {
     208           0 :         nRedSteps   <<= 1;
     209           0 :         nGreenSteps <<= 1;
     210           0 :         nBlueSteps  <<= 1;
     211             :     }
     212             : 
     213             :     // Anzahl der Schritte berechnen, falls nichts uebergeben wurde
     214       69547 :     if ( !nStepCount )
     215             :     {
     216             :         long nInc;
     217             : 
     218       69547 :         if ( meOutDevType != OUTDEV_PRINTER && !bMtf )
     219             :         {
     220       69547 :             nInc = (nMinRect < 50) ? 2 : 4;
     221             :         }
     222             :         else
     223             :         {
     224             :             // #105998# Use display-equivalent step size calculation
     225           0 :             nInc = (nMinRect < 800) ? 10 : 20;
     226             :         }
     227             : 
     228       69547 :         nStepCount = nMinRect / nInc;
     229             :     }
     230             :     // minimal drei Schritte und maximal die Anzahl der Farbunterschiede
     231       69547 :     long nSteps = std::max( nStepCount, 2L );
     232       69547 :     long nCalcSteps  = std::abs( nRedSteps );
     233       69547 :     long nTempSteps = std::abs( nGreenSteps );
     234       69547 :     if ( nTempSteps > nCalcSteps )
     235           0 :         nCalcSteps = nTempSteps;
     236       69547 :     nTempSteps = std::abs( nBlueSteps );
     237       69547 :     if ( nTempSteps > nCalcSteps )
     238           0 :         nCalcSteps = nTempSteps;
     239       69547 :     if ( nCalcSteps < nSteps )
     240        2895 :         nSteps = nCalcSteps;
     241       69547 :     if ( !nSteps )
     242          22 :         nSteps = 1;
     243             : 
     244             :     // Falls axialer Farbverlauf, muss die Schrittanzahl ungerade sein
     245       69547 :     if ( !bLinear && !(nSteps & 1) )
     246           0 :         nSteps++;
     247             : 
     248             :     // Berechnung ueber Double-Addition wegen Genauigkeit
     249       69547 :     double fScanLine = aRect.Top();
     250       69547 :     double fScanInc  = (double)aRect.GetHeight() / (double)nSteps;
     251             : 
     252             :     // Startfarbe berechnen und setzen
     253             :     sal_uInt8   nRed;
     254             :     sal_uInt8   nGreen;
     255             :     sal_uInt8   nBlue;
     256             :     long    nSteps2;
     257       69547 :     long    nStepsHalf = 0;
     258       69547 :     if ( bLinear )
     259             :     {
     260             :         // Um 1 erhoeht, um die Border innerhalb der Schleife
     261             :         // zeichnen zu koennen
     262       69547 :         nSteps2     = nSteps + 1;
     263       69547 :         nRed        = (sal_uInt8)nStartRed;
     264       69547 :         nGreen      = (sal_uInt8)nStartGreen;
     265       69547 :         nBlue       = (sal_uInt8)nStartBlue;
     266             :     }
     267             :     else
     268             :     {
     269             :         // Um 2 erhoeht, um die Border innerhalb der Schleife
     270             :         // zeichnen zu koennen
     271           0 :         nSteps2     = nSteps + 2;
     272           0 :         nRed        = (sal_uInt8)nEndRed;
     273           0 :         nGreen      = (sal_uInt8)nEndGreen;
     274           0 :         nBlue       = (sal_uInt8)nEndBlue;
     275           0 :         nStepsHalf  = nSteps >> 1;
     276             :     }
     277             : 
     278       69547 :     if ( bMtf )
     279           0 :         mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) );
     280             :     else
     281       69547 :         mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     282             : 
     283             :     // Startpolygon erzeugen (== Borderpolygon)
     284       69547 :     Polygon     aPoly( 4 );
     285      139094 :     Polygon     aTempPoly( 2 );
     286      139094 :     Polygon     aTempPoly2( 2 );
     287             :     /* n#710061 Use overlapping fills to avoid color
     288             :      * leak via gaps in some pdf viewers
     289             :      */
     290       69547 :     Point       aOverLap( 0, fScanInc*.1 );
     291       69547 :     aPoly[0] = aFullRect.TopLeft();
     292       69547 :     aPoly[1] = aFullRect.TopRight();
     293       69547 :     aPoly[2] = aRect.TopRight();
     294       69547 :     aPoly[3] = aRect.TopLeft();
     295       69547 :     aPoly.Rotate( aCenter, nAngle );
     296       69547 :     aTempPoly[0] = aPoly[3];
     297       69547 :     aTempPoly[1] = aPoly[2];
     298             : 
     299             : 
     300             :     // Schleife, um rotierten Verlauf zu fuellen
     301     1502613 :     for ( long i = 0; i < nSteps2; i++ )
     302             :     {
     303             :         // berechnetesPolygon ausgeben
     304     1433066 :         if ( bMtf )
     305           0 :             mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
     306             :         else
     307     1433066 :             ImplDrawPolygon( aPoly, pClipPolyPoly );
     308             : 
     309             :         // neues Polygon berechnen
     310     1433066 :         aRect.Top() = (long)(fScanLine += fScanInc);
     311             : 
     312     1433066 :         aPoly[0] = aTempPoly[0];
     313     1433066 :         aPoly[1] = aTempPoly[1];
     314             :         // unteren Rand komplett fuellen
     315     1433066 :         if ( i == nSteps )
     316             :         {
     317       69547 :             aTempPoly[0] = aFullRect.BottomLeft();
     318       69547 :             aTempPoly[1] = aFullRect.BottomRight();
     319       69547 :             aTempPoly2   = aTempPoly;
     320             :         }
     321             :         else
     322             :         {
     323     1363519 :             aTempPoly[0] = aRect.TopLeft();
     324     1363519 :             aTempPoly[1] = aRect.TopRight();
     325     1363519 :             aTempPoly2[0]= aTempPoly[0] + aOverLap;
     326     1363519 :             aTempPoly2[1]= aTempPoly[1] + aOverLap;
     327             :         }
     328     1433066 :         aTempPoly2.Rotate( aCenter, nAngle );
     329     1433066 :         aTempPoly.Rotate( aCenter, nAngle );
     330             : 
     331     1433066 :         aPoly[2] = aTempPoly2[1];
     332     1433066 :         aPoly[3] = aTempPoly2[0];
     333             : 
     334             :         // Farbintensitaeten aendern...
     335             :         // fuer lineare FV
     336     1433066 :         if ( bLinear )
     337             :         {
     338     1433066 :             nRed    = ImplGetGradientColorValue( nStartRed+((nRedSteps*i)/nSteps2) );
     339     1433066 :             nGreen  = ImplGetGradientColorValue( nStartGreen+((nGreenSteps*i)/nSteps2) );
     340     1433066 :             nBlue   = ImplGetGradientColorValue( nStartBlue+((nBlueSteps*i)/nSteps2) );
     341             :         }
     342             :         // fuer radiale FV
     343             :         else
     344             :         {
     345             :             // fuer axiale FV muss die letzte Farbe der ersten
     346             :             // Farbe entsprechen
     347             :             // #107350# Setting end color one step earlier, as the
     348             :             // last time we get here, we drop out of the loop later
     349             :             // on.
     350           0 :             if ( i >= nSteps )
     351             :             {
     352           0 :                 nRed    = (sal_uInt8)nEndRed;
     353           0 :                 nGreen  = (sal_uInt8)nEndGreen;
     354           0 :                 nBlue   = (sal_uInt8)nEndBlue;
     355             :             }
     356             :             else
     357             :             {
     358           0 :                 if ( i <= nStepsHalf )
     359             :                 {
     360           0 :                     nRed    = ImplGetGradientColorValue( nEndRed-((nRedSteps*i)/nSteps2) );
     361           0 :                     nGreen  = ImplGetGradientColorValue( nEndGreen-((nGreenSteps*i)/nSteps2) );
     362           0 :                     nBlue   = ImplGetGradientColorValue( nEndBlue-((nBlueSteps*i)/nSteps2) );
     363             :                 }
     364             :                 // genau die Mitte und hoeher
     365             :                 else
     366             :                 {
     367           0 :                     long i2 = i - nStepsHalf;
     368           0 :                     nRed    = ImplGetGradientColorValue( nStartRed+((nRedSteps*i2)/nSteps2) );
     369           0 :                     nGreen  = ImplGetGradientColorValue( nStartGreen+((nGreenSteps*i2)/nSteps2) );
     370           0 :                     nBlue   = ImplGetGradientColorValue( nStartBlue+((nBlueSteps*i2)/nSteps2) );
     371             :                 }
     372             :             }
     373             :         }
     374             : 
     375     1433066 :         if ( bMtf )
     376           0 :             mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) );
     377             :         else
     378     1433066 :             mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     379       69547 :     }
     380       69547 : }
     381             : 
     382           0 : void OutputDevice::ImplDrawComplexGradient( const Rectangle& rRect,
     383             :                                             const Gradient& rGradient,
     384             :                                             sal_Bool bMtf, const PolyPolygon* pClipPolyPoly )
     385             : {
     386             :     // Feststellen ob Ausgabe ueber Polygon oder PolyPolygon
     387             :     // Bei Rasteroperationen ungleich Overpaint immer PolyPolygone,
     388             :     // da es zu falschen Ergebnissen kommt, wenn man mehrfach uebereinander
     389             :     // ausgibt
     390             :     // Bei Druckern auch immer PolyPolygone, da nicht alle Drucker
     391             :     // das Uebereinanderdrucken von Polygonen koennen
     392             :     // Virtuelle Device werden auch ausgeklammert, da einige Treiber
     393             :     // ansonsten zu langsam sind
     394             :     PolyPolygon*    pPolyPoly;
     395           0 :     Rectangle       aRect;
     396           0 :     Point           aCenter;
     397           0 :     Color           aStartCol( rGradient.GetStartColor() );
     398           0 :     Color           aEndCol( rGradient.GetEndColor() );
     399           0 :     long            nStartRed = ( (long) aStartCol.GetRed() * rGradient.GetStartIntensity() ) / 100;
     400           0 :     long            nStartGreen = ( (long) aStartCol.GetGreen() * rGradient.GetStartIntensity() ) / 100;
     401           0 :     long            nStartBlue = ( (long) aStartCol.GetBlue() * rGradient.GetStartIntensity() ) / 100;
     402           0 :     long            nEndRed = ( (long) aEndCol.GetRed() * rGradient.GetEndIntensity() ) / 100;
     403           0 :     long            nEndGreen = ( (long) aEndCol.GetGreen() * rGradient.GetEndIntensity() ) / 100;
     404           0 :     long            nEndBlue = ( (long) aEndCol.GetBlue() * rGradient.GetEndIntensity() ) / 100;
     405           0 :     long            nRedSteps = nEndRed - nStartRed;
     406           0 :     long            nGreenSteps = nEndGreen - nStartGreen;
     407           0 :     long            nBlueSteps = nEndBlue   - nStartBlue;
     408           0 :     long            nStepCount = rGradient.GetSteps();
     409           0 :     sal_uInt16          nAngle = rGradient.GetAngle() % 3600;
     410             : 
     411           0 :     rGradient.GetBoundRect( rRect, aRect, aCenter );
     412             : 
     413           0 :     if( (meRasterOp != ROP_OVERPAINT) || (meOutDevType != OUTDEV_WINDOW) || bMtf )
     414           0 :         pPolyPoly = new PolyPolygon( 2 );
     415             :     else
     416           0 :         pPolyPoly = NULL;
     417             : 
     418           0 :     long nMinRect = std::min( aRect.GetWidth(), aRect.GetHeight() );
     419             : 
     420             :     // Anzahl der Schritte berechnen, falls nichts uebergeben wurde
     421           0 :     if( !nStepCount )
     422             :     {
     423             :         long nInc;
     424             : 
     425           0 :         if ( meOutDevType != OUTDEV_PRINTER && !bMtf )
     426             :         {
     427           0 :             nInc = ( nMinRect < 50 ) ? 2 : 4;
     428             :         }
     429             :         else
     430             :         {
     431             :             // #105998# Use display-equivalent step size calculation
     432           0 :             nInc = (nMinRect < 800) ? 10 : 20;
     433             :         }
     434             : 
     435           0 :         nStepCount = nMinRect / nInc;
     436             :     }
     437             : 
     438             :     // minimal drei Schritte und maximal die Anzahl der Farbunterschiede
     439           0 :     long nSteps = std::max( nStepCount, 2L );
     440           0 :     long nCalcSteps  = std::abs( nRedSteps );
     441           0 :     long nTempSteps = std::abs( nGreenSteps );
     442           0 :     if ( nTempSteps > nCalcSteps )
     443           0 :         nCalcSteps = nTempSteps;
     444           0 :     nTempSteps = std::abs( nBlueSteps );
     445           0 :     if ( nTempSteps > nCalcSteps )
     446           0 :         nCalcSteps = nTempSteps;
     447           0 :     if ( nCalcSteps < nSteps )
     448           0 :         nSteps = nCalcSteps;
     449           0 :     if ( !nSteps )
     450           0 :         nSteps = 1;
     451             : 
     452             :     // Ausgabebegrenzungen und Schrittweite fuer jede Richtung festlegen
     453           0 :     Polygon aPoly;
     454           0 :     double  fScanLeft = aRect.Left();
     455           0 :     double  fScanTop = aRect.Top();
     456           0 :     double  fScanRight = aRect.Right();
     457           0 :     double  fScanBottom = aRect.Bottom();
     458           0 :     double  fScanIncX = (double) aRect.GetWidth() / (double) nSteps * 0.5;
     459           0 :     double  fScanIncY = (double) aRect.GetHeight() / (double) nSteps * 0.5;
     460             : 
     461             :     // all gradients are rendered as nested rectangles which shrink
     462             :     // equally in each dimension - except for 'square' gradients
     463             :     // which shrink to a central vertex but are not per-se square.
     464           0 :     if( rGradient.GetStyle() != GradientStyle_SQUARE )
     465             :     {
     466           0 :         fScanIncY = std::min( fScanIncY, fScanIncX );
     467           0 :         fScanIncX = fScanIncY;
     468             :     }
     469             : 
     470           0 :     sal_uInt8   nRed = (sal_uInt8) nStartRed, nGreen = (sal_uInt8) nStartGreen, nBlue = (sal_uInt8) nStartBlue;
     471           0 :     bool    bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
     472             : 
     473           0 :     if( bMtf )
     474           0 :         mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) );
     475             :     else
     476           0 :         mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     477             : 
     478           0 :     if( pPolyPoly )
     479             :     {
     480           0 :         pPolyPoly->Insert( aPoly = rRect );
     481           0 :         pPolyPoly->Insert( aPoly );
     482             :     }
     483             :     else
     484             :     {
     485             :         // extend rect, to avoid missing bounding line
     486           0 :         Rectangle aExtRect( rRect );
     487             : 
     488           0 :         aExtRect.Left() -= 1;
     489           0 :         aExtRect.Top() -= 1;
     490           0 :         aExtRect.Right() += 1;
     491           0 :         aExtRect.Bottom() += 1;
     492             : 
     493           0 :         ImplDrawPolygon( aPoly = aExtRect, pClipPolyPoly );
     494             :     }
     495             : 
     496             :     // Schleife, um nacheinander die Polygone/PolyPolygone auszugeben
     497           0 :     for( long i = 1; i < nSteps; i++ )
     498             :     {
     499             :         // neues Polygon berechnen
     500           0 :         aRect.Left() = (long)( fScanLeft += fScanIncX );
     501           0 :         aRect.Top() = (long)( fScanTop += fScanIncY );
     502           0 :         aRect.Right() = (long)( fScanRight -= fScanIncX );
     503           0 :         aRect.Bottom() = (long)( fScanBottom -= fScanIncY );
     504             : 
     505           0 :         if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) )
     506           0 :             break;
     507             : 
     508           0 :         if( rGradient.GetStyle() == GradientStyle_RADIAL || rGradient.GetStyle() == GradientStyle_ELLIPTICAL )
     509           0 :             aPoly = Polygon( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
     510             :         else
     511           0 :             aPoly = Polygon( aRect );
     512             : 
     513           0 :         aPoly.Rotate( aCenter, nAngle );
     514             : 
     515             :         // Farbe entsprechend anpassen
     516           0 :         const long nStepIndex = ( ( pPolyPoly != NULL ) ? i : ( i + 1 ) );
     517           0 :         nRed = ImplGetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) / nSteps ) );
     518           0 :         nGreen = ImplGetGradientColorValue( nStartGreen + ( ( nGreenSteps * nStepIndex ) / nSteps ) );
     519           0 :         nBlue = ImplGetGradientColorValue( nStartBlue + ( ( nBlueSteps * nStepIndex ) / nSteps ) );
     520             : 
     521             :         // entweder langsame PolyPolygon-Ausgaben oder schnelles Polygon-Painting
     522           0 :         if( pPolyPoly )
     523             :         {
     524           0 :             bPaintLastPolygon = true; // #107349# Paint last polygon only if loop has generated any output
     525             : 
     526           0 :             pPolyPoly->Replace( pPolyPoly->GetObject( 1 ), 0 );
     527           0 :             pPolyPoly->Replace( aPoly, 1 );
     528             : 
     529           0 :             if( bMtf )
     530           0 :                 mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) );
     531             :             else
     532           0 :                 ImplDrawPolyPolygon( *pPolyPoly, pClipPolyPoly );
     533             : 
     534             :             // #107349# Set fill color _after_ geometry painting:
     535             :             // pPolyPoly's geometry is the band from last iteration's
     536             :             // aPoly to current iteration's aPoly. The window outdev
     537             :             // path (see else below), on the other hand, paints the
     538             :             // full aPoly. Thus, here, we're painting the band before
     539             :             // the one painted in the window outdev path below. To get
     540             :             // matching colors, have to delay color setting here.
     541           0 :             if( bMtf )
     542           0 :                 mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) );
     543             :             else
     544           0 :                 mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     545             :         }
     546             :         else
     547             :         {
     548             :             // #107349# Set fill color _before_ geometry painting
     549           0 :             if( bMtf )
     550           0 :                 mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) );
     551             :             else
     552           0 :                 mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     553             : 
     554           0 :             ImplDrawPolygon( aPoly, pClipPolyPoly );
     555             :         }
     556             :     }
     557             : 
     558             :     // Falls PolyPolygon-Ausgabe, muessen wir noch ein letztes inneres Polygon zeichnen
     559           0 :     if( pPolyPoly )
     560             :     {
     561           0 :         const Polygon& rPoly = pPolyPoly->GetObject( 1 );
     562             : 
     563           0 :         if( !rPoly.GetBoundRect().IsEmpty() )
     564             :         {
     565             :             // #107349# Paint last polygon with end color only if loop
     566             :             // has generated output. Otherwise, the current
     567             :             // (i.e. start) color is taken, to generate _any_ output.
     568           0 :             if( bPaintLastPolygon )
     569             :             {
     570           0 :                 nRed = ImplGetGradientColorValue( nEndRed );
     571           0 :                 nGreen = ImplGetGradientColorValue( nEndGreen );
     572           0 :                 nBlue = ImplGetGradientColorValue( nEndBlue );
     573             :             }
     574             : 
     575           0 :             if( bMtf )
     576             :             {
     577           0 :                 mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) );
     578           0 :                 mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) );
     579             :             }
     580             :             else
     581             :             {
     582           0 :                 mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
     583           0 :                    ImplDrawPolygon( rPoly, pClipPolyPoly );
     584             :             }
     585             :         }
     586             : 
     587           0 :         delete pPolyPoly;
     588           0 :     }
     589           0 : }
     590             : 
     591      155413 : void OutputDevice::DrawGradient( const Rectangle& rRect,
     592             :                                  const Gradient& rGradient )
     593             : {
     594             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
     595             :     DBG_CHKOBJ( &rGradient, Gradient, NULL );
     596             : 
     597      155413 :     if ( mnDrawMode & DRAWMODE_NOGRADIENT )
     598           0 :         return;
     599      155413 :     else if ( mnDrawMode & ( DRAWMODE_BLACKGRADIENT | DRAWMODE_WHITEGRADIENT | DRAWMODE_SETTINGSGRADIENT) )
     600             :     {
     601           0 :         Color aColor;
     602             : 
     603           0 :         if ( mnDrawMode & DRAWMODE_BLACKGRADIENT )
     604           0 :             aColor = Color( COL_BLACK );
     605           0 :         else if ( mnDrawMode & DRAWMODE_WHITEGRADIENT )
     606           0 :             aColor = Color( COL_WHITE );
     607           0 :         else if ( mnDrawMode & DRAWMODE_SETTINGSGRADIENT )
     608           0 :             aColor = GetSettings().GetStyleSettings().GetWindowColor();
     609             : 
     610           0 :         if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT )
     611             :         {
     612           0 :             aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
     613           0 :                             ( aColor.GetGreen() >> 1 ) | 0x80,
     614           0 :                             ( aColor.GetBlue() >> 1 ) | 0x80 );
     615             :         }
     616             : 
     617           0 :         Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
     618           0 :         SetLineColor( aColor );
     619           0 :         SetFillColor( aColor );
     620           0 :         DrawRect( rRect );
     621           0 :         Pop();
     622           0 :         return;
     623             :     }
     624             : 
     625      155413 :     Gradient aGradient( rGradient );
     626             : 
     627      155413 :     if ( mnDrawMode & ( DRAWMODE_GRAYGRADIENT | DRAWMODE_GHOSTEDGRADIENT ) )
     628             :     {
     629           0 :         Color aStartCol( aGradient.GetStartColor() );
     630           0 :         Color aEndCol( aGradient.GetEndColor() );
     631             : 
     632           0 :         if ( mnDrawMode & DRAWMODE_GRAYGRADIENT )
     633             :         {
     634           0 :             sal_uInt8 cStartLum = aStartCol.GetLuminance(), cEndLum = aEndCol.GetLuminance();
     635           0 :             aStartCol = Color( cStartLum, cStartLum, cStartLum );
     636           0 :             aEndCol = Color( cEndLum, cEndLum, cEndLum );
     637             :         }
     638             : 
     639           0 :         if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT )
     640             :         {
     641           0 :             aStartCol = Color( ( aStartCol.GetRed() >> 1 ) | 0x80,
     642           0 :                                ( aStartCol.GetGreen() >> 1 ) | 0x80,
     643           0 :                                ( aStartCol.GetBlue() >> 1 ) | 0x80 );
     644             : 
     645           0 :             aEndCol = Color( ( aEndCol.GetRed() >> 1 ) | 0x80,
     646           0 :                              ( aEndCol.GetGreen() >> 1 ) | 0x80,
     647           0 :                              ( aEndCol.GetBlue() >> 1 ) | 0x80 );
     648             :         }
     649             : 
     650           0 :         aGradient.SetStartColor( aStartCol );
     651           0 :         aGradient.SetEndColor( aEndCol );
     652             :     }
     653             : 
     654      155413 :     if( mpMetaFile )
     655           0 :         mpMetaFile->AddAction( new MetaGradientAction( rRect, aGradient ) );
     656             : 
     657      155413 :     if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
     658           0 :         return;
     659             : 
     660             :     // Rechteck in Pixel umrechnen
     661      155413 :     Rectangle aRect( ImplLogicToDevicePixel( rRect ) );
     662      155413 :     aRect.Justify();
     663             : 
     664             :     // Wenn Rechteck leer ist, brauchen wir nichts machen
     665      155413 :     if ( !aRect.IsEmpty() )
     666             :     {
     667             :         // Clip Region sichern
     668      155413 :         Push( PUSH_CLIPREGION );
     669      155413 :         IntersectClipRegion( rRect );
     670             : 
     671             :         // because we draw with no border line, we have to expand gradient
     672             :         // rect to avoid missing lines on the right and bottom edge
     673      155413 :         aRect.Left()--;
     674      155413 :         aRect.Top()--;
     675      155413 :         aRect.Right()++;
     676      155413 :         aRect.Bottom()++;
     677             : 
     678             :         // we need a graphics
     679      155413 :         if ( !mpGraphics )
     680             :         {
     681           0 :             if ( !ImplGetGraphics() )
     682           0 :                 return;
     683             :         }
     684             : 
     685      155413 :         if ( mbInitClipRegion )
     686      155413 :             ImplInitClipRegion();
     687             : 
     688      155413 :         if ( !mbOutputClipped )
     689             :         {
     690             :             // Gradienten werden ohne Umrandung gezeichnet
     691       69547 :             if ( mbLineColor || mbInitLineColor )
     692             :             {
     693       69534 :                 mpGraphics->SetLineColor();
     694       69534 :                 mbInitLineColor = sal_True;
     695             :             }
     696             : 
     697       69547 :             mbInitFillColor = sal_True;
     698             : 
     699             :             // calculate step count if necessary
     700       69547 :             if ( !aGradient.GetSteps() )
     701       69547 :                 aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
     702             : 
     703       69547 :             if( aGradient.GetStyle() == GradientStyle_LINEAR || aGradient.GetStyle() == GradientStyle_AXIAL )
     704       69547 :                 ImplDrawLinearGradient( aRect, aGradient, sal_False, NULL );
     705             :             else
     706           0 :                 ImplDrawComplexGradient( aRect, aGradient, sal_False, NULL );
     707             :         }
     708             : 
     709      155413 :         Pop();
     710             :     }
     711             : 
     712      155413 :     if( mpAlphaVDev )
     713             :     {
     714             :         // #i32109#: Make gradient area opaque
     715           0 :         mpAlphaVDev->ImplFillOpaqueRectangle( rRect );
     716      155413 :     }
     717             : }
     718             : 
     719           0 : void OutputDevice::DrawGradient( const PolyPolygon& rPolyPoly,
     720             :                                  const Gradient& rGradient )
     721             : {
     722             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
     723             :     DBG_CHKOBJ( &rGradient, Gradient, NULL );
     724             : 
     725           0 :     if( mbInitClipRegion )
     726           0 :         ImplInitClipRegion();
     727             : 
     728           0 :     if( mbOutputClipped )
     729           0 :         return;
     730             : 
     731           0 :     if( !mpGraphics )
     732           0 :         if( !ImplGetGraphics() )
     733           0 :             return;
     734             : 
     735           0 :     if( rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize() && !( mnDrawMode & DRAWMODE_NOGRADIENT ) )
     736             :     {
     737           0 :         if ( mnDrawMode & ( DRAWMODE_BLACKGRADIENT | DRAWMODE_WHITEGRADIENT | DRAWMODE_SETTINGSGRADIENT) )
     738             :         {
     739           0 :             Color aColor;
     740             : 
     741           0 :             if ( mnDrawMode & DRAWMODE_BLACKGRADIENT )
     742           0 :                 aColor = Color( COL_BLACK );
     743           0 :             else if ( mnDrawMode & DRAWMODE_WHITEGRADIENT )
     744           0 :                 aColor = Color( COL_WHITE );
     745           0 :             else if ( mnDrawMode & DRAWMODE_SETTINGSGRADIENT )
     746           0 :                 aColor = GetSettings().GetStyleSettings().GetWindowColor();
     747             : 
     748           0 :             if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT )
     749             :             {
     750           0 :                 aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
     751           0 :                                 ( aColor.GetGreen() >> 1 ) | 0x80,
     752           0 :                                 ( aColor.GetBlue() >> 1 ) | 0x80 );
     753             :             }
     754             : 
     755           0 :             Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
     756           0 :             SetLineColor( aColor );
     757           0 :             SetFillColor( aColor );
     758           0 :             DrawPolyPolygon( rPolyPoly );
     759           0 :             Pop();
     760           0 :             return;
     761             :         }
     762             : 
     763           0 :         if( mpMetaFile )
     764             :         {
     765           0 :             const Rectangle aRect( rPolyPoly.GetBoundRect() );
     766             : 
     767           0 :             mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_BEGIN" ) );
     768           0 :             mpMetaFile->AddAction( new MetaGradientExAction( rPolyPoly, rGradient ) );
     769             : 
     770           0 :             if( OUTDEV_PRINTER == meOutDevType )
     771             :             {
     772           0 :                 Push( PUSH_CLIPREGION );
     773           0 :                 IntersectClipRegion(Region(rPolyPoly));
     774           0 :                 DrawGradient( aRect, rGradient );
     775           0 :                 Pop();
     776             :             }
     777             :             else
     778             :             {
     779           0 :                 const sal_Bool  bOldOutput = IsOutputEnabled();
     780             : 
     781           0 :                 EnableOutput( sal_False );
     782           0 :                 Push( PUSH_RASTEROP );
     783           0 :                 SetRasterOp( ROP_XOR );
     784           0 :                 DrawGradient( aRect, rGradient );
     785           0 :                 SetFillColor( COL_BLACK );
     786           0 :                 SetRasterOp( ROP_0 );
     787           0 :                 DrawPolyPolygon( rPolyPoly );
     788           0 :                 SetRasterOp( ROP_XOR );
     789           0 :                 DrawGradient( aRect, rGradient );
     790           0 :                 Pop();
     791           0 :                 EnableOutput( bOldOutput );
     792             :             }
     793             : 
     794           0 :             mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_END" ) );
     795             :         }
     796             : 
     797           0 :         if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
     798           0 :             return;
     799             : 
     800           0 :         Gradient aGradient( rGradient );
     801             : 
     802           0 :         if ( mnDrawMode & ( DRAWMODE_GRAYGRADIENT | DRAWMODE_GHOSTEDGRADIENT ) )
     803             :         {
     804           0 :             Color aStartCol( aGradient.GetStartColor() );
     805           0 :             Color aEndCol( aGradient.GetEndColor() );
     806             : 
     807           0 :             if ( mnDrawMode & DRAWMODE_GRAYGRADIENT )
     808             :             {
     809           0 :                 sal_uInt8 cStartLum = aStartCol.GetLuminance(), cEndLum = aEndCol.GetLuminance();
     810           0 :                 aStartCol = Color( cStartLum, cStartLum, cStartLum );
     811           0 :                 aEndCol = Color( cEndLum, cEndLum, cEndLum );
     812             :             }
     813             : 
     814           0 :             if ( mnDrawMode & DRAWMODE_GHOSTEDGRADIENT )
     815             :             {
     816           0 :                 aStartCol = Color( ( aStartCol.GetRed() >> 1 ) | 0x80,
     817           0 :                                    ( aStartCol.GetGreen() >> 1 ) | 0x80,
     818           0 :                                    ( aStartCol.GetBlue() >> 1 ) | 0x80 );
     819             : 
     820           0 :                 aEndCol = Color( ( aEndCol.GetRed() >> 1 ) | 0x80,
     821           0 :                                  ( aEndCol.GetGreen() >> 1 ) | 0x80,
     822           0 :                                  ( aEndCol.GetBlue() >> 1 ) | 0x80 );
     823             :             }
     824             : 
     825           0 :             aGradient.SetStartColor( aStartCol );
     826           0 :             aGradient.SetEndColor( aEndCol );
     827             :         }
     828             : 
     829           0 :         if( OUTDEV_PRINTER == meOutDevType || ImplGetSVData()->maGDIData.mbNoXORClipping )
     830             :         {
     831           0 :             const Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
     832             : 
     833           0 :             if( !Rectangle( PixelToLogic( Point() ), GetOutputSize() ).IsEmpty() )
     834             :             {
     835             :                 // Rechteck in Pixel umrechnen
     836           0 :                 Rectangle aRect( ImplLogicToDevicePixel( aBoundRect ) );
     837           0 :                 aRect.Justify();
     838             : 
     839             :                 // Wenn Rechteck leer ist, brauchen wir nichts machen
     840           0 :                 if ( !aRect.IsEmpty() )
     841             :                 {
     842           0 :                     if( !mpGraphics && !ImplGetGraphics() )
     843           0 :                         return;
     844             : 
     845           0 :                     if( mbInitClipRegion )
     846           0 :                         ImplInitClipRegion();
     847             : 
     848           0 :                     if( !mbOutputClipped )
     849             :                     {
     850           0 :                         PolyPolygon aClipPolyPoly( ImplLogicToDevicePixel( rPolyPoly ) );
     851             : 
     852             :                         // Gradienten werden ohne Umrandung gezeichnet
     853           0 :                         if( mbLineColor || mbInitLineColor )
     854             :                         {
     855           0 :                             mpGraphics->SetLineColor();
     856           0 :                             mbInitLineColor = sal_True;
     857             :                         }
     858             : 
     859           0 :                         mbInitFillColor = sal_True;
     860             : 
     861             :                         // calculate step count if necessary
     862           0 :                         if ( !aGradient.GetSteps() )
     863           0 :                             aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
     864             : 
     865           0 :                         if( aGradient.GetStyle() == GradientStyle_LINEAR || aGradient.GetStyle() == GradientStyle_AXIAL )
     866           0 :                             ImplDrawLinearGradient( aRect, aGradient, sal_False, &aClipPolyPoly );
     867             :                         else
     868           0 :                             ImplDrawComplexGradient( aRect, aGradient, sal_False, &aClipPolyPoly );
     869             :                     }
     870             :                 }
     871             :             }
     872             :         }
     873             :         else
     874             :         {
     875           0 :             const PolyPolygon   aPolyPoly( LogicToPixel( rPolyPoly ) );
     876           0 :             const Rectangle     aBoundRect( aPolyPoly.GetBoundRect() );
     877           0 :             Point aPoint;
     878           0 :             Rectangle           aDstRect( aPoint, GetOutputSizePixel() );
     879             : 
     880           0 :             aDstRect.Intersection( aBoundRect );
     881             : 
     882           0 :             if( OUTDEV_WINDOW == meOutDevType )
     883             :             {
     884           0 :                 const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() );
     885             : 
     886           0 :                 if( !aPaintRgn.IsNull() )
     887           0 :                     aDstRect.Intersection( LogicToPixel( aPaintRgn ).GetBoundRect() );
     888             :             }
     889             : 
     890           0 :             if( !aDstRect.IsEmpty() )
     891             :             {
     892             :                 VirtualDevice*  pVDev;
     893           0 :                 const Size      aDstSize( aDstRect.GetSize() );
     894             : 
     895           0 :                 if( HasAlpha() )
     896             :                 {
     897             :                     // #110958# Pay attention to alpha VDevs here, otherwise,
     898             :                     // background will be wrong: Temp VDev has to have alpha, too.
     899           0 :                     pVDev = new VirtualDevice( *this, 0, GetAlphaBitCount() > 1 ? 0 : 1 );
     900             :                 }
     901             :                 else
     902             :                 {
     903             :                     // nothing special here. Plain VDev
     904           0 :                     pVDev = new VirtualDevice();
     905             :                 }
     906             : 
     907           0 :                 if( pVDev->SetOutputSizePixel( aDstSize) )
     908             :                 {
     909           0 :                     MapMode         aVDevMap;
     910           0 :                     const sal_Bool      bOldMap = mbMap;
     911             : 
     912           0 :                     EnableMapMode( sal_False );
     913             : 
     914           0 :                     pVDev->DrawOutDev( Point(), aDstSize, aDstRect.TopLeft(), aDstSize, *this );
     915           0 :                     pVDev->SetRasterOp( ROP_XOR );
     916           0 :                     aVDevMap.SetOrigin( Point( -aDstRect.Left(), -aDstRect.Top() ) );
     917           0 :                     pVDev->SetMapMode( aVDevMap );
     918           0 :                     pVDev->DrawGradient( aBoundRect, aGradient );
     919           0 :                     pVDev->SetFillColor( COL_BLACK );
     920           0 :                     pVDev->SetRasterOp( ROP_0 );
     921           0 :                     pVDev->DrawPolyPolygon( aPolyPoly );
     922           0 :                     pVDev->SetRasterOp( ROP_XOR );
     923           0 :                     pVDev->DrawGradient( aBoundRect, aGradient );
     924           0 :                     aVDevMap.SetOrigin( Point() );
     925           0 :                     pVDev->SetMapMode( aVDevMap );
     926           0 :                     DrawOutDev( aDstRect.TopLeft(), aDstSize, Point(), aDstSize, *pVDev );
     927             : 
     928           0 :                     EnableMapMode( bOldMap );
     929             :                 }
     930             : 
     931           0 :                 delete pVDev;
     932           0 :             }
     933           0 :         }
     934             :     }
     935             : 
     936           0 :     if( mpAlphaVDev )
     937           0 :         mpAlphaVDev->DrawPolyPolygon( rPolyPoly );
     938             : }
     939             : 
     940           0 : void OutputDevice::AddGradientActions( const Rectangle& rRect, const Gradient& rGradient,
     941             :                                        GDIMetaFile& rMtf )
     942             : {
     943             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
     944             :     DBG_CHKOBJ( &rGradient, Gradient, NULL );
     945             : 
     946           0 :     Rectangle aRect( rRect );
     947             : 
     948           0 :     aRect.Justify();
     949             : 
     950             :     // Wenn Rechteck leer ist, brauchen wir nichts machen
     951           0 :     if ( !aRect.IsEmpty() )
     952             :     {
     953           0 :         Gradient        aGradient( rGradient );
     954           0 :         GDIMetaFile*    pOldMtf = mpMetaFile;
     955             : 
     956           0 :         mpMetaFile = &rMtf;
     957           0 :         mpMetaFile->AddAction( new MetaPushAction( PUSH_ALL ) );
     958           0 :         mpMetaFile->AddAction( new MetaISectRectClipRegionAction( aRect ) );
     959           0 :         mpMetaFile->AddAction( new MetaLineColorAction( Color(), sal_False ) );
     960             : 
     961             :         // because we draw with no border line, we have to expand gradient
     962             :         // rect to avoid missing lines on the right and bottom edge
     963           0 :         aRect.Left()--;
     964           0 :         aRect.Top()--;
     965           0 :         aRect.Right()++;
     966           0 :         aRect.Bottom()++;
     967             : 
     968             :         // calculate step count if necessary
     969           0 :         if ( !aGradient.GetSteps() )
     970           0 :             aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
     971             : 
     972           0 :         if( aGradient.GetStyle() == GradientStyle_LINEAR || aGradient.GetStyle() == GradientStyle_AXIAL )
     973           0 :             ImplDrawLinearGradient( aRect, aGradient, sal_True, NULL );
     974             :         else
     975           0 :             ImplDrawComplexGradient( aRect, aGradient, sal_True, NULL );
     976             : 
     977           0 :         mpMetaFile->AddAction( new MetaPopAction() );
     978           0 :         mpMetaFile = pOldMtf;
     979             :     }
     980           0 : }
     981             : 
     982         238 : void OutputDevice::DrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch )
     983             : {
     984             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
     985             : 
     986         238 :     Hatch aHatch( rHatch );
     987             : 
     988         238 :     if ( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE |
     989             :                         DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE |
     990             :                         DRAWMODE_SETTINGSLINE ) )
     991             :     {
     992           0 :         Color aColor( rHatch.GetColor() );
     993             : 
     994           0 :         if ( mnDrawMode & DRAWMODE_BLACKLINE )
     995           0 :             aColor = Color( COL_BLACK );
     996           0 :         else if ( mnDrawMode & DRAWMODE_WHITELINE )
     997           0 :             aColor = Color( COL_WHITE );
     998           0 :         else if ( mnDrawMode & DRAWMODE_GRAYLINE )
     999             :         {
    1000           0 :             const sal_uInt8 cLum = aColor.GetLuminance();
    1001           0 :             aColor = Color( cLum, cLum, cLum );
    1002             :         }
    1003           0 :         else if( mnDrawMode & DRAWMODE_SETTINGSLINE )
    1004             :         {
    1005           0 :             aColor = GetSettings().GetStyleSettings().GetFontColor();
    1006             :         }
    1007             : 
    1008           0 :         if ( mnDrawMode & DRAWMODE_GHOSTEDLINE )
    1009             :         {
    1010           0 :             aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
    1011           0 :                             ( aColor.GetGreen() >> 1 ) | 0x80,
    1012           0 :                             ( aColor.GetBlue() >> 1 ) | 0x80);
    1013             :         }
    1014             : 
    1015           0 :         aHatch.SetColor( aColor );
    1016             :     }
    1017             : 
    1018         238 :     if( mpMetaFile )
    1019           0 :         mpMetaFile->AddAction( new MetaHatchAction( rPolyPoly, aHatch ) );
    1020             : 
    1021         238 :     if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
    1022           0 :         return;
    1023             : 
    1024         238 :     if( !mpGraphics && !ImplGetGraphics() )
    1025           0 :         return;
    1026             : 
    1027         238 :     if( mbInitClipRegion )
    1028           0 :         ImplInitClipRegion();
    1029             : 
    1030         238 :     if( mbOutputClipped )
    1031           0 :         return;
    1032             : 
    1033         238 :     if( rPolyPoly.Count() )
    1034             :     {
    1035         238 :         PolyPolygon     aPolyPoly( LogicToPixel( rPolyPoly ) );
    1036         238 :         GDIMetaFile*    pOldMetaFile = mpMetaFile;
    1037         238 :         sal_Bool            bOldMap = mbMap;
    1038             : 
    1039         238 :         aPolyPoly.Optimize( POLY_OPTIMIZE_NO_SAME );
    1040         238 :         aHatch.SetDistance( ImplLogicWidthToDevicePixel( aHatch.GetDistance() ) );
    1041             : 
    1042         238 :         mpMetaFile = NULL;
    1043         238 :         EnableMapMode( sal_False );
    1044         238 :         Push( PUSH_LINECOLOR );
    1045         238 :         SetLineColor( aHatch.GetColor() );
    1046         238 :         ImplInitLineColor();
    1047         238 :         ImplDrawHatch( aPolyPoly, aHatch, sal_False );
    1048         238 :         Pop();
    1049         238 :         EnableMapMode( bOldMap );
    1050         238 :         mpMetaFile = pOldMetaFile;
    1051             :     }
    1052             : 
    1053         238 :     if( mpAlphaVDev )
    1054           0 :         mpAlphaVDev->DrawHatch( rPolyPoly, rHatch );
    1055             : }
    1056             : 
    1057           0 : void OutputDevice::AddHatchActions( const PolyPolygon& rPolyPoly, const Hatch& rHatch,
    1058             :                                     GDIMetaFile& rMtf )
    1059             : {
    1060             :     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
    1061             : 
    1062           0 :     PolyPolygon aPolyPoly( rPolyPoly );
    1063           0 :     aPolyPoly.Optimize( POLY_OPTIMIZE_NO_SAME | POLY_OPTIMIZE_CLOSE );
    1064             : 
    1065           0 :     if( aPolyPoly.Count() )
    1066             :     {
    1067           0 :         GDIMetaFile* pOldMtf = mpMetaFile;
    1068             : 
    1069           0 :         mpMetaFile = &rMtf;
    1070           0 :         mpMetaFile->AddAction( new MetaPushAction( PUSH_ALL ) );
    1071           0 :         mpMetaFile->AddAction( new MetaLineColorAction( rHatch.GetColor(), sal_True ) );
    1072           0 :         ImplDrawHatch( aPolyPoly, rHatch, sal_True );
    1073           0 :         mpMetaFile->AddAction( new MetaPopAction() );
    1074           0 :         mpMetaFile = pOldMtf;
    1075           0 :     }
    1076           0 : }
    1077             : 
    1078         238 : void OutputDevice::ImplDrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch, sal_Bool bMtf )
    1079             : {
    1080         238 :     if(rPolyPoly.Count())
    1081             :     {
    1082             :         // #i115630# ImplDrawHatch does not work with beziers included in the polypolygon, take care of that
    1083         238 :         bool bIsCurve(false);
    1084             : 
    1085         476 :         for(sal_uInt16 a(0); !bIsCurve && a < rPolyPoly.Count(); a++)
    1086             :         {
    1087         238 :             if(rPolyPoly[a].HasFlags())
    1088             :             {
    1089           0 :                 bIsCurve = true;
    1090             :             }
    1091             :         }
    1092             : 
    1093         238 :         if(bIsCurve)
    1094             :         {
    1095             :             OSL_ENSURE(false, "ImplDrawHatch does *not* support curves, falling back to AdaptiveSubdivide()...");
    1096           0 :             PolyPolygon aPolyPoly;
    1097             : 
    1098           0 :             rPolyPoly.AdaptiveSubdivide(aPolyPoly);
    1099           0 :             ImplDrawHatch(aPolyPoly, rHatch, bMtf);
    1100             :         }
    1101             :         else
    1102             :         {
    1103         238 :             Rectangle   aRect( rPolyPoly.GetBoundRect() );
    1104         238 :             const long  nLogPixelWidth = ImplDevicePixelToLogicWidth( 1 );
    1105         238 :             const long  nWidth = ImplDevicePixelToLogicWidth( std::max( ImplLogicWidthToDevicePixel( rHatch.GetDistance() ), 3L ) );
    1106         238 :             Point*      pPtBuffer = new Point[ HATCH_MAXPOINTS ];
    1107         238 :             Point       aPt1, aPt2, aEndPt1;
    1108         238 :             Size        aInc;
    1109             : 
    1110             :             // Single hatch
    1111         238 :             aRect.Left() -= nLogPixelWidth; aRect.Top() -= nLogPixelWidth; aRect.Right() += nLogPixelWidth; aRect.Bottom() += nLogPixelWidth;
    1112         238 :             ImplCalcHatchValues( aRect, nWidth, rHatch.GetAngle(), aPt1, aPt2, aInc, aEndPt1 );
    1113       12495 :             do
    1114             :             {
    1115       12495 :                 ImplDrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer, bMtf );
    1116       12495 :                 aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height();
    1117       12495 :                 aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height();
    1118             :             }
    1119       12495 :             while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) );
    1120             : 
    1121         238 :             if( ( rHatch.GetStyle() == HATCH_DOUBLE ) || ( rHatch.GetStyle() == HATCH_TRIPLE ) )
    1122             :             {
    1123             :                 // Double hatch
    1124           0 :                 ImplCalcHatchValues( aRect, nWidth, rHatch.GetAngle() + 900, aPt1, aPt2, aInc, aEndPt1 );
    1125           0 :                 do
    1126             :                 {
    1127           0 :                     ImplDrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer, bMtf );
    1128           0 :                     aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height();
    1129           0 :                     aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height();
    1130             :                 }
    1131           0 :                 while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) );
    1132             : 
    1133           0 :                 if( rHatch.GetStyle() == HATCH_TRIPLE )
    1134             :                 {
    1135             :                     // Triple hatch
    1136           0 :                     ImplCalcHatchValues( aRect, nWidth, rHatch.GetAngle() + 450, aPt1, aPt2, aInc, aEndPt1 );
    1137           0 :                     do
    1138             :                     {
    1139           0 :                         ImplDrawHatchLine( Line( aPt1, aPt2 ), rPolyPoly, pPtBuffer, bMtf );
    1140           0 :                         aPt1.X() += aInc.Width(); aPt1.Y() += aInc.Height();
    1141           0 :                         aPt2.X() += aInc.Width(); aPt2.Y() += aInc.Height();
    1142             :                     }
    1143           0 :                     while( ( aPt1.X() <= aEndPt1.X() ) && ( aPt1.Y() <= aEndPt1.Y() ) );
    1144             :                 }
    1145             :             }
    1146             : 
    1147         238 :             delete[] pPtBuffer;
    1148             :         }
    1149             :     }
    1150         238 : }
    1151             : 
    1152         238 : void OutputDevice::ImplCalcHatchValues( const Rectangle& rRect, long nDist, sal_uInt16 nAngle10,
    1153             :                                         Point& rPt1, Point& rPt2, Size& rInc, Point& rEndPt1 )
    1154             : {
    1155         238 :     Point   aRef;
    1156         238 :     long    nAngle = nAngle10 % 1800;
    1157         238 :     long    nOffset = 0;
    1158             : 
    1159         238 :     if( nAngle > 900 )
    1160           0 :         nAngle -= 1800;
    1161             : 
    1162         238 :     aRef = ( !IsRefPoint() ? rRect.TopLeft() : GetRefPoint() );
    1163             : 
    1164         238 :     if( 0 == nAngle )
    1165             :     {
    1166         238 :         rInc = Size( 0, nDist );
    1167         238 :         rPt1 = rRect.TopLeft();
    1168         238 :         rPt2 = rRect.TopRight();
    1169         238 :         rEndPt1 = rRect.BottomLeft();
    1170             : 
    1171         238 :         if( aRef.Y() <= rRect.Top() )
    1172         238 :             nOffset = ( ( rRect.Top() - aRef.Y() ) % nDist );
    1173             :         else
    1174           0 :             nOffset = ( nDist - ( ( aRef.Y() - rRect.Top() ) % nDist ) );
    1175             : 
    1176         238 :         rPt1.Y() -= nOffset;
    1177         238 :         rPt2.Y() -= nOffset;
    1178             :     }
    1179           0 :     else if( 900 == nAngle )
    1180             :     {
    1181           0 :         rInc = Size( nDist, 0 );
    1182           0 :         rPt1 = rRect.TopLeft();
    1183           0 :         rPt2 = rRect.BottomLeft();
    1184           0 :         rEndPt1 = rRect.TopRight();
    1185             : 
    1186           0 :         if( aRef.X() <= rRect.Left() )
    1187           0 :             nOffset = ( rRect.Left() - aRef.X() ) % nDist;
    1188             :         else
    1189           0 :             nOffset = nDist - ( ( aRef.X() - rRect.Left() ) % nDist );
    1190             : 
    1191           0 :         rPt1.X() -= nOffset;
    1192           0 :         rPt2.X() -= nOffset;
    1193             :     }
    1194           0 :     else if( nAngle >= -450 && nAngle <= 450 )
    1195             :     {
    1196           0 :         const double    fAngle = F_PI1800 * labs( nAngle );
    1197           0 :         const double    fTan = tan( fAngle );
    1198           0 :         const long      nYOff = FRound( ( rRect.Right() - rRect.Left() ) * fTan );
    1199             :         long            nPY;
    1200             : 
    1201           0 :         rInc = Size( 0, nDist = FRound( nDist / cos( fAngle ) ) );
    1202             : 
    1203           0 :         if( nAngle > 0 )
    1204             :         {
    1205           0 :             rPt1 = rRect.TopLeft();
    1206           0 :             rPt2 = Point( rRect.Right(), rRect.Top() - nYOff );
    1207           0 :             rEndPt1 = Point( rRect.Left(), rRect.Bottom() + nYOff );
    1208           0 :             nPY = FRound( aRef.Y() - ( ( rPt1.X() - aRef.X() ) * fTan ) );
    1209             :         }
    1210             :         else
    1211             :         {
    1212           0 :             rPt1 = rRect.TopRight();
    1213           0 :             rPt2 = Point( rRect.Left(), rRect.Top() - nYOff );
    1214           0 :             rEndPt1 = Point( rRect.Right(), rRect.Bottom() + nYOff );
    1215           0 :             nPY = FRound( aRef.Y() + ( ( rPt1.X() - aRef.X() ) * fTan ) );
    1216             :         }
    1217             : 
    1218           0 :         if( nPY <= rPt1.Y() )
    1219           0 :             nOffset = ( rPt1.Y() - nPY ) % nDist;
    1220             :         else
    1221           0 :             nOffset = nDist - ( ( nPY - rPt1.Y() ) % nDist );
    1222             : 
    1223           0 :         rPt1.Y() -= nOffset;
    1224           0 :         rPt2.Y() -= nOffset;
    1225             :     }
    1226             :     else
    1227             :     {
    1228           0 :         const double fAngle = F_PI1800 * labs( nAngle );
    1229           0 :         const double fTan = tan( fAngle );
    1230           0 :         const long   nXOff = FRound( ( rRect.Bottom() - rRect.Top() ) / fTan );
    1231             :         long         nPX;
    1232             : 
    1233           0 :         rInc = Size( nDist = FRound( nDist / sin( fAngle ) ), 0 );
    1234             : 
    1235           0 :         if( nAngle > 0 )
    1236             :         {
    1237           0 :             rPt1 = rRect.TopLeft();
    1238           0 :             rPt2 = Point( rRect.Left() - nXOff, rRect.Bottom() );
    1239           0 :             rEndPt1 = Point( rRect.Right() + nXOff, rRect.Top() );
    1240           0 :             nPX = FRound( aRef.X() - ( ( rPt1.Y() - aRef.Y() ) / fTan ) );
    1241             :         }
    1242             :         else
    1243             :         {
    1244           0 :             rPt1 = rRect.BottomLeft();
    1245           0 :             rPt2 = Point( rRect.Left() - nXOff, rRect.Top() );
    1246           0 :             rEndPt1 = Point( rRect.Right() + nXOff, rRect.Bottom() );
    1247           0 :             nPX = FRound( aRef.X() + ( ( rPt1.Y() - aRef.Y() ) / fTan ) );
    1248             :         }
    1249             : 
    1250           0 :         if( nPX <= rPt1.X() )
    1251           0 :             nOffset = ( rPt1.X() - nPX ) % nDist;
    1252             :         else
    1253           0 :             nOffset = nDist - ( ( nPX - rPt1.X() ) % nDist );
    1254             : 
    1255           0 :         rPt1.X() -= nOffset;
    1256           0 :         rPt2.X() -= nOffset;
    1257             :     }
    1258         238 : }
    1259             : 
    1260       12495 : void OutputDevice::ImplDrawHatchLine( const Line& rLine, const PolyPolygon& rPolyPoly,
    1261             :                                       Point* pPtBuffer, sal_Bool bMtf )
    1262             : {
    1263             :     double  fX, fY;
    1264       12495 :     long    nAdd, nPCounter = 0;
    1265             : 
    1266       24990 :     for( long nPoly = 0, nPolyCount = rPolyPoly.Count(); nPoly < nPolyCount; nPoly++ )
    1267             :     {
    1268       12495 :         const Polygon& rPoly = rPolyPoly[ (sal_uInt16) nPoly ];
    1269             : 
    1270       12495 :         if( rPoly.GetSize() > 1 )
    1271             :         {
    1272       12495 :             Line    aCurSegment( rPoly[ 0 ], Point() );
    1273             : 
    1274       62475 :             for( long i = 1, nCount = rPoly.GetSize(); i <= nCount; i++ )
    1275             :             {
    1276       49980 :                 aCurSegment.SetEnd( rPoly[ (sal_uInt16)( i % nCount ) ] );
    1277       49980 :                 nAdd = 0;
    1278             : 
    1279       49980 :                 if( rLine.Intersection( aCurSegment, fX, fY ) )
    1280             :                 {
    1281       49028 :                     if( ( fabs( fX - aCurSegment.GetStart().X() ) <= 0.0000001 ) &&
    1282       24514 :                         ( fabs( fY - aCurSegment.GetStart().Y() ) <= 0.0000001 ) )
    1283             :                     {
    1284           0 :                         const Line      aPrevSegment( rPoly[ (sal_uInt16)( ( i > 1 ) ? ( i - 2 ) : ( nCount - 1 ) ) ], aCurSegment.GetStart() );
    1285           0 :                         const double    fPrevDistance = rLine.GetDistance( aPrevSegment.GetStart() );
    1286           0 :                         const double    fCurDistance = rLine.GetDistance( aCurSegment.GetEnd() );
    1287             : 
    1288           0 :                         if( ( fPrevDistance <= 0.0 && fCurDistance > 0.0 ) ||
    1289           0 :                             ( fPrevDistance > 0.0 && fCurDistance < 0.0 ) )
    1290             :                         {
    1291           0 :                             nAdd = 1;
    1292             :                         }
    1293             :                     }
    1294       49028 :                     else if( ( fabs( fX - aCurSegment.GetEnd().X() ) <= 0.0000001 ) &&
    1295       24514 :                              ( fabs( fY - aCurSegment.GetEnd().Y() ) <= 0.0000001 ) )
    1296             :                     {
    1297           0 :                         const Line aNextSegment( aCurSegment.GetEnd(), rPoly[ (sal_uInt16)( ( i + 1 ) % nCount ) ] );
    1298             : 
    1299           0 :                         if( ( fabs( rLine.GetDistance( aNextSegment.GetEnd() ) ) <= 0.0000001 ) &&
    1300           0 :                             ( rLine.GetDistance( aCurSegment.GetStart() ) > 0.0 ) )
    1301             :                         {
    1302           0 :                             nAdd = 1;
    1303             :                         }
    1304             :                     }
    1305             :                     else
    1306       24514 :                         nAdd = 1;
    1307             : 
    1308       24514 :                     if( nAdd )
    1309       24514 :                         pPtBuffer[ nPCounter++ ] = Point( FRound( fX ), FRound( fY ) );
    1310             :                 }
    1311             : 
    1312       49980 :                 aCurSegment.SetStart( aCurSegment.GetEnd() );
    1313             :             }
    1314             :         }
    1315             :     }
    1316             : 
    1317       12495 :     if( nPCounter > 1 )
    1318             :     {
    1319       12257 :         qsort( pPtBuffer, nPCounter, sizeof( Point ), ImplHatchCmpFnc );
    1320             : 
    1321       12257 :         if( nPCounter & 1 )
    1322           0 :             nPCounter--;
    1323             : 
    1324       12257 :         if( bMtf )
    1325             :         {
    1326           0 :             for( long i = 0; i < nPCounter; i += 2 )
    1327           0 :                 mpMetaFile->AddAction( new MetaLineAction( pPtBuffer[ i ], pPtBuffer[ i + 1 ] ) );
    1328             :         }
    1329             :         else
    1330             :         {
    1331       24514 :             for( long i = 0; i < nPCounter; i += 2 )
    1332             :             {
    1333       12257 :                 if( mpPDFWriter )
    1334             :                 {
    1335           0 :                     mpPDFWriter->drawLine( pPtBuffer[ i ], pPtBuffer[ i+1 ] );
    1336             :                 }
    1337             :                 else
    1338             :                 {
    1339       12257 :                     const Point aPt1( ImplLogicToDevicePixel( pPtBuffer[ i ] ) );
    1340       12257 :                     const Point aPt2( ImplLogicToDevicePixel( pPtBuffer[ i + 1 ] ) );
    1341       12257 :                     mpGraphics->DrawLine( aPt1.X(), aPt1.Y(), aPt2.X(), aPt2.Y(), this );
    1342             :                 }
    1343             :             }
    1344             :         }
    1345             :     }
    1346       12960 : }
    1347             : 
    1348             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10