Fix saveLayer bugs in SkMatrixClipStateMgr

https://codereview.chromium.org/169283011/



git-svn-id: http://skia.googlecode.com/svn/trunk@13533 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
robertphillips@google.com 2014-02-21 17:46:37 +00:00
parent dfff2737f8
commit fc4ded9f4a
2 changed files with 137 additions and 14 deletions

View File

@ -112,6 +112,10 @@ SkMatrixClipStateMgr::SkMatrixClipStateMgr()
fCurMCState = (MatrixClipState*)fMatrixClipStack.push_back();
new (fCurMCState) MatrixClipState(NULL, 0); // balanced in restore()
#ifdef SK_DEBUG
fActualDepth = 0;
#endif
}
SkMatrixClipStateMgr::~SkMatrixClipStateMgr() {
@ -141,14 +145,27 @@ int SkMatrixClipStateMgr::save(SkCanvas::SaveFlags flags) {
int SkMatrixClipStateMgr::saveLayer(const SkRect* bounds, const SkPaint* paint,
SkCanvas::SaveFlags flags) {
#ifdef SK_DEBUG
if (fCurMCState->fIsSaveLayer) {
SkASSERT(0 == fSkipOffsets->count());
}
#endif
// Since the saveLayer call draws something we need to potentially dump
// out the MC state
this->call(kOther_CallType);
SkDEBUGCODE(bool saved =) this->call(kOther_CallType);
int result = this->MCStackPush(flags);
++fCurMCState->fLayerID;
fCurMCState->fIsSaveLayer = true;
#ifdef SK_DEBUG
if (saved) {
fCurMCState->fExpectedDepth++; // 1 for nesting save
}
fCurMCState->fExpectedDepth++; // 1 for saveLayer
#endif
fCurMCState->fSaveLayerBaseStateID = fCurOpenStateID;
fCurMCState->fSavedSkipOffsets = fSkipOffsets;
@ -158,6 +175,9 @@ int SkMatrixClipStateMgr::saveLayer(const SkRect* bounds, const SkPaint* paint,
fPicRecord->recordSaveLayer(bounds, paint,
(SkCanvas::SaveFlags)(flags| SkCanvas::kMatrixClip_SaveFlag));
#ifdef SK_DEBUG
fActualDepth++;
#endif
return result;
}
@ -165,13 +185,25 @@ void SkMatrixClipStateMgr::restore() {
SkDEBUGCODE(this->validate();)
if (fCurMCState->fIsSaveLayer) {
if (fCurMCState->fSaveLayerBaseStateID != fCurOpenStateID) {
if (fCurMCState->fHasOpen) {
fCurMCState->fHasOpen = false;
fPicRecord->recordRestore(); // Close the open block inside the saveLayer
#ifdef SK_DEBUG
SkASSERT(fActualDepth > 0);
fActualDepth--;
#endif
} else {
SkASSERT(0 == fSkipOffsets->count());
}
// The saveLayer's don't carry any matrix or clip state in the
// new scheme so make sure the saveLayer's recordRestore doesn't
// try to finalize them (i.e., fill in their skip offsets).
fPicRecord->recordRestore(false); // close of saveLayer
#ifdef SK_DEBUG
SkASSERT(fActualDepth > 0);
fActualDepth--;
#endif
fCurOpenStateID = fCurMCState->fSaveLayerBaseStateID;
@ -182,10 +214,23 @@ void SkMatrixClipStateMgr::restore() {
fSkipOffsets = fCurMCState->fSavedSkipOffsets;
}
bool prevHadOpen = fCurMCState->fHasOpen;
bool prevWasSaveLayer = fCurMCState->fIsSaveLayer;
fCurMCState->~MatrixClipState(); // balanced in save()
fMatrixClipStack.pop_back();
fCurMCState = (MatrixClipState*)fMatrixClipStack.back();
if (!prevWasSaveLayer) {
fCurMCState->fHasOpen = prevHadOpen;
}
if (fCurMCState->fIsSaveLayer) {
if (0 != fSkipOffsets->count()) {
SkASSERT(fCurMCState->fHasOpen);
}
}
SkDEBUGCODE(this->validate();)
}
@ -198,6 +243,25 @@ int32_t SkMatrixClipStateMgr::NewMCStateID() {
return gMCStateID;
}
bool SkMatrixClipStateMgr::isCurrentlyOpen(int32_t stateID) {
if (fCurMCState->fIsSaveLayer)
return false;
SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart);
for (const MatrixClipState* state = (const MatrixClipState*) iter.prev();
state != NULL;
state = (const MatrixClipState*) iter.prev()) {
if (state->fIsSaveLayer) {
if (state->fSaveLayerBaseStateID == stateID) {
return true;
}
}
}
return false;
}
bool SkMatrixClipStateMgr::call(CallType callType) {
SkDEBUGCODE(this->validate();)
@ -215,18 +279,36 @@ bool SkMatrixClipStateMgr::call(CallType callType) {
return false;
}
if (kIdentityWideOpenStateID != fCurOpenStateID &&
(!fCurMCState->fIsSaveLayer ||
fCurMCState->fSaveLayerBaseStateID != fCurOpenStateID)) {
if (kIdentityWideOpenStateID != fCurOpenStateID &&
!this->isCurrentlyOpen(fCurOpenStateID)) {
// Don't write a restore if the open state is one in which a saveLayer
// is nested. The save after the saveLayer's restore will close it.
fPicRecord->recordRestore(); // Close the open block
fCurMCState->fHasOpen = false;
#ifdef SK_DEBUG
SkASSERT(fActualDepth > 0);
fActualDepth--;
#endif
}
// Install the required MC state as the active one
fCurOpenStateID = fCurMCState->fMCStateID;
if (kIdentityWideOpenStateID == fCurOpenStateID) {
SkASSERT(0 == fActualDepth);
SkASSERT(!fCurMCState->fHasOpen);
SkASSERT(0 == fSkipOffsets->count());
return false;
}
SkASSERT(!fCurMCState->fHasOpen);
SkASSERT(0 == fSkipOffsets->count());
fCurMCState->fHasOpen = true;
fPicRecord->recordSave(SkCanvas::kMatrixClip_SaveFlag);
#ifdef SK_DEBUG
fActualDepth++;
SkASSERT(fActualDepth == fCurMCState->fExpectedDepth);
#endif
// write out clips
SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart);
@ -241,19 +323,33 @@ bool SkMatrixClipStateMgr::call(CallType callType) {
}
}
int curMatID;
if (NULL == state) {
// There was no saveLayer in the MC stack so we need to output them all
iter.reset(fMatrixClipStack, SkDeque::Iter::kFront_IterStart);
state = (const MatrixClipState*) iter.next();
curMatID = kIdentityMatID;
} else {
// SkDeque's iterators actually return the previous location so we
// need to reverse and go forward one to get back on track.
iter.next();
SkDEBUGCODE(const MatrixClipState* test = (const MatrixClipState*)) iter.next();
SkASSERT(test == state);
curMatID = state->fMatrixInfo->getID(this);
// TODO: this assumes that, in the case of Save|SaveLayer when the SaveLayer
// doesn't save the clip, that the SaveLayer doesn't add any additional clip state.
// This assumption will be removed when we explicitly store the clip state in
// self-contained objects. It is valid for the small set of skps.
if (NULL != state->fPrev && state->fClipInfo == state->fPrev->fClipInfo) {
// By the above assumption the SaveLayer's MC state has already been
// written out by the prior Save so don't output it again.
state = (const MatrixClipState*) iter.next();
}
}
int curMatID = NULL != state ? state->fMatrixInfo->getID(this) : kIdentityMatID;
for ( ; state != NULL; state = (const MatrixClipState*) iter.next()) {
state->fClipInfo->writeClip(&curMatID, this);
}
@ -271,7 +367,6 @@ bool SkMatrixClipStateMgr::call(CallType callType) {
}
SkDEBUGCODE(this->validate();)
return true;
}
@ -284,12 +379,19 @@ void SkMatrixClipStateMgr::fillInSkips(SkWriter32* writer, int32_t restoreOffset
}
fSkipOffsets->rewind();
SkASSERT(0 == fSkipOffsets->count());
}
void SkMatrixClipStateMgr::finish() {
if (kIdentityWideOpenStateID != fCurOpenStateID) {
fPicRecord->recordRestore(); // Close the open block
fCurMCState->fHasOpen = false;
#ifdef SK_DEBUG
SkASSERT(fActualDepth > 0);
fActualDepth--;
#endif
fCurOpenStateID = kIdentityWideOpenStateID;
SkASSERT(!fCurMCState->fHasOpen);
}
}
@ -305,10 +407,12 @@ void SkMatrixClipStateMgr::validate() {
for (const MatrixClipState* state = (const MatrixClipState*) iter.prev();
state != NULL;
state = (const MatrixClipState*) iter.prev()) {
clipCount += state->fClipInfo->numClips();
if (state->fIsSaveLayer) {
break;
}
if (NULL == state->fPrev || state->fPrev->fClipInfo != state->fClipInfo) {
clipCount += state->fClipInfo->numClips();
}
if (state->fIsSaveLayer) {
break;
}
}
SkASSERT(fSkipOffsets->count() == clipCount);

View File

@ -180,10 +180,10 @@ public:
};
MatrixClipState(MatrixClipState* prev, int flags)
#ifdef SK_DEBUG
: fPrev(prev)
#endif
{
fHasOpen = false;
if (NULL == prev) {
fLayerID = 0;
@ -193,6 +193,9 @@ public:
// The identity/wide-open-clip state is current by default
fMCStateID = kIdentityWideOpenStateID;
#ifdef SK_DEBUG
fExpectedDepth = 1;
#endif
}
else {
fLayerID = prev->fLayerID;
@ -214,6 +217,9 @@ public:
// Initially a new save/saveLayer represents the same MC state
// as its predecessor.
fMCStateID = prev->fMCStateID;
#ifdef SK_DEBUG
fExpectedDepth = prev->fExpectedDepth;
#endif
}
fIsSaveLayer = false;
@ -234,8 +240,13 @@ public:
int32_t fSaveLayerBaseStateID;
SkTDArray<int>* fSavedSkipOffsets;
// Does the MC state have an open block in the skp?
bool fHasOpen;
MatrixClipState* fPrev;
#ifdef SK_DEBUG
MatrixClipState* fPrev; // debugging aid
int fExpectedDepth; // debugging aid
#endif
int32_t fMCStateID;
@ -365,6 +376,8 @@ protected:
void addClipOffset(int offset) {
SkASSERT(NULL != fSkipOffsets);
SkASSERT(kIdentityWideOpenStateID != fCurOpenStateID);
SkASSERT(fCurMCState->fHasOpen);
SkASSERT(!fCurMCState->fIsSaveLayer);
*fSkipOffsets->append() = offset;
}
@ -385,6 +398,12 @@ protected:
SkASSERT(index >= 0 && index < fMatrixDict.count());
return fMatrixDict[index];
}
bool isCurrentlyOpen(int32_t stateID);
#ifdef SK_DEBUG
int fActualDepth;
#endif
};
#endif