| /* | |
| * Copyright 2013 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "SkDeviceLooper.h" | |
| SkDeviceLooper::SkDeviceLooper(const SkPixmap& base, const SkRasterClip& rc, const SkIRect& bounds, | |
| bool aa) | |
| : fBaseDst(base) | |
| , fBaseRC(rc) | |
| , fSubsetRC(rc.isForceConservativeRects()) | |
| , fDelta(aa ? kAA_Delta : kBW_Delta) | |
| { | |
| // sentinels that next() has not yet been called, and so our mapper functions | |
| // should not be called either. | |
| fCurrDst = nullptr; | |
| fCurrRC = nullptr; | |
| if (!rc.isEmpty()) { | |
| // clip must be contained by the bitmap | |
| SkASSERT(SkIRect::MakeWH(base.width(), base.height()).contains(rc.getBounds())); | |
| } | |
| if (rc.isEmpty() || !fClippedBounds.intersect(bounds, rc.getBounds())) { | |
| fState = kDone_State; | |
| } else if (this->fitsInDelta(fClippedBounds)) { | |
| fState = kSimple_State; | |
| } else { | |
| // back up by 1 DX, so that next() will put us in a correct starting | |
| // position. | |
| fCurrOffset.set(fClippedBounds.left() - fDelta, | |
| fClippedBounds.top()); | |
| fState = kComplex_State; | |
| } | |
| } | |
| SkDeviceLooper::~SkDeviceLooper() {} | |
| void SkDeviceLooper::mapRect(SkRect* dst, const SkRect& src) const { | |
| SkASSERT(kDone_State != fState); | |
| SkASSERT(fCurrDst); | |
| SkASSERT(fCurrRC); | |
| *dst = src; | |
| dst->offset(SkIntToScalar(-fCurrOffset.fX), | |
| SkIntToScalar(-fCurrOffset.fY)); | |
| } | |
| void SkDeviceLooper::mapMatrix(SkMatrix* dst, const SkMatrix& src) const { | |
| SkASSERT(kDone_State != fState); | |
| SkASSERT(fCurrDst); | |
| SkASSERT(fCurrRC); | |
| *dst = src; | |
| dst->postTranslate(SkIntToScalar(-fCurrOffset.fX), SkIntToScalar(-fCurrOffset.fY)); | |
| } | |
| bool SkDeviceLooper::computeCurrBitmapAndClip() { | |
| SkASSERT(kComplex_State == fState); | |
| SkIRect r = SkIRect::MakeXYWH(fCurrOffset.x(), fCurrOffset.y(), | |
| fDelta, fDelta); | |
| if (!fBaseDst.extractSubset(&fSubsetDst, r)) { | |
| fSubsetRC.setEmpty(); | |
| } else { | |
| fBaseRC.translate(-r.left(), -r.top(), &fSubsetRC); | |
| (void)fSubsetRC.op(SkIRect::MakeWH(fDelta, fDelta), SkRegion::kIntersect_Op); | |
| } | |
| fCurrDst = &fSubsetDst; | |
| fCurrRC = &fSubsetRC; | |
| return !fCurrRC->isEmpty(); | |
| } | |
| static bool next_tile(const SkIRect& boundary, int delta, SkIPoint* offset) { | |
| // can we move to the right? | |
| if (offset->x() + delta < boundary.right()) { | |
| offset->fX += delta; | |
| return true; | |
| } | |
| // reset to the left, but move down a row | |
| offset->fX = boundary.left(); | |
| if (offset->y() + delta < boundary.bottom()) { | |
| offset->fY += delta; | |
| return true; | |
| } | |
| // offset is now outside of boundary, so we're done | |
| return false; | |
| } | |
| bool SkDeviceLooper::next() { | |
| switch (fState) { | |
| case kDone_State: | |
| // in theory, we should not get called here, since we must have | |
| // previously returned false, but we check anyway. | |
| break; | |
| case kSimple_State: | |
| // first time for simple | |
| if (nullptr == fCurrDst) { | |
| fCurrDst = &fBaseDst; | |
| fCurrRC = &fBaseRC; | |
| fCurrOffset.set(0, 0); | |
| return true; | |
| } | |
| // 2nd time for simple, we are done | |
| break; | |
| case kComplex_State: | |
| // need to propogate fCurrOffset through clippedbounds | |
| // left to right, until we wrap around and move down | |
| while (next_tile(fClippedBounds, fDelta, &fCurrOffset)) { | |
| if (this->computeCurrBitmapAndClip()) { | |
| return true; | |
| } | |
| } | |
| break; | |
| } | |
| fState = kDone_State; | |
| return false; | |
| } |