/*
 * Copyright (C) 2016-2019 Apple Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#include "config.h"
#include "Gradient.h"

#include "FloatPoint.h"
#include "GraphicsContext.h"
#include "PlatformContextDirect2D.h"
#include <d2d1.h>
#include <wtf/MathExtras.h>
#include <wtf/RetainPtr.h>

#define GRADIENT_DRAWING 3

namespace WebCore {

void Gradient::platformDestroy()
{
    if (m_gradient)
        m_gradient->Release();
    m_gradient = nullptr;
}

ID2D1Brush* Gradient::platformGradient()
{
    ASSERT(m_gradient);
    return m_gradient;
}

ID2D1Brush* Gradient::createPlatformGradientIfNecessary(ID2D1RenderTarget* context)
{
    generateGradient(context);
    return m_gradient;
}

static bool circleIsEntirelyContained(const FloatPoint& centerA, float radiusA, const FloatPoint& centerB, float radiusB)
{
    double deltaX = centerB.x() - centerA.x();
    double deltaY = centerB.y() - centerA.y();
    double deltaRadius = radiusB - radiusA;

    return deltaX * deltaX + deltaY * deltaY < deltaRadius * deltaRadius && radiusA < radiusB;
}

void Gradient::generateGradient(ID2D1RenderTarget* renderTarget)
{
    sortStopsIfNecessary();

    Vector<D2D1_GRADIENT_STOP> gradientStops;
    // FIXME: Add support for ExtendedColor.
    for (auto stop : m_stops) {
        float r;
        float g;
        float b;
        float a;
        stop.color.getRGBA(r, g, b, a);
        gradientStops.append(D2D1::GradientStop(stop.offset, D2D1::ColorF(r, g, b, a)));
    }

    WTF::switchOn(m_data,
        [&] (const LinearData&) {
            // No action needed.
        },
        [&] (RadialData& data) {
            RELEASE_ASSERT(data.startRadius >= 0);
            RELEASE_ASSERT(data.endRadius >= 0);

            if (data.startRadius > data.endRadius) {
                gradientStops.reverse();
                for (auto& stop : gradientStops)
                    stop.position = 1.0 - stop.position;

                std::swap(data.startRadius, data.endRadius);
                std::swap(data.point0, data.point1);
            }

            if (data.startRadius) {
                RELEASE_ASSERT(data.endRadius > 0);
                float startPosition = data.startRadius / data.endRadius;
                RELEASE_ASSERT(startPosition <= 1.0);
                float availableRange = 1.0 - startPosition;
                RELEASE_ASSERT(availableRange <= 1.0 && availableRange >= 0);

                for (auto& stop : gradientStops) {
                    stop.position *= availableRange;
                    stop.position += startPosition;
                }

                // Restore the 'start' position
                auto firstStop = gradientStops.first();
                if (!WTF::areEssentiallyEqual(firstStop.position, 0.0f)) {
                    firstStop.position = 0;
                    gradientStops.insert(0, firstStop);
                }
            }
        },
        [&] (const ConicData&) {
            // FIXME: Assess whether needed for Conic Gradients.
        }
    );

    COMPtr<ID2D1GradientStopCollection> gradientStopCollection;
    HRESULT hr = renderTarget->CreateGradientStopCollection(gradientStops.data(), gradientStops.size(), &gradientStopCollection);
    RELEASE_ASSERT(SUCCEEDED(hr));

    if (m_gradient) {
        m_gradient->Release();
        m_gradient = nullptr;
    }

    WTF::switchOn(m_data,
        [&] (const LinearData& data) {
            ID2D1LinearGradientBrush* linearGradient = nullptr;
            hr = renderTarget->CreateLinearGradientBrush(
                D2D1::LinearGradientBrushProperties(data.point0, data.point1),
                D2D1::BrushProperties(), gradientStopCollection.get(),
                &linearGradient);
            RELEASE_ASSERT(SUCCEEDED(hr));
            m_gradient = linearGradient;
        },
        [&] (const RadialData& data) {
            FloatSize offset;
            if (!circleIsEntirelyContained(data.point0, data.startRadius, data.point1, data.endRadius))
                offset = (data.point1.scaled(data.startRadius) - data.point0.scaled(data.endRadius)) / (data.endRadius - data.startRadius);
            else
                offset = data.point0 - data.point1;

            FloatPoint center = data.point1;
            float radiusX = data.endRadius;
            float radiusY = radiusX / data.aspectRatio;

            ID2D1RadialGradientBrush* radialGradient = nullptr;
            hr = renderTarget->CreateRadialGradientBrush(
                D2D1::RadialGradientBrushProperties(center, D2D1::Point2F(offset.width(), offset.height()), radiusX, radiusY),
                D2D1::BrushProperties(), gradientStopCollection.get(),
                &radialGradient);
            RELEASE_ASSERT(SUCCEEDED(hr));
            m_gradient = radialGradient;
        },
        [&] (const ConicData&) {
            // FIXME: implement conic gradient rendering.
        }
    );

    hash();
}

void Gradient::fill(GraphicsContext& context, const FloatRect& rect)
{
    auto d2dContext = context.platformContext()->renderTarget();

    WTF::switchOn(m_data,
        [&] (const LinearData& data) {
            if (!m_cachedHash || !m_gradient)
                generateGradient(d2dContext);

#if !ASSERT_DISABLED
            d2dContext->SetTags(GRADIENT_DRAWING, __LINE__);
#endif

            const D2D1_RECT_F d2dRect = rect;
            d2dContext->FillRectangle(&d2dRect, m_gradient);
        },
        [&] (const RadialData& data) {
            bool needScaling = data.aspectRatio != 1;
            if (needScaling) {
                context.save();
                // Scale from the center of the gradient. We only ever scale non-deprecated gradients,
                // for which m_p0 == m_p1.
                ASSERT(data.point0 == data.point1);

                D2D1_MATRIX_3X2_F ctm = { };
                d2dContext->GetTransform(&ctm);

                AffineTransform transform(ctm);
                transform.translate(data.point0);
                transform.scaleNonUniform(1.0, 1.0 / data.aspectRatio);
                transform.translate(-data.point0);

                d2dContext->SetTransform(ctm);
            }

            if (!m_cachedHash || !m_gradient)
                generateGradient(d2dContext);

#if !ASSERT_DISABLED
            d2dContext->SetTags(GRADIENT_DRAWING, __LINE__);
#endif

            const D2D1_RECT_F d2dRect = rect;
            d2dContext->FillRectangle(&d2dRect, m_gradient);

            if (needScaling)
                context.restore();
        },
        [&] (const ConicData&) {
            // FIXME: implement conic gradient rendering.
        }
    );
}

}
