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
SkDeviceLooper(const SkBitmap & base,const SkRasterClip & rc,const SkIRect & bounds,bool aa)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
~SkDeviceLooper()41 SkDeviceLooper::~SkDeviceLooper() {
42 }
43
mapRect(SkRect * dst,const SkRect & src) const44 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
mapMatrix(SkMatrix * dst,const SkMatrix & src) const54 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
computeCurrBitmapAndClip()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
next_tile(const SkIRect & boundary,int delta,SkIPoint * offset)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
next()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