diff options
author | Armin Le Grand <alg@apache.org> | 2013-06-08 14:27:01 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2013-07-12 12:54:41 +0100 |
commit | 04d937c1ec36c2d9fa8c90604c81a37d30e97da6 (patch) | |
tree | 72fafe46cd2abb7f3a417b02a34e0d87e6647bde /vcl | |
parent | cad6d7e516e5cc1e0f66d7e400ce949707c94cc7 (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.cxx | 17 | ||||
-rw-r--r-- | vcl/source/gdi/outdev4.cxx | 347 |
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 |