/* * 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; }