/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkCoreBlitters.h"
#include "SkColorPriv.h"
#include "SkShader.h"
#include "SkUtils.h"
#include "SkXfermode.h"
#include "SkBlitMask.h"
#include "SkTemplates.h"
#include "SkPM4f.h"

template <typename State> class SkState_Blitter : public SkRasterBlitter {
    typedef SkRasterBlitter INHERITED;
    State fState;

public:
    SkState_Blitter(const SkPixmap& device, const SkPaint& paint)
        : INHERITED(device)
        , fState(device.info(), paint, nullptr)
    {}

    void blitH(int x, int y, int width) override {
        SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());

        fState.fProc1(fState.fXfer, State::WritableAddr(fDevice, x, y),
                      &fState.fPM4f, width, nullptr);
    }

    void blitV(int x, int y, int height, SkAlpha alpha) override {
        SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height());

        typename State::DstType* device = State::WritableAddr(fDevice, x, y);
        size_t                 deviceRB = fDevice.rowBytes();

        for (int i = 0; i < height; ++i) {
            fState.fProc1(fState.fXfer, device, &fState.fPM4f, 1, &alpha);
            device = (typename State::DstType*)((char*)device + deviceRB);
        }
    }

    void blitRect(int x, int y, int width, int height) override {
        SkASSERT(x >= 0 && y >= 0 &&
                 x + width <= fDevice.width() && y + height <= fDevice.height());

        typename State::DstType* device = State::WritableAddr(fDevice, x, y);
        size_t        deviceRB = fDevice.rowBytes();

        do {
            fState.fProc1(fState.fXfer, device, &fState.fPM4f, width, nullptr);
            y += 1;
            device = (typename State::DstType*)((char*)device + deviceRB);
        } while (--height > 0);
    }

    void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override {
        typename State::DstType* device = State::WritableAddr(fDevice, x, y);

        for (;;) {
            int count = *runs;
            if (count <= 0) {
                break;
            }
            int aa = *antialias;
            if (aa) {
                if (aa == 255) {
                    fState.fProc1(fState.fXfer, device, &fState.fPM4f, count, nullptr);
                } else {
                    for (int i = 0; i < count; ++i) {
                        fState.fProc1(fState.fXfer, &device[i], &fState.fPM4f, 1, antialias);
                    }
                }
            }
            device += count;
            runs += count;
            antialias += count;
            x += count;
        }
    }

    void blitLCDMask(const SkMask& mask, const SkIRect& clip) {
        auto proc = fState.getLCDProc(SkXfermode::kSrcIsSingle_LCDFlag);

        const int x = clip.fLeft;
        const int width = clip.width();
        const int y = clip.fTop;
        const int height = clip.height();

        typename State::DstType* device = State::WritableAddr(fDevice, x, y);
        const size_t dstRB = fDevice.rowBytes();
        const uint16_t* maskRow = (const uint16_t*)mask.getAddr(x, y);
        const size_t maskRB = mask.fRowBytes;

        for (int i = 0; i < height; ++i) {
            proc(device, &fState.fPM4f, width, maskRow);
            device = (typename State::DstType*)((char*)device + dstRB);
            maskRow = (const uint16_t*)((const char*)maskRow + maskRB);
        }
    }

    void blitMask(const SkMask& mask, const SkIRect& clip) override {
        if (SkMask::kLCD16_Format == mask.fFormat) {
            this->blitLCDMask(mask, clip);
            return;
        }
        if (SkMask::kA8_Format != mask.fFormat) {
            this->INHERITED::blitMask(mask, clip);
            return;
        }

        SkASSERT(mask.fBounds.contains(clip));

        const int x = clip.fLeft;
        const int width = clip.width();
        const int y = clip.fTop;
        const int height = clip.height();

        typename State::DstType* device = State::WritableAddr(fDevice, x, y);
        const size_t dstRB = fDevice.rowBytes();
        const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y);
        const size_t maskRB = mask.fRowBytes;

        for (int i = 0; i < height; ++i) {
            fState.fProc1(fState.fXfer, device, &fState.fPM4f, width, maskRow);
            device = (typename State::DstType*)((char*)device + dstRB);
            maskRow += maskRB;
        }
    }
};

///////////////////////////////////////////////////////////////////////////////////////////////////

template <typename State> class SkState_Shader_Blitter : public SkShaderBlitter {
public:
    SkState_Shader_Blitter(const SkPixmap& device, const SkPaint& paint,
                           const SkShader::Context::BlitState& bstate)
        : INHERITED(device, paint, bstate.fCtx)
        , fState(device.info(), paint, bstate.fCtx)
        , fBState(bstate)
        , fBlitBW(bstate.fBlitBW)
        , fBlitAA(bstate.fBlitAA)
    {}

    void blitH(int x, int y, int width) override {
        SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());

        if (fBlitBW) {
            fBlitBW(&fBState, x, y, fDevice, width);
            return;
        }

        typename State::DstType* device = State::WritableAddr(fDevice, x, y);
        fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
        fState.fProcN(fState.fXfer, device, fState.fBuffer, width, nullptr);
    }

    void blitV(int x, int y, int height, SkAlpha alpha) override {
        SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height());

        if (fBlitAA) {
            for (const int bottom = y + height; y < bottom; ++y) {
                fBlitAA(&fBState, x, y, fDevice, 1, &alpha);
            }
            return;
        }

        typename State::DstType* device = State::WritableAddr(fDevice, x, y);
        size_t                   deviceRB = fDevice.rowBytes();

        if (fConstInY) {
            fShaderContext->shadeSpan4f(x, y, fState.fBuffer, 1);
        }
        for (const int bottom = y + height; y < bottom; ++y) {
            if (!fConstInY) {
                fShaderContext->shadeSpan4f(x, y, fState.fBuffer, 1);
            }
            fState.fProcN(fState.fXfer, device, fState.fBuffer, 1, &alpha);
            device = (typename State::DstType*)((char*)device + deviceRB);
        }
    }

    void blitRect(int x, int y, int width, int height) override {
        SkASSERT(x >= 0 && y >= 0 &&
                 x + width <= fDevice.width() && y + height <= fDevice.height());

        if (fBlitBW) {
            for (const int bottom = y + height; y < bottom; ++y) {
                fBlitBW(&fBState, x, y, fDevice, width);
            }
            return;
        }

        typename State::DstType* device = State::WritableAddr(fDevice, x, y);
        size_t                   deviceRB = fDevice.rowBytes();

        if (fConstInY) {
            fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
        }
        for (const int bottom = y + height; y < bottom; ++y) {
            if (!fConstInY) {
                fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
            }
            fState.fProcN(fState.fXfer, device, fState.fBuffer, width, nullptr);
            device = (typename State::DstType*)((char*)device + deviceRB);
        }
    }

    void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override {
        typename State::DstType* device = State::WritableAddr(fDevice, x, y);

        for (;;) {
            int count = *runs;
            if (count <= 0) {
                break;
            }
            int aa = *antialias;
            if (aa) {
                if (fBlitBW && (aa == 255)) {
                    fBlitBW(&fBState, x, y, fDevice, count);
                } else {
                    fShaderContext->shadeSpan4f(x, y, fState.fBuffer, count);
                    if (aa == 255) {
                        fState.fProcN(fState.fXfer, device, fState.fBuffer, count, nullptr);
                    } else {
                        for (int i = 0; i < count; ++i) {
                            fState.fProcN(fState.fXfer, &device[i], &fState.fBuffer[i], 1, antialias);
                        }
                    }
                }
            }
            device += count;
            runs += count;
            antialias += count;
            x += count;
        }
    }

    void blitLCDMask(const SkMask& mask, const SkIRect& clip) {
        auto proc = fState.getLCDProc(0);

        const int x = clip.fLeft;
        const int width = clip.width();
        int y = clip.fTop;

        typename State::DstType* device = State::WritableAddr(fDevice, x, y);
        const size_t deviceRB = fDevice.rowBytes();
        const uint16_t* maskRow = (const uint16_t*)mask.getAddr(x, y);
        const size_t maskRB = mask.fRowBytes;

        if (fConstInY) {
            fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
        }
        for (; y < clip.fBottom; ++y) {
            if (!fConstInY) {
                fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
            }
            proc(device, fState.fBuffer, width, maskRow);
            device = (typename State::DstType*)((char*)device + deviceRB);
            maskRow = (const uint16_t*)((const char*)maskRow + maskRB);
        }
    }

    void blitMask(const SkMask& mask, const SkIRect& clip) override {
        if (SkMask::kLCD16_Format == mask.fFormat) {
            this->blitLCDMask(mask, clip);
            return;
        }
        if (SkMask::kA8_Format != mask.fFormat) {
            this->INHERITED::blitMask(mask, clip);
            return;
        }

        SkASSERT(mask.fBounds.contains(clip));

        const int x = clip.fLeft;
        const int width = clip.width();
        int y = clip.fTop;
        const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y);
        const size_t maskRB = mask.fRowBytes;

        if (fBlitAA) {
            for (; y < clip.fBottom; ++y) {
                fBlitAA(&fBState, x, y, fDevice, width, maskRow);
                maskRow += maskRB;
            }
            return;
        }

        typename State::DstType* device = State::WritableAddr(fDevice, x, y);
        const size_t deviceRB = fDevice.rowBytes();

        if (fConstInY) {
            fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
        }
        for (; y < clip.fBottom; ++y) {
            if (!fConstInY) {
                fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
            }
            fState.fProcN(fState.fXfer, device, fState.fBuffer, width, maskRow);
            device = (typename State::DstType*)((char*)device + deviceRB);
            maskRow += maskRB;
        }
    }

protected:
    State                        fState;
    SkShader::Context::BlitState fBState;
    SkShader::Context::BlitBW    fBlitBW;
    SkShader::Context::BlitAA    fBlitAA;

    typedef SkShaderBlitter INHERITED;
};

///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////

static bool is_opaque(const SkPaint& paint, const SkShader::Context* shaderContext) {
    return shaderContext ? SkToBool(shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag)
    : 0xFF == paint.getAlpha();
}

struct State4f {
    State4f(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext) {
        fXfer = paint.getXfermode();
        if (shaderContext) {
            fBuffer.reset(info.width());
        } else {
            fPM4f = SkColor4f::FromColor(paint.getColor()).premul();
        }
        fFlags = 0;
    }

    SkXfermode*             fXfer;
    SkPM4f                  fPM4f;
    SkAutoTMalloc<SkPM4f>   fBuffer;
    uint32_t                fFlags;

    SkShader::Context::BlitState fBState;
};

struct State32 : State4f {
    typedef uint32_t    DstType;

    SkXfermode::D32Proc fProc1;
    SkXfermode::D32Proc fProcN;

    State32(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext)
        : State4f(info, paint, shaderContext)
    {
        if (is_opaque(paint, shaderContext)) {
            fFlags |= SkXfermode::kSrcIsOpaque_D32Flag;
        }
        if (info.gammaCloseToSRGB()) {
            fFlags |= SkXfermode::kDstIsSRGB_D32Flag;
        }
        fProc1 = SkXfermode::GetD32Proc(fXfer, fFlags | SkXfermode::kSrcIsSingle_D32Flag);
        fProcN = SkXfermode::GetD32Proc(fXfer, fFlags);
    }

    SkXfermode::LCD32Proc getLCDProc(uint32_t oneOrManyFlag) const {
        uint32_t flags = fFlags & 1;
        if (fFlags & SkXfermode::kDstIsSRGB_D32Flag) {
            flags |= SkXfermode::kDstIsSRGB_LCDFlag;
        }
        return SkXfermode::GetLCD32Proc(flags | oneOrManyFlag);
    }

    static DstType* WritableAddr(const SkPixmap& device, int x, int y) {
        return device.writable_addr32(x, y);
    }
};

struct StateF16 : State4f {
    typedef uint64_t    DstType;

    SkXfermode::F16Proc fProc1;
    SkXfermode::F16Proc fProcN;

    StateF16(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext)
        : State4f(info, paint, shaderContext)
    {
        if (is_opaque(paint, shaderContext)) {
            fFlags |= SkXfermode::kSrcIsOpaque_F16Flag;
        }
        SkASSERT(kRGBA_F16_SkColorType == info.colorType());
        fProc1 = SkXfermode::GetF16Proc(fXfer, fFlags | SkXfermode::kSrcIsSingle_F16Flag);
        fProcN = SkXfermode::GetF16Proc(fXfer, fFlags);
    }

    SkXfermode::LCDF16Proc getLCDProc(uint32_t oneOrManyFlag) const {
        uint32_t flags = fFlags & 1;
        return SkXfermode::GetLCDF16Proc(flags | oneOrManyFlag);
    }

    static DstType* WritableAddr(const SkPixmap& device, int x, int y) {
        return device.writable_addr64(x, y);
    }
};

template <typename State> SkBlitter* create(const SkPixmap& device, const SkPaint& paint,
                                            SkShader::Context* shaderContext,
                                            SkTBlitterAllocator* allocator) {
    SkASSERT(allocator != nullptr);

    if (shaderContext) {
        SkShader::Context::BlitState bstate;
        sk_bzero(&bstate, sizeof(bstate));
        bstate.fCtx = shaderContext;
        bstate.fXfer = paint.getXfermode();

        (void)shaderContext->chooseBlitProcs(device.info(), &bstate);
        return allocator->createT<SkState_Shader_Blitter<State>>(device, paint, bstate);
    } else {
        SkColor color = paint.getColor();
        if (0 == SkColorGetA(color)) {
            return nullptr;
        }
        return allocator->createT<SkState_Blitter<State>>(device, paint);
    }
}

SkBlitter* SkBlitter_ARGB32_Create(const SkPixmap& device, const SkPaint& paint,
                                   SkShader::Context* shaderContext,
                                   SkTBlitterAllocator* allocator) {
    return create<State32>(device, paint, shaderContext, allocator);
}

SkBlitter* SkBlitter_F16_Create(const SkPixmap& device, const SkPaint& paint,
                                SkShader::Context* shaderContext,
                                SkTBlitterAllocator* allocator) {
    return create<StateF16>(device, paint, shaderContext, allocator);
}
