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