/*
 * 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 "ImageBitmapRenderingContext.h"

#include "HTMLCanvasElement.h"
#include "ImageBitmap.h"
#include "ImageBuffer.h"
#include "InspectorInstrumentation.h"
#include <wtf/IsoMallocInlines.h>

namespace WebCore {

WTF_MAKE_ISO_ALLOCATED_IMPL(ImageBitmapRenderingContext);

#if USE(IOSURFACE_CANVAS_BACKING_STORE)
static RenderingMode bufferRenderingMode = RenderingMode::Accelerated;
#else
static RenderingMode bufferRenderingMode = RenderingMode::Unaccelerated;
#endif

std::unique_ptr<ImageBitmapRenderingContext> ImageBitmapRenderingContext::create(CanvasBase& canvas, ImageBitmapRenderingContextSettings&& settings)
{
    auto renderingContext = std::unique_ptr<ImageBitmapRenderingContext>(new ImageBitmapRenderingContext(canvas, WTFMove(settings)));

    InspectorInstrumentation::didCreateCanvasRenderingContext(*renderingContext);

    return renderingContext;
}

ImageBitmapRenderingContext::ImageBitmapRenderingContext(CanvasBase& canvas, ImageBitmapRenderingContextSettings&& settings)
    : CanvasRenderingContext(canvas)
    , m_settings(WTFMove(settings))
{
    setOutputBitmap(nullptr);
}

ImageBitmapRenderingContext::~ImageBitmapRenderingContext() = default;

HTMLCanvasElement* ImageBitmapRenderingContext::canvas() const
{
    auto& base = canvasBase();
    if (!is<HTMLCanvasElement>(base))
        return nullptr;
    return &downcast<HTMLCanvasElement>(base);
}

bool ImageBitmapRenderingContext::isAccelerated() const
{
    return bufferRenderingMode == RenderingMode::Accelerated;
}

void ImageBitmapRenderingContext::setOutputBitmap(RefPtr<ImageBitmap> imageBitmap)
{
    // 1. If a bitmap argument was not provided, then:

    if (!imageBitmap) {

        // 1.1. Set context's bitmap mode to blank.

        m_bitmapMode = BitmapMode::Blank;

        // 1.2. Let canvas be the canvas element to which context is bound.

        // 1.3. Set context's output bitmap to be transparent black with an
        //      intrinsic width equal to the numeric value of canvas's width attribute
        //      and an intrinsic height equal to the numeric value of canvas's height
        //      attribute, those values being interpreted in CSS pixels.

        // FIXME: What is the point of creating a full size transparent buffer that
        // can never be changed? Wouldn't a 1x1 buffer give the same rendering? The
        // only reason I can think of is toDataURL(), but that doesn't seem like
        // a good enough argument to waste memory.

        canvas()->setImageBufferAndMarkDirty(ImageBuffer::create(FloatSize(canvas()->width(), canvas()->height()), bufferRenderingMode, 1, DestinationColorSpace::SRGB(), PixelFormat::BGRA8));

        // 1.4. Set the output bitmap's origin-clean flag to true.

        canvas()->setOriginClean();
        return;
    }

    // 2. If a bitmap argument was provided, then:

    // 2.1. Set context's bitmap mode to valid.

    m_bitmapMode = BitmapMode::Valid;

    // 2.2. Set context's output bitmap to refer to the same underlying
    //      bitmap data as bitmap, without making a copy.
    //      Note: the origin-clean flag of bitmap is included in the
    //      bitmap data to be referenced by context's output bitmap.

    if (imageBitmap->originClean())
        canvas()->setOriginClean();
    else
        canvas()->setOriginTainted();
    canvas()->setImageBufferAndMarkDirty(imageBitmap->takeImageBuffer());
}

ExceptionOr<void> ImageBitmapRenderingContext::transferFromImageBitmap(RefPtr<ImageBitmap> imageBitmap)
{
    // 1. Let bitmapContext be the ImageBitmapRenderingContext object on which
    //    the transferFromImageBitmap() method was called.

    // 2. If imageBitmap is null, then run the steps to set an ImageBitmapRenderingContext's
    //    output bitmap, with bitmapContext as the context argument and no bitmap argument,
    //    then abort these steps.

    if (!imageBitmap) {
        setOutputBitmap(nullptr);
        return { };
    }

    // 3. If the value of imageBitmap's [[Detached]] internal slot is set to true,
    //    then throw an "InvalidStateError" DOMException and abort these steps.

    if (imageBitmap->isDetached())
        return Exception { InvalidStateError };

    // 4. Run the steps to set an ImageBitmapRenderingContext's output bitmap,
    //    with the context argument equal to bitmapContext, and the bitmap
    //    argument referring to imageBitmap's underlying bitmap data.

    setOutputBitmap(imageBitmap);

    // 5. Set the value of imageBitmap's [[Detached]] internal slot to true.
    // 6. Unset imageBitmap's bitmap data.

    // Note that the algorithm in the specification is currently a bit
    // muddy here. The setOutputBitmap step above had to transfer ownership
    // from the imageBitmap to this object, which requires a detach and unset,
    // so this step isn't necessary, but we'll do it anyway.

    imageBitmap->close();

    return { };
}

}
