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