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 , 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
~SkDeviceLooper()40 SkDeviceLooper::~SkDeviceLooper() {
41 }
42
mapRect(SkRect * dst,const SkRect & src) const43 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
mapMatrix(SkMatrix * dst,const SkMatrix & src) const53 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
computeCurrBitmapAndClip()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
next_tile(const SkIRect & boundary,int delta,SkIPoint * offset)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
next()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