Refactor SkPicturePlayback for SkPictureReplacementPlayback
This CL is intended to maximize code reuse when SkPictureReplacementPlayback is split off. R=mtklein@google.com Author: robertphillips@google.com Review URL: https://codereview.chromium.org/378343002
This commit is contained in:
parent
762c718824
commit
ec66e6264d
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user