| Index: src/core/SkMatrixClipStateMgr.cpp
|
| diff --git a/src/core/SkMatrixClipStateMgr.cpp b/src/core/SkMatrixClipStateMgr.cpp
|
| index cffad712956d35c78c51d34837df3c7450fb1476..4cf99bca97cdf4f5cd7d78e61857d43c497bb48a 100644
|
| --- a/src/core/SkMatrixClipStateMgr.cpp
|
| +++ b/src/core/SkMatrixClipStateMgr.cpp
|
| @@ -21,6 +21,7 @@ bool SkMatrixClipStateMgr::MatrixClipState::ClipInfo::clipPath(SkPictureRecord*
|
| newClip->fOp = op;
|
| newClip->fDoAA = doAA;
|
| newClip->fMatrixID = matrixID;
|
| + newClip->fOffset = kInvalidJumpOffset;
|
| return false;
|
| }
|
|
|
| @@ -35,6 +36,7 @@ bool SkMatrixClipStateMgr::MatrixClipState::ClipInfo::clipRegion(SkPictureRecord
|
| newClip->fOp = op;
|
| newClip->fDoAA = true; // not necessary but sanity preserving
|
| newClip->fMatrixID = matrixID;
|
| + newClip->fOffset = kInvalidJumpOffset;
|
| return false;
|
| }
|
|
|
| @@ -53,10 +55,17 @@ void SkMatrixClipStateMgr::writeDeltaMat(int currentMatID, int desiredMatID) {
|
| // 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) {
|
| + SkMatrixClipStateMgr* mgr,
|
| + bool* overrideFirstOp) {
|
| 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) {
|
| @@ -70,31 +79,43 @@ void SkMatrixClipStateMgr::MatrixClipState::ClipInfo::writeClip(int* curMatID,
|
| mgr->writeDeltaMat(*curMatID, curClip.fMatrixID);
|
| *curMatID = curClip.fMatrixID;
|
|
|
| - int offset;
|
| -
|
| switch (curClip.fClipType) {
|
| case kRect_ClipType:
|
| - offset = mgr->getPicRecord()->recordClipRect(curClip.fGeom.fRRect.rect(),
|
| - curClip.fOp, curClip.fDoAA);
|
| + curClip.fOffset = mgr->getPicRecord()->recordClipRect(curClip.fGeom.fRRect.rect(),
|
| + op, curClip.fDoAA);
|
| break;
|
| case kRRect_ClipType:
|
| - offset = mgr->getPicRecord()->recordClipRRect(curClip.fGeom.fRRect, curClip.fOp,
|
| - curClip.fDoAA);
|
| + curClip.fOffset = mgr->getPicRecord()->recordClipRRect(curClip.fGeom.fRRect, op,
|
| + curClip.fDoAA);
|
| break;
|
| case kPath_ClipType:
|
| - offset = mgr->getPicRecord()->recordClipPath(curClip.fGeom.fPathID, curClip.fOp,
|
| - curClip.fDoAA);
|
| + curClip.fOffset = mgr->getPicRecord()->recordClipPath(curClip.fGeom.fPathID, op,
|
| + curClip.fDoAA);
|
| break;
|
| case kRegion_ClipType: {
|
| const SkRegion* region = mgr->lookupRegion(curClip.fGeom.fRegionID);
|
| - offset = mgr->getPicRecord()->recordClipRegion(*region, curClip.fOp);
|
| + curClip.fOffset = mgr->getPicRecord()->recordClipRegion(*region, op);
|
| break;
|
| }
|
| default:
|
| SkASSERT(0);
|
| }
|
| + }
|
| +}
|
|
|
| - mgr->addClipOffset(offset);
|
| +// 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;)
|
| }
|
| }
|
|
|
| @@ -105,8 +126,6 @@ SkMatrixClipStateMgr::SkMatrixClipStateMgr()
|
| sizeof(fMatrixClipStackStorage))
|
| , fCurOpenStateID(kIdentityWideOpenStateID) {
|
|
|
| - fSkipOffsets = SkNEW(SkTDArray<int>);
|
| -
|
| // The first slot in the matrix dictionary is reserved for the identity matrix
|
| fMatrixDict.append()->reset();
|
|
|
| @@ -118,12 +137,12 @@ SkMatrixClipStateMgr::~SkMatrixClipStateMgr() {
|
| for (int i = 0; i < fRegionDict.count(); ++i) {
|
| SkDELETE(fRegionDict[i]);
|
| }
|
| -
|
| - SkDELETE(fSkipOffsets);
|
| }
|
|
|
|
|
| -int SkMatrixClipStateMgr::MCStackPush(SkCanvas::SaveFlags flags) {
|
| +int SkMatrixClipStateMgr::save(SkCanvas::SaveFlags flags) {
|
| + SkDEBUGCODE(this->validate();)
|
| +
|
| MatrixClipState* newTop = (MatrixClipState*)fMatrixClipStack.push_back();
|
| new (newTop) MatrixClipState(fCurMCState, flags); // balanced in restore()
|
| fCurMCState = newTop;
|
| @@ -133,29 +152,14 @@ int SkMatrixClipStateMgr::MCStackPush(SkCanvas::SaveFlags flags) {
|
| 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) {
|
| - // Since the saveLayer call draws something we need to potentially dump
|
| - // out the MC state
|
| - this->call(kOther_CallType);
|
| -
|
| - int result = this->MCStackPush(flags);
|
| + int result = this->save(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;
|
| @@ -166,20 +170,21 @@ void SkMatrixClipStateMgr::restore() {
|
|
|
| if (fCurMCState->fIsSaveLayer) {
|
| if (fCurMCState->fSaveLayerBaseStateID != fCurOpenStateID) {
|
| - fPicRecord->recordRestore(); // Close the open block inside the saveLayer
|
| + fPicRecord->recordRestore(); // Close the open block
|
| }
|
| // 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
|
|
|
| - fCurOpenStateID = fCurMCState->fSaveLayerBaseStateID;
|
| -
|
| - SkASSERT(0 == fSkipOffsets->count());
|
| - SkASSERT(NULL != fCurMCState->fSavedSkipOffsets);
|
| + // Close the Save that brackets the saveLayer. TODO: this doesn't handle
|
| + // the skip offsets correctly
|
| + if (fCurMCState->fSaveLayerBracketed) {
|
| + fPicRecord->recordRestore(false);
|
| + }
|
|
|
| - SkDELETE(fSkipOffsets);
|
| - fSkipOffsets = fCurMCState->fSavedSkipOffsets;
|
| + // MC states can be allowed to fuse across saveLayer/restore boundaries
|
| + fCurOpenStateID = kIdentityWideOpenStateID;
|
| }
|
|
|
| fCurMCState->~MatrixClipState(); // balanced in save()
|
| @@ -215,11 +220,7 @@ bool SkMatrixClipStateMgr::call(CallType callType) {
|
| return false;
|
| }
|
|
|
| - 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.
|
| + if (kIdentityWideOpenStateID != fCurOpenStateID) {
|
| fPicRecord->recordRestore(); // Close the open block
|
| }
|
|
|
| @@ -229,40 +230,17 @@ bool SkMatrixClipStateMgr::call(CallType callType) {
|
| fPicRecord->recordSave(SkCanvas::kMatrixClip_SaveFlag);
|
|
|
| // write out clips
|
| - 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.prev()) {
|
| - if (state->fIsSaveLayer) {
|
| - break;
|
| - }
|
| - }
|
| + SkDeque::F2BIter iter(fMatrixClipStack);
|
| + bool firstClip = true;
|
|
|
| - 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);
|
| + int curMatID = kIdentityMatID;
|
| + for (const MatrixClipState* state = (const MatrixClipState*) iter.next();
|
| + state != NULL;
|
| + state = (const MatrixClipState*) iter.next()) {
|
| + state->fClipInfo->writeClip(&curMatID, this, &firstClip);
|
| }
|
|
|
| // 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
|
| @@ -275,17 +253,6 @@ bool SkMatrixClipStateMgr::call(CallType callType) {
|
| 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(uint32_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
|
| @@ -295,23 +262,16 @@ void SkMatrixClipStateMgr::finish() {
|
|
|
| #ifdef SK_DEBUG
|
| void SkMatrixClipStateMgr::validate() {
|
| - 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();
|
| + 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();
|
| state != NULL;
|
| - state = (const MatrixClipState*) iter.prev()) {
|
| - clipCount += state->fClipInfo->numClips();
|
| - if (state->fIsSaveLayer) {
|
| - break;
|
| - }
|
| + state = (const MatrixClipState*) iter.next()) {
|
| + state->fClipInfo->checkOffsetNotEqual(-1);
|
| }
|
| -
|
| - SkASSERT(fSkipOffsets->count() == clipCount);
|
| }
|
| }
|
| #endif
|
|
|