Index: src/core/SkPicturePlayback.cpp |
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp |
index 734a54a3c7e9a2e9ec9f69701c0f74176db013c1..eee63d20ec2e5480f16fd7bbaca30c454e2bab63 100644 |
--- a/src/core/SkPicturePlayback.cpp |
+++ b/src/core/SkPicturePlayback.cpp |
@@ -106,17 +106,7 @@ static SkBitmap shallow_copy(const SkBitmap& bitmap) { |
return bitmap; |
} |
-void SkPicturePlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) { |
- AutoResetOpID aroi(this); |
- SkASSERT(0 == fCurOffset); |
- |
- // kDrawComplete will be the signal that we have reached the end of |
- // the command stream |
- static const uint32_t kDrawComplete = SK_MaxU32; |
- |
- SkReader32 reader(fPictureData->fOpData->bytes(), fPictureData->fOpData->size()); |
- SkAutoTDelete<const SkPicture::OperationList> activeOpsList; |
- const SkTDArray<void*>* activeOps = NULL; |
+const SkPicture::OperationList* SkPicturePlayback::getActiveOps(const SkCanvas* canvas) { |
if (fUseBBH && NULL != fPictureData->fStateTree && NULL != fPictureData->fBoundingHierarchy) { |
SkRect clipBounds; |
@@ -124,28 +114,151 @@ void SkPicturePlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) |
SkIRect query; |
clipBounds.roundOut(&query); |
- activeOpsList.reset(fPictureData->getActiveOps(query)); |
- if (NULL != activeOpsList.get()) { |
- if (0 == activeOpsList->numOps()) { |
- return; // nothing to draw |
+ return fPictureData->getActiveOps(query); |
+ } |
+ } |
+ |
+ return NULL; |
+} |
+ |
+// Initialize the state tree iterator. Return false if there is nothing left to draw. |
+bool SkPicturePlayback::initIterator(SkPictureStateTree::Iterator* iter, |
+ SkCanvas* canvas, |
+ const SkPicture::OperationList *activeOpsList) { |
+ |
+ if (NULL != activeOpsList) { |
+ if (0 == activeOpsList->numOps()) { |
+ return false; // nothing to draw |
+ } |
+ |
+ fPictureData->fStateTree->initIterator(iter, activeOpsList->fOps, canvas); |
+ } |
+ |
+ return true; |
+} |
+ |
+bool SkPicturePlayback::replaceOps(SkPictureStateTree::Iterator* iter, |
+ SkReader32* reader, |
+ SkCanvas* canvas, |
+ const SkMatrix& initialMatrix) { |
+ if (NULL != fReplacements) { |
+ // Potentially replace a block of operations with a single drawBitmap call |
+ SkPicturePlayback::PlaybackReplacements::ReplacementInfo* temp = |
+ fReplacements->lookupByStart(reader->offset()); |
+ if (NULL != temp) { |
+ SkASSERT(NULL != temp->fBM); |
+ SkASSERT(NULL != temp->fPaint); |
+ canvas->save(); |
+ canvas->setMatrix(initialMatrix); |
+ SkRect src = SkRect::Make(temp->fSrcRect); |
+ SkRect dst = SkRect::MakeXYWH(temp->fPos.fX, temp->fPos.fY, |
+ temp->fSrcRect.width(), |
+ temp->fSrcRect.height()); |
+ canvas->drawBitmapRectToRect(*temp->fBM, &src, dst, temp->fPaint); |
+ canvas->restore(); |
+ |
+ if (iter->isValid()) { |
+ // This save is needed since the BBH will automatically issue |
+ // a restore to balanced the saveLayer we're skipping |
+ canvas->save(); |
+ |
+ // At this point we know that the PictureStateTree was aiming |
+ // for some draw op within temp's saveLayer (although potentially |
+ // in a separate saveLayer nested inside it). |
+ // We need to skip all the operations inside temp's range |
+ // along with all the associated state changes but update |
+ // the state tree to the first operation outside temp's range. |
+ |
+ uint32_t skipTo; |
+ do { |
+ skipTo = iter->nextDraw(); |
+ if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { |
+ break; |
+ } |
+ |
+ if (skipTo <= temp->fStop) { |
+ reader->setOffset(skipTo); |
+ uint32_t size; |
+ DrawType op = ReadOpAndSize(reader, &size); |
+ // Since we are relying on the normal SkPictureStateTree |
+ // playback we need to convert any nested saveLayer calls |
+ // it may issue into saves (so that all its internal |
+ // restores will be balanced). |
+ if (SAVE_LAYER == op) { |
+ canvas->save(); |
+ } |
+ } |
+ } while (skipTo <= temp->fStop); |
+ |
+ if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { |
+ reader->setOffset(reader->size()); // skip to end |
+ return true; |
} |
- activeOps = &(activeOpsList.get()->fOps); |
+ reader->setOffset(skipTo); |
+ } else { |
+ reader->setOffset(temp->fStop); |
+ uint32_t size; |
+ SkDEBUGCODE(DrawType op = ) ReadOpAndSize(reader, &size); |
+ SkASSERT(RESTORE == op); |
} |
+ |
+ return true; |
} |
} |
- SkPictureStateTree::Iterator it = (NULL == activeOps) ? |
- SkPictureStateTree::Iterator() : |
- fPictureData->fStateTree->getIterator(*activeOps, canvas); |
+ return false; |
+} |
- if (it.isValid()) { |
- uint32_t skipTo = it.nextDraw(); |
- if (kDrawComplete == skipTo) { |
- return; |
+// If 'iter' is valid use it to skip forward through the picture. |
+void SkPicturePlayback::StepIterator(SkPictureStateTree::Iterator* iter, SkReader32* reader) { |
+ if (iter->isValid()) { |
+ uint32_t skipTo = iter->nextDraw(); |
+ if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { |
+ reader->setOffset(reader->size()); // skip to end |
+ } else { |
+ reader->setOffset(skipTo); |
} |
- reader.setOffset(skipTo); |
} |
+} |
+ |
+// Update the iterator and state tree to catch up with the skipped ops. |
+void SkPicturePlayback::SkipIterTo(SkPictureStateTree::Iterator* iter, |
+ SkReader32* reader, |
+ uint32_t skipTo) { |
+ SkASSERT(skipTo <= reader->size()); |
+ SkASSERT(reader->offset() <= skipTo); // should only be skipping forward |
+ |
+ if (iter->isValid()) { |
+ // If using a bounding box hierarchy, advance the state tree |
+ // iterator until at or after skipTo |
+ uint32_t adjustedSkipTo; |
+ do { |
+ adjustedSkipTo = iter->nextDraw(); |
+ } while (adjustedSkipTo < skipTo); |
+ skipTo = adjustedSkipTo; |
+ } |
+ if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { |
+ reader->setOffset(reader->size()); // skip to end |
+ } else { |
+ reader->setOffset(skipTo); |
+ } |
+} |
+ |
+void SkPicturePlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) { |
+ AutoResetOpID aroi(this); |
+ SkASSERT(0 == fCurOffset); |
+ |
+ SkAutoTDelete<const SkPicture::OperationList> activeOpsList(this->getActiveOps(canvas)); |
+ SkPictureStateTree::Iterator it; |
+ |
+ if (!this->initIterator(&it, canvas, activeOpsList.get())) { |
+ return; // nothing to draw |
+ } |
+ |
+ SkReader32 reader(fPictureData->opData()->bytes(), fPictureData->opData()->size()); |
+ |
+ StepIterator(&it, &reader); |
// Record this, so we can concat w/ it if we encounter a setMatrix() |
SkMatrix initialMatrix = canvas->getTotalMatrix(); |
@@ -153,109 +266,26 @@ void SkPicturePlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) |
SkAutoCanvasRestore acr(canvas, false); |
while (!reader.eof()) { |
- if (callback && callback->abortDrawing()) { |
+ if (NULL != callback && callback->abortDrawing()) { |
return; |
} |
- if (NULL != fReplacements) { |
- // Potentially replace a block of operations with a single drawBitmap call |
- SkPicturePlayback::PlaybackReplacements::ReplacementInfo* temp = |
- fReplacements->lookupByStart(reader.offset()); |
- if (NULL != temp) { |
- SkASSERT(NULL != temp->fBM); |
- SkASSERT(NULL != temp->fPaint); |
- canvas->save(); |
- canvas->setMatrix(initialMatrix); |
- SkRect src = SkRect::Make(temp->fSrcRect); |
- SkRect dst = SkRect::MakeXYWH(temp->fPos.fX, temp->fPos.fY, |
- temp->fSrcRect.width(), |
- temp->fSrcRect.height()); |
- canvas->drawBitmapRectToRect(*temp->fBM, &src, dst, temp->fPaint); |
- canvas->restore(); |
- |
- if (it.isValid()) { |
- // This save is needed since the BBH will automatically issue |
- // a restore to balanced the saveLayer we're skipping |
- canvas->save(); |
- |
- // At this point we know that the PictureStateTree was aiming |
- // for some draw op within temp's saveLayer (although potentially |
- // in a separate saveLayer nested inside it). |
- // We need to skip all the operations inside temp's range |
- // along with all the associated state changes but update |
- // the state tree to the first operation outside temp's range. |
- |
- uint32_t skipTo; |
- do { |
- skipTo = it.nextDraw(); |
- if (kDrawComplete == skipTo) { |
- break; |
- } |
- |
- if (skipTo <= temp->fStop) { |
- reader.setOffset(skipTo); |
- uint32_t size; |
- DrawType op = ReadOpAndSize(&reader, &size); |
- // Since we are relying on the normal SkPictureStateTree |
- // playback we need to convert any nested saveLayer calls |
- // it may issue into saves (so that all its internal |
- // restores will be balanced). |
- if (SAVE_LAYER == op) { |
- canvas->save(); |
- } |
- } |
- } while (skipTo <= temp->fStop); |
- |
- if (kDrawComplete == skipTo) { |
- break; |
- } |
- |
- reader.setOffset(skipTo); |
- } else { |
- reader.setOffset(temp->fStop); |
- uint32_t size; |
- SkDEBUGCODE(DrawType op = ) ReadOpAndSize(&reader, &size); |
- SkASSERT(RESTORE == op); |
- } |
- continue; |
- } |
+ if (this->replaceOps(&it, &reader, canvas, initialMatrix)) { |
+ continue; |
} |
fCurOffset = reader.offset(); |
uint32_t size; |
DrawType op = ReadOpAndSize(&reader, &size); |
- size_t skipTo = 0; |
if (NOOP == op) { |
// NOOPs are to be ignored - do not propagate them any further |
- skipTo = fCurOffset + size; |
- } |
- |
- if (0 != skipTo) { |
- if (it.isValid()) { |
- // If using a bounding box hierarchy, advance the state tree |
- // iterator until at or after skipTo |
- uint32_t adjustedSkipTo; |
- do { |
- adjustedSkipTo = it.nextDraw(); |
- } while (adjustedSkipTo < skipTo); |
- skipTo = adjustedSkipTo; |
- } |
- if (kDrawComplete == skipTo) { |
- break; |
- } |
- reader.setOffset(skipTo); |
+ SkipIterTo(&it, &reader, fCurOffset + size); |
continue; |
} |
this->handleOp(&reader, op, size, canvas, initialMatrix); |
- if (it.isValid()) { |
- uint32_t skipTo = it.nextDraw(); |
- if (kDrawComplete == skipTo) { |
- break; |
- } |
- reader.setOffset(skipTo); |
- } |
+ StepIterator(&it, &reader); |
} |
} |