Make GrPaint have a variable sized array of color and coverage stages rather than a fixed size.

R=robertphillips@google.com, jvanverth@google.com

Author: bsalomon@google.com

Review URL: https://chromiumcodereview.appspot.com/18686007

git-svn-id: http://skia.googlecode.com/svn/trunk@10062 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 3b0d143..ab7693c 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -38,15 +38,6 @@
     #define CHECK_SHOULD_DRAW(draw, forceI) this->prepareDraw(draw, forceI)
 #endif
 
-// we use the same effect slot on GrPaint for bitmaps and shaders (since drawBitmap, drawSprite,
-// and drawDevice ignore SkShader)
-enum {
-    kShaderEffectIdx = 0,
-    kBitmapEffectIdx = 0,
-    kColorFilterEffectIdx = 1,
-    kXfermodeEffectIdx = 2,
-};
-
 // This constant represents the screen alignment criterion in texels for
 // requiring texture domain clamping to prevent color bleeding when drawing
 // a sub region of a larger source image.
@@ -442,16 +433,6 @@
     return fRenderTarget;
 }
 
-bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
-    GrTexture* texture = fRenderTarget->asTexture();
-    if (NULL != texture) {
-        paint->colorStage(kBitmapEffectIdx)->setEffect(
-            GrSimpleTextureEffect::Create(texture, SkMatrix::I()))->unref();
-        return true;
-    }
-    return false;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
@@ -489,7 +470,7 @@
     GrEffectRef* xferEffect = NULL;
     if (SkXfermode::AsNewEffectOrCoeff(mode, dev->context(), &xferEffect, &sm, &dm)) {
         if (NULL != xferEffect) {
-            grPaint->colorStage(kXfermodeEffectIdx)->setEffect(xferEffect)->unref();
+            grPaint->addColorEffect(xferEffect)->unref();
             sm = SkXfermode::kOne_Coeff;
             dm = SkXfermode::kZero_Coeff;
         }
@@ -513,7 +494,6 @@
         GrAssert(!constantColor);
     } else {
         grPaint->setColor(SkColor2GrColor(skPaint.getColor()));
-        GrAssert(!grPaint->isColorStageEnabled(kShaderEffectIdx));
     }
 
     SkColorFilter* colorFilter = skPaint.getColorFilter();
@@ -526,7 +506,7 @@
         } else {
             SkAutoTUnref<GrEffectRef> effect(colorFilter->asNewEffect(dev->context()));
             if (NULL != effect.get()) {
-                grPaint->colorStage(kColorFilterEffectIdx)->setEffect(effect);
+                grPaint->addColorEffect(effect);
             } else {
                 // TODO: rewrite this using asNewEffect()
                 SkColor color;
@@ -552,32 +532,33 @@
     SkShader* shader = skPaint.getShader();
     if (NULL == shader) {
         return skPaint2GrPaintNoShader(dev, skPaint, false, constantColor, grPaint);
-    } else if (!skPaint2GrPaintNoShader(dev, skPaint, true, false, grPaint)) {
-        return false;
     }
 
+    // setup the shader as the first color effect on the paint
     SkAutoTUnref<GrEffectRef> effect(shader->asNewEffect(dev->context(), skPaint));
     if (NULL != effect.get()) {
-        grPaint->colorStage(kShaderEffectIdx)->setEffect(effect);
-        return true;
-    }
+        grPaint->addColorEffect(effect);
+        // Now setup the rest of the paint.
+        return skPaint2GrPaintNoShader(dev, skPaint, true, false, grPaint);
+    } else {
+        // We still don't have SkColorShader::asNewEffect() implemented.
+        SkShader::GradientInfo info;
+        SkColor                color;
 
-    // We still don't have SkColorShader::asNewEffect() implemented.
-    SkShader::GradientInfo info;
-    SkColor                color;
-
-    info.fColors = &color;
-    info.fColorOffsets = NULL;
-    info.fColorCount = 1;
-    if (SkShader::kColor_GradientType == shader->asAGradient(&info)) {
-        SkPaint copy(skPaint);
-        copy.setShader(NULL);
-        // modulate the paint alpha by the shader's solid color alpha
-        U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
-        copy.setColor(SkColorSetA(color, newA));
-        return skPaint2GrPaintNoShader(dev, copy, false, constantColor, grPaint);
+        info.fColors = &color;
+        info.fColorOffsets = NULL;
+        info.fColorCount = 1;
+        if (SkShader::kColor_GradientType == shader->asAGradient(&info)) {
+            SkPaint copy(skPaint);
+            copy.setShader(NULL);
+            // modulate the paint alpha by the shader's solid color alpha
+            U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
+            copy.setColor(SkColorSetA(color, newA));
+            return skPaint2GrPaintNoShader(dev, copy, false, constantColor, grPaint);
+        } else {
+            return false;
+        }
     }
-    return false;
 }
 }
 
@@ -769,22 +750,16 @@
 // Return true if the mask was successfully drawn.
 bool draw_mask(GrContext* context, const SkRect& maskRect,
                GrPaint* grp, GrTexture* mask) {
-
     GrContext::AutoMatrix am;
     if (!am.setIdentity(context, grp)) {
         return false;
     }
 
-    static const int MASK_IDX = GrPaint::kMaxCoverageStages - 1;
-    // we assume the last mask index is available for use
-    GrAssert(!grp->isCoverageStageEnabled(MASK_IDX));
-
     SkMatrix matrix;
     matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop);
     matrix.postIDiv(mask->width(), mask->height());
 
-    grp->coverageStage(MASK_IDX)->reset();
-    grp->coverageStage(MASK_IDX)->setEffect(GrSimpleTextureEffect::Create(mask, matrix))->unref();
+    grp->addCoverageEffect(GrSimpleTextureEffect::Create(mask, matrix))->unref();
     context->drawRect(*grp, maskRect);
     return true;
 }
@@ -1169,20 +1144,14 @@
         return;
     }
 
-    GrPaint grPaint;
-
-    bool alphaOnly = !(SkBitmap::kA8_Config == bitmap.config());
-    if (!skPaint2GrPaintNoShader(this, paint, alphaOnly, false, &grPaint)) {
-        return;
-    }
     GrTextureParams params;
     params.setBilerp(paint.isFilterBitmap());
 
     if (!this->shouldTileBitmap(bitmap, params, srcRectPtr)) {
         // take the simple case
-        this->internalDrawBitmap(bitmap, srcRect, m, params, &grPaint);
+        this->internalDrawBitmap(bitmap, srcRect, m, params, paint);
     } else {
-        this->drawTiledBitmap(bitmap, srcRect, m, params, &grPaint);
+        this->drawTiledBitmap(bitmap, srcRect, m, params, paint);
     }
 }
 
@@ -1192,7 +1161,7 @@
                                   const SkRect& srcRect,
                                   const SkMatrix& m,
                                   const GrTextureParams& params,
-                                  GrPaint* grPaint) {
+                                  const SkPaint& paint) {
     const int maxTextureSize = fContext->getMaxTextureSize();
 
     int tileSize = determine_tile_size(bitmap, srcRect, maxTextureSize);
@@ -1241,7 +1210,7 @@
                 tmpM.preTranslate(SkIntToScalar(iTileR.fLeft),
                                   SkIntToScalar(iTileR.fTop));
 
-                this->internalDrawBitmap(tmpB, tileR, tmpM, params, grPaint);
+                this->internalDrawBitmap(tmpB, tileR, tmpM, params, paint);
             }
         }
     }
@@ -1301,7 +1270,7 @@
                                      const SkRect& srcRect,
                                      const SkMatrix& m,
                                      const GrTextureParams& params,
-                                     GrPaint* grPaint) {
+                                     const SkPaint& paint) {
     SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
              bitmap.height() <= fContext->getMaxTextureSize());
 
@@ -1371,8 +1340,17 @@
     } else {
         effect.reset(GrSimpleTextureEffect::Create(texture, SkMatrix::I(), params));
     }
-    grPaint->colorStage(kBitmapEffectIdx)->setEffect(effect);
-    fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
+
+    // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring
+    // the rest from the SkPaint.
+    GrPaint grPaint;
+    grPaint.addColorEffect(effect);
+    bool alphaOnly = !(SkBitmap::kA8_Config == bitmap.config());
+    if (!skPaint2GrPaintNoShader(this, paint, alphaOnly, false, &grPaint)) {
+        return;
+    }
+
+    fContext->drawRectToRect(grPaint, dstRect, paintRect, &m);
 }
 
 static bool filter_texture(SkDevice* device, GrContext* context,
@@ -1404,33 +1382,28 @@
     int w = bitmap.width();
     int h = bitmap.height();
 
-    GrPaint grPaint;
-    if(!skPaint2GrPaintNoShader(this, paint, true, false, &grPaint)) {
-        return;
-    }
-
-    GrEffectStage* stage = grPaint.colorStage(kBitmapEffectIdx);
-
     GrTexture* texture;
-    stage->reset();
     // draw sprite uses the default texture params
     SkAutoCachedTexture act(this, bitmap, NULL, &texture);
-    grPaint.colorStage(kBitmapEffectIdx)->setEffect(
-        GrSimpleTextureEffect::Create(texture, SkMatrix::I()))->unref();
 
     SkImageFilter* filter = paint.getImageFilter();
     SkIPoint offset = SkIPoint::Make(0, 0);
     if (NULL != filter) {
         SkBitmap filterBitmap;
         if (filter_texture(this, fContext, texture, filter, w, h, &filterBitmap, &offset)) {
-            grPaint.colorStage(kBitmapEffectIdx)->setEffect(
-                GrSimpleTextureEffect::Create(filterBitmap.getTexture(), SkMatrix::I()))->unref();
-            texture = filterBitmap.getTexture();
+            texture = (GrTexture*) filterBitmap.getTexture();
             w = filterBitmap.width();
             h = filterBitmap.height();
         }
     }
 
+    GrPaint grPaint;
+    grPaint.addColorTextureEffect(texture, SkMatrix::I());
+
+    if(!skPaint2GrPaintNoShader(this, paint, true, false, &grPaint)) {
+        return;
+    }
+
     fContext->drawRectToRect(grPaint,
                              GrRect::MakeXYWH(SkIntToScalar(left),
                                               SkIntToScalar(top),
@@ -1484,27 +1457,22 @@
     // drawDevice is defined to be in device coords.
     CHECK_SHOULD_DRAW(draw, true);
 
-    GrPaint grPaint;
-    grPaint.colorStage(kBitmapEffectIdx)->reset();
-    if (!dev->bindDeviceAsTexture(&grPaint) ||
-        !skPaint2GrPaintNoShader(this, paint, true, false, &grPaint)) {
+    GrRenderTarget* devRT = device->accessRenderTarget();
+    GrTexture* devTex;
+    if (NULL == (devTex = devRT->asTexture())) {
         return;
     }
 
-    GrTexture* devTex = (*grPaint.getColorStage(kBitmapEffectIdx).getEffect())->texture(0);
-    SkASSERT(NULL != devTex);
-
     const SkBitmap& bm = dev->accessBitmap(false);
     int w = bm.width();
     int h = bm.height();
 
     SkImageFilter* filter = paint.getImageFilter();
+
     if (NULL != filter) {
         SkBitmap filterBitmap;
         SkIPoint offset = SkIPoint::Make(0, 0);
         if (filter_texture(this, fContext, devTex, filter, w, h, &filterBitmap, &offset)) {
-            grPaint.colorStage(kBitmapEffectIdx)->setEffect(
-                GrSimpleTextureEffect::Create(filterBitmap.getTexture(), SkMatrix::I()))->unref();
             devTex = filterBitmap.getTexture();
             w = filterBitmap.width();
             h = filterBitmap.height();
@@ -1513,13 +1481,20 @@
         }
     }
 
+    GrPaint grPaint;
+    grPaint.addColorTextureEffect(devTex, SkMatrix::I());
+
+    if (!skPaint2GrPaintNoShader(this, paint, true, false, &grPaint)) {
+        return;
+    }
+
     GrRect dstRect = GrRect::MakeXYWH(SkIntToScalar(x),
                                       SkIntToScalar(y),
                                       SkIntToScalar(w),
                                       SkIntToScalar(h));
 
-    // The device being drawn may not fill up its texture (saveLayer uses
-    // the approximate ).
+    // The device being drawn may not fill up its texture (e.g. saveLayer uses approximate
+    // scratch texture).
     GrRect srcRect = GrRect::MakeWH(SK_Scalar1 * w / devTex->width(),
                                     SK_Scalar1 * h / devTex->height());