Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2013 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 "SkDeviceLooper.h"
      9 
     10 SkDeviceLooper::SkDeviceLooper(const SkPixmap& base, const SkRasterClip& rc, const SkIRect& bounds,
     11                                bool aa)
     12     : fBaseDst(base)
     13     , fBaseRC(rc)
     14     , fSubsetRC(rc.isForceConservativeRects())
     15     , fDelta(aa ? kAA_Delta : kBW_Delta)
     16 {
     17     // sentinels that next() has not yet been called, and so our mapper functions
     18     // should not be called either.
     19     fCurrDst = nullptr;
     20     fCurrRC = nullptr;
     21 
     22     if (!rc.isEmpty()) {
     23         // clip must be contained by the bitmap
     24         SkASSERT(SkIRect::MakeWH(base.width(), base.height()).contains(rc.getBounds()));
     25     }
     26 
     27     if (rc.isEmpty() || !fClippedBounds.intersect(bounds, rc.getBounds())) {
     28         fState = kDone_State;
     29     } else if (this->fitsInDelta(fClippedBounds)) {
     30         fState = kSimple_State;
     31     } else {
     32         // back up by 1 DX, so that next() will put us in a correct starting
     33         // position.
     34         fCurrOffset.set(fClippedBounds.left() - fDelta,
     35                         fClippedBounds.top());
     36         fState = kComplex_State;
     37     }
     38 }
     39 
     40 SkDeviceLooper::~SkDeviceLooper() {}
     41 
     42 void SkDeviceLooper::mapRect(SkRect* dst, const SkRect& src) const {
     43     SkASSERT(kDone_State != fState);
     44     SkASSERT(fCurrDst);
     45     SkASSERT(fCurrRC);
     46 
     47     *dst = src;
     48     dst->offset(SkIntToScalar(-fCurrOffset.fX),
     49                 SkIntToScalar(-fCurrOffset.fY));
     50 }
     51 
     52 void SkDeviceLooper::mapMatrix(SkMatrix* dst, const SkMatrix& src) const {
     53     SkASSERT(kDone_State != fState);
     54     SkASSERT(fCurrDst);
     55     SkASSERT(fCurrRC);
     56 
     57     *dst = src;
     58     dst->postTranslate(SkIntToScalar(-fCurrOffset.fX), SkIntToScalar(-fCurrOffset.fY));
     59 }
     60 
     61 bool SkDeviceLooper::computeCurrBitmapAndClip() {
     62     SkASSERT(kComplex_State == fState);
     63 
     64     SkIRect r = SkIRect::MakeXYWH(fCurrOffset.x(), fCurrOffset.y(),
     65                                   fDelta, fDelta);
     66     if (!fBaseDst.extractSubset(&fSubsetDst, r)) {
     67         fSubsetRC.setEmpty();
     68     } else {
     69         fBaseRC.translate(-r.left(), -r.top(), &fSubsetRC);
     70         (void)fSubsetRC.op(SkIRect::MakeWH(fDelta, fDelta), SkRegion::kIntersect_Op);
     71     }
     72 
     73     fCurrDst = &fSubsetDst;
     74     fCurrRC = &fSubsetRC;
     75     return !fCurrRC->isEmpty();
     76 }
     77 
     78 static bool next_tile(const SkIRect& boundary, int delta, SkIPoint* offset) {
     79     // can we move to the right?
     80     if (offset->x() + delta < boundary.right()) {
     81         offset->fX += delta;
     82         return true;
     83     }
     84 
     85     // reset to the left, but move down a row
     86     offset->fX = boundary.left();
     87     if (offset->y() + delta < boundary.bottom()) {
     88         offset->fY += delta;
     89         return true;
     90     }
     91 
     92     // offset is now outside of boundary, so we're done
     93     return false;
     94 }
     95 
     96 bool SkDeviceLooper::next() {
     97     switch (fState) {
     98         case kDone_State:
     99             // in theory, we should not get called here, since we must have
    100             // previously returned false, but we check anyway.
    101             break;
    102 
    103         case kSimple_State:
    104             // first time for simple
    105             if (nullptr == fCurrDst) {
    106                 fCurrDst = &fBaseDst;
    107                 fCurrRC = &fBaseRC;
    108                 fCurrOffset.set(0, 0);
    109                 return true;
    110             }
    111             // 2nd time for simple, we are done
    112             break;
    113 
    114         case kComplex_State:
    115             // need to propogate fCurrOffset through clippedbounds
    116             // left to right, until we wrap around and move down
    117 
    118             while (next_tile(fClippedBounds, fDelta, &fCurrOffset)) {
    119                 if (this->computeCurrBitmapAndClip()) {
    120                     return true;
    121                 }
    122             }
    123             break;
    124     }
    125     fState = kDone_State;
    126     return false;
    127 }
    128