|
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 } |