oox: import gradient fill to model::FormatScheme

Change-Id: I90bc7cf4239f08efbc7239928c34ccdbec20cb2c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147575
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
diff --git a/include/docmodel/theme/FormatScheme.hxx b/include/docmodel/theme/FormatScheme.hxx
index a256532..39fa5d3 100644
--- a/include/docmodel/theme/FormatScheme.hxx
+++ b/include/docmodel/theme/FormatScheme.hxx
@@ -159,6 +159,52 @@ public:
    }
};

class DOCMODEL_DLLPUBLIC GradientStop
{
public:
    double mfPosition = 0.0; // 0.0 - 1.0
    ColorDefinition maColor;
};

enum class GradientType
{
    Undefined,
    Linear,
    Circle,
    Rectangle,
    Shape,
};

struct DOCMODEL_DLLPUBLIC LinearGradientProperties
{
    sal_Int32 mnAngle = 0;
    bool mbScaled = false;
};

struct DOCMODEL_DLLPUBLIC RelativeRectangle
{
    sal_Int32 mnLeft = 0;
    sal_Int32 mnTop = 0;
    sal_Int32 mnRight = 0;
    sal_Int32 mnBottom = 0;
};

class DOCMODEL_DLLPUBLIC GradientFill : public Fill
{
public:
    bool mbRotateWithShape = false;
    GradientType meGradientType = GradientType::Undefined;
    std::vector<GradientStop> maGradientStops;
    LinearGradientProperties maLinearGradient;
    RelativeRectangle maFillToRectangle;
    RelativeRectangle maTileRectangle;

    GradientFill()
        : Fill(FillType::Gradient)
    {
    }
};

// Format Scheme

class DOCMODEL_DLLPUBLIC FillStyle
diff --git a/include/oox/drawingml/drawingmltypes.hxx b/include/oox/drawingml/drawingmltypes.hxx
index 5fe86d5..8dd5dee 100644
--- a/include/oox/drawingml/drawingmltypes.hxx
+++ b/include/oox/drawingml/drawingmltypes.hxx
@@ -31,6 +31,7 @@
#include <com/sun/star/style/TabAlign.hpp>
#include <com/sun/star/uno/Reference.hxx>
#include <o3tl/unit_conversion.hxx>
#include <docmodel/theme/FormatScheme.hxx>
#include <oox/dllapi.h>
#include <rtl/ustring.hxx>
#include <sal/types.h>
@@ -100,6 +101,9 @@ css::awt::Size GetSize2D( const css::uno::Reference< css::xml::sax::XFastAttribu
/** converts the attributes from a CT_RelativeRect to an IntegerRectangle2D */
css::geometry::IntegerRectangle2D GetRelativeRect( const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttributes );

void fillRelativeRectangle(model::RelativeRectangle& rRelativeRectangle,
                           const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttributes);

/** converts EMUs into 1/100th mmm */
sal_Int32 GetCoordinate( sal_Int32 nValue );

diff --git a/oox/inc/drawingml/misccontexts.hxx b/oox/inc/drawingml/misccontexts.hxx
index e2e255d..6bbaa74 100644
--- a/oox/inc/drawingml/misccontexts.hxx
+++ b/oox/inc/drawingml/misccontexts.hxx
@@ -42,10 +42,9 @@ public:
class GradientFillContext final : public ::oox::core::ContextHandler2
{
public:
    explicit            GradientFillContext(
                            ::oox::core::ContextHandler2Helper const & rParent,
                            const ::oox::AttributeList& rAttribs,
                            GradientFillProperties& rGradientProps );
    explicit GradientFillContext(::oox::core::ContextHandler2Helper const & rParent,
        const ::oox::AttributeList& rAttribs, GradientFillProperties& rGradientProps,
        model::GradientFill* pGradientFill);

    virtual ::oox::core::ContextHandlerRef
                        onCreateContext(
@@ -53,6 +52,7 @@ public:
                            const ::oox::AttributeList& rAttribs ) override;

private:
    model::GradientFill* mpGradientFill;
    GradientFillProperties& mrGradientProps;
};

diff --git a/oox/source/drawingml/drawingmltypes.cxx b/oox/source/drawingml/drawingmltypes.cxx
index fc2f28d..d0bf1bf 100644
--- a/oox/source/drawingml/drawingmltypes.cxx
+++ b/oox/source/drawingml/drawingmltypes.cxx
@@ -400,6 +400,14 @@ IntegerRectangle2D GetRelativeRect( const Reference< XFastAttributeList >& xAttr
    return r;
}

void fillRelativeRectangle(model::RelativeRectangle& rRelativeRectangle, const Reference<XFastAttributeList>& xAttribs)
{
    rRelativeRectangle.mnLeft = GetST_Percentage(xAttribs->getOptionalValue(XML_l));
    rRelativeRectangle.mnTop = GetST_Percentage(xAttribs->getOptionalValue(XML_t));
    rRelativeRectangle.mnRight = GetST_Percentage(xAttribs->getOptionalValue(XML_r));
    rRelativeRectangle.mnBottom = GetST_Percentage(xAttribs->getOptionalValue(XML_b));
}

/** converts the attributes from a CT_Size2D into an awt Size with 1/100thmm */
awt::Size GetSize2D( const Reference< XFastAttributeList >& xAttribs )
{
diff --git a/oox/source/drawingml/misccontexts.cxx b/oox/source/drawingml/misccontexts.cxx
index 9a5ff0e..e72e6ea 100644
--- a/oox/source/drawingml/misccontexts.cxx
+++ b/oox/source/drawingml/misccontexts.cxx
@@ -44,13 +44,17 @@ SolidFillContext::SolidFillContext(ContextHandler2Helper const & rParent, FillPr
SolidFillContext::~SolidFillContext()
{}

GradientFillContext::GradientFillContext( ContextHandler2Helper const & rParent,
        const AttributeList& rAttribs, GradientFillProperties& rGradientProps ) :
    ContextHandler2( rParent ),
    mrGradientProps( rGradientProps )
GradientFillContext::GradientFillContext(ContextHandler2Helper const & rParent,
        const AttributeList& rAttribs, GradientFillProperties& rGradientProps, model::GradientFill* pGradientFill)
    : ContextHandler2(rParent)
    , mpGradientFill(pGradientFill)
    , mrGradientProps(rGradientProps)
{
    auto oRotateWithShape = rAttribs.getBool(XML_rotWithShape);
    mrGradientProps.moShadeFlip = rAttribs.getToken( XML_flip );
    mrGradientProps.moRotateWithShape = rAttribs.getBool( XML_rotWithShape );
    mrGradientProps.moRotateWithShape = oRotateWithShape;
    if (mpGradientFill && oRotateWithShape)
        mpGradientFill->mbRotateWithShape = *oRotateWithShape;
}

ContextHandlerRef GradientFillContext::onCreateContext(
@@ -62,30 +66,73 @@ ContextHandlerRef GradientFillContext::onCreateContext(
            return this;    // for gs elements

        case A_TOKEN( gs ):
            if( rAttribs.hasAttribute( XML_pos ) )
            if (rAttribs.hasAttribute(XML_pos))
            {
                double fPosition = getLimitedValue< double >( rAttribs.getDouble( XML_pos, 0.0 ) / 100000.0, 0.0, 1.0 );
                auto aElement = mrGradientProps.maGradientStops.emplace( fPosition, Color() );
                return new ColorContext( *this, aElement->second );
                double fPosition = getLimitedValue<double>(rAttribs.getDouble(XML_pos, 0.0) / 100000.0, 0.0, 1.0);
                auto aElement = mrGradientProps.maGradientStops.emplace(fPosition, Color());

                model::ColorDefinition* pColorDefinition = nullptr;
                if (mpGradientFill)
                {
                    model::GradientStop& rStop = mpGradientFill->maGradientStops.emplace_back();
                    rStop.mfPosition = fPosition;
                    pColorDefinition = &rStop.maColor;
                }

                return new ColorContext(*this, aElement->second, pColorDefinition);
            }
        break;

        case A_TOKEN( lin ):
            mrGradientProps.moShadeAngle = rAttribs.getInteger( XML_ang );
            mrGradientProps.moShadeScaled = rAttribs.getBool( XML_scaled );
        {
            mrGradientProps.moShadeAngle = rAttribs.getInteger(XML_ang);
            mrGradientProps.moShadeScaled = rAttribs.getBool(XML_scaled);

            if (mpGradientFill)
            {
                mpGradientFill->meGradientType = model::GradientType::Linear;
                mpGradientFill->maLinearGradient.mnAngle = rAttribs.getInteger(XML_ang, 0);
                mpGradientFill->maLinearGradient.mbScaled = rAttribs.getBool(XML_scaled, false);
            }
        }
        break;

        case A_TOKEN( path ):
        {
            // always set a path type, this disables linear gradient in conversion
            mrGradientProps.moGradientPath = rAttribs.getToken( XML_path, XML_rect );
            sal_Int32 nToken = rAttribs.getToken(XML_path, XML_rect);
            mrGradientProps.moGradientPath = nToken;
            if (mpGradientFill)
            {
                switch (nToken)
                {
                    case XML_rect:
                        mpGradientFill->meGradientType = model::GradientType::Rectangle;
                        break;
                    case XML_circle:
                        mpGradientFill->meGradientType = model::GradientType::Circle;
                        break;
                    case XML_shape:
                        mpGradientFill->meGradientType = model::GradientType::Shape;
                        break;
                    default:
                        break;
                }
            }
            return this;    // for fillToRect element

        }
        case A_TOKEN( fillToRect ):
        {
            mrGradientProps.moFillToRect = GetRelativeRect( rAttribs.getFastAttributeList() );
            if (mpGradientFill)
                fillRelativeRectangle(mpGradientFill->maFillToRectangle, rAttribs.getFastAttributeList());
        }
        break;

        case A_TOKEN( tileRect ):
            mrGradientProps.moTileRect = GetRelativeRect( rAttribs.getFastAttributeList() );
            mrGradientProps.moTileRect = GetRelativeRect(rAttribs.getFastAttributeList());
            if (mpGradientFill)
                fillRelativeRectangle(mpGradientFill->maTileRectangle, rAttribs.getFastAttributeList());
        break;
    }
    return nullptr;
@@ -105,9 +152,9 @@ ContextHandlerRef PatternFillContext::onCreateContext(
    switch( nElement )
    {
        case A_TOKEN( bgClr ):
            return new ColorContext( *this, mrPatternProps.maPattBgColor );
            return new ColorContext(*this, mrPatternProps.maPattBgColor, nullptr);
        case A_TOKEN( fgClr ):
            return new ColorContext( *this, mrPatternProps.maPattFgColor );
            return new ColorContext(*this, mrPatternProps.maPattFgColor, nullptr);
    }
    return nullptr;
}
@@ -134,9 +181,9 @@ ContextHandlerRef ColorChangeContext::onCreateContext(
    switch( nElement )
    {
        case A_TOKEN( clrFrom ):
            return new ColorContext( *this, mrBlipProps.maColorChangeFrom );
            return new ColorContext(*this, mrBlipProps.maColorChangeFrom, nullptr);
        case A_TOKEN( clrTo ):
            return new ColorContext( *this, mrBlipProps.maColorChangeTo );
            return new ColorContext(*this, mrBlipProps.maColorChangeTo, nullptr);
    }
    return nullptr;
}
@@ -220,7 +267,7 @@ DuotoneContext::~DuotoneContext()
        sal_Int32 /*nElement*/, const AttributeList& /*rAttribs*/ )
{
    if( mnColorIndex < 2 )
        return new ColorValueContext( *this, mrBlipProps.maDuotoneColors[mnColorIndex++] );
        return new ColorValueContext(*this, mrBlipProps.maDuotoneColors[mnColorIndex++], nullptr);
    return nullptr;
}

@@ -307,7 +354,13 @@ ContextHandlerRef FillPropertiesContext::createFillContext(
        case A_TOKEN( gradFill ):
        {
            rFillProps.moFillType = getBaseToken(nElement);
            return new GradientFillContext(rParent, rAttribs, rFillProps.maGradientProps);
            model::GradientFill* pGradientFill = nullptr;
            if (pFillStyle)
            {
                pFillStyle->mpFill = std::make_unique<model::GradientFill>();
                pGradientFill = static_cast<model::GradientFill*>(pFillStyle->mpFill.get());
            }
            return new GradientFillContext(rParent, rAttribs, rFillProps.maGradientProps, pGradientFill);
        }
        case A_TOKEN( pattFill ):
        {