You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openoffice.apache.org by al...@apache.org on 2012/10/02 11:21:48 UTC

svn commit: r1392804 - /incubator/ooo/trunk/main/vcl/source/gdi/outdev4.cxx

Author: alg
Date: Tue Oct  2 09:21:47 2012
New Revision: 1392804

URL: http://svn.apache.org/viewvc?rev=1392804&view=rev
Log:
#120957# Added Reginas corrections for gradient colors for linear gradients in VCL renderers
Patch by: Regina
Review by: alg

Modified:
    incubator/ooo/trunk/main/vcl/source/gdi/outdev4.cxx

Modified: incubator/ooo/trunk/main/vcl/source/gdi/outdev4.cxx
URL: http://svn.apache.org/viewvc/incubator/ooo/trunk/main/vcl/source/gdi/outdev4.cxx?rev=1392804&r1=1392803&r2=1392804&view=diff
==============================================================================
--- incubator/ooo/trunk/main/vcl/source/gdi/outdev4.cxx (original)
+++ incubator/ooo/trunk/main/vcl/source/gdi/outdev4.cxx Tue Oct  2 09:21:47 2012
@@ -170,12 +170,8 @@ void OutputDevice::ImplDrawLinearGradien
 										   const Gradient& rGradient,
 										   sal_Bool bMtf, const PolyPolygon* pClipPolyPoly )
 {
-	// rotiertes BoundRect ausrechnen
+	// get BoundRect of rotated rectangle
 	Rectangle aRect = rRect;
-	aRect.Left()--;
-	aRect.Top()--;
-	aRect.Right()++;
-	aRect.Bottom()++;
 	sal_uInt16	nAngle = rGradient.GetAngle() % 3600;
 	double	fAngle	= nAngle * F_PI1800;
 	double	fWidth	= aRect.GetWidth();
@@ -191,224 +187,205 @@ void OutputDevice::ImplDrawLinearGradien
 	aRect.Top()    -= (long)fDY;
 	aRect.Bottom() += (long)fDY;
 
-	// Rand berechnen und Rechteck neu setzen
+	sal_Bool	bLinear = ( rGradient.GetStyle() == GRADIENT_LINEAR );
+	double		fBorder = rGradient.GetBorder() * aRect.GetHeight() / 100.0;
 	Point		aCenter = rRect.Center();
-	Rectangle	aFullRect = aRect;
-	long		nBorder = (long)rGradient.GetBorder() * aRect.GetHeight() / 100;
-	sal_Bool		bLinear;
+    if ( !bLinear )
+    {
+        fBorder /= 2.0;
+    }
+    Rectangle aMirrorRect = aRect; // used in style axial
+    aMirrorRect.Top() = ( aRect.Top() + aRect.Bottom() ) / 2;
+    if ( !bLinear )
+    {
+        aRect.Bottom() = aMirrorRect.Top();
+    }
 
-	// Rand berechnen und Rechteck neu setzen fuer linearen Farbverlauf
-	if ( rGradient.GetStyle() == GRADIENT_LINEAR )
-	{
-		bLinear = sal_True;
-		aRect.Top() += nBorder;
-	}
-	// Rand berechnen und Rechteck neu setzen fuer axiale Farbverlauf
-	else
-	{
-		bLinear = sal_False;
-		nBorder >>= 1;
+	// 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;
 
-		aRect.Top()    += nBorder;
-		aRect.Bottom() -= nBorder;
-	}
+    // 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;
+    }
 
-	// Top darf nicht groesser als Bottom sein
-	aRect.Top() = Min( aRect.Top(), (long)(aRect.Bottom() - 1) );
+    sal_uInt8   nRed;
+    sal_uInt8   nGreen;
+    sal_uInt8   nBlue;
+
+    // Create border
+    Rectangle aBorderRect = aRect;
+    Polygon     aPoly( 4 );
+    if (fBorder > 0.0)
+    {
+        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 );
+        }
+    }
+    
+    // calculate step count
+    long    nStepCount  = rGradient.GetSteps();
+	// generate nStepCount, if not passed
 	long nMinRect = aRect.GetHeight();
-
-	// 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();
-
-	// Bei nicht linearen Farbverlaeufen haben wir nur die halben Steps
-	// pro Farbe
-	if ( !bLinear )
-	{
-		nRedSteps	<<= 1;
-		nGreenSteps <<= 1;
-		nBlueSteps	<<= 1;
-	}
-
-	// Anzahl der Schritte berechnen, falls nichts uebergeben wurde
 	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;
         }
-
-		if ( !nInc )
-			nInc = 1;
-
 		nStepCount = nMinRect / nInc;
 	}
-	// minimal drei Schritte und maximal die Anzahl der Farbunterschiede
-	long nSteps = Max( nStepCount, 2L );
-	long nCalcSteps  = Abs( nRedSteps );
-	long nTempSteps = Abs( nGreenSteps );
-	if ( nTempSteps > nCalcSteps )
-		nCalcSteps = nTempSteps;
-	nTempSteps = 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++;
-
-	// Berechnung ueber Double-Addition wegen Genauigkeit
-	double fScanLine = aRect.Top();
-	double fScanInc  = (double)aRect.GetHeight() / (double)nSteps;
-
-	// Startfarbe berechnen und setzen
-	sal_uInt8	nRed;
-	sal_uInt8	nGreen;
-	sal_uInt8	nBlue;
-	long	nSteps2;
-	long	nStepsHalf = 0;
-	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;
-	}
-	else
-	{
-		// 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 ) );
-
-	// Startpolygon erzeugen (== Borderpolygon)
-	Polygon 	aPoly( 4 );
-	Polygon 	aTempPoly( 2 );
-	aPoly[0] = aFullRect.TopLeft();
-	aPoly[1] = aFullRect.TopRight();
-	aPoly[2] = aRect.TopRight();
-	aPoly[3] = aRect.TopLeft();
-	aPoly.Rotate( aCenter, nAngle );
-
-	// Schleife, um rotierten Verlauf zu fuellen
-	for ( long i = 0; i < nSteps2; i++ )
-	{
-		// berechnetesPolygon ausgeben
-		if ( bMtf )
-			mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
-		else
-			ImplDrawPolygon( aPoly, pClipPolyPoly );
-
-		// neues Polygon berechnen
-		aRect.Top() = (long)(fScanLine += fScanInc);
+	// minimal three steps and maximal as max color steps
+	long   nAbsRedSteps   = Abs( nEndRed   - nStartRed );
+	long   nAbsGreenSteps = Abs( nEndGreen - nStartGreen );
+	long   nAbsBlueSteps  = Abs( nEndBlue  - nStartBlue );
+	long   nMaxColorSteps = Max( nAbsRedSteps , nAbsGreenSteps );
+    nMaxColorSteps = Max( nMaxColorSteps, nAbsBlueSteps );
+	long nSteps = Min( nStepCount, nMaxColorSteps );
+    if ( nSteps < 3)
+    {
+        nSteps = 3;
+    }
 
-		// unteren Rand komplett fuellen
-		if ( i == nSteps )
-		{
-			aTempPoly[0] = aFullRect.BottomLeft();
-			aTempPoly[1] = aFullRect.BottomRight();
-		}
-		else
-		{
-			aTempPoly[0] = aRect.TopLeft();
-			aTempPoly[1] = aRect.TopRight();
-		}
-		aTempPoly.Rotate( aCenter, nAngle );
+    double fScanInc = ((double)aRect.GetHeight()) / (double) nSteps;
+    double fGradientLine = (double)aRect.Top();
+    double fMirrorGradientLine = (double) aMirrorRect.Bottom();
+
+    double fAlpha = 0.0;
+    const double fStepsMinus1 = ((double)nSteps) - 1.0;
+    double fTempColor;
+    if ( !bLinear)
+    {
+        nSteps -= 1; // draw middle polygons as one polygon after loop to avoid gap
+    }
+    for ( long i = 0; i < nSteps; i++ )
+    {
+        // 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 ) );
 
-		aPoly[0] = aPoly[3];
-		aPoly[1] = aPoly[2];
-		aPoly[2] = aTempPoly[1];
-		aPoly[3] = aTempPoly[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;
-			}
-			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) );
-				}
-			}
-		}
+        // Polygon for this color step
+        aRect.Top() = (long)( fGradientLine + ((double) i) * fScanInc );
+        aRect.Bottom() = (long)( fGradientLine + ( ((double) i) + 1.0 ) * 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 );
+        if ( !bLinear )
+        {
+            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
+                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 ) );
 
-		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 );
+    }
 }
 
 // -----------------------------------------------------------------------