| /* | |
| * Copyright 2017 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef SkRasterClipStack_DEFINED | |
| #define SkRasterClipStack_DEFINED | |
| #include "include/core/SkClipOp.h" | |
| #include "src/base/SkTBlockList.h" | |
| #include "src/core/SkRasterClip.h" | |
| #include "src/core/SkScan.h" | |
| class SkRasterClipStack : SkNoncopyable { | |
| public: | |
| SkRasterClipStack(int width, int height) | |
| : fRootBounds(SkIRect::MakeWH(width, height)) | |
| , fDisableAA(SkScan::PathRequiresTiling(fRootBounds)) { | |
| fStack.emplace_back(SkRasterClip(fRootBounds)); | |
| SkASSERT(fStack.count() == 1); | |
| } | |
| void setNewSize(int w, int h) { | |
| fRootBounds.setXYWH(0, 0, w, h); | |
| SkASSERT(fStack.count() == 1); | |
| Rec& rec = fStack.back(); | |
| SkASSERT(rec.fDeferredCount == 0); | |
| rec.fRC.setRect(fRootBounds); | |
| } | |
| const SkRasterClip& rc() const { return fStack.back().fRC; } | |
| void save() { | |
| SkDEBUGCODE(fCounter += 1); | |
| SkASSERT(fStack.back().fDeferredCount >= 0); | |
| fStack.back().fDeferredCount += 1; | |
| } | |
| void restore() { | |
| SkDEBUGCODE(fCounter -= 1); | |
| SkASSERT(fCounter >= 0); | |
| if (--fStack.back().fDeferredCount < 0) { | |
| SkASSERT(fStack.back().fDeferredCount == -1); | |
| SkASSERT(fStack.count() > 1); | |
| fStack.pop_back(); | |
| } | |
| } | |
| void clipRect(const SkMatrix& ctm, const SkRect& rect, SkClipOp op, bool aa) { | |
| this->writable_rc().op(rect, ctm, op, this->finalAA(aa)); | |
| this->validate(); | |
| } | |
| void clipRRect(const SkMatrix& ctm, const SkRRect& rrect, SkClipOp op, bool aa) { | |
| this->writable_rc().op(rrect, ctm, op, this->finalAA(aa)); | |
| this->validate(); | |
| } | |
| void clipPath(const SkMatrix& ctm, const SkPath& path, SkClipOp op, bool aa) { | |
| this->writable_rc().op(path, ctm, op, this->finalAA(aa)); | |
| this->validate(); | |
| } | |
| void clipShader(sk_sp<SkShader> sh) { | |
| this->writable_rc().op(std::move(sh)); | |
| this->validate(); | |
| } | |
| void clipRegion(const SkRegion& rgn, SkClipOp op) { | |
| this->writable_rc().op(rgn, op); | |
| this->validate(); | |
| } | |
| void replaceClip(const SkIRect& rect) { | |
| SkIRect devRect = rect; | |
| if (!devRect.intersect(fRootBounds)) { | |
| this->writable_rc().setEmpty(); | |
| } else { | |
| this->writable_rc().setRect(devRect); | |
| } | |
| } | |
| void validate() const { | |
| #ifdef SK_DEBUG | |
| const SkRasterClip& clip = this->rc(); | |
| if (fRootBounds.isEmpty()) { | |
| SkASSERT(clip.isEmpty()); | |
| } else if (!clip.isEmpty()) { | |
| SkASSERT(fRootBounds.contains(clip.getBounds())); | |
| } | |
| #endif | |
| } | |
| private: | |
| struct Rec { | |
| SkRasterClip fRC; | |
| int fDeferredCount; // 0 for a "normal" entry | |
| Rec(const SkRasterClip& rc) : fRC(rc), fDeferredCount(0) {} | |
| }; | |
| SkTBlockList<Rec, 16> fStack; | |
| SkIRect fRootBounds; | |
| bool fDisableAA; | |
| SkDEBUGCODE(int fCounter = 0;) | |
| SkRasterClip& writable_rc() { | |
| SkASSERT(fStack.back().fDeferredCount >= 0); | |
| if (fStack.back().fDeferredCount > 0) { | |
| fStack.back().fDeferredCount -= 1; | |
| fStack.emplace_back(fStack.back().fRC); | |
| } | |
| return fStack.back().fRC; | |
| } | |
| bool finalAA(bool aa) const { return aa && !fDisableAA; } | |
| }; | |
| #endif |