| Index: src/core/SkBlitter.cpp
 | 
| diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp
 | 
| index 7243f521613905cf164ecbff723d246ff5276917..52a05eded8fda41b55cc66a300875877b90e3f00 100644
 | 
| --- a/src/core/SkBlitter.cpp
 | 
| +++ b/src/core/SkBlitter.cpp
 | 
| @@ -26,15 +26,6 @@
 | 
|  
 | 
|  bool SkBlitter::isNullBlitter() const { return false; }
 | 
|  
 | 
| -bool SkBlitter::resetShaderContext(const SkBitmap& device, const SkPaint& paint,
 | 
| -                                   const SkMatrix& matrix) {
 | 
| -    return true;
 | 
| -}
 | 
| -
 | 
| -SkShader::Context* SkBlitter::getShaderContext() const {
 | 
| -    return NULL;
 | 
| -}
 | 
| -
 | 
|  const SkBitmap* SkBlitter::justAnOpaqueColor(uint32_t* value) {
 | 
|      return NULL;
 | 
|  }
 | 
| @@ -577,149 +568,102 @@
 | 
|  public:
 | 
|      Sk3DShader(SkShader* proxy) : fProxy(proxy) {
 | 
|          SkSafeRef(proxy);
 | 
| +        fMask = NULL;
 | 
|      }
 | 
|  
 | 
|      virtual ~Sk3DShader() {
 | 
|          SkSafeUnref(fProxy);
 | 
|      }
 | 
|  
 | 
| -    virtual size_t contextSize() const SK_OVERRIDE {
 | 
| -        size_t size = sizeof(Sk3DShaderContext);
 | 
| +    void setMask(const SkMask* mask) { fMask = mask; }
 | 
| +
 | 
| +    virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
 | 
| +                            const SkMatrix& matrix) SK_OVERRIDE {
 | 
| +        if (!this->INHERITED::setContext(device, paint, matrix)) {
 | 
| +            return false;
 | 
| +        }
 | 
|          if (fProxy) {
 | 
| -            size += fProxy->contextSize();
 | 
| -        }
 | 
| -        return size;
 | 
| -    }
 | 
| -
 | 
| -    virtual bool validContext(const SkBitmap& device, const SkPaint& paint,
 | 
| -                              const SkMatrix& matrix, SkMatrix* totalInverse = NULL) const
 | 
| -            SK_OVERRIDE
 | 
| -    {
 | 
| -        if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) {
 | 
| -            return false;
 | 
| -        }
 | 
| +            if (!fProxy->setContext(device, paint, matrix)) {
 | 
| +                // must keep our set/end context calls balanced
 | 
| +                this->INHERITED::endContext();
 | 
| +                return false;
 | 
| +            }
 | 
| +        } else {
 | 
| +            fPMColor = SkPreMultiplyColor(paint.getColor());
 | 
| +        }
 | 
| +        return true;
 | 
| +    }
 | 
| +
 | 
| +    virtual void endContext() SK_OVERRIDE {
 | 
|          if (fProxy) {
 | 
| -            return fProxy->validContext(device, paint, matrix);
 | 
| -        }
 | 
| -        return true;
 | 
| -    }
 | 
| -
 | 
| -    virtual SkShader::Context* createContext(const SkBitmap& device,
 | 
| -                                             const SkPaint& paint,
 | 
| -                                             const SkMatrix& matrix,
 | 
| -                                             void* storage) const SK_OVERRIDE
 | 
| -    {
 | 
| -        if (!this->validContext(device, paint, matrix)) {
 | 
| -            return NULL;
 | 
| -        }
 | 
| -
 | 
| -        SkShader::Context* proxyContext;
 | 
| +            fProxy->endContext();
 | 
| +        }
 | 
| +        this->INHERITED::endContext();
 | 
| +    }
 | 
| +
 | 
| +    virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE {
 | 
|          if (fProxy) {
 | 
| -            char* proxyContextStorage = (char*) storage + sizeof(Sk3DShaderContext);
 | 
| -            proxyContext = fProxy->createContext(device, paint, matrix, proxyContextStorage);
 | 
| -            SkASSERT(proxyContext);
 | 
| -        } else {
 | 
| -            proxyContext = NULL;
 | 
| -        }
 | 
| -        return SkNEW_PLACEMENT_ARGS(storage, Sk3DShaderContext, (*this, device, paint, matrix,
 | 
| -                                                                 proxyContext));
 | 
| -    }
 | 
| -
 | 
| -    class Sk3DShaderContext : public SkShader::Context {
 | 
| -    public:
 | 
| -        // Calls proxyContext's destructor but will NOT free its memory.
 | 
| -        Sk3DShaderContext(const Sk3DShader& shader, const SkBitmap& device, const SkPaint& paint,
 | 
| -                          const SkMatrix& matrix, SkShader::Context* proxyContext)
 | 
| -            : INHERITED(shader, device, paint, matrix)
 | 
| -            , fMask(NULL)
 | 
| -            , fProxyContext(proxyContext)
 | 
| -        {
 | 
| -            if (!fProxyContext) {
 | 
| -                fPMColor = SkPreMultiplyColor(paint.getColor());
 | 
| -            }
 | 
| -        }
 | 
| -
 | 
| -        virtual ~Sk3DShaderContext() {
 | 
| -            if (fProxyContext) {
 | 
| -                fProxyContext->~Context();
 | 
| -            }
 | 
| -        }
 | 
| -
 | 
| -        void setMask(const SkMask* mask) { fMask = mask; }
 | 
| -
 | 
| -        virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE {
 | 
| -            if (fProxyContext) {
 | 
| -                fProxyContext->shadeSpan(x, y, span, count);
 | 
| -            }
 | 
| -
 | 
| -            if (fMask == NULL) {
 | 
| -                if (fProxyContext == NULL) {
 | 
| -                    sk_memset32(span, fPMColor, count);
 | 
| -                }
 | 
| -                return;
 | 
| -            }
 | 
| -
 | 
| -            SkASSERT(fMask->fBounds.contains(x, y));
 | 
| -            SkASSERT(fMask->fBounds.contains(x + count - 1, y));
 | 
| -
 | 
| -            size_t          size = fMask->computeImageSize();
 | 
| -            const uint8_t*  alpha = fMask->getAddr8(x, y);
 | 
| -            const uint8_t*  mulp = alpha + size;
 | 
| -            const uint8_t*  addp = mulp + size;
 | 
| -
 | 
| -            if (fProxyContext) {
 | 
| -                for (int i = 0; i < count; i++) {
 | 
| -                    if (alpha[i]) {
 | 
| -                        SkPMColor c = span[i];
 | 
| -                        if (c) {
 | 
| -                            unsigned a = SkGetPackedA32(c);
 | 
| -                            unsigned r = SkGetPackedR32(c);
 | 
| -                            unsigned g = SkGetPackedG32(c);
 | 
| -                            unsigned b = SkGetPackedB32(c);
 | 
| -
 | 
| -                            unsigned mul = SkAlpha255To256(mulp[i]);
 | 
| -                            unsigned add = addp[i];
 | 
| -
 | 
| -                            r = SkFastMin32(SkAlphaMul(r, mul) + add, a);
 | 
| -                            g = SkFastMin32(SkAlphaMul(g, mul) + add, a);
 | 
| -                            b = SkFastMin32(SkAlphaMul(b, mul) + add, a);
 | 
| -
 | 
| -                            span[i] = SkPackARGB32(a, r, g, b);
 | 
| -                        }
 | 
| -                    } else {
 | 
| -                        span[i] = 0;
 | 
| -                    }
 | 
| -                }
 | 
| -            } else {    // color
 | 
| -                unsigned a = SkGetPackedA32(fPMColor);
 | 
| -                unsigned r = SkGetPackedR32(fPMColor);
 | 
| -                unsigned g = SkGetPackedG32(fPMColor);
 | 
| -                unsigned b = SkGetPackedB32(fPMColor);
 | 
| -                for (int i = 0; i < count; i++) {
 | 
| -                    if (alpha[i]) {
 | 
| +            fProxy->shadeSpan(x, y, span, count);
 | 
| +        }
 | 
| +
 | 
| +        if (fMask == NULL) {
 | 
| +            if (fProxy == NULL) {
 | 
| +                sk_memset32(span, fPMColor, count);
 | 
| +            }
 | 
| +            return;
 | 
| +        }
 | 
| +
 | 
| +        SkASSERT(fMask->fBounds.contains(x, y));
 | 
| +        SkASSERT(fMask->fBounds.contains(x + count - 1, y));
 | 
| +
 | 
| +        size_t          size = fMask->computeImageSize();
 | 
| +        const uint8_t*  alpha = fMask->getAddr8(x, y);
 | 
| +        const uint8_t*  mulp = alpha + size;
 | 
| +        const uint8_t*  addp = mulp + size;
 | 
| +
 | 
| +        if (fProxy) {
 | 
| +            for (int i = 0; i < count; i++) {
 | 
| +                if (alpha[i]) {
 | 
| +                    SkPMColor c = span[i];
 | 
| +                    if (c) {
 | 
| +                        unsigned a = SkGetPackedA32(c);
 | 
| +                        unsigned r = SkGetPackedR32(c);
 | 
| +                        unsigned g = SkGetPackedG32(c);
 | 
| +                        unsigned b = SkGetPackedB32(c);
 | 
| +
 | 
|                          unsigned mul = SkAlpha255To256(mulp[i]);
 | 
|                          unsigned add = addp[i];
 | 
|  
 | 
| -                        span[i] = SkPackARGB32( a,
 | 
| -                                        SkFastMin32(SkAlphaMul(r, mul) + add, a),
 | 
| -                                        SkFastMin32(SkAlphaMul(g, mul) + add, a),
 | 
| -                                        SkFastMin32(SkAlphaMul(b, mul) + add, a));
 | 
| -                    } else {
 | 
| -                        span[i] = 0;
 | 
| +                        r = SkFastMin32(SkAlphaMul(r, mul) + add, a);
 | 
| +                        g = SkFastMin32(SkAlphaMul(g, mul) + add, a);
 | 
| +                        b = SkFastMin32(SkAlphaMul(b, mul) + add, a);
 | 
| +
 | 
| +                        span[i] = SkPackARGB32(a, r, g, b);
 | 
|                      }
 | 
| +                } else {
 | 
| +                    span[i] = 0;
 | 
|                  }
 | 
|              }
 | 
| -        }
 | 
| -
 | 
| -    private:
 | 
| -        // Unowned.
 | 
| -        const SkMask*       fMask;
 | 
| -        // Memory is unowned, but we need to call the destructor.
 | 
| -        SkShader::Context*  fProxyContext;
 | 
| -        SkPMColor           fPMColor;
 | 
| -
 | 
| -        typedef SkShader::Context INHERITED;
 | 
| -    };
 | 
| +        } else {    // color
 | 
| +            unsigned a = SkGetPackedA32(fPMColor);
 | 
| +            unsigned r = SkGetPackedR32(fPMColor);
 | 
| +            unsigned g = SkGetPackedG32(fPMColor);
 | 
| +            unsigned b = SkGetPackedB32(fPMColor);
 | 
| +            for (int i = 0; i < count; i++) {
 | 
| +                if (alpha[i]) {
 | 
| +                    unsigned mul = SkAlpha255To256(mulp[i]);
 | 
| +                    unsigned add = addp[i];
 | 
| +
 | 
| +                    span[i] = SkPackARGB32( a,
 | 
| +                                    SkFastMin32(SkAlphaMul(r, mul) + add, a),
 | 
| +                                    SkFastMin32(SkAlphaMul(g, mul) + add, a),
 | 
| +                                    SkFastMin32(SkAlphaMul(b, mul) + add, a));
 | 
| +                } else {
 | 
| +                    span[i] = 0;
 | 
| +                }
 | 
| +            }
 | 
| +        }
 | 
| +    }
 | 
|  
 | 
|  #ifndef SK_IGNORE_TO_STRING
 | 
|      virtual void toString(SkString* str) const SK_OVERRIDE {
 | 
| @@ -741,30 +685,29 @@
 | 
|  protected:
 | 
|      Sk3DShader(SkReadBuffer& buffer) : INHERITED(buffer) {
 | 
|          fProxy = buffer.readShader();
 | 
| -        // Leaving this here until we bump the picture version, though this
 | 
| -        // shader should never be recorded.
 | 
| -        buffer.readColor();
 | 
| +        fPMColor = buffer.readColor();
 | 
| +        fMask = NULL;
 | 
|      }
 | 
|  
 | 
|      virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
 | 
|          this->INHERITED::flatten(buffer);
 | 
|          buffer.writeFlattenable(fProxy);
 | 
| -        // Leaving this here until we bump the picture version, though this
 | 
| -        // shader should never be recorded.
 | 
| -        buffer.writeColor(SkColor());
 | 
| +        buffer.writeColor(fPMColor);
 | 
|      }
 | 
|  
 | 
|  private:
 | 
|      SkShader*       fProxy;
 | 
| +    SkPMColor       fPMColor;
 | 
| +    const SkMask*   fMask;
 | 
|  
 | 
|      typedef SkShader INHERITED;
 | 
|  };
 | 
|  
 | 
|  class Sk3DBlitter : public SkBlitter {
 | 
|  public:
 | 
| -    Sk3DBlitter(SkBlitter* proxy, Sk3DShader::Sk3DShaderContext* shaderContext)
 | 
| +    Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader)
 | 
|          : fProxy(proxy)
 | 
| -        , f3DShaderContext(shaderContext)
 | 
| +        , f3DShader(SkRef(shader))
 | 
|      {}
 | 
|  
 | 
|      virtual void blitH(int x, int y, int width) {
 | 
| @@ -786,22 +729,22 @@
 | 
|  
 | 
|      virtual void blitMask(const SkMask& mask, const SkIRect& clip) {
 | 
|          if (mask.fFormat == SkMask::k3D_Format) {
 | 
| -            f3DShaderContext->setMask(&mask);
 | 
| +            f3DShader->setMask(&mask);
 | 
|  
 | 
|              ((SkMask*)&mask)->fFormat = SkMask::kA8_Format;
 | 
|              fProxy->blitMask(mask, clip);
 | 
|              ((SkMask*)&mask)->fFormat = SkMask::k3D_Format;
 | 
|  
 | 
| -            f3DShaderContext->setMask(NULL);
 | 
| +            f3DShader->setMask(NULL);
 | 
|          } else {
 | 
|              fProxy->blitMask(mask, clip);
 | 
|          }
 | 
|      }
 | 
|  
 | 
|  private:
 | 
| -    // Both pointers are unowned. They will be deleted by SkSmallAllocator.
 | 
| -    SkBlitter*                     fProxy;
 | 
| -    Sk3DShader::Sk3DShaderContext* f3DShaderContext;
 | 
| +    // fProxy is unowned. It will be deleted by SkSmallAllocator.
 | 
| +    SkBlitter*               fProxy;
 | 
| +    SkAutoTUnref<Sk3DShader> f3DShader;
 | 
|  };
 | 
|  
 | 
|  ///////////////////////////////////////////////////////////////////////////////
 | 
| @@ -811,7 +754,8 @@
 | 
|  static bool just_solid_color(const SkPaint& paint) {
 | 
|      if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) {
 | 
|          SkShader* shader = paint.getShader();
 | 
| -        if (NULL == shader) {
 | 
| +        if (NULL == shader ||
 | 
| +            (shader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
 | 
|              return true;
 | 
|          }
 | 
|      }
 | 
| @@ -949,22 +893,16 @@
 | 
|      }
 | 
|  
 | 
|      /*
 | 
| -     *  We create a SkShader::Context object, and store it on the blitter.
 | 
| +     *  We need to have balanced calls to the shader:
 | 
| +     *      setContext
 | 
| +     *      endContext
 | 
| +     *  We make the first call here, in case it fails we can abort the draw.
 | 
| +     *  The endContext() call is made by the blitter (assuming setContext did
 | 
| +     *  not fail) in its destructor.
 | 
|       */
 | 
| -    SkShader::Context* shaderContext;
 | 
| -    if (shader) {
 | 
| -        // Try to create the ShaderContext
 | 
| -        void* storage = allocator->reserveT<SkShader::Context>(shader->contextSize());
 | 
| -        shaderContext = shader->createContext(device, *paint, matrix, storage);
 | 
| -        if (!shaderContext) {
 | 
| -            allocator->freeLast();
 | 
| -            blitter = allocator->createT<SkNullBlitter>();
 | 
| -            return blitter;
 | 
| -        }
 | 
| -        SkASSERT(shaderContext);
 | 
| -        SkASSERT((void*) shaderContext == storage);
 | 
| -    } else {
 | 
| -        shaderContext = NULL;
 | 
| +    if (shader && !shader->setContext(device, *paint, matrix)) {
 | 
| +        blitter = allocator->createT<SkNullBlitter>();
 | 
| +        return blitter;
 | 
|      }
 | 
|  
 | 
|  
 | 
| @@ -975,20 +913,19 @@
 | 
|                  SkASSERT(NULL == paint->getXfermode());
 | 
|                  blitter = allocator->createT<SkA8_Coverage_Blitter>(device, *paint);
 | 
|              } else if (shader) {
 | 
| -                blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint, shaderContext);
 | 
| +                blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint);
 | 
|              } else {
 | 
|                  blitter = allocator->createT<SkA8_Blitter>(device, *paint);
 | 
|              }
 | 
|              break;
 | 
|  
 | 
|          case kRGB_565_SkColorType:
 | 
| -            blitter = SkBlitter_ChooseD565(device, *paint, shaderContext, allocator);
 | 
| +            blitter = SkBlitter_ChooseD565(device, *paint, allocator);
 | 
|              break;
 | 
|  
 | 
|          case kN32_SkColorType:
 | 
|              if (shader) {
 | 
| -                blitter = allocator->createT<SkARGB32_Shader_Blitter>(
 | 
| -                        device, *paint, shaderContext);
 | 
| +                blitter = allocator->createT<SkARGB32_Shader_Blitter>(device, *paint);
 | 
|              } else if (paint->getColor() == SK_ColorBLACK) {
 | 
|                  blitter = allocator->createT<SkARGB32_Black_Blitter>(device, *paint);
 | 
|              } else if (paint->getAlpha() == 0xFF) {
 | 
| @@ -1007,9 +944,7 @@
 | 
|      if (shader3D) {
 | 
|          SkBlitter* innerBlitter = blitter;
 | 
|          // innerBlitter was allocated by allocator, which will delete it.
 | 
| -        // We know shaderContext is of type Sk3DShaderContext because it belongs to shader3D.
 | 
| -        blitter = allocator->createT<Sk3DBlitter>(innerBlitter,
 | 
| -                static_cast<Sk3DShader::Sk3DShaderContext*>(shaderContext));
 | 
| +        blitter = allocator->createT<Sk3DBlitter>(innerBlitter, shader3D);
 | 
|      }
 | 
|      return blitter;
 | 
|  }
 | 
| @@ -1021,36 +956,18 @@
 | 
|  
 | 
|  ///////////////////////////////////////////////////////////////////////////////
 | 
|  
 | 
| -SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint,
 | 
| -                                 SkShader::Context* shaderContext)
 | 
| -        : INHERITED(device)
 | 
| -        , fShader(paint.getShader())
 | 
| -        , fShaderContext(shaderContext) {
 | 
| +SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint)
 | 
| +        : INHERITED(device) {
 | 
| +    fShader = paint.getShader();
 | 
|      SkASSERT(fShader);
 | 
| -    SkASSERT(fShaderContext);
 | 
| +    SkASSERT(fShader->setContextHasBeenCalled());
 | 
|  
 | 
|      fShader->ref();
 | 
| -    fShaderFlags = fShaderContext->getFlags();
 | 
| +    fShaderFlags = fShader->getFlags();
 | 
|  }
 | 
|  
 | 
|  SkShaderBlitter::~SkShaderBlitter() {
 | 
| +    SkASSERT(fShader->setContextHasBeenCalled());
 | 
| +    fShader->endContext();
 | 
|      fShader->unref();
 | 
|  }
 | 
| -
 | 
| -bool SkShaderBlitter::resetShaderContext(const SkBitmap& device, const SkPaint& paint,
 | 
| -                                         const SkMatrix& matrix) {
 | 
| -    if (!fShader->validContext(device, paint, matrix)) {
 | 
| -        return false;
 | 
| -    }
 | 
| -
 | 
| -    // Only destroy the old context if we have a new one. We need to ensure to have a
 | 
| -    // live context in fShaderContext because the storage is owned by an SkSmallAllocator
 | 
| -    // outside of this class.
 | 
| -    // The new context will be of the same size as the old one because we use the same
 | 
| -    // shader to create it. It is therefore safe to re-use the storage.
 | 
| -    fShaderContext->~Context();
 | 
| -    fShaderContext = fShader->createContext(device, paint, matrix, (void*)fShaderContext);
 | 
| -    SkASSERT(fShaderContext);
 | 
| -
 | 
| -    return true;
 | 
| -}
 | 
| 
 |