Fixed color bleeding issue when drawing a sub region of a bitmap with filtering enabled.
Problem was resolved by adding the notion of a custom texture domain in generated shaders, when necessary.




git-svn-id: http://skia.googlecode.com/svn/trunk@1337 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
index 518b4ee..efee91e 100644
--- a/gpu/src/GrDrawTarget.cpp
+++ b/gpu/src/GrDrawTarget.cpp
@@ -19,6 +19,8 @@
 #include "GrGpuVertex.h"
 #include "GrTexture.h"
 
+namespace {
+
 // recursive helper for creating mask with all the tex coord bits set for
 // one stage
 template <int N>
@@ -26,16 +28,16 @@
     return GrDrawTarget::StageTexCoordVertexLayoutBit(stage, N) |
            stage_mask_recur<N+1>(stage);
 }
-template<> // linux build doesn't like static on specializations
+template<> 
 int stage_mask_recur<GrDrawTarget::kNumStages>(int) { return 0; }
 
 // mask of all tex coord indices for one stage
-static int stage_tex_coord_mask(int stage) {
+int stage_tex_coord_mask(int stage) {
     return stage_mask_recur<0>(stage);
 }
 
 // mask of all bits relevant to one stage
-static int stage_mask(int stage) {
+int stage_mask(int stage) {
     return stage_tex_coord_mask(stage) |
            GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(stage);
 }
@@ -47,11 +49,11 @@
     return GrDrawTarget::StageTexCoordVertexLayoutBit(N, texCoordIdx) |
            tex_coord_mask_recur<N+1>(texCoordIdx);
 }
-template<> // linux build doesn't like static on specializations
+template<> 
 int tex_coord_mask_recur<GrDrawTarget::kMaxTexCoords>(int) { return 0; }
 
 // mask of all bits relevant to one texture coordinate index
-static int tex_coord_idx_mask(int texCoordIdx) {
+int tex_coord_idx_mask(int texCoordIdx) {
     return tex_coord_mask_recur<0>(texCoordIdx);
 }
 
@@ -66,6 +68,8 @@
     return true;
 }
 
+} //unnamed namespace
+
 size_t GrDrawTarget::VertexSize(GrVertexLayout vertexLayout) {
     GrAssert(check_layout(vertexLayout));
 
diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp
index 5d2d8b3..ab327d0 100644
--- a/gpu/src/GrGLProgram.cpp
+++ b/gpu/src/GrGLProgram.cpp
@@ -120,6 +120,11 @@
     s->appendS32(stage);
 }
 
+static void tex_domain_name(int stage, GrStringBuilder* s) {
+    *s = "uTexDom";
+    s->appendS32(stage);
+}
+
 GrGLProgram::GrGLProgram() {
     for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
         fStageEffects[stage] = NULL;
@@ -650,6 +655,15 @@
                                              radial2ParamName.c_str()));
                 GrAssert(kUnusedUniform != locations.fRadial2Uni);
             }
+
+            if (kUseUniform == locations.fTexDomUni) {
+                GrStringBuilder texDomName;
+                tex_domain_name(s, &texDomName);
+                locations.fTexDomUni = GR_GL(GetUniformLocation(
+                                             progID,
+                                             texDomName.c_str()));
+                GrAssert(kUnusedUniform != locations.fTexDomUni);
+            }
         }
     }
     GR_GL(UseProgram(progID));
@@ -869,6 +883,24 @@
         modulate.printf(" * %s", fsInColor);
     }
 
+    if (desc.fOptFlags & 
+        ProgramDesc::StageDesc::kCustomTextureDomain_OptFlagBit) {
+        GrStringBuilder texDomainName;
+        tex_domain_name(stageNum, &texDomainName);
+        segments->fFSUnis.appendf("uniform %s %s;\n", 
+                                  float_vector_type(4),
+                                  texDomainName.c_str());
+        GrStringBuilder coordVar("clampCoord");
+        segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
+                                  float_vector_type(coordDims),
+                                  coordVar.c_str(),
+                                  sampleCoords.c_str(),
+                                  texDomainName.c_str(),
+                                  texDomainName.c_str());
+        sampleCoords = coordVar;
+        locations->fTexDomUni = kUseUniform;
+    }
+
     if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
         locations->fNormalizedTexelSizeUni = kUseUniform;
         if (complexCoord) {
diff --git a/gpu/src/GrGLProgram.h b/gpu/src/GrGLProgram.h
index 1611ca2..74078e3 100644
--- a/gpu/src/GrGLProgram.h
+++ b/gpu/src/GrGLProgram.h
@@ -70,14 +70,6 @@
      */
     void doGLPost() const;
 
-    /**
-     *  Configures the GrGLProgram based on the state of a GrDrawTarget
-     *  object.  This is the fast and light initialization. Retrieves all the
-     *  state that is required for performing the heavy init (i.e. genProgram),
-     *  or for retrieving heavy init results from cache.
-     */
-    void buildFromTarget(const GrDrawTarget* target);
-
     static int PositionAttributeIdx() { return 0; }
     static int TexCoordAttributeIdx(int tcIdx) { return 1 + tcIdx; }
     static int ColorAttributeIdx() { return 1 + GrDrawTarget::kMaxTexCoords; }
@@ -114,8 +106,9 @@
 
         struct StageDesc {
             enum OptFlagBits {
-                kNoPerspective_OptFlagBit  = 0x1,
-                kIdentityMatrix_OptFlagBit = 0x2
+                kNoPerspective_OptFlagBit       = 1 << 0,
+                kIdentityMatrix_OptFlagBit      = 1 << 1,
+                kCustomTextureDomain_OptFlagBit = 1 << 2
             };
 
             unsigned fOptFlags;
@@ -153,11 +146,13 @@
         GrGLint fNormalizedTexelSizeUni;
         GrGLint fSamplerUni;
         GrGLint fRadial2Uni;
+        GrGLint fTexDomUni;
         void reset() {
             fTextureMatrixUni = kUnusedUniform;
             fNormalizedTexelSizeUni = kUnusedUniform;
             fSamplerUni = kUnusedUniform;
             fRadial2Uni = kUnusedUniform;
+            fTexDomUni = kUnusedUniform;
         }
     };
 
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index fcfc120..125b820 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -309,8 +309,39 @@
     }
 }
 
+void GrGpuGLShaders::flushTextureDomain(int s) {
+    const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
+    if (GrGLProgram::kUnusedUniform != uni) {
+        const GrRect &texDom = 
+            fCurrDrawState.fSamplerStates[s].getTextureDomain();
+
+        float values[4] = {
+            GrScalarToFloat(texDom.left()), 
+            GrScalarToFloat(texDom.top()), 
+            GrScalarToFloat(texDom.right()), 
+            GrScalarToFloat(texDom.bottom())            
+        };
+
+        GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
+        GrGLTexture::Orientation orientation = texture->orientation();
+
+        // vertical flip if necessary
+        if (GrGLTexture::kBottomUp_Orientation == orientation) {
+            values[1] = 1.0f - values[1];
+            values[3] = 1.0f - values[3];
+        }
+
+        values[0] *= SkScalarToFloat(texture->contentScaleX());
+        values[2] *= SkScalarToFloat(texture->contentScaleX());
+        values[1] *= SkScalarToFloat(texture->contentScaleY());
+        values[3] *= SkScalarToFloat(texture->contentScaleY());
+
+        GR_GL(Uniform4fv(uni, 1, values));
+    }
+}
+
 void GrGpuGLShaders::flushTextureMatrix(int s) {
-    const int& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
+    const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
     GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
     if (NULL != texture) {
         if (GrGLProgram::kUnusedUniform != uni &&
@@ -516,6 +547,8 @@
         this->flushRadial2(s);
 
         this->flushTexelSize(s);
+
+        this->flushTextureDomain(s);
     }
     this->flushEdgeAAData();
     resetDirtyFlags();
@@ -702,6 +735,16 @@
                     break;
             }
 
+            if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
+                GrAssert(GrSamplerState::kClamp_WrapMode == 
+                    fCurrDrawState.fSamplerStates[s].getWrapX() && 
+                    GrSamplerState::kClamp_WrapMode ==
+                    fCurrDrawState.fSamplerStates[s].getWrapY());
+                stage.fOptFlags |= 
+                    GrGLProgram::ProgramDesc::StageDesc::
+                    kCustomTextureDomain_OptFlagBit;
+            }
+
             if (GrPixelConfigIsAlphaOnly(texture->config())) {
                 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
             } else {
@@ -725,4 +768,3 @@
 }
 
 
-
diff --git a/gpu/src/GrGpuGLShaders.h b/gpu/src/GrGpuGLShaders.h
index bb3024f..9392d1c 100644
--- a/gpu/src/GrGpuGLShaders.h
+++ b/gpu/src/GrGpuGLShaders.h
@@ -51,6 +51,9 @@
     // sets the texture matrix uniform for currently bound program
     void flushTextureMatrix(int stage);
 
+    // sets the texture domain uniform for currently bound program
+    void flushTextureDomain(int stage);
+
     // sets the color specified by GrDrawTarget::setColor()
     void flushColor();