Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/vcl/source/gdi/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 23 kB image not shown  

Quelle  gradient.cxx   Sprache: C

 
/* -*- 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 .
 */


#include <tools/gen.hxx>

#include <vcl/gradient.hxx>
#include <vcl/metaact.hxx>
#include <cmath>

class Gradient::Impl
{
public:
    css::awt::GradientStyle       meStyle;
    Color               maStartColor;
    Color               maEndColor;
    Degree10            mnAngle;
    sal_uInt16          mnBorder;
    sal_uInt16          mnOfsX;
    sal_uInt16          mnOfsY;
    sal_uInt16          mnIntensityStart;
    sal_uInt16          mnIntensityEnd;
    sal_uInt16          mnStepCount;

    Impl()
        : meStyle (css::awt::GradientStyle_LINEAR)
        , maStartColor(COL_BLACK)
        , maEndColor(COL_WHITE)
        , mnAngle(0)
        , mnBorder(0)
        , mnOfsX(50)
        , mnOfsY(50)
        , mnIntensityStart(100)
        , mnIntensityEnd(100)
        , mnStepCount(0)
    {
    }

    Impl(const Impl& rImplGradient)
        : meStyle (rImplGradient.meStyle)
        , maStartColor(rImplGradient.maStartColor)
        , maEndColor(rImplGradient.maEndColor)
        , mnAngle(rImplGradient.mnAngle)
        , mnBorder(rImplGradient.mnBorder)
        , mnOfsX(rImplGradient.mnOfsX)
        , mnOfsY(rImplGradient.mnOfsY)
        , mnIntensityStart(rImplGradient.mnIntensityStart)
        , mnIntensityEnd(rImplGradient.mnIntensityEnd)
        , mnStepCount(rImplGradient.mnStepCount)
    {
    }

    bool operator==(const Impl& rImpl_Gradient) const
    {
        return (meStyle == rImpl_Gradient.meStyle)
            && (mnAngle  == rImpl_Gradient.mnAngle)
            && (mnBorder == rImpl_Gradient.mnBorder)
            && (mnOfsX == rImpl_Gradient.mnOfsX)
            && (mnOfsY == rImpl_Gradient.mnOfsY)
            && (mnStepCount == rImpl_Gradient.mnStepCount)
            && (mnIntensityStart == rImpl_Gradient.mnIntensityStart)
            && (mnIntensityEnd == rImpl_Gradient.mnIntensityEnd)
            && (maStartColor == rImpl_Gradient.maStartColor)
            && (maEndColor == rImpl_Gradient.maEndColor);
    }
};

Gradient::Gradient() = default;

Gradient::Gradient( const Gradient& ) = default;

Gradient::Gradient( Gradient&& ) = default;

Gradient::Gradient( css::awt::GradientStyle eStyle,
                    const Color& rStartColor, const Color& rEndColor )
{
    mpImplGradient->meStyle         = eStyle;
    mpImplGradient->maStartColor    = rStartColor;
    mpImplGradient->maEndColor      = rEndColor;
}

Gradient::~Gradient() = default;


css::awt::GradientStyle Gradient::GetStyle() const
{
    return mpImplGradient->meStyle;
}

void Gradient::SetStyle( css::awt::GradientStyle eStyle )
{
    mpImplGradient->meStyle = eStyle;
}

const Color& Gradient::GetStartColor() const
{
    return mpImplGradient->maStartColor;
}

void Gradient::SetStartColor( const Color& rColor )
{
    mpImplGradient->maStartColor = rColor;
}

const Color& Gradient::GetEndColor() const
{
    return mpImplGradient->maEndColor;
}

void Gradient::SetEndColor( const Color& rColor )
{
    mpImplGradient->maEndColor = rColor;
}

Degree10 Gradient::GetAngle() const
{
    return mpImplGradient->mnAngle;
}

void Gradient::SetAngle( Degree10 nAngle )
{
    mpImplGradient->mnAngle = nAngle;
}

sal_uInt16 Gradient::GetBorder() const
{
    return mpImplGradient->mnBorder;
}

void Gradient::SetBorder( sal_uInt16 nBorder )
{
    mpImplGradient->mnBorder = nBorder;
}

sal_uInt16 Gradient::GetOfsX() const
{
    return mpImplGradient->mnOfsX;
}

void Gradient::SetOfsX( sal_uInt16 nOfsX )
{
    mpImplGradient->mnOfsX = nOfsX;
}

sal_uInt16 Gradient::GetOfsY() const
{
    return mpImplGradient->mnOfsY;
}

void Gradient::SetOfsY( sal_uInt16 nOfsY )
{
    mpImplGradient->mnOfsY = nOfsY;
}

sal_uInt16 Gradient::GetStartIntensity() const
{
    return mpImplGradient->mnIntensityStart;
}

void Gradient::SetStartIntensity( sal_uInt16 nIntens )
{
    mpImplGradient->mnIntensityStart = nIntens;
}

sal_uInt16 Gradient::GetEndIntensity() const
{
    return mpImplGradient->mnIntensityEnd;
}

void Gradient::SetEndIntensity( sal_uInt16 nIntens )
{
    mpImplGradient->mnIntensityEnd = nIntens;
}

sal_uInt16 Gradient::GetSteps() const
{
    return mpImplGradient->mnStepCount;
}

void Gradient::SetSteps( sal_uInt16 nSteps )
{
    mpImplGradient->mnStepCount = nSteps;
}

void Gradient::GetBoundRect( const tools::Rectangle& rRect, tools::Rectangle& rBoundRect, Point& rCenter ) const
{
    tools::Rectangle aRect( rRect );
    Degree10 nAngle = GetAngle() % 3600_deg10;

    if( GetStyle() == css::awt::GradientStyle_LINEAR || GetStyle() == css::awt::GradientStyle_AXIAL )
    {
        const double    fAngle = toRadians(nAngle);
        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;
        aRect.AdjustLeft( -static_cast<tools::Long>(fDX) );
        aRect.AdjustRight(static_cast<tools::Long>(fDX) );
        aRect.AdjustTop( -static_cast<tools::Long>(fDY) );
        aRect.AdjustBottom(static_cast<tools::Long>(fDY) );

        rBoundRect = aRect;
        rCenter = rRect.Center();
    }
    else
    {
        if( GetStyle() == css::awt::GradientStyle_SQUARE || GetStyle() == css::awt::GradientStyle_RECT )
        {
            const double    fAngle = toRadians(nAngle);
            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;

            aRect.AdjustLeft( -static_cast<tools::Long>(fDX) );
            aRect.AdjustRight(static_cast<tools::Long>(fDX) );
            aRect.AdjustTop( -static_cast<tools::Long>(fDY) );
            aRect.AdjustBottom(static_cast<tools::Long>(fDY) );
        }

        Size aSize( aRect.GetSize() );

        if( GetStyle() == css::awt::GradientStyle_RADIAL )
        {
            // Calculation of radii for circle
            aSize.setWidth( static_cast<tools::Long>(0.5 + std::hypot(aSize.Width(), aSize.Height())) );
            aSize.setHeight( aSize.Width() );
        }
        else if( GetStyle() == css::awt::GradientStyle_ELLIPTICAL )
        {
            // Calculation of radii for ellipse
            aSize.setWidth( static_cast<tools::Long>( 0.5 + static_cast<double>(aSize.Width())  * M_SQRT2 ) );
            aSize.setHeight( static_cast<tools::Long>( 0.5 + static_cast<double>(aSize.Height()) * M_SQRT2) );
        }

        // Calculate new centers
        tools::Long    nZWidth = aRect.GetWidth() * static_cast<tools::Long>(GetOfsX()) / 100;
        tools::Long    nZHeight = aRect.GetHeight() * static_cast<tools::Long>(GetOfsY()) / 100;
        tools::Long    nBorderX = static_cast<tools::Long>(GetBorder()) * aSize.Width()  / 100;
        tools::Long    nBorderY = static_cast<tools::Long>(GetBorder()) * aSize.Height() / 100;
        rCenter = Point( aRect.Left() + nZWidth, aRect.Top() + nZHeight );

        // Respect borders
        aSize.AdjustWidth( -nBorderX );
        aSize.AdjustHeight( -nBorderY );

        // Recalculate output rectangle
        aRect.SetLeft( rCenter.X() - ( aSize.Width() >> 1 ) );
        aRect.SetTop( rCenter.Y() - ( aSize.Height() >> 1 ) );

        aRect.SetSize( aSize );
        rBoundRect = aRect;
    }
}

void Gradient::MakeGrayscale()
{
    Color aStartCol(GetStartColor());
    Color aEndCol(GetEndColor());
    sal_uInt8 cStartLum = aStartCol.GetLuminance();
    sal_uInt8 cEndLum = aEndCol.GetLuminance();

    aStartCol = Color(cStartLum, cStartLum, cStartLum);
    aEndCol = Color(cEndLum, cEndLum, cEndLum);

    SetStartColor(aStartCol);
    SetEndColor(aEndCol);
}

Gradient& Gradient::operator=( const Gradient& ) = default;

Gradient& Gradient::operator=( Gradient&& ) = default;

bool Gradient::operator==( const Gradient& rGradient ) const
{
    return mpImplGradient == rGradient.mpImplGradient;
}

const sal_uInt32 GRADIENT_DEFAULT_STEPCOUNT = 0;

void Gradient::AddGradientActions(tools::Rectangle const& rRect, GDIMetaFile& ;rMetaFile)
{
    tools::Rectangle aRect(rRect);
    aRect.Normalize();

    // do nothing if the rectangle is empty
    if (aRect.IsEmpty())
        return;

    rMetaFile.AddAction(new MetaPushAction(vcl::PushFlags::ALL));
    rMetaFile.AddAction(new MetaISectRectClipRegionAction( aRect));
    rMetaFile.AddAction(new MetaLineColorAction(Color(), false));

    // 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 );

    // calculate step count if necessary
    if (!GetSteps())
        SetSteps(GRADIENT_DEFAULT_STEPCOUNT);

    if (GetStyle() == css::awt::GradientStyle_LINEAR || GetStyle() == css::awt::GradientStyle_AXIAL)
        DrawLinearGradientToMetafile(aRect, rMetaFile);
    else
        DrawComplexGradientToMetafile(aRect, rMetaFile);

    rMetaFile.AddAction(new MetaPopAction());
}

tools::Long Gradient::GetMetafileSteps(tools::Rectangle const& rRect) const
{
    // calculate step count
    tools::Long nStepCount = GetSteps();

    if (nStepCount)
        return nStepCount;

    if (GetStyle() == css::awt::GradientStyle_LINEAR || GetStyle() == css::awt::GradientStyle_AXIAL)
        return rRect.GetHeight();
    else
        return std::min(rRect.GetWidth(), rRect.GetHeight());
}


static sal_uInt8 GetGradientColorValue(tools::Long nValue)
{
    if ( nValue < 0 )
        return 0;
    else if ( nValue > 0xFF )
        return 0xFF;
    else
        return static_cast<sal_uInt8>(nValue);
}

void Gradient::DrawLinearGradientToMetafile(tools::Rectangle const& rRect, GDIMetaFile& rMetaFile) const
{
    // get BoundRect of rotated rectangle
    tools::Rectangle aRect;
    Point aCenter;
    Degree10 nAngle = GetAngle() % 3600_deg10;

    GetBoundRect(rRect, aRect, aCenter);

    bool bLinear = (GetStyle() == css::awt::GradientStyle_LINEAR);
    double fBorder = GetBorder() * aRect.GetHeight() / 100.0;
    if ( !bLinear )
    {
        fBorder /= 2.0;
    }
    tools::Rectangle aMirrorRect = aRect; // used in style axial
    aMirrorRect.SetTop( ( aRect.Top() + aRect.Bottom() ) / 2 );
    if ( !bLinear )
    {
        aRect.SetBottom( aMirrorRect.Top() );
    }

    // colour-intensities of start- and finish; change if needed
    tools::Long    nFactor;
    Color   aStartCol   = GetStartColor();
    Color   aEndCol     = GetEndColor();
    tools::Long    nStartRed   = aStartCol.GetRed();
    tools::Long    nStartGreen = aStartCol.GetGreen();
    tools::Long    nStartBlue  = aStartCol.GetBlue();
    tools::Long    nEndRed     = aEndCol.GetRed();
    tools::Long    nEndGreen   = aEndCol.GetGreen();
    tools::Long    nEndBlue    = aEndCol.GetBlue();
    nFactor     = GetStartIntensity();
    nStartRed   = (nStartRed   * nFactor) / 100;
    nStartGreen = (nStartGreen * nFactor) / 100;
    nStartBlue  = (nStartBlue  * nFactor) / 100;
    nFactor     = GetEndIntensity();
    nEndRed     = (nEndRed   * nFactor) / 100;
    nEndGreen   = (nEndGreen * nFactor) / 100;
    nEndBlue    = (nEndBlue  * nFactor) / 100;

    // gradient style axial has exchanged start and end colors
    if ( !bLinear)
    {
        std::swap( nStartRed, nEndRed );
        std::swap( nStartGreen, nEndGreen );
        std::swap( nStartBlue, nEndBlue );
    }

    sal_uInt8   nRed;
    sal_uInt8   nGreen;
    sal_uInt8   nBlue;

    // Create border
    tools::Rectangle aBorderRect = aRect;
    tools::Polygon aPoly( 4 );
    if (fBorder > 0.0)
    {
        nRed        = static_cast<sal_uInt8>(nStartRed);
        nGreen      = static_cast<sal_uInt8>(nStartGreen);
        nBlue       = static_cast<sal_uInt8>(nStartBlue);

        rMetaFile.AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );

        aBorderRect.SetBottom( static_cast<tools::Long>( aBorderRect.Top() + fBorder ) );
        aRect.SetTop( aBorderRect.Bottom() );
        aPoly[0] = aBorderRect.TopLeft();
        aPoly[1] = aBorderRect.TopRight();
        aPoly[2] = aBorderRect.BottomRight();
        aPoly[3] = aBorderRect.BottomLeft();
        aPoly.Rotate( aCenter, nAngle );

        rMetaFile.AddAction( new MetaPolygonAction( aPoly ) );

        if ( !bLinear)
        {
            aBorderRect = aMirrorRect;
            aBorderRect.SetTop( static_cast<tools::Long>( aBorderRect.Bottom() - fBorder ) );
            aMirrorRect.SetBottom( aBorderRect.Top() );
            aPoly[0] = aBorderRect.TopLeft();
            aPoly[1] = aBorderRect.TopRight();
            aPoly[2] = aBorderRect.BottomRight();
            aPoly[3] = aBorderRect.BottomLeft();
            aPoly.Rotate( aCenter, nAngle );

            rMetaFile.AddAction( new MetaPolygonAction( aPoly ) );
        }
    }

    tools::Long nStepCount = GetMetafileSteps(aRect);

    // minimal three steps and maximal as max color steps
    tools::Long   nAbsRedSteps   = std::abs( nEndRed   - nStartRed );
    tools::Long   nAbsGreenSteps = std::abs( nEndGreen - nStartGreen );
    tools::Long   nAbsBlueSteps  = std::abs( nEndBlue  - nStartBlue );
    tools::Long   nMaxColorSteps = std::max( nAbsRedSteps , nAbsGreenSteps );
    nMaxColorSteps = std::max( nMaxColorSteps, nAbsBlueSteps );
    tools::Long nSteps = std::min( nStepCount, nMaxColorSteps );
    if ( nSteps < 3)
    {
        nSteps = 3;
    }

    double fScanInc = static_cast<double>(aRect.GetHeight()) / static_cast<double>(nSteps);
    double fGradientLine = static_cast<double>(aRect.Top());
    double fMirrorGradientLine = static_cast<double>(aMirrorRect.Bottom());

    const double 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
        double 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));

        rMetaFile.AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );

        // Polygon for this color step
        aRect.SetTop( static_cast<tools::Long>( fGradientLine + static_cast<double>(i) * fScanInc ) );
        aRect.SetBottom( static_cast<tools::Long>( fGradientLine + ( static_cast<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 );

        rMetaFile.AddAction( new MetaPolygonAction( aPoly ) );

        if ( !bLinear )
        {
            aMirrorRect.SetBottom( static_cast<tools::Long>( fMirrorGradientLine - static_cast<double>(i) * fScanInc ) );
            aMirrorRect.SetTop( static_cast<tools::Long>( fMirrorGradientLine - (static_cast<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 );

            rMetaFile.AddAction( new MetaPolygonAction( aPoly ) );
        }
    }
    if ( bLinear)
        return;

    // draw middle polygon with end color
    nRed = GetGradientColorValue(nEndRed);
    nGreen = GetGradientColorValue(nEndGreen);
    nBlue = GetGradientColorValue(nEndBlue);

    rMetaFile.AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );

    aRect.SetTop( static_cast<tools::Long>( fGradientLine + static_cast<double>(nSteps) * fScanInc ) );
    aRect.SetBottom( static_cast<tools::Long>( fMirrorGradientLine - static_cast<double>(nSteps) * fScanInc ) );
    aPoly[0] = aRect.TopLeft();
    aPoly[1] = aRect.TopRight();
    aPoly[2] = aRect.BottomRight();
    aPoly[3] = aRect.BottomLeft();
    aPoly.Rotate( aCenter, nAngle );

    rMetaFile.AddAction( new MetaPolygonAction( std::move(aPoly) ) );

}

void Gradient::DrawComplexGradientToMetafile(tools::Rectangle const& rRect, GDIMetaFile& rMetaFile) const
{
    // 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.

    tools::Rectangle aRect;
    Point aCenter;
    GetBoundRect(rRect, aRect, aCenter);

    std::optional<tools::PolyPolygon> xPolyPoly;
    xPolyPoly = tools::PolyPolygon( 2 );

    // last parameter - true if complex gradient, false if linear
    tools::Long nStepCount = GetMetafileSteps(rRect);

    // at least three steps and at most the number of colour differences
    tools::Long nSteps = std::max(nStepCount, tools::Long(2));

    Color aStartCol(GetStartColor());
    Color aEndCol(GetEndColor());

    tools::Long nStartRed = (static_cast<tools::Long>(aStartCol.GetRed()) * GetStartIntensity()) / 100;
    tools::Long nStartGreen = (static_cast<tools::Long>(aStartCol.GetGreen()) * GetStartIntensity()) / 100;
    tools::Long nStartBlue = (static_cast<tools::Long>(aStartCol.GetBlue()) * GetStartIntensity()) / 100;

    tools::Long nEndRed = (static_cast<tools::Long>(aEndCol.GetRed()) * GetEndIntensity()) / 100;
    tools::Long nEndGreen = (static_cast<tools::Long>(aEndCol.GetGreen()) * GetEndIntensity()) / 100;
    tools::Long nEndBlue = (static_cast<tools::Long>(aEndCol.GetBlue()) * GetEndIntensity()) / 100;

    tools::Long nRedSteps = nEndRed - nStartRed;
    tools::Long nGreenSteps = nEndGreen - nStartGreen;
    tools::Long nBlueSteps = nEndBlue - nStartBlue;

    tools::Long nCalcSteps  = std::abs(nRedSteps);
    tools::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;

    // determine output limits and stepsizes for all directions
    tools::Polygon aPoly;
    double  fScanLeft = aRect.Left();
    double  fScanTop = aRect.Top();
    double  fScanRight = aRect.Right();
    double  fScanBottom = aRect.Bottom();
    double fScanIncX = static_cast<double>(aRect.GetWidth()) / static_cast<double>(nSteps) * 0.5;
    double fScanIncY = static_cast<double>(aRect.GetHeight()) / static_cast<double>(nSteps) * 0.5;

    // 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 (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

    rMetaFile.AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );

    aPoly = tools::Polygon(rRect);
    xPolyPoly->Insert( aPoly );
    xPolyPoly->Insert( aPoly );

    // loop to output Polygon/PolyPolygon sequentially
    for( tools::Long i = 1; i < nSteps; i++ )
    {
        // calculate new Polygon
        fScanLeft += fScanIncX;
        aRect.SetLeft( static_cast<tools::Long>( fScanLeft ) );
        fScanTop += fScanIncY;
        aRect.SetTop( static_cast<tools::Long>( fScanTop ) );
        fScanRight -= fScanIncX;
        aRect.SetRight( static_cast<tools::Long>( fScanRight ) );
        fScanBottom -= fScanIncY;
        aRect.SetBottom( static_cast<tools::Long>( fScanBottom ) );

        if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) )
            break;

        if (GetStyle() == css::awt::GradientStyle_RADIAL || GetStyle() == css::awt::GradientStyle_ELLIPTICAL)
            aPoly = tools::Polygon( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
        else
            aPoly = tools::Polygon( aRect );

        aPoly.Rotate(aCenter, GetAngle() % 3600_deg10);

        // adapt colour accordingly
        const tools::Long nStepIndex = ( xPolyPoly ? i : ( i + 1 ) );
        nRed = GetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) / nSteps ) );
        nGreen = GetGradientColorValue( nStartGreen + ( ( nGreenSteps * nStepIndex ) / nSteps ) );
        nBlue = GetGradientColorValue( nStartBlue + ( ( nBlueSteps * nStepIndex ) / nSteps ) );

        bPaintLastPolygon = true// #107349# Paint last polygon only if loop has generated any output

        xPolyPoly->Replace( xPolyPoly->GetObject( 1 ), 0 );
        xPolyPoly->Replace( aPoly, 1 );

        rMetaFile.AddAction( new MetaPolyPolygonAction( *xPolyPoly ) );

        // #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.
        rMetaFile.AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
    }

    const tools::Polygon& rPoly = xPolyPoly->GetObject( 1 );

    if( rPoly.GetBoundRect().IsEmpty() )
        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 );
    }

    rMetaFile.AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
    rMetaFile.AddAction( new MetaPolygonAction( rPoly ) );
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=94 H=96 G=94

¤ Dauer der Verarbeitung: 0.13 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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 und die Messung sind noch experimentell.