Index: src/core/SkMatrixClipStateMgr.cpp |
=================================================================== |
--- src/core/SkMatrixClipStateMgr.cpp (revision 13495) |
+++ src/core/SkMatrixClipStateMgr.cpp (working copy) |
@@ -21,7 +21,6 @@ |
newClip->fOp = op; |
newClip->fDoAA = doAA; |
newClip->fMatrixID = matrixID; |
- newClip->fOffset = kInvalidJumpOffset; |
return false; |
} |
@@ -36,7 +35,6 @@ |
newClip->fOp = op; |
newClip->fDoAA = true; // not necessary but sanity preserving |
newClip->fMatrixID = matrixID; |
- newClip->fOffset = kInvalidJumpOffset; |
return false; |
} |
@@ -55,17 +53,10 @@ |
// Note: this only writes out the clips for the current save state. To get the |
// entire clip stack requires iterating of the entire matrix/clip stack. |
void SkMatrixClipStateMgr::MatrixClipState::ClipInfo::writeClip(int* curMatID, |
- SkMatrixClipStateMgr* mgr, |
- bool* overrideFirstOp) { |
+ SkMatrixClipStateMgr* mgr) { |
for (int i = 0; i < fClips.count(); ++i) { |
ClipOp& curClip = fClips[i]; |
- SkRegion::Op op = curClip.fOp; |
- if (*overrideFirstOp) { |
- op = SkRegion::kReplace_Op; |
- *overrideFirstOp = false; |
- } |
- |
// TODO: use the matrix ID to skip writing the identity matrix |
// over and over, i.e.: |
// if (*curMatID != curClip.fMatrixID) { |
@@ -79,43 +70,31 @@ |
mgr->writeDeltaMat(*curMatID, curClip.fMatrixID); |
*curMatID = curClip.fMatrixID; |
+ int offset = 0; |
+ |
switch (curClip.fClipType) { |
case kRect_ClipType: |
- curClip.fOffset = mgr->getPicRecord()->recordClipRect(curClip.fGeom.fRRect.rect(), |
- op, curClip.fDoAA); |
+ offset = mgr->getPicRecord()->recordClipRect(curClip.fGeom.fRRect.rect(), |
+ curClip.fOp, curClip.fDoAA); |
break; |
case kRRect_ClipType: |
- curClip.fOffset = mgr->getPicRecord()->recordClipRRect(curClip.fGeom.fRRect, op, |
- curClip.fDoAA); |
+ offset = mgr->getPicRecord()->recordClipRRect(curClip.fGeom.fRRect, curClip.fOp, |
+ curClip.fDoAA); |
break; |
case kPath_ClipType: |
- curClip.fOffset = mgr->getPicRecord()->recordClipPath(curClip.fGeom.fPathID, op, |
- curClip.fDoAA); |
+ offset = mgr->getPicRecord()->recordClipPath(curClip.fGeom.fPathID, curClip.fOp, |
+ curClip.fDoAA); |
break; |
case kRegion_ClipType: { |
const SkRegion* region = mgr->lookupRegion(curClip.fGeom.fRegionID); |
- curClip.fOffset = mgr->getPicRecord()->recordClipRegion(*region, op); |
+ offset = mgr->getPicRecord()->recordClipRegion(*region, curClip.fOp); |
break; |
} |
default: |
SkASSERT(0); |
} |
- } |
-} |
-// Fill in the skip offsets for all the clips written in the current block |
-void SkMatrixClipStateMgr::MatrixClipState::ClipInfo::fillInSkips(SkWriter32* writer, |
- int32_t restoreOffset) { |
- for (int i = 0; i < fClips.count(); ++i) { |
- ClipOp& curClip = fClips[i]; |
- |
- if (-1 == curClip.fOffset) { |
- continue; |
- } |
-// SkDEBUGCODE(uint32_t peek = writer->read32At(curClip.fOffset);) |
-// SkASSERT(-1 == peek); |
- writer->overwriteTAt(curClip.fOffset, restoreOffset); |
- SkDEBUGCODE(curClip.fOffset = -1;) |
+ mgr->addClipOffset(offset); |
} |
} |
@@ -126,6 +105,8 @@ |
sizeof(fMatrixClipStackStorage)) |
, fCurOpenStateID(kIdentityWideOpenStateID) { |
+ fSkipOffsets = SkNEW(SkTDArray<int>); |
+ |
// The first slot in the matrix dictionary is reserved for the identity matrix |
fMatrixDict.append()->reset(); |
@@ -137,12 +118,12 @@ |
for (int i = 0; i < fRegionDict.count(); ++i) { |
SkDELETE(fRegionDict[i]); |
} |
+ |
+ SkDELETE(fSkipOffsets); |
} |
-int SkMatrixClipStateMgr::save(SkCanvas::SaveFlags flags) { |
- SkDEBUGCODE(this->validate();) |
- |
+int SkMatrixClipStateMgr::MCStackPush(SkCanvas::SaveFlags flags) { |
MatrixClipState* newTop = (MatrixClipState*)fMatrixClipStack.push_back(); |
new (newTop) MatrixClipState(fCurMCState, flags); // balanced in restore() |
fCurMCState = newTop; |
@@ -152,14 +133,29 @@ |
return fMatrixClipStack.count(); |
} |
+int SkMatrixClipStateMgr::save(SkCanvas::SaveFlags flags) { |
+ SkDEBUGCODE(this->validate();) |
+ |
+ return this->MCStackPush(flags); |
+} |
+ |
int SkMatrixClipStateMgr::saveLayer(const SkRect* bounds, const SkPaint* paint, |
SkCanvas::SaveFlags flags) { |
- int result = this->save(flags); |
+ // Since the saveLayer call draws something we need to potentially dump |
+ // out the MC state |
+ this->call(kOther_CallType); |
+ |
+ int result = this->MCStackPush(flags); |
++fCurMCState->fLayerID; |
fCurMCState->fIsSaveLayer = true; |
- fCurMCState->fSaveLayerBracketed = this->call(kOther_CallType); |
fCurMCState->fSaveLayerBaseStateID = fCurOpenStateID; |
+ fCurMCState->fSavedSkipOffsets = fSkipOffsets; |
+ |
+ // TODO: recycle these rather then new & deleting them on every saveLayer/ |
+ // restore |
+ fSkipOffsets = SkNEW(SkTDArray<int>); |
+ |
fPicRecord->recordSaveLayer(bounds, paint, |
(SkCanvas::SaveFlags)(flags| SkCanvas::kMatrixClip_SaveFlag)); |
return result; |
@@ -170,21 +166,20 @@ |
if (fCurMCState->fIsSaveLayer) { |
if (fCurMCState->fSaveLayerBaseStateID != fCurOpenStateID) { |
- fPicRecord->recordRestore(); // Close the open block |
+ fPicRecord->recordRestore(); // Close the open block inside the saveLayer |
} |
// 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 |
- // Close the Save that brackets the saveLayer. TODO: this doesn't handle |
- // the skip offsets correctly |
- if (fCurMCState->fSaveLayerBracketed) { |
- fPicRecord->recordRestore(false); |
- } |
+ fCurOpenStateID = fCurMCState->fSaveLayerBaseStateID; |
- // MC states can be allowed to fuse across saveLayer/restore boundaries |
- fCurOpenStateID = kIdentityWideOpenStateID; |
+ SkASSERT(0 == fSkipOffsets->count()); |
+ SkASSERT(NULL != fCurMCState->fSavedSkipOffsets); |
+ |
+ SkDELETE(fSkipOffsets); |
+ fSkipOffsets = fCurMCState->fSavedSkipOffsets; |
} |
fCurMCState->~MatrixClipState(); // balanced in save() |
@@ -220,7 +215,11 @@ |
return false; |
} |
- if (kIdentityWideOpenStateID != fCurOpenStateID) { |
+ if (kIdentityWideOpenStateID != fCurOpenStateID && |
+ (!fCurMCState->fIsSaveLayer || |
+ fCurMCState->fSaveLayerBaseStateID != 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 |
} |
@@ -230,17 +229,40 @@ |
fPicRecord->recordSave(SkCanvas::kMatrixClip_SaveFlag); |
// write out clips |
- SkDeque::F2BIter iter(fMatrixClipStack); |
- bool firstClip = true; |
- |
- int curMatID = kIdentityMatID; |
- for (const MatrixClipState* state = (const MatrixClipState*) iter.next(); |
+ SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart); |
+ const MatrixClipState* state; |
+ // Loop back across the MC states until the last saveLayer. The MC |
+ // state in front of the saveLayer has already been written out. |
+ for (state = (const MatrixClipState*) iter.prev(); |
state != NULL; |
- state = (const MatrixClipState*) iter.next()) { |
- state->fClipInfo->writeClip(&curMatID, this, &firstClip); |
+ state = (const MatrixClipState*) iter.prev()) { |
+ if (state->fIsSaveLayer) { |
+ break; |
+ } |
} |
+ 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(); |
+ } 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); |
+ } |
+ |
+ int curMatID = NULL != state ? state->fMatrixInfo->getID(this) : kIdentityMatID; |
+ for ( ; state != NULL; state = (const MatrixClipState*) iter.next()) { |
+ state->fClipInfo->writeClip(&curMatID, this); |
+ } |
+ |
// write out matrix |
+ // TODO: this test isn't quite right. It should be: |
+ // if (curMatID != fCurMCState->fMatrixInfo->getID(this)) { |
+ // but right now the testing harness always expects a matrix if |
+ // the matrices are non-I |
if (kIdentityMatID != fCurMCState->fMatrixInfo->getID(this)) { |
// TODO: writing out the delta matrix here is an artifact of the writing |
// out of the entire clip stack (with its matrices). Ultimately we will |
@@ -253,6 +275,17 @@ |
return true; |
} |
+// Fill in the skip offsets for all the clips written in the current block |
+void SkMatrixClipStateMgr::fillInSkips(SkWriter32* writer, int32_t restoreOffset) { |
+ for (int i = 0; i < fSkipOffsets->count(); ++i) { |
+ SkDEBUGCODE(int32_t peek = writer->readTAt<int32_t>((*fSkipOffsets)[i]);) |
+ SkASSERT(-1 == peek); |
+ writer->overwriteTAt<int32_t>((*fSkipOffsets)[i], restoreOffset); |
+ } |
+ |
+ fSkipOffsets->rewind(); |
+} |
+ |
void SkMatrixClipStateMgr::finish() { |
if (kIdentityWideOpenStateID != fCurOpenStateID) { |
fPicRecord->recordRestore(); // Close the open block |
@@ -262,16 +295,23 @@ |
#ifdef SK_DEBUG |
void SkMatrixClipStateMgr::validate() { |
- if (fCurOpenStateID == fCurMCState->fMCStateID) { |
- // The current state is the active one so all its skip offsets should |
- // still be -1 |
- SkDeque::F2BIter iter(fMatrixClipStack); |
- |
- for (const MatrixClipState* state = (const MatrixClipState*) iter.next(); |
+ if (fCurOpenStateID == fCurMCState->fMCStateID && |
+ (!fCurMCState->fIsSaveLayer || |
+ fCurOpenStateID != fCurMCState->fSaveLayerBaseStateID)) { |
+ // The current state is the active one so it should have a skip |
+ // offset for each clip |
+ SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart); |
+ int clipCount = 0; |
+ for (const MatrixClipState* state = (const MatrixClipState*) iter.prev(); |
state != NULL; |
- state = (const MatrixClipState*) iter.next()) { |
- state->fClipInfo->checkOffsetNotEqual(-1); |
+ state = (const MatrixClipState*) iter.prev()) { |
+ clipCount += state->fClipInfo->numClips(); |
+ if (state->fIsSaveLayer) { |
+ break; |
+ } |
} |
+ |
+ SkASSERT(fSkipOffsets->count() == clipCount); |
} |
} |
#endif |