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

#include "SkColorFilter.h"
#include "SkColorSpacePriv.h"
#include "SkColorSpaceXformer.h"
#include "SkDrawLooper.h"
#include "SkGradientShader.h"
#include "SkImage.h"
#include "SkImage_Base.h"
#include "SkImageFilter.h"
#include "SkImagePriv.h"
#include "SkShaderBase.h"

SkColorSpaceXformer::SkColorSpaceXformer(sk_sp<SkColorSpace> dst)
    : fDst(std::move(dst))
    , fFromSRGBSteps(sk_srgb_singleton(), kUnpremul_SkAlphaType,
                     fDst.get()         , kUnpremul_SkAlphaType)
    , fReentryCount(0) {

    SkRasterPipeline p(&fAlloc);
    p.append(SkRasterPipeline::load_bgra, &fFromSRGBSrc);
    fFromSRGBSteps.apply(&p);
    p.append(SkRasterPipeline::store_bgra, &fFromSRGBDst);
    fFromSRGB = p.compile();
}

SkColorSpaceXformer::~SkColorSpaceXformer() {}

std::unique_ptr<SkColorSpaceXformer> SkColorSpaceXformer::Make(sk_sp<SkColorSpace> dst) {
    return std::unique_ptr<SkColorSpaceXformer>(new SkColorSpaceXformer{std::move(dst)});
}

// So what's up with these caches?
//
// We want to cache transformed objects for a couple of reasons:
//
// 1) to avoid redundant work - the inputs are a DAG, not a tree (e.g. same SkImage drawn multiple
//    times in a SkPicture), so if we blindly recurse we could end up transforming the same objects
//    repeatedly.
//
// 2) to avoid topology changes - we want the output to remain isomorphic with the input -- this is
//    particularly important for image filters (to maintain their original DAG structure in order
//    to not defeat their own/internal caching), but also for avoiding unnecessary cloning
//    (e.g. duplicated SkImages allocated for the example in #1 above).
//
// The caching scope is naturaly bound by the lifetime of the SkColorSpaceXformer object, but
// clients may choose to not discard xformers immediately - in which case, caching indefinitely
// is problematic.  The solution is to limit the cache scope to the top level apply() call
// (i.e. we only keep cached objects alive while transforming).

class SkColorSpaceXformer::AutoCachePurge {
public:
    AutoCachePurge(SkColorSpaceXformer* xformer)
        : fXformer(xformer) {
        fXformer->fReentryCount++;
    }

    ~AutoCachePurge() {
        SkASSERT(fXformer->fReentryCount > 0);
        if (--fXformer->fReentryCount == 0) {
            fXformer->purgeCaches();
        }
    }

private:
    SkColorSpaceXformer* fXformer;
};

template <typename T>
sk_sp<T> SkColorSpaceXformer::cachedApply(const T* src, Cache<T>* cache,
                                          sk_sp<T> (*applyFunc)(const T*, SkColorSpaceXformer*)) {
    if (!src) {
        return nullptr;
    }

    auto key = sk_ref_sp(const_cast<T*>(src));
    if (auto* xformed = cache->find(key)) {
        return sk_ref_sp(xformed->get());
    }

    auto xformed = applyFunc(src, this);
    cache->set(std::move(key), xformed);

    return xformed;
}

void SkColorSpaceXformer::purgeCaches() {
    fImageCache.reset();
    fColorFilterCache.reset();
    fImageFilterCache.reset();
}

sk_sp<SkImage> SkColorSpaceXformer::apply(const SkImage* src) {
    const AutoCachePurge autoPurge(this);
    return this->cachedApply<SkImage>(src, &fImageCache,
        [](const SkImage* img, SkColorSpaceXformer* xformer) {
            return img->makeColorSpace(xformer->fDst);
        });
}

sk_sp<SkImage> SkColorSpaceXformer::apply(const SkBitmap& src) {
    const AutoCachePurge autoPurge(this);
    sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(src, kNever_SkCopyPixelsMode);
    if (!image) {
        return nullptr;
    }

    sk_sp<SkImage> xformed = image->makeColorSpace(fDst);
    // We want to be sure we don't let the kNever_SkCopyPixelsMode image escape this stack frame.
    SkASSERT(xformed != image);
    return xformed;
}

sk_sp<SkColorFilter> SkColorSpaceXformer::apply(const SkColorFilter* colorFilter) {
    const AutoCachePurge autoPurge(this);
    return this->cachedApply<SkColorFilter>(colorFilter, &fColorFilterCache,
        [](const SkColorFilter* f, SkColorSpaceXformer* xformer) {
            return f->makeColorSpace(xformer);
        });
}

sk_sp<SkImageFilter> SkColorSpaceXformer::apply(const SkImageFilter* imageFilter) {
    const AutoCachePurge autoPurge(this);
    return this->cachedApply<SkImageFilter>(imageFilter, &fImageFilterCache,
        [](const SkImageFilter* f, SkColorSpaceXformer* xformer) {
            return f->makeColorSpace(xformer);
        });
}

sk_sp<SkShader> SkColorSpaceXformer::apply(const SkShader* shader) {
    const AutoCachePurge autoPurge(this);
    return as_SB(shader)->makeColorSpace(this);
}

void SkColorSpaceXformer::apply(SkColor* xformed, const SkColor* srgb, int n) {
    fFromSRGBSrc.pixels = const_cast<SkColor*>(srgb);
    fFromSRGBDst.pixels = xformed;
    fFromSRGB(0,0,n,1);
}

SkColor SkColorSpaceXformer::apply(SkColor srgb) {
    SkColor xformed;
    this->apply(&xformed, &srgb, 1);
    return xformed;
}

SkPaint SkColorSpaceXformer::apply(const SkPaint& src) {
    const AutoCachePurge autoPurge(this);

    SkPaint dst = src;

    // All SkColorSpaces have the same black point.
    if (src.getColor() & 0xffffff) {
        dst.setColor(this->apply(src.getColor()));
    }

    if (auto shader = src.getShader()) {
        dst.setShader(this->apply(shader));
    }

    if (auto cf = src.getColorFilter()) {
        dst.setColorFilter(this->apply(cf));
    }

    if (auto looper = src.getDrawLooper()) {
        dst.setDrawLooper(looper->makeColorSpace(this));
    }

    if (auto imageFilter = src.getImageFilter()) {
        dst.setImageFilter(this->apply(imageFilter));
    }

    return dst;
}

SkCanvas::Lattice SkColorSpaceXformer::apply(const SkCanvas::Lattice& lattice,
                                             SkColor* colorBuffer, int count) {
    if (count) {
        this->apply(colorBuffer, lattice.fColors, count);
        return {lattice.fXDivs, lattice.fYDivs, lattice.fRectTypes,
                lattice.fXCount, lattice.fYCount, lattice.fBounds, colorBuffer};
    }

    return lattice;
}
