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::op(const SkIRect& rect, SkRegion::Op op) {
     96     AUTO_RASTERCLIP_VALIDATE(*this);
     97 
     98     fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
     99     return this->updateCacheAndReturnNonEmpty();
    100 }
    101 
    102 bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
    103     AUTO_RASTERCLIP_VALIDATE(*this);
    104 
    105     if (fIsBW) {
    106         (void)fBW.op(rgn, op);
    107     } else {
    108         SkAAClip tmp;
    109         tmp.setRegion(rgn);
    110         (void)fAA.op(tmp, op);
    111     }
    112     return this->updateCacheAndReturnNonEmpty();
    113 }
    114 
    115 bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
    116     AUTO_RASTERCLIP_VALIDATE(*this);
    117     clip.validate();
    118 
    119     if (this->isBW() && clip.isBW()) {
    120         (void)fBW.op(clip.fBW, op);
    121     } else {
    122         SkAAClip tmp;
    123         const SkAAClip* other;
    124 
    125         if (this->isBW()) {
    126             this->convertToAA();
    127         }
    128         if (clip.isBW()) {
    129             tmp.setRegion(clip.bwRgn());
    130             other = &tmp;
    131         } else {
    132             other = &clip.aaRgn();
    133         }
    134         (void)fAA.op(*other, op);
    135     }
    136     return this->updateCacheAndReturnNonEmpty();
    137 }
    138 
    139 /**
    140  *  Our antialiasing currently has a granularity of 1/4 of a pixel along each
    141  *  axis. Thus we can treat an axis coordinate as an integer if it differs
    142  *  from its nearest int by < half of that value (1.8 in this case).
    143  */
    144 static bool nearly_integral(SkScalar x) {
    145     static const SkScalar domain = SK_Scalar1 / 4;
    146     static const SkScalar halfDomain = domain / 2;
    147 
    148     x += halfDomain;
    149     return x - SkScalarFloorToScalar(x) < domain;
    150 }
    151 
    152 bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
    153     AUTO_RASTERCLIP_VALIDATE(*this);
    154 
    155     if (fIsBW && doAA) {
    156         // check that the rect really needs aa, or is it close enought to
    157         // integer boundaries that we can just treat it as a BW rect?
    158         if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) &&
    159             nearly_integral(r.fRight) && nearly_integral(r.fBottom)) {
    160             doAA = false;
    161         }
    162     }
    163 
    164     if (fIsBW && !doAA) {
    165         SkIRect ir;
    166         r.round(&ir);
    167         (void)fBW.op(ir, op);
    168     } else {
    169         if (fIsBW) {
    170             this->convertToAA();
    171         }
    172         (void)fAA.op(r, op, doAA);
    173     }
    174     return this->updateCacheAndReturnNonEmpty();
    175 }
    176 
    177 void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
    178     if (NULL == dst) {
    179         return;
    180     }
    181 
    182     AUTO_RASTERCLIP_VALIDATE(*this);
    183 
    184     if (this->isEmpty()) {
    185         dst->setEmpty();
    186         return;
    187     }
    188     if (0 == (dx | dy)) {
    189         *dst = *this;
    190         return;
    191     }
    192 
    193     dst->fIsBW = fIsBW;
    194     if (fIsBW) {
    195         fBW.translate(dx, dy, &dst->fBW);
    196         dst->fAA.setEmpty();
    197     } else {
    198         fAA.translate(dx, dy, &dst->fAA);
    199         dst->fBW.setEmpty();
    200     }
    201     dst->updateCacheAndReturnNonEmpty();
    202 }
    203 
    204 bool SkRasterClip::quickContains(const SkIRect& ir) const {
    205     return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
    206 }
    207 
    208 ///////////////////////////////////////////////////////////////////////////////
    209 
    210 const SkRegion& SkRasterClip::forceGetBW() {
    211     AUTO_RASTERCLIP_VALIDATE(*this);
    212 
    213     if (!fIsBW) {
    214         fBW.setRect(fAA.getBounds());
    215     }
    216     return fBW;
    217 }
    218 
    219 void SkRasterClip::convertToAA() {
    220     AUTO_RASTERCLIP_VALIDATE(*this);
    221 
    222     SkASSERT(fIsBW);
    223     fAA.setRegion(fBW);
    224     fIsBW = false;
    225     (void)this->updateCacheAndReturnNonEmpty();
    226 }
    227 
    228 #ifdef SK_DEBUG
    229 void SkRasterClip::validate() const {
    230     // can't ever assert that fBW is empty, since we may have called forceGetBW
    231     if (fIsBW) {
    232         SkASSERT(fAA.isEmpty());
    233     }
    234 
    235     fBW.validate();
    236     fAA.validate();
    237 
    238     SkASSERT(this->computeIsEmpty() == fIsEmpty);
    239     SkASSERT(this->computeIsRect() == fIsRect);
    240 }
    241 #endif
    242 
    243 ///////////////////////////////////////////////////////////////////////////////
    244 
    245 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
    246     SkDEBUGCODE(fClipRgn = NULL;)
    247     SkDEBUGCODE(fBlitter = NULL;)
    248 }
    249 
    250 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
    251                                                SkBlitter* blitter) {
    252     this->init(clip, blitter);
    253 }
    254 
    255 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
    256                                                SkBlitter* blitter) {
    257     SkASSERT(blitter);
    258     SkASSERT(aaclip);
    259     fBWRgn.setRect(aaclip->getBounds());
    260     fAABlitter.init(blitter, aaclip);
    261     // now our return values
    262     fClipRgn = &fBWRgn;
    263     fBlitter = &fAABlitter;
    264 }
    265 
    266 void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
    267     SkASSERT(blitter);
    268     if (clip.isBW()) {
    269         fClipRgn = &clip.bwRgn();
    270         fBlitter = blitter;
    271     } else {
    272         const SkAAClip& aaclip = clip.aaRgn();
    273         fBWRgn.setRect(aaclip.getBounds());
    274         fAABlitter.init(blitter, &aaclip);
    275         // now our return values
    276         fClipRgn = &fBWRgn;
    277         fBlitter = &fAABlitter;
    278     }
    279 }
    280