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 SkBitmap& base,
     11                                const SkRasterClip& rc,
     12                                const SkIRect& bounds, bool aa)
     13 : fBaseBitmap(base)
     14 , fBaseRC(rc)
     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     fCurrBitmap = NULL;
     20     fCurrRC = NULL;
     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 
     43 void SkDeviceLooper::mapRect(SkRect* dst, const SkRect& src) const {
     44     SkASSERT(kDone_State != fState);
     45     SkASSERT(fCurrBitmap);
     46     SkASSERT(fCurrRC);
     47 
     48     *dst = src;
     49     dst->offset(SkIntToScalar(-fCurrOffset.fX),
     50                 SkIntToScalar(-fCurrOffset.fY));
     51 }
     52 
     53 void SkDeviceLooper::mapMatrix(SkMatrix* dst, const SkMatrix& src) const {
     54     SkASSERT(kDone_State != fState);
     55     SkASSERT(fCurrBitmap);
     56     SkASSERT(fCurrRC);
     57 
     58     *dst = src;
     59     dst->postTranslate(SkIntToScalar(-fCurrOffset.fX),
     60                        SkIntToScalar(-fCurrOffset.fY));
     61 }
     62 
     63 bool SkDeviceLooper::computeCurrBitmapAndClip() {
     64     SkASSERT(kComplex_State == fState);
     65 
     66     SkIRect r = SkIRect::MakeXYWH(fCurrOffset.x(), fCurrOffset.y(),
     67                                   fDelta, fDelta);
     68     if (!fBaseBitmap.extractSubset(&fSubsetBitmap, r)) {
     69         fSubsetRC.setEmpty();
     70     } else {
     71         fSubsetBitmap.lockPixels();
     72         fBaseRC.translate(-r.left(), -r.top(), &fSubsetRC);
     73         (void)fSubsetRC.op(SkIRect::MakeWH(fDelta, fDelta),
     74                            SkRegion::kIntersect_Op);
     75     }
     76 
     77     fCurrBitmap = &fSubsetBitmap;
     78     fCurrRC = &fSubsetRC;
     79     return !fCurrRC->isEmpty();
     80 }
     81 
     82 static bool next_tile(const SkIRect& boundary, int delta, SkIPoint* offset) {
     83     // can we move to the right?
     84     if (offset->x() + delta < boundary.right()) {
     85         offset->fX += delta;
     86         return true;
     87     }
     88 
     89     // reset to the left, but move down a row
     90     offset->fX = boundary.left();
     91     if (offset->y() + delta < boundary.bottom()) {
     92         offset->fY += delta;
     93         return true;
     94     }
     95 
     96     // offset is now outside of boundary, so we're done
     97     return false;
     98 }
     99 
    100 bool SkDeviceLooper::next() {
    101     switch (fState) {
    102         case kDone_State:
    103             // in theory, we should not get called here, since we must have
    104             // previously returned false, but we check anyway.
    105             break;
    106 
    107         case kSimple_State:
    108             // first time for simple
    109             if (NULL == fCurrBitmap) {
    110                 fCurrBitmap = &fBaseBitmap;
    111                 fCurrRC = &fBaseRC;
    112                 fCurrOffset.set(0, 0);
    113                 return true;
    114             }
    115             // 2nd time for simple, we are done
    116             break;
    117 
    118         case kComplex_State:
    119             // need to propogate fCurrOffset through clippedbounds
    120             // left to right, until we wrap around and move down
    121 
    122             while (next_tile(fClippedBounds, fDelta, &fCurrOffset)) {
    123                 if (this->computeCurrBitmapAndClip()) {
    124                     return true;
    125                 }
    126             }
    127             break;
    128     }
    129     fState = kDone_State;
    130     return false;
    131 }
    132