Replace StatefulBaseRenderer inheritance with CanvasState member

Incrementally disentangles DisplayListRenderer and OpenGLRenderer.
Introduces abstract CanvasStateClient class to share three functions
between the two.

Design doc at https://docs.google.com/a/google.com/document/d/1PY1JF7AfPEF2UOUAnETS5j_4_tnJShTAMExvpCJfP8o/edit?usp=sharing.

BUG:15672762
R=djsollen@google.com,ccraik@google.com,jreck@google.com

Change-Id: Ic9fdffe18808e7d921ad06d01ea1ca25b2ad6f23
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 5b74add..51f257f 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -25,10 +25,9 @@
 		Animator.cpp \
 		AnimatorManager.cpp \
 		AssetAtlas.cpp \
-		DamageAccumulator.cpp \
-		FontRenderer.cpp \
-		GammaFontRenderer.cpp \
 		Caches.cpp \
+		CanvasState.cpp \
+		DamageAccumulator.cpp \
 		DisplayList.cpp \
 		DeferredDisplayList.cpp \
 		DeferredLayerUpdater.cpp \
@@ -38,6 +37,8 @@
 		DrawProfiler.cpp \
 		Extensions.cpp \
 		FboCache.cpp \
+		FontRenderer.cpp \
+		GammaFontRenderer.cpp \
 		GradientCache.cpp \
 		Image.cpp \
 		Interpolator.cpp \
@@ -62,7 +63,6 @@
 		SkiaShader.cpp \
 		Snapshot.cpp \
 		SpotShadow.cpp \
-		StatefulBaseRenderer.cpp \
 		Stencil.cpp \
 		TessellationCache.cpp \
 		Texture.cpp \
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/CanvasState.cpp
similarity index 71%
rename from libs/hwui/StatefulBaseRenderer.cpp
rename to libs/hwui/CanvasState.cpp
index 88d6f68..20cc17e 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -14,41 +14,45 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "OpenGLRenderer"
-
 #include <SkCanvas.h>
 
-#include "StatefulBaseRenderer.h"
-
+#include "CanvasState.h"
 #include "utils/MathUtils.h"
 
 namespace android {
 namespace uirenderer {
 
-StatefulBaseRenderer::StatefulBaseRenderer()
+
+CanvasState::CanvasState(CanvasStateClient& renderer)
         : mDirtyClip(false)
         , mWidth(-1)
         , mHeight(-1)
         , mSaveCount(1)
         , mFirstSnapshot(new Snapshot)
+        , mCanvas(renderer)
         , mSnapshot(mFirstSnapshot) {
+
 }
 
-void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop,
+CanvasState::~CanvasState() {
+
+}
+
+void CanvasState::initializeSaveStack(float clipLeft, float clipTop,
         float clipRight, float clipBottom, const Vector3& lightCenter) {
     mSnapshot = new Snapshot(mFirstSnapshot,
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
-    mSnapshot->fbo = getTargetFbo();
+    mSnapshot->fbo = mCanvas.onGetTargetFbo();
     mSnapshot->setRelativeLightCenter(lightCenter);
     mSaveCount = 1;
 }
 
-void StatefulBaseRenderer::setViewport(int width, int height) {
+void CanvasState::setViewport(int width, int height) {
     mWidth = width;
     mHeight = height;
     mFirstSnapshot->initializeViewport(width, height);
-    onViewportInitialized();
+    mCanvas.onViewportInitialized();
 
     // create a temporary 1st snapshot, so old snapshots are released,
     // and viewport can be queried safely.
@@ -63,24 +67,24 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
- * Non-virtual implementation of save, guaranteed to save without side-effects
+ * Guaranteed to save without side-effects
  *
- * The approach here and in restoreSnapshot(), allows subclasses to directly manipulate the save
+ * This approach, here and in restoreSnapshot(), allows subclasses to directly manipulate the save
  * stack, and ensures restoreToCount() doesn't call back into subclass overrides.
  */
-int StatefulBaseRenderer::saveSnapshot(int flags) {
+int CanvasState::saveSnapshot(int flags) {
     mSnapshot = new Snapshot(mSnapshot, flags);
     return mSaveCount++;
 }
 
-int StatefulBaseRenderer::save(int flags) {
+int CanvasState::save(int flags) {
     return saveSnapshot(flags);
 }
 
 /**
- * Non-virtual implementation of restore, guaranteed to restore without side-effects.
+ * Guaranteed to restore without side-effects.
  */
-void StatefulBaseRenderer::restoreSnapshot() {
+void CanvasState::restoreSnapshot() {
     sp<Snapshot> toRemove = mSnapshot;
     sp<Snapshot> toRestore = mSnapshot->previous;
 
@@ -88,16 +92,16 @@
     mSnapshot = toRestore;
 
     // subclass handles restore implementation
-    onSnapshotRestored(*toRemove, *toRestore);
+    mCanvas.onSnapshotRestored(*toRemove, *toRestore);
 }
 
-void StatefulBaseRenderer::restore() {
+void CanvasState::restore() {
     if (mSaveCount > 1) {
         restoreSnapshot();
     }
 }
 
-void StatefulBaseRenderer::restoreToCount(int saveCount) {
+void CanvasState::restoreToCount(int saveCount) {
     if (saveCount < 1) saveCount = 1;
 
     while (mSaveCount > saveCount) {
@@ -109,40 +113,40 @@
 // Matrix
 ///////////////////////////////////////////////////////////////////////////////
 
-void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const {
+void CanvasState::getMatrix(SkMatrix* matrix) const {
     mSnapshot->transform->copyTo(*matrix);
 }
 
-void StatefulBaseRenderer::translate(float dx, float dy, float dz) {
+void CanvasState::translate(float dx, float dy, float dz) {
     mSnapshot->transform->translate(dx, dy, dz);
 }
 
-void StatefulBaseRenderer::rotate(float degrees) {
+void CanvasState::rotate(float degrees) {
     mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
 }
 
-void StatefulBaseRenderer::scale(float sx, float sy) {
+void CanvasState::scale(float sx, float sy) {
     mSnapshot->transform->scale(sx, sy, 1.0f);
 }
 
-void StatefulBaseRenderer::skew(float sx, float sy) {
+void CanvasState::skew(float sx, float sy) {
     mSnapshot->transform->skew(sx, sy);
 }
 
-void StatefulBaseRenderer::setMatrix(const SkMatrix& matrix) {
+void CanvasState::setMatrix(const SkMatrix& matrix) {
     mSnapshot->transform->load(matrix);
 }
 
-void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) {
+void CanvasState::setMatrix(const Matrix4& matrix) {
     mSnapshot->transform->load(matrix);
 }
 
-void StatefulBaseRenderer::concatMatrix(const SkMatrix& matrix) {
+void CanvasState::concatMatrix(const SkMatrix& matrix) {
     mat4 transform(matrix);
     mSnapshot->transform->multiply(transform);
 }
 
-void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) {
+void CanvasState::concatMatrix(const Matrix4& matrix) {
     mSnapshot->transform->multiply(matrix);
 }
 
@@ -150,7 +154,7 @@
 // Clip
 ///////////////////////////////////////////////////////////////////////////////
 
-bool StatefulBaseRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
+bool CanvasState::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
     if (CC_LIKELY(currentTransform()->rectToRect())) {
         mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op);
         return !mSnapshot->clipRect->isEmpty();
@@ -159,10 +163,10 @@
     SkPath path;
     path.addRect(left, top, right, bottom);
 
-    return StatefulBaseRenderer::clipPath(&path, op);
+    return CanvasState::clipPath(&path, op);
 }
 
-bool StatefulBaseRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
+bool CanvasState::clipPath(const SkPath* path, SkRegion::Op op) {
     SkMatrix transform;
     currentTransform()->copyTo(transform);
 
@@ -189,12 +193,12 @@
     return !mSnapshot->clipRect->isEmpty();
 }
 
-bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
+bool CanvasState::clipRegion(const SkRegion* region, SkRegion::Op op) {
     mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op);
     return !mSnapshot->clipRect->isEmpty();
 }
 
-void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
+void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
     Rect bounds;
     float radius;
     if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
@@ -209,7 +213,7 @@
     }
 }
 
-void StatefulBaseRenderer::setClippingRoundRect(LinearAllocator& allocator,
+void CanvasState::setClippingRoundRect(LinearAllocator& allocator,
         const Rect& rect, float radius, bool highPriority) {
     mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority);
 }
@@ -229,7 +233,7 @@
  * @param snapOut if set, the geometry will be treated as having an AA ramp.
  *         See Rect::snapGeometryToPixelBoundaries()
  */
-bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
+bool CanvasState::calculateQuickRejectForScissor(float left, float top,
         float right, float bottom,
         bool* clipRequired, bool* roundRectClipRequired,
         bool snapOut) const {
@@ -259,18 +263,7 @@
     return false;
 }
 
-/**
- * Returns false if drawing won't be clipped out.
- *
- * Makes the decision conservatively, by rounding out the mapped rect before comparing with the
- * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but
- * rejection is still desired.
- *
- * This function, unlike quickRejectSetupScissor, should be used where precise geometry information
- * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass
- * rejection where precise rejection isn't important, or precise information isn't available.
- */
-bool StatefulBaseRenderer::quickRejectConservative(float left, float top,
+bool CanvasState::quickRejectConservative(float left, float top,
         float right, float bottom) const {
     if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
         return true;
@@ -288,5 +281,5 @@
     return false;
 }
 
-}; // namespace uirenderer
-}; // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
new file mode 100644
index 0000000..b15698e
--- /dev/null
+++ b/libs/hwui/CanvasState.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_CANVAS_STATE_H
+#define ANDROID_HWUI_CANVAS_STATE_H
+
+#include <SkMatrix.h>
+#include <SkPath.h>
+#include <SkRegion.h>
+
+#include "Snapshot.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Abstract base class for any class containing CanvasState.
+ * Defines three mandatory callbacks.
+ */
+class CanvasStateClient {
+public:
+    CanvasStateClient() { }
+    virtual ~CanvasStateClient() { }
+
+    /**
+     * Callback allowing embedder to take actions in the middle of a
+     * setViewport() call.
+     */
+    virtual void onViewportInitialized() = 0;
+
+    /**
+     * Callback allowing embedder to take actions in the middle of a
+     * restore() call.  May be called several times sequentially.
+     */
+    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) = 0;
+
+    /**
+     * Allows subclasses to control what value is stored in snapshot's
+     * fbo field in * initializeSaveStack.
+     */
+    virtual GLuint onGetTargetFbo() const = 0;
+
+}; // class CanvasStateClient
+
+/**
+ * Implements Canvas state methods on behalf of Renderers.
+ *
+ * Manages the Snapshot stack, implementing matrix, save/restore, and clipping methods in the
+ * Renderer interface. Drawing and recording classes that include a CanvasState will have
+ * different use cases:
+ *
+ * Drawing subclasses (i.e. OpenGLRenderer) can query attributes (such as transform) or hook into
+ * changes (e.g. save/restore) with minimal surface area for manipulating the stack itself.
+ *
+ * Recording subclasses (i.e. DisplayListRenderer) can both record and pass through state operations
+ * to CanvasState, so that not only will querying operations work (getClip/Matrix), but so
+ * that quickRejection can also be used.
+ */
+
+class CanvasState {
+public:
+    CanvasState(CanvasStateClient& renderer);
+    ~CanvasState();
+
+    /**
+     * Initializes the first snapshot, computing the projection matrix,
+     * and stores the dimensions of the render target.
+     */
+    void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom,
+            const Vector3& lightCenter);
+
+    void setViewport(int width, int height);
+
+    bool hasRectToRectTransform() const {
+        return CC_LIKELY(currentTransform()->rectToRect());
+    }
+
+    // Save (layer)
+    int getSaveCount() const { return mSaveCount; }
+    int save(int flags);
+    void restore();
+    void restoreToCount(int saveCount);
+
+    // Save/Restore without side-effects
+    int saveSnapshot(int flags);
+    void restoreSnapshot();
+
+    // Matrix
+    void getMatrix(SkMatrix* outMatrix) const;
+    void translate(float dx, float dy, float dz = 0.0f);
+    void rotate(float degrees);
+    void scale(float sx, float sy);
+    void skew(float sx, float sy);
+
+    void setMatrix(const SkMatrix& matrix);
+    void setMatrix(const Matrix4& matrix); // internal only convenience method
+    void concatMatrix(const SkMatrix& matrix);
+    void concatMatrix(const Matrix4& matrix); // internal only convenience method
+
+    // Clip
+    const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
+    const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
+
+    bool quickRejectConservative(float left, float top, float right, float bottom) const;
+
+    bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
+    bool clipPath(const SkPath* path, SkRegion::Op op);
+    bool clipRegion(const SkRegion* region, SkRegion::Op op);
+
+    bool isCurrentClipSimple() const {
+        return currentSnapshot()->clipRegion->isEmpty();
+    }
+
+    /**
+     * Sets a "clipping outline", which is independent from the regular clip.
+     * Currently only supports rectangles or rounded rectangles; passing in a
+     * more complicated outline fails silently. Replaces any previous clipping
+     * outline.
+     */
+    void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
+    void setClippingRoundRect(LinearAllocator& allocator,
+            const Rect& rect, float radius, bool highPriority = true);
+
+    /**
+     * Returns true if drawing in the rectangle (left, top, right, bottom)
+     * will be clipped out. Is conservative: might return false when subpixel-
+     * perfect tests would return true.
+     */
+    bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
+            bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const;
+
+    void setDirtyClip(bool opaque) { mDirtyClip = opaque; }
+    bool getDirtyClip() const { return mDirtyClip; }
+
+    void scaleAlpha(float alpha) { mSnapshot->alpha *= alpha; }
+    void setEmpty(bool value) { mSnapshot->empty = value; }
+    void setInvisible(bool value) { mSnapshot->invisible = value; }
+
+    inline const mat4* currentTransform() const { return currentSnapshot()->transform; }
+    inline const Rect* currentClipRect() const { return currentSnapshot()->clipRect; }
+    inline Region* currentRegion() const { return currentSnapshot()->region; }
+    inline int currentFlags() const { return currentSnapshot()->flags; }
+    const Vector3& currentLightCenter() const { return currentSnapshot()->getRelativeLightCenter(); }
+    inline bool currentlyIgnored() const { return currentSnapshot()->isIgnored(); }
+    int getViewportWidth() const { return currentSnapshot()->getViewportWidth(); }
+    int getViewportHeight() const { return currentSnapshot()->getViewportHeight(); }
+    int getWidth() { return mWidth; }
+    int getHeight() { return mHeight; }
+
+    inline const Snapshot* currentSnapshot() const {
+        return mSnapshot != NULL ? mSnapshot.get() : mFirstSnapshot.get();
+    }
+    inline Snapshot* writableSnapshot() { return mSnapshot.get(); }
+    inline const Snapshot* firstSnapshot() const { return mFirstSnapshot.get(); }
+
+private:
+    /// No default constructor - must supply a CanvasStateClient (mCanvas).
+    CanvasState();
+
+    /// indicates that the clip has been changed since the last time it was consumed
+    bool mDirtyClip;
+
+    /// Dimensions of the drawing surface
+    int mWidth, mHeight;
+
+    /// Number of saved states
+    int mSaveCount;
+
+    /// Base state
+    sp<Snapshot> mFirstSnapshot;
+
+    /// Host providing callbacks
+    CanvasStateClient& mCanvas;
+
+    /// Current state
+    sp<Snapshot> mSnapshot;
+
+}; // class CanvasState
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_CANVAS_STATE_H
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index ab9ca1f..c0b8a56 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -32,7 +32,8 @@
 namespace uirenderer {
 
 DisplayListRenderer::DisplayListRenderer()
-    : mCaches(Caches::getInstance())
+    : mState(*this)
+    , mCaches(Caches::getInstance())
     , mDisplayListData(NULL)
     , mTranslateX(0.0f)
     , mTranslateY(0.0f)
@@ -66,10 +67,10 @@
             "prepareDirty called a second time during a recording!");
     mDisplayListData = new DisplayListData();
 
-    initializeSaveStack(0, 0, getWidth(), getHeight(), Vector3());
+    mState.initializeSaveStack(0, 0, mState.getWidth(), mState.getHeight(), Vector3());
 
     mDeferredBarrierType = kBarrier_InOrder;
-    mDirtyClip = opaque;
+    mState.setDirtyClip(opaque);
     mRestoreSaveCount = -1;
 }
 
@@ -93,7 +94,7 @@
 
 int DisplayListRenderer::save(int flags) {
     addStateOp(new (alloc()) SaveOp(flags));
-    return StatefulBaseRenderer::save(flags);
+    return mState.save(flags);
 }
 
 void DisplayListRenderer::restore() {
@@ -104,13 +105,13 @@
 
     mRestoreSaveCount--;
     flushTranslate();
-    StatefulBaseRenderer::restore();
+    mState.restore();
 }
 
 void DisplayListRenderer::restoreToCount(int saveCount) {
     mRestoreSaveCount = saveCount;
     flushTranslate();
-    StatefulBaseRenderer::restoreToCount(saveCount);
+    mState.restoreToCount(saveCount);
 }
 
 int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
@@ -120,7 +121,7 @@
 
     paint = refPaint(paint);
     addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, paint, flags));
-    return StatefulBaseRenderer::save(flags);
+    return mState.save(flags);
 }
 
 void DisplayListRenderer::translate(float dx, float dy, float dz) {
@@ -129,50 +130,50 @@
     mTranslateX += dx;
     mTranslateY += dy;
     flushRestoreToCount();
-    StatefulBaseRenderer::translate(dx, dy, dz);
+    mState.translate(dx, dy, dz);
 }
 
 void DisplayListRenderer::rotate(float degrees) {
     addStateOp(new (alloc()) RotateOp(degrees));
-    StatefulBaseRenderer::rotate(degrees);
+    mState.rotate(degrees);
 }
 
 void DisplayListRenderer::scale(float sx, float sy) {
     addStateOp(new (alloc()) ScaleOp(sx, sy));
-    StatefulBaseRenderer::scale(sx, sy);
+    mState.scale(sx, sy);
 }
 
 void DisplayListRenderer::skew(float sx, float sy) {
     addStateOp(new (alloc()) SkewOp(sx, sy));
-    StatefulBaseRenderer::skew(sx, sy);
+    mState.skew(sx, sy);
 }
 
 void DisplayListRenderer::setMatrix(const SkMatrix& matrix) {
     addStateOp(new (alloc()) SetMatrixOp(matrix));
-    StatefulBaseRenderer::setMatrix(matrix);
+    mState.setMatrix(matrix);
 }
 
 void DisplayListRenderer::concatMatrix(const SkMatrix& matrix) {
     addStateOp(new (alloc()) ConcatMatrixOp(matrix));
-    StatefulBaseRenderer::concatMatrix(matrix);
+    mState.concatMatrix(matrix);
 }
 
 bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom,
         SkRegion::Op op) {
     addStateOp(new (alloc()) ClipRectOp(left, top, right, bottom, op));
-    return StatefulBaseRenderer::clipRect(left, top, right, bottom, op);
+    return mState.clipRect(left, top, right, bottom, op);
 }
 
 bool DisplayListRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
     path = refPath(path);
     addStateOp(new (alloc()) ClipPathOp(path, op));
-    return StatefulBaseRenderer::clipPath(path, op);
+    return mState.clipPath(path, op);
 }
 
 bool DisplayListRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
     region = refRegion(region);
     addStateOp(new (alloc()) ClipRegionOp(region, op));
-    return StatefulBaseRenderer::clipRegion(region, op);
+    return mState.clipRegion(region, op);
 }
 
 void DisplayListRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t flags) {
@@ -180,7 +181,7 @@
 
     // dirty is an out parameter and should not be recorded,
     // it matters only when replaying the display list
-    DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *currentTransform());
+    DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *mState.currentTransform());
     addRenderNodeOp(op);
 }
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 34b0a1f..7dd788d 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -25,9 +25,11 @@
 #include <SkTLazy.h>
 #include <cutils/compiler.h>
 
+#include "CanvasState.h"
 #include "DisplayList.h"
 #include "DisplayListLogBuffer.h"
-#include "StatefulBaseRenderer.h"
+#include "RenderNode.h"
+#include "Renderer.h"
 
 namespace android {
 namespace uirenderer {
@@ -57,7 +59,7 @@
 /**
  * Records drawing commands in a display list for later playback into an OpenGLRenderer.
  */
-class ANDROID_API DisplayListRenderer: public StatefulBaseRenderer {
+class ANDROID_API DisplayListRenderer: public Renderer, public CanvasStateClient {
 public:
     DisplayListRenderer();
     virtual ~DisplayListRenderer();
@@ -70,6 +72,9 @@
 // Frame state operations
 // ----------------------------------------------------------------------------
     virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
+    virtual void prepare(bool opaque) {
+        prepareDirty(0.0f, 0.0f, mState.getWidth(), mState.getHeight(), opaque);
+    }
     virtual bool finish();
     virtual void interrupt();
     virtual void resume();
@@ -77,7 +82,10 @@
 // ----------------------------------------------------------------------------
 // Canvas state operations
 // ----------------------------------------------------------------------------
+    virtual void setViewport(int width, int height) { mState.setViewport(width, height); }
+
     // Save (layer)
+    virtual int getSaveCount() const { return mState.getSaveCount(); }
     virtual int save(int flags);
     virtual void restore();
     virtual void restoreToCount(int saveCount);
@@ -85,6 +93,8 @@
             const SkPaint* paint, int flags);
 
     // Matrix
+    virtual void getMatrix(SkMatrix* outMatrix) const { mState.getMatrix(outMatrix); }
+
     virtual void translate(float dx, float dy, float dz = 0.0f);
     virtual void rotate(float degrees);
     virtual void scale(float sx, float sy);
@@ -100,9 +110,14 @@
 
     // Misc
     virtual void setDrawFilter(SkDrawFilter* filter);
+    virtual const Rect& getLocalClipBounds() const { return mState.getLocalClipBounds(); }
+    const Rect& getRenderTargetClipBounds() const { return mState.getRenderTargetClipBounds(); }
+    virtual bool quickRejectConservative(float left, float top, float right, float bottom) const {
+        return mState.quickRejectConservative(left, top, right, bottom);
+    }
 
     bool isCurrentTransformSimple() {
-        return currentTransform()->isSimple();
+        return mState.currentTransform()->isSimple();
     }
 
 // ----------------------------------------------------------------------------
@@ -163,7 +178,18 @@
     void setHighContrastText(bool highContrastText) {
         mHighContrastText = highContrastText;
     }
+
+// ----------------------------------------------------------------------------
+// CanvasState callbacks
+// ----------------------------------------------------------------------------
+    virtual void onViewportInitialized() { }
+    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) { }
+    virtual GLuint onGetTargetFbo() const { return -1; }
+
 private:
+
+    CanvasState mState;
+
     enum DeferredBarrierType {
         kBarrier_None,
         kBarrier_InOrder,
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 9306f13..268b9da 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -91,7 +91,7 @@
     return retval;
 }
 
-GLuint LayerRenderer::getTargetFbo() const {
+GLuint LayerRenderer::onGetTargetFbo() const {
     return mLayer->getFbo();
 }
 
@@ -116,7 +116,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 Region* LayerRenderer::getRegion() const {
-    if (currentSnapshot()->flags & Snapshot::kFlagFboTarget) {
+    if (mState.currentFlags() & Snapshot::kFlagFboTarget) {
         return OpenGLRenderer::getRegion();
     }
     return &mLayer->region;
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 47099bf..769ef49 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -68,7 +68,7 @@
     virtual void ensureStencilBuffer();
     virtual bool hasLayer() const;
     virtual Region* getRegion() const;
-    virtual GLuint getTargetFbo() const;
+    virtual GLuint onGetTargetFbo() const;
     virtual bool suppressErrorChecks() const;
 
 private:
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 1ac9e7b..71b7c11 100755
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -147,7 +147,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
-        : mFrameStarted(false)
+        : mState(*this)
+        , mFrameStarted(false)
         , mCaches(Caches::getInstance())
         , mExtensions(Extensions::getInstance())
         , mRenderState(renderState)
@@ -205,7 +206,7 @@
 void OpenGLRenderer::setupFrameState(float left, float top,
         float right, float bottom, bool opaque) {
     mCaches.clearGarbage();
-    initializeSaveStack(left, top, right, bottom, mLightCenter);
+    mState.initializeSaveStack(left, top, right, bottom, mLightCenter);
     mOpaque = opaque;
     mTilingClip.set(left, top, right, bottom);
 }
@@ -214,11 +215,11 @@
     if (mFrameStarted) return;
     mFrameStarted = true;
 
-    mDirtyClip = true;
+    mState.setDirtyClip(true);
 
     discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
 
-    mRenderState.setViewport(getWidth(), getHeight());
+    mRenderState.setViewport(mState.getWidth(), mState.getHeight());
 
     // Functors break the tiling extension in pretty spectacular ways
     // This ensures we don't use tiling when a functor is going to be
@@ -257,8 +258,8 @@
     // perform a discard to let the driver know we don't need to preserve
     // the back buffer for this frame.
     if (mExtensions.hasDiscardFramebuffer() &&
-            left <= 0.0f && top <= 0.0f && right >= getWidth() && bottom >= getHeight()) {
-        const bool isFbo = getTargetFbo() == 0;
+            left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) {
+        const bool isFbo = onGetTargetFbo() == 0;
         const GLenum attachments[] = {
                 isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0,
                 isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT };
@@ -329,7 +330,7 @@
 
     // When finish() is invoked on FBO 0 we've reached the end
     // of the current frame
-    if (getTargetFbo() == 0) {
+    if (onGetTargetFbo() == 0) {
         mCaches.pathCache.trim();
         mCaches.tessellationCache.trim();
     }
@@ -363,9 +364,9 @@
 }
 
 void OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
-    if (currentSnapshot()->isIgnored()) return;
+    if (mState.currentlyIgnored()) return;
 
-    Rect clip(*currentClipRect());
+    Rect clip(*mState.currentClipRect());
     clip.snapToPixelBoundaries();
 
     // Since we don't know what the functor will draw, let's dirty
@@ -384,9 +385,9 @@
     info.height = getViewportHeight();
     currentTransform()->copyTo(&info.transform[0]);
 
-    bool prevDirtyClip = mDirtyClip;
+    bool prevDirtyClip = mState.getDirtyClip();
     // setup GL state for functor
-    if (mDirtyClip) {
+    if (mState.getDirtyClip()) {
         setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
     }
     if (mCaches.enableScissor() || prevDirtyClip) {
@@ -436,11 +437,11 @@
 }
 
 void OpenGLRenderer::renderOverdraw() {
-    if (mCaches.debugOverdraw && getTargetFbo() == 0) {
+    if (mCaches.debugOverdraw && onGetTargetFbo() == 0) {
         const Rect* clip = &mTilingClip;
 
         mCaches.enableScissor();
-        mCaches.setScissor(clip->left, firstSnapshot()->getViewportHeight() - clip->bottom,
+        mCaches.setScissor(clip->left, mState.firstSnapshot()->getViewportHeight() - clip->bottom,
                 clip->right - clip->left, clip->bottom - clip->top);
 
         // 1x overdraw
@@ -519,7 +520,7 @@
 
         if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
             mLayerUpdates.clear();
-            mRenderState.bindFramebuffer(getTargetFbo());
+            mRenderState.bindFramebuffer(onGetTargetFbo());
         }
         endMark();
     }
@@ -546,7 +547,7 @@
         }
 
         mLayerUpdates.clear();
-        mRenderState.bindFramebuffer(getTargetFbo());
+        mRenderState.bindFramebuffer(onGetTargetFbo());
 
         endMark();
     }
@@ -628,9 +629,9 @@
     // force matrix/clip isolation for layer
     flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
 
-    const int count = saveSnapshot(flags);
+    const int count = mState.saveSnapshot(flags);
 
-    if (!currentSnapshot()->isIgnored()) {
+    if (!mState.currentlyIgnored()) {
         createLayer(left, top, right, bottom, paint, flags, convexMask);
     }
 
@@ -643,7 +644,7 @@
     currentTransform()->mapRect(bounds);
 
     // Layers only make sense if they are in the framebuffer's bounds
-    if (bounds.intersect(*currentClipRect())) {
+    if (bounds.intersect(*mState.currentClipRect())) {
         // We cannot work with sub-pixels in this case
         bounds.snapToPixelBoundaries();
 
@@ -677,17 +678,17 @@
     if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
             bounds.getHeight() > mCaches.maxTextureSize ||
             (fboLayer && clip.isEmpty())) {
-        mSnapshot->empty = fboLayer;
+        writableSnapshot()->empty = fboLayer;
     } else {
-        mSnapshot->invisible = mSnapshot->invisible || (alpha <= 0 && fboLayer);
+        writableSnapshot()->invisible = writableSnapshot()->invisible || (alpha <= 0 && fboLayer);
     }
 }
 
 int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
         const SkPaint* paint, int flags) {
-    const int count = saveSnapshot(flags);
+    const int count = mState.saveSnapshot(flags);
 
-    if (!currentSnapshot()->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
+    if (!mState.currentlyIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
         // initialize the snapshot as though it almost represents an FBO layer so deferred draw
         // operations will be able to store and restore the current clip and transform info, and
         // quick rejection will be correct (for display lists)
@@ -697,11 +698,11 @@
         calculateLayerBoundsAndClip(bounds, clip, true);
         updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint));
 
-        if (!currentSnapshot()->isIgnored()) {
-            mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
-            mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
-            mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
-            mSnapshot->roundRectClipState = NULL;
+        if (!mState.currentlyIgnored()) {
+            writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
+            writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
+            writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
+            writableSnapshot()->roundRectClipState = NULL;
         }
     }
 
@@ -773,7 +774,7 @@
     updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint));
 
     // Bail out if we won't draw in this snapshot
-    if (currentSnapshot()->isIgnored()) {
+    if (mState.currentlyIgnored()) {
         return false;
     }
 
@@ -793,8 +794,8 @@
     layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
 
     // Save the layer in the snapshot
-    mSnapshot->flags |= Snapshot::kFlagIsLayer;
-    mSnapshot->layer = layer;
+    writableSnapshot()->flags |= Snapshot::kFlagIsLayer;
+    writableSnapshot()->layer = layer;
 
     ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u",
             fboLayer ? "" : "unclipped ",
@@ -832,13 +833,13 @@
     layer->clipRect.set(clip);
     layer->setFbo(mCaches.fboCache.get());
 
-    mSnapshot->region = &mSnapshot->layer->region;
-    mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
-    mSnapshot->fbo = layer->getFbo();
-    mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
-    mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
-    mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
-    mSnapshot->roundRectClipState = NULL;
+    writableSnapshot()->region = &writableSnapshot()->layer->region;
+    writableSnapshot()->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
+    writableSnapshot()->fbo = layer->getFbo();
+    writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
+    writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
+    writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
+    writableSnapshot()->roundRectClipState = NULL;
 
     endTiling();
     debugOverdraw(false, false);
@@ -885,7 +886,7 @@
     const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;
 
     bool clipRequired = false;
-    calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
+    mState.calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
             &clipRequired, NULL, false); // safely ignore return, should never be rejected
     mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
 
@@ -930,7 +931,7 @@
         save(0);
         // the layer contains screen buffer content that shouldn't be alpha modulated
         // (and any necessary alpha modulation was handled drawing into the layer)
-        mSnapshot->alpha = 1.0f;
+        writableSnapshot()->alpha = 1.0f;
         composeLayerRect(layer, rect, true);
         restore();
     }
@@ -1038,13 +1039,13 @@
  * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
  * by saveLayer's restore
  */
-#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) {                             \
-        DRAW_COMMAND;                                                            \
-        if (CC_UNLIKELY(mCaches.debugOverdraw && getTargetFbo() == 0 && COND)) { \
-            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);                 \
-            DRAW_COMMAND;                                                        \
-            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                     \
-        }                                                                        \
+#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) {                               \
+        DRAW_COMMAND;                                                              \
+        if (CC_UNLIKELY(mCaches.debugOverdraw && onGetTargetFbo() == 0 && COND)) { \
+            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);                   \
+            DRAW_COMMAND;                                                          \
+            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                       \
+        }                                                                          \
     }
 
 #define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
@@ -1273,7 +1274,7 @@
 }
 
 void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
-    if (bounds.intersect(*currentClipRect())) {
+    if (bounds.intersect(*mState.currentClipRect())) {
         bounds.snapToPixelBoundaries();
         android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
         if (!dirty.isEmpty()) {
@@ -1301,7 +1302,7 @@
     const size_t count = mLayers.size();
     if (count == 0) return;
 
-    if (!currentSnapshot()->isIgnored()) {
+    if (!mState.currentlyIgnored()) {
         EVENT_LOGD("clearLayerRegions");
         // Doing several glScissor/glClear here can negatively impact
         // GPUs with a tiler architecture, instead we draw quads with
@@ -1357,7 +1358,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
-    const Rect* currentClip = currentClipRect();
+    const Rect* currentClip = mState.currentClipRect();
     const mat4* currentMatrix = currentTransform();
 
     if (stateDeferFlags & kStateDeferFlag_Draw) {
@@ -1410,12 +1411,12 @@
 
 void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
     setMatrix(state.mMatrix);
-    mSnapshot->alpha = state.mAlpha;
+    writableSnapshot()->alpha = state.mAlpha;
     mDrawModifiers = state.mDrawModifiers;
-    mSnapshot->roundRectClipState = state.mRoundRectClipState;
+    writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
 
     if (state.mClipValid && !skipClipRestore) {
-        mSnapshot->setClip(state.mClip.left, state.mClip.top,
+        writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
                 state.mClip.right, state.mClip.bottom);
         dirtyClip();
     }
@@ -1430,9 +1431,9 @@
  */
 void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
     if (clipRect != NULL) {
-        mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
+        writableSnapshot()->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
     } else {
-        mSnapshot->setClip(0, 0, getWidth(), getHeight());
+        writableSnapshot()->setClip(0, 0, mState.getWidth(), mState.getHeight());
     }
     dirtyClip();
     mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled);
@@ -1443,12 +1444,12 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::setScissorFromClip() {
-    Rect clip(*currentClipRect());
+    Rect clip(*mState.currentClipRect());
     clip.snapToPixelBoundaries();
 
     if (mCaches.setScissor(clip.left, getViewportHeight() - clip.bottom,
             clip.getWidth(), clip.getHeight())) {
-        mDirtyClip = false;
+        mState.setDirtyClip(false);
     }
 }
 
@@ -1484,7 +1485,7 @@
 
             // NOTE: The order here is important, we must set dirtyClip to false
             //       before any draw call to avoid calling back into this method
-            mDirtyClip = false;
+            mState.setDirtyClip(false);
 
             ensureStencilBuffer();
 
@@ -1553,7 +1554,7 @@
 
     bool clipRequired = false;
     bool roundRectClipRequired = false;
-    if (calculateQuickRejectForScissor(left, top, right, bottom,
+    if (mState.calculateQuickRejectForScissor(left, top, right, bottom,
             &clipRequired, &roundRectClipRequired, snapOut)) {
         return true;
     }
@@ -1585,7 +1586,7 @@
     if (clearLayer) clearLayerRegions();
     // Make sure setScissor & setStencil happen at the beginning of
     // this method
-    if (mDirtyClip) {
+    if (mState.getDirtyClip()) {
         if (mCaches.scissorEnabled) {
             setScissorFromClip();
         }
@@ -1723,7 +1724,7 @@
     useProgram(mCaches.programCache.get(mDescription));
     if (mDescription.hasRoundRectClip) {
         // TODO: avoid doing this repeatedly, stashing state pointer in program
-        const RoundRectClipState* state = mSnapshot->roundRectClipState;
+        const RoundRectClipState* state = writableSnapshot()->roundRectClipState;
         const Rect& innerRect = state->innerRect;
         glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"),
                 innerRect.left, innerRect.top,
@@ -1751,7 +1752,7 @@
 
     bool dirty = right - left > 0.0f && bottom - top > 0.0f;
     const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
-    mCaches.currentProgram->set(mSnapshot->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset);
+    mCaches.currentProgram->set(writableSnapshot()->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset);
     if (dirty && mTrackDirtyRegions) {
         if (!ignoreTransform) {
             dirtyLayer(left, top, right, bottom, *currentTransform());
@@ -1942,7 +1943,7 @@
             return;
         }
 
-        DeferredDisplayList deferredList(*currentClipRect());
+        DeferredDisplayList deferredList(*mState.currentClipRect());
         DeferStateStruct deferStruct(deferredList, *this, replayFlags);
         renderNode->defer(deferStruct, 0);
 
@@ -2056,7 +2057,7 @@
 
 void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
         const float* vertices, const int* colors, const SkPaint* paint) {
-    if (!vertices || currentSnapshot()->isIgnored()) {
+    if (!vertices || mState.currentlyIgnored()) {
         return;
     }
 
@@ -2369,7 +2370,7 @@
     setupDraw();
     setupDrawNoTexture();
     if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp));
-    setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
+    setupDrawColor(color, ((color >> 24) & 0xFF) * writableSnapshot()->alpha);
     setupDrawColorFilter(getColorFilter(paint));
     setupDrawShader(getShader(paint));
     setupDrawBlending(paint, isAA);
@@ -2445,7 +2446,7 @@
  * memory transfer by removing need for degenerate vertices.
  */
 void OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
-    if (currentSnapshot()->isIgnored() || count < 4) return;
+    if (mState.currentlyIgnored() || count < 4) return;
 
     count &= ~0x3; // round down to nearest four
 
@@ -2462,7 +2463,7 @@
 }
 
 void OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
-    if (currentSnapshot()->isIgnored() || count < 2) return;
+    if (mState.currentlyIgnored() || count < 2) return;
 
     count &= ~0x1; // round down to nearest two
 
@@ -2482,9 +2483,9 @@
 
 void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
     // No need to check against the clip, we fill the clip region
-    if (currentSnapshot()->isIgnored()) return;
+    if (mState.currentlyIgnored()) return;
 
-    Rect clip(*currentClipRect());
+    Rect clip(*mState.currentClipRect());
     clip.snapToPixelBoundaries();
 
     SkPaint paint;
@@ -2511,7 +2512,7 @@
 
 void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
         float rx, float ry, const SkPaint* p) {
-    if (currentSnapshot()->isIgnored()
+    if (mState.currentlyIgnored()
             || quickRejectSetupScissor(left, top, right, bottom, p)
             || paintWillNotDraw(*p)) {
         return;
@@ -2530,7 +2531,7 @@
 }
 
 void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
-    if (currentSnapshot()->isIgnored()
+    if (mState.currentlyIgnored()
             || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
             || paintWillNotDraw(*p)) {
         return;
@@ -2552,7 +2553,7 @@
 
 void OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
         const SkPaint* p) {
-    if (currentSnapshot()->isIgnored()
+    if (mState.currentlyIgnored()
             || quickRejectSetupScissor(left, top, right, bottom, p)
             || paintWillNotDraw(*p)) {
         return;
@@ -2575,7 +2576,7 @@
 
 void OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
         float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
-    if (currentSnapshot()->isIgnored()
+    if (mState.currentlyIgnored()
             || quickRejectSetupScissor(left, top, right, bottom, p)
             || paintWillNotDraw(*p)) {
         return;
@@ -2610,7 +2611,7 @@
 
 void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
         const SkPaint* p) {
-    if (currentSnapshot()->isIgnored()
+    if (mState.currentlyIgnored()
             || quickRejectSetupScissor(left, top, right, bottom, p)
             || paintWillNotDraw(*p)) {
         return;
@@ -2669,7 +2670,7 @@
     const float sx = x - shadow->left + textShadow.dx;
     const float sy = y - shadow->top + textShadow.dy;
 
-    const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha;
+    const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * writableSnapshot()->alpha;
     if (getShader(paint)) {
         textShadow.color = SK_ColorWHITE;
     }
@@ -2693,13 +2694,13 @@
 }
 
 bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
-    float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
+    float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha;
     return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
 }
 
 void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
         const float* positions, const SkPaint* paint) {
-    if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
+    if (text == NULL || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
         return;
     }
 
@@ -2737,7 +2738,7 @@
     }
     fontRenderer.setTextureFiltering(linearFilter);
 
-    const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
+    const Rect* clip = pureTranslate ? writableSnapshot()->clipRect : &writableSnapshot()->getLocalClip();
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
     const bool hasActiveLayer = hasLayer();
@@ -2777,6 +2778,69 @@
     return true;
 }
 
+int OpenGLRenderer::getSaveCount() const {
+    return mState.getSaveCount();
+}
+
+int OpenGLRenderer::save(int flags) {
+    return mState.save(flags);
+}
+
+void OpenGLRenderer::restore() {
+    return mState.restore();
+}
+
+void OpenGLRenderer::restoreToCount(int saveCount) {
+    return mState.restoreToCount(saveCount);
+}
+
+void OpenGLRenderer::translate(float dx, float dy, float dz) {
+    return mState.translate(dx, dy, dz);
+}
+
+void OpenGLRenderer::rotate(float degrees) {
+    return mState.rotate(degrees);
+}
+
+void OpenGLRenderer::scale(float sx, float sy) {
+    return mState.scale(sx, sy);
+}
+
+void OpenGLRenderer::skew(float sx, float sy) {
+    return mState.skew(sx, sy);
+}
+
+void OpenGLRenderer::setMatrix(const Matrix4& matrix) {
+    mState.setMatrix(matrix);
+}
+
+void OpenGLRenderer::concatMatrix(const Matrix4& matrix) {
+    mState.concatMatrix(matrix);
+}
+
+bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
+    return mState.clipRect(left, top, right, bottom, op);
+}
+
+bool OpenGLRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
+    return mState.clipPath(path, op);
+}
+
+bool OpenGLRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
+    return mState.clipRegion(region, op);
+}
+
+void OpenGLRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
+    mState.setClippingOutline(allocator, outline);
+}
+
+void OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator,
+        const Rect& rect, float radius, bool highPriority) {
+    mState.setClippingRoundRect(allocator, rect, radius, highPriority);
+}
+
+
+
 void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
         const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
         DrawOpMode drawOpMode) {
@@ -2784,7 +2848,7 @@
     if (drawOpMode == kDrawOpMode_Immediate) {
         // The checks for corner-case ignorable text and quick rejection is only done for immediate
         // drawing as ops from DeferredDisplayList are already filtered for these
-        if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint) ||
+        if (text == NULL || count == 0 || mState.currentlyIgnored() || canSkipText(paint) ||
                 quickRejectSetupScissor(bounds)) {
             return;
         }
@@ -2834,7 +2898,7 @@
     fontRenderer.setTextureFiltering(linearFilter);
 
     // TODO: Implement better clipping for scaled/rotated text
-    const Rect* clip = !pureTranslate ? NULL : currentClipRect();
+    const Rect* clip = !pureTranslate ? NULL : mState.currentClipRect();
     Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
     bool status;
@@ -2866,7 +2930,7 @@
 
 void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
         const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
-    if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
+    if (text == NULL || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
         return;
     }
 
@@ -2882,7 +2946,7 @@
     getAlphaAndMode(paint, &alpha, &mode);
     TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
 
-    const Rect* clip = &mSnapshot->getLocalClip();
+    const Rect* clip = &writableSnapshot()->getLocalClip();
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
     const bool hasActiveLayer = hasLayer();
@@ -2899,7 +2963,7 @@
 }
 
 void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
-    if (currentSnapshot()->isIgnored()) return;
+    if (mState.currentlyIgnored()) return;
 
     mCaches.activeTexture(0);
 
@@ -2929,7 +2993,7 @@
     }
 
     bool clipRequired = false;
-    const bool rejected = calculateQuickRejectForScissor(x, y,
+    const bool rejected = mState.calculateQuickRejectForScissor(x, y,
             x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, NULL, false);
 
     if (rejected) {
@@ -3114,7 +3178,7 @@
 }
 
 void OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
-    if (currentSnapshot()->isIgnored()) {
+    if (mState.currentlyIgnored()) {
         return;
     }
 
@@ -3131,7 +3195,7 @@
 
 void OpenGLRenderer::drawShadow(float casterAlpha,
         const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
-    if (currentSnapshot()->isIgnored()) return;
+    if (mState.currentlyIgnored()) return;
 
     // TODO: use quickRejectWithScissor. For now, always force enable scissor.
     mCaches.enableScissor();
@@ -3373,7 +3437,7 @@
 void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
         ProgramDescription& description, bool swapSrcDst) {
 
-    if (mSnapshot->roundRectClipState != NULL /*&& !mSkipOutlineClip*/) {
+    if (writableSnapshot()->roundRectClipState != NULL /*&& !mSkipOutlineClip*/) {
         blend = true;
         mDescription.hasRoundRectClip = true;
     }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 65d6deb..fde9e0f 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -38,13 +38,14 @@
 
 #include <androidfw/ResourceTypes.h>
 
+#include "CanvasState.h"
 #include "Debug.h"
 #include "Extensions.h"
 #include "Matrix.h"
 #include "Program.h"
 #include "Rect.h"
+#include "Renderer.h"
 #include "Snapshot.h"
-#include "StatefulBaseRenderer.h"
 #include "UvMapper.h"
 #include "Vertex.h"
 #include "Caches.h"
@@ -116,7 +117,7 @@
 /**
  * OpenGL Renderer implementation.
  */
-class OpenGLRenderer : public StatefulBaseRenderer {
+class OpenGLRenderer : public Renderer, public CanvasStateClient {
 public:
     OpenGLRenderer(RenderState& renderState);
     virtual ~OpenGLRenderer();
@@ -125,8 +126,10 @@
     void initLight(const Vector3& lightCenter, float lightRadius,
             uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
 
-    virtual void onViewportInitialized();
     virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
+    virtual void prepare(bool opaque) {
+        prepareDirty(0.0f, 0.0f, mState.getWidth(), mState.getHeight(), opaque);
+    }
     virtual bool finish();
 
     virtual void callDrawGLFunction(Functor* functor, Rect& dirty);
@@ -218,20 +221,16 @@
     }
 
     // simple rect clip
-    bool isCurrentClipSimple() {
-        return mSnapshot->clipRegion->isEmpty();
-    }
+    bool isCurrentClipSimple() { return mState.isCurrentClipSimple(); }
 
-    int getViewportWidth() { return currentSnapshot()->getViewportWidth(); }
-    int getViewportHeight() { return currentSnapshot()->getViewportHeight(); }
+    int getViewportWidth() { return mState.getViewportWidth(); }
+    int getViewportHeight() { return mState.getViewportHeight(); }
 
     /**
      * Scales the alpha on the current snapshot. This alpha value will be modulated
      * with other alpha values when drawing primitives.
      */
-    void scaleAlpha(float alpha) {
-        mSnapshot->alpha *= alpha;
-    }
+    void scaleAlpha(float alpha) { mState.scaleAlpha(alpha); }
 
     /**
      * Inserts a named event marker in the stream of GL commands.
@@ -328,11 +327,63 @@
     }
 #endif
 
-    const Vector3& getLightCenter() const { return currentSnapshot()->getRelativeLightCenter(); }
+    const Vector3& getLightCenter() const { return mState.currentLightCenter(); }
     float getLightRadius() const { return mLightRadius; }
     uint8_t getAmbientShadowAlpha() const { return mAmbientShadowAlpha; }
     uint8_t getSpotShadowAlpha() const { return mSpotShadowAlpha; }
 
+    ///////////////////////////////////////////////////////////////////
+    /// State manipulation
+
+    virtual void setViewport(int width, int height) { mState.setViewport(width, height); }
+
+    virtual int getSaveCount() const;
+    virtual int save(int flags);
+    virtual void restore();
+    virtual void restoreToCount(int saveCount);
+
+    virtual void getMatrix(SkMatrix* outMatrix) const { mState.getMatrix(outMatrix); }
+    virtual void setMatrix(const SkMatrix& matrix) { mState.setMatrix(matrix); }
+    virtual void concatMatrix(const SkMatrix& matrix) { mState.concatMatrix(matrix); }
+
+    virtual void translate(float dx, float dy, float dz = 0.0f);
+    virtual void rotate(float degrees);
+    virtual void scale(float sx, float sy);
+    virtual void skew(float sx, float sy);
+
+    void setMatrix(const Matrix4& matrix); // internal only convenience method
+    void concatMatrix(const Matrix4& matrix); // internal only convenience method
+
+    virtual const Rect& getLocalClipBounds() const { return mState.getLocalClipBounds(); }
+    const Rect& getRenderTargetClipBounds() const { return mState.getRenderTargetClipBounds(); }
+    virtual bool quickRejectConservative(float left, float top, float right, float bottom) const {
+        return mState.quickRejectConservative(left, top, right, bottom);
+    }
+
+    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
+    virtual bool clipPath(const SkPath* path, SkRegion::Op op);
+    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
+
+    /**
+     * Does not support different clipping Ops (that is, every call to setClippingOutline is
+     * effectively using SkRegion::kReplaceOp)
+     *
+     * The clipping outline is independent from the regular clip.
+     */
+    void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
+    void setClippingRoundRect(LinearAllocator& allocator,
+            const Rect& rect, float radius, bool highPriority = true);
+
+    inline bool hasRectToRectTransform() const { return mState.hasRectToRectTransform(); }
+    inline const mat4* currentTransform() const { return mState.currentTransform(); }
+
+    ///////////////////////////////////////////////////////////////////
+    /// CanvasStateClient interface
+
+    virtual void onViewportInitialized();
+    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored);
+    virtual GLuint onGetTargetFbo() const { return 0; }
+
 protected:
     /**
      * Perform the setup specific to a frame. This method does not
@@ -396,22 +447,16 @@
      * Returns the region of the current layer.
      */
     virtual Region* getRegion() const {
-        return mSnapshot->region;
+        return mState.currentRegion();
     }
 
     /**
      * Indicates whether rendering is currently targeted at a layer.
      */
     virtual bool hasLayer() const {
-        return (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region;
+        return (mState.currentFlags() & Snapshot::kFlagFboTarget) && mState.currentRegion();
     }
 
-    /**
-     * Returns the name of the FBO this renderer is rendering into.
-     */
-    virtual GLuint getTargetFbo() const {
-        return 0;
-    }
 
     /**
      * Renders the specified layer as a textured quad.
@@ -464,6 +509,8 @@
 
     inline RenderState& renderState() { return mRenderState; }
 
+    CanvasState mState;
+
 private:
     /**
      * Discards the content of the framebuffer if supported by the driver.
@@ -499,8 +546,6 @@
      */
     void endTiling();
 
-    void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored);
-
     /**
      * Sets the clipping rectangle using glScissor. The clip is defined by
      * the current snapshot's clipRect member.
@@ -916,9 +961,7 @@
     /**
      * Should be invoked every time the glScissor is modified.
      */
-    inline void dirtyClip() {
-        mDirtyClip = true;
-    }
+    inline void dirtyClip() { mState.setDirtyClip(true); }
 
     inline const UvMapper& getMapper(const Texture* texture) {
         return texture && texture->uvMapper ? *texture->uvMapper : mUvMapper;
@@ -932,6 +975,8 @@
     Texture* getTexture(const SkBitmap* bitmap);
 
     bool reportAndClearDirty() { bool ret = mDirty; mDirty = false; return ret; }
+    inline Snapshot* writableSnapshot() { return mState.writableSnapshot(); }
+    inline const Snapshot* currentSnapshot() const { return mState.currentSnapshot(); }
 
     /**
      * Model-view matrix used to position/size objects
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
deleted file mode 100644
index 612992f..0000000
--- a/libs/hwui/StatefulBaseRenderer.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_STATEFUL_BASE_RENDERER_H
-#define ANDROID_HWUI_STATEFUL_BASE_RENDERER_H
-
-#include <utils/RefBase.h>
-
-#include "Renderer.h"
-#include "Snapshot.h"
-
-namespace android {
-namespace uirenderer {
-
-/**
- * Abstract Renderer subclass, which implements Canvas state methods.
- *
- * Manages the Snapshot stack, implementing matrix, save/restore, and clipping methods in the
- * Renderer interface. Drawing and recording classes that extend StatefulBaseRenderer will have
- * different use cases:
- *
- * Drawing subclasses (i.e. OpenGLRenderer) can query attributes (such as transform) or hook into
- * changes (e.g. save/restore) with minimal surface area for manipulating the stack itself.
- *
- * Recording subclasses (i.e. DisplayListRenderer) can both record and pass through state operations
- * to StatefulBaseRenderer, so that not only will querying operations work (getClip/Matrix), but so
- * that quickRejection can also be used.
- */
-class StatefulBaseRenderer : public Renderer {
-public:
-    StatefulBaseRenderer();
-
-    virtual void prepare(bool opaque) {
-        prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
-    }
-
-    /**
-     * Initialize the first snapshot, computing the projection matrix, and stores the dimensions of
-     * the render target.
-     */
-    virtual void setViewport(int width, int height);
-    void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom,
-            const Vector3& lightCenter);
-
-    // getters
-    bool hasRectToRectTransform() const {
-        return CC_LIKELY(currentTransform()->rectToRect());
-    }
-
-    // Save (layer)
-    virtual int getSaveCount() const { return mSaveCount; }
-    virtual int save(int flags);
-    virtual void restore();
-    virtual void restoreToCount(int saveCount);
-    //virtual int saveLayer(float left, float top, float right, float bottom,
-    //        int alpha, SkXfermode::Mode mode, int flags);
-
-    // Matrix
-    virtual void getMatrix(SkMatrix* outMatrix) const;
-    virtual void translate(float dx, float dy, float dz = 0.0f);
-    virtual void rotate(float degrees);
-    virtual void scale(float sx, float sy);
-    virtual void skew(float sx, float sy);
-
-    virtual void setMatrix(const SkMatrix& matrix);
-    void setMatrix(const Matrix4& matrix); // internal only convenience method
-    virtual void concatMatrix(const SkMatrix& matrix);
-    void concatMatrix(const Matrix4& matrix); // internal only convenience method
-
-    // Clip
-    virtual const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
-
-    virtual bool quickRejectConservative(float left, float top, float right, float bottom) const;
-
-    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
-    virtual bool clipPath(const SkPath* path, SkRegion::Op op);
-    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
-
-    /**
-     * Does not support different clipping Ops (that is, every call to setClippingOutline is
-     * effectively using SkRegion::kReplaceOp)
-     *
-     * The clipping outline is independent from the regular clip.
-     */
-    void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
-    void setClippingRoundRect(LinearAllocator& allocator,
-            const Rect& rect, float radius, bool highPriority = true);
-
-    inline const mat4* currentTransform() const {
-        return mSnapshot->transform;
-    }
-
-protected:
-    const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
-
-    int getWidth() { return mWidth; }
-    int getHeight() { return mHeight; }
-
-    // Save
-    int saveSnapshot(int flags);
-    void restoreSnapshot();
-
-    // allows subclasses to control what value is stored in snapshot's fbo field in
-    // initializeSaveStack
-    virtual GLuint getTargetFbo() const {
-        return -1;
-    }
-
-    // Clip
-    bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
-            bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const;
-
-    /**
-     * Called just after a restore has occurred. The 'removed' snapshot popped from the stack,
-     * 'restored' snapshot has become the top/current.
-     *
-     * Subclasses can override this method to handle layer restoration
-     */
-    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {};
-
-    virtual void onViewportInitialized() {};
-
-    inline const Rect* currentClipRect() const {
-        return mSnapshot->clipRect;
-    }
-
-    inline const Snapshot* currentSnapshot() const {
-        return mSnapshot != NULL ? mSnapshot.get() : mFirstSnapshot.get();
-    }
-
-    inline const Snapshot* firstSnapshot() const {
-        return mFirstSnapshot.get();
-    }
-
-    // indicites that the clip has been changed since the last time it was consumed
-    bool mDirtyClip;
-
-private:
-    // Dimensions of the drawing surface
-    int mWidth, mHeight;
-
-    // Number of saved states
-    int mSaveCount;
-
-    // Base state
-    sp<Snapshot> mFirstSnapshot;
-
-protected:
-    // Current state
-    // TODO: should become private, once hooks needed by OpenGLRenderer are added
-    sp<Snapshot> mSnapshot;
-}; // class StatefulBaseRenderer
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_STATEFUL_BASE_RENDERER_H