Fix various draw ops that may incorrectly not scissor

bug:8965976

Also consolidates quickReject scissor-ing and scissor-less paths.
Renamed plain 'quickReject' method, as it has sideEffects beyond what
the java and skia canvases do.

Change-Id: I4bdf874d3c8f469d283eae1e71c5e7ea53d47016
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 5866404..f3592a3 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -298,7 +298,7 @@
 
 static bool android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom) {
-    return renderer->quickReject(left, top, right, bottom);
+    return renderer->quickRejectNoScissor(left, top, right, bottom);
 }
 
 static bool android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject clazz,
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index f25ec2d..0d4dd1a 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -356,22 +356,26 @@
                     level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
         }
     }
+
+    bool clipToBoundsNeeded = mClipToBounds;
     if (mAlpha < 1) {
         if (mCaching) {
             ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha);
+            clipToBoundsNeeded = false; // clipping done by layer
         } else if (!mHasOverlappingRendering) {
             ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha);
         } else {
             int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
-            if (mClipToBounds) {
+            if (clipToBoundsNeeded) {
                 flags |= SkCanvas::kClipToLayer_SaveFlag;
+                clipToBoundsNeeded = false; // clipping done by save layer
             }
             ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
                     (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
                     (int)(mAlpha * 255), flags);
         }
     }
-    if (mClipToBounds && !mCaching) {
+    if (clipToBoundsNeeded) {
         ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
                 (float) mRight - mLeft, (float) mBottom - mTop);
     }
@@ -406,9 +410,11 @@
             renderer.concatMatrix(mTransformMatrix);
         }
     }
+    bool clipToBoundsNeeded = mClipToBounds;
     if (mAlpha < 1) {
         if (mCaching) {
             renderer.setOverrideLayerAlpha(mAlpha);
+            clipToBoundsNeeded = false; // clipping done by layer
         } else if (!mHasOverlappingRendering) {
             renderer.scaleAlpha(mAlpha);
         } else {
@@ -416,15 +422,16 @@
             // have to pass it into this call. In fact, this information might be in the
             // location/size info that we store with the new native transform data.
             int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
-            if (mClipToBounds) {
+            if (clipToBoundsNeeded) {
                 saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
+                clipToBoundsNeeded = false; // clipping done by saveLayer
             }
             handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop,
                     mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT,
                     mClipToBounds);
         }
     }
-    if (mClipToBounds && !mCaching) {
+    if (clipToBoundsNeeded) {
         handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op),
                 PROPERTY_SAVECOUNT, mClipToBounds);
     }
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index c68cc06..05f43a9 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -993,6 +993,10 @@
     const Rect& rect = layer->layer;
     const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;
 
+    bool clipRequired = false;
+    quickRejectNoScissor(rect, &clipRequired); // safely ignore return, should never be rejected
+    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
+
     if (fboLayer) {
         endTiling();
 
@@ -1568,8 +1572,9 @@
     return mSnapshot->getLocalClip();
 }
 
-bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom) {
-    if (mSnapshot->isIgnored()) {
+bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom,
+        bool* clipRequired) {
+    if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
         return true;
     }
 
@@ -1580,23 +1585,10 @@
     Rect clipRect(*mSnapshot->clipRect);
     clipRect.snapToPixelBoundaries();
 
-    return !clipRect.intersects(r);
-}
+    if (!clipRect.intersects(r)) return true;
 
-bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom,
-        Rect& transformed, Rect& clip) {
-    if (mSnapshot->isIgnored()) {
-        return true;
-    }
-
-    transformed.set(left, top, right, bottom);
-    currentTransform().mapRect(transformed);
-    transformed.snapToPixelBoundaries();
-
-    clip.set(*mSnapshot->clipRect);
-    clip.snapToPixelBoundaries();
-
-    return !clip.intersects(transformed);
+    if (clipRequired) *clipRequired = !clipRect.contains(r);
+    return false;
 }
 
 bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom,
@@ -1610,23 +1602,15 @@
 }
 
 bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
-    if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
+    bool clipRequired = false;
+    if (quickRejectNoScissor(left, top, right, bottom, &clipRequired)) {
         return true;
     }
 
-    Rect r(left, top, right, bottom);
-    currentTransform().mapRect(r);
-    r.snapToPixelBoundaries();
-
-    Rect clipRect(*mSnapshot->clipRect);
-    clipRect.snapToPixelBoundaries();
-
-    bool rejected = !clipRect.intersects(r);
-    if (!isDeferred() && !rejected) {
-        mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clipRect.contains(r));
+    if (!isDeferred()) {
+        mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
     }
-
-    return rejected;
+    return false;
 }
 
 void OpenGLRenderer::debugClip() {
@@ -2163,6 +2147,9 @@
         return DrawGlInfo::kStatusDone;
     }
 
+    // TODO: use quickReject on bounds from vertices
+    mCaches.enableScissor();
+
     float left = FLT_MAX;
     float top = FLT_MAX;
     float right = FLT_MIN;
@@ -2829,6 +2816,8 @@
         return DrawGlInfo::kStatusDone;
     }
 
+    mCaches.enableScissor();
+
     float x = 0.0f;
     float y = 0.0f;
     const bool pureTranslate = currentTransform().isPureTranslate();
@@ -2984,6 +2973,9 @@
         return DrawGlInfo::kStatusDone;
     }
 
+    // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
+    mCaches.enableScissor();
+
     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
     fontRenderer.setFont(paint, mat4::identity());
     fontRenderer.setTextureFiltering(true);
@@ -3059,10 +3051,9 @@
         }
     }
 
-    Rect transformed;
-    Rect clip;
+    bool clipRequired = false;
     const bool rejected = quickRejectNoScissor(x, y,
-            x + layer->layer.getWidth(), y + layer->layer.getHeight(), transformed, clip);
+            x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired);
 
     if (rejected) {
         if (transform && !transform->isIdentity()) {
@@ -3073,7 +3064,7 @@
 
     updateLayer(layer, true);
 
-    mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clip.contains(transformed));
+    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
     mCaches.activeTexture(0);
 
     if (CC_LIKELY(!layer->region.isEmpty())) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index ad9b1b9..5b7f90d 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -252,11 +252,31 @@
     virtual void concatMatrix(SkMatrix* matrix);
 
     ANDROID_API const Rect& getClipBounds();
-    ANDROID_API bool quickReject(float left, float top, float right, float bottom);
+
+    /**
+     * Performs a quick reject but adjust the bounds to account for stroke width if necessary
+     */
+    bool quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint);
+
+    /**
+     * Returns false and sets scissor based upon bounds if drawing won't be clipped out
+     */
+    bool quickReject(float left, float top, float right, float bottom);
     bool quickReject(const Rect& bounds) {
         return quickReject(bounds.left, bounds.top, bounds.right, bounds.bottom);
     }
-    bool quickRejectNoScissor(float left, float top, float right, float bottom);
+
+    /**
+     * Same as quickReject, without the scissor, instead returning clipRequired through pointer.
+     * clipRequired will be only set if not rejected
+     */
+    ANDROID_API bool quickRejectNoScissor(float left, float top, float right, float bottom,
+            bool* clipRequired = NULL);
+    bool quickRejectNoScissor(const Rect& bounds, bool* clipRequired = NULL) {
+        return quickRejectNoScissor(bounds.left, bounds.top, bounds.right, bounds.bottom,
+                clipRequired);
+    }
+
     virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
     virtual bool clipPath(SkPath* path, SkRegion::Op op);
     virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
@@ -604,18 +624,6 @@
     void setStencilFromClip();
 
     /**
-     * Performs a quick reject but does not affect the scissor. Returns
-     * the transformed rect to test and the current clip.
-     */
-    bool quickRejectNoScissor(float left, float top, float right, float bottom,
-            Rect& transformed, Rect& clip);
-
-    /**
-     * Performs a quick reject but adjust the bounds to account for stroke width if necessary
-     */
-    bool quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint);
-
-    /**
      * Given the local bounds of the layer, calculates ...
      */
     void calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer);
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 87c6c105..7531769 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace uirenderer {
 
-#define RECT_STRING "%4.2f %4.2f %4.2f %4.2f"
+#define RECT_STRING "%7.2f %7.2f %7.2f %7.2f"
 #define RECT_ARGS(r) \
     (r).left, (r).top, (r).right, (r).bottom