Add support for Canvas flags on save.

This is required for the rewrite of layers support.

Change-Id: I5c0867dcf5aeb0392c8d0fbab05febb0eaff70d9
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 65cb182..11a5d69 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -320,7 +320,7 @@
 
     @Override
     public int save() {
-        return nSave(mRenderer, 0);
+        return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG);
     }
     
     @Override
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 02f5dc5..47ab355 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -127,7 +127,8 @@
 }
 
 void OpenGLRenderer::prepare() {
-    mSnapshot = new Snapshot(mFirstSnapshot);
+    mSnapshot = new Snapshot(mFirstSnapshot,
+            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     mSaveCount = 1;
 
     glViewport(0, 0, mWidth, mHeight);
@@ -175,7 +176,7 @@
 }
 
 int OpenGLRenderer::save(int flags) {
-    return saveSnapshot();
+    return saveSnapshot(flags);
 }
 
 void OpenGLRenderer::restore() {
@@ -192,8 +193,8 @@
     }
 }
 
-int OpenGLRenderer::saveSnapshot() {
-    mSnapshot = new Snapshot(mSnapshot);
+int OpenGLRenderer::saveSnapshot(int flags) {
+    mSnapshot = new Snapshot(mSnapshot, flags);
     return mSaveCount++;
 }
 
@@ -231,7 +232,7 @@
 
 int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
         const SkPaint* p, int flags) {
-    int count = saveSnapshot();
+    int count = saveSnapshot(flags);
 
     int alpha = 255;
     SkXfermode::Mode mode;
@@ -258,13 +259,13 @@
 
 int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
         int alpha, int flags) {
-    int count = saveSnapshot();
-    if (alpha > 0 && !mSnapshot->invisible) {
-        createLayer(mSnapshot, left, top, right, bottom, alpha, SkXfermode::kSrcOver_Mode, flags);
+    if (alpha == 0xff) {
+        return saveLayer(left, top, right, bottom, NULL, flags);
     } else {
-        mSnapshot->invisible = true;
+        SkPaint paint;
+        paint.setAlpha(alpha);
+        return saveLayer(left, top, right, bottom, &paint, flags);
     }
-    return count;
 }
 
 bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
@@ -272,8 +273,12 @@
     LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top);
     LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
 
+    Rect bounds(left, top, right, bottom);
+    // TODO: Apply transformations and treat layers in screen coordinates
+    // mSnapshot->transform->mapRect(bounds);
+
     GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0;
-    LayerSize size(right - left, bottom - top);
+    LayerSize size(bounds.getWidth(), bounds.getHeight());
 
     Layer* layer = mCaches.layerCache.get(size, previousFbo);
     if (!layer) {
@@ -290,24 +295,26 @@
 
     layer->mode = mode;
     layer->alpha = alpha / 255.0f;
-    layer->layer.set(left, top, right, bottom);
+    layer->layer.set(bounds);
 
     // Save the layer in the snapshot
     snapshot->flags |= Snapshot::kFlagIsLayer;
     snapshot->layer = layer;
     snapshot->fbo = layer->fbo;
-    snapshot->transform.loadTranslate(-left, -top, 0.0f);
-    snapshot->setClip(0.0f, 0.0f, right - left, bottom - top);
-    snapshot->viewport.set(0.0f, 0.0f, right - left, bottom - top);
-    snapshot->height = bottom - top;
+    // TODO: Temporary until real layer support is implemented
+    snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
+    // TODO: Temporary until real layer support is implemented
+    snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
+    snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
+    snapshot->height = bounds.getHeight();
     snapshot->flags |= Snapshot::kFlagDirtyOrtho;
     snapshot->orthoMatrix.load(mOrthoMatrix);
 
     setScissorFromClip();
 
     // Change the ortho projection
-    glViewport(0, 0, right - left, bottom - top);
-    mOrthoMatrix.loadOrtho(0.0f, right - left, bottom - top, 0.0f, -1.0f, 1.0f);
+    glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
+    mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
 
     return true;
 }
@@ -323,8 +330,8 @@
     glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
 
     // Restore the clip from the previous snapshot
-    const Rect& clip = previous->clipRect;
-    glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight());
+    const Rect& clip = *previous->clipRect;
+    glScissor(clip.left, previous->height - clip.bottom, clip.getWidth(), clip.getHeight());
 
     Layer* layer = current->layer;
     const Rect& rect = layer->layer;
@@ -355,28 +362,28 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::translate(float dx, float dy) {
-    mSnapshot->transform.translate(dx, dy, 0.0f);
+    mSnapshot->transform->translate(dx, dy, 0.0f);
 }
 
 void OpenGLRenderer::rotate(float degrees) {
-    mSnapshot->transform.rotate(degrees, 0.0f, 0.0f, 1.0f);
+    mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
 }
 
 void OpenGLRenderer::scale(float sx, float sy) {
-    mSnapshot->transform.scale(sx, sy, 1.0f);
+    mSnapshot->transform->scale(sx, sy, 1.0f);
 }
 
 void OpenGLRenderer::setMatrix(SkMatrix* matrix) {
-    mSnapshot->transform.load(*matrix);
+    mSnapshot->transform->load(*matrix);
 }
 
 void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
-    mSnapshot->transform.copyTo(*matrix);
+    mSnapshot->transform->copyTo(*matrix);
 }
 
 void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
     mat4 m(*matrix);
-    mSnapshot->transform.multiply(m);
+    mSnapshot->transform->multiply(m);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -384,7 +391,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::setScissorFromClip() {
-    const Rect& clip = mSnapshot->clipRect;
+    const Rect& clip = *mSnapshot->clipRect;
     glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight());
 }
 
@@ -396,8 +403,8 @@
     if (mSnapshot->invisible) return true;
 
     Rect r(left, top, right, bottom);
-    mSnapshot->transform.mapRect(r);
-    return !mSnapshot->clipRect.intersects(r);
+    mSnapshot->transform->mapRect(r);
+    return !mSnapshot->clipRect->intersects(r);
 }
 
 bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
@@ -405,7 +412,7 @@
     if (clipped) {
         setScissorFromClip();
     }
-    return !mSnapshot->clipRect.isEmpty();
+    return !mSnapshot->clipRect->isEmpty();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -501,7 +508,7 @@
 
 void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
     if (mSnapshot->invisible) return;
-    const Rect& clip = mSnapshot->clipRect;
+    const Rect& clip = *mSnapshot->clipRect;
     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
 }
 
@@ -538,7 +545,7 @@
     float scaleX = paint->getTextScaleX();
     bool applyScaleX = scaleX < 0.9999f || scaleX > 1.0001f;
     if (applyScaleX) {
-        save(0);
+        save(SkCanvas::kMatrix_SaveFlag);
         translate(x - (x * scaleX), 0.0f);
         scale(scaleX, 1.0f);
     }
@@ -747,7 +754,7 @@
      } else {
          mModelView.loadIdentity();
      }
-     mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+     mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
      glUniform4f(mCaches.currentProgram->color, r, g, b, a);
 
      textureUnit++;
@@ -852,7 +859,7 @@
     mModelView.loadTranslate(left, top, 0.0f);
     mModelView.scale(right - left, bottom - top, 1.0f);
     if (!ignoreTransform) {
-        mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+        mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
     } else {
         mat4 identity;
         mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity);
@@ -900,7 +907,7 @@
     mModelView.scale(right - left, bottom - top, 1.0f);
 
     useProgram(mCaches.programCache.get(description));
-    mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+    mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
 
     chooseBlending(blend || alpha < 1.0f, mode);
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index d0e04b2..0e90d20 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -108,9 +108,11 @@
      * The new snapshot is saved in mSnapshot and the previous snapshot
      * is linked from mSnapshot->previous.
      *
+     * @param flags The save flags; see SkCanvas for more information
+     *
      * @return The new save count. This value can be passed to #restoreToCount()
      */
-    int saveSnapshot();
+    int saveSnapshot(int flags);
 
     /**
      * Restores the current snapshot; mSnapshot becomes mSnapshot->previous.
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 7be0c340..6b22c2b 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -91,11 +91,11 @@
         set(r.left, r.top, r.right, r.bottom);
     }
 
-    float getWidth() const {
+    inline float getWidth() const {
         return right - left;
     }
 
-    float getHeight() const {
+    inline float getHeight() const {
         return bottom - top;
     }
 
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index c7a01b1..a5e0f78 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -167,12 +167,12 @@
         shaderMatrix.mapPoint(start.left, start.top);
         shaderMatrix.mapPoint(start.right, start.bottom);
     }
-    snapshot.transform.mapRect(start);
+    snapshot.transform->mapRect(start);
 
     const float gradientX = start.right - start.left;
     const float gradientY = start.bottom - start.top;
 
-    mat4 screenSpace(snapshot.transform);
+    mat4 screenSpace(*snapshot.transform);
     screenSpace.multiply(modelView);
 
     // Uniforms
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 97e7cae..da48243 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -22,6 +22,7 @@
 
 #include <utils/RefBase.h>
 
+#include <SkCanvas.h>
 #include <SkRegion.h>
 
 #include "Layer.h"
@@ -42,27 +43,40 @@
  */
 class Snapshot: public LightRefBase<Snapshot> {
 public:
-    Snapshot(): invisible(false), flags(0), previous(NULL), layer(NULL), fbo(0) { }
+    Snapshot(): invisible(false), flags(0), previous(NULL), layer(NULL), fbo(0) {
+        transform = &mTransformRoot;
+        clipRect = &mClipRectRoot;
+    }
 
     /**
-     * Copies the specified snapshot. Only the transform and clip rectangle
-     * are copied. The layer information is set to 0 and the transform is
-     * assumed to be dirty. The specified snapshot is stored as the previous
-     * snapshot.
+     * Copies the specified snapshot/ The specified snapshot is stored as
+     * the previous snapshot.
      */
-    Snapshot(const sp<Snapshot>& s):
+    Snapshot(const sp<Snapshot>& s, int saveFlags):
             height(s->height),
-            transform(s->transform),
-            clipRect(s->clipRect),
             invisible(s->invisible),
             flags(0),
             previous(s),
             layer(NULL),
             fbo(s->fbo),
             viewport(s->viewport) {
+        if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
+            mTransformRoot.load(*s->transform);
+            transform = &mTransformRoot;
+        } else {
+            transform = s->transform;
+        }
+
+        if (saveFlags & SkCanvas::kClip_SaveFlag) {
+            mClipRectRoot.set(*s->clipRect);
+            clipRect = &mClipRectRoot;
+        } else {
+            clipRect = s->clipRect;
+        }
+
         if ((s->flags & Snapshot::kFlagClipSet) &&
                 !(s->flags & Snapshot::kFlagDirtyLocalClip)) {
-            localClip.set(s->localClip);
+            mLocalClip.set(s->mLocalClip);
         } else {
             flags |= Snapshot::kFlagDirtyLocalClip;
         }
@@ -99,23 +113,23 @@
         bool clipped = false;
 
         Rect r(left, top, right, bottom);
-        transform.mapRect(r);
+        transform->mapRect(r);
 
         switch (op) {
             case SkRegion::kDifference_Op:
                 break;
             case SkRegion::kIntersect_Op:
-                clipped = clipRect.intersect(r);
+                clipped = clipRect->intersect(r);
                 break;
             case SkRegion::kUnion_Op:
-                clipped = clipRect.unionWith(r);
+                clipped = clipRect->unionWith(r);
                 break;
             case SkRegion::kXOR_Op:
                 break;
             case SkRegion::kReverseDifference_Op:
                 break;
             case SkRegion::kReplace_Op:
-                clipRect.set(r);
+                clipRect->set(r);
                 clipped = true;
                 break;
         }
@@ -131,21 +145,34 @@
      * Sets the current clip.
      */
     void setClip(float left, float top, float right, float bottom) {
-        clipRect.set(left, top, right, bottom);
+        clipRect->set(left, top, right, bottom);
         flags |= Snapshot::kFlagClipSet | Snapshot::kFlagDirtyLocalClip;
     }
 
     const Rect& getLocalClip() {
         if (flags & Snapshot::kFlagDirtyLocalClip) {
             mat4 inverse;
-            inverse.loadInverse(transform);
+            inverse.loadInverse(*transform);
 
-            localClip.set(clipRect);
-            inverse.mapRect(localClip);
+            mLocalClip.set(*clipRect);
+            inverse.mapRect(mLocalClip);
 
             flags &= ~Snapshot::kFlagDirtyLocalClip;
         }
-        return localClip;
+        return mLocalClip;
+    }
+
+    // TODO: Temporary
+    void resetTransform(float x, float y, float z) {
+        transform = &mTransformRoot;
+        transform->loadTranslate(x, y, z);
+    }
+
+    // TODO: Temporary
+    void resetClip(float left, float top, float right, float bottom) {
+        clipRect = &mClipRectRoot;
+        clipRect->set(left, top, right, bottom);
+        flags |= Snapshot::kFlagClipSet | Snapshot::kFlagDirtyLocalClip;
     }
 
     /**
@@ -154,18 +181,6 @@
     int height;
 
     /**
-     * Local transformation. Holds the current translation, scale and
-     * rotation values.
-     */
-    mat4 transform;
-
-    /**
-     * Current clip region. The clip is stored in canvas-space coordinates,
-     * (screen-space coordinates in the regular case.)
-     */
-    Rect clipRect;
-
-    /**
      * If true, the layer won't be rendered.
      */
     bool invisible;
@@ -196,8 +211,22 @@
      */
     mat4 orthoMatrix;
 
+    /**
+     * Local transformation. Holds the current translation, scale and
+     * rotation values.
+     */
+    mat4* transform;
+
+    /**
+     * Current clip region. The clip is stored in canvas-space coordinates,
+     * (screen-space coordinates in the regular case.)
+     */
+    Rect* clipRect;
+
 private:
-    Rect localClip;
+    mat4 mTransformRoot;
+    Rect mClipRectRoot;
+    Rect mLocalClip;
 
 }; // class Snapshot