[Libreoffice-commits] core.git: vcl/source

Armin Le Grand alg at apache.org
Fri Jul 12 04:56:07 PDT 2013


 vcl/source/gdi/gradient.cxx |   17 --
 vcl/source/gdi/outdev4.cxx  |  347 ++++++++++++++++++++------------------------
 2 files changed, 166 insertions(+), 198 deletions(-)

New commits:
commit 04d937c1ec36c2d9fa8c90604c81a37d30e97da6
Author: Armin Le Grand <alg at apache.org>
Date:   Sat Jun 8 14:27:01 2013 +0100

    Resolves: #i120957# Added Reginas corrections for gradient colors for...
    
    linear gradients in VCL renderers
    
    Patch by: Regina
    Review by: alg
    
    (cherry picked from commit 94205034afa2abe9ab73b2f5d0c76f295a7889c9)
    
    Conflicts:
    	vcl/source/gdi/outdev4.cxx
    
    Change-Id: I8b66bb1b9155253e138c7ebb4fc3e0686bae7913

diff --git a/vcl/source/gdi/gradient.cxx b/vcl/source/gdi/gradient.cxx
index b4099b5..c1058b2 100644
--- a/vcl/source/gdi/gradient.cxx
+++ b/vcl/source/gdi/gradient.cxx
@@ -194,20 +194,15 @@ void Gradient::GetBoundRect( const Rectangle& rRect, Rectangle& rBoundRect, Poin
 
     if( GetStyle() == GradientStyle_LINEAR || GetStyle() == GradientStyle_AXIAL )
     {
-        aRect.Left()--;
-        aRect.Top()--;
-        aRect.Right()++;
-        aRect.Bottom()++;
-
         const double    fAngle = nAngle * F_PI1800;
         const double    fWidth = aRect.GetWidth();
         const double    fHeight = aRect.GetHeight();
-        double          fDX = fWidth  * fabs( cos( fAngle ) ) + fHeight * fabs( sin( fAngle ) );
-        double          fDY = fHeight * fabs( cos( fAngle ) ) + fWidth  * fabs( sin( fAngle ) );
-
-        fDX = ( fDX - fWidth  ) * 0.5 + 0.5;
-        fDY = ( fDY - fHeight ) * 0.5 + 0.5;
-
+        double  fDX     = fWidth  * fabs( cos( fAngle ) ) +
+                          fHeight * fabs( sin( fAngle ) );
+        double  fDY     = fHeight * fabs( cos( fAngle ) ) +
+                          fWidth  * fabs( sin( fAngle ) );
+                fDX     = (fDX - fWidth)  * 0.5 + 0.5;
+                fDY     = (fDY - fHeight) * 0.5 + 0.5;
         aRect.Left()   -= (long) fDX;
         aRect.Right()  += (long) fDX;
         aRect.Top()    -= (long) fDY;
diff --git a/vcl/source/gdi/outdev4.cxx b/vcl/source/gdi/outdev4.cxx
index 4dd70e6..1be80e9 100644
--- a/vcl/source/gdi/outdev4.cxx
+++ b/vcl/source/gdi/outdev4.cxx
@@ -146,236 +146,210 @@ void OutputDevice::ImplDrawLinearGradient( const Rectangle& rRect,
                                            const Gradient& rGradient,
                                            sal_Bool bMtf, const PolyPolygon* pClipPolyPoly )
 {
-    // rotiertes BoundRect ausrechnen
+    // get BoundRect of rotated rectangle
     Rectangle aRect;
     Point     aCenter;
     sal_uInt16    nAngle = rGradient.GetAngle() % 3600;
 
     rGradient.GetBoundRect( rRect, aRect, aCenter );
 
-    // Rand berechnen und Rechteck neu setzen
-    Rectangle   aFullRect = aRect;
-    long        nBorder = (long)rGradient.GetBorder() * aRect.GetHeight() / 100;
-
-    // Rand berechnen und Rechteck neu setzen fuer linearen Farbverlauf
     bool bLinear = (rGradient.GetStyle() == GradientStyle_LINEAR);
-    if ( bLinear )
+    double fBorder = rGradient.GetBorder() * aRect.GetHeight() / 100.0;
+    if ( !bLinear )
     {
-        aRect.Top() += nBorder;
+        fBorder /= 2.0;
     }
-    // Rand berechnen und Rechteck neu setzen fuer axiale Farbverlauf
-    else
+    Rectangle aMirrorRect = aRect; // used in style axial
+    aMirrorRect.Top() = ( aRect.Top() + aRect.Bottom() ) / 2;
+    if ( !bLinear )
     {
-        nBorder >>= 1;
-
-        aRect.Top()    += nBorder;
-        aRect.Bottom() -= nBorder;
+        aRect.Bottom() = aMirrorRect.Top();
     }
 
-    // Top darf nicht groesser als Bottom sein
-    aRect.Top() = std::min( aRect.Top(), (long)(aRect.Bottom() - 1) );
-
-    long nMinRect = aRect.GetHeight();
+    // Intensitaeten von Start- und Endfarbe ggf. aendern
+    long    nFactor;
+    Color   aStartCol   = rGradient.GetStartColor();
+    Color   aEndCol     = rGradient.GetEndColor();
+    long    nStartRed   = aStartCol.GetRed();
+    long    nStartGreen = aStartCol.GetGreen();
+    long    nStartBlue  = aStartCol.GetBlue();
+    long    nEndRed     = aEndCol.GetRed();
+    long    nEndGreen   = aEndCol.GetGreen();
+    long    nEndBlue    = aEndCol.GetBlue();
+            nFactor     = rGradient.GetStartIntensity();
+            nStartRed   = (nStartRed   * nFactor) / 100;
+            nStartGreen = (nStartGreen * nFactor) / 100;
+            nStartBlue  = (nStartBlue  * nFactor) / 100;
+            nFactor     = rGradient.GetEndIntensity();
+            nEndRed     = (nEndRed   * nFactor) / 100;
+            nEndGreen   = (nEndGreen * nFactor) / 100;
+            nEndBlue    = (nEndBlue  * nFactor) / 100;
+
+    // gradient style axial has exchanged start and end colors
+    if ( !bLinear)
+    {
+        long nTempColor = nStartRed;
+        nStartRed = nEndRed;
+        nEndRed = nTempColor;
+        nTempColor = nStartGreen;
+        nStartGreen = nEndGreen;
+        nEndGreen = nTempColor;
+        nTempColor = nStartBlue;
+        nStartBlue = nEndBlue;
+        nEndBlue = nTempColor;
+    }
 
-    // Intensitaeten von Start- und Endfarbe ggf. aendern und
-    // Farbschrittweiten berechnen
-    long            nFactor;
-    Color           aStartCol   = rGradient.GetStartColor();
-    Color           aEndCol     = rGradient.GetEndColor();
-    long            nStartRed   = aStartCol.GetRed();
-    long            nStartGreen = aStartCol.GetGreen();
-    long            nStartBlue  = aStartCol.GetBlue();
-    long            nEndRed     = aEndCol.GetRed();
-    long            nEndGreen   = aEndCol.GetGreen();
-    long            nEndBlue    = aEndCol.GetBlue();
-                    nFactor     = rGradient.GetStartIntensity();
-                    nStartRed   = (nStartRed   * nFactor) / 100;
-                    nStartGreen = (nStartGreen * nFactor) / 100;
-                    nStartBlue  = (nStartBlue  * nFactor) / 100;
-                    nFactor     = rGradient.GetEndIntensity();
-                    nEndRed     = (nEndRed   * nFactor) / 100;
-                    nEndGreen   = (nEndGreen * nFactor) / 100;
-                    nEndBlue    = (nEndBlue  * nFactor) / 100;
-    long            nRedSteps   = nEndRed   - nStartRed;
-    long            nGreenSteps = nEndGreen - nStartGreen;
-    long            nBlueSteps  = nEndBlue  - nStartBlue;
-    long            nStepCount = rGradient.GetSteps();
+    sal_uInt8   nRed;
+    sal_uInt8   nGreen;
+    sal_uInt8   nBlue;
 
-    // Bei nicht linearen Farbverlaeufen haben wir nur die halben Steps
-    // pro Farbe
-    if ( !bLinear )
+    // Create border
+    Rectangle aBorderRect = aRect;
+    Polygon     aPoly( 4 );
+    if (fBorder > 0.0)
     {
-        nRedSteps   <<= 1;
-        nGreenSteps <<= 1;
-        nBlueSteps  <<= 1;
+        nRed        = (sal_uInt8)nStartRed;
+        nGreen      = (sal_uInt8)nStartGreen;
+        nBlue       = (sal_uInt8)nStartBlue;
+        if ( bMtf )
+            mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) );
+        else
+            mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+
+        aBorderRect.Bottom() = (long)( aBorderRect.Top() + fBorder );
+        aRect.Top() = aBorderRect.Bottom();
+        aPoly[0] = aBorderRect.TopLeft();
+        aPoly[1] = aBorderRect.TopRight();
+        aPoly[2] = aBorderRect.BottomRight();
+        aPoly[3] = aBorderRect.BottomLeft();
+        aPoly.Rotate( aCenter, nAngle );
+        if ( bMtf )
+            mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
+        else
+            ImplDrawPolygon( aPoly, pClipPolyPoly );
+        if ( !bLinear)
+        {
+            aBorderRect = aMirrorRect;
+            aBorderRect.Top() = (long) ( aBorderRect.Bottom() - fBorder );
+            aMirrorRect.Bottom() = aBorderRect.Top();
+            aPoly[0] = aBorderRect.TopLeft();
+            aPoly[1] = aBorderRect.TopRight();
+            aPoly[2] = aBorderRect.BottomRight();
+            aPoly[3] = aBorderRect.BottomLeft();
+            aPoly.Rotate( aCenter, nAngle );
+            if ( bMtf )
+                mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
+            else
+                ImplDrawPolygon( aPoly, pClipPolyPoly );
+        }
     }
 
-    // Anzahl der Schritte berechnen, falls nichts uebergeben wurde
+    // calculate step count
+    long    nStepCount  = rGradient.GetSteps();
+    // generate nStepCount, if not passed
+    long nMinRect = aRect.GetHeight();
     if ( !nStepCount )
     {
-        long nInc;
-
+        long nInc = 1;
         if ( meOutDevType != OUTDEV_PRINTER && !bMtf )
         {
             nInc = (nMinRect < 50) ? 2 : 4;
         }
         else
         {
-            // #105998# Use display-equivalent step size calculation
+            // Use display-equivalent step size calculation
             nInc = (nMinRect < 800) ? 10 : 20;
         }
-
         nStepCount = nMinRect / nInc;
     }
-    // minimal drei Schritte und maximal die Anzahl der Farbunterschiede
-    long nSteps = std::max( nStepCount, 2L );
-    long nCalcSteps  = std::abs( nRedSteps );
-    long nTempSteps = std::abs( nGreenSteps );
-    if ( nTempSteps > nCalcSteps )
-        nCalcSteps = nTempSteps;
-    nTempSteps = std::abs( nBlueSteps );
-    if ( nTempSteps > nCalcSteps )
-        nCalcSteps = nTempSteps;
-    if ( nCalcSteps < nSteps )
-        nSteps = nCalcSteps;
-    if ( !nSteps )
-        nSteps = 1;
 
-    // Falls axialer Farbverlauf, muss die Schrittanzahl ungerade sein
-    if ( !bLinear && !(nSteps & 1) )
-        nSteps++;
+    // minimal three steps and maximal as max color steps
+    long   nAbsRedSteps   = std::abs( nEndRed   - nStartRed );
+    long   nAbsGreenSteps = std::abs( nEndGreen - nStartGreen );
+    long   nAbsBlueSteps  = std::abs( nEndBlue  - nStartBlue );
+    long   nMaxColorSteps = std::max( nAbsRedSteps , nAbsGreenSteps );
+    nMaxColorSteps = std::max( nMaxColorSteps, nAbsBlueSteps );
+    long nSteps = std::min( nStepCount, nMaxColorSteps );
+    if ( nSteps < 3)
+    {
+        nSteps = 3;
+    }
 
-    // Berechnung ueber Double-Addition wegen Genauigkeit
-    double fScanLine = aRect.Top();
-    double fScanInc  = (double)aRect.GetHeight() / (double)nSteps;
+    double fScanInc = ((double)aRect.GetHeight()) / (double) nSteps;
+    double fGradientLine = (double)aRect.Top();
+    double fMirrorGradientLine = (double) aMirrorRect.Bottom();
 
-    // Startfarbe berechnen und setzen
-    sal_uInt8   nRed;
-    sal_uInt8   nGreen;
-    sal_uInt8   nBlue;
-    long    nSteps2;
-    long    nStepsHalf = 0;
-    if ( bLinear )
+    double fAlpha = 0.0;
+    const double fStepsMinus1 = ((double)nSteps) - 1.0;
+    double fTempColor;
+    if ( !bLinear)
     {
-        // Um 1 erhoeht, um die Border innerhalb der Schleife
-        // zeichnen zu koennen
-        nSteps2     = nSteps + 1;
-        nRed        = (sal_uInt8)nStartRed;
-        nGreen      = (sal_uInt8)nStartGreen;
-        nBlue       = (sal_uInt8)nStartBlue;
+        nSteps -= 1; // draw middle polygons as one polygon after loop to avoid gap
     }
-    else
+    for ( long i = 0; i < nSteps; i++ )
     {
-        // Um 2 erhoeht, um die Border innerhalb der Schleife
-        // zeichnen zu koennen
-        nSteps2     = nSteps + 2;
-        nRed        = (sal_uInt8)nEndRed;
-        nGreen      = (sal_uInt8)nEndGreen;
-        nBlue       = (sal_uInt8)nEndBlue;
-        nStepsHalf  = nSteps >> 1;
-    }
-
-    if ( bMtf )
-        mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) );
-    else
-        mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+        // linear interpolation of color
+        fAlpha = ((double)i) / fStepsMinus1;
+        fTempColor = ((double)nStartRed) * (1.0-fAlpha) + ((double)nEndRed) * fAlpha;
+        nRed = ImplGetGradientColorValue((long)fTempColor);
+        fTempColor = ((double)nStartGreen) * (1.0-fAlpha) + ((double)nEndGreen) * fAlpha;
+        nGreen = ImplGetGradientColorValue((long)fTempColor);
+        fTempColor = ((double)nStartBlue) * (1.0-fAlpha) + ((double)nEndBlue) * fAlpha;
+        nBlue = ImplGetGradientColorValue((long)fTempColor);
+        if ( bMtf )
+            mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) );
+        else
+            mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
 
-    // Startpolygon erzeugen (== Borderpolygon)
-    Polygon     aPoly( 4 );
-    Polygon     aTempPoly( 2 );
-    Polygon     aTempPoly2( 2 );
-    /* n#710061 Use overlapping fills to avoid color
-     * leak via gaps in some pdf viewers
-     */
-    Point       aOverLap( 0, fScanInc*.1 );
-    aPoly[0] = aFullRect.TopLeft();
-    aPoly[1] = aFullRect.TopRight();
-    aPoly[2] = aRect.TopRight();
-    aPoly[3] = aRect.TopLeft();
-    aPoly.Rotate( aCenter, nAngle );
-    aTempPoly[0] = aPoly[3];
-    aTempPoly[1] = aPoly[2];
-
-
-    // Schleife, um rotierten Verlauf zu fuellen
-    for ( long i = 0; i < nSteps2; i++ )
-    {
-        // berechnetesPolygon ausgeben
+        // Polygon for this color step
+        aRect.Top() = (long)( fGradientLine + ((double) i) * fScanInc );
+        aRect.Bottom() = (long)( fGradientLine + ( ((double) i) + 1.0 ) * fScanInc + fScanInc*.1 );
+        aPoly[0] = aRect.TopLeft();
+        aPoly[1] = aRect.TopRight();
+        aPoly[2] = aRect.BottomRight();
+        aPoly[3] = aRect.BottomLeft();
+        aPoly.Rotate( aCenter, nAngle );
         if ( bMtf )
             mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
         else
             ImplDrawPolygon( aPoly, pClipPolyPoly );
-
-        // neues Polygon berechnen
-        aRect.Top() = (long)(fScanLine += fScanInc);
-
-        aPoly[0] = aTempPoly[0];
-        aPoly[1] = aTempPoly[1];
-        // unteren Rand komplett fuellen
-        if ( i == nSteps )
-        {
-            aTempPoly[0] = aFullRect.BottomLeft();
-            aTempPoly[1] = aFullRect.BottomRight();
-            aTempPoly2   = aTempPoly;
-        }
-        else
+        if ( !bLinear )
         {
-            aTempPoly[0] = aRect.TopLeft();
-            aTempPoly[1] = aRect.TopRight();
-            aTempPoly2[0]= aTempPoly[0] + aOverLap;
-            aTempPoly2[1]= aTempPoly[1] + aOverLap;
-        }
-        aTempPoly2.Rotate( aCenter, nAngle );
-        aTempPoly.Rotate( aCenter, nAngle );
-
-        aPoly[2] = aTempPoly2[1];
-        aPoly[3] = aTempPoly2[0];
-
-        // Farbintensitaeten aendern...
-        // fuer lineare FV
-        if ( bLinear )
-        {
-            nRed    = ImplGetGradientColorValue( nStartRed+((nRedSteps*i)/nSteps2) );
-            nGreen  = ImplGetGradientColorValue( nStartGreen+((nGreenSteps*i)/nSteps2) );
-            nBlue   = ImplGetGradientColorValue( nStartBlue+((nBlueSteps*i)/nSteps2) );
-        }
-        // fuer radiale FV
-        else
-        {
-            // fuer axiale FV muss die letzte Farbe der ersten
-            // Farbe entsprechen
-            // #107350# Setting end color one step earlier, as the
-            // last time we get here, we drop out of the loop later
-            // on.
-            if ( i >= nSteps )
-            {
-                nRed    = (sal_uInt8)nEndRed;
-                nGreen  = (sal_uInt8)nEndGreen;
-                nBlue   = (sal_uInt8)nEndBlue;
-            }
+            aMirrorRect.Bottom() = (long)( fMirrorGradientLine - ((double) i) * fScanInc );
+            aMirrorRect.Top() = (long)( fMirrorGradientLine - (((double) i) + 1.0)* fScanInc );
+            aPoly[0] = aMirrorRect.TopLeft();
+            aPoly[1] = aMirrorRect.TopRight();
+            aPoly[2] = aMirrorRect.BottomRight();
+            aPoly[3] = aMirrorRect.BottomLeft();
+            aPoly.Rotate( aCenter, nAngle );
+            if ( bMtf )
+                mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
             else
-            {
-                if ( i <= nStepsHalf )
-                {
-                    nRed    = ImplGetGradientColorValue( nEndRed-((nRedSteps*i)/nSteps2) );
-                    nGreen  = ImplGetGradientColorValue( nEndGreen-((nGreenSteps*i)/nSteps2) );
-                    nBlue   = ImplGetGradientColorValue( nEndBlue-((nBlueSteps*i)/nSteps2) );
-                }
-                // genau die Mitte und hoeher
-                else
-                {
-                    long i2 = i - nStepsHalf;
-                    nRed    = ImplGetGradientColorValue( nStartRed+((nRedSteps*i2)/nSteps2) );
-                    nGreen  = ImplGetGradientColorValue( nStartGreen+((nGreenSteps*i2)/nSteps2) );
-                    nBlue   = ImplGetGradientColorValue( nStartBlue+((nBlueSteps*i2)/nSteps2) );
-                }
-            }
+                ImplDrawPolygon( aPoly, pClipPolyPoly );
         }
-
+    }
+    if ( !bLinear)
+    {
+        // draw middle polygon with end color
+        nRed = ImplGetGradientColorValue(nEndRed);
+        nGreen = ImplGetGradientColorValue(nEndGreen);
+        nBlue = ImplGetGradientColorValue(nEndBlue);
         if ( bMtf )
             mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) );
         else
             mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+
+        aRect.Top() = (long)( fGradientLine + ((double)nSteps) * fScanInc );
+        aRect.Bottom() = (long)( fMirrorGradientLine - ((double) nSteps) * fScanInc );
+        aPoly[0] = aRect.TopLeft();
+        aPoly[1] = aRect.TopRight();
+        aPoly[2] = aRect.BottomRight();
+        aPoly[3] = aRect.BottomLeft();
+        aPoly.Rotate( aCenter, nAngle );
+        if ( bMtf )
+            mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
+        else
+            ImplDrawPolygon( aPoly, pClipPolyPoly );
     }
 }
 
@@ -406,7 +380,7 @@ void OutputDevice::ImplDrawComplexGradient( const Rectangle& rRect,
     long            nGreenSteps = nEndGreen - nStartGreen;
     long            nBlueSteps = nEndBlue   - nStartBlue;
     long            nStepCount = rGradient.GetSteps();
-    sal_uInt16          nAngle = rGradient.GetAngle() % 3600;
+    sal_uInt16      nAngle = rGradient.GetAngle() % 3600;
 
     rGradient.GetBoundRect( rRect, aRect, aCenter );
 
@@ -455,8 +429,8 @@ void OutputDevice::ImplDrawComplexGradient( const Rectangle& rRect,
     double  fScanTop = aRect.Top();
     double  fScanRight = aRect.Right();
     double  fScanBottom = aRect.Bottom();
-    double  fScanIncX = (double) aRect.GetWidth() / (double) nSteps * 0.5;
-    double  fScanIncY = (double) aRect.GetHeight() / (double) nSteps * 0.5;
+    double fScanIncX = (double) aRect.GetWidth() / (double) nSteps * 0.5;
+    double fScanIncY = (double) aRect.GetHeight() / (double) nSteps * 0.5;
 
     // all gradients are rendered as nested rectangles which shrink
     // equally in each dimension - except for 'square' gradients
@@ -466,7 +440,6 @@ void OutputDevice::ImplDrawComplexGradient( const Rectangle& rRect,
         fScanIncY = std::min( fScanIncY, fScanIncX );
         fScanIncX = fScanIncY;
     }
-
     sal_uInt8   nRed = (sal_uInt8) nStartRed, nGreen = (sal_uInt8) nStartGreen, nBlue = (sal_uInt8) nStartBlue;
     bool    bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
 


More information about the Libreoffice-commits mailing list