Kaydet (Commit) 94205034 authored tarafından Armin Le Grand's avatar Armin Le Grand

#120957# Added Reginas corrections for gradient colors for linear gradients in VCL renderers

Patch by: Regina
Review by: alg
üst 8465cbeb
...@@ -170,12 +170,8 @@ void OutputDevice::ImplDrawLinearGradient( const Rectangle& rRect, ...@@ -170,12 +170,8 @@ void OutputDevice::ImplDrawLinearGradient( const Rectangle& rRect,
const Gradient& rGradient, const Gradient& rGradient,
sal_Bool bMtf, const PolyPolygon* pClipPolyPoly ) sal_Bool bMtf, const PolyPolygon* pClipPolyPoly )
{ {
// rotiertes BoundRect ausrechnen // get BoundRect of rotated rectangle
Rectangle aRect = rRect; Rectangle aRect = rRect;
aRect.Left()--;
aRect.Top()--;
aRect.Right()++;
aRect.Bottom()++;
sal_uInt16 nAngle = rGradient.GetAngle() % 3600; sal_uInt16 nAngle = rGradient.GetAngle() % 3600;
double fAngle = nAngle * F_PI1800; double fAngle = nAngle * F_PI1800;
double fWidth = aRect.GetWidth(); double fWidth = aRect.GetWidth();
...@@ -191,35 +187,21 @@ void OutputDevice::ImplDrawLinearGradient( const Rectangle& rRect, ...@@ -191,35 +187,21 @@ void OutputDevice::ImplDrawLinearGradient( const Rectangle& rRect,
aRect.Top() -= (long)fDY; aRect.Top() -= (long)fDY;
aRect.Bottom() += (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(); Point aCenter = rRect.Center();
Rectangle aFullRect = aRect; if ( !bLinear )
long nBorder = (long)rGradient.GetBorder() * aRect.GetHeight() / 100;
sal_Bool bLinear;
// Rand berechnen und Rechteck neu setzen fuer linearen Farbverlauf
if ( rGradient.GetStyle() == GRADIENT_LINEAR )
{ {
bLinear = sal_True; fBorder /= 2.0;
aRect.Top() += nBorder;
} }
// Rand berechnen und Rechteck neu setzen fuer axiale Farbverlauf Rectangle aMirrorRect = aRect; // used in style axial
else aMirrorRect.Top() = ( aRect.Top() + aRect.Bottom() ) / 2;
if ( !bLinear )
{ {
bLinear = sal_False; aRect.Bottom() = aMirrorRect.Top();
nBorder >>= 1;
aRect.Top() += nBorder;
aRect.Bottom() -= nBorder;
} }
// Top darf nicht groesser als Bottom sein // Intensitaeten von Start- und Endfarbe ggf. aendern
aRect.Top() = Min( aRect.Top(), (long)(aRect.Bottom() - 1) );
long nMinRect = aRect.GetHeight();
// Intensitaeten von Start- und Endfarbe ggf. aendern und
// Farbschrittweiten berechnen
long nFactor; long nFactor;
Color aStartCol = rGradient.GetStartColor(); Color aStartCol = rGradient.GetStartColor();
Color aEndCol = rGradient.GetEndColor(); Color aEndCol = rGradient.GetEndColor();
...@@ -237,177 +219,172 @@ void OutputDevice::ImplDrawLinearGradient( const Rectangle& rRect, ...@@ -237,177 +219,172 @@ void OutputDevice::ImplDrawLinearGradient( const Rectangle& rRect,
nEndRed = (nEndRed * nFactor) / 100; nEndRed = (nEndRed * nFactor) / 100;
nEndGreen = (nEndGreen * nFactor) / 100; nEndGreen = (nEndGreen * nFactor) / 100;
nEndBlue = (nEndBlue * 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;
if ( meOutDevType != OUTDEV_PRINTER && !bMtf ) // gradient style axial has exchanged start and end colors
{ if ( !bLinear)
nInc = (nMinRect < 50) ? 2 : 4;
}
else
{ {
// #105998# Use display-equivalent step size calculation long nTempColor = nStartRed;
nInc = (nMinRect < 800) ? 10 : 20; nStartRed = nEndRed;
} nEndRed = nTempColor;
nTempColor = nStartGreen;
if ( !nInc ) nStartGreen = nEndGreen;
nInc = 1; nEndGreen = nTempColor;
nTempColor = nStartBlue;
nStepCount = nMinRect / nInc; nStartBlue = nEndBlue;
nEndBlue = nTempColor;
} }
// 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 nRed;
sal_uInt8 nGreen; sal_uInt8 nGreen;
sal_uInt8 nBlue; sal_uInt8 nBlue;
long nSteps2;
long nStepsHalf = 0; // Create border
if ( bLinear ) Rectangle aBorderRect = aRect;
Polygon aPoly( 4 );
if (fBorder > 0.0)
{ {
// Um 1 erhoeht, um die Border innerhalb der Schleife
// zeichnen zu koennen
nSteps2 = nSteps + 1;
nRed = (sal_uInt8)nStartRed; nRed = (sal_uInt8)nStartRed;
nGreen = (sal_uInt8)nStartGreen; nGreen = (sal_uInt8)nStartGreen;
nBlue = (sal_uInt8)nStartBlue; 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 ) if ( bMtf )
mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) ); mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) );
else else
mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
// Startpolygon erzeugen (== Borderpolygon) aBorderRect.Bottom() = (long)( aBorderRect.Top() + fBorder );
Polygon aPoly( 4 ); aRect.Top() = aBorderRect.Bottom();
Polygon aTempPoly( 2 ); aPoly[0] = aBorderRect.TopLeft();
aPoly[0] = aFullRect.TopLeft(); aPoly[1] = aBorderRect.TopRight();
aPoly[1] = aFullRect.TopRight(); aPoly[2] = aBorderRect.BottomRight();
aPoly[2] = aRect.TopRight(); aPoly[3] = aBorderRect.BottomLeft();
aPoly[3] = aRect.TopLeft();
aPoly.Rotate( aCenter, nAngle ); aPoly.Rotate( aCenter, nAngle );
// Schleife, um rotierten Verlauf zu fuellen
for ( long i = 0; i < nSteps2; i++ )
{
// berechnetesPolygon ausgeben
if ( bMtf ) if ( bMtf )
mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) ); mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
else else
ImplDrawPolygon( aPoly, pClipPolyPoly ); 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 );
}
}
// neues Polygon berechnen // calculate step count
aRect.Top() = (long)(fScanLine += fScanInc); long nStepCount = rGradient.GetSteps();
// generate nStepCount, if not passed
// unteren Rand komplett fuellen long nMinRect = aRect.GetHeight();
if ( i == nSteps ) if ( !nStepCount )
{ {
aTempPoly[0] = aFullRect.BottomLeft(); long nInc = 1;
aTempPoly[1] = aFullRect.BottomRight(); if ( meOutDevType != OUTDEV_PRINTER && !bMtf )
{
nInc = (nMinRect < 50) ? 2 : 4;
} }
else else
{ {
aTempPoly[0] = aRect.TopLeft(); // Use display-equivalent step size calculation
aTempPoly[1] = aRect.TopRight(); nInc = (nMinRect < 800) ? 10 : 20;
}
nStepCount = nMinRect / nInc;
} }
aTempPoly.Rotate( aCenter, nAngle );
aPoly[0] = aPoly[3];
aPoly[1] = aPoly[2];
aPoly[2] = aTempPoly[1];
aPoly[3] = aTempPoly[0];
// Farbintensitaeten aendern... // minimal three steps and maximal as max color steps
// fuer lineare FV long nAbsRedSteps = Abs( nEndRed - nStartRed );
if ( bLinear ) 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)
{ {
nRed = ImplGetGradientColorValue( nStartRed+((nRedSteps*i)/nSteps2) ); nSteps = 3;
nGreen = ImplGetGradientColorValue( nStartGreen+((nGreenSteps*i)/nSteps2) );
nBlue = ImplGetGradientColorValue( nStartBlue+((nBlueSteps*i)/nSteps2) );
} }
// fuer radiale FV
else double fScanInc = ((double)aRect.GetHeight()) / (double) nSteps;
{ double fGradientLine = (double)aRect.Top();
// fuer axiale FV muss die letzte Farbe der ersten double fMirrorGradientLine = (double) aMirrorRect.Bottom();
// Farbe entsprechen
// #107350# Setting end color one step earlier, as the double fAlpha = 0.0;
// last time we get here, we drop out of the loop later const double fStepsMinus1 = ((double)nSteps) - 1.0;
// on. double fTempColor;
if ( i >= nSteps ) if ( !bLinear)
{ {
nRed = (sal_uInt8)nEndRed; nSteps -= 1; // draw middle polygons as one polygon after loop to avoid gap
nGreen = (sal_uInt8)nEndGreen;
nBlue = (sal_uInt8)nEndBlue;
} }
else for ( long i = 0; i < nSteps; i++ )
{ {
if ( i <= nStepsHalf ) // linear interpolation of color
{ fAlpha = ((double)i) / fStepsMinus1;
nRed = ImplGetGradientColorValue( nEndRed-((nRedSteps*i)/nSteps2) ); fTempColor = ((double)nStartRed) * (1.0-fAlpha) + ((double)nEndRed) * fAlpha;
nGreen = ImplGetGradientColorValue( nEndGreen-((nGreenSteps*i)/nSteps2) ); nRed = ImplGetGradientColorValue((long)fTempColor);
nBlue = ImplGetGradientColorValue( nEndBlue-((nBlueSteps*i)/nSteps2) ); fTempColor = ((double)nStartGreen) * (1.0-fAlpha) + ((double)nEndGreen) * fAlpha;
} nGreen = ImplGetGradientColorValue((long)fTempColor);
// genau die Mitte und hoeher 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 ) );
// 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 else
ImplDrawPolygon( aPoly, pClipPolyPoly );
if ( !bLinear )
{ {
long i2 = i - nStepsHalf; aMirrorRect.Bottom() = (long)( fMirrorGradientLine - ((double) i) * fScanInc );
nRed = ImplGetGradientColorValue( nStartRed+((nRedSteps*i2)/nSteps2) ); aMirrorRect.Top() = (long)( fMirrorGradientLine - (((double) i) + 1.0)* fScanInc );
nGreen = ImplGetGradientColorValue( nStartGreen+((nGreenSteps*i2)/nSteps2) ); aPoly[0] = aMirrorRect.TopLeft();
nBlue = ImplGetGradientColorValue( nStartBlue+((nBlueSteps*i2)/nSteps2) ); 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 ) if ( bMtf )
mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) ); mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), sal_True ) );
else else
mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) ); 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 );
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment