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 SkPixmap & base,const SkRasterClip & rc,const SkIRect & bounds,bool aa)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
~SkDeviceLooper()39 SkDeviceLooper::~SkDeviceLooper() {}
40
mapRect(SkRect * dst,const SkRect & src) const41 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
mapMatrix(SkMatrix * dst,const SkMatrix & src) const51 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
computeCurrBitmapAndClip()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
next_tile(const SkIRect & boundary,int delta,SkIPoint * offset)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
next()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