
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#include "SkBlitRow.h"
#include "SkColorFilter.h"
#include "SkColorPriv.h"
#include "SkUtils.h"

#define ILLEGAL_XFERMODE_MODE   ((SkXfermode::Mode)-1)

// baseclass for filters that store a color and mode
class SkModeColorFilter : public SkColorFilter {
public:
    SkModeColorFilter(SkColor color) {
        fColor = color;
        fMode = ILLEGAL_XFERMODE_MODE;

        fPMColor = SkPreMultiplyColor(fColor);
    }

    SkModeColorFilter(SkColor color, SkXfermode::Mode mode) {
        fColor = color;
        fMode = mode;

        fPMColor = SkPreMultiplyColor(fColor);
    };

    virtual bool asColorMode(SkColor* color, SkXfermode::Mode* mode) {
        if (ILLEGAL_XFERMODE_MODE == fMode) {
            return false;
        }

        if (color) {
            *color = fColor;
        }
        if (mode) {
            *mode = fMode;
        }
        return true;
    }

    SkColor getColor() const { return fColor; }
    SkXfermode::Mode getMode() const { return fMode; }
    bool isModeValid() const { return ILLEGAL_XFERMODE_MODE != fMode; }

protected:
    virtual void flatten(SkFlattenableWriteBuffer& buffer) {
        this->INHERITED::flatten(buffer);
        buffer.write32(fColor);
        buffer.write32(fMode);
    }

    SkModeColorFilter(SkFlattenableReadBuffer& buffer) {
        fColor = buffer.readU32();
        fMode = (SkXfermode::Mode)buffer.readU32();

        fPMColor = SkPreMultiplyColor(fColor);
    }

    // cache of fColor in premultiply space
    SkPMColor   fPMColor;

private:
    SkColor             fColor;
    SkXfermode::Mode    fMode;

    typedef SkColorFilter INHERITED;
};

class Src_SkModeColorFilter : public SkModeColorFilter {
public:
    Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrc_Mode) {}

    virtual uint32_t getFlags() {
        if (SkGetPackedA32(fPMColor) == 0xFF) {
            return kAlphaUnchanged_Flag | kHasFilter16_Flag;
        } else {
            return 0;
        }
    }

    virtual void filterSpan(const SkPMColor shader[], int count,
                            SkPMColor result[]) {
        sk_memset32(result, fPMColor, count);
    }

    virtual void filterSpan16(const uint16_t shader[], int count,
                              uint16_t result[]) {
        SkASSERT(this->getFlags() & kHasFilter16_Flag);
        sk_memset16(result, SkPixel32ToPixel16(fPMColor), count);
    }

    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
        return SkNEW_ARGS(Src_SkModeColorFilter, (buffer));
    }

protected:
    virtual Factory getFactory() { return CreateProc; }

    Src_SkModeColorFilter(SkFlattenableReadBuffer& buffer)
        : INHERITED(buffer) {}

private:
    typedef SkModeColorFilter INHERITED;
};

class SrcOver_SkModeColorFilter : public SkModeColorFilter {
public:
    SrcOver_SkModeColorFilter(SkColor color)
            : INHERITED(color, SkXfermode::kSrcOver_Mode) {
        fColor32Proc = NULL;
    }

    virtual uint32_t getFlags() {
        if (SkGetPackedA32(fPMColor) == 0xFF) {
            return kAlphaUnchanged_Flag | kHasFilter16_Flag;
        } else {
            return 0;
        }
    }

    virtual void filterSpan(const SkPMColor shader[], int count,
                            SkPMColor result[]) {
        if (NULL == fColor32Proc) {
            fColor32Proc = SkBlitRow::ColorProcFactory();
        }
        fColor32Proc(result, shader, count, fPMColor);
    }

    virtual void filterSpan16(const uint16_t shader[], int count,
                              uint16_t result[]) {
        SkASSERT(this->getFlags() & kHasFilter16_Flag);
        sk_memset16(result, SkPixel32ToPixel16(fPMColor), count);
    }

    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
        return SkNEW_ARGS(SrcOver_SkModeColorFilter, (buffer));
    }

protected:
    virtual Factory getFactory() { return CreateProc;  }

    SrcOver_SkModeColorFilter(SkFlattenableReadBuffer& buffer)
        : INHERITED(buffer), fColor32Proc(NULL) {}

private:

    SkBlitRow::ColorProc fColor32Proc;

    typedef SkModeColorFilter INHERITED;
};

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

class Proc_SkModeColorFilter : public SkModeColorFilter {
public:
    Proc_SkModeColorFilter(SkColor color, SkXfermode::Mode mode) : INHERITED(color, mode) {
        fProc = SkXfermode::GetProc(mode);
        fProc16 = SkXfermode::GetProc16(mode, color);
    }

    Proc_SkModeColorFilter(SkColor color,
                           SkXfermodeProc proc, SkXfermodeProc16 proc16)
            : INHERITED(color, ILLEGAL_XFERMODE_MODE) {
        fProc = proc;
        fProc16 = proc16;
    }

    virtual uint32_t getFlags() {
        return fProc16 ? (kAlphaUnchanged_Flag | kHasFilter16_Flag) : 0;
    }

    virtual void filterSpan(const SkPMColor shader[], int count,
                            SkPMColor result[]) {
        SkPMColor       color = fPMColor;
        SkXfermodeProc  proc = fProc;

        for (int i = 0; i < count; i++) {
            result[i] = proc(color, shader[i]);
        }
    }

    virtual void filterSpan16(const uint16_t shader[], int count,
                              uint16_t result[]) {
        SkASSERT(this->getFlags() & kHasFilter16_Flag);

        SkPMColor        color = fPMColor;
        SkXfermodeProc16 proc16 = fProc16;

        for (int i = 0; i < count; i++) {
            result[i] = proc16(color, shader[i]);
        }
    }

    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
        return SkNEW_ARGS(Proc_SkModeColorFilter, (buffer));
    }

protected:
    virtual void flatten(SkFlattenableWriteBuffer& buffer) {
        this->INHERITED::flatten(buffer);
        buffer.writeFunctionPtr((void*)fProc);
        buffer.writeFunctionPtr((void*)fProc16);
    }

    virtual Factory getFactory() {
        return CreateProc;
    }

    Proc_SkModeColorFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
        fProc = (SkXfermodeProc) buffer.readFunctionPtr();
        fProc16 = (SkXfermodeProc16) buffer.readFunctionPtr();
    }

private:
    SkXfermodeProc   fProc;
    SkXfermodeProc16 fProc16;

    typedef SkModeColorFilter INHERITED;
};

SkColorFilter* SkColorFilter::CreateProcFilter(SkColor color,
                                               SkXfermodeProc proc,
                                               SkXfermodeProc16 proc16) {
    return proc ?
            SkNEW_ARGS(Proc_SkModeColorFilter, (color, proc, proc16)) :
            NULL;
}

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

SkColorFilter* SkColorFilter::CreateModeFilter(SkColor color,
                                               SkXfermode::Mode mode) {
    unsigned alpha = SkColorGetA(color);

    // first collaps some modes if possible

    if (SkXfermode::kClear_Mode == mode) {
        color = 0;
        mode = SkXfermode::kSrc_Mode;
    } else if (SkXfermode::kSrcOver_Mode == mode) {
        if (0 == alpha) {
            mode = SkXfermode::kDst_Mode;
        } else if (255 == alpha) {
            mode = SkXfermode::kSrc_Mode;
        }
        // else just stay srcover
    }

    // weed out combinations that are noops, and just return null
    if (SkXfermode::kDst_Mode == mode ||
        (0 == alpha && (SkXfermode::kSrcOver_Mode == mode ||
                        SkXfermode::kDstOver_Mode == mode ||
                        SkXfermode::kDstOut_Mode == mode ||
                        SkXfermode::kSrcATop_Mode == mode ||
                        SkXfermode::kXor_Mode == mode ||
                        SkXfermode::kDarken_Mode == mode)) ||
            (0xFF == alpha && SkXfermode::kDstIn_Mode == mode)) {
        return NULL;
    }

    switch (mode) {
        case SkXfermode::kSrc_Mode:
            return SkNEW_ARGS(Src_SkModeColorFilter, (color));
        case SkXfermode::kSrcOver_Mode:
            return SkNEW_ARGS(SrcOver_SkModeColorFilter, (color));
        default:
            return SkNEW_ARGS(Proc_SkModeColorFilter, (color, mode));
    }
}

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

static inline unsigned pin(unsigned value, unsigned max) {
    if (value > max) {
        value = max;
    }
    return value;
}

static inline unsigned SkUClampMax(unsigned value, unsigned max) {
    SkASSERT((int32_t)value >= 0);
    SkASSERT((int32_t)max >= 0);

    int diff = max - value;
    // clear diff if diff is positive
    diff &= diff >> 31;

    return value + diff;
}

class SkLightingColorFilter : public SkColorFilter {
public:
    SkLightingColorFilter(SkColor mul, SkColor add) : fMul(mul), fAdd(add) {}

    virtual void filterSpan(const SkPMColor shader[], int count,
                            SkPMColor result[]) {
        unsigned scaleR = SkAlpha255To256(SkColorGetR(fMul));
        unsigned scaleG = SkAlpha255To256(SkColorGetG(fMul));
        unsigned scaleB = SkAlpha255To256(SkColorGetB(fMul));

        unsigned addR = SkColorGetR(fAdd);
        unsigned addG = SkColorGetG(fAdd);
        unsigned addB = SkColorGetB(fAdd);

        for (int i = 0; i < count; i++) {
            SkPMColor c = shader[i];
            if (c) {
                unsigned a = SkGetPackedA32(c);
                unsigned scaleA = SkAlpha255To256(a);
                unsigned r = pin(SkAlphaMul(SkGetPackedR32(c), scaleR) + SkAlphaMul(addR, scaleA), a);
                unsigned g = pin(SkAlphaMul(SkGetPackedG32(c), scaleG) + SkAlphaMul(addG, scaleA), a);
                unsigned b = pin(SkAlphaMul(SkGetPackedB32(c), scaleB) + SkAlphaMul(addB, scaleA), a);
                c = SkPackARGB32(a, r, g, b);
            }
            result[i] = c;
        }
    }

protected:
    virtual void flatten(SkFlattenableWriteBuffer& buffer) {
        this->INHERITED::flatten(buffer);
        buffer.write32(fMul);
        buffer.write32(fAdd);
    }

    virtual Factory getFactory() {
        return CreateProc;
    }

    SkLightingColorFilter(SkFlattenableReadBuffer& buffer) {
        fMul = buffer.readU32();
        fAdd = buffer.readU32();
    }

    SkColor fMul, fAdd;

private:
    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
        return SkNEW_ARGS(SkLightingColorFilter, (buffer));
    }

    typedef SkColorFilter INHERITED;
};

class SkLightingColorFilter_JustAdd : public SkLightingColorFilter {
public:
    SkLightingColorFilter_JustAdd(SkColor mul, SkColor add)
        : INHERITED(mul, add) {}

    virtual void filterSpan(const SkPMColor shader[], int count,
                            SkPMColor result[]) {
        unsigned addR = SkColorGetR(fAdd);
        unsigned addG = SkColorGetG(fAdd);
        unsigned addB = SkColorGetB(fAdd);

        for (int i = 0; i < count; i++) {
            SkPMColor c = shader[i];
            if (c) {
                unsigned a = SkGetPackedA32(c);
                unsigned scaleA = SkAlpha255To256(a);
                unsigned r = pin(SkGetPackedR32(c) + SkAlphaMul(addR, scaleA), a);
                unsigned g = pin(SkGetPackedG32(c) + SkAlphaMul(addG, scaleA), a);
                unsigned b = pin(SkGetPackedB32(c) + SkAlphaMul(addB, scaleA), a);
                c = SkPackARGB32(a, r, g, b);
            }
            result[i] = c;
        }
    }

protected:
    virtual Factory getFactory() { return CreateProc; }

    SkLightingColorFilter_JustAdd(SkFlattenableReadBuffer& buffer)
        : INHERITED(buffer) {}

private:
    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer)  {
        return SkNEW_ARGS(SkLightingColorFilter_JustAdd, (buffer));
    }

    typedef SkLightingColorFilter INHERITED;
};

class SkLightingColorFilter_JustMul : public SkLightingColorFilter {
public:
    SkLightingColorFilter_JustMul(SkColor mul, SkColor add)
        : INHERITED(mul, add) {}

    virtual void filterSpan(const SkPMColor shader[], int count,
                            SkPMColor result[]) {
        unsigned scaleR = SkAlpha255To256(SkColorGetR(fMul));
        unsigned scaleG = SkAlpha255To256(SkColorGetG(fMul));
        unsigned scaleB = SkAlpha255To256(SkColorGetB(fMul));

        for (int i = 0; i < count; i++) {
            SkPMColor c = shader[i];
            if (c) {
                unsigned a = SkGetPackedA32(c);
                unsigned r = SkAlphaMul(SkGetPackedR32(c), scaleR);
                unsigned g = SkAlphaMul(SkGetPackedG32(c), scaleG);
                unsigned b = SkAlphaMul(SkGetPackedB32(c), scaleB);
                c = SkPackARGB32(a, r, g, b);
            }
            result[i] = c;
        }
    }

protected:
    virtual Factory getFactory() { return CreateProc; }

    SkLightingColorFilter_JustMul(SkFlattenableReadBuffer& buffer)
        : INHERITED(buffer) {}

private:
    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
        return SkNEW_ARGS(SkLightingColorFilter_JustMul, (buffer));
    }

    typedef SkLightingColorFilter INHERITED;
};

class SkLightingColorFilter_SingleMul : public SkLightingColorFilter {
public:
    SkLightingColorFilter_SingleMul(SkColor mul, SkColor add)
            : INHERITED(mul, add) {
        SkASSERT(SkColorGetR(add) == 0);
        SkASSERT(SkColorGetG(add) == 0);
        SkASSERT(SkColorGetB(add) == 0);
        SkASSERT(SkColorGetR(mul) == SkColorGetG(mul));
        SkASSERT(SkColorGetR(mul) == SkColorGetB(mul));
    }

    virtual uint32_t getFlags() {
        return this->INHERITED::getFlags() | (kAlphaUnchanged_Flag | kHasFilter16_Flag);
    }

    virtual void filterSpan16(const uint16_t shader[], int count,
                              uint16_t result[]) {
        // all mul components are the same
        unsigned scale = SkAlpha255To256(SkColorGetR(fMul));

        if (count > 0) {
            do {
                *result++ = SkAlphaMulRGB16(*shader++, scale);
            } while (--count > 0);
        }
    }

protected:
    virtual Factory getFactory() { return CreateProc; }

    SkLightingColorFilter_SingleMul(SkFlattenableReadBuffer& buffer)
        : INHERITED(buffer) {}

private:
    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
        return SkNEW_ARGS(SkLightingColorFilter_SingleMul, (buffer));
    }

    typedef SkLightingColorFilter INHERITED;
};

class SkLightingColorFilter_NoPin : public SkLightingColorFilter {
public:
    SkLightingColorFilter_NoPin(SkColor mul, SkColor add)
    : INHERITED(mul, add) {}

    virtual void filterSpan(const SkPMColor shader[], int count,
                            SkPMColor result[]) {
        unsigned scaleR = SkAlpha255To256(SkColorGetR(fMul));
        unsigned scaleG = SkAlpha255To256(SkColorGetG(fMul));
        unsigned scaleB = SkAlpha255To256(SkColorGetB(fMul));

        unsigned addR = SkColorGetR(fAdd);
        unsigned addG = SkColorGetG(fAdd);
        unsigned addB = SkColorGetB(fAdd);

        for (int i = 0; i < count; i++) {
            SkPMColor c = shader[i];
            if (c) {
                unsigned a = SkGetPackedA32(c);
                unsigned scaleA = SkAlpha255To256(a);
                unsigned r = SkAlphaMul(SkGetPackedR32(c), scaleR) + SkAlphaMul(addR, scaleA);
                unsigned g = SkAlphaMul(SkGetPackedG32(c), scaleG) + SkAlphaMul(addG, scaleA);
                unsigned b = SkAlphaMul(SkGetPackedB32(c), scaleB) + SkAlphaMul(addB, scaleA);
                c = SkPackARGB32(a, r, g, b);
            }
            result[i] = c;
        }
    }

protected:
    virtual Factory getFactory() { return CreateProc; }

    SkLightingColorFilter_NoPin(SkFlattenableReadBuffer& buffer)
        : INHERITED(buffer) {}

private:
    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
        return SkNEW_ARGS(SkLightingColorFilter_NoPin, (buffer));
    }

    typedef SkLightingColorFilter INHERITED;
};

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

class SkSimpleColorFilter : public SkColorFilter {
protected:
    void filterSpan(const SkPMColor src[], int count, SkPMColor result[]) {
        if (result != src) {
            memcpy(result, src, count * sizeof(SkPMColor));
        }
    }

    virtual void flatten(SkFlattenableWriteBuffer& buffer) {}

    virtual Factory getFactory() {
        return CreateProc;
    }

    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
        return SkNEW(SkSimpleColorFilter);
    }
};

SkColorFilter* SkColorFilter::CreateLightingFilter(SkColor mul, SkColor add) {
    mul &= 0x00FFFFFF;
    add &= 0x00FFFFFF;

    if (0xFFFFFF == mul) {
        if (0 == add) {
            return SkNEW(SkSimpleColorFilter);   // no change to the colors
        } else {
            return SkNEW_ARGS(SkLightingColorFilter_JustAdd, (mul, add));
        }
    }

    if (0 == add) {
        if (SkColorGetR(mul) == SkColorGetG(mul) &&
                SkColorGetR(mul) == SkColorGetB(mul)) {
            return SkNEW_ARGS(SkLightingColorFilter_SingleMul, (mul, add));
        } else {
            return SkNEW_ARGS(SkLightingColorFilter_JustMul, (mul, add));
        }
    }

    if (SkColorGetR(mul) + SkColorGetR(add) <= 255 &&
        SkColorGetG(mul) + SkColorGetG(add) <= 255 &&
        SkColorGetB(mul) + SkColorGetB(add) <= 255) {
            return SkNEW_ARGS(SkLightingColorFilter_NoPin, (mul, add));
    }

    return SkNEW_ARGS(SkLightingColorFilter, (mul, add));
}

static SkFlattenable::Registrar
    gSrcColorFilterReg("Src_SkModeColorFilterReg",
                       Src_SkModeColorFilter::CreateProc);

static SkFlattenable::Registrar
    gSrcOverColorFilterReg("SrcOver_SkModeColorFilterReg",
                       SrcOver_SkModeColorFilter::CreateProc);

static SkFlattenable::Registrar
    gProcColorFilterReg("Proc_SkModeColorFilterReg",
                       Proc_SkModeColorFilter::CreateProc);
