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