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