| /* | |
| * 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 "SkClipOp.h" | |
| #include "SkDeque.h" | |
| #include "SkRasterClip.h" | |
| #include <new> | |
| template <typename T> class SkTStack { | |
| public: | |
| SkTStack(void* storage, size_t size) : fDeque(sizeof(T), storage, size), fTop(nullptr) {} | |
| ~SkTStack() { | |
| while (!fDeque.empty()) { | |
| ((T*)fDeque.back())->~T(); | |
| fDeque.pop_back(); | |
| } | |
| } | |
| bool empty() const { return fDeque.empty(); } | |
| int count() const { return fDeque.count(); } | |
| const T& top() const { | |
| SkASSERT(fTop); | |
| return *fTop; | |
| } | |
| T& top() { | |
| SkASSERT(fTop); | |
| return *fTop; | |
| } | |
| T* push_raw() { return (T*)fDeque.push_back(); } | |
| T& push() { | |
| fTop = this->push_raw(); | |
| new (fTop) T(); | |
| return *fTop; | |
| } | |
| T& push(const T& src) { | |
| fTop = this->push_raw(); | |
| new (fTop) T(src); | |
| return *fTop; | |
| } | |
| void pop() { | |
| fTop->~T(); | |
| fDeque.pop_back(); | |
| fTop = fDeque.empty() ? nullptr : (T*)fDeque.back(); | |
| } | |
| private: | |
| SkDeque fDeque; | |
| T* fTop; | |
| }; | |
| class SkRasterClipStack : SkNoncopyable { | |
| int fCounter = 0; | |
| public: | |
| SkRasterClipStack(int width, int height) | |
| : fStack(fStorage, sizeof(fStorage)) | |
| , fRootBounds(SkIRect::MakeWH(width, height)) | |
| { | |
| Rec& rec = fStack.push(); | |
| rec.fRC.setRect(fRootBounds); | |
| rec.fDeferredCount = 0; | |
| SkASSERT(fStack.count() == 1); | |
| } | |
| void setNewSize(int w, int h) { | |
| fRootBounds.setXYWH(0, 0, w, h); | |
| SkASSERT(fStack.count() == 1); | |
| Rec& rec = fStack.top(); | |
| SkASSERT(rec.fDeferredCount == 0); | |
| rec.fRC.setRect(fRootBounds); | |
| } | |
| const SkRasterClip& rc() const { return fStack.top().fRC; } | |
| void save() { | |
| fCounter += 1; | |
| SkASSERT(fStack.top().fDeferredCount >= 0); | |
| fStack.top().fDeferredCount += 1; | |
| } | |
| void restore() { | |
| fCounter -= 1; SkASSERT(fCounter >= 0); | |
| if (--fStack.top().fDeferredCount < 0) { | |
| SkASSERT(fStack.top().fDeferredCount == -1); | |
| SkASSERT(fStack.count() > 1); | |
| fStack.pop(); | |
| } | |
| } | |
| void clipRect(const SkMatrix& ctm, const SkRect& rect, SkClipOp op, bool aa) { | |
| this->writable_rc().op(rect, ctm, fRootBounds, (SkRegion::Op)op, aa); | |
| this->trimIfExpanding(op); | |
| this->validate(); | |
| } | |
| void clipRRect(const SkMatrix& ctm, const SkRRect& rrect, SkClipOp op, bool aa) { | |
| this->writable_rc().op(rrect, ctm, fRootBounds, (SkRegion::Op)op, aa); | |
| this->trimIfExpanding(op); | |
| this->validate(); | |
| } | |
| void clipPath(const SkMatrix& ctm, const SkPath& path, SkClipOp op, bool aa) { | |
| this->writable_rc().op(path, ctm, fRootBounds, (SkRegion::Op)op, aa); | |
| this->trimIfExpanding(op); | |
| this->validate(); | |
| } | |
| void clipRegion(const SkRegion& rgn, SkClipOp op) { | |
| this->writable_rc().op(rgn, (SkRegion::Op)op); | |
| this->trimIfExpanding(op); | |
| this->validate(); | |
| } | |
| void setDeviceClipRestriction(SkIRect* mutableClipRestriction) { | |
| this->writable_rc().setDeviceClipRestriction(mutableClipRestriction); | |
| } | |
| 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 | |
| }; | |
| enum { | |
| ELEM_COUNT = 16, | |
| PTR_COUNT = ELEM_COUNT * sizeof(Rec) / sizeof(void*) | |
| }; | |
| void* fStorage[PTR_COUNT]; | |
| SkTStack<Rec> fStack; | |
| SkIRect fRootBounds; | |
| SkRasterClip& writable_rc() { | |
| SkASSERT(fStack.top().fDeferredCount >= 0); | |
| if (fStack.top().fDeferredCount > 0) { | |
| fStack.top().fDeferredCount -= 1; | |
| fStack.push(fStack.top()); | |
| fStack.top().fDeferredCount = 0; | |
| } | |
| return fStack.top().fRC; | |
| } | |
| void trimIfExpanding(SkClipOp op) { | |
| if ((int)op > (int)SkClipOp::kIntersect) { | |
| Rec& rec = fStack.top(); | |
| SkASSERT(rec.fDeferredCount == 0); | |
| rec.fRC.op(fRootBounds, SkRegion::kIntersect_Op); | |
| } | |
| } | |
| }; | |
| #endif |