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     SkIRect bitmapBounds = SkIRect::MakeWH(base.width(), base.height());
     23     if (!fClippedBounds.intersect(bounds, bitmapBounds)) {
     24         fState = kDone_State;
     25     } else if (this->fitsInDelta(bounds)) {
     26         fState = kSimple_State;
     27     } else {
     28         // back up by 1 DX, so that next() will put us in a correct starting
     29         // position.
     30         fCurrOffset.set(fClippedBounds.left() - fDelta,
     31                         fClippedBounds.top());
     32         fState = kComplex_State;
     33     }
     34 }
     35 
     36 SkDeviceLooper::~SkDeviceLooper() {
     37 }
     38 
     39 void SkDeviceLooper::mapRect(SkRect* dst, const SkRect& src) const {
     40     SkASSERT(kDone_State != fState);
     41     SkASSERT(fCurrBitmap);
     42     SkASSERT(fCurrRC);
     43 
     44     *dst = src;
     45     dst->offset(SkIntToScalar(-fCurrOffset.fX),
     46                 SkIntToScalar(-fCurrOffset.fY));
     47 }
     48 
     49 void SkDeviceLooper::mapMatrix(SkMatrix* dst, const SkMatrix& src) const {
     50     SkASSERT(kDone_State != fState);
     51     SkASSERT(fCurrBitmap);
     52     SkASSERT(fCurrRC);
     53 
     54     *dst = src;
     55     dst->postTranslate(SkIntToScalar(-fCurrOffset.fX),
     56                        SkIntToScalar(-fCurrOffset.fY));
     57 }
     58 
     59 bool SkDeviceLooper::computeCurrBitmapAndClip() {
     60     SkASSERT(kComplex_State == fState);
     61 
     62     SkIRect r = SkIRect::MakeXYWH(fCurrOffset.x(), fCurrOffset.y(),
     63                                   fDelta, fDelta);
     64     if (!fBaseBitmap.extractSubset(&fSubsetBitmap, r)) {
     65         fState = kDone_State;
     66         return false;
     67     }
     68     fSubsetBitmap.lockPixels();
     69 
     70     fBaseRC.translate(-r.left(), -r.top(), &fSubsetRC);
     71     (void)fSubsetRC.op(SkIRect::MakeWH(fDelta, fDelta), SkRegion::kIntersect_Op);
     72 
     73     fCurrBitmap = &fSubsetBitmap;
     74     fCurrRC = &fSubsetRC;
     75     return true;
     76 }
     77 
     78 bool SkDeviceLooper::next() {
     79     switch (fState) {
     80         case kDone_State:
     81             // in theory, we should not get called here, since we must have
     82             // previously returned false, but we check anyway.
     83             break;
     84 
     85         case kSimple_State:
     86             // first time for simple
     87             if (NULL == fCurrBitmap) {
     88                 fCurrBitmap = &fBaseBitmap;
     89                 fCurrRC = &fBaseRC;
     90                 fCurrOffset.set(0, 0);
     91                 return true;
     92             }
     93             // 2nd time for simple, we are done
     94             break;
     95 
     96         case kComplex_State:
     97             // need to propogate fCurrOffset through clippedbounds
     98             // left to right, until we wrap around and move down
     99 
    100             if (fCurrOffset.x() + fDelta < fClippedBounds.right()) {
    101                 fCurrOffset.fX += fDelta;
    102                 return this->computeCurrBitmapAndClip();
    103             }
    104             fCurrOffset.fX = fClippedBounds.left();
    105             if (fCurrOffset.y() + fDelta < fClippedBounds.bottom()) {
    106                 fCurrOffset.fY += fDelta;
    107                 return this->computeCurrBitmapAndClip();
    108             }
    109             break;
    110     }
    111 
    112     fState = kDone_State;
    113     return false;
    114 }
    115