summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorArmin Le Grand <alg@apache.org>2013-06-08 14:27:01 +0100
committerCaolán McNamara <caolanm@redhat.com>2013-07-12 12:54:41 +0100
commit04d937c1ec36c2d9fa8c90604c81a37d30e97da6 (patch)
tree72fafe46cd2abb7f3a417b02a34e0d87e6647bde /vcl
parentcad6d7e516e5cc1e0f66d7e400ce949707c94cc7 (diff)
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
Diffstat (limited to 'vcl')
-rw-r--r--vcl/source/gdi/gradient.cxx17
-rw-r--r--vcl/source/gdi/outdev4.cxx347
2 files changed, 166 insertions, 198 deletions
diff --git a/vcl/source/gdi/gradient.cxx b/vcl/source/gdi/gradient.cxx
index b4099b527d8b..c1058b22213b 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 4dd70e638486..1be80e94b91b 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