• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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