Add support for ovals and stroked rectangles.

Change-Id: I1292e241386763c82e6622c8f7ed90b0f5b7bd4f
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index e47dc93..936e9d2 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -525,7 +525,7 @@
     @Override
     public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
             Paint paint) {
-        throw new UnsupportedOperationException();
+        // TODO: Implement
     }
 
     @Override
@@ -705,9 +705,14 @@
 
     @Override
     public void drawOval(RectF oval, Paint paint) {
-        throw new UnsupportedOperationException();
+        boolean hasModifier = setupModifiers(paint);
+        nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
+        if (hasModifier) nResetModifiers(mRenderer); 
     }
 
+    private native void nDrawOval(int renderer, float left, float top, float right, float bottom,
+            int paint);
+
     @Override
     public void drawPaint(Paint paint) {
         final Rect r = mClipBounds;
@@ -765,12 +770,12 @@
 
     @Override
     public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
-        throw new UnsupportedOperationException();
+        // TODO: Implement
     }
 
     @Override
     public void drawPosText(String text, float[] pos, Paint paint) {
-        throw new UnsupportedOperationException();
+        // TODO: Implement
     }
 
     @Override
@@ -879,12 +884,12 @@
     @Override
     public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
             float vOffset, Paint paint) {
-        throw new UnsupportedOperationException();
+        // TODO: Implement
     }
 
     @Override
     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
-        throw new UnsupportedOperationException();
+        // TODO: Implement
     }
 
     @Override
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 554e336f..2daffbb 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -326,6 +326,12 @@
     renderer->drawCircle(x, y, radius, paint);
 }
 
+static void android_view_GLES20Canvas_drawOval(JNIEnv* env, jobject canvas,
+        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
+        SkPaint* paint) {
+    renderer->drawOval(left, top, right, bottom, paint);
+}
+
 static void android_view_GLES20Canvas_drawRects(JNIEnv* env, jobject canvas,
         OpenGLRenderer* renderer, SkRegion* region, SkPaint* paint) {
     SkRegion::Iterator it(*region);
@@ -602,6 +608,7 @@
     { "nDrawRects",         "(III)V",          (void*) android_view_GLES20Canvas_drawRects },
     { "nDrawRoundRect",     "(IFFFFFFI)V",     (void*) android_view_GLES20Canvas_drawRoundRect },
     { "nDrawCircle",        "(IFFFI)V",        (void*) android_view_GLES20Canvas_drawCircle },
+    { "nDrawOval",          "(IFFFFI)V",       (void*) android_view_GLES20Canvas_drawOval },
     { "nDrawPath",          "(III)V",          (void*) android_view_GLES20Canvas_drawPath },
     { "nDrawLines",         "(I[FIII)V",       (void*) android_view_GLES20Canvas_drawLines },
 
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 24585d5..3bac422 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -162,6 +162,8 @@
     PathCache pathCache;
     RoundRectShapeCache roundRectShapeCache;
     CircleShapeCache circleShapeCache;
+    OvalShapeCache ovalShapeCache;
+    RectShapeCache rectShapeCache;
     PatchCache patchCache;
     TextDropShadowCache dropShadowCache;
     FboCache fboCache;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 58ef7b3..8714997 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -107,6 +107,7 @@
     "DrawRect",
     "DrawRoundRect",
     "DrawCircle",
+    "DrawOval",
     "DrawPath",
     "DrawLines",
     "DrawText",
@@ -358,6 +359,10 @@
                 renderer.drawCircle(getFloat(), getFloat(), getFloat(), getPaint());
             }
             break;
+            case DrawOval: {
+                renderer.drawOval(getFloat(), getFloat(), getFloat(), getFloat(), getPaint());
+            }
+            break;
             case DrawPath: {
                 renderer.drawPath(getPath(), getPaint());
             }
@@ -663,6 +668,13 @@
     addPaint(paint);
 }
 
+void DisplayListRenderer::drawOval(float left, float top, float right, float bottom,
+        SkPaint* paint) {
+    addOp(DisplayList::DrawOval);
+    addBounds(left, top, right, bottom);
+    addPaint(paint);
+}
+
 void DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) {
     addOp(DisplayList::DrawPath);
     addPath(path);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 68e4359..8183e25 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -113,6 +113,7 @@
         DrawRect,
         DrawRoundRect,
         DrawCircle,
+        DrawOval,
         DrawPath,
         DrawLines,
         DrawText,
@@ -279,6 +280,7 @@
     void drawRoundRect(float left, float top, float right, float bottom,
             float rx, float ry, SkPaint* paint);
     void drawCircle(float x, float y, float radius, SkPaint* paint);
+    void drawOval(float left, float top, float right, float bottom, SkPaint* paint);
     void drawPath(SkPath* path, SkPaint* paint);
     void drawLines(float* points, int count, SkPaint* paint);
     void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 9aa3e7c..99c0600 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1360,14 +1360,7 @@
     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
 }
 
-void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
-        float rx, float ry, SkPaint* paint) {
-    if (mSnapshot->isIgnored()) return;
-
-    glActiveTexture(gTextureUnits[0]);
-
-    const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect(
-            right - left, bottom - top, rx, ry, paint);
+void OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture, SkPaint* paint) {
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
@@ -1377,22 +1370,47 @@
     drawPathTexture(texture, x, y, paint);
 }
 
+void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
+        float rx, float ry, SkPaint* paint) {
+    if (mSnapshot->isIgnored()) return;
+
+    glActiveTexture(gTextureUnits[0]);
+    const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect(
+            right - left, bottom - top, rx, ry, paint);
+    drawShape(left, top, texture, paint);
+}
+
 void OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
     if (mSnapshot->isIgnored()) return;
 
     glActiveTexture(gTextureUnits[0]);
-
     const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, paint);
-    if (!texture) return;
-    const AutoTexture autoCleanup(texture);
+    drawShape(x - radius, y - radius, texture, paint);
+}
 
-    const float left = (x - radius) + texture->left - texture->offset;
-    const float top = (y - radius) + texture->top - texture->offset;
+void OpenGLRenderer::drawOval(float left, float top, float right, float bottom, SkPaint* paint) {
+    if (mSnapshot->isIgnored()) return;
 
-    drawPathTexture(texture, left, top, paint);
+    glActiveTexture(gTextureUnits[0]);
+    const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, paint);
+    drawShape(left, top, texture, paint);
+}
+
+void OpenGLRenderer::drawRectAsShape(float left, float top, float right, float bottom,
+        SkPaint* paint) {
+    if (mSnapshot->isIgnored()) return;
+
+    glActiveTexture(gTextureUnits[0]);
+    const PathTexture* texture = mCaches.rectShapeCache.getRect(right - left, bottom - top, paint);
+    drawShape(left, top, texture, paint);
 }
 
 void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) {
+    if (p->getStyle() != SkPaint::kFill_Style) {
+        drawRectAsShape(left, top, right, bottom, p);
+        return;
+    }
+
     if (quickReject(left, top, right, bottom)) {
         return;
     }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 42e93ad..30cf102 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -112,6 +112,7 @@
     virtual void drawRoundRect(float left, float top, float right, float bottom,
             float rx, float ry, SkPaint* paint);
     virtual void drawCircle(float x, float y, float radius, SkPaint* paint);
+    virtual void drawOval(float left, float top, float right, float bottom, SkPaint* paint);
     virtual void drawPath(SkPath* path, SkPaint* paint);
     virtual void drawLines(float* points, int count, SkPaint* paint);
     virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
@@ -277,6 +278,9 @@
     void drawColorRect(float left, float top, float right, float bottom,
             int color, SkXfermode::Mode mode, bool ignoreTransform = false);
 
+    void drawShape(float left, float top, const PathTexture* texture, SkPaint* paint);
+    void drawRectAsShape(float left, float top, float right, float bottom, SkPaint* p);
+
     /**
      * Draws a textured rectangle with the specified texture. The specified coordinates
      * are transformed by the current snapshot's transform matrix.
diff --git a/libs/hwui/ShapeCache.cpp b/libs/hwui/ShapeCache.cpp
index b78eecb..da86075 100644
--- a/libs/hwui/ShapeCache.cpp
+++ b/libs/hwui/ShapeCache.cpp
@@ -68,5 +68,51 @@
     return texture;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// Ovals
+///////////////////////////////////////////////////////////////////////////////
+
+OvalShapeCache::OvalShapeCache(): ShapeCache<OvalShapeCacheEntry>(
+        "oval", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
+}
+
+PathTexture* OvalShapeCache::getOval(float width, float height, SkPaint* paint) {
+    OvalShapeCacheEntry entry(width, height, paint);
+    PathTexture* texture = get(entry);
+
+    if (!texture) {
+        SkPath path;
+        SkRect r;
+        r.set(0.0f, 0.0f, width, height);
+        path.addOval(r, SkPath::kCW_Direction);
+
+        texture = addTexture(entry, &path, paint);
+    }
+
+    return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Rects
+///////////////////////////////////////////////////////////////////////////////
+
+RectShapeCache::RectShapeCache(): ShapeCache<RectShapeCacheEntry>(
+        "rect", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
+}
+
+PathTexture* RectShapeCache::getRect(float width, float height, SkPaint* paint) {
+    RectShapeCacheEntry entry(width, height, paint);
+    PathTexture* texture = get(entry);
+
+    if (!texture) {
+        SkPath path;
+        path.addRect(0.0f, 0.0f, width, height, SkPath::kCW_Direction);
+
+        texture = addTexture(entry, &path, paint);
+    }
+
+    return texture;
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
index c627931..a4aff9d 100644
--- a/libs/hwui/ShapeCache.h
+++ b/libs/hwui/ShapeCache.h
@@ -76,6 +76,7 @@
 struct ShapeCacheEntry {
     enum ShapeType {
         kShapeNone,
+        kShapeRect,
         kShapeRoundRect,
         kShapeCircle,
         kShapeOval,
@@ -216,6 +217,70 @@
     uint32_t mRadius;
 }; // CircleShapeCacheEntry
 
+struct OvalShapeCacheEntry: public ShapeCacheEntry {
+    OvalShapeCacheEntry(float width, float height, SkPaint* paint):
+            ShapeCacheEntry(ShapeCacheEntry::kShapeOval, paint) {
+        mWidth = *(uint32_t*) &width;
+        mHeight = *(uint32_t*) &height;
+    }
+
+    OvalShapeCacheEntry(): ShapeCacheEntry() {
+        mWidth = mHeight = 0;
+    }
+
+    OvalShapeCacheEntry(const OvalShapeCacheEntry& entry):
+            ShapeCacheEntry(entry) {
+        mWidth = entry.mWidth;
+        mHeight = entry.mHeight;
+    }
+
+    bool lessThan(const ShapeCacheEntry& r) const {
+        const OvalShapeCacheEntry& rhs = (const OvalShapeCacheEntry&) r;
+        LTE_INT(mWidth) {
+            LTE_INT(mHeight) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+private:
+    uint32_t mWidth;
+    uint32_t mHeight;
+}; // OvalShapeCacheEntry
+
+struct RectShapeCacheEntry: public ShapeCacheEntry {
+    RectShapeCacheEntry(float width, float height, SkPaint* paint):
+            ShapeCacheEntry(ShapeCacheEntry::kShapeRect, paint) {
+        mWidth = *(uint32_t*) &width;
+        mHeight = *(uint32_t*) &height;
+    }
+
+    RectShapeCacheEntry(): ShapeCacheEntry() {
+        mWidth = mHeight = 0;
+    }
+
+    RectShapeCacheEntry(const RectShapeCacheEntry& entry):
+            ShapeCacheEntry(entry) {
+        mWidth = entry.mWidth;
+        mHeight = entry.mHeight;
+    }
+
+    bool lessThan(const ShapeCacheEntry& r) const {
+        const RectShapeCacheEntry& rhs = (const RectShapeCacheEntry&) r;
+        LTE_INT(mWidth) {
+            LTE_INT(mHeight) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+private:
+    uint32_t mWidth;
+    uint32_t mHeight;
+}; // RectShapeCacheEntry
+
 /**
  * A simple LRU shape cache. The cache has a maximum size expressed in bytes.
  * Any texture added to the cache causing the cache to grow beyond the maximum
@@ -289,8 +354,21 @@
     CircleShapeCache();
 
     PathTexture* getCircle(float radius, SkPaint* paint);
-}; // class RoundRectShapeCache
+}; // class CircleShapeCache
 
+class OvalShapeCache: public ShapeCache<OvalShapeCacheEntry> {
+public:
+    OvalShapeCache();
+
+    PathTexture* getOval(float width, float height, SkPaint* paint);
+}; // class OvalShapeCache
+
+class RectShapeCache: public ShapeCache<RectShapeCacheEntry> {
+public:
+    RectShapeCache();
+
+    PathTexture* getRect(float width, float height, SkPaint* paint);
+}; // class RectShapeCache
 
 ///////////////////////////////////////////////////////////////////////////////
 // Constructors/destructor
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
index 536a669..ddf43d7 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
@@ -38,6 +38,7 @@
         private Paint mStrokePaint;
         private Paint mFillPaint;
         private RectF mRect;
+        private RectF mOval;
 
         ShapesView(Context c) {
             super(c);
@@ -60,6 +61,8 @@
             mFillPaint.setAntiAlias(true);
             mFillPaint.setColor(0xff0000ff);
             mFillPaint.setStyle(Paint.Style.FILL);
+
+            mOval = new RectF(0.0f, 0.0f, 80.0f, 45.0f);
         }
 
         @Override
@@ -87,6 +90,28 @@
             canvas.translate(0.0f, 110.0f);
             canvas.drawCircle(80.0f, 45.0f, 45.0f, mFillPaint);
             canvas.restore();
+
+            canvas.save();
+            canvas.translate(450.0f, 50.0f);
+            canvas.drawOval(mOval, mNormalPaint);
+
+            canvas.translate(0.0f, 110.0f);
+            canvas.drawOval(mOval, mStrokePaint);
+
+            canvas.translate(0.0f, 110.0f);
+            canvas.drawOval(mOval, mFillPaint);
+            canvas.restore();
+
+            canvas.save();
+            canvas.translate(650.0f, 50.0f);
+            canvas.drawRect(0.0f, 0.0f, 160.0f, 90.0f, mNormalPaint);
+
+            canvas.translate(0.0f, 110.0f);
+            canvas.drawRect(0.0f, 0.0f, 160.0f, 90.0f, mStrokePaint);
+
+            canvas.translate(0.0f, 110.0f);
+            canvas.drawRect(0.0f, 0.0f, 160.0f, 90.0f, mFillPaint);
+            canvas.restore();
         }
     }
 }