LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkRasterClip.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 150 274 54.7 %
Date: 2017-07-14 16:53:18 Functions: 22 35 62.9 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #include "SkPath.h"
      10             : 
      11             : enum MutateResult {
      12             :     kDoNothing_MutateResult,
      13             :     kReplaceClippedAgainstGlobalBounds_MutateResult,
      14             :     kContinue_MutateResult,
      15             : };
      16             : 
      17         571 : static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled) {
      18         571 :     if (inverseFilled) {
      19           0 :         switch (*op) {
      20             :             case SkRegion::kIntersect_Op:
      21             :             case SkRegion::kDifference_Op:
      22             :                 // These ops can only shrink the current clip. So leaving
      23             :                 // the clip unchanged conservatively respects the contract.
      24           0 :                 return kDoNothing_MutateResult;
      25             :             case SkRegion::kUnion_Op:
      26             :             case SkRegion::kReplace_Op:
      27             :             case SkRegion::kReverseDifference_Op:
      28             :             case SkRegion::kXOR_Op: {
      29             :                 // These ops can grow the current clip up to the extents of
      30             :                 // the input clip, which is inverse filled, so we just set
      31             :                 // the current clip to the device bounds.
      32           0 :                 *op = SkRegion::kReplace_Op;
      33           0 :                 return kReplaceClippedAgainstGlobalBounds_MutateResult;
      34             :             }
      35             :         }
      36             :     } else {
      37             :         // Not inverse filled
      38         571 :         switch (*op) {
      39             :             case SkRegion::kIntersect_Op:
      40             :             case SkRegion::kUnion_Op:
      41             :             case SkRegion::kReplace_Op:
      42         571 :                 return kContinue_MutateResult;
      43             :             case SkRegion::kDifference_Op:
      44             :                 // Difference can only shrink the current clip.
      45             :                 // Leaving clip unchanged conservatively fullfills the contract.
      46           0 :                 return kDoNothing_MutateResult;
      47             :             case SkRegion::kReverseDifference_Op:
      48             :                 // To reverse, we swap in the bounds with a replace op.
      49             :                 // As with difference, leave it unchanged.
      50           0 :                 *op = SkRegion::kReplace_Op;
      51           0 :                 return kContinue_MutateResult;
      52             :             case SkRegion::kXOR_Op:
      53             :                 // Be conservative, based on (A XOR B) always included in (A union B),
      54             :                 // which is always included in (bounds(A) union bounds(B))
      55           0 :                 *op = SkRegion::kUnion_Op;
      56           0 :                 return kContinue_MutateResult;
      57             :         }
      58             :     }
      59           0 :     SkFAIL("should not get here");
      60           0 :     return kDoNothing_MutateResult;
      61             : }
      62             : 
      63         532 : void SkConservativeClip::op(const SkRect& localRect, const SkMatrix& ctm, const SkIRect& devBounds,
      64             :                             SkRegion::Op op, bool doAA) {
      65             :     SkIRect ir;
      66         532 :     switch (mutate_conservative_op(&op, false)) {
      67             :         case kDoNothing_MutateResult:
      68           0 :             return;
      69             :         case kReplaceClippedAgainstGlobalBounds_MutateResult:
      70           0 :             ir = devBounds;
      71           0 :             break;
      72             :         case kContinue_MutateResult: {
      73             :             SkRect devRect;
      74         532 :             ctm.mapRect(&devRect, localRect);
      75         532 :             ir = doAA ? devRect.roundOut() : devRect.round();
      76         532 :         } break;
      77             :     }
      78         532 :     this->op(ir, op);
      79             : }
      80             : 
      81           0 : void SkConservativeClip::op(const SkRRect& rrect, const SkMatrix& ctm, const SkIRect& devBounds,
      82             :                             SkRegion::Op op, bool doAA) {
      83           0 :     this->op(rrect.getBounds(), ctm, devBounds, op, doAA);
      84           0 : }
      85             : 
      86          39 : void SkConservativeClip::op(const SkPath& path, const SkMatrix& ctm, const SkIRect& devBounds,
      87             :                             SkRegion::Op op, bool doAA) {
      88             :     SkIRect ir;
      89          39 :     switch (mutate_conservative_op(&op, path.isInverseFillType())) {
      90             :         case kDoNothing_MutateResult:
      91           0 :             return;
      92             :         case kReplaceClippedAgainstGlobalBounds_MutateResult:
      93           0 :             ir = devBounds;
      94           0 :             break;
      95             :         case kContinue_MutateResult: {
      96          39 :             SkRect bounds = path.getBounds();
      97          39 :             ctm.mapRect(&bounds);
      98          39 :             ir = bounds.roundOut();
      99          39 :             break;
     100             :         }
     101             :     }
     102          39 :     return this->op(ir, op);
     103             : }
     104             : 
     105          24 : void SkConservativeClip::op(const SkRegion& rgn, SkRegion::Op op) {
     106          24 :     this->op(rgn.getBounds(), op);
     107          24 : }
     108             : 
     109         595 : void SkConservativeClip::op(const SkIRect& devRect, SkRegion::Op op) {
     110         595 :     if (SkRegion::kIntersect_Op == op) {
     111         595 :         if (!fBounds.intersect(devRect)) {
     112          15 :             fBounds.setEmpty();
     113             :         }
     114         595 :         return;
     115             :     }
     116             : 
     117             :     // This may still create a complex region (which we would then take the bounds
     118             :     // Perhaps we should inline the op-logic directly to never create the rgn...
     119           0 :     SkRegion result;
     120           0 :     result.op(SkRegion(fBounds), SkRegion(devRect), op);
     121           0 :     fBounds = result.getBounds();
     122           0 :     this->applyClipRestriction(op, &fBounds);
     123             : }
     124             : 
     125             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     126             : 
     127         595 : SkRasterClip::SkRasterClip(const SkRasterClip& src) {
     128        1190 :     AUTO_RASTERCLIP_VALIDATE(src);
     129             : 
     130         595 :     fIsBW = src.fIsBW;
     131         595 :     if (fIsBW) {
     132         473 :         fBW = src.fBW;
     133             :     } else {
     134         122 :         fAA = src.fAA;
     135             :     }
     136             : 
     137         595 :     fIsEmpty = src.isEmpty();
     138         595 :     fIsRect = src.isRect();
     139         595 :     fClipRestrictionRect = src.fClipRestrictionRect;
     140         595 :     SkDEBUGCODE(this->validate();)
     141         595 : }
     142             : 
     143           0 : SkRasterClip::SkRasterClip(const SkRegion& rgn) : fBW(rgn) {
     144           0 :     fIsBW = true;
     145           0 :     fIsEmpty = this->computeIsEmpty();  // bounds might be empty, so compute
     146           0 :     fIsRect = !fIsEmpty;
     147           0 :     SkDEBUGCODE(this->validate();)
     148           0 : }
     149             : 
     150           0 : SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
     151           0 :     fIsBW = true;
     152           0 :     fIsEmpty = this->computeIsEmpty();  // bounds might be empty, so compute
     153           0 :     fIsRect = !fIsEmpty;
     154           0 :     SkDEBUGCODE(this->validate();)
     155           0 : }
     156             : 
     157         396 : SkRasterClip::SkRasterClip() {
     158         396 :     fIsBW = true;
     159         396 :     fIsEmpty = true;
     160         396 :     fIsRect = false;
     161         396 :     SkDEBUGCODE(this->validate();)
     162         396 : }
     163             : 
     164        1878 : SkRasterClip::~SkRasterClip() {
     165         939 :     SkDEBUGCODE(this->validate();)
     166         939 : }
     167             : 
     168           0 : bool SkRasterClip::operator==(const SkRasterClip& other) const {
     169           0 :     if (fIsBW != other.fIsBW) {
     170           0 :         return false;
     171             :     }
     172           0 :     bool isEqual = fIsBW ? fBW == other.fBW : fAA == other.fAA;
     173             : #ifdef SK_DEBUG
     174           0 :     if (isEqual) {
     175           0 :         SkASSERT(fIsEmpty == other.fIsEmpty);
     176           0 :         SkASSERT(fIsRect == other.fIsRect);
     177             :     }
     178             : #endif
     179           0 :     return isEqual;
     180             : }
     181             : 
     182           0 : bool SkRasterClip::isComplex() const {
     183           0 :     return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
     184             : }
     185             : 
     186        1981 : const SkIRect& SkRasterClip::getBounds() const {
     187        1981 :     return fIsBW ? fBW.getBounds() : fAA.getBounds();
     188             : }
     189             : 
     190           0 : bool SkRasterClip::setEmpty() {
     191           0 :     AUTO_RASTERCLIP_VALIDATE(*this);
     192             : 
     193           0 :     fIsBW = true;
     194           0 :     fBW.setEmpty();
     195           0 :     fAA.setEmpty();
     196           0 :     fIsEmpty = true;
     197           0 :     fIsRect = false;
     198           0 :     return false;
     199             : }
     200             : 
     201          88 : bool SkRasterClip::setRect(const SkIRect& rect) {
     202         176 :     AUTO_RASTERCLIP_VALIDATE(*this);
     203             : 
     204          88 :     fIsBW = true;
     205          88 :     fAA.setEmpty();
     206          88 :     fIsRect = fBW.setRect(rect);
     207          88 :     fIsEmpty = !fIsRect;
     208         176 :     return fIsRect;
     209             : }
     210             : 
     211             : /////////////////////////////////////////////////////////////////////////////////////
     212             : 
     213           0 : bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) {
     214             :     SkRegion::Op op;
     215           0 :     if (isInverse) {
     216           0 :         op = SkRegion::kDifference_Op;
     217             :     } else {
     218           0 :         op = SkRegion::kIntersect_Op;
     219             :     }
     220           0 :     fBW.setRect(clipR);
     221           0 :     fBW.op(r.roundOut(), op);
     222           0 :     return this->updateCacheAndReturnNonEmpty();
     223             : }
     224             : 
     225             : /////////////////////////////////////////////////////////////////////////////////////
     226             : 
     227          39 : bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
     228          78 :     AUTO_RASTERCLIP_VALIDATE(*this);
     229             : 
     230          39 :     if (this->isBW() && !doAA) {
     231           0 :         (void)fBW.setPath(path, clip);
     232             :     } else {
     233             :         // TODO: since we are going to over-write fAA completely (aren't we?)
     234             :         // we should just clear our BW data (if any) and set fIsAA=true
     235          39 :         if (this->isBW()) {
     236          39 :             this->convertToAA();
     237             :         }
     238          39 :         (void)fAA.setPath(path, &clip, doAA);
     239             :     }
     240          78 :     return this->updateCacheAndReturnNonEmpty();
     241             : }
     242             : 
     243           0 : bool SkRasterClip::op(const SkRRect& rrect, const SkMatrix& matrix, const SkIRect& devBounds,
     244             :                       SkRegion::Op op, bool doAA) {
     245           0 :     SkIRect bounds(devBounds);
     246           0 :     this->applyClipRestriction(op, &bounds);
     247             : 
     248           0 :     SkPath path;
     249           0 :     path.addRRect(rrect);
     250             : 
     251           0 :     return this->op(path, matrix, bounds, op, doAA);
     252             : }
     253             : 
     254          39 : bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& devBounds,
     255             :                       SkRegion::Op op, bool doAA) {
     256          78 :     AUTO_RASTERCLIP_VALIDATE(*this);
     257          39 :     SkIRect bounds(devBounds);
     258          39 :     this->applyClipRestriction(op, &bounds);
     259             : 
     260             :     // base is used to limit the size (and therefore memory allocation) of the
     261             :     // region that results from scan converting devPath.
     262          78 :     SkRegion base;
     263             : 
     264          78 :     SkPath devPath;
     265          39 :     if (matrix.isIdentity()) {
     266          25 :         devPath = path;
     267             :     } else {
     268          14 :         path.transform(matrix, &devPath);
     269          14 :         devPath.setIsVolatile(true);
     270             :     }
     271          39 :     if (SkRegion::kIntersect_Op == op) {
     272             :         // since we are intersect, we can do better (tighter) with currRgn's
     273             :         // bounds, than just using the device. However, if currRgn is complex,
     274             :         // our region blitter may hork, so we do that case in two steps.
     275          39 :         if (this->isRect()) {
     276             :             // FIXME: we should also be able to do this when this->isBW(),
     277             :             // but relaxing the test above triggers GM asserts in
     278             :             // SkRgnBuilder::blitH(). We need to investigate what's going on.
     279          29 :             return this->setPath(devPath, this->bwRgn(), doAA);
     280             :         } else {
     281          10 :             base.setRect(this->getBounds());
     282          20 :             SkRasterClip clip;
     283          10 :             clip.setPath(devPath, base, doAA);
     284          10 :             return this->op(clip, op);
     285             :         }
     286             :     } else {
     287           0 :         base.setRect(bounds);
     288             : 
     289           0 :         if (SkRegion::kReplace_Op == op) {
     290           0 :             return this->setPath(devPath, base, doAA);
     291             :         } else {
     292           0 :             SkRasterClip clip;
     293           0 :             clip.setPath(devPath, base, doAA);
     294           0 :             return this->op(clip, op);
     295             :         }
     296             :     }
     297             : }
     298             : 
     299           0 : bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
     300           0 :     SkRegion tmp;
     301           0 :     tmp.setRect(clip);
     302           0 :     return this->setPath(path, tmp, doAA);
     303             : }
     304             : 
     305           0 : bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
     306           0 :     AUTO_RASTERCLIP_VALIDATE(*this);
     307             : 
     308           0 :     fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
     309           0 :     return this->updateCacheAndReturnNonEmpty();
     310             : }
     311             : 
     312          24 : bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
     313          48 :     AUTO_RASTERCLIP_VALIDATE(*this);
     314             : 
     315          24 :     if (fIsBW) {
     316          24 :         (void)fBW.op(rgn, op);
     317             :     } else {
     318           0 :         SkAAClip tmp;
     319           0 :         tmp.setRegion(rgn);
     320           0 :         (void)fAA.op(tmp, op);
     321             :     }
     322          48 :     return this->updateCacheAndReturnNonEmpty();
     323             : }
     324             : 
     325          10 : bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
     326          20 :     AUTO_RASTERCLIP_VALIDATE(*this);
     327          10 :     clip.validate();
     328             : 
     329          10 :     if (this->isBW() && clip.isBW()) {
     330           0 :         (void)fBW.op(clip.fBW, op);
     331             :     } else {
     332          20 :         SkAAClip tmp;
     333             :         const SkAAClip* other;
     334             : 
     335          10 :         if (this->isBW()) {
     336           0 :             this->convertToAA();
     337             :         }
     338          10 :         if (clip.isBW()) {
     339           0 :             tmp.setRegion(clip.bwRgn());
     340           0 :             other = &tmp;
     341             :         } else {
     342          10 :             other = &clip.aaRgn();
     343             :         }
     344          10 :         (void)fAA.op(*other, op);
     345             :     }
     346          20 :     return this->updateCacheAndReturnNonEmpty();
     347             : }
     348             : 
     349             : /**
     350             :  *  Our antialiasing currently has a granularity of 1/4 of a pixel along each
     351             :  *  axis. Thus we can treat an axis coordinate as an integer if it differs
     352             :  *  from its nearest int by < half of that value (1.8 in this case).
     353             :  */
     354        1674 : static bool nearly_integral(SkScalar x) {
     355             :     static const SkScalar domain = SK_Scalar1 / 4;
     356             :     static const SkScalar halfDomain = domain / 2;
     357             : 
     358        1674 :     x += halfDomain;
     359        1674 :     return x - SkScalarFloorToScalar(x) < domain;
     360             : }
     361             : 
     362         532 : bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, const SkIRect& devBounds,
     363             :                       SkRegion::Op op, bool doAA) {
     364        1064 :     AUTO_RASTERCLIP_VALIDATE(*this);
     365             :     SkRect devRect;
     366             : 
     367         532 :     const bool isScaleTrans = matrix.isScaleTranslate();
     368         532 :     if (!isScaleTrans) {
     369           0 :         SkPath path;
     370           0 :         path.addRect(localRect);
     371           0 :         path.setIsVolatile(true);
     372           0 :         return this->op(path, matrix, devBounds, op, doAA);
     373             :     }
     374             : 
     375         532 :     matrix.mapRect(&devRect, localRect);
     376             : 
     377         532 :     if (fIsBW && doAA) {
     378             :         // check that the rect really needs aa, or is it close enought to
     379             :         // integer boundaries that we can just treat it as a BW rect?
     380        1675 :         if (nearly_integral(devRect.fLeft) && nearly_integral(devRect.fTop) &&
     381        1255 :             nearly_integral(devRect.fRight) && nearly_integral(devRect.fBottom)) {
     382         418 :             doAA = false;
     383             :         }
     384             :     }
     385             : 
     386         532 :     if (fIsBW && !doAA) {
     387             :         SkIRect ir;
     388         419 :         devRect.round(&ir);
     389         419 :         this->applyClipRestriction(op, &ir);
     390         419 :         (void)fBW.op(ir, op);
     391             :     } else {
     392         113 :         if (fIsBW) {
     393           1 :             this->convertToAA();
     394             :         }
     395         113 :         this->applyClipRestriction(op, &devRect);
     396         113 :         (void)fAA.op(devRect, op, doAA);
     397             :     }
     398         532 :     return this->updateCacheAndReturnNonEmpty();
     399             : }
     400             : 
     401           0 : void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
     402           0 :     if (nullptr == dst) {
     403           0 :         return;
     404             :     }
     405             : 
     406           0 :     AUTO_RASTERCLIP_VALIDATE(*this);
     407             : 
     408           0 :     if (this->isEmpty()) {
     409           0 :         dst->setEmpty();
     410           0 :         return;
     411             :     }
     412           0 :     if (0 == (dx | dy)) {
     413           0 :         *dst = *this;
     414           0 :         return;
     415             :     }
     416             : 
     417           0 :     dst->fIsBW = fIsBW;
     418           0 :     if (fIsBW) {
     419           0 :         fBW.translate(dx, dy, &dst->fBW);
     420           0 :         dst->fAA.setEmpty();
     421             :     } else {
     422           0 :         fAA.translate(dx, dy, &dst->fAA);
     423           0 :         dst->fBW.setEmpty();
     424             :     }
     425           0 :     dst->updateCacheAndReturnNonEmpty();
     426             : }
     427             : 
     428          43 : bool SkRasterClip::quickContains(const SkIRect& ir) const {
     429          43 :     return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
     430             : }
     431             : 
     432             : ///////////////////////////////////////////////////////////////////////////////
     433             : 
     434           0 : const SkRegion& SkRasterClip::forceGetBW() {
     435           0 :     AUTO_RASTERCLIP_VALIDATE(*this);
     436             : 
     437           0 :     if (!fIsBW) {
     438           0 :         fBW.setRect(fAA.getBounds());
     439             :     }
     440           0 :     return fBW;
     441             : }
     442             : 
     443          40 : void SkRasterClip::convertToAA() {
     444          80 :     AUTO_RASTERCLIP_VALIDATE(*this);
     445             : 
     446          40 :     SkASSERT(fIsBW);
     447          40 :     fAA.setRegion(fBW);
     448          40 :     fIsBW = false;
     449             : 
     450             :     // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize"
     451             :     // ourselves back to BW.
     452          40 :     (void)this->updateCacheAndReturnNonEmpty(false);
     453          40 : }
     454             : 
     455             : #ifdef SK_DEBUG
     456        4674 : void SkRasterClip::validate() const {
     457             :     // can't ever assert that fBW is empty, since we may have called forceGetBW
     458        4674 :     if (fIsBW) {
     459        3777 :         SkASSERT(fAA.isEmpty());
     460             :     }
     461             : 
     462        4674 :     fBW.validate();
     463        4674 :     fAA.validate();
     464             : 
     465        4674 :     SkASSERT(this->computeIsEmpty() == fIsEmpty);
     466        4674 :     SkASSERT(this->computeIsRect() == fIsRect);
     467        4674 : }
     468             : #endif
     469             : 
     470             : ///////////////////////////////////////////////////////////////////////////////
     471             : 
     472          17 : SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
     473          17 :     SkDEBUGCODE(fClipRgn = nullptr;)
     474          17 :     SkDEBUGCODE(fBlitter = nullptr;)
     475          17 : }
     476             : 
     477         169 : SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
     478         169 :                                                SkBlitter* blitter) {
     479         169 :     this->init(clip, blitter);
     480         169 : }
     481             : 
     482           0 : SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
     483           0 :                                                SkBlitter* blitter) {
     484           0 :     SkASSERT(blitter);
     485           0 :     SkASSERT(aaclip);
     486           0 :     fBWRgn.setRect(aaclip->getBounds());
     487           0 :     fAABlitter.init(blitter, aaclip);
     488             :     // now our return values
     489           0 :     fClipRgn = &fBWRgn;
     490           0 :     fBlitter = &fAABlitter;
     491           0 : }
     492             : 
     493         171 : void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
     494         171 :     SkASSERT(blitter);
     495         171 :     if (clip.isBW()) {
     496          14 :         fClipRgn = &clip.bwRgn();
     497          14 :         fBlitter = blitter;
     498             :     } else {
     499         157 :         const SkAAClip& aaclip = clip.aaRgn();
     500         157 :         fBWRgn.setRect(aaclip.getBounds());
     501         157 :         fAABlitter.init(blitter, &aaclip);
     502             :         // now our return values
     503         157 :         fClipRgn = &fBWRgn;
     504         157 :         fBlitter = &fAABlitter;
     505             :     }
     506         171 : }

Generated by: LCOV version 1.13