Fix 9patch rendering.

Change-Id: Ic4c18ff483cca95fbabcb10843f7714efe488adb
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b1f5f6b..f187d3e 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -399,7 +399,7 @@
 
     drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
             1.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
-            &mMeshVertices[0].texture[0], NULL, 0, true, true);
+            &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, true, true);
 
     resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
 
@@ -574,13 +574,12 @@
     Patch* mesh = mCaches.patchCache.get(patch);
     mesh->updateVertices(bitmap, left, top, right, bottom,
             &patch->xDivs[0], &patch->yDivs[0], patch->numXDivs, patch->numYDivs);
-    mesh->dump();
 
     // Specify right and bottom as +1.0f from left/top to prevent scaling since the
     // patch mesh already defines the final size
     drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha / 255.0f,
             mode, texture->blend, &mesh->vertices[0].position[0],
-            &mesh->vertices[0].texture[0], mesh->indices, mesh->indicesCount);
+            &mesh->vertices[0].texture[0], GL_TRIANGLES, mesh->verticesCount);
 }
 
 void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
@@ -956,19 +955,21 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
-    drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend,
-            &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL);
+    drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode,
+            texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
+            GL_TRIANGLE_STRIP, gMeshCount);
 }
 
 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) {
     drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend,
-            &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL);
+            &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
+            GL_TRIANGLE_STRIP, gMeshCount);
 }
 
 void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
-        GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount,
+        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
         bool swapSrcDst, bool ignoreTransform) {
     clearLayerRegions();
 
@@ -1010,11 +1011,7 @@
         mColorFilter->setupProgram(mCaches.currentProgram);
     }
 
-    if (!indices) {
-        glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
-    } else {
-        glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices);
-    }
+    glDrawArrays(drawMode, 0, elementsCount);
     glDisableVertexAttribArray(texCoordsSlot);
 }
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 3126754..49a69f9 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -229,7 +229,7 @@
      */
     void drawTextureMesh(float left, float top, float right, float bottom, GLuint texture,
             float alpha, SkXfermode::Mode mode, bool blend,
-            GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount = 0,
+            GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
             bool swapSrcDst = false, bool ignoreTransform = false);
 
     /**
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 4b6bb37..a660730 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "OpenGLRenderer"
 
 #include <cstring>
+#include <cmath>
 
 #include <utils/Log.h>
 
@@ -29,38 +30,14 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-Patch::Patch(const uint32_t xCount, const uint32_t yCount):
-        xCount(xCount + 2), yCount(yCount + 2) {
-    verticesCount = (xCount + 2) * (yCount + 2);
-    vertices = new TextureVertex[verticesCount];
-
+Patch::Patch(const uint32_t xCount, const uint32_t yCount) {
     // 2 triangles per patch, 3 vertices per triangle
-    indicesCount = (xCount + 1) * (yCount + 1) * 2 * 3;
-    indices = new uint16_t[indicesCount];
-
-    const uint32_t xNum = xCount + 1;
-    const uint32_t yNum = yCount + 1;
-
-    uint16_t* startIndices = indices;
-    uint32_t n = 0;
-    for (uint32_t y = 0; y < yNum; y++) {
-        for (uint32_t x = 0; x < xNum; x++) {
-            *startIndices++ = n;
-            *startIndices++ = n + 1;
-            *startIndices++ = n + xNum + 2;
-
-            *startIndices++ = n;
-            *startIndices++ = n + xNum + 2;
-            *startIndices++ = n + xNum + 1;
-
-            n += 1;
-        }
-        n += 1;
-    }
+    verticesCount = (xCount + 1) * (yCount + 1) * 2 * 3;
+    vertices = new TextureVertex[verticesCount];
+    memset(vertices, 0, sizeof(TextureVertex) * verticesCount);
 }
 
 Patch::~Patch() {
-    delete indices;
     delete vertices;
 }
 
@@ -69,15 +46,13 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void Patch::updateVertices(const SkBitmap* bitmap, float left, float top, float right,
-        float bottom, const int32_t* xDivs,  const int32_t* yDivs, const uint32_t width,
+        float bottom, const int32_t* xDivs, const int32_t* yDivs, const uint32_t width,
         const uint32_t height) {
     const uint32_t xStretchCount = (width + 1) >> 1;
     const uint32_t yStretchCount = (height + 1) >> 1;
 
-    float xStretch = 0;
-    float yStretch = 0;
-    float xStretchTex = 0;
-    float yStretchTex = 0;
+    float stretchX = 0.0f;
+    float stretchY = 0.0;
 
     const float meshWidth = right - left;
 
@@ -89,9 +64,10 @@
         for (uint32_t i = 1; i < width; i += 2) {
             stretchSize += xDivs[i] - xDivs[i - 1];
         }
-        xStretchTex = (stretchSize / bitmapWidth) / xStretchCount;
+        const float xStretchTex = stretchSize;
         const float fixed = bitmapWidth - stretchSize;
-        xStretch = (right - left - fixed) / xStretchCount;
+        const float xStretch = right - left - fixed;
+        stretchX = xStretch / xStretchTex;
     }
 
     if (yStretchCount > 0) {
@@ -99,89 +75,86 @@
         for (uint32_t i = 1; i < height; i += 2) {
             stretchSize += yDivs[i] - yDivs[i - 1];
         }
-        yStretchTex = (stretchSize / bitmapHeight) / yStretchCount;
+        const float yStretchTex = stretchSize;
         const float fixed = bitmapHeight - stretchSize;
-        yStretch = (bottom - top - fixed) / yStretchCount;
+        const float yStretch = bottom - top - fixed;
+        stretchY = yStretch / yStretchTex;
     }
 
-    float vy = 0.0f;
-    float ty = 0.0f;
     TextureVertex* vertex = vertices;
 
-    generateVertices(vertex, 0.0f, 0.0f, xDivs, width, xStretch, xStretchTex,
-            meshWidth, bitmapWidth);
-    vertex += width + 2;
+    float previousStepY = 0.0f;
 
-    for (uint32_t y = 0; y < height; y++) {
-        if (y & 1) {
-            vy += yStretch;
-            ty += yStretchTex;
+    float y1 = 0.0f;
+    float v1 = 0.0f;
+
+    for (uint32_t i = 0; i < height; i++) {
+        float stepY = yDivs[i];
+
+        float y2 = 0.0f;
+        if (i & 1) {
+            const float segment = stepY - previousStepY;
+            y2 = y1 + segment * stretchY;
         } else {
-            const float step = float(yDivs[y]);
-            vy += step;
-            ty += step / bitmapHeight;
+            y2 = y1 + stepY - previousStepY;
         }
-        generateVertices(vertex, vy, ty, xDivs, width, xStretch, xStretchTex,
-                meshWidth, bitmapWidth);
-        vertex += width + 2;
+        float v2 = fmax(0.0f, stepY - 0.5f) / bitmapHeight;
+
+        generateRow(vertex, y1, y2, v1, v2, xDivs, width, stretchX,
+                right - left, bitmapWidth);
+
+        y1 = y2;
+        v1 = (stepY + 0.5f) / bitmapHeight;
+
+        previousStepY = stepY;
     }
 
-    generateVertices(vertex, bottom - top, 1.0f, xDivs, width, xStretch, xStretchTex,
-            meshWidth, bitmapWidth);
+    generateRow(vertex, y1, bottom - top, v1, 1.0f, xDivs, width, stretchX,
+            right - left, bitmapWidth);
 }
 
-inline void Patch::generateVertices(TextureVertex* vertex, float y, float v,
-        const int32_t xDivs[], uint32_t xCount, float xStretch, float xStretchTex,
-        float width, float widthTex) {
-    float vx = 0.0f;
-    float tx = 0.0f;
+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) {
+    float previousStepX = 0.0f;
 
-    TextureVertex::set(vertex, vx, y, tx, v);
-    vertex++;
+    float x1 = 0.0f;
+    float u1 = 0.0f;
 
-    for (uint32_t x = 0; x < xCount; x++) {
-        if (x & 1) {
-            vx += xStretch;
-            tx += xStretchTex;
+    // Generate the row quad by quad
+    for (uint32_t i = 0; i < xCount; i++) {
+        float stepX = xDivs[i];
+
+        float x2 = 0.0f;
+        if (i & 1) {
+            const float segment = stepX - previousStepX;
+            x2 = x1 + segment * stretchX;
         } else {
-            const float step = float(xDivs[x]);
-            vx += step;
-            tx += step / widthTex;
+            x2 = x1 + stepX - previousStepX;
         }
+        float u2 = fmax(0.0f, stepX - 0.5f) / bitmapWidth;
 
-        TextureVertex::set(vertex, vx, y, tx, v);
-        vertex++;
+        generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2);
+
+        x1 = x2;
+        u1 = (stepX + 0.5f) / bitmapWidth;
+
+        previousStepX = stepX;
     }
 
-    TextureVertex::set(vertex, width, y, 1.0f, v);
-    vertex++;
+    generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2);
 }
 
-///////////////////////////////////////////////////////////////////////////////
-// Debug tools
-///////////////////////////////////////////////////////////////////////////////
+inline void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
+            float u1, float v1, float u2, float v2) {
+    // Left triangle
+    TextureVertex::set(vertex++, x1, y1, u1, v1);
+    TextureVertex::set(vertex++, x2, y1, u2, v1);
+    TextureVertex::set(vertex++, x1, y2, u1, v2);
 
-void Patch::dump() {
-    LOGD("Vertices [");
-    for (uint32_t y = 0; y < yCount; y++) {
-        char buffer[512];
-        buffer[0] = '\0';
-        uint32_t offset = 0;
-        for (uint32_t x = 0; x < xCount; x++) {
-            TextureVertex* v = &vertices[y * xCount + x];
-            offset += sprintf(&buffer[offset], " (%.4f,%.4f)-(%.4f,%.4f)",
-                    v->position[0], v->position[1], v->texture[0], v->texture[1]);
-        }
-        LOGD("  [%s ]", buffer);
-    }
-    LOGD("]\nIndices [ ");
-    char buffer[4096];
-    buffer[0] = '\0';
-    uint32_t offset = 0;
-    for (uint32_t i = 0; i < indicesCount; i++) {
-        offset += sprintf(&buffer[offset], "%d ", indices[i]);
-    }
-    LOGD("  %s\n]", buffer);
+    // Right triangle
+    TextureVertex::set(vertex++, x1, y2, u1, v2);
+    TextureVertex::set(vertex++, x2, y1, u2, v1);
+    TextureVertex::set(vertex++, x2, y2, u2, v2);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index 5d3ad03..f712455 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -62,21 +62,16 @@
     void updateVertices(const SkBitmap* bitmap, float left, float top, float right, float bottom,
             const int32_t* xDivs,  const int32_t* yDivs,
             const uint32_t width, const uint32_t height);
-    void dump();
-
-    uint32_t xCount;
-    uint32_t yCount;
-
-    uint16_t* indices;
-    uint32_t indicesCount;
 
     TextureVertex* vertices;
     uint32_t verticesCount;
 
 private:
-    static inline void generateVertices(TextureVertex* vertex, float y, float v,
-            const int32_t xDivs[], uint32_t xCount, float xStretch, float xStretchTex,
-            float width, float widthTex);
+    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);
+    static inline void generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
+            float u1, float v1, float u2, float v2);
 }; // struct Patch
 
 }; // namespace uirenderer
diff --git a/tests/HwAccelerationTest/res/drawable/patch.9.png b/tests/HwAccelerationTest/res/drawable/patch.9.png
new file mode 100644
index 0000000..e3b3639
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable/patch.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ThinPatchesActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ThinPatchesActivity.java
index d374c32..4f605fa 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ThinPatchesActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ThinPatchesActivity.java
@@ -41,13 +41,14 @@
     }
 
     private class PatchView extends View {
-        private Drawable mPatch;
+        private Drawable mPatch1, mPatch2;
 
         public PatchView(Activity activity) {
             super(activity);
 
             final Resources resources = activity.getResources();
-            mPatch = resources.getDrawable(R.drawable.btn_toggle_on);
+            mPatch1 = resources.getDrawable(R.drawable.patch);
+            mPatch2 = resources.getDrawable(R.drawable.btn_toggle_on);
         }
 
         @Override
@@ -58,8 +59,13 @@
             final int left = (getWidth() - width) / 2;
             final int top  = (getHeight() - height) / 2;
 
-            mPatch.setBounds(left, top, left + width, top + height);
-            mPatch.draw(canvas);
+            mPatch1.setBounds(left, top, left + width, top + height);
+            mPatch1.draw(canvas);
+
+            canvas.translate(0.0f, height + 20.0f);
+            
+            mPatch2.setBounds(left, top, left + width, top + height);
+            mPatch2.draw(canvas);
         }
     }
 }