SkDeviceLooper.cpp revision 636d87a3f411507020a21c6b0641da795eb5d275
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
10SkDeviceLooper::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
40SkDeviceLooper::~SkDeviceLooper() {
41}
42
43void 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
53void 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
63bool 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
82static 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
100bool 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