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