Track AA-ness and rect-ness in SkConservativeClip

This is needed so that SkNoPixelsDevice can switch to using
SkConservativeClip and more fully implement the SkDevice API.

Tracking the AA-ness allows SkCanvas/SkDevice::isClipAA() to be more
accurate; previously for recording canvases, it always returns false.
Technically, it will still return false after this CL until
SkNoPixelsDevice is updated to use SkConservativClip's new AA tracking.

Tracking whether or not the clip shape remains an intersection of rects
is similarly meant so that SkDevice's getClipType and
SkCanvas::isClipRect are more accurate. Without this tracking,
SkNoPixelsDevice always claimed the clip was a rectangle. This is not
accurate, even if all it needs to otherwise track is the bounds of the
more complex shape. We got away with it because it doesn't seem to be
critically relied on during any recording steps of clients.

Bug: skia:9283
Change-Id: I3acde969aca9d7eb97a7e1c7ab8374e7230b04fa
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/335825
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Auto-Submit: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index a84e139..d1ec60a 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1664,7 +1664,7 @@
     AutoValidateClip avc(this);
 
     FOR_EACH_TOP_DEVICE(device->clipShader(sh, op));
-
+    fMCRec->fRasterClip.opShader(sh);
     // we don't know how to mutate our conservative bounds, so we don't
 }
 
diff --git a/src/core/SkRasterClip.cpp b/src/core/SkRasterClip.cpp
index 57cb1e5..c71c0b4 100644
--- a/src/core/SkRasterClip.cpp
+++ b/src/core/SkRasterClip.cpp
@@ -63,6 +63,8 @@
 
 void SkConservativeClip::opRect(const SkRect& localRect, const SkMatrix& ctm,
                                 const SkIRect& devBounds, SkRegion::Op op, bool doAA) {
+    this->applyOpParams(op, doAA ? ClipAA::kYes : ClipAA::kNo,
+                        ctm.isScaleTranslate() ? IsRect::kYes : IsRect::kNo);
     SkIRect ir;
     switch (mutate_conservative_op(&op, false)) {
         case kDoNothing_MutateResult:
@@ -81,11 +83,14 @@
 
 void SkConservativeClip::opRRect(const SkRRect& rrect, const SkMatrix& ctm,
                                  const SkIRect& devBounds, SkRegion::Op op, bool doAA) {
+    this->applyOpParams(op, doAA ? ClipAA::kYes : ClipAA::kNo,
+                        (rrect.isRect() && ctm.isScaleTranslate()) ? IsRect::kYes : IsRect:: kNo);
     this->opRect(rrect.getBounds(), ctm, devBounds, op, doAA);
 }
 
 void SkConservativeClip::opPath(const SkPath& path, const SkMatrix& ctm, const SkIRect& devBounds,
                                 SkRegion::Op op, bool doAA) {
+    this->applyOpParams(op, doAA ? ClipAA::kYes : ClipAA::kNo, IsRect::kNo);
     SkIRect ir;
     switch (mutate_conservative_op(&op, path.isInverseFillType())) {
         case kDoNothing_MutateResult:
@@ -104,10 +109,13 @@
 }
 
 void SkConservativeClip::opRegion(const SkRegion& rgn, SkRegion::Op op) {
+    this->applyOpParams(op, ClipAA::kNo, rgn.isRect() ? IsRect::kYes : IsRect::kNo);
     this->opIRect(rgn.getBounds(), op);
 }
 
 void SkConservativeClip::opIRect(const SkIRect& devRect, SkRegion::Op op) {
+    this->applyOpParams(op, ClipAA::kNo, IsRect::kYes);
+
     if (SkRegion::kIntersect_Op == op) {
         if (!fBounds.intersect(devRect)) {
             fBounds.setEmpty();
diff --git a/src/core/SkRasterClip.h b/src/core/SkRasterClip.h
index 10215a2..c490e08 100644
--- a/src/core/SkRasterClip.h
+++ b/src/core/SkRasterClip.h
@@ -16,8 +16,11 @@
 class SkRRect;
 
 class SkConservativeClip {
-    SkIRect         fBounds;
-    const SkIRect*  fClipRestrictionRect;
+    SkIRect         fBounds = SkIRect::MakeEmpty();
+    bool            fIsRect = true;
+    bool            fAA = false;
+
+    const SkIRect*  fClipRestrictionRect = nullptr;
 
     inline void applyClipRestriction(SkRegion::Op op, SkIRect* bounds) {
         if (op >= SkRegion::kUnion_Op && fClipRestrictionRect
@@ -28,19 +31,33 @@
         }
     }
 
-public:
-    SkConservativeClip() : fBounds(SkIRect::MakeEmpty()), fClipRestrictionRect(nullptr) {}
+    enum class ClipAA : bool { kNo = false, kYes = true };
+    enum class IsRect : bool { kNo = false, kYes = true };
 
+    inline void applyOpParams(SkRegion::Op op, ClipAA aa, IsRect rect) {
+        fAA |= (bool) aa;
+        fIsRect &= (op == SkRegion::kIntersect_Op && (bool) rect);
+    }
+
+public:
     bool isEmpty() const { return fBounds.isEmpty(); }
-    bool isRect() const { return true; }
+    bool isRect() const { return fIsRect; }
+    bool isAA() const { return fAA; }
     const SkIRect& getBounds() const { return fBounds; }
 
-    void setEmpty() { fBounds.setEmpty(); }
-    void setRect(const SkIRect& r) { fBounds = r; }
+    void setEmpty() { this->setRect(SkIRect::MakeEmpty()); }
+    void setRect(const SkIRect& r) {
+        fBounds = r;
+        fIsRect = true;
+        fAA = false;
+    }
     void setDeviceClipRestriction(const SkIRect* rect) {
         fClipRestrictionRect = rect;
     }
 
+    void opShader(sk_sp<SkShader>) {
+        fIsRect = false;
+    }
     void opRect(const SkRect&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA);
     void opRRect(const SkRRect&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA);
     void opPath(const SkPath&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA);