Simplify matrix calculations

 Bug: 13913604

Change-Id: I2c0f85a34e1e520050a5a6131306d6b7c352d827
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 823ae7b..2489c92 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -154,8 +154,8 @@
     } else if (properties().getAnimationMatrix()) {
         renderer.concatMatrix(properties().getAnimationMatrix());
     }
-    if (properties().getMatrixFlags() != 0) {
-        if (properties().getMatrixFlags() == TRANSLATION) {
+    if (properties().hasTransformMatrix()) {
+        if (properties().isTransformTranslateOnly()) {
             renderer.translate(properties().getTranslationX(), properties().getTranslationY());
         } else {
             renderer.concatMatrix(*properties().getTransformMatrix());
@@ -214,8 +214,8 @@
         mat4 anim(*properties().getAnimationMatrix());
         matrix.multiply(anim);
     }
-    if (properties().getMatrixFlags() != 0) {
-        if (properties().getMatrixFlags() == TRANSLATION) {
+    if (properties().hasTransformMatrix()) {
+        if (properties().isTransformTranslateOnly()) {
             matrix.translate(properties().getTranslationX(), properties().getTranslationY(),
                     true3dTransform ? properties().getTranslationZ() : 0.0f);
         } else {
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index e7e7768..08829ef 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -27,6 +27,16 @@
 
 #include "Matrix.h"
 
+/**
+ * Convenience value to check for float values that are close enough to zero to be considered
+ * zero.
+ */
+#define NONZERO_EPSILON .001f
+
+static inline bool is_zero(float value) {
+    return (value >= -NONZERO_EPSILON) || (value <= NONZERO_EPSILON);
+}
+
 namespace android {
 namespace uirenderer {
 
@@ -42,22 +52,18 @@
         , mPivotX(0), mPivotY(0)
         , mLeft(0), mTop(0), mRight(0), mBottom(0)
         , mWidth(0), mHeight(0)
-        , mPrevWidth(-1), mPrevHeight(-1)
         , mPivotExplicitlySet(false)
-        , mMatrixDirty(false)
-        , mMatrixFlags(0)
+        , mMatrixOrPivotDirty(false)
         , mCaching(false) {
 }
 
 RenderProperties::ComputedFields::ComputedFields()
         : mTransformMatrix(NULL)
-        , mTransformMatrix3D(NULL)
         , mClipPath(NULL) {
 }
 
 RenderProperties::ComputedFields::~ComputedFields() {
     delete mTransformMatrix;
-    delete mTransformMatrix3D;
     delete mClipPath;
 }
 
@@ -82,7 +88,7 @@
         updateClipPath();
 
         // Force recalculation of the matrix, since other's dirty bit may be clear
-        mPrimitiveFields.mMatrixDirty = true;
+        mPrimitiveFields.mMatrixOrPivotDirty = true;
         updateMatrix();
     }
     return *this;
@@ -100,8 +106,8 @@
         ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
                 level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
     }
-    if (mPrimitiveFields.mMatrixFlags != 0) {
-        if (mPrimitiveFields.mMatrixFlags == TRANSLATION) {
+    if (hasTransformMatrix()) {
+        if (isTransformTranslateOnly()) {
             ALOGD("%*sTranslate %.2f, %.2f, %.2f",
                     level * 2, "", mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY, mPrimitiveFields.mTranslationZ);
         } else {
@@ -134,52 +140,36 @@
 }
 
 void RenderProperties::updateMatrix() {
-    if (mPrimitiveFields.mMatrixDirty) {
-        // NOTE: mComputedFields.mTransformMatrix won't be up to date if a DisplayList goes from a complex transform
-        // to a pure translate. This is safe because the mPrimitiveFields.matrix isn't read in pure translate cases.
-        if (mPrimitiveFields.mMatrixFlags && mPrimitiveFields.mMatrixFlags != TRANSLATION) {
-            if (!mComputedFields.mTransformMatrix) {
-                // only allocate a mPrimitiveFields.matrix if we have a complex transform
-                mComputedFields.mTransformMatrix = new SkMatrix();
-            }
-            if (!mPrimitiveFields.mPivotExplicitlySet) {
-                if (mPrimitiveFields.mWidth != mPrimitiveFields.mPrevWidth || mPrimitiveFields.mHeight != mPrimitiveFields.mPrevHeight) {
-                    mPrimitiveFields.mPrevWidth = mPrimitiveFields.mWidth;
-                    mPrimitiveFields.mPrevHeight = mPrimitiveFields.mHeight;
-                    mPrimitiveFields.mPivotX = mPrimitiveFields.mPrevWidth / 2.0f;
-                    mPrimitiveFields.mPivotY = mPrimitiveFields.mPrevHeight / 2.0f;
-                }
-            }
-
-            if ((mPrimitiveFields.mMatrixFlags & ROTATION_3D) == 0) {
-                mComputedFields.mTransformMatrix->setTranslate(
-                        mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY);
-                mComputedFields.mTransformMatrix->preRotate(mPrimitiveFields.mRotation,
-                        mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
-                mComputedFields.mTransformMatrix->preScale(
-                        mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY,
-                        mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
-            } else {
-                if (!mComputedFields.mTransformMatrix3D) {
-                    mComputedFields.mTransformMatrix3D = new SkMatrix();
-                }
-                mComputedFields.mTransformMatrix->reset();
-                mComputedFields.mTransformCamera.save();
-                mComputedFields.mTransformMatrix->preScale(
-                        mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY,
-                        mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
-                mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX);
-                mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY);
-                mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation);
-                mComputedFields.mTransformCamera.getMatrix(mComputedFields.mTransformMatrix3D);
-                mComputedFields.mTransformMatrix3D->preTranslate(-mPrimitiveFields.mPivotX, -mPrimitiveFields.mPivotY);
-                mComputedFields.mTransformMatrix3D->postTranslate(mPrimitiveFields.mPivotX + mPrimitiveFields.mTranslationX,
-                        mPrimitiveFields.mPivotY + mPrimitiveFields.mTranslationY);
-                mComputedFields.mTransformMatrix->postConcat(*mComputedFields.mTransformMatrix3D);
-                mComputedFields.mTransformCamera.restore();
-            }
+    if (mPrimitiveFields.mMatrixOrPivotDirty) {
+        if (!mComputedFields.mTransformMatrix) {
+            // only allocate a mPrimitiveFields.matrix if we have a complex transform
+            mComputedFields.mTransformMatrix = new SkMatrix();
         }
-        mPrimitiveFields.mMatrixDirty = false;
+        if (!mPrimitiveFields.mPivotExplicitlySet) {
+            mPrimitiveFields.mPivotX = mPrimitiveFields.mWidth / 2.0f;
+            mPrimitiveFields.mPivotY = mPrimitiveFields.mHeight / 2.0f;
+        }
+        SkMatrix* transform = mComputedFields.mTransformMatrix;
+        transform->reset();
+        if (is_zero(getRotationX()) && is_zero(getRotationY())) {
+            transform->setTranslate(getTranslationX(), getTranslationY());
+            transform->preRotate(getRotation(), getPivotX(), getPivotY());
+            transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
+        } else {
+            SkMatrix transform3D;
+            mComputedFields.mTransformCamera.save();
+            transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
+            mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX);
+            mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY);
+            mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation);
+            mComputedFields.mTransformCamera.getMatrix(&transform3D);
+            transform3D.preTranslate(-getPivotX(), -getPivotY());
+            transform3D.postTranslate(getPivotX() + getTranslationX(),
+                    getPivotY() + getTranslationY());
+            transform->postConcat(transform3D);
+            mComputedFields.mTransformCamera.restore();
+        }
+        mPrimitiveFields.mMatrixOrPivotDirty = false;
     }
 }
 
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index dd68210..4270da2 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -28,12 +28,6 @@
 #include "RevealClip.h"
 #include "Outline.h"
 
-#define TRANSLATION 0x0001
-#define ROTATION    0x0002
-#define ROTATION_3D 0x0004
-#define SCALE       0x0008
-#define PIVOT       0x0010
-
 class SkBitmap;
 class SkPaint;
 
@@ -114,7 +108,7 @@
     void setTranslationX(float translationX) {
         if (translationX != mPrimitiveFields.mTranslationX) {
             mPrimitiveFields.mTranslationX = translationX;
-            onTranslationUpdate();
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -125,7 +119,7 @@
     void setTranslationY(float translationY) {
         if (translationY != mPrimitiveFields.mTranslationY) {
             mPrimitiveFields.mTranslationY = translationY;
-            onTranslationUpdate();
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -136,7 +130,7 @@
     void setTranslationZ(float translationZ) {
         if (translationZ != mPrimitiveFields.mTranslationZ) {
             mPrimitiveFields.mTranslationZ = translationZ;
-            onTranslationUpdate();
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -147,12 +141,7 @@
     void setRotation(float rotation) {
         if (rotation != mPrimitiveFields.mRotation) {
             mPrimitiveFields.mRotation = rotation;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mRotation == 0.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~ROTATION;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= ROTATION;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -163,12 +152,7 @@
     void setRotationX(float rotationX) {
         if (rotationX != mPrimitiveFields.mRotationX) {
             mPrimitiveFields.mRotationX = rotationX;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mRotationX == 0.0f && mPrimitiveFields.mRotationY == 0.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~ROTATION_3D;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= ROTATION_3D;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -179,12 +163,7 @@
     void setRotationY(float rotationY) {
         if (rotationY != mPrimitiveFields.mRotationY) {
             mPrimitiveFields.mRotationY = rotationY;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mRotationX == 0.0f && mPrimitiveFields.mRotationY == 0.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~ROTATION_3D;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= ROTATION_3D;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -195,12 +174,7 @@
     void setScaleX(float scaleX) {
         if (scaleX != mPrimitiveFields.mScaleX) {
             mPrimitiveFields.mScaleX = scaleX;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mScaleX == 1.0f && mPrimitiveFields.mScaleY == 1.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~SCALE;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= SCALE;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -211,12 +185,7 @@
     void setScaleY(float scaleY) {
         if (scaleY != mPrimitiveFields.mScaleY) {
             mPrimitiveFields.mScaleY = scaleY;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mScaleX == 1.0f && mPrimitiveFields.mScaleY == 1.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~SCALE;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= SCALE;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -226,12 +195,7 @@
 
     void setPivotX(float pivotX) {
         mPrimitiveFields.mPivotX = pivotX;
-        mPrimitiveFields.mMatrixDirty = true;
-        if (mPrimitiveFields.mPivotX == 0.0f && mPrimitiveFields.mPivotY == 0.0f) {
-            mPrimitiveFields.mMatrixFlags &= ~PIVOT;
-        } else {
-            mPrimitiveFields.mMatrixFlags |= PIVOT;
-        }
+        mPrimitiveFields.mMatrixOrPivotDirty = true;
         mPrimitiveFields.mPivotExplicitlySet = true;
     }
 
@@ -245,12 +209,7 @@
 
     void setPivotY(float pivotY) {
         mPrimitiveFields.mPivotY = pivotY;
-        mPrimitiveFields.mMatrixDirty = true;
-        if (mPrimitiveFields.mPivotX == 0.0f && mPrimitiveFields.mPivotY == 0.0f) {
-            mPrimitiveFields.mMatrixFlags &= ~PIVOT;
-        } else {
-            mPrimitiveFields.mMatrixFlags |= PIVOT;
-        }
+        mPrimitiveFields.mMatrixOrPivotDirty = true;
         mPrimitiveFields.mPivotExplicitlySet = true;
     }
 
@@ -264,7 +223,7 @@
 
     void setCameraDistance(float distance) {
         if (distance != getCameraDistance()) {
-            mPrimitiveFields.mMatrixDirty = true;
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
             mComputedFields.mTransformCamera.setCameraLocation(0, 0, distance);
         }
     }
@@ -278,8 +237,8 @@
         if (left != mPrimitiveFields.mLeft) {
             mPrimitiveFields.mLeft = left;
             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -292,8 +251,8 @@
         if (top != mPrimitiveFields.mTop) {
             mPrimitiveFields.mTop = top;
             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -306,8 +265,8 @@
         if (right != mPrimitiveFields.mRight) {
             mPrimitiveFields.mRight = right;
             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -320,8 +279,8 @@
         if (bottom != mPrimitiveFields.mBottom) {
             mPrimitiveFields.mBottom = bottom;
             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -336,8 +295,8 @@
             mPrimitiveFields.mTop = top;
             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -350,8 +309,8 @@
             mPrimitiveFields.mBottom = bottom;
             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -360,8 +319,8 @@
         if (offset != 0) {
             mPrimitiveFields.mLeft += offset;
             mPrimitiveFields.mRight += offset;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -370,8 +329,8 @@
         if (offset != 0) {
             mPrimitiveFields.mTop += offset;
             mPrimitiveFields.mBottom += offset;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -392,11 +351,17 @@
         return mAnimationMatrix;
     }
 
-    uint32_t getMatrixFlags() const {
-        return mPrimitiveFields.mMatrixFlags;
+    bool hasTransformMatrix() const {
+        return getTransformMatrix() && !getTransformMatrix()->isIdentity();
+    }
+
+    // May only call this if hasTransformMatrix() is true
+    bool isTransformTranslateOnly() const {
+        return getTransformMatrix()->getType() == SkMatrix::kTranslate_Mask;
     }
 
     const SkMatrix* getTransformMatrix() const {
+        LOG_ALWAYS_FATAL_IF(mPrimitiveFields.mMatrixOrPivotDirty, "Cannot get a dirty matrix!");
         return mComputedFields.mTransformMatrix;
     }
 
@@ -452,14 +417,6 @@
     }
 
 private:
-    void onTranslationUpdate() {
-        mPrimitiveFields.mMatrixDirty = true;
-        if (mPrimitiveFields.mTranslationX == 0.0f && mPrimitiveFields.mTranslationY == 0.0f && mPrimitiveFields.mTranslationZ == 0.0f) {
-            mPrimitiveFields.mMatrixFlags &= ~TRANSLATION;
-        } else {
-            mPrimitiveFields.mMatrixFlags |= TRANSLATION;
-        }
-    }
 
     // Rendering properties
     struct PrimitiveFields {
@@ -478,10 +435,8 @@
         float mPivotX, mPivotY;
         int mLeft, mTop, mRight, mBottom;
         int mWidth, mHeight;
-        int mPrevWidth, mPrevHeight;
         bool mPivotExplicitlySet;
-        bool mMatrixDirty;
-        uint32_t mMatrixFlags;
+        bool mMatrixOrPivotDirty;
         bool mCaching;
     } mPrimitiveFields;
 
@@ -506,7 +461,6 @@
         SkMatrix* mTransformMatrix;
 
         Sk3DView mTransformCamera;
-        SkMatrix* mTransformMatrix3D;
         SkPath* mClipPath; // TODO: remove this, create new ops for efficient/special case clipping
         SkRegion::Op mClipPathOp;
     } mComputedFields;