<commit_before>/*
 * 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 "include/core/SkRefCnt.h"
#include "include/core/SkString.h"
#include "include/core/SkUnPreMultiply.h"
#include "include/private/SkNx.h"
#include "include/private/SkTDArray.h"
#include "src/core/SkArenaAlloc.h"
#include "src/core/SkColorFilterBase.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkColorSpaceXformSteps.h"
#include "src/core/SkMatrixProvider.h"
#include "src/core/SkRasterPipeline.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkVM.h"
#include "src/core/SkWriteBuffer.h"

#if SK_SUPPORT_GPU
#include "src/gpu/GrColorSpaceXform.h"
#include "src/gpu/GrFragmentProcessor.h"
#include "src/gpu/effects/generated/GrMixerEffect.h"
#endif

bool SkColorFilter::asColorMode(SkColor* color, SkBlendMode* mode) const {
    return as_CFB(this)->onAsAColorMode(color, mode);
}

bool SkColorFilter::asAColorMode(SkColor* color, SkBlendMode* mode) const {
    return as_CFB(this)->onAsAColorMode(color, mode);
}

bool SkColorFilter::asAColorMatrix(float matrix[20]) const {
    return as_CFB(this)->onAsAColorMatrix(matrix);
}

uint32_t SkColorFilter::getFlags() const { return as_CFB(this)->onGetFlags(); }

bool SkColorFilter::isAlphaUnchanged() const {
    return SkToBool(this->getFlags() & kAlphaUnchanged_Flag);
}

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

bool SkColorFilterBase::onAsAColorMode(SkColor*, SkBlendMode*) const {
    return false;
}

bool SkColorFilterBase::onAsAColorMatrix(float matrix[20]) const {
    return false;
}

#if SK_SUPPORT_GPU
std::unique_ptr<GrFragmentProcessor> SkColorFilterBase::asFragmentProcessor(
        GrRecordingContext* context, const GrColorInfo& dstColorInfo) const {
    // TODO(skbug.com/10217): remove this method once all SkColorFilters support the new API.
    if (!this->colorFilterAcceptsInputFP()) {
        // This color filter doesn't implement `asFragmentProcessor` at all.
        return nullptr;
    }

    // This color filter has been updated to absorb an input FP. Redirect to the new API.
    auto [success, fp] = this->asFragmentProcessor(/*inputFP=*/nullptr, context, dstColorInfo);
    return success ? std::move(fp) : nullptr;
}

GrFPResult SkColorFilterBase::asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
                                                  GrRecordingContext* context,
                                                  const GrColorInfo& dstColorInfo) const {
    // A filter that overrides `colorFilterAcceptsInputFP` should also have overridden this method.
    SkASSERT(!this->colorFilterAcceptsInputFP());

    // This color filter doesn't support taking an inputFP yet. Call the deprecated version instead.
    std::unique_ptr<GrFragmentProcessor> filter = this->asFragmentProcessor(context, dstColorInfo);
    if (filter == nullptr) {
        return GrFPFailure(std::move(inputFP));
    }

    if (inputFP == nullptr) {
        // An input FP wasn't actually provided, so we can just return the color filter FP as-is.
        return GrFPSuccess(std::move(filter));
    } else {
        // Use RunInSeries as a crutch to make this color filter work with an input FP.
        std::unique_ptr<GrFragmentProcessor> series[] = {
            std::move(inputFP),
            std::move(filter),
        };
        return GrFPSuccess(GrFragmentProcessor::RunInSeries(series, SK_ARRAY_COUNT(series)));
    }
}
#endif

bool SkColorFilterBase::appendStages(const SkStageRec& rec, bool shaderIsOpaque) const {
    return this->onAppendStages(rec, shaderIsOpaque);
}

skvm::Color SkColorFilterBase::program(skvm::Builder* p, skvm::Color c,
                                       SkColorSpace* dstCS,
                                       skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
    skvm::F32 original = c.a;
    if ((c = this->onProgram(p,c, dstCS, uniforms,alloc))) {
        if (this->isAlphaUnchanged()) {
            c.a = original;
        }
        return c;
    }
    //SkDebugf("cannot onProgram %s\n", this->getTypeName());
    return {};
}

SkColor SkColorFilter::filterColor(SkColor c) const {
    // This is mostly meaningless. We should phase-out this call entirely.
    SkColorSpace* cs = nullptr;
    return this->filterColor4f(SkColor4f::FromColor(c), cs, cs).toSkColor();
}

SkColor4f SkColorFilter::filterColor4f(const SkColor4f& origSrcColor, SkColorSpace* srcCS,
                                       SkColorSpace* dstCS) const {
    SkColor4f color = origSrcColor;
    SkColorSpaceXformSteps(srcCS, kUnpremul_SkAlphaType,
                           dstCS, kPremul_SkAlphaType).apply(color.vec());

    constexpr size_t kEnoughForCommonFilters = 512; // big enough for compose+colormatrix
    SkSTArenaAlloc<kEnoughForCommonFilters> alloc;
    SkRasterPipeline    pipeline(&alloc);
    pipeline.append_constant_color(&alloc, color.vec());
    SkPaint dummyPaint;
    SkSimpleMatrixProvider matrixProvider(SkMatrix::I());
    SkStageRec rec = {
        &pipeline, &alloc, kRGBA_F32_SkColorType, dstCS, dummyPaint, nullptr, matrixProvider
    };
    as_CFB(this)->onAppendStages(rec, color.fA == 1);

    SkPMColor4f dst;
    SkRasterPipeline_MemoryCtx dstPtr = { &dst, 0 };
    pipeline.append(SkRasterPipeline::store_f32, &dstPtr);
    pipeline.run(0,0, 1,1);
    return dst.unpremul();
}

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

class SkComposeColorFilter : public SkColorFilterBase {
public:
    uint32_t onGetFlags() const override {
        // Can only claim alphaunchanged support if both our proxys do.
        return fOuter->onGetFlags() & fInner->onGetFlags();
    }

    bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
        bool innerIsOpaque = shaderIsOpaque;
        if (!fInner->isAlphaUnchanged()) {
            innerIsOpaque = false;
        }
        return fInner->appendStages(rec, shaderIsOpaque) &&
               fOuter->appendStages(rec, innerIsOpaque);
    }

    skvm::Color onProgram(skvm::Builder* p, skvm::Color c,
                          SkColorSpace* dstCS,
                          skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override {
               c = fInner->program(p, c, dstCS, uniforms, alloc);
        return c ? fOuter->program(p, c, dstCS, uniforms, alloc) : skvm::Color{};
    }

#if SK_SUPPORT_GPU
    std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
            GrRecordingContext* context, const GrColorInfo& dstColorInfo) const override {
        auto innerFP = fInner->asFragmentProcessor(context, dstColorInfo);
        auto outerFP = fOuter->asFragmentProcessor(context, dstColorInfo);
        if (!innerFP || !outerFP) {
            return nullptr;
        }
        std::unique_ptr<GrFragmentProcessor> series[] = { std::move(innerFP), std::move(outerFP) };
        return GrFragmentProcessor::RunInSeries(series, 2);
    }
#endif<commit_msg>Update SkComposeColorFilter to support an input FP.<commit_after>/*
 * 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 "include/core/SkRefCnt.h"
#include "include/core/SkString.h"
#include "include/core/SkUnPreMultiply.h"
#include "include/private/SkNx.h"
#include "include/private/SkTDArray.h"
#include "src/core/SkArenaAlloc.h"
#include "src/core/SkColorFilterBase.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkColorSpaceXformSteps.h"
#include "src/core/SkMatrixProvider.h"
#include "src/core/SkRasterPipeline.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkVM.h"
#include "src/core/SkWriteBuffer.h"

#if SK_SUPPORT_GPU
#include "src/gpu/GrColorSpaceXform.h"
#include "src/gpu/GrFragmentProcessor.h"
#include "src/gpu/effects/generated/GrMixerEffect.h"
#endif

bool SkColorFilter::asColorMode(SkColor* color, SkBlendMode* mode) const {
    return as_CFB(this)->onAsAColorMode(color, mode);
}

bool SkColorFilter::asAColorMode(SkColor* color, SkBlendMode* mode) const {
    return as_CFB(this)->onAsAColorMode(color, mode);
}

bool SkColorFilter::asAColorMatrix(float matrix[20]) const {
    return as_CFB(this)->onAsAColorMatrix(matrix);
}

uint32_t SkColorFilter::getFlags() const { return as_CFB(this)->onGetFlags(); }

bool SkColorFilter::isAlphaUnchanged() const {
    return SkToBool(this->getFlags() & kAlphaUnchanged_Flag);
}

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

bool SkColorFilterBase::onAsAColorMode(SkColor*, SkBlendMode*) const {
    return false;
}

bool SkColorFilterBase::onAsAColorMatrix(float matrix[20]) const {
    return false;
}

#if SK_SUPPORT_GPU
std::unique_ptr<GrFragmentProcessor> SkColorFilterBase::asFragmentProcessor(
        GrRecordingContext* context, const GrColorInfo& dstColorInfo) const {
    // TODO(skbug.com/10217): remove this method once all SkColorFilters support the new API.
    if (!this->colorFilterAcceptsInputFP()) {
        // This color filter doesn't implement `asFragmentProcessor` at all.
        return nullptr;
    }

    // This color filter has been updated to absorb an input FP. Redirect to the new API.
    auto [success, fp] = this->asFragmentProcessor(/*inputFP=*/nullptr, context, dstColorInfo);
    return success ? std::move(fp) : nullptr;
}

GrFPResult SkColorFilterBase::asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
                                                  GrRecordingContext* context,
                                                  const GrColorInfo& dstColorInfo) const {
    // A filter that overrides `colorFilterAcceptsInputFP` should also have overridden this method.
    SkASSERT(!this->colorFilterAcceptsInputFP());

    // This color filter doesn't support taking an inputFP yet. Call the deprecated version instead.
    std::unique_ptr<GrFragmentProcessor> filter = this->asFragmentProcessor(context, dstColorInfo);
    if (filter == nullptr) {
        return GrFPFailure(std::move(inputFP));
    }

    if (inputFP == nullptr) {
        // An input FP wasn't actually provided, so we can just return the color filter FP as-is.
        return GrFPSuccess(std::move(filter));
    } else {
        // Use RunInSeries as a crutch to make this color filter work with an input FP.
        std::unique_ptr<GrFragmentProcessor> series[] = {
            std::move(inputFP),
            std::move(filter),
        };
        return GrFPSuccess(GrFragmentProcessor::RunInSeries(series, SK_ARRAY_COUNT(series)));
    }
}
#endif

bool SkColorFilterBase::appendStages(const SkStageRec& rec, bool shaderIsOpaque) const {
    return this->onAppendStages(rec, shaderIsOpaque);
}

skvm::Color SkColorFilterBase::program(skvm::Builder* p, skvm::Color c,
                                       SkColorSpace* dstCS,
                                       skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const {
    skvm::F32 original = c.a;
    if ((c = this->onProgram(p,c, dstCS, uniforms,alloc))) {
        if (this->isAlphaUnchanged()) {
            c.a = original;
        }
        return c;
    }
    //SkDebugf("cannot onProgram %s\n", this->getTypeName());
    return {};
}

SkColor SkColorFilter::filterColor(SkColor c) const {
    // This is mostly meaningless. We should phase-out this call entirely.
    SkColorSpace* cs = nullptr;
    return this->filterColor4f(SkColor4f::FromColor(c), cs, cs).toSkColor();
}

SkColor4f SkColorFilter::filterColor4f(const SkColor4f& origSrcColor, SkColorSpace* srcCS,
                                       SkColorSpace* dstCS) const {
    SkColor4f color = origSrcColor;
    SkColorSpaceXformSteps(srcCS, kUnpremul_SkAlphaType,
                           dstCS, kPremul_SkAlphaType).apply(color.vec());

    constexpr size_t kEnoughForCommonFilters = 512; // big enough for compose+colormatrix
    SkSTArenaAlloc<kEnoughForCommonFilters> alloc;
    SkRasterPipeline    pipeline(&alloc);
    pipeline.append_constant_color(&alloc, color.vec());
    SkPaint dummyPaint;
    SkSimpleMatrixProvider matrixProvider(SkMatrix::I());
    SkStageRec rec = {
        &pipeline, &alloc, kRGBA_F32_SkColorType, dstCS, dummyPaint, nullptr, matrixProvider
    };
    as_CFB(this)->onAppendStages(rec, color.fA == 1);

    SkPMColor4f dst;
    SkRasterPipeline_MemoryCtx dstPtr = { &dst, 0 };
    pipeline.append(SkRasterPipeline::store_f32, &dstPtr);
    pipeline.run(0,0, 1,1);
    return dst.unpremul();
}

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

class SkComposeColorFilter : public SkColorFilterBase {
public:
    uint32_t onGetFlags() const override {
        // Can only claim alphaunchanged support if both our proxys do.
        return fOuter->onGetFlags() & fInner->onGetFlags();
    }

    bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
        bool innerIsOpaque = shaderIsOpaque;
        if (!fInner->isAlphaUnchanged()) {
            innerIsOpaque = false;
        }
        return fInner->appendStages(rec, shaderIsOpaque) &&
               fOuter->appendStages(rec, innerIsOpaque);
    }

    skvm::Color onProgram(skvm::Builder* p, skvm::Color c,
                          SkColorSpace* dstCS,
                          skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override {
               c = fInner->program(p, c, dstCS, uniforms, alloc);
        return c ? fOuter->program(p, c, dstCS, uniforms, alloc) : skvm::Color{};
    }

#if SK_SUPPORT_GPU
    bool colorFilterAcceptsInputFP() const override { return true; }
    GrFPResult asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
                                   GrRecordingContext* context,
                                   const GrColorInfo& dstColorInfo) const override {
        GrFragmentProcessor* originalInputFP = inputFP.get();

        auto [innerSuccess, innerFP] =
                fInner->asFragmentProcessor(std::move(inputFP), context, dstColorInfo);
        if (!innerSuccess) {
            return GrFPFailure(std::move(innerFP));
        }

        auto [outerSuccess, outerFP] =
                fOuter->asFragmentProcessor(std::move(innerFP), context, dstColorInfo);
        if (!outerSuccess) {
            // In the rare event that the outer FP cannot be built, we have no good way of
            // separating the inputFP from the innerFP, so we need to return a cloned inputFP.
            // This could hypothetically be expensive, but failure here should be extremely rare.
            return GrFPFailure(originalInputFP->clone());
        }

        return GrFPSuccess(std::move(outerFP));
    }
#endif
{'fraction_non_alphanumeric': 0.13173290296550333, 'fraction_numerical': 0.005312352901620604, 'mean_word_length': 2.9178082191780823, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5419002', 'n_tokens_mistral': 4451, 'n_tokens_neox': 4347, 'n_words': 1021}