Revert of Revert of Extract most of the mutable state of SkShader into a separate Context object. (https://codereview.chromium.org/249643002/)

Reason for revert:
Chromium side change landed along side DEPS roll that includes r14323.

Original issue's description:
> Revert of Extract most of the mutable state of SkShader into a separate Context object. (https://codereview.chromium.org/207683004/)
>
> Reason for revert:
> This is blocking the DEPS roll into Chromium. Failures can be seen here:
>
> http://build.chromium.org/p/tryserver.chromium/builders/android_dbg/builds/174333
>
> Original issue's description:
> > Extract most of the mutable state of SkShader into a separate Context object.
> >
> > SkShader currently stores some state during draw calls via setContext(...).
> > Move that mutable state into a separate SkShader::Context class that is
> > constructed on demand for the duration of the draw.
> >
> > Calls to setContext() are replaced with createContext() which returns a context
> > corresponding to the shader object or NULL if the parameters to createContext
> > are invalid.
> >
> > TEST=out/Debug/dm
> > BUG=skia:1976
> >
> > Committed: http://code.google.com/p/skia/source/detail?r=14216
> >
> > Committed: http://code.google.com/p/skia/source/detail?r=14323
>
> TBR=scroggo@google.com,skyostil@chromium.org,tomhudson@chromium.org,senorblanco@chromium.org,reed@google.com,bungeman@google.com,dominikg@chromium.org
> NOTREECHECKS=true
> NOTRY=true
> BUG=skia:1976
>
> Committed: http://code.google.com/p/skia/source/detail?r=14326

R=scroggo@google.com, skyostil@chromium.org, tomhudson@chromium.org, senorblanco@chromium.org, reed@google.com, bungeman@google.com, dominikg@chromium.org
TBR=bungeman@google.com, dominikg@chromium.org, reed@google.com, scroggo@google.com, senorblanco@chromium.org, skyostil@chromium.org, tomhudson@chromium.org
NOTREECHECKS=true
NOTRY=true
BUG=skia:1976

Author: bsalomon@google.com

Review URL: https://codereview.chromium.org/246403013

git-svn-id: http://skia.googlecode.com/svn/trunk@14328 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkShader.h b/include/core/SkShader.h
index 6566e69..cc2cc75 100644
--- a/include/core/SkShader.h
+++ b/include/core/SkShader.h
@@ -38,7 +38,7 @@
     virtual ~SkShader();
 
     /**
-     * Returns true if the local matrix is not an identity matrix.
+     *  Returns true if the local matrix is not an identity matrix.
      */
     bool hasLocalMatrix() const { return !fLocalMatrix.isIdentity(); }
 
@@ -96,7 +96,7 @@
         */
         kIntrinsicly16_Flag = 0x04,
 
-        /** set (after setContext) if the spans only vary in X (const in Y).
+        /** set if the spans only vary in X (const in Y).
             e.g. an Nx1 bitmap that is being tiled in Y, or a linear-gradient
             that varies from left-to-right. This flag specifies this for
             shadeSpan().
@@ -112,84 +112,111 @@
     };
 
     /**
-     *  Called sometimes before drawing with this shader. Return the type of
-     *  alpha your shader will return. The default implementation returns 0.
-     *  Your subclass should override if it can (even sometimes) report a
-     *  non-zero value, since that will enable various blitters to perform
-     *  faster.
-     */
-    virtual uint32_t getFlags() { return 0; }
-
-    /**
      *  Returns true if the shader is guaranteed to produce only opaque
      *  colors, subject to the SkPaint using the shader to apply an opaque
      *  alpha value. Subclasses should override this to allow some
-     *  optimizations.  isOpaque() can be called at any time, unlike getFlags,
-     *  which only works properly when the context is set.
+     *  optimizations.
      */
     virtual bool isOpaque() const { return false; }
 
-    /**
-     *  Return the alpha associated with the data returned by shadeSpan16(). If
-     *  kHasSpan16_Flag is not set, this value is meaningless.
-     */
-    virtual uint8_t getSpan16Alpha() const { return fPaintAlpha; }
+    class Context : public ::SkNoncopyable {
+    public:
+        Context(const SkShader& shader, const SkBitmap& device,
+                const SkPaint& paint, const SkMatrix& matrix);
+
+        virtual ~Context();
+
+        /**
+         *  Called sometimes before drawing with this shader. Return the type of
+         *  alpha your shader will return. The default implementation returns 0.
+         *  Your subclass should override if it can (even sometimes) report a
+         *  non-zero value, since that will enable various blitters to perform
+         *  faster.
+         */
+        virtual uint32_t getFlags() const { return 0; }
+
+        /**
+         *  Return the alpha associated with the data returned by shadeSpan16(). If
+         *  kHasSpan16_Flag is not set, this value is meaningless.
+         */
+        virtual uint8_t getSpan16Alpha() const { return fPaintAlpha; }
+
+        /**
+         *  Called for each span of the object being drawn. Your subclass should
+         *  set the appropriate colors (with premultiplied alpha) that correspond
+         *  to the specified device coordinates.
+         */
+        virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0;
+
+        typedef void (*ShadeProc)(void* ctx, int x, int y, SkPMColor[], int count);
+        virtual ShadeProc asAShadeProc(void** ctx);
+
+        /**
+         *  Called only for 16bit devices when getFlags() returns
+         *  kOpaqueAlphaFlag | kHasSpan16_Flag
+         */
+        virtual void shadeSpan16(int x, int y, uint16_t[], int count);
+
+        /**
+         *  Similar to shadeSpan, but only returns the alpha-channel for a span.
+         *  The default implementation calls shadeSpan() and then extracts the alpha
+         *  values from the returned colors.
+         */
+        virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count);
+
+        /**
+         *  Helper function that returns true if this shader's shadeSpan16() method
+         *  can be called.
+         */
+        bool canCallShadeSpan16() {
+            return SkShader::CanCallShadeSpan16(this->getFlags());
+        }
+
+    protected:
+        // Reference to shader, so we don't have to dupe information.
+        const SkShader& fShader;
+
+        enum MatrixClass {
+            kLinear_MatrixClass,            // no perspective
+            kFixedStepInX_MatrixClass,      // fast perspective, need to call fixedStepInX() each
+                                            // scanline
+            kPerspective_MatrixClass        // slow perspective, need to mappoints each pixel
+        };
+        static MatrixClass ComputeMatrixClass(const SkMatrix&);
+
+        uint8_t             getPaintAlpha() const { return fPaintAlpha; }
+        const SkMatrix&     getTotalInverse() const { return fTotalInverse; }
+        MatrixClass         getInverseClass() const { return (MatrixClass)fTotalInverseClass; }
+
+    private:
+        SkMatrix            fTotalInverse;
+        uint8_t             fPaintAlpha;
+        uint8_t             fTotalInverseClass;
+
+        typedef SkNoncopyable INHERITED;
+    };
 
     /**
-     *  Called once before drawing, with the current paint and device matrix.
-     *  Return true if your shader supports these parameters, or false if not.
-     *  If false is returned, nothing will be drawn. If true is returned, then
-     *  a balancing call to endContext() will be made before the next call to
-     *  setContext.
-     *
-     *  Subclasses should be sure to call their INHERITED::setContext() if they
-     *  override this method.
+     *  Subclasses should be sure to call their INHERITED::validContext() if
+     *  they override this method.
      */
-    virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
-                            const SkMatrix& matrix);
+    virtual bool validContext(const SkBitmap& device, const SkPaint& paint,
+                              const SkMatrix& matrix, SkMatrix* totalInverse = NULL) const;
 
     /**
-     *  Assuming setContext returned true, endContext() will be called when
-     *  the draw using the shader has completed. It is an error for setContext
-     *  to be called twice w/o an intervening call to endContext().
-     *
-     *  Subclasses should be sure to call their INHERITED::endContext() if they
-     *  override this method.
+     *  Create the actual object that does the shading.
+     *  Returns NULL if validContext() returns false.
+     *  Size of storage must be >= contextSize.
      */
-    virtual void endContext();
-
-    SkDEBUGCODE(bool setContextHasBeenCalled() const { return SkToBool(fInSetContext); })
+    virtual Context* createContext(const SkBitmap& device,
+                                   const SkPaint& paint,
+                                   const SkMatrix& matrix,
+                                   void* storage) const = 0;
 
     /**
-     *  Called for each span of the object being drawn. Your subclass should
-     *  set the appropriate colors (with premultiplied alpha) that correspond
-     *  to the specified device coordinates.
+     *  Return the size of a Context returned by createContext.
      */
-    virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0;
-
-    typedef void (*ShadeProc)(void* ctx, int x, int y, SkPMColor[], int count);
-    virtual ShadeProc asAShadeProc(void** ctx);
-
-    /**
-     *  Called only for 16bit devices when getFlags() returns
-     *  kOpaqueAlphaFlag | kHasSpan16_Flag
-     */
-    virtual void shadeSpan16(int x, int y, uint16_t[], int count);
-
-    /**
-     *  Similar to shadeSpan, but only returns the alpha-channel for a span.
-     *  The default implementation calls shadeSpan() and then extracts the alpha
-     *  values from the returned colors.
-     */
-    virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count);
-
-    /**
-     *  Helper function that returns true if this shader's shadeSpan16() method
-     *  can be called.
-     */
-    bool canCallShadeSpan16() {
-        return SkShader::CanCallShadeSpan16(this->getFlags());
-    }
+    virtual size_t contextSize() const = 0;
 
     /**
      *  Helper to check the flags to know if it is legal to call shadeSpan16()
@@ -322,7 +349,7 @@
      *  The incoming color to the effect has r=g=b=a all extracted from the SkPaint's alpha.
      *  The output color should be the computed SkShader premul color modulated by the incoming
      *  color. The GrContext may be used by the effect to create textures. The GPU device does not
-     *  call setContext. Instead we pass the SkPaint here in case the shader needs paint info.
+     *  call createContext. Instead we pass the SkPaint here in case the shader needs paint info.
      */
     virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint& paint) const;
 
@@ -362,26 +389,14 @@
     SK_DEFINE_FLATTENABLE_TYPE(SkShader)
 
 protected:
-    enum MatrixClass {
-        kLinear_MatrixClass,            // no perspective
-        kFixedStepInX_MatrixClass,      // fast perspective, need to call fixedStepInX() each scanline
-        kPerspective_MatrixClass        // slow perspective, need to mappoints each pixel
-    };
-    static MatrixClass ComputeMatrixClass(const SkMatrix&);
-
-    // These can be called by your subclass after setContext() has been called
-    uint8_t             getPaintAlpha() const { return fPaintAlpha; }
-    const SkMatrix&     getTotalInverse() const { return fTotalInverse; }
-    MatrixClass         getInverseClass() const { return (MatrixClass)fTotalInverseClass; }
 
     SkShader(SkReadBuffer& );
     virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
+
 private:
     SkMatrix            fLocalMatrix;
-    SkMatrix            fTotalInverse;
-    uint8_t             fPaintAlpha;
-    uint8_t             fTotalInverseClass;
-    SkDEBUGCODE(SkBool8 fInSetContext;)
+
+    bool computeTotalInverse(const SkMatrix& matrix, SkMatrix* totalInverse) const;
 
     typedef SkFlattenable INHERITED;
 };