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 #include "SkRasterClip.h"
      9 
     10 
     11 SkRasterClip::SkRasterClip() {
     12     fIsBW = true;
     13     fIsEmpty = true;
     14     fIsRect = false;
     15     SkDEBUGCODE(this->validate();)
     16 }
     17 
     18 SkRasterClip::SkRasterClip(const SkRasterClip& src) {
     19     AUTO_RASTERCLIP_VALIDATE(src);
     20 
     21     fIsBW = src.fIsBW;
     22     if (fIsBW) {
     23         fBW = src.fBW;
     24     } else {
     25         fAA = src.fAA;
     26     }
     27 
     28     fIsEmpty = src.isEmpty();
     29     fIsRect = src.isRect();
     30     SkDEBUGCODE(this->validate();)
     31 }
     32 
     33 SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
     34     fIsBW = true;
     35     fIsEmpty = this->computeIsEmpty();  // bounds might be empty, so compute
     36     fIsRect = !fIsEmpty;
     37     SkDEBUGCODE(this->validate();)
     38 }
     39 
     40 SkRasterClip::~SkRasterClip() {
     41     SkDEBUGCODE(this->validate();)
     42 }
     43 
     44 bool SkRasterClip::isComplex() const {
     45     return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
     46 }
     47 
     48 const SkIRect& SkRasterClip::getBounds() const {
     49     return fIsBW ? fBW.getBounds() : fAA.getBounds();
     50 }
     51 
     52 bool SkRasterClip::setEmpty() {
     53     AUTO_RASTERCLIP_VALIDATE(*this);
     54 
     55     fIsBW = true;
     56     fBW.setEmpty();
     57     fAA.setEmpty();
     58     fIsEmpty = true;
     59     fIsRect = false;
     60     return false;
     61 }
     62 
     63 bool SkRasterClip::setRect(const SkIRect& rect) {
     64     AUTO_RASTERCLIP_VALIDATE(*this);
     65 
     66     fIsBW = true;
     67     fAA.setEmpty();
     68     fIsRect = fBW.setRect(rect);
     69     fIsEmpty = !fIsRect;
     70     return fIsRect;
     71 }
     72 
     73 bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
     74     AUTO_RASTERCLIP_VALIDATE(*this);
     75 
     76     if (this->isBW() && !doAA) {
     77         (void)fBW.setPath(path, clip);
     78     } else {
     79         // TODO: since we are going to over-write fAA completely (aren't we?)
     80         // we should just clear our BW data (if any) and set fIsAA=true
     81         if (this->isBW()) {
     82             this->convertToAA();
     83         }
     84         (void)fAA.setPath(path, &clip, doAA);
     85     }
     86     return this->updateCacheAndReturnNonEmpty();
     87 }
     88 
     89 bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
     90     SkRegion tmp;
     91     tmp.setRect(clip);
     92     return this->setPath(path, tmp, doAA);
     93 }
     94 
     95 bool SkRasterClip::setPath(const SkPath& path, const SkRasterClip& clip,
     96                            bool doAA) {
     97     if (clip.isBW()) {
     98         return this->setPath(path, clip.bwRgn(), doAA);
     99     } else {
    100         SkRegion tmp;
    101         tmp.setRect(clip.getBounds());
    102         if (!this->setPath(path, clip, doAA)) {
    103             return false;
    104         }
    105         return this->op(clip, SkRegion::kIntersect_Op);
    106     }
    107 }
    108 
    109 bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
    110     AUTO_RASTERCLIP_VALIDATE(*this);
    111 
    112     fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
    113     return this->updateCacheAndReturnNonEmpty();
    114 }
    115 
    116 bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
    117     AUTO_RASTERCLIP_VALIDATE(*this);
    118 
    119     if (fIsBW) {
    120         (void)fBW.op(rgn, op);
    121     } else {
    122         SkAAClip tmp;
    123         tmp.setRegion(rgn);
    124         (void)fAA.op(tmp, op);
    125     }
    126     return this->updateCacheAndReturnNonEmpty();
    127 }
    128 
    129 bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
    130     AUTO_RASTERCLIP_VALIDATE(*this);
    131     clip.validate();
    132 
    133     if (this->isBW() && clip.isBW()) {
    134         (void)fBW.op(clip.fBW, op);
    135     } else {
    136         SkAAClip tmp;
    137         const SkAAClip* other;
    138 
    139         if (this->isBW()) {
    140             this->convertToAA();
    141         }
    142         if (clip.isBW()) {
    143             tmp.setRegion(clip.bwRgn());
    144             other = &tmp;
    145         } else {
    146             other = &clip.aaRgn();
    147         }
    148         (void)fAA.op(*other, op);
    149     }
    150     return this->updateCacheAndReturnNonEmpty();
    151 }
    152 
    153 /**
    154  *  Our antialiasing currently has a granularity of 1/4 of a pixel along each
    155  *  axis. Thus we can treat an axis coordinate as an integer if it differs
    156  *  from its nearest int by < half of that value (1.8 in this case).
    157  */
    158 static bool nearly_integral(SkScalar x) {
    159     static const SkScalar domain = SK_Scalar1 / 4;
    160     static const SkScalar halfDomain = domain / 2;
    161 
    162     x += halfDomain;
    163     return x - SkScalarFloorToScalar(x) < domain;
    164 }
    165 
    166 bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
    167     AUTO_RASTERCLIP_VALIDATE(*this);
    168 
    169     if (fIsBW && doAA) {
    170         // check that the rect really needs aa, or is it close enought to
    171         // integer boundaries that we can just treat it as a BW rect?
    172         if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) &&
    173             nearly_integral(r.fRight) && nearly_integral(r.fBottom)) {
    174             doAA = false;
    175         }
    176     }
    177 
    178     if (fIsBW && !doAA) {
    179         SkIRect ir;
    180         r.round(&ir);
    181         (void)fBW.op(ir, op);
    182     } else {
    183         if (fIsBW) {
    184             this->convertToAA();
    185         }
    186         (void)fAA.op(r, op, doAA);
    187     }
    188     return this->updateCacheAndReturnNonEmpty();
    189 }
    190 
    191 void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
    192     if (NULL == dst) {
    193         return;
    194     }
    195 
    196     AUTO_RASTERCLIP_VALIDATE(*this);
    197 
    198     if (this->isEmpty()) {
    199         dst->setEmpty();
    200         return;
    201     }
    202     if (0 == (dx | dy)) {
    203         *dst = *this;
    204         return;
    205     }
    206 
    207     dst->fIsBW = fIsBW;
    208     if (fIsBW) {
    209         fBW.translate(dx, dy, &dst->fBW);
    210         dst->fAA.setEmpty();
    211     } else {
    212         fAA.translate(dx, dy, &dst->fAA);
    213         dst->fBW.setEmpty();
    214     }
    215     dst->updateCacheAndReturnNonEmpty();
    216 }
    217 
    218 bool SkRasterClip::quickContains(const SkIRect& ir) const {
    219     return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
    220 }
    221 
    222 ///////////////////////////////////////////////////////////////////////////////
    223 
    224 const SkRegion& SkRasterClip::forceGetBW() {
    225     AUTO_RASTERCLIP_VALIDATE(*this);
    226 
    227     if (!fIsBW) {
    228         fBW.setRect(fAA.getBounds());
    229     }
    230     return fBW;
    231 }
    232 
    233 void SkRasterClip::convertToAA() {
    234     AUTO_RASTERCLIP_VALIDATE(*this);
    235 
    236     SkASSERT(fIsBW);
    237     fAA.setRegion(fBW);
    238     fIsBW = false;
    239     (void)this->updateCacheAndReturnNonEmpty();
    240 }
    241 
    242 #ifdef SK_DEBUG
    243 void SkRasterClip::validate() const {
    244     // can't ever assert that fBW is empty, since we may have called forceGetBW
    245     if (fIsBW) {
    246         SkASSERT(fAA.isEmpty());
    247     }
    248 
    249     fBW.validate();
    250     fAA.validate();
    251 
    252     SkASSERT(this->computeIsEmpty() == fIsEmpty);
    253     SkASSERT(this->computeIsRect() == fIsRect);
    254 }
    255 #endif
    256 
    257 ///////////////////////////////////////////////////////////////////////////////
    258 
    259 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
    260     SkDEBUGCODE(fClipRgn = NULL;)
    261     SkDEBUGCODE(fBlitter = NULL;)
    262 }
    263 
    264 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
    265                                                SkBlitter* blitter) {
    266     this->init(clip, blitter);
    267 }
    268 
    269 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
    270                                                SkBlitter* blitter) {
    271     SkASSERT(blitter);
    272     SkASSERT(aaclip);
    273     fBWRgn.setRect(aaclip->getBounds());
    274     fAABlitter.init(blitter, aaclip);
    275     // now our return values
    276     fClipRgn = &fBWRgn;
    277     fBlitter = &fAABlitter;
    278 }
    279 
    280 void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
    281     SkASSERT(blitter);
    282     if (clip.isBW()) {
    283         fClipRgn = &clip.bwRgn();
    284         fBlitter = blitter;
    285     } else {
    286         const SkAAClip& aaclip = clip.aaRgn();
    287         fBWRgn.setRect(aaclip.getBounds());
    288         fAABlitter.init(blitter, &aaclip);
    289         // now our return values
    290         fClipRgn = &fBWRgn;
    291         fBlitter = &fAABlitter;
    292     }
    293 }
    294