Implement quickReject() and drawRect().

The OpenGL ES 2.0 renderer can now draw colored rectangles. At least there's
something on screen now.

Change-Id: I80a13ccc1dd56784edf74f2670a364f30700234a
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index eb077cb..5c24058f 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -193,9 +193,11 @@
 
     @Override
     public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
-        // TODO: Implement
-        return false;
+        return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt);
     }
+    
+    private native boolean nQuickReject(int renderer, float left, float top,
+            float right, float bottom, int edge);
 
     @Override
     public boolean quickReject(Path path, EdgeType type) {
@@ -480,17 +482,20 @@
 
     @Override
     public void drawRect(float left, float top, float right, float bottom, Paint paint) {
-        // TODO: Implement
+        nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
     }
 
+    private native void nDrawRect(int renderer, float left, float top, float right, float bottom,
+            int paint);
+
     @Override
     public void drawRect(Rect r, Paint paint) {
-        // TODO: Implement
+        drawRect(r.left, r.top, r.right, r.bottom, paint);
     }
 
     @Override
-    public void drawRect(RectF rect, Paint paint) {
-        // TODO: Implement
+    public void drawRect(RectF r, Paint paint) {
+        drawRect(r.left, r.top, r.right, r.bottom, paint);
     }
 
     @Override
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 95476eb..aca63e8 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -18,7 +18,9 @@
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 
+#include <SkCanvas.h>
 #include <SkMatrix.h>
+#include <SkPaint.h>
 #include <SkXfermode.h>
 
 #include <OpenGLRenderer.h>
@@ -93,6 +95,12 @@
 // Clipping
 // ----------------------------------------------------------------------------
 
+static bool android_view_GLES20Renderer_quickReject(JNIEnv* env, jobject canvas,
+        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
+        SkCanvas::EdgeType edge) {
+    return renderer->quickReject(left, top, right, bottom);
+}
+
 static bool android_view_GLES20Renderer_clipRectF(JNIEnv* env, jobject canvas,
         OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom) {
     return renderer->clipRect(left, top, right, bottom);
@@ -157,6 +165,12 @@
     renderer->drawColor(color, (SkXfermode::Mode) mode);
 }
 
+static void android_view_GLES20Renderer_drawRect(JNIEnv* env, jobject canvas,
+        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
+        SkPaint* paint) {
+    renderer->drawRect(left, top, right, bottom, paint);
+}
+
 // ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
@@ -164,31 +178,33 @@
 const char* const kClassPathName = "android/view/GLES20Canvas";
 
 static JNINativeMethod gMethods[] = {
-    {   "nCreateRenderer",    "()I",      (void*) android_view_GLES20Renderer_createRenderer },
-    {   "nDestroyRenderer",   "(I)V",     (void*) android_view_GLES20Renderer_destroyRenderer },
-    {   "nSetViewport",       "(III)V",   (void*) android_view_GLES20Renderer_setViewport },
-    {   "nPrepare",           "(I)V",     (void*) android_view_GLES20Renderer_prepare },
+    {   "nCreateRenderer",    "()I",       (void*) android_view_GLES20Renderer_createRenderer },
+    {   "nDestroyRenderer",   "(I)V",      (void*) android_view_GLES20Renderer_destroyRenderer },
+    {   "nSetViewport",       "(III)V",    (void*) android_view_GLES20Renderer_setViewport },
+    {   "nPrepare",           "(I)V",      (void*) android_view_GLES20Renderer_prepare },
 
-    {   "nSave",              "(II)I",    (void*) android_view_GLES20Renderer_save },
-    {   "nRestore",           "(I)V",     (void*) android_view_GLES20Renderer_restore },
-    {   "nRestoreToCount",    "(II)V",    (void*) android_view_GLES20Renderer_restoreToCount },
-    {   "nGetSaveCount",      "(I)I",     (void*) android_view_GLES20Renderer_getSaveCount },
+    {   "nSave",              "(II)I",     (void*) android_view_GLES20Renderer_save },
+    {   "nRestore",           "(I)V",      (void*) android_view_GLES20Renderer_restore },
+    {   "nRestoreToCount",    "(II)V",     (void*) android_view_GLES20Renderer_restoreToCount },
+    {   "nGetSaveCount",      "(I)I",      (void*) android_view_GLES20Renderer_getSaveCount },
 
-    {   "nClipRect",          "(IFFFF)Z", (void*) android_view_GLES20Renderer_clipRectF },
-    {   "nClipRect",          "(IIIII)Z", (void*) android_view_GLES20Renderer_clipRect },
+    {   "nQuickReject",       "(IFFFFI)Z", (void*) android_view_GLES20Renderer_quickReject },
+    {   "nClipRect",          "(IFFFF)Z",  (void*) android_view_GLES20Renderer_clipRectF },
+    {   "nClipRect",          "(IIIII)Z",  (void*) android_view_GLES20Renderer_clipRect },
+
+    {   "nTranslate",         "(IFF)V",    (void*) android_view_GLES20Renderer_translate },
+    {   "nRotate",            "(IF)V",     (void*) android_view_GLES20Renderer_rotate },
+    {   "nScale",             "(IFF)V",    (void*) android_view_GLES20Renderer_scale },
+
+    {   "nSetMatrix",         "(II)V",     (void*) android_view_GLES20Renderer_setMatrix },
+    {   "nGetMatrix",         "(II)V",     (void*) android_view_GLES20Renderer_getMatrix },
+    {   "nConcatMatrix",      "(II)V",     (void*) android_view_GLES20Renderer_concatMatrix },
+
+    {   "nDrawColor",         "(III)V",    (void*) android_view_GLES20Renderer_drawColor },
+    {   "nDrawRect",          "(IFFFFI)V", (void*) android_view_GLES20Renderer_drawRect },
 
     {   "nGetClipBounds",     "(ILandroid/graphics/Rect;)Z",
-    		(void*) android_view_GLES20Renderer_getClipBounds },
-
-    {   "nTranslate",         "(IFF)V",   (void*) android_view_GLES20Renderer_translate },
-    {   "nRotate",            "(IF)V",    (void*) android_view_GLES20Renderer_rotate },
-    {   "nScale",             "(IFF)V",   (void*) android_view_GLES20Renderer_scale },
-
-    {   "nSetMatrix",         "(II)V",    (void*) android_view_GLES20Renderer_setMatrix },
-    {   "nGetMatrix",         "(II)V",    (void*) android_view_GLES20Renderer_getMatrix },
-    {   "nConcatMatrix",      "(II)V",    (void*) android_view_GLES20Renderer_concatMatrix },
-
-    {   "nDrawColor",         "(III)V",   (void*) android_view_GLES20Renderer_drawColor },
+            (void*) android_view_GLES20Renderer_getClipBounds },
 };
 
 #define FIND_CLASS(var, className) \
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index e556350..3a0c18c 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -653,7 +653,11 @@
         EdgeType(int nativeInt) {
             this.nativeInt = nativeInt;
         }
-        final int nativeInt;
+
+        /**
+         * @hide
+         */
+        public final int nativeInt;
     }
 
     /**
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 862a2ec..88ff0e6 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -27,7 +27,11 @@
  */
 public class Paint {
 
-    /*package*/ int     mNativePaint;
+    /**
+     * @hide
+     */
+    public int mNativePaint;
+
     private ColorFilter mColorFilter;
     private MaskFilter  mMaskFilter;
     private PathEffect  mPathEffect;
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index c097d7f..59b7fef 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -30,95 +30,95 @@
 namespace uirenderer {
 
 void Matrix4::loadIdentity() {
-	mMat[0]  = 1.0f;
-	mMat[1]  = 0.0f;
-	mMat[2]  = 0.0f;
-	mMat[3]  = 0.0f;
+	data[0]  = 1.0f;
+	data[1]  = 0.0f;
+	data[2]  = 0.0f;
+	data[3]  = 0.0f;
 
-	mMat[4]  = 0.0f;
-	mMat[5]  = 1.0f;
-	mMat[6]  = 0.0f;
-	mMat[7]  = 0.0f;
+	data[4]  = 0.0f;
+	data[5]  = 1.0f;
+	data[6]  = 0.0f;
+	data[7]  = 0.0f;
 
-	mMat[8]  = 0.0f;
-	mMat[9]  = 0.0f;
-	mMat[10] = 1.0f;
-	mMat[11] = 0.0f;
+	data[8]  = 0.0f;
+	data[9]  = 0.0f;
+	data[10] = 1.0f;
+	data[11] = 0.0f;
 
-	mMat[12] = 0.0f;
-	mMat[13] = 0.0f;
-	mMat[14] = 0.0f;
-	mMat[15] = 1.0f;
+	data[12] = 0.0f;
+	data[13] = 0.0f;
+	data[14] = 0.0f;
+	data[15] = 1.0f;
 }
 
 void Matrix4::load(const float* v) {
-	memcpy(mMat, v, sizeof(mMat));
+	memcpy(data, v, sizeof(data));
 }
 
 void Matrix4::load(const Matrix4& v) {
-	memcpy(mMat, v.mMat, sizeof(mMat));
+	memcpy(data, v.data, sizeof(data));
 }
 
 void Matrix4::load(const SkMatrix& v) {
-	memset(mMat, 0, sizeof(mMat));
+	memset(data, 0, sizeof(data));
 
-	mMat[0]  = v[SkMatrix::kMScaleX];
-	mMat[4]  = v[SkMatrix::kMSkewX];
-	mMat[12] = v[SkMatrix::kMTransX];
+	data[0]  = v[SkMatrix::kMScaleX];
+	data[4]  = v[SkMatrix::kMSkewX];
+	data[12] = v[SkMatrix::kMTransX];
 
-	mMat[1]  = v[SkMatrix::kMSkewY];
-	mMat[5]  = v[SkMatrix::kMScaleY];
-	mMat[13] = v[SkMatrix::kMTransY];
+	data[1]  = v[SkMatrix::kMSkewY];
+	data[5]  = v[SkMatrix::kMScaleY];
+	data[13] = v[SkMatrix::kMTransY];
 
-	mMat[3]  = v[SkMatrix::kMPersp0];
-	mMat[7]  = v[SkMatrix::kMPersp1];
-	mMat[15] = v[SkMatrix::kMPersp2];
+	data[3]  = v[SkMatrix::kMPersp0];
+	data[7]  = v[SkMatrix::kMPersp1];
+	data[15] = v[SkMatrix::kMPersp2];
 
-	mMat[10] = 1.0f;
+	data[10] = 1.0f;
 }
 
 void Matrix4::copyTo(SkMatrix& v) const {
 	v.reset();
 
-	v.set(SkMatrix::kMScaleX, mMat[0]);
-	v.set(SkMatrix::kMSkewX,  mMat[4]);
-	v.set(SkMatrix::kMTransX, mMat[12]);
+	v.set(SkMatrix::kMScaleX, data[0]);
+	v.set(SkMatrix::kMSkewX,  data[4]);
+	v.set(SkMatrix::kMTransX, data[12]);
 
-	v.set(SkMatrix::kMSkewY,  mMat[1]);
-	v.set(SkMatrix::kMScaleY, mMat[5]);
-	v.set(SkMatrix::kMTransY, mMat[13]);
+	v.set(SkMatrix::kMSkewY,  data[1]);
+	v.set(SkMatrix::kMScaleY, data[5]);
+	v.set(SkMatrix::kMTransY, data[13]);
 
-	v.set(SkMatrix::kMPersp0, mMat[3]);
-	v.set(SkMatrix::kMPersp1, mMat[7]);
-	v.set(SkMatrix::kMPersp2, mMat[15]);
+	v.set(SkMatrix::kMPersp0, data[3]);
+	v.set(SkMatrix::kMPersp1, data[7]);
+	v.set(SkMatrix::kMPersp2, data[15]);
 }
 
 void Matrix4::copyTo(float* v) const {
-	memcpy(v, mMat, sizeof(mMat));
+	memcpy(v, data, sizeof(data));
 }
 
 void Matrix4::loadTranslate(float x, float y, float z) {
 	loadIdentity();
-	mMat[12] = x;
-	mMat[13] = y;
-	mMat[14] = z;
+	data[12] = x;
+	data[13] = y;
+	data[14] = z;
 }
 
 void Matrix4::loadScale(float sx, float sy, float sz) {
 	loadIdentity();
-	mMat[0]  = sx;
-	mMat[5]  = sy;
-	mMat[10] = sz;
+	data[0]  = sx;
+	data[5]  = sy;
+	data[10] = sz;
 }
 
 void Matrix4::loadRotate(float angle, float x, float y, float z) {
-	mMat[3]  = 0.0f;
-	mMat[7]  = 0.0f;
-	mMat[11] = 0.0f;
-	mMat[12] = 0.0f;
-	mMat[13] = 0.0f;
-	mMat[14] = 0.0f;
-	mMat[15] = 1.0f;
+	data[3]  = 0.0f;
+	data[7]  = 0.0f;
+	data[11] = 0.0f;
+	data[12] = 0.0f;
+	data[13] = 0.0f;
+	data[14] = 0.0f;
+	data[15] = 1.0f;
 
 	angle *= float(M_PI / 180.0f);
 	float c = cosf(angle);
@@ -133,15 +133,15 @@
 	const float ys = y * s;
 	const float zs = z * s;
 
-	mMat[0]  = x * x * nc +  c;
-	mMat[4]  =    xy * nc - zs;
-	mMat[8]  =    zx * nc + ys;
-	mMat[1]  =    xy * nc + zs;
-	mMat[5]  = y * y * nc +  c;
-	mMat[9]  =    yz * nc - xs;
-	mMat[2]  =    zx * nc - ys;
-	mMat[6]  =    yz * nc + xs;
-	mMat[10] = z * z * nc +  c;
+	data[0]  = x * x * nc +  c;
+	data[4]  =    xy * nc - zs;
+	data[8]  =    zx * nc + ys;
+	data[1]  =    xy * nc + zs;
+	data[5]  = y * y * nc +  c;
+	data[9]  =    yz * nc - xs;
+	data[2]  =    zx * nc - ys;
+	data[6]  =    yz * nc + xs;
+	data[10] = z * z * nc +  c;
 }
 
 void Matrix4::loadMultiply(const Matrix4& u, const Matrix4& v) {
@@ -152,7 +152,7 @@
         float w = 0;
 
         for (int j = 0 ; j < 4 ; j++) {
-            const float e = v.get(i,j);
+            const float e = v.get(i, j);
             x += u.get(j, 0) * e;
             y += u.get(j, 1) * e;
             z += u.get(j, 2) * e;
@@ -168,22 +168,22 @@
 
 void Matrix4::loadOrtho(float left, float right, float bottom, float top, float near, float far) {
     loadIdentity();
-    mMat[0]  = 2.0f / (right - left);
-    mMat[5]  = 2.0f / (top - bottom);
-    mMat[10] = -2.0f / (far - near);
-    mMat[12] = -(right + left) / (right - left);
-    mMat[13] = -(top + bottom) / (top - bottom);
-    mMat[14] = -(far + near) / (far - near);
+    data[0]  = 2.0f / (right - left);
+    data[5]  = 2.0f / (top - bottom);
+    data[10] = -2.0f / (far - near);
+    data[12] = -(right + left) / (right - left);
+    data[13] = -(top + bottom) / (top - bottom);
+    data[14] = -(far + near) / (far - near);
 }
 
 #define MUL_ADD_STORE(a, b, c) a = (a) * (b) + (c)
 
 void Matrix4::mapRect(Rect& r) const {
-	const float sx = mMat[0];
-	const float sy = mMat[5];
+	const float sx = data[0];
+	const float sy = data[5];
 
-	const float tx = mMat[12];
-	const float ty = mMat[13];
+	const float tx = data[12];
+	const float ty = data[13];
 
 	MUL_ADD_STORE(r.left, sx, tx);
 	MUL_ADD_STORE(r.right, sx, tx);
@@ -193,10 +193,10 @@
 
 void Matrix4::dump() const {
 	LOGD("Matrix4[");
-	LOGD("  %f %f %f %f", mMat[0], mMat[4], mMat[ 8], mMat[12]);
-	LOGD("  %f %f %f %f", mMat[1], mMat[5], mMat[ 9], mMat[13]);
-	LOGD("  %f %f %f %f", mMat[2], mMat[6], mMat[10], mMat[14]);
-	LOGD("  %f %f %f %f", mMat[3], mMat[7], mMat[11], mMat[15]);
+	LOGD("  %f %f %f %f", data[0], data[4], data[ 8], data[12]);
+	LOGD("  %f %f %f %f", data[1], data[5], data[ 9], data[13]);
+	LOGD("  %f %f %f %f", data[2], data[6], data[10], data[14]);
+	LOGD("  %f %f %f %f", data[3], data[7], data[11], data[15]);
 	LOGD("]");
 }
 
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 9bd289f..8fa5e4d 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -30,6 +30,8 @@
 
 class Matrix4 {
 public:
+	float data[16];
+
 	Matrix4() {
 		loadIdentity();
 	}
@@ -92,14 +94,12 @@
 
 private:
     inline float get(int i, int j) const {
-        return mMat[i * 4 + j];
+        return data[i * 4 + j];
     }
 
     inline void set(int i, int j, float v) {
-    	mMat[i * 4 + j] = v;
+    	data[i * 4 + j] = v;
     }
-
-	float mMat[16];
 }; // class Matrix4
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 575bc20..2ebd7cd 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -27,6 +27,7 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
+#include <SkPaint.h>
 #include <SkXfermode.h>
 
 #include "OpenGLRenderer.h"
@@ -39,20 +40,20 @@
 // Defines
 ///////////////////////////////////////////////////////////////////////////////
 
-#define SOLID_WHITE { 1.0f, 1.0f, 1.0f, 1.0f }
-
-#define P(x, y) { x, y }
+#define V(x, y) { { x, y } }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Globals
 ///////////////////////////////////////////////////////////////////////////////
 
-const Vertex gDrawColorVertices[] = {
-		{ P(0.0f, 0.0f), SOLID_WHITE },
-		{ P(1.0f, 0.0f), SOLID_WHITE },
-		{ P(0.0f, 1.0f), SOLID_WHITE },
-		{ P(1.0f, 1.0f), SOLID_WHITE }
+const SimpleVertex gDrawColorVertices[] = {
+		V(0.0f, 0.0f),
+		V(1.0f, 0.0f),
+		V(0.0f, 1.0f),
+		V(1.0f, 1.0f)
 };
+const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex);
+const GLsizei gDrawColorVertexCount = 4;
 
 ///////////////////////////////////////////////////////////////////////////////
 // Shaders
@@ -142,6 +143,15 @@
 	color = addAttrib("color");
 	projection = addUniform("projection");
 	modelView = addUniform("modelView");
+	transform = addUniform("transform");
+}
+
+void DrawColorProgram::use(const GLfloat* projectionMatrix, const GLfloat* modelViewMatrix,
+        const GLfloat* transformMatrix) {
+	Program::use();
+	glUniformMatrix4fv(projection, 1, GL_FALSE, projectionMatrix);
+	glUniformMatrix4fv(modelView, 1, GL_FALSE, modelViewMatrix);
+	glUniformMatrix4fv(transform, 1, GL_FALSE, transformMatrix);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -179,7 +189,7 @@
     glViewport(0, 0, width, height);
 
     mat4 ortho;
-    ortho.loadOrtho(0, width, height, 0, 0, 1);
+    ortho.loadOrtho(0, width, height, 0, -1, 1);
     ortho.copyTo(mOrthoMatrix);
 
     mWidth = width;
@@ -196,6 +206,7 @@
     glClear(GL_COLOR_BUFFER_BIT);
 
     glEnable(GL_SCISSOR_TEST);
+    glScissor(0, 0, mWidth, mHeight);
 
     mSnapshot->clipRect.set(0.0f, 0.0f, mWidth, mHeight);
 }
@@ -291,13 +302,31 @@
 
 void OpenGLRenderer::setScissorFromClip() {
 	const Rect& clip = mSnapshot->getMappedClip();
-	glScissor(clip.left, clip.top, clip.getWidth(), clip.getHeight());
+	glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight());
 }
 
 const Rect& OpenGLRenderer::getClipBounds() {
 	return mSnapshot->clipRect;
 }
 
+bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
+    /*
+     * The documentation of quickReject() indicates that the specified rect
+     * is transformed before being compared to the clip rect. However, the
+     * clip rect is not stored transformed in the snapshot and can thus be
+     * compared directly
+     *
+     * The following code can be used instead to performed a mapped comparison:
+     *
+     *     mSnapshot->transform.mapRect(r);
+     *     const Rect& clip = mSnapshot->getMappedClip();
+     *     return !clip.intersects(r);
+     */
+
+    Rect r(left, top, right, bottom);
+    return !mSnapshot->clipRect.intersects(r);
+}
+
 bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom) {
 	bool clipped = mSnapshot->clipRect.intersect(left, top, right, bottom);
 	if (clipped) {
@@ -312,40 +341,38 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
-	GLfloat a = ((color >> 24) & 0xFF) / 255.0f;
-	GLfloat r = ((color >> 16) & 0xFF) / 255.0f;
-	GLfloat g = ((color >>  8) & 0xFF) / 255.0f;
-	GLfloat b = ((color      ) & 0xFF) / 255.0f;
+    // TODO: Set the transfer mode
+    const Rect& clip = mSnapshot->clipRect;
+    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color);
+}
 
-	// TODO Optimize this section
-	const Rect& clip = mSnapshot->getMappedClip();
+void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* paint) {
+    // TODO Support more than  just color
+    // TODO: Set the transfer mode
+    drawColorRect(left, top, right, bottom, paint->getColor());
+}
 
-	mat4 modelView;
-	modelView.loadScale(clip.getWidth(), clip.getHeight(), 1.0f);
-	modelView.translate(clip.left, clip.top, 0.0f);
+void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, int color) {
+    GLfloat a = ((color >> 24) & 0xFF) / 255.0f;
+    GLfloat r = ((color >> 16) & 0xFF) / 255.0f;
+    GLfloat g = ((color >>  8) & 0xFF) / 255.0f;
+    GLfloat b = ((color      ) & 0xFF) / 255.0f;
 
-	float matrix[16];
-	modelView.copyTo(matrix);
-	// TODO Optimize this section
+    mModelView.loadTranslate(left, top, 0.0f);
+    mModelView.scale(right - left, bottom - top, 1.0f);
 
-	mDrawColorShader->use();
+    mDrawColorShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]);
 
-	glUniformMatrix4fv(mDrawColorShader->projection, 1, GL_FALSE, &mOrthoMatrix[0]);
-	glUniformMatrix4fv(mDrawColorShader->modelView, 1, GL_FALSE, &matrix[0]);
+    const GLvoid* p = &gDrawColorVertices[0].position[0];
 
-	glEnableVertexAttribArray(mDrawColorShader->position);
+    glEnableVertexAttribArray(mDrawColorShader->position);
+    glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE,
+            gDrawColorVertexStride, p);
+    glVertexAttrib4f(mDrawColorShader->color, r, g, b, a);
 
-	GLsizei stride = sizeof(Vertex);
-	const GLvoid* p = &gDrawColorVertices[0].position[0];
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount);
 
-	glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE, stride, p);
-	glVertexAttrib4f(mDrawColorShader->color, r, g, b, a);
-
-	GLsizei vertexCount = sizeof(gDrawColorVertices) / sizeof(Vertex);
-	glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexCount);
-
-	glDisableVertexAttribArray(mDrawColorShader->position);
-	glDisableVertexAttribArray(mDrawColorShader->color);
+    glDisableVertexAttribArray(mDrawColorShader->position);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 88cbc1c..bef4193 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -72,10 +72,9 @@
 	Rect mappedClip;
 }; // class Snapshot
 
-struct Vertex {
+struct SimpleVertex {
 	float position[2];
-	float color[4];
-}; // struct Vertex
+}; // struct SimpleVertex
 
 typedef char* shader;
 
@@ -112,11 +111,15 @@
 public:
 	DrawColorProgram();
 
+	void use(const GLfloat* projectionMatrix, const GLfloat* modelViewMatrix,
+	         const GLfloat* transformMatrix);
+
 	int position;
 	int color;
 
 	int projection;
 	int modelView;
+	int transform;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -145,9 +148,11 @@
     void concatMatrix(SkMatrix* matrix);
 
     const Rect& getClipBounds();
+    bool quickReject(float left, float top, float right, float bottom);
     bool clipRect(float left, float top, float right, float bottom);
 
     void drawColor(int color, SkXfermode::Mode mode);
+    void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
 
 private:
     int saveSnapshot();
@@ -155,12 +160,17 @@
 
     void setScissorFromClip();
 
+    void drawColorRect(float left, float top, float right, float bottom, int color);
+
     // Dimensions of the drawing surface
     int mWidth, mHeight;
 
     // Matrix used for ortho projection in shaders
     float mOrthoMatrix[16];
 
+    // Model-view matrix used to position/size objects
+    mat4 mModelView;
+
     // Number of saved states
     int mSaveCount;
     // Base state
diff --git a/libs/hwui/shaders/drawColor.vert b/libs/hwui/shaders/drawColor.vert
index fd3cb45..4b7f883 100644
--- a/libs/hwui/shaders/drawColor.vert
+++ b/libs/hwui/shaders/drawColor.vert
@@ -5,12 +5,13 @@
 
 uniform mat4 projection;
 uniform mat4 modelView;
+uniform mat4 transform;
 
 varying vec4 outColor;
 
 void main(void) {
 	outColor = color;
-	gl_Position = projection * modelView * position;
+	gl_Position = projection * transform * modelView * position;
 }
 
 );
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java
index 81b9357..14154a8 100644
--- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java
@@ -60,20 +60,32 @@
             canvas.save();
             canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f);
             Log.d(LOG_TAG, "clipRect = " + canvas.getClipBounds());
+            Log.d(LOG_TAG, "rejected = " + canvas.quickReject(100.0f, 100.0f, 110.0f, 110.0f,
+                    Canvas.EdgeType.BW));
+            Log.d(LOG_TAG, "rejected = " + canvas.quickReject(25.0f, 5.0f, 30.0f, 10.0f,
+                    Canvas.EdgeType.BW));
             canvas.restore();
             
             canvas.save();
             canvas.scale(2.0f, 2.0f);
             canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f);
             Log.d(LOG_TAG, "clipRect = " + canvas.getClipBounds());
+            Log.d(LOG_TAG, "rejected = " + canvas.quickReject(50.0f, 50.0f, 60.0f, 60.0f,
+                    Canvas.EdgeType.BW));
+            Log.d(LOG_TAG, "rejected = " + canvas.quickReject(25.0f, 5.0f, 30.0f, 10.0f,
+                    Canvas.EdgeType.BW));
             canvas.restore();
 
             canvas.save();
             canvas.translate(20.0f, 20.0f);
             canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f);
             Log.d(LOG_TAG, "clipRect = " + canvas.getClipBounds());
+            Log.d(LOG_TAG, "rejected = " + canvas.quickReject(80.0f, 80.0f, 90.0f, 90.0f,
+                    Canvas.EdgeType.BW));
+            Log.d(LOG_TAG, "rejected = " + canvas.quickReject(25.0f, 5.0f, 30.0f, 10.0f,
+                    Canvas.EdgeType.BW));
             canvas.restore();
-            
+
             canvas.scale(2.0f, 2.0f);            
             canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f);