11c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com/*
21c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com * Copyright 2013 Google Inc.
31c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com *
41c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com * Use of this source code is governed by a BSD-style license that can be
51c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com * found in the LICENSE file.
61c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com */
71c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com
81c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com#include "SkDeviceLooper.h"
91c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com
101c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.comSkDeviceLooper::SkDeviceLooper(const SkBitmap& base,
111c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com                               const SkRasterClip& rc,
121c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com                               const SkIRect& bounds, bool aa)
13d954498c01ccf0417feacf89e45d0c62a06a813breed    : fBaseBitmap(base)
14d954498c01ccf0417feacf89e45d0c62a06a813breed    , fBaseRC(rc)
15d954498c01ccf0417feacf89e45d0c62a06a813breed    , fSubsetRC(rc.isForceConservativeRects())
16d954498c01ccf0417feacf89e45d0c62a06a813breed    , fDelta(aa ? kAA_Delta : kBW_Delta)
171c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com{
181c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    // sentinels that next() has not yet been called, and so our mapper functions
191c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    // should not be called either.
201c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    fCurrBitmap = NULL;
211c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    fCurrRC = NULL;
221c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com
23636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    if (!rc.isEmpty()) {
24636d87a3f411507020a21c6b0641da795eb5d275reed@google.com        // clip must be contained by the bitmap
25636d87a3f411507020a21c6b0641da795eb5d275reed@google.com        SkASSERT(SkIRect::MakeWH(base.width(), base.height()).contains(rc.getBounds()));
26636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    }
27636d87a3f411507020a21c6b0641da795eb5d275reed@google.com
28636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    if (rc.isEmpty() || !fClippedBounds.intersect(bounds, rc.getBounds())) {
291c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com        fState = kDone_State;
30636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    } else if (this->fitsInDelta(fClippedBounds)) {
311c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com        fState = kSimple_State;
321c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    } else {
331c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com        // back up by 1 DX, so that next() will put us in a correct starting
341c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com        // position.
351c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com        fCurrOffset.set(fClippedBounds.left() - fDelta,
361c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com                        fClippedBounds.top());
371c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com        fState = kComplex_State;
381c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    }
391c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com}
401c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com
411c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.comSkDeviceLooper::~SkDeviceLooper() {
421c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com}
431c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com
441c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.comvoid SkDeviceLooper::mapRect(SkRect* dst, const SkRect& src) const {
451c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    SkASSERT(kDone_State != fState);
461c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    SkASSERT(fCurrBitmap);
471c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    SkASSERT(fCurrRC);
481c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com
491c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    *dst = src;
501c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    dst->offset(SkIntToScalar(-fCurrOffset.fX),
511c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com                SkIntToScalar(-fCurrOffset.fY));
521c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com}
531c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com
541c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.comvoid SkDeviceLooper::mapMatrix(SkMatrix* dst, const SkMatrix& src) const {
551c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    SkASSERT(kDone_State != fState);
561c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    SkASSERT(fCurrBitmap);
571c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    SkASSERT(fCurrRC);
581c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com
591c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    *dst = src;
601c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    dst->postTranslate(SkIntToScalar(-fCurrOffset.fX),
611c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com                       SkIntToScalar(-fCurrOffset.fY));
621c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com}
631c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com
641c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.combool SkDeviceLooper::computeCurrBitmapAndClip() {
651c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    SkASSERT(kComplex_State == fState);
666b00a1ec2ad525cae559d6b6e2157786686b2953skia.committer@gmail.com
671c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    SkIRect r = SkIRect::MakeXYWH(fCurrOffset.x(), fCurrOffset.y(),
681c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com                                  fDelta, fDelta);
691c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    if (!fBaseBitmap.extractSubset(&fSubsetBitmap, r)) {
70636d87a3f411507020a21c6b0641da795eb5d275reed@google.com        fSubsetRC.setEmpty();
71636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    } else {
72636d87a3f411507020a21c6b0641da795eb5d275reed@google.com        fSubsetBitmap.lockPixels();
73636d87a3f411507020a21c6b0641da795eb5d275reed@google.com        fBaseRC.translate(-r.left(), -r.top(), &fSubsetRC);
74636d87a3f411507020a21c6b0641da795eb5d275reed@google.com        (void)fSubsetRC.op(SkIRect::MakeWH(fDelta, fDelta),
75636d87a3f411507020a21c6b0641da795eb5d275reed@google.com                           SkRegion::kIntersect_Op);
761c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    }
776b00a1ec2ad525cae559d6b6e2157786686b2953skia.committer@gmail.com
781c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    fCurrBitmap = &fSubsetBitmap;
791c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    fCurrRC = &fSubsetRC;
80636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    return !fCurrRC->isEmpty();
81636d87a3f411507020a21c6b0641da795eb5d275reed@google.com}
82636d87a3f411507020a21c6b0641da795eb5d275reed@google.com
83636d87a3f411507020a21c6b0641da795eb5d275reed@google.comstatic bool next_tile(const SkIRect& boundary, int delta, SkIPoint* offset) {
84636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    // can we move to the right?
85636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    if (offset->x() + delta < boundary.right()) {
86636d87a3f411507020a21c6b0641da795eb5d275reed@google.com        offset->fX += delta;
87636d87a3f411507020a21c6b0641da795eb5d275reed@google.com        return true;
88636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    }
89636d87a3f411507020a21c6b0641da795eb5d275reed@google.com
90636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    // reset to the left, but move down a row
91636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    offset->fX = boundary.left();
92636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    if (offset->y() + delta < boundary.bottom()) {
93636d87a3f411507020a21c6b0641da795eb5d275reed@google.com        offset->fY += delta;
94636d87a3f411507020a21c6b0641da795eb5d275reed@google.com        return true;
95636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    }
962291e72b998244f3b4426b7307967b096ab13b1askia.committer@gmail.com
97636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    // offset is now outside of boundary, so we're done
98636d87a3f411507020a21c6b0641da795eb5d275reed@google.com    return false;
991c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com}
1001c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com
1011c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.combool SkDeviceLooper::next() {
1021c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    switch (fState) {
1031c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com        case kDone_State:
1041c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com            // in theory, we should not get called here, since we must have
1051c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com            // previously returned false, but we check anyway.
1061c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com            break;
1076b00a1ec2ad525cae559d6b6e2157786686b2953skia.committer@gmail.com
1081c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com        case kSimple_State:
1091c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com            // first time for simple
1101c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com            if (NULL == fCurrBitmap) {
1111c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com                fCurrBitmap = &fBaseBitmap;
1121c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com                fCurrRC = &fBaseRC;
1131c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com                fCurrOffset.set(0, 0);
1141c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com                return true;
1151c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com            }
1161c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com            // 2nd time for simple, we are done
1171c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com            break;
1181c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com
1191c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com        case kComplex_State:
1201c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com            // need to propogate fCurrOffset through clippedbounds
1211c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com            // left to right, until we wrap around and move down
1226b00a1ec2ad525cae559d6b6e2157786686b2953skia.committer@gmail.com
123636d87a3f411507020a21c6b0641da795eb5d275reed@google.com            while (next_tile(fClippedBounds, fDelta, &fCurrOffset)) {
124636d87a3f411507020a21c6b0641da795eb5d275reed@google.com                if (this->computeCurrBitmapAndClip()) {
125636d87a3f411507020a21c6b0641da795eb5d275reed@google.com                    return true;
126636d87a3f411507020a21c6b0641da795eb5d275reed@google.com                }
1271c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com            }
1281c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com            break;
1291c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    }
1301c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    fState = kDone_State;
1311c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com    return false;
1321c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com}
133