Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2010 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef SkRasterClip_DEFINED
      9 #define SkRasterClip_DEFINED
     10 
     11 #include "SkRegion.h"
     12 #include "SkAAClip.h"
     13 
     14 class SkRRect;
     15 
     16 class SkConservativeClip {
     17     SkIRect         fBounds;
     18     const SkIRect*  fClipRestrictionRect;
     19 
     20     inline void applyClipRestriction(SkRegion::Op op, SkIRect* bounds) {
     21         if (op >= SkRegion::kUnion_Op && fClipRestrictionRect
     22             && !fClipRestrictionRect->isEmpty()) {
     23             if (!bounds->intersect(*fClipRestrictionRect)) {
     24                 bounds->setEmpty();
     25             }
     26         }
     27     }
     28 
     29 public:
     30     SkConservativeClip() : fBounds(SkIRect::MakeEmpty()), fClipRestrictionRect(nullptr) {}
     31 
     32     bool isEmpty() const { return fBounds.isEmpty(); }
     33     bool isRect() const { return true; }
     34     const SkIRect& getBounds() const { return fBounds; }
     35 
     36     void setEmpty() { fBounds.setEmpty(); }
     37     void setRect(const SkIRect& r) { fBounds = r; }
     38     void setDeviceClipRestriction(const SkIRect* rect) {
     39         fClipRestrictionRect = rect;
     40     }
     41 
     42     void opRect(const SkRect&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA);
     43     void opRRect(const SkRRect&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA);
     44     void opPath(const SkPath&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA);
     45     void opRegion(const SkRegion&, SkRegion::Op);
     46     void opIRect(const SkIRect&, SkRegion::Op);
     47 };
     48 
     49 /**
     50  *  Wraps a SkRegion and SkAAClip, so we have a single object that can represent either our
     51  *  BW or antialiased clips.
     52  *
     53  *  This class is optimized for the raster backend of canvas, but can be expense to keep up2date,
     54  *  so it supports a runtime option (force-conservative-rects) to turn it into a super-fast
     55  *  rect-only tracker. The gpu backend uses this since it does not need the result (it uses
     56  *  SkClipStack instead).
     57  */
     58 class SkRasterClip {
     59 public:
     60     SkRasterClip();
     61     SkRasterClip(const SkIRect&);
     62     SkRasterClip(const SkRegion&);
     63     SkRasterClip(const SkRasterClip&);
     64     ~SkRasterClip();
     65 
     66     // Only compares the current state. Does not compare isForceConservativeRects(), so that field
     67     // could be different but this could still return true.
     68     bool operator==(const SkRasterClip&) const;
     69     bool operator!=(const SkRasterClip& other) const {
     70         return !(*this == other);
     71     }
     72 
     73     bool isBW() const { return fIsBW; }
     74     bool isAA() const { return !fIsBW; }
     75     const SkRegion& bwRgn() const { SkASSERT(fIsBW); return fBW; }
     76     const SkAAClip& aaRgn() const { SkASSERT(!fIsBW); return fAA; }
     77 
     78     bool isEmpty() const {
     79         SkASSERT(this->computeIsEmpty() == fIsEmpty);
     80         return fIsEmpty;
     81     }
     82 
     83     bool isRect() const {
     84         SkASSERT(this->computeIsRect() == fIsRect);
     85         return fIsRect;
     86     }
     87 
     88     bool isComplex() const;
     89     const SkIRect& getBounds() const;
     90 
     91     bool setEmpty();
     92     bool setRect(const SkIRect&);
     93 
     94     bool op(const SkIRect&, SkRegion::Op);
     95     bool op(const SkRegion&, SkRegion::Op);
     96     bool op(const SkRect&, const SkMatrix& matrix, const SkIRect&, SkRegion::Op, bool doAA);
     97     bool op(const SkRRect&, const SkMatrix& matrix, const SkIRect&, SkRegion::Op, bool doAA);
     98     bool op(const SkPath&, const SkMatrix& matrix, const SkIRect&, SkRegion::Op, bool doAA);
     99 
    100     void translate(int dx, int dy, SkRasterClip* dst) const;
    101     void translate(int dx, int dy) {
    102         this->translate(dx, dy, this);
    103     }
    104 
    105     bool quickContains(const SkIRect& rect) const;
    106     bool quickContains(int left, int top, int right, int bottom) const {
    107         return quickContains(SkIRect::MakeLTRB(left, top, right, bottom));
    108     }
    109 
    110     /**
    111      *  Return true if this region is empty, or if the specified rectangle does
    112      *  not intersect the region. Returning false is not a guarantee that they
    113      *  intersect, but returning true is a guarantee that they do not.
    114      */
    115     bool quickReject(const SkIRect& rect) const {
    116         return !SkIRect::Intersects(this->getBounds(), rect);
    117     }
    118 
    119     // hack for SkCanvas::getTotalClip
    120     const SkRegion& forceGetBW();
    121 
    122 #ifdef SK_DEBUG
    123     void validate() const;
    124 #else
    125     void validate() const {}
    126 #endif
    127 
    128     void setDeviceClipRestriction(const SkIRect* rect) {
    129         fClipRestrictionRect = rect;
    130     }
    131 
    132 private:
    133     SkRegion    fBW;
    134     SkAAClip    fAA;
    135     bool        fIsBW;
    136     // these 2 are caches based on querying the right obj based on fIsBW
    137     bool        fIsEmpty;
    138     bool        fIsRect;
    139     const SkIRect*    fClipRestrictionRect = nullptr;
    140 
    141     bool computeIsEmpty() const {
    142         return fIsBW ? fBW.isEmpty() : fAA.isEmpty();
    143     }
    144 
    145     bool computeIsRect() const {
    146         return fIsBW ? fBW.isRect() : fAA.isRect();
    147     }
    148 
    149     bool updateCacheAndReturnNonEmpty(bool detectAARect = true) {
    150         fIsEmpty = this->computeIsEmpty();
    151 
    152         // detect that our computed AA is really just a (hard-edged) rect
    153         if (detectAARect && !fIsEmpty && !fIsBW && fAA.isRect()) {
    154             fBW.setRect(fAA.getBounds());
    155             fAA.setEmpty(); // don't need this guy anymore
    156             fIsBW = true;
    157         }
    158 
    159         fIsRect = this->computeIsRect();
    160         return !fIsEmpty;
    161     }
    162 
    163     void convertToAA();
    164 
    165     bool setPath(const SkPath& path, const SkRegion& clip, bool doAA);
    166     bool setPath(const SkPath& path, const SkIRect& clip, bool doAA);
    167     bool op(const SkRasterClip&, SkRegion::Op);
    168     bool setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse);
    169 
    170     inline void applyClipRestriction(SkRegion::Op op, SkIRect* bounds) {
    171         if (op >= SkRegion::kUnion_Op && fClipRestrictionRect
    172             && !fClipRestrictionRect->isEmpty()) {
    173             if (!bounds->intersect(*fClipRestrictionRect)) {
    174                 bounds->setEmpty();
    175             }
    176         }
    177     }
    178 
    179     inline void applyClipRestriction(SkRegion::Op op, SkRect* bounds) {
    180         if (op >= SkRegion::kUnion_Op && fClipRestrictionRect
    181             && !fClipRestrictionRect->isEmpty()) {
    182             if (!bounds->intersect(SkRect::Make(*fClipRestrictionRect))) {
    183                 bounds->setEmpty();
    184             }
    185         }
    186     }
    187 };
    188 
    189 class SkAutoRasterClipValidate : SkNoncopyable {
    190 public:
    191     SkAutoRasterClipValidate(const SkRasterClip& rc) : fRC(rc) {
    192         fRC.validate();
    193     }
    194     ~SkAutoRasterClipValidate() {
    195         fRC.validate();
    196     }
    197 private:
    198     const SkRasterClip& fRC;
    199 };
    200 #define SkAutoRasterClipValidate(...) SK_REQUIRE_LOCAL_VAR(SkAutoRasterClipValidate)
    201 
    202 #ifdef SK_DEBUG
    203     #define AUTO_RASTERCLIP_VALIDATE(rc)    SkAutoRasterClipValidate arcv(rc)
    204 #else
    205     #define AUTO_RASTERCLIP_VALIDATE(rc)
    206 #endif
    207 
    208 ///////////////////////////////////////////////////////////////////////////////
    209 
    210 /**
    211  *  Encapsulates the logic of deciding if we need to change/wrap the blitter
    212  *  for aaclipping. If so, getRgn and getBlitter return modified values. If
    213  *  not, they return the raw blitter and (bw) clip region.
    214  *
    215  *  We need to keep the constructor/destructor cost as small as possible, so we
    216  *  can freely put this guy on the stack, and not pay too much for the case when
    217  *  we're really BW anyways.
    218  */
    219 class SkAAClipBlitterWrapper {
    220 public:
    221     SkAAClipBlitterWrapper();
    222     SkAAClipBlitterWrapper(const SkRasterClip&, SkBlitter*);
    223     SkAAClipBlitterWrapper(const SkAAClip*, SkBlitter*);
    224 
    225     void init(const SkRasterClip&, SkBlitter*);
    226 
    227     const SkIRect& getBounds() const {
    228         SkASSERT(fClipRgn);
    229         return fClipRgn->getBounds();
    230     }
    231     const SkRegion& getRgn() const {
    232         SkASSERT(fClipRgn);
    233         return *fClipRgn;
    234     }
    235     SkBlitter* getBlitter() {
    236         SkASSERT(fBlitter);
    237         return fBlitter;
    238     }
    239 
    240 private:
    241     SkRegion        fBWRgn;
    242     SkAAClipBlitter fAABlitter;
    243     // what we return
    244     const SkRegion* fClipRgn;
    245     SkBlitter* fBlitter;
    246 };
    247 
    248 #endif
    249