Merge "Fast text selection drawing."
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 78836fa..91dbe1f 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -527,11 +527,18 @@
     @Override
     public void drawPath(Path path, Paint paint) {
         boolean hasModifier = setupModifiers(paint);
-        nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
+        if (path.isSimplePath) {
+            if (path.rects != null) {
+                nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
+            }
+        } else {
+            nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
+        }
         if (hasModifier) nResetModifiers(mRenderer);
     }
 
     private native void nDrawPath(int renderer, int path, int paint);
+    private native void nDrawRects(int renderer, int region, int paint);
 
     @Override
     public void drawPicture(Picture picture) {
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index be29433..9f94af9 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -236,6 +236,16 @@
     renderer->drawRect(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);
+    while (!it.done()) {
+        const SkIRect& r = it.rect();
+        renderer->drawRect(r.fLeft, r.fTop, r.fRight, r.fBottom, paint);
+        it.next();
+    }
+}
+
 static void android_view_GLES20Canvas_drawPath(JNIEnv* env, jobject canvas,
         OpenGLRenderer* renderer, SkPath* path, SkPaint* paint) {
     renderer->drawPath(path, paint);
@@ -386,6 +396,7 @@
     { "nDrawPatch",         "(II[BFFFFI)V",    (void*) android_view_GLES20Canvas_drawPatch },
     { "nDrawColor",         "(III)V",          (void*) android_view_GLES20Canvas_drawColor },
     { "nDrawRect",          "(IFFFFI)V",       (void*) android_view_GLES20Canvas_drawRect },
+    { "nDrawRects",         "(III)V",          (void*) android_view_GLES20Canvas_drawRects },
     { "nDrawPath",          "(III)V",          (void*) android_view_GLES20Canvas_drawPath },
 
     { "nResetModifiers",    "(I)V",            (void*) android_view_GLES20Canvas_resetModifiers },
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 8251881..c3416a0 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -16,6 +16,8 @@
 
 package android.graphics;
 
+import android.view.HardwareRenderer;
+
 /**
  * The Path class encapsulates compound (multiple contour) geometric paths
  * consisting of straight line segments, quadratic curves, and cubic curves.
@@ -30,10 +32,21 @@
     public final int mNativePath;
 
     /**
+     * @hide
+     */
+    public boolean isSimplePath = true;
+    /**
+     * @hide
+     */
+    public Region rects;
+    private boolean mDetectSimplePaths;
+
+    /**
      * Create an empty path
      */
     public Path() {
         mNativePath = init1();
+        mDetectSimplePaths = HardwareRenderer.isAvailable();
     }
 
     /**
@@ -47,6 +60,7 @@
             valNative = src.mNativePath;
         }
         mNativePath = init2(valNative);
+        mDetectSimplePaths = HardwareRenderer.isAvailable();
     }
     
     /**
@@ -54,6 +68,10 @@
      * This does NOT change the fill-type setting.
      */
     public void reset() {
+        isSimplePath = true;
+        if (mDetectSimplePaths) {
+            if (rects != null) rects.setEmpty();
+        }
         native_reset(mNativePath);
     }
 
@@ -62,6 +80,10 @@
      * keeps the internal data structure for faster reuse.
      */
     public void rewind() {
+        isSimplePath = true;
+        if (mDetectSimplePaths) {
+            if (rects != null) rects.setEmpty();
+        }
         native_rewind(mNativePath);
     }
 
@@ -69,6 +91,7 @@
     */
     public void set(Path src) {
         if (this != src) {
+            isSimplePath = src.isSimplePath;
             native_set(mNativePath, src.mNativePath);
         }
     }
@@ -164,6 +187,7 @@
      * @param bounds Returns the computed bounds of the path's control points.
      * @param exact This parameter is no longer used.
      */
+    @SuppressWarnings({"UnusedDeclaration"})
     public void computeBounds(RectF bounds, boolean exact) {
         native_computeBounds(mNativePath, bounds);
     }
@@ -240,6 +264,7 @@
      * @param y2 The y-coordinate of the end point on a quadratic curve
      */
     public void quadTo(float x1, float y1, float x2, float y2) {
+        isSimplePath = false;
         native_quadTo(mNativePath, x1, y1, x2, y2);
     }
 
@@ -258,6 +283,7 @@
      *            this contour, for the end point of a quadratic curve
      */
     public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
+        isSimplePath = false;
         native_rQuadTo(mNativePath, dx1, dy1, dx2, dy2);
     }
 
@@ -275,6 +301,7 @@
      */
     public void cubicTo(float x1, float y1, float x2, float y2,
                         float x3, float y3) {
+        isSimplePath = false;
         native_cubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
     }
 
@@ -285,6 +312,7 @@
      */
     public void rCubicTo(float x1, float y1, float x2, float y2,
                          float x3, float y3) {
+        isSimplePath = false;
         native_rCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
     }
 
@@ -303,6 +331,7 @@
      */
     public void arcTo(RectF oval, float startAngle, float sweepAngle,
                       boolean forceMoveTo) {
+        isSimplePath = false;
         native_arcTo(mNativePath, oval, startAngle, sweepAngle, forceMoveTo);
     }
     
@@ -318,6 +347,7 @@
      * @param sweepAngle  Sweep angle (in degrees) measured clockwise
      */
     public void arcTo(RectF oval, float startAngle, float sweepAngle) {
+        isSimplePath = false;
         native_arcTo(mNativePath, oval, startAngle, sweepAngle, false);
     }
     
@@ -326,6 +356,7 @@
      * first point of the contour, a line segment is automatically added.
      */
     public void close() {
+        isSimplePath = false;
         native_close(mNativePath);
     }
 
@@ -355,6 +386,11 @@
         if (rect == null) {
             throw new NullPointerException("need rect parameter");
         }
+        if (mDetectSimplePaths) {
+            if (rects == null) rects = new Region();
+            rects.op((int) rect.left, (int) rect.top, (int) rect.right, (int) rect.bottom,
+                    Region.Op.UNION);
+        }
         native_addRect(mNativePath, rect, dir.nativeInt);
     }
 
@@ -367,8 +403,11 @@
      * @param bottom The bottom of a rectangle to add to the path
      * @param dir    The direction to wind the rectangle's contour
      */
-    public void addRect(float left, float top, float right, float bottom,
-                        Direction dir) {
+    public void addRect(float left, float top, float right, float bottom, Direction dir) {
+        if (mDetectSimplePaths) {
+            if (rects == null) rects = new Region();
+            rects.op((int) left, (int) top, (int) right, (int) bottom, Region.Op.UNION);
+        }
         native_addRect(mNativePath, left, top, right, bottom, dir.nativeInt);
     }
 
@@ -382,6 +421,7 @@
         if (oval == null) {
             throw new NullPointerException("need oval parameter");
         }
+        isSimplePath = false;
         native_addOval(mNativePath, oval, dir.nativeInt);
     }
 
@@ -394,6 +434,7 @@
      * @param dir    The direction to wind the circle's contour
      */
     public void addCircle(float x, float y, float radius, Direction dir) {
+        isSimplePath = false;
         native_addCircle(mNativePath, x, y, radius, dir.nativeInt);
     }
 
@@ -408,6 +449,7 @@
         if (oval == null) {
             throw new NullPointerException("need oval parameter");
         }
+        isSimplePath = false;
         native_addArc(mNativePath, oval, startAngle, sweepAngle);
     }
 
@@ -423,6 +465,7 @@
         if (rect == null) {
             throw new NullPointerException("need rect parameter");
         }
+        isSimplePath = false;
         native_addRoundRect(mNativePath, rect, rx, ry, dir.nativeInt);
     }
     
@@ -442,6 +485,7 @@
         if (radii.length < 8) {
             throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
         }
+        isSimplePath = false;
         native_addRoundRect(mNativePath, rect, radii, dir.nativeInt);
     }
     
@@ -452,6 +496,7 @@
      * @param dx  The amount to translate the path in X as it is added
      */
     public void addPath(Path src, float dx, float dy) {
+        isSimplePath = false;
         native_addPath(mNativePath, src.mNativePath, dx, dy);
     }
 
@@ -461,6 +506,7 @@
      * @param src The path that is appended to the current path
      */
     public void addPath(Path src) {
+        isSimplePath = false;
         native_addPath(mNativePath, src.mNativePath);
     }
 
@@ -470,6 +516,7 @@
      * @param src The path to add as a new contour
      */
     public void addPath(Path src, Matrix matrix) {
+        if (!src.isSimplePath) isSimplePath = false;
         native_addPath(mNativePath, src.mNativePath, matrix.native_instance);
     }
 
@@ -506,6 +553,7 @@
      * @param dy The new Y coordinate for the last point
      */
     public void setLastPoint(float dx, float dy) {
+        isSimplePath = false;
         native_setLastPoint(mNativePath, dx, dy);
     }
 
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 15a4e88..3569d6a 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -137,9 +137,6 @@
         SkMatrix* matrix, bool blend):
         SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend),
         mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) {
-    for (int i = 0; i < count; i++) {
-        LOGD("[GL] Gradient color %d = 0x%x", i, colors[i]);
-    }
 }
 
 SkiaLinearGradientShader::~SkiaLinearGradientShader() {