Index: src/core/SkMatrixClipStateMgr.cpp |
=================================================================== |
--- src/core/SkMatrixClipStateMgr.cpp (revision 13521) |
+++ src/core/SkMatrixClipStateMgr.cpp (working copy) |
@@ -112,6 +112,10 @@ |
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::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 @@ |
fPicRecord->recordSaveLayer(bounds, paint, |
(SkCanvas::SaveFlags)(flags| SkCanvas::kMatrixClip_SaveFlag)); |
+#ifdef SK_DEBUG |
+ fActualDepth++; |
+#endif |
return result; |
} |
@@ -165,13 +185,25 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
} |
} |
+ 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 @@ |
} |
SkDEBUGCODE(this->validate();) |
- |
return true; |
} |
@@ -284,12 +379,19 @@ |
} |
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 @@ |
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); |