/*
 * 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::JSGlobalObject& 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
}

}
