Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(640)

Unified Diff: src/core/SkMatrixClipStateMgr.cpp

Issue 169283011: Fix saveLayer bugs in SkMatrixClipStateMgr (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/core/SkMatrixClipStateMgr.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « src/core/SkMatrixClipStateMgr.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698