/*
 * Copyright (C) 2017 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. AND ITS CONTRIBUTORS ``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 ITS 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 "OffscreenCanvas.h"

#include "CanvasRenderingContext.h"
#include "ImageBitmap.h"
#include "JSDOMPromiseDeferred.h"
#include "WebGLRenderingContext.h"
#include <wtf/IsoMallocInlines.h>

namespace WebCore {

WTF_MAKE_ISO_ALLOCATED_IMPL(OffscreenCanvas);

Ref<OffscreenCanvas> OffscreenCanvas::create(ScriptExecutionContext& context, unsigned width, unsigned height)
{
    return adoptRef(*new OffscreenCanvas(context, width, height));
}

OffscreenCanvas::OffscreenCanvas(ScriptExecutionContext& context, unsigned width, unsigned height)
    : ContextDestructionObserver(&context)
    , m_size(width, height)
{
}

OffscreenCanvas::~OffscreenCanvas()
{
    notifyObserversCanvasDestroyed();

    m_context = nullptr;
}

unsigned OffscreenCanvas::width() const
{
    return m_size.width();
}

void OffscreenCanvas::setWidth(unsigned newWidth)
{
    return m_size.setWidth(newWidth);
}

unsigned OffscreenCanvas::height() const
{
    return m_size.height();
}

void OffscreenCanvas::setHeight(unsigned newHeight)
{
    return m_size.setHeight(newHeight);
}

const IntSize& OffscreenCanvas::size() const
{
    return m_size;
}

void OffscreenCanvas::setSize(const IntSize& newSize)
{
    m_size = newSize;
}

#if ENABLE(WEBGL)
ExceptionOr<OffscreenRenderingContext> OffscreenCanvas::getContext(JSC::ExecState& state, RenderingContextType contextType, Vector<JSC::Strong<JSC::Unknown>>&& arguments)
{
    if (m_context && contextType == RenderingContextType::Webgl)
        return { RefPtr<WebGLRenderingContext> { &downcast<WebGLRenderingContext>(*m_context) } };

    if (contextType == RenderingContextType::Webgl) {
        auto scope = DECLARE_THROW_SCOPE(state.vm());
        auto attributes = convert<IDLDictionary<WebGLContextAttributes>>(state, !arguments.isEmpty() ? arguments[0].get() : JSC::jsUndefined());
        RETURN_IF_EXCEPTION(scope, Exception { ExistingExceptionError });

        m_context = WebGLRenderingContextBase::create(*this, attributes, "webgl");
        if (!m_context)
            return { nullptr };

        return { RefPtr<WebGLRenderingContext> { &downcast<WebGLRenderingContext>(*m_context) } };
    }

    return { nullptr };
}
#endif

RefPtr<ImageBitmap> OffscreenCanvas::transferToImageBitmap()
{
    if (!m_context)
        return nullptr;

#if ENABLE(WEBGL)
    if (!is<WebGLRenderingContext>(*m_context))
        return nullptr;

    auto webGLContext = &downcast<WebGLRenderingContext>(*m_context);

    // FIXME: We're supposed to create an ImageBitmap using the backing
    // store from this canvas (or its context), but for now we'll just
    // create a new bitmap and paint into it.

    auto imageBitmap = ImageBitmap::create(m_size);
    if (!imageBitmap->buffer())
        return nullptr;

    auto* gc3d = webGLContext->graphicsContext3D();
    gc3d->paintRenderingResultsToCanvas(imageBitmap->buffer());

    // FIXME: The transfer algorithm requires that the canvas effectively
    // creates a new backing store. Since we're not doing that yet, we
    // need to erase what's there.

    GC3Dfloat clearColor[4];
    gc3d->getFloatv(GraphicsContext3D::COLOR_CLEAR_VALUE, clearColor);
    gc3d->clearColor(0, 0, 0, 0);
    gc3d->clear(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT);
    gc3d->clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);

    return imageBitmap;
#else
    return nullptr;
#endif
}

}
