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

Generated by: LCOV version 1.10