| Index: src/pipe/SkGPipeWrite.cpp
|
| diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
|
| index b61de1c912db6c3088048be23042ae405818f715..43240803256ca534e33fe31c8c1169eadeeee19c 100644
|
| --- a/src/pipe/SkGPipeWrite.cpp
|
| +++ b/src/pipe/SkGPipeWrite.cpp
|
| @@ -167,32 +167,63 @@ public:
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| +/**
|
| + * If SkBitmaps are to be flattened to send to the reader, this class is
|
| + * provided to the SkBitmapHeap to tell the SkGPipeCanvas to do so.
|
| + */
|
| +class BitmapShuttle : public SkBitmapHeap::ExternalStorage {
|
| +public:
|
| + BitmapShuttle(SkGPipeCanvas*);
|
| +
|
| + ~BitmapShuttle();
|
| +
|
| + virtual bool insert(const SkBitmap& bitmap, int32_t slot) SK_OVERRIDE;
|
| +
|
| + /**
|
| + * Remove the SkGPipeCanvas used for insertion. After this, calls to
|
| + * insert will crash.
|
| + */
|
| + void removeCanvas();
|
| +
|
| +private:
|
| + SkGPipeCanvas* fCanvas;
|
| +};
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| class SkGPipeCanvas : public SkCanvas {
|
| public:
|
| SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags,
|
| uint32_t width, uint32_t height);
|
| virtual ~SkGPipeCanvas();
|
|
|
| - void finish() {
|
| - if (!fDone) {
|
| - if (this->needOpBytes()) {
|
| - this->writeOp(kDone_DrawOp);
|
| - this->doNotify();
|
| - if (shouldFlattenBitmaps(fFlags)) {
|
| - // In this case, a BitmapShuttle is reffed by the SkBitmapHeap
|
| - // and refs this canvas. Unref the SkBitmapHeap to end the
|
| - // circular reference. When shouldFlattenBitmaps is false,
|
| - // there is no circular reference, so the SkBitmapHeap can be
|
| - // safely unreffed in the destructor.
|
| - fBitmapHeap->unref();
|
| - // This eliminates a similar circular reference (Canvas owns
|
| - // the FlattenableHeap which holds a ref to the SkBitmapHeap).
|
| - fFlattenableHeap.setBitmapStorage(NULL);
|
| - fBitmapHeap = NULL;
|
| - }
|
| - }
|
| - fDone = true;
|
| + /**
|
| + * Called when nothing else is to be written to the stream. Any repeated
|
| + * calls are ignored.
|
| + *
|
| + * @param notifyReaders Whether to send a message to the reader(s) that
|
| + * the writer is through sending commands. Should generally be true,
|
| + * unless there is an error which prevents further messages from
|
| + * being sent.
|
| + */
|
| + void finish(bool notifyReaders) {
|
| + if (fDone) {
|
| + return;
|
| + }
|
| + if (notifyReaders && this->needOpBytes()) {
|
| + this->writeOp(kDone_DrawOp);
|
| + this->doNotify();
|
| }
|
| + if (shouldFlattenBitmaps(fFlags)) {
|
| + // The following circular references exist:
|
| + // fFlattenableHeap -> fWriteBuffer -> fBitmapStorage -> fExternalStorage -> fCanvas
|
| + // fBitmapHeap -> fExternalStorage -> fCanvas
|
| + // fFlattenableHeap -> fBitmapStorage -> fExternalStorage -> fCanvas
|
| +
|
| + // Break them all by destroying the final link to this SkGPipeCanvas.
|
| + fBitmapShuttle->removeCanvas();
|
| + }
|
| + fDone = true;
|
| }
|
|
|
| void flushRecording(bool detachCurrentBlock);
|
| @@ -306,9 +337,11 @@ private:
|
| // if a new SkFlatData was added when in cross process mode
|
| void flattenFactoryNames();
|
|
|
| - FlattenableHeap fFlattenableHeap;
|
| - FlatDictionary fFlatDictionary;
|
| - int fCurrFlatIndex[kCount_PaintFlats];
|
| + FlattenableHeap fFlattenableHeap;
|
| + FlatDictionary fFlatDictionary;
|
| + SkAutoTUnref<BitmapShuttle> fBitmapShuttle;
|
| + int fCurrFlatIndex[kCount_PaintFlats];
|
| +
|
| int flattenToIndex(SkFlattenable* obj, PaintFlats);
|
|
|
| // Common code used by drawBitmap*. Behaves differently depending on the
|
| @@ -390,24 +423,6 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| -/**
|
| - * If SkBitmaps are to be flattened to send to the reader, this class is
|
| - * provided to the SkBitmapHeap to tell the SkGPipeCanvas to do so.
|
| - */
|
| -class BitmapShuttle : public SkBitmapHeap::ExternalStorage {
|
| -public:
|
| - BitmapShuttle(SkGPipeCanvas*);
|
| -
|
| - ~BitmapShuttle();
|
| -
|
| - virtual bool insert(const SkBitmap& bitmap, int32_t slot) SK_OVERRIDE;
|
| -
|
| -private:
|
| - SkGPipeCanvas* fCanvas;
|
| -};
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| #define MIN_BLOCK_SIZE (16 * 1024)
|
| #define BITMAPS_TO_KEEP 5
|
| #define FLATTENABLES_TO_KEEP 10
|
| @@ -440,9 +455,8 @@ SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
|
| }
|
|
|
| if (shouldFlattenBitmaps(flags)) {
|
| - BitmapShuttle* shuttle = SkNEW_ARGS(BitmapShuttle, (this));
|
| - fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, (shuttle, BITMAPS_TO_KEEP));
|
| - shuttle->unref();
|
| + fBitmapShuttle.reset(SkNEW_ARGS(BitmapShuttle, (this)));
|
| + fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, (fBitmapShuttle.get(), BITMAPS_TO_KEEP));
|
| } else {
|
| fBitmapHeap = SkNEW_ARGS(SkBitmapHeap,
|
| (BITMAPS_TO_KEEP, controller->numberOfReaders()));
|
| @@ -456,7 +470,7 @@ SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
|
| }
|
|
|
| SkGPipeCanvas::~SkGPipeCanvas() {
|
| - this->finish();
|
| + this->finish(true);
|
| SkSafeUnref(fFactorySet);
|
| SkSafeUnref(fBitmapHeap);
|
| }
|
| @@ -474,7 +488,8 @@ bool SkGPipeCanvas::needOpBytes(size_t needed) {
|
| size_t blockSize = SkMax32(MIN_BLOCK_SIZE, needed);
|
| void* block = fController->requestBlock(blockSize, &fBlockSize);
|
| if (NULL == block) {
|
| - fDone = true;
|
| + // Do not notify the readers, which would call this function again.
|
| + this->finish(false);
|
| return false;
|
| }
|
| SkASSERT(SkIsAlign4(fBlockSize));
|
| @@ -1179,7 +1194,7 @@ SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t
|
|
|
| void SkGPipeWriter::endRecording() {
|
| if (fCanvas) {
|
| - fCanvas->finish();
|
| + fCanvas->finish(true);
|
| fCanvas->unref();
|
| fCanvas = NULL;
|
| }
|
| @@ -1211,9 +1226,18 @@ BitmapShuttle::BitmapShuttle(SkGPipeCanvas* canvas) {
|
| }
|
|
|
| BitmapShuttle::~BitmapShuttle() {
|
| - fCanvas->unref();
|
| + this->removeCanvas();
|
| }
|
|
|
| bool BitmapShuttle::insert(const SkBitmap& bitmap, int32_t slot) {
|
| + SkASSERT(fCanvas != NULL);
|
| return fCanvas->shuttleBitmap(bitmap, slot);
|
| }
|
| +
|
| +void BitmapShuttle::removeCanvas() {
|
| + if (NULL == fCanvas) {
|
| + return;
|
| + }
|
| + fCanvas->unref();
|
| + fCanvas = NULL;
|
| +}
|
|
|