Optimize 9patch rendering.

This change detects empty quads in 9patches and removes them from
the mesh to avoid unnecessary blending.

Change-Id: I4500566fb4cb6845d64dcb59b522c0be7a0ec704
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 2001919..dfa614c 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -257,8 +257,9 @@
     Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(storage);
     Res_png_9patch::deserialize(patch);
 
-    renderer->drawPatch(bitmap, &patch->xDivs[0], &patch->yDivs[0],
-            patch->numXDivs, patch->numYDivs, left, top, right, bottom, paint);
+    renderer->drawPatch(bitmap, &patch->xDivs[0], &patch->yDivs[0], &patch->colors[0],
+            patch->numXDivs, patch->numYDivs, patch->numColors,
+            left, top, right, bottom, paint);
 
     env->ReleaseByteArrayElements(chunks, storage, 0);
 }
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index df6feba..6de4d84 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -86,7 +86,7 @@
                        mPaint != null ? mPaint.mNativePaint : 0,
                        canvas.mDensity, mBitmap.mDensity);
         } else {
-            canvas.drawPatch(mBitmap, mChunk, location, null);
+            canvas.drawPatch(mBitmap, mChunk, location, mPaint);
         }
     }
     
@@ -104,7 +104,7 @@
                         canvas.mDensity, mBitmap.mDensity);
         } else {
             mRect.set(location);
-            canvas.drawPatch(mBitmap, mChunk, mRect, null);
+            canvas.drawPatch(mBitmap, mChunk, mRect, mPaint);
         }
     }
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 61e5408..b3517c4 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -236,16 +236,19 @@
             case DrawPatch: {
                 int32_t* xDivs = NULL;
                 int32_t* yDivs = NULL;
+                uint32_t* colors = NULL;
                 uint32_t xDivsCount = 0;
                 uint32_t yDivsCount = 0;
+                int8_t numColors = 0;
 
                 SkBitmap* bitmap = getBitmap();
 
                 xDivs = getInts(xDivsCount);
                 yDivs = getInts(yDivsCount);
+                colors = getUInts(numColors);
 
-                renderer.drawPatch(bitmap, xDivs, yDivs, xDivsCount, yDivsCount,
-                        getFloat(), getFloat(), getFloat(), getFloat(), getPaint());
+                renderer.drawPatch(bitmap, xDivs, yDivs, colors, xDivsCount, yDivsCount,
+                        numColors, getFloat(), getFloat(), getFloat(), getFloat(), getPaint());
             }
             break;
             case DrawColor: {
@@ -450,12 +453,13 @@
 }
 
 void DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-        uint32_t width, uint32_t height, float left, float top, float right, float bottom,
-        const SkPaint* paint) {
+        const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
+        float left, float top, float right, float bottom, const SkPaint* paint) {
     addOp(DisplayList::DrawPatch);
     addBitmap(bitmap);
     addInts(xDivs, width);
     addInts(yDivs, height);
+    addUInts(colors, numColors);
     addBounds(left, top, right, bottom);
     addPaint(paint);
 }
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 0fbfce1..9e6d5b1 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -169,6 +169,11 @@
         return (int32_t*) mReader.skip(count * sizeof(int32_t));
     }
 
+    uint32_t* getUInts(int8_t& count) {
+        count = getInt();
+        return (uint32_t*) mReader.skip(count * sizeof(uint32_t));
+    }
+
     float* getFloats(int& count) {
         count = getInt();
         return (float*) mReader.skip(count * sizeof(float));
@@ -236,8 +241,8 @@
             float srcRight, float srcBottom, float dstLeft, float dstTop,
             float dstRight, float dstBottom, const SkPaint* paint);
     void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-            uint32_t width, uint32_t height, float left, float top, float right, float bottom,
-            const SkPaint* paint);
+            const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
+            float left, float top, float right, float bottom, const SkPaint* paint);
     void drawColor(int color, SkXfermode::Mode mode);
     void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
     void drawPath(SkPath* path, SkPaint* paint);
@@ -291,6 +296,13 @@
         }
     }
 
+    void addUInts(const uint32_t* values, int8_t count) {
+        mWriter.writeInt(count);
+        for (int8_t i = 0; i < count; i++) {
+            mWriter.writeInt(values[i]);
+        }
+    }
+
     inline void addFloat(float value) {
         mWriter.writeScalar(value);
     }
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 219fd5e..5502e66 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -24,6 +24,7 @@
 
 #include <SkMatrix.h>
 
+#include "utils/Compare.h"
 #include "Matrix.h"
 
 namespace android {
@@ -53,9 +54,6 @@
     mSimpleMatrix = true;
 }
 
-#define EPSILON 0.00001f
-#define almost(u, v) (fabs((u) - (v)) < EPSILON)
-
 bool Matrix4::changesBounds() {
     return !(almost(data[0], 1.0f) && almost(data[1], 0.0f) && almost(data[2], 0.0f) &&
              almost(data[4], 0.0f) && almost(data[5], 1.0f) && almost(data[6], 0.0f) &&
diff --git a/libs/hwui/OpenGLDebugRenderer.cpp b/libs/hwui/OpenGLDebugRenderer.cpp
index b9583e5..d492e23 100644
--- a/libs/hwui/OpenGLDebugRenderer.cpp
+++ b/libs/hwui/OpenGLDebugRenderer.cpp
@@ -72,11 +72,11 @@
 }
 
 void OpenGLDebugRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-        uint32_t width, uint32_t height, float left, float top, float right, float bottom,
-        const SkPaint* paint) {
+        const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
+        float left, float top, float right, float bottom, const SkPaint* paint) {
     mPrimitivesCount++;
     StopWatch w("drawPatch");
-    OpenGLRenderer::drawPatch(bitmap, xDivs, yDivs, width, height,
+    OpenGLRenderer::drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors,
             left, top, right, bottom, paint);
 }
 
diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h
index 2ac19ae..4997ef3 100644
--- a/libs/hwui/OpenGLDebugRenderer.h
+++ b/libs/hwui/OpenGLDebugRenderer.h
@@ -46,8 +46,8 @@
             float srcRight, float srcBottom, float dstLeft, float dstTop,
             float dstRight, float dstBottom, const SkPaint* paint);
     void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-            uint32_t width, uint32_t height, float left, float top, float right, float bottom,
-            const SkPaint* paint);
+            const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
+            float left, float top, float right, float bottom, const SkPaint* paint);
     void drawColor(int color, SkXfermode::Mode mode);
     void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
     void drawPath(SkPath* path, SkPaint* paint);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index cb23680..e965e61 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -689,8 +689,8 @@
 }
 
 void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-        uint32_t width, uint32_t height, float left, float top, float right, float bottom,
-        const SkPaint* paint) {
+        const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
+        float left, float top, float right, float bottom, const SkPaint* paint) {
     if (quickReject(left, top, right, bottom)) {
         return;
     }
@@ -705,7 +705,7 @@
     getAlphaAndMode(paint, &alpha, &mode);
 
     const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(),
-            right - left, bottom - top, xDivs, yDivs, width, height);
+            right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
 
     // Specify right and bottom as +1.0f from left/top to prevent scaling since the
     // patch mesh already defines the final size
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 4caa8fb..9900a27 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -101,8 +101,8 @@
             float srcRight, float srcBottom, float dstLeft, float dstTop,
             float dstRight, float dstBottom, const SkPaint* paint);
     virtual void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-            uint32_t width, uint32_t height, float left, float top, float right, float bottom,
-            const SkPaint* paint);
+            const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
+            float left, float top, float right, float bottom, const SkPaint* paint);
     virtual void drawColor(int color, SkXfermode::Mode mode);
     virtual void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
     virtual void drawPath(SkPath* path, SkPaint* paint);
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index ca0a0b1..560decf 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -18,6 +18,8 @@
 
 #include <cmath>
 
+#include <utils/Log.h>
+
 #include "Patch.h"
 
 namespace android {
@@ -27,9 +29,9 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-Patch::Patch(const uint32_t xCount, const uint32_t yCount) {
+Patch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads) {
     // 2 triangles per patch, 3 vertices per triangle
-    verticesCount = (xCount + 1) * (yCount + 1) * 2 * 3;
+    verticesCount = ((xCount + 1) * (yCount + 1) - emptyQuads) * 2 * 3;
     vertices = new TextureVertex[verticesCount];
 }
 
@@ -43,7 +45,8 @@
 
 void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
         float left, float top, float right, float bottom,
-        const int32_t* xDivs, const int32_t* yDivs, const uint32_t width, const uint32_t height) {
+        const int32_t* xDivs, const int32_t* yDivs,
+        const uint32_t width, const uint32_t height, const uint32_t colorKey) {
     const uint32_t xStretchCount = (width + 1) >> 1;
     const uint32_t yStretchCount = (height + 1) >> 1;
 
@@ -75,6 +78,7 @@
     }
 
     TextureVertex* vertex = vertices;
+    uint32_t quadCount = 0;
 
     float previousStepY = 0.0f;
 
@@ -94,7 +98,7 @@
         float v2 = fmax(0.0f, stepY - 0.5f) / bitmapHeight;
 
         generateRow(vertex, y1, y2, v1, v2, xDivs, width, stretchX,
-                right - left, bitmapWidth);
+                right - left, bitmapWidth, quadCount, colorKey);
 
         y1 = y2;
         v1 = (stepY + 0.5f) / bitmapHeight;
@@ -103,11 +107,12 @@
     }
 
     generateRow(vertex, y1, bottom - top, v1, 1.0f, xDivs, width, stretchX,
-            right - left, bitmapWidth);
+            right - left, bitmapWidth, quadCount, colorKey);
 }
 
 inline void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2,
-        const int32_t xDivs[], uint32_t xCount, float stretchX, float width, float bitmapWidth) {
+        const int32_t xDivs[], uint32_t xCount, float stretchX, float width, float bitmapWidth,
+        uint32_t& quadCount, const uint32_t colorKey) {
     float previousStepX = 0.0f;
 
     float x1 = 0.0f;
@@ -126,7 +131,7 @@
         }
         float u2 = fmax(0.0f, stepX - 0.5f) / bitmapWidth;
 
-        generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2);
+        generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount, colorKey);
 
         x1 = x2;
         u1 = (stepX + 0.5f) / bitmapWidth;
@@ -134,11 +139,15 @@
         previousStepX = stepX;
     }
 
-    generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2);
+    generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount, colorKey);
 }
 
 inline void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
-            float u1, float v1, float u2, float v2) {
+            float u1, float v1, float u2, float v2, uint32_t& quadCount, const uint32_t colorKey) {
+    if (((colorKey >> quadCount++) & 0x1) == 1) {
+        return;
+    }
+
     // Left triangle
     TextureVertex::set(vertex++, x1, y1, u1, v1);
     TextureVertex::set(vertex++, x2, y1, u2, v1);
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index a9109cd..54c9d6c 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -18,29 +18,36 @@
 #define ANDROID_UI_PATCH_H
 
 #include <sys/types.h>
-#include <cstring>
 
 #include "Vertex.h"
+#include "utils/Compare.h"
 
 namespace android {
 namespace uirenderer {
 
+///////////////////////////////////////////////////////////////////////////////
+// 9-patch structures
+///////////////////////////////////////////////////////////////////////////////
+
 /**
  * Description of a patch.
  */
 struct PatchDescription {
-    PatchDescription(): bitmapWidth(0), bitmapHeight(0),
-            pixelWidth(0), pixelHeight(0), xCount(0), yCount(0) { }
+    PatchDescription(): bitmapWidth(0), bitmapHeight(0), pixelWidth(0), pixelHeight(0),
+            xCount(0), yCount(0), emptyCount(0), colorKey(0) { }
     PatchDescription(const float bitmapWidth, const float bitmapHeight,
             const float pixelWidth, const float pixelHeight,
-            const uint32_t xCount, const uint32_t yCount):
+            const uint32_t xCount, const uint32_t yCount,
+            const int8_t emptyCount, const uint32_t colorKey):
             bitmapWidth(bitmapWidth), bitmapHeight(bitmapHeight),
             pixelWidth(pixelWidth), pixelHeight(pixelHeight),
-            xCount(xCount), yCount(yCount) { }
+            xCount(xCount), yCount(yCount),
+            emptyCount(emptyCount), colorKey(colorKey) { }
     PatchDescription(const PatchDescription& description):
             bitmapWidth(description.bitmapWidth), bitmapHeight(description.bitmapHeight),
             pixelWidth(description.pixelWidth), pixelHeight(description.pixelHeight),
-            xCount(description.xCount), yCount(description.yCount) { }
+            xCount(description.xCount), yCount(description.yCount),
+            emptyCount(description.emptyCount), colorKey(description.colorKey) { }
 
     float bitmapWidth;
     float bitmapHeight;
@@ -48,9 +55,26 @@
     float pixelHeight;
     uint32_t xCount;
     uint32_t yCount;
+    int8_t emptyCount;
+    uint32_t colorKey;
 
     bool operator<(const PatchDescription& rhs) const {
-        return memcmp(this, &rhs, sizeof(PatchDescription)) < 0;
+        compare(bitmapWidth) {
+            compare(bitmapHeight) {
+                compare(pixelWidth) {
+                    compare(pixelHeight) {
+                        compareI(xCount) {
+                            compareI(yCount) {
+                                compareI(emptyCount) {
+                                    compareI(colorKey) return false;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return false;
     }
 }; // struct PatchDescription
 
@@ -59,13 +83,14 @@
  * indices to render the vertices.
  */
 struct Patch {
-    Patch(const uint32_t xCount, const uint32_t yCount);
+    Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads = 0);
     ~Patch();
 
     void updateVertices(const float bitmapWidth, const float bitmapHeight,
             float left, float top, float right, float bottom,
             const int32_t* xDivs, const int32_t* yDivs,
-            const uint32_t width, const uint32_t height);
+            const uint32_t width, const uint32_t height,
+            const uint32_t colorKey = 0);
 
     TextureVertex* vertices;
     uint32_t verticesCount;
@@ -73,10 +98,12 @@
 private:
     static inline void generateRow(TextureVertex*& vertex, float y1, float y2,
             float v1, float v2, const int32_t xDivs[], uint32_t xCount,
-            float stretchX, float width, float bitmapWidth);
+            float stretchX, float width, float bitmapWidth,
+            uint32_t& quadCount, const uint32_t colorKey);
     static inline void generateQuad(TextureVertex*& vertex,
             float x1, float y1, float x2, float y2,
-            float u1, float v1, float u2, float v2);
+            float u1, float v1, float u2, float v2,
+            uint32_t& quadCount, const uint32_t colorKey);
 }; // struct Patch
 
 }; // namespace uirenderer
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index eca5e4d..4762d21 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -17,7 +17,6 @@
 #define LOG_TAG "OpenGLRenderer"
 
 #include <utils/Log.h>
-#include <utils/ResourceTypes.h>
 
 #include "PatchCache.h"
 #include "Properties.h"
@@ -45,7 +44,7 @@
 
 void PatchCache::clear() {
     size_t count = mCache.size();
-    for (int i = 0; i < count; i++) {
+    for (size_t i = 0; i < count; i++) {
         delete mCache.valueAt(i);
     }
     mCache.clear();
@@ -53,11 +52,23 @@
 
 Patch* PatchCache::get(const float bitmapWidth, const float bitmapHeight,
         const float pixelWidth, const float pixelHeight,
-        const int32_t* xDivs, const int32_t* yDivs,
-        const uint32_t width, const uint32_t height) {
+        const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors,
+        const uint32_t width, const uint32_t height, const int8_t numColors) {
+
+    int8_t transparentQuads = 0;
+    uint32_t colorKey = 0;
+
+    if (uint8_t(numColors) < sizeof(uint32_t) * 4) {
+        for (int8_t i = 0; i < numColors; i++) {
+            if (colors[i] == 0x0) {
+                transparentQuads++;
+                colorKey |= 0x1 << i;
+            }
+        }
+    }
 
     const PatchDescription description(bitmapWidth, bitmapHeight,
-            pixelWidth, pixelHeight, width, height);
+            pixelWidth, pixelHeight, width, height, transparentQuads, colorKey);
 
     ssize_t index = mCache.indexOfKey(description);
     Patch* mesh = NULL;
@@ -66,11 +77,13 @@
     }
 
     if (!mesh) {
-        PATCH_LOGD("Creating new patch mesh, w=%d h=%d", width, height);
+        PATCH_LOGD("New patch mesh "
+                "xCount=%d yCount=%d, w=%.2f h=%.2f, bw=%.2f bh=%.2f",
+                width, height, pixelWidth, pixelHeight, bitmapWidth, bitmapHeight);
 
-        mesh = new Patch(width, height);
+        mesh = new Patch(width, height, transparentQuads);
         mesh->updateVertices(bitmapWidth, bitmapHeight, 0.0f, 0.0f,
-                pixelWidth, pixelHeight, xDivs, yDivs, width, height);
+                pixelWidth, pixelHeight, xDivs, yDivs, width, height, colorKey);
 
         if (mCache.size() >= mMaxEntries) {
             delete mCache.valueAt(mCache.size() - 1);
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index 08f78a3..2a8ac82 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -29,7 +29,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 // Debug
-#define DEBUG_PATCHES 0
+#define DEBUG_PATCHES 1
 
 // Debug
 #if DEBUG_PATCHES
@@ -50,8 +50,8 @@
 
     Patch* get(const float bitmapWidth, const float bitmapHeight,
             const float pixelWidth, const float pixelHeight,
-            const int32_t* xDivs, const int32_t* yDivs,
-            const uint32_t width, const uint32_t height);
+            const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors,
+            const uint32_t width, const uint32_t height, const int8_t numColors);
     void clear();
 
 private:
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index 596dfab..0c74261 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -22,6 +22,7 @@
 #include <SkPath.h>
 
 #include "Texture.h"
+#include "utils/Compare.h"
 #include "utils/GenerationCache.h"
 
 namespace android {
@@ -63,7 +64,18 @@
     float strokeWidth;
 
     bool operator<(const PathCacheEntry& rhs) const {
-        return memcmp(this, &rhs, sizeof(PathCacheEntry)) < 0;
+        compareI(path) {
+            compareI(join) {
+                compareI(cap) {
+                    compareI(style) {
+                        compare(miter) {
+                            compare(strokeWidth) return false;
+                        }
+                    }
+                }
+            }
+        }
+        return false;
     }
 }; // struct PathCacheEntry
 
diff --git a/libs/hwui/utils/Compare.h b/libs/hwui/utils/Compare.h
new file mode 100644
index 0000000..754b470
--- /dev/null
+++ b/libs/hwui/utils/Compare.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 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_UI_COMPARE_H
+#define ANDROID_UI_COMPARE_H
+
+#include <cmath>
+
+#define EPSILON 0.00001f
+
+#define almost(u, v) (fabs((u) - (v)) < EPSILON)
+
+/**
+ * Compare floats.
+ */
+#define compare(a) \
+    if (a < rhs.a) return true; \
+    if (almost(a, rhs.a))
+
+/**
+ * Compare integers.
+ */
+#define compareI(a) \
+    if (a < rhs.a) return true; \
+    if (a == rhs.a)
+
+#endif // ANDROID_UI_COMPARE_H