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

#ifndef GrTextureDomainEffect_DEFINED
#define GrTextureDomainEffect_DEFINED

#include "GrSingleTextureEffect.h"

class GrGLTextureDomainEffect;
struct SkRect;

/**
 * Limits a texture's lookup coordinates to a domain. Samples outside the domain are either clamped
 * the edge of the domain or result in a vec4 of zeros. The domain is clipped to normalized texture
 * coords ([0,1]x[0,1] square). Bilinear filtering can cause texels outside the domain to affect the
 * read value unless the caller considers this when calculating the domain. TODO: This should be a
 * helper that can assist an effect rather than effect unto itself.
 */
class GrTextureDomainEffect : public GrSingleTextureEffect {

public:
    /**
     * If SkShader::kDecal_TileMode sticks then this enum could be replaced by SkShader::TileMode.
     * We could also consider replacing/augmenting Decal mode with Border mode where the color
     * outside of the domain is user-specifiable. Decal mode currently has a hard (non-lerped)
     * transition between the border and the interior.
     */
    enum WrapMode {
        kClamp_WrapMode,
        kDecal_WrapMode,
    };

    static GrEffectRef* Create(GrTexture*,
                               const SkMatrix&,
                               const SkRect& domain,
                               WrapMode,
                               GrTextureParams::FilterMode filterMode,
                               CoordsType = kLocal_CoordsType);

    virtual ~GrTextureDomainEffect();

    static const char* Name() { return "TextureDomain"; }

    typedef GrGLTextureDomainEffect GLEffect;

    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;

    const SkRect& domain() const { return fTextureDomain; }
    WrapMode wrapMode() const { return fWrapMode; }

    /* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled
       texels neighboring the domain may be read. */
    static const SkRect MakeTexelDomain(const GrTexture* texture, const SkIRect& texelRect) {
        SkScalar wInv = SK_Scalar1 / texture->width();
        SkScalar hInv = SK_Scalar1 / texture->height();
        SkRect result = {
            texelRect.fLeft * wInv,
            texelRect.fTop * hInv,
            texelRect.fRight * wInv,
            texelRect.fBottom * hInv
        };
        return result;
    }

protected:
    WrapMode fWrapMode;
    SkRect   fTextureDomain;

private:
    GrTextureDomainEffect(GrTexture*,
                          const SkMatrix&,
                          const SkRect& domain,
                          WrapMode,
                          GrTextureParams::FilterMode filterMode,
                          CoordsType type);

    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;

    GR_DECLARE_EFFECT_TEST;

    typedef GrSingleTextureEffect INHERITED;
};

#endif
