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