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

#ifndef SkSamplingPriv_DEFINED
#define SkSamplingPriv_DEFINED

#include "include/core/SkSamplingOptions.h"

class SkReadBuffer;
class SkWriteBuffer;

// Given a src rect in texels to be filtered, this number of surrounding texels are needed by
// the kernel in x and y.
static constexpr int kBicubicFilterTexelPad = 2;

// Private copy of SkFilterQuality, just for legacy deserialization
// Matches values in SkFilterQuality
enum SkLegacyFQ {
    kNone_SkLegacyFQ   = 0,    //!< nearest-neighbor; fastest but lowest quality
    kLow_SkLegacyFQ    = 1,    //!< bilerp
    kMedium_SkLegacyFQ = 2,    //!< bilerp + mipmaps; good for down-scaling
    kHigh_SkLegacyFQ   = 3,    //!< bicubic resampling; slowest but good quality

    kLast_SkLegacyFQ = kHigh_SkLegacyFQ,
};

// Matches values in SkSamplingOptions::MediumBehavior
enum SkMediumAs {
    kNearest_SkMediumAs,
    kLinear_SkMediumAs,
};

class SkSamplingPriv {
public:
    static size_t FlatSize(const SkSamplingOptions& options) {
        size_t size = sizeof(uint32_t);  // maxAniso
        if (!options.isAniso()) {
            size += 3 * sizeof(uint32_t);  // bool32 + [2 floats | 2 ints]
        }
        return size;
    }

    // Returns true if the sampling can be ignored when the CTM is identity.
    static bool NoChangeWithIdentityMatrix(const SkSamplingOptions& sampling) {
        // If B == 0, the cubic resampler should have no effect for identity matrices
        // https://entropymine.com/imageworsener/bicubic/
        // We assume aniso has no effect with an identity transform.
        return !sampling.useCubic || sampling.cubic.B == 0;
    }

    // Makes a fallback SkSamplingOptions for cases where anisotropic filtering is not allowed.
    // anisotropic filtering can access mip levels if present, but we don't add mipmaps to non-
    // mipmapped images when the user requests anisotropic. So we shouldn't fall back to a
    // sampling that would trigger mip map creation.
    static SkSamplingOptions AnisoFallback(bool imageIsMipped) {
        auto mm = imageIsMipped ? SkMipmapMode::kLinear : SkMipmapMode::kNone;
        return SkSamplingOptions(SkFilterMode::kLinear, mm);
    }

    static SkSamplingOptions FromFQ(SkLegacyFQ fq, SkMediumAs behavior = kNearest_SkMediumAs) {
        switch (fq) {
            case kHigh_SkLegacyFQ:
                return SkSamplingOptions(SkCubicResampler{1/3.0f, 1/3.0f});
            case kMedium_SkLegacyFQ:
                return SkSamplingOptions(SkFilterMode::kLinear,
                                          behavior == kNearest_SkMediumAs ? SkMipmapMode::kNearest
                                                                          : SkMipmapMode::kLinear);
            case kLow_SkLegacyFQ:
                return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone);
            case kNone_SkLegacyFQ:
                break;
        }
        return SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone);
    }
};

#endif
