Add support for partial invalidates in WebView
Bug #3461349

This change also fixes two bugs that prevented partial invalidates
from working with other views. Both bugs were in our EGL implementation:
they were preventing the caller from comparing the current context/surface
with another context/surface. This was causing HardwareRenderer to always
redraw the entire screen.

Change-Id: I33e096b304d4a0b7e6c8f92930f71d2ece9bebf5
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 9a6a274..fa5479b 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -245,11 +245,12 @@
     private static native void nDestroyDisplayList(int displayList);
 
     @Override
-    public boolean drawDisplayList(DisplayList displayList) {
-        return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
+    public boolean drawDisplayList(DisplayList displayList, Rect dirty) {
+        return nDrawDisplayList(mRenderer,
+                ((GLES20DisplayList) displayList).mNativeDisplayList, dirty);
     }
 
-    private static native boolean nDrawDisplayList(int renderer, int displayList);
+    private static native boolean nDrawDisplayList(int renderer, int displayList, Rect dirty);
 
     ///////////////////////////////////////////////////////////////////////////
     // Hardware layer
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index e6fecc8..cb1003a 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -53,8 +53,13 @@
      * Draws the specified display list onto this canvas.
      * 
      * @param displayList The display list to replay.
+     * @param dirty The dirty region to redraw in the next pass, matters only
+     *        if this method returns true, can be null.
+     * 
+     * @return True if the content of the display list requires another
+     *         drawing pass (invalidate()), false otherwise
      */
-    abstract boolean drawDisplayList(DisplayList displayList);
+    abstract boolean drawDisplayList(DisplayList displayList, Rect dirty);
 
     /**
      * Draws the specified layer onto this canvas.
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index b53aa21..c078c08 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -269,7 +269,7 @@
         static EGLDisplay sEglDisplay;
         static EGLConfig sEglConfig;
 
-        private static Thread sEglThread;        
+        private static Thread sEglThread;
 
         EGLSurface mEglSurface;
         
@@ -284,6 +284,8 @@
         final boolean mTranslucent;
 
         private boolean mDestroyed;
+        
+        private final Rect mRedrawClip = new Rect();
 
         GlRenderer(int glVersion, boolean translucent) {
             mGlVersion = glVersion;
@@ -606,8 +608,13 @@
 
                         DisplayList displayList = view.getDisplayList();
                         if (displayList != null) {
-                            if (canvas.drawDisplayList(displayList)) {
-                                view.invalidate();
+                            if (canvas.drawDisplayList(displayList, mRedrawClip)) {
+                                if (mRedrawClip.isEmpty()) {
+                                    view.invalidate();
+                                } else {
+                                    view.getParent().invalidateChild(view, mRedrawClip);
+                                }
+                                mRedrawClip.setEmpty();
                             }
                         } else {
                             // Shouldn't reach here
@@ -646,8 +653,8 @@
         private int checkCurrent() {
             // TODO: Don't check the current context when we have one per UI thread
             // TODO: Use a threadlocal flag to know whether the surface has changed
-            if (sEgl.eglGetCurrentContext() != sEglContext ||
-                    sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW) != mEglSurface) {
+            if (!sEglContext.equals(sEgl.eglGetCurrentContext()) ||
+                    !mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) {
                 if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) {
                     fallback(true);
                     Log.e(LOG_TAG, "eglMakeCurrent failed " +
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 3153ac5..06d918b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2585,7 +2585,7 @@
                     }
                 } else {
                     child.mPrivateFlags &= ~DIRTY_MASK;
-                    ((HardwareCanvas) canvas).drawDisplayList(displayList);
+                    ((HardwareCanvas) canvas).drawDisplayList(displayList, null);
                 }
             }
         } else if (cache != null) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index f0a3a0f..eb7269b 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -351,7 +351,8 @@
 
     private ZoomManager mZoomManager;
 
-    private Rect mGLRectViewport = new Rect();
+    private final Rect mGLRectViewport = new Rect();
+    private final Rect mViewRectViewport = new Rect();
     private boolean mGLViewportEmpty = false;
 
     /**
@@ -4152,7 +4153,7 @@
 
         if (canvas.isHardwareAccelerated()) {
             int functor = nativeGetDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
-                    getScale(), extras);
+                    mGLViewportEmpty ? null : mViewRectViewport, getScale(), extras);
             ((HardwareCanvas) canvas).callDrawGLFunction(functor);
         } else {
             DrawFilter df = null;
@@ -5258,6 +5259,7 @@
             // Then need to invert the Y axis, just for GL
             View rootView = getRootView();
             int rootViewHeight = rootView.getHeight();
+            mViewRectViewport.set(mGLRectViewport);
             int savedWebViewBottom = mGLRectViewport.bottom;
             mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeight();
             mGLRectViewport.top = rootViewHeight - savedWebViewBottom;
@@ -5265,7 +5267,8 @@
         } else {
             mGLViewportEmpty = true;
         }
-        nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport);
+        nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
+                mGLViewportEmpty ? null : mViewRectViewport);
     }
 
     /**
@@ -8531,8 +8534,9 @@
             boolean splitIfNeeded);
     private native void     nativeDumpDisplayTree(String urlOrNull);
     private native boolean  nativeEvaluateLayersAnimations();
-    private native int      nativeGetDrawGLFunction(Rect rect, float scale, int extras);
-    private native void     nativeUpdateDrawGLFunction(Rect rect);
+    private native int      nativeGetDrawGLFunction(Rect rect, Rect viewRect,
+            float scale, int extras);
+    private native void     nativeUpdateDrawGLFunction(Rect rect, Rect viewRect);
     private native boolean  nativeDrawGL(Rect rect, float scale, int extras);
     private native void     nativeExtendSelection(int x, int y);
     private native int      nativeFindAll(String findLower, String findUpper,
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 7a609a5..a78f660 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -35,7 +35,6 @@
 
 #include <DisplayListRenderer.h>
 #include <LayerRenderer.h>
-#include <OpenGLDebugRenderer.h>
 #include <OpenGLRenderer.h>
 #include <SkiaShader.h>
 #include <SkiaColorFilter.h>
@@ -60,7 +59,6 @@
 
 // Debug
 #define DEBUG_RENDERER 0
-#define PROFILE_RENDERER 0
 
 // Debug
 #if DEBUG_RENDERER
@@ -99,11 +97,7 @@
 
 static OpenGLRenderer* android_view_GLES20Canvas_createRenderer(JNIEnv* env, jobject clazz) {
     RENDERER_LOGD("Create OpenGLRenderer");
-#if PROFILE_RENDERER
-    return new OpenGLDebugRenderer;
-#else
     return new OpenGLRenderer;
-#endif
 }
 
 static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject clazz,
@@ -139,7 +133,8 @@
 
 static bool android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, Functor *functor) {
-    return renderer->callDrawGLFunction(functor);
+    android::uirenderer::Rect dirty;
+    return renderer->callDrawGLFunction(functor, dirty);
 }
 
 // ----------------------------------------------------------------------------
@@ -503,8 +498,14 @@
 }
 
 static bool android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
-        jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList) {
-    return renderer->drawDisplayList(displayList);
+        jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList, jobject dirty) {
+    android::uirenderer::Rect bounds;
+    bool redraw = renderer->drawDisplayList(displayList, bounds);
+    if (redraw && dirty != NULL) {
+        env->CallVoidMethod(dirty, gRectClassInfo.set,
+                int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
+    }
+    return redraw;
 }
 
 // ----------------------------------------------------------------------------
@@ -663,7 +664,8 @@
     { "nGetDisplayList",         "(I)I",       (void*) android_view_GLES20Canvas_getDisplayList },
     { "nDestroyDisplayList",     "(I)V",       (void*) android_view_GLES20Canvas_destroyDisplayList },
     { "nGetDisplayListRenderer", "(I)I",       (void*) android_view_GLES20Canvas_getDisplayListRenderer },
-    { "nDrawDisplayList",        "(II)Z",      (void*) android_view_GLES20Canvas_drawDisplayList },
+    { "nDrawDisplayList",        "(IILandroid/graphics/Rect;)Z",
+                                               (void*) android_view_GLES20Canvas_drawDisplayList },
 
     { "nInterrupt",              "(I)V",       (void*) android_view_GLES20Canvas_interrupt },
     { "nResume",                 "(I)V",       (void*) android_view_GLES20Canvas_resume },
diff --git a/include/utils/Functor.h b/include/utils/Functor.h
index 3955bc3..565f4a3 100644
--- a/include/utils/Functor.h
+++ b/include/utils/Functor.h
@@ -26,6 +26,7 @@
     Functor() {}
     virtual ~Functor() {}
     virtual status_t operator ()() { return true; }
+    virtual status_t operator ()(float* data, uint32_t len) { return true; }
 };
 
 }; // namespace android
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 38e0848..f4a0161 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -15,7 +15,6 @@
 		LayerCache.cpp \
 		LayerRenderer.cpp \
 		Matrix.cpp \
-		OpenGLDebugRenderer.cpp \
 		OpenGLRenderer.cpp \
 		Patch.cpp \
 		PatchCache.cpp \
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index d5d2ba0..737fa02 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -166,7 +166,7 @@
 void DisplayList::init() {
 }
 
-bool DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) {
+bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) {
     bool needsInvalidate = false;
     TextContainer text;
     mReader.rewind();
@@ -189,7 +189,7 @@
             case DrawGLFunction: {
                 Functor *functor = (Functor *) getInt();
                 DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
-                needsInvalidate |= renderer.callDrawGLFunction(functor);
+                needsInvalidate |= renderer.callDrawGLFunction(functor, dirty);
             }
             break;
             case Save: {
@@ -287,7 +287,7 @@
                 DisplayList* displayList = getDisplayList();
                 DISPLAY_LIST_LOGD("%s%s %p, %d", (char*) indent, OP_NAMES[op],
                     displayList, level + 1);
-                needsInvalidate |= renderer.drawDisplayList(displayList, level + 1);
+                needsInvalidate |= renderer.drawDisplayList(displayList, dirty, level + 1);
             }
             break;
             case DrawLayer: {
@@ -589,7 +589,8 @@
 void DisplayListRenderer::resume() {
 }
 
-bool DisplayListRenderer::callDrawGLFunction(Functor *functor) {
+bool DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
+    // Ignore dirty during recording, it matters only when we replay
     addOp(DisplayList::DrawGLFunction);
     addInt((int) functor);
     return false; // No invalidate needed at record-time
@@ -673,7 +674,9 @@
     return OpenGLRenderer::clipRect(left, top, right, bottom, op);
 }
 
-bool DisplayListRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) {
+bool DisplayListRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, uint32_t level) {
+    // dirty is an out parameter and should not be recorded,
+    // it matters only when replaying the display list
     addOp(DisplayList::DrawDisplayList);
     addDisplayList(displayList);
     return false;
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index e8f189d..f24545d 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -103,7 +103,7 @@
 
     void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
 
-    bool replay(OpenGLRenderer& renderer, uint32_t level = 0);
+    bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
 
 private:
     void init();
@@ -214,7 +214,7 @@
     void prepareDirty(float left, float top, float right, float bottom, bool opaque);
     void finish();
 
-    bool callDrawGLFunction(Functor *functor);
+    bool callDrawGLFunction(Functor *functor, Rect& dirty);
 
     void interrupt();
     void resume();
@@ -238,7 +238,7 @@
 
     bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
-    bool drawDisplayList(DisplayList* displayList, uint32_t level = 0);
+    bool drawDisplayList(DisplayList* displayList, Rect& dirty, uint32_t level = 0);
     void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
diff --git a/libs/hwui/OpenGLDebugRenderer.cpp b/libs/hwui/OpenGLDebugRenderer.cpp
deleted file mode 100644
index 05870bb..0000000
--- a/libs/hwui/OpenGLDebugRenderer.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "OpenGLRenderer"
-
-#include <utils/StopWatch.h>
-
-#include "OpenGLDebugRenderer.h"
-
-namespace android {
-namespace uirenderer {
-
-void OpenGLDebugRenderer::prepareDirty(float left, float top,
-        float right, float bottom, bool opaque) {
-    mPrimitivesCount = 0;
-    LOGD("========= Frame start =========");
-    OpenGLRenderer::prepareDirty(left, top, right, bottom, opaque);
-}
-
-void OpenGLDebugRenderer::finish() {
-    LOGD("========= Frame end =========");
-    LOGD("Primitives draw count = %d", mPrimitivesCount);
-    OpenGLRenderer::finish();
-}
-
-void OpenGLDebugRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
-    mPrimitivesCount++;
-    StopWatch w("composeLayer");
-    return OpenGLRenderer::composeLayer(current, previous);
-}
-
-int OpenGLDebugRenderer::saveLayer(float left, float top, float right, float bottom,
-        SkPaint* p, int flags) {
-    mPrimitivesCount++;
-    StopWatch w("saveLayer");
-    return OpenGLRenderer::saveLayer(left, top, right, bottom, p, flags);
-}
-
-bool OpenGLDebugRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) {
-    mPrimitivesCount++;
-    StopWatch w("drawDisplayList");
-    return OpenGLRenderer::drawDisplayList(displayList);
-}
-
-void OpenGLDebugRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawLayer");
-    OpenGLRenderer::drawLayer(layer, x, y, paint);
-}
-
-void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float left, float top,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawBitmap");
-    OpenGLRenderer::drawBitmap(bitmap, left, top, paint);
-}
-
-void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawBitmapMatrix");
-    OpenGLRenderer::drawBitmap(bitmap, matrix, paint);
-}
-
-void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
-        float srcRight, float srcBottom, float dstLeft, float dstTop,
-        float dstRight, float dstBottom, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawBitmapRect");
-    OpenGLRenderer::drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
-            dstLeft, dstTop, dstRight, dstBottom, paint);
-}
-
-void OpenGLDebugRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-        const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-        float left, float top, float right, float bottom, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawPatch");
-    OpenGLRenderer::drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors,
-            left, top, right, bottom, paint);
-}
-
-void OpenGLDebugRenderer::drawColor(int color, SkXfermode::Mode mode) {
-    mPrimitivesCount++;
-    StopWatch w("drawColor");
-    OpenGLRenderer::drawColor(color, mode);
-}
-
-void OpenGLDebugRenderer::drawRect(float left, float top, float right, float bottom,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawRect");
-    OpenGLRenderer::drawRect(left, top, right, bottom, paint);
-}
-
-void OpenGLDebugRenderer::drawRoundRect(float left, float top, float right, float bottom,
-        float rx, float ry, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawRoundRect");
-    OpenGLRenderer::drawRoundRect(left, top, right, bottom, rx, ry, paint);
-}
-
-void OpenGLDebugRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawCircle");
-    OpenGLRenderer::drawCircle(x, y, radius, paint);
-}
-
-void OpenGLDebugRenderer::drawOval(float left, float top, float right, float bottom,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawOval");
-    OpenGLRenderer::drawOval(left, top, right, bottom, paint);
-}
-
-void OpenGLDebugRenderer::drawArc(float left, float top, float right, float bottom,
-        float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawArc");
-    OpenGLRenderer::drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint);
-}
-
-void OpenGLDebugRenderer::drawPath(SkPath* path, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawPath");
-    OpenGLRenderer::drawPath(path, paint);
-}
-
-void OpenGLDebugRenderer::drawLines(float* points, int count, SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawLines");
-    OpenGLRenderer::drawLines(points, count, paint);
-}
-
-void OpenGLDebugRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
-        SkPaint* paint) {
-    mPrimitivesCount++;
-    StopWatch w("drawText");
-    OpenGLRenderer::drawText(text, bytesCount, count, x, y, paint);
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h
deleted file mode 100644
index 1a18a67..0000000
--- a/libs/hwui/OpenGLDebugRenderer.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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_HWUI_OPENGL_DEBUG_RENDERER_H
-#define ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
-
-#include "OpenGLRenderer.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Renderer
-///////////////////////////////////////////////////////////////////////////////
-
-class OpenGLDebugRenderer: public OpenGLRenderer {
-public:
-    OpenGLDebugRenderer(): mPrimitivesCount(0) {
-    }
-
-    ~OpenGLDebugRenderer() {
-    }
-
-    void prepareDirty(float left, float top, float right, float bottom, bool opaque);
-    void finish();
-
-    int saveLayer(float left, float top, float right, float bottom,
-            SkPaint* p, int flags);
-
-    bool drawDisplayList(DisplayList* displayList, uint32_t level = 0);
-    void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
-            float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, SkPaint* paint);
-    void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
-            const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-            float left, float top, float right, float bottom, SkPaint* paint);
-    void drawColor(int color, SkXfermode::Mode mode);
-    void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
-    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 drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, 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);
-
-protected:
-    void composeLayer(sp<Snapshot> current, sp<Snapshot> previous);
-
-private:
-    uint32_t mPrimitivesCount;
-
-}; // class OpenGLDebugRenderer
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index dfca7eb..1f65201 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -210,7 +210,7 @@
     glBlendEquation(GL_FUNC_ADD);
 }
 
-bool OpenGLRenderer::callDrawGLFunction(Functor *functor) {
+bool OpenGLRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
     interrupt();
     if (mDirtyClip) {
         setScissorFromClip();
@@ -226,9 +226,16 @@
     }
 #endif
 
-    status_t result = (*functor)();
+    float bounds[4];
+    status_t result = (*functor)(&bounds[0], 4);
+
+    if (result != 0) {
+        Rect localDirty(bounds[0], bounds[1], bounds[2], bounds[3]);
+        dirty.unionWith(localDirty);
+    }
+
     resume();
-    return (result == 0) ? false : true;
+    return result != 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1057,11 +1064,11 @@
 // Drawing
 ///////////////////////////////////////////////////////////////////////////////
 
-bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) {
+bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, uint32_t level) {
     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
     // will be performed by the display list itself
     if (displayList) {
-        return displayList->replay(*this, level);
+        return displayList->replay(*this, dirty, level);
     }
     return false;
 }
@@ -1522,7 +1529,6 @@
             break;
     }
 
-    // TODO: Handle paint->getTextScaleX()
     const float oldX = x;
     const float oldY = y;
     const bool pureTranslate = mSnapshot->transform->isPureTranslate();
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 7bbf034..9d86388 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -70,7 +70,7 @@
     virtual void interrupt();
     virtual void resume();
 
-    virtual bool callDrawGLFunction(Functor *functor);
+    virtual bool callDrawGLFunction(Functor *functor, Rect& dirty);
 
     int getSaveCount() const;
     virtual int save(int flags);
@@ -96,7 +96,7 @@
     bool quickReject(float left, float top, float right, float bottom);
     virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
-    virtual bool drawDisplayList(DisplayList* displayList, uint32_t level = 0);
+    virtual bool drawDisplayList(DisplayList* displayList, Rect& dirty, uint32_t level = 0);
     virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index 62c4250..d46686d 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -42,6 +42,17 @@
 
         textSize = paint->getTextSize();
         typeface = paint->getTypeface();
+
+        flags = 0;
+        if (paint->isFakeBoldText()) {
+            flags |= Font::kFakeBold;
+        }
+
+        const float skewX = paint->getTextSkewX();
+        italicStyle = *(uint32_t*) &skewX;
+
+        const float scaleXFloat = paint->getTextScaleX();
+        scaleX = *(uint32_t*) &scaleXFloat;
     }
 
     ~ShadowText() {
@@ -51,6 +62,9 @@
     uint32_t len;
     float textSize;
     SkTypeface* typeface;
+    uint32_t flags;
+    uint32_t italicStyle;
+    uint32_t scaleX;
     const char16_t* text;
     String16 str;
 
@@ -65,7 +79,13 @@
             LTE_INT(radius) {
                 LTE_FLOAT(textSize) {
                     LTE_INT(typeface) {
-                        return strncmp16(text, rhs.text, len >> 1) < 0;
+                        LTE_INT(flags) {
+                            LTE_INT(italicStyle) {
+                                LTE_INT(scaleX) {
+                                    return strncmp16(text, rhs.text, len >> 1) < 0;
+                                }
+                            }
+                        }
                     }
                 }
             }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
index e7f431c..3c8432e 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
@@ -58,10 +58,12 @@
             mScaledPaint = new Paint();
             mScaledPaint.setAntiAlias(true);
             mScaledPaint.setTextSize(16.0f);
+            mScaledPaint.setShadowLayer(3.0f, 3.0f, 3.0f, 0xff00ff00);
 
             mSkewPaint = new Paint();
             mSkewPaint.setAntiAlias(true);
-            mSkewPaint.setTextSize(16.0f);            
+            mSkewPaint.setTextSize(16.0f);
+            mSkewPaint.setShadowLayer(3.0f, 3.0f, 3.0f, 0xff000000);
         }
 
         @Override
@@ -106,11 +108,11 @@
             mStrikePaint.setUnderlineText(true);
             
             mSkewPaint.setTextSkewX(-0.25f);
-            canvas.drawText("Hello OpenGL renderer!", 680, 200, mSkewPaint);
+            canvas.drawText("Hello OpenGL renderer!", 980, 200, mSkewPaint);
             mSkewPaint.setTextSkewX(0.5f);
-            canvas.drawText("Hello OpenGL renderer!", 680, 230, mSkewPaint);
+            canvas.drawText("Hello OpenGL renderer!", 980, 230, mSkewPaint);
             mSkewPaint.setTextSkewX(0.0f);
-            canvas.drawText("Hello OpenGL renderer!", 680, 260, mSkewPaint);
+            canvas.drawText("Hello OpenGL renderer!", 980, 260, mSkewPaint);
 
             mScaledPaint.setTextScaleX(0.5f);
             canvas.drawText("Hello OpenGL renderer!", 500, 200, mScaledPaint);
@@ -125,4 +127,4 @@
             canvas.restore();
         }
     }
-}
\ No newline at end of file
+}