[SurfaceFlinger] Move Transform to libs/ui

A bunch of code in SurfaceFlinger uses Transform, so does RenderEngine. In
order to move RenderEngine to its own library, we need to lift Transform to
another place where it's part of VNDK. Since Transform depends on libs/ui, we
move Transform to libs/ui as well.

BUG: 112585051
Test: Build, flash, boot and check transformation.
Change-Id: Ie4d13ee135ba3f71fcbd9f86994a0b048e2c6878
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index d25ad1a..e3ef2a9 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -65,6 +65,7 @@
         "PixelFormat.cpp",
         "Rect.cpp",
         "Region.cpp",
+        "Transform.cpp",
         "UiConfig.cpp",
     ],
 
diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp
new file mode 100644
index 0000000..8e949ec
--- /dev/null
+++ b/libs/ui/Transform.cpp
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include <math.h>
+
+#include <cutils/compiler.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace ui {
+
+Transform::Transform() {
+    reset();
+}
+
+Transform::Transform(const Transform&  other)
+    : mMatrix(other.mMatrix), mType(other.mType) {
+}
+
+Transform::Transform(uint32_t orientation) {
+    set(orientation, 0, 0);
+}
+
+Transform::~Transform() = default;
+
+static const float EPSILON = 0.0f;
+
+bool Transform::isZero(float f) {
+    return fabs(f) <= EPSILON;
+}
+
+bool Transform::absIsOne(float f) {
+    return isZero(fabs(f) - 1.0f);
+}
+
+Transform Transform::operator * (const Transform& rhs) const
+{
+    if (CC_LIKELY(mType == IDENTITY))
+        return rhs;
+
+    Transform r(*this);
+    if (rhs.mType == IDENTITY)
+        return r;
+
+    // TODO: we could use mType to optimize the matrix multiply
+    const mat33& A(mMatrix);
+    const mat33& B(rhs.mMatrix);
+          mat33& D(r.mMatrix);
+    for (size_t i = 0; i < 3; i++) {
+        const float v0 = A[0][i];
+        const float v1 = A[1][i];
+        const float v2 = A[2][i];
+        D[0][i] = v0*B[0][0] + v1*B[0][1] + v2*B[0][2];
+        D[1][i] = v0*B[1][0] + v1*B[1][1] + v2*B[1][2];
+        D[2][i] = v0*B[2][0] + v1*B[2][1] + v2*B[2][2];
+    }
+    r.mType |= rhs.mType;
+
+    // TODO: we could recompute this value from r and rhs
+    r.mType &= 0xFF;
+    r.mType |= UNKNOWN_TYPE;
+    return r;
+}
+
+Transform& Transform::operator=(const Transform& other) {
+    mMatrix = other.mMatrix;
+    mType = other.mType;
+    return *this;
+}
+
+const vec3& Transform::operator [] (size_t i) const {
+    return mMatrix[i];
+}
+
+float Transform::tx() const {
+    return mMatrix[2][0];
+}
+
+float Transform::ty() const {
+    return mMatrix[2][1];
+}
+
+void Transform::reset() {
+    mType = IDENTITY;
+    for(size_t i = 0; i < 3; i++) {
+        vec3& v(mMatrix[i]);
+        for (size_t j = 0; j < 3; j++)
+            v[j] = ((i == j) ? 1.0f : 0.0f);
+    }
+}
+
+void Transform::set(float tx, float ty)
+{
+    mMatrix[2][0] = tx;
+    mMatrix[2][1] = ty;
+    mMatrix[2][2] = 1.0f;
+
+    if (isZero(tx) && isZero(ty)) {
+        mType &= ~TRANSLATE;
+    } else {
+        mType |= TRANSLATE;
+    }
+}
+
+void Transform::set(float a, float b, float c, float d)
+{
+    mat33& M(mMatrix);
+    M[0][0] = a;    M[1][0] = b;
+    M[0][1] = c;    M[1][1] = d;
+    M[0][2] = 0;    M[1][2] = 0;
+    mType = UNKNOWN_TYPE;
+}
+
+status_t Transform::set(uint32_t flags, float w, float h)
+{
+    if (flags & ROT_INVALID) {
+        // that's not allowed!
+        reset();
+        return BAD_VALUE;
+    }
+
+    Transform H, V, R;
+    if (flags & ROT_90) {
+        // w & h are inverted when rotating by 90 degrees
+        std::swap(w, h);
+    }
+
+    if (flags & FLIP_H) {
+        H.mType = (FLIP_H << 8) | SCALE;
+        H.mType |= isZero(w) ? IDENTITY : TRANSLATE;
+        mat33& M(H.mMatrix);
+        M[0][0] = -1;
+        M[2][0] = w;
+    }
+
+    if (flags & FLIP_V) {
+        V.mType = (FLIP_V << 8) | SCALE;
+        V.mType |= isZero(h) ? IDENTITY : TRANSLATE;
+        mat33& M(V.mMatrix);
+        M[1][1] = -1;
+        M[2][1] = h;
+    }
+
+    if (flags & ROT_90) {
+        const float original_w = h;
+        R.mType = (ROT_90 << 8) | ROTATE;
+        R.mType |= isZero(original_w) ? IDENTITY : TRANSLATE;
+        mat33& M(R.mMatrix);
+        M[0][0] = 0;    M[1][0] =-1;    M[2][0] = original_w;
+        M[0][1] = 1;    M[1][1] = 0;
+    }
+
+    *this = (R*(H*V));
+    return NO_ERROR;
+}
+
+vec2 Transform::transform(const vec2& v) const {
+    vec2 r;
+    const mat33& M(mMatrix);
+    r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0];
+    r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1];
+    return r;
+}
+
+vec3 Transform::transform(const vec3& v) const {
+    vec3 r;
+    const mat33& M(mMatrix);
+    r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]*v[2];
+    r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]*v[2];
+    r[2] = M[0][2]*v[0] + M[1][2]*v[1] + M[2][2]*v[2];
+    return r;
+}
+
+vec2 Transform::transform(int x, int y) const
+{
+    return transform(vec2(x,y));
+}
+
+Rect Transform::makeBounds(int w, int h) const
+{
+    return transform( Rect(w, h) );
+}
+
+Rect Transform::transform(const Rect& bounds, bool roundOutwards) const
+{
+    Rect r;
+    vec2 lt( bounds.left,  bounds.top    );
+    vec2 rt( bounds.right, bounds.top    );
+    vec2 lb( bounds.left,  bounds.bottom );
+    vec2 rb( bounds.right, bounds.bottom );
+
+    lt = transform(lt);
+    rt = transform(rt);
+    lb = transform(lb);
+    rb = transform(rb);
+
+    if (roundOutwards) {
+        r.left   = static_cast<int32_t>(floorf(std::min({lt[0], rt[0], lb[0], rb[0]})));
+        r.top    = static_cast<int32_t>(floorf(std::min({lt[1], rt[1], lb[1], rb[1]})));
+        r.right  = static_cast<int32_t>(ceilf(std::max({lt[0], rt[0], lb[0], rb[0]})));
+        r.bottom = static_cast<int32_t>(ceilf(std::max({lt[1], rt[1], lb[1], rb[1]})));
+    } else {
+        r.left   = static_cast<int32_t>(floorf(std::min({lt[0], rt[0], lb[0], rb[0]}) + 0.5f));
+        r.top    = static_cast<int32_t>(floorf(std::min({lt[1], rt[1], lb[1], rb[1]}) + 0.5f));
+        r.right  = static_cast<int32_t>(floorf(std::max({lt[0], rt[0], lb[0], rb[0]}) + 0.5f));
+        r.bottom = static_cast<int32_t>(floorf(std::max({lt[1], rt[1], lb[1], rb[1]}) + 0.5f));
+    }
+
+    return r;
+}
+
+FloatRect Transform::transform(const FloatRect& bounds) const
+{
+    vec2 lt(bounds.left, bounds.top);
+    vec2 rt(bounds.right, bounds.top);
+    vec2 lb(bounds.left, bounds.bottom);
+    vec2 rb(bounds.right, bounds.bottom);
+
+    lt = transform(lt);
+    rt = transform(rt);
+    lb = transform(lb);
+    rb = transform(rb);
+
+    FloatRect r;
+    r.left = std::min({lt[0], rt[0], lb[0], rb[0]});
+    r.top = std::min({lt[1], rt[1], lb[1], rb[1]});
+    r.right = std::max({lt[0], rt[0], lb[0], rb[0]});
+    r.bottom = std::max({lt[1], rt[1], lb[1], rb[1]});
+
+    return r;
+}
+
+Region Transform::transform(const Region& reg) const
+{
+    Region out;
+    if (CC_UNLIKELY(type() > TRANSLATE)) {
+        if (CC_LIKELY(preserveRects())) {
+            Region::const_iterator it = reg.begin();
+            Region::const_iterator const end = reg.end();
+            while (it != end) {
+                out.orSelf(transform(*it++));
+            }
+        } else {
+            out.set(transform(reg.bounds()));
+        }
+    } else {
+        int xpos = static_cast<int>(floorf(tx() + 0.5f));
+        int ypos = static_cast<int>(floorf(ty() + 0.5f));
+        out = reg.translate(xpos, ypos);
+    }
+    return out;
+}
+
+uint32_t Transform::type() const
+{
+    if (mType & UNKNOWN_TYPE) {
+        // recompute what this transform is
+
+        const mat33& M(mMatrix);
+        const float a = M[0][0];
+        const float b = M[1][0];
+        const float c = M[0][1];
+        const float d = M[1][1];
+        const float x = M[2][0];
+        const float y = M[2][1];
+
+        bool scale = false;
+        uint32_t flags = ROT_0;
+        if (isZero(b) && isZero(c)) {
+            if (a<0)    flags |= FLIP_H;
+            if (d<0)    flags |= FLIP_V;
+            if (!absIsOne(a) || !absIsOne(d)) {
+                scale = true;
+            }
+        } else if (isZero(a) && isZero(d)) {
+            flags |= ROT_90;
+            if (b>0)    flags |= FLIP_V;
+            if (c<0)    flags |= FLIP_H;
+            if (!absIsOne(b) || !absIsOne(c)) {
+                scale = true;
+            }
+        } else {
+            // there is a skew component and/or a non 90 degrees rotation
+            flags = ROT_INVALID;
+        }
+
+        mType = flags << 8;
+        if (flags & ROT_INVALID) {
+            mType |= UNKNOWN;
+        } else {
+            if ((flags & ROT_90) || ((flags & ROT_180) == ROT_180))
+                mType |= ROTATE;
+            if (flags & FLIP_H)
+                mType ^= SCALE;
+            if (flags & FLIP_V)
+                mType ^= SCALE;
+            if (scale)
+                mType |= SCALE;
+        }
+
+        if (!isZero(x) || !isZero(y))
+            mType |= TRANSLATE;
+    }
+    return mType;
+}
+
+Transform Transform::inverse() const {
+    // our 3x3 matrix is always of the form of a 2x2 transformation
+    // followed by a translation: T*M, therefore:
+    // (T*M)^-1 = M^-1 * T^-1
+    Transform result;
+    if (mType <= TRANSLATE) {
+        // 1 0 0
+        // 0 1 0
+        // x y 1
+        result = *this;
+        result.mMatrix[2][0] = -result.mMatrix[2][0];
+        result.mMatrix[2][1] = -result.mMatrix[2][1];
+    } else {
+        // a c 0
+        // b d 0
+        // x y 1
+        const mat33& M(mMatrix);
+        const float a = M[0][0];
+        const float b = M[1][0];
+        const float c = M[0][1];
+        const float d = M[1][1];
+        const float x = M[2][0];
+        const float y = M[2][1];
+
+        const float idet = 1.0f / (a*d - b*c);
+        result.mMatrix[0][0] =  d*idet;
+        result.mMatrix[0][1] = -c*idet;
+        result.mMatrix[1][0] = -b*idet;
+        result.mMatrix[1][1] =  a*idet;
+        result.mType = mType;
+
+        vec2 T(-x, -y);
+        T = result.transform(T);
+        result.mMatrix[2][0] = T[0];
+        result.mMatrix[2][1] = T[1];
+    }
+    return result;
+}
+
+uint32_t Transform::getType() const {
+    return type() & 0xFF;
+}
+
+uint32_t Transform::getOrientation() const
+{
+    return (type() >> 8) & 0xFF;
+}
+
+bool Transform::preserveRects() const
+{
+    return (getOrientation() & ROT_INVALID) ? false : true;
+}
+
+void Transform::dump(const char* name) const
+{
+    type(); // updates the type
+
+    String8 flags, type;
+    const mat33& m(mMatrix);
+    uint32_t orient = mType >> 8;
+
+    if (orient&ROT_INVALID) {
+        flags.append("ROT_INVALID ");
+    } else {
+        if (orient&ROT_90) {
+            flags.append("ROT_90 ");
+        } else {
+            flags.append("ROT_0 ");
+        }
+        if (orient&FLIP_V)
+            flags.append("FLIP_V ");
+        if (orient&FLIP_H)
+            flags.append("FLIP_H ");
+    }
+
+    if (!(mType&(SCALE|ROTATE|TRANSLATE)))
+        type.append("IDENTITY ");
+    if (mType&SCALE)
+        type.append("SCALE ");
+    if (mType&ROTATE)
+        type.append("ROTATE ");
+    if (mType&TRANSLATE)
+        type.append("TRANSLATE ");
+
+    ALOGD("%s 0x%08x (%s, %s)", name, mType, flags.string(), type.string());
+    ALOGD("%.4f  %.4f  %.4f", static_cast<double>(m[0][0]), static_cast<double>(m[1][0]),
+          static_cast<double>(m[2][0]));
+    ALOGD("%.4f  %.4f  %.4f", static_cast<double>(m[0][1]), static_cast<double>(m[1][1]),
+          static_cast<double>(m[2][1]));
+    ALOGD("%.4f  %.4f  %.4f", static_cast<double>(m[0][2]), static_cast<double>(m[1][2]),
+          static_cast<double>(m[2][2]));
+}
+
+}  // namespace ui
+}  // namespace android
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
new file mode 100644
index 0000000..42dca75
--- /dev/null
+++ b/libs/ui/include/ui/Transform.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2007 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_TRANSFORM_H
+#define ANDROID_TRANSFORM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware/hardware.h>
+#include <math/vec2.h>
+#include <math/vec3.h>
+#include <ui/Point.h>
+#include <ui/Rect.h>
+
+namespace android {
+
+class Region;
+
+namespace ui {
+
+class Transform {
+public:
+    Transform();
+    Transform(const Transform&  other);
+    explicit Transform(uint32_t orientation);
+    ~Transform();
+
+    enum orientation_flags {
+        ROT_0   = 0x00000000,
+        FLIP_H  = HAL_TRANSFORM_FLIP_H,
+        FLIP_V  = HAL_TRANSFORM_FLIP_V,
+        ROT_90  = HAL_TRANSFORM_ROT_90,
+        ROT_180 = FLIP_H|FLIP_V,
+        ROT_270 = ROT_180|ROT_90,
+        ROT_INVALID = 0x80
+    };
+
+    enum type_mask : uint32_t {
+        IDENTITY            = 0,
+        TRANSLATE           = 0x1,
+        ROTATE              = 0x2,
+        SCALE               = 0x4,
+        UNKNOWN             = 0x8
+    };
+
+    // query the transform
+    bool        preserveRects() const;
+    uint32_t    getType() const;
+    uint32_t    getOrientation() const;
+
+    const vec3& operator [] (size_t i) const;  // returns column i
+    float   tx() const;
+    float   ty() const;
+
+    // modify the transform
+    void        reset();
+    void        set(float tx, float ty);
+    void        set(float a, float b, float c, float d);
+    status_t    set(uint32_t flags, float w, float h);
+
+    // transform data
+    Rect    makeBounds(int w, int h) const;
+    vec2    transform(int x, int y) const;
+    Region  transform(const Region& reg) const;
+    Rect    transform(const Rect& bounds,
+                      bool roundOutwards = false) const;
+    FloatRect transform(const FloatRect& bounds) const;
+    Transform& operator = (const Transform& other);
+    Transform operator * (const Transform& rhs) const;
+    // assumes the last row is < 0 , 0 , 1 >
+    vec2 transform(const vec2& v) const;
+    vec3 transform(const vec3& v) const;
+
+    Transform inverse() const;
+
+    // for debugging
+    void dump(const char* name) const;
+
+private:
+    struct mat33 {
+        vec3 v[3];
+        inline const vec3& operator [] (size_t i) const { return v[i]; }
+        inline vec3& operator [] (size_t i) { return v[i]; }
+    };
+
+    enum { UNKNOWN_TYPE = 0x80000000 };
+
+    uint32_t type() const;
+    static bool absIsOne(float f);
+    static bool isZero(float f);
+
+    mat33               mMatrix;
+    mutable uint32_t    mType;
+};
+
+}  // namespace ui
+}  // namespace android
+
+#endif /* ANDROID_TRANSFORM_H */