diff options
-rw-r--r-- | src/core/SkPicturePlayback.cpp | 254 | ||||
-rw-r--r-- | src/core/SkPicturePlayback.h | 13 | ||||
-rw-r--r-- | src/core/SkPictureStateTree.cpp | 26 | ||||
-rw-r--r-- | src/core/SkPictureStateTree.h | 16 |
4 files changed, 178 insertions, 131 deletions
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp index 734a54a3c7..eee63d20ec 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); } } diff --git a/src/core/SkPicturePlayback.h b/src/core/SkPicturePlayback.h index 4248e2de5c..6c32b15239 100644 --- a/src/core/SkPicturePlayback.h +++ b/src/core/SkPicturePlayback.h @@ -9,6 +9,7 @@ #define SkPicturePlayback_DEFINED #include "SkPictureFlat.h" // for DrawType +#include "SkPictureStateTree.h" class SkBitmap; class SkCanvas; @@ -96,6 +97,18 @@ protected: SkCanvas* canvas, const SkMatrix& initialMatrix); + const SkPicture::OperationList* getActiveOps(const SkCanvas* canvas); + bool initIterator(SkPictureStateTree::Iterator* iter, + SkCanvas* canvas, + const SkPicture::OperationList *activeOpsList); + static void StepIterator(SkPictureStateTree::Iterator* iter, SkReader32* reader); + static void SkipIterTo(SkPictureStateTree::Iterator* iter, + SkReader32* reader, uint32_t skipTo); + bool replaceOps(SkPictureStateTree::Iterator* iter, + SkReader32* reader, + SkCanvas* canvas, + const SkMatrix& initialMatrix); + static DrawType ReadOpAndSize(SkReader32* reader, uint32_t* size); class AutoResetOpID { diff --git a/src/core/SkPictureStateTree.cpp b/src/core/SkPictureStateTree.cpp index fdd86464a9..d2f0e6efcd 100644 --- a/src/core/SkPictureStateTree.cpp +++ b/src/core/SkPictureStateTree.cpp @@ -73,9 +73,10 @@ void SkPictureStateTree::appendClip(size_t offset) { this->appendNode(offset); } -SkPictureStateTree::Iterator SkPictureStateTree::getIterator(const SkTDArray<void*>& draws, - SkCanvas* canvas) { - return Iterator(draws, canvas, &fRoot); +void SkPictureStateTree::initIterator(SkPictureStateTree::Iterator* iter, + const SkTDArray<void*>& draws, + SkCanvas* canvas) { + iter->init(draws, canvas, &fRoot); } void SkPictureStateTree::appendNode(size_t offset) { @@ -88,15 +89,16 @@ void SkPictureStateTree::appendNode(size_t offset) { fCurrentState.fNode = n; } -SkPictureStateTree::Iterator::Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root) - : fDraws(&draws) - , fCanvas(canvas) - , fCurrentNode(root) - , fPlaybackMatrix(canvas->getTotalMatrix()) - , fCurrentMatrix(NULL) - , fPlaybackIndex(0) - , fSave(false) - , fValid(true) { +void SkPictureStateTree::Iterator::init(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root) { + SkASSERT(!fValid); + fDraws = &draws; + fCanvas = canvas; + fCurrentNode = root; + fPlaybackMatrix = canvas->getTotalMatrix(); + fCurrentMatrix = NULL; + fPlaybackIndex = 0; + fSave = false; + fValid = true; } void SkPictureStateTree::Iterator::setCurrentMatrix(const SkMatrix* matrix) { diff --git a/src/core/SkPictureStateTree.h b/src/core/SkPictureStateTree.h index da51a5b954..15bb02f354 100644 --- a/src/core/SkPictureStateTree.h +++ b/src/core/SkPictureStateTree.h @@ -50,11 +50,13 @@ public: Draw* appendDraw(size_t offset); /** - * Given a list of draws, and a canvas, returns an iterator that produces the correct sequence - * of offsets into the command buffer to carry out those calls with correct matrix/clip state. - * This handles saves/restores, and does all necessary matrix setup. + * Given a list of draws, and a canvas, initialize an iterator that produces the correct + * sequence of offsets into the command buffer to carry out those calls with correct + * matrix/clip state. This handles saves/restores, and does all necessary matrix setup. */ - Iterator getIterator(const SkTDArray<void*>& draws, SkCanvas* canvas); + void initIterator(SkPictureStateTree::Iterator* iter, + const SkTDArray<void*>& draws, + SkCanvas* canvas); void appendSave(); void appendSaveLayer(size_t offset); @@ -83,11 +85,11 @@ public: */ uint32_t nextDraw(); static const uint32_t kDrawComplete = SK_MaxU32; - Iterator() : fPlaybackMatrix(), fValid(false) { } + Iterator() : fValid(false) { } bool isValid() const { return fValid; } private: - Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root); + void init(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root); void setCurrentMatrix(const SkMatrix*); @@ -104,7 +106,7 @@ public: SkTDArray<Node*> fNodes; // The matrix of the canvas we're playing back into - const SkMatrix fPlaybackMatrix; + SkMatrix fPlaybackMatrix; // Cache of current matrix, so we can avoid redundantly setting it const SkMatrix* fCurrentMatrix; |