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