| Index: src/core/SkPicturePlayback.cpp
|
| ===================================================================
|
| --- src/core/SkPicturePlayback.cpp (revision 14614)
|
| +++ src/core/SkPicturePlayback.cpp (working copy)
|
| @@ -23,6 +23,33 @@
|
| */
|
| #define SPEW_CLIP_SKIPPINGx
|
|
|
| +SkPicturePlayback::PlaybackReplacements::ReplacementInfo*
|
| +SkPicturePlayback::PlaybackReplacements::push() {
|
| + SkDEBUGCODE(this->validate());
|
| + return fReplacements.push();
|
| +}
|
| +
|
| +void SkPicturePlayback::PlaybackReplacements::freeAll() {
|
| + for (int i = 0; i < fReplacements.count(); ++i) {
|
| + SkDELETE(fReplacements[i].fBM);
|
| + }
|
| + fReplacements.reset();
|
| +}
|
| +
|
| +#ifdef SK_DEBUG
|
| +void SkPicturePlayback::PlaybackReplacements::validate() const {
|
| + // Check that the ranges are monotonically increasing and non-overlapping
|
| + if (fReplacements.count() > 0) {
|
| + SkASSERT(fReplacements[0].fStart < fReplacements[0].fStop);
|
| +
|
| + for (int i = 1; i < fReplacements.count(); ++i) {
|
| + SkASSERT(fReplacements[i].fStart < fReplacements[i].fStop);
|
| + SkASSERT(fReplacements[i-1].fStop < fReplacements[i].fStart);
|
| + }
|
| + }
|
| +}
|
| +#endif
|
| +
|
| SkPicturePlayback::SkPicturePlayback(const SkPicture* picture, const SkPictInfo& info)
|
| : fPicture(picture)
|
| , fInfo(info) {
|
| @@ -205,6 +232,10 @@
|
| fStateTree = NULL;
|
| fCachedActiveOps = NULL;
|
| fCurOffset = 0;
|
| + fUseBBH = true;
|
| + fStart = 0;
|
| + fStop = 0;
|
| + fReplacements = NULL;
|
| }
|
|
|
| SkPicturePlayback::~SkPicturePlayback() {
|
| @@ -744,6 +775,21 @@
|
| SkPicturePlayback* fPlayback;
|
| };
|
|
|
| +// TODO: Replace with hash or pass in "lastLookedUp" hint
|
| +SkPicturePlayback::PlaybackReplacements::ReplacementInfo*
|
| +SkPicturePlayback::PlaybackReplacements::lookupByStart(size_t start) {
|
| + SkDEBUGCODE(this->validate());
|
| + for (int i = 0; i < fReplacements.count(); ++i) {
|
| + if (start == fReplacements[i].fStart) {
|
| + return &fReplacements[i];
|
| + } else if (start < fReplacements[i].fStart) {
|
| + return NULL; // the ranges are monotonically increasing and non-overlapping
|
| + }
|
| + }
|
| +
|
| + return NULL;
|
| +}
|
| +
|
| void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) {
|
| SkAutoResetOpID aroi(this);
|
| SkASSERT(0 == fCurOffset);
|
| @@ -769,20 +815,24 @@
|
| TextContainer text;
|
| const SkTDArray<void*>* activeOps = NULL;
|
|
|
| - if (NULL != fStateTree && NULL != fBoundingHierarchy) {
|
| - SkRect clipBounds;
|
| - if (canvas.getClipBounds(&clipBounds)) {
|
| - SkIRect query;
|
| - clipBounds.roundOut(&query);
|
| + // When draw limits are enabled (i.e., 0 != fStart || 0 != fStop) the state
|
| + // tree isn't used to pick and choose the draw operations
|
| + if (0 == fStart && 0 == fStop) {
|
| + if (fUseBBH && NULL != fStateTree && NULL != fBoundingHierarchy) {
|
| + SkRect clipBounds;
|
| + if (canvas.getClipBounds(&clipBounds)) {
|
| + SkIRect query;
|
| + clipBounds.roundOut(&query);
|
|
|
| - const SkPicture::OperationList& activeOpsList = this->getActiveOps(query);
|
| - if (activeOpsList.valid()) {
|
| - if (0 == activeOpsList.numOps()) {
|
| - return; // nothing to draw
|
| + const SkPicture::OperationList& activeOpsList = this->getActiveOps(query);
|
| + if (activeOpsList.valid()) {
|
| + if (0 == activeOpsList.numOps()) {
|
| + return; // nothing to draw
|
| + }
|
| +
|
| + // Since the opList is valid we know it is our derived class
|
| + activeOps = &((const CachedOperationList&)activeOpsList).fOps;
|
| }
|
| -
|
| - // Since the opList is valid we know it is our derived class
|
| - activeOps = &((const CachedOperationList&)activeOpsList).fOps;
|
| }
|
| }
|
| }
|
| @@ -791,6 +841,14 @@
|
| SkPictureStateTree::Iterator() :
|
| fStateTree->getIterator(*activeOps, &canvas);
|
|
|
| + if (0 != fStart || 0 != fStop) {
|
| + reader.setOffset(fStart);
|
| + uint32_t size;
|
| + SkDEBUGCODE(DrawType op =) read_op_and_size(&reader, &size);
|
| + SkASSERT(SAVE_LAYER == op);
|
| + reader.setOffset(fStart+size);
|
| + }
|
| +
|
| if (it.isValid()) {
|
| uint32_t skipTo = it.nextDraw();
|
| if (kDrawComplete == skipTo) {
|
| @@ -821,7 +879,61 @@
|
| return;
|
| }
|
| #endif
|
| + if (0 != fStart || 0 != fStop) {
|
| + size_t offset = reader.offset() ;
|
| + if (offset >= fStop) {
|
| + uint32_t size;
|
| + SkDEBUGCODE(DrawType op =) read_op_and_size(&reader, &size);
|
| + SkASSERT(RESTORE == op);
|
| + 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.drawBitmap(*temp->fBM, temp->fPos.fX, temp->fPos.fY, temp->fPaint);
|
| +
|
| + if (it.isValid()) {
|
| + // This save is needed since the BBH will automatically issue
|
| + // a restore to balanced the saveLayer we're skipping
|
| + canvas.save();
|
| + // Note: This skipping only works if the client only issues
|
| + // well behaved saveLayer calls (i.e., doesn't use
|
| + // kMatrix_SaveFlag or kClip_SaveFlag in isolation)
|
| +
|
| + // 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.
|
| + SkASSERT(it.peekDraw() >= temp->fStart && it.peekDraw() <= temp->fStop);
|
| +
|
| + while (kDrawComplete != it.peekDraw() && it.peekDraw() <= temp->fStop) {
|
| + it.skipDraw();
|
| + }
|
| +
|
| + if (kDrawComplete == it.peekDraw()) {
|
| + break;
|
| + }
|
| +
|
| + uint32_t skipTo = it.nextDraw();
|
| + reader.setOffset(skipTo);
|
| + } else {
|
| + reader.setOffset(temp->fStop);
|
| + uint32_t size;
|
| + SkDEBUGCODE(DrawType op =) read_op_and_size(&reader, &size);
|
| + SkASSERT(RESTORE == op);
|
| + }
|
| + continue;
|
| + }
|
| + }
|
| +
|
| #ifdef SPEW_CLIP_SKIPPING
|
| opCount++;
|
| #endif
|
| @@ -915,8 +1027,7 @@
|
| SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
|
| bool doAA = ClipParams_unpackDoAA(packed);
|
| size_t offsetToRestore = reader.readInt();
|
| - SkASSERT(!offsetToRestore || \
|
| - offsetToRestore >= reader.offset());
|
| + SkASSERT(!offsetToRestore || offsetToRestore >= reader.offset());
|
| canvas.clipRRect(rrect, regionOp, doAA);
|
| if (canvas.isClipEmpty() && offsetToRestore) {
|
| #ifdef SPEW_CLIP_SKIPPING
|
|
|