/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// Convert rectangle to a tools::PolyPolygon by first converting to a Polygon
tools::Polygon aPolygon ( rRect );
tools::PolyPolygon aPolyPoly ( aPolygon );
if (mbInitClipRegion)
InitClipRegion(); // don't return on mbOutputClipped here, as we may need to draw the clipped metafile, even if the output is clipped
if ( rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize() )
{ if ( mnDrawMode & ( DrawModeFlags::BlackGradient | DrawModeFlags::WhiteGradient | DrawModeFlags::SettingsGradient) )
{
Color aColor = GetSingleColorGradientFill();
// do nothing if the rectangle is empty if ( !aRect.IsEmpty() )
{
tools::PolyPolygon aClixPolyPoly( ImplLogicToDevicePixel( rPolyPoly ) ); bool bDrawn = false;
if( !mpGraphics && !AcquireGraphics() ) return;
// secure clip region
Push( vcl::PushFlags::CLIPREGION );
IntersectClipRegion( aBoundRect );
if (mbInitClipRegion)
InitClipRegion();
// try to draw gradient natively if (!mbOutputClipped)
bDrawn = mpGraphics->DrawGradient( aClixPolyPoly, aGradient, *this );
// calculate step count if necessary if ( !aGradient.GetSteps() )
aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
if ( rPolyPoly.IsRect() )
{ // because we draw with no border line, we have to expand gradient // rect to avoid missing lines on the right and bottom edge
aRect.AdjustLeft( -1 );
aRect.AdjustTop( -1 );
aRect.AdjustRight( 1 );
aRect.AdjustBottom( 1 );
}
// if the clipping polypolygon is a rectangle, then it's the same size as the bounding of the // polypolygon, so pass in a NULL for the clipping parameter if( aGradient.GetStyle() == css::awt::GradientStyle_LINEAR || rGradient.GetStyle() == css::awt::GradientStyle_AXIAL )
DrawLinearGradient( aRect, aGradient, aClixPolyPoly.IsRect() ? nullptr : &aClixPolyPoly ); else
DrawComplexGradient( aRect, aGradient, aClixPolyPoly.IsRect() ? nullptr : &aClixPolyPoly );
}
constdouble fStepsMinus1 = static_cast<double>(nSteps) - 1.0; if ( !bLinear)
{
nSteps -= 1; // draw middle polygons as one polygon after loop to avoid gap
}
for ( tools::Long i = 0; i < nSteps; i++ )
{ // linear interpolation of color constdouble fAlpha = static_cast<double>(i) / fStepsMinus1; double fTempColor = static_cast<double>(nStartRed) * (1.0-fAlpha) + static_cast<double>(nEndRed) * fAlpha;
nRed = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
fTempColor = static_cast<double>(nStartGreen) * (1.0-fAlpha) + static_cast<double>(nEndGreen) * fAlpha;
nGreen = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
fTempColor = static_cast<double>(nStartBlue) * (1.0-fAlpha) + static_cast<double>(nEndBlue) * fAlpha;
nBlue = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
// Determine if we output via Polygon or PolyPolygon // For all rasteroperations other than Overpaint always use PolyPolygon, // as we will get wrong results if we output multiple times on top of each other. // Also for printers always use PolyPolygon, as not all printers // can print polygons on top of each other.
// all gradients are rendered as nested rectangles which shrink // equally in each dimension - except for 'square' gradients // which shrink to a central vertex but are not per-se square. if( rGradient.GetStyle() != css::awt::GradientStyle_SQUARE )
{
fScanIncY = std::min( fScanIncY, fScanIncX );
fScanIncX = fScanIncY;
}
sal_uInt8 nRed = static_cast<sal_uInt8>(nStartRed), nGreen = static_cast<sal_uInt8>(nStartGreen), nBlue = static_cast<sal_uInt8>(nStartBlue); bool bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
// either slow tools::PolyPolygon output or fast Polygon-Painting if( xPolyPoly )
{
bPaintLastPolygon = true; // #107349# Paint last polygon only if loop has generated any output
// #107349# Set fill color _after_ geometry painting: // xPolyPoly's geometry is the band from last iteration's // aPoly to current iteration's aPoly. The window outdev // path (see else below), on the other hand, paints the // full aPoly. Thus, here, we're painting the band before // the one painted in the window outdev path below. To get // matching colors, have to delay color setting here.
mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
} else
{ // #107349# Set fill color _before_ geometry painting
mpGraphics->SetFillColor( Color( nRed, nGreen, nBlue ) );
ImplDrawPolygon( aPoly, pClixPolyPoly );
}
}
// we should draw last inner Polygon if we output PolyPolygon if( !xPolyPoly ) return;
// #107349# Paint last polygon with end color only if loop // has generated output. Otherwise, the current // (i.e. start) color is taken, to generate _any_ output. if( bPaintLastPolygon )
{
nRed = GetGradientColorValue( nEndRed );
nGreen = GetGradientColorValue( nEndGreen );
nBlue = GetGradientColorValue( nEndBlue );
}
Color OutputDevice::GetSingleColorGradientFill()
{
Color aColor;
// we should never call on this function if any of these aren't set!
assert( mnDrawMode & ( DrawModeFlags::BlackGradient | DrawModeFlags::WhiteGradient | DrawModeFlags::SettingsGradient) );
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.