Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(779)

Side by Side Diff: src/pipe/SkGPipeWrite.cpp

Issue 69633003: Fix a memory leak in SkGPipeCanvas. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2011 Google Inc. 3 * Copyright 2011 Google Inc.
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 #include "SkAnnotation.h" 9 #include "SkAnnotation.h"
10 #include "SkBitmapDevice.h" 10 #include "SkBitmapDevice.h"
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 } 160 }
161 static void flattenFlattenableProc(SkOrderedWriteBuffer& buffer, 161 static void flattenFlattenableProc(SkOrderedWriteBuffer& buffer,
162 const void* obj) { 162 const void* obj) {
163 buffer.writeFlattenable((SkFlattenable*)obj); 163 buffer.writeFlattenable((SkFlattenable*)obj);
164 } 164 }
165 165
166 }; 166 };
167 167
168 /////////////////////////////////////////////////////////////////////////////// 168 ///////////////////////////////////////////////////////////////////////////////
169 169
170 /**
171 * If SkBitmaps are to be flattened to send to the reader, this class is
172 * provided to the SkBitmapHeap to tell the SkGPipeCanvas to do so.
173 */
174 class BitmapShuttle : public SkBitmapHeap::ExternalStorage {
175 public:
176 BitmapShuttle(SkGPipeCanvas*);
177
178 ~BitmapShuttle();
179
180 virtual bool insert(const SkBitmap& bitmap, int32_t slot) SK_OVERRIDE;
181
182 /**
183 * Remove the SkGPipeCanvas used for insertion. After this, calls to
184 * insert will crash.
185 */
186 void removeCanvas();
187
188 private:
189 SkGPipeCanvas* fCanvas;
190 };
191
192 ///////////////////////////////////////////////////////////////////////////////
193
170 class SkGPipeCanvas : public SkCanvas { 194 class SkGPipeCanvas : public SkCanvas {
171 public: 195 public:
172 SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags, 196 SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags,
173 uint32_t width, uint32_t height); 197 uint32_t width, uint32_t height);
174 virtual ~SkGPipeCanvas(); 198 virtual ~SkGPipeCanvas();
175 199
176 void finish() { 200 /**
177 if (!fDone) { 201 * Called when nothing else is to be written to the stream. Any repeated
178 if (this->needOpBytes()) { 202 * calls are ignored.
179 this->writeOp(kDone_DrawOp); 203 *
180 this->doNotify(); 204 * @param notifyReaders Whether to send a message to the reader(s) that
181 if (shouldFlattenBitmaps(fFlags)) { 205 * the writer is through sending commands. Should generally be true,
182 // In this case, a BitmapShuttle is reffed by the SkBitmapHe ap 206 * unless there is an error which prevents further messages from
183 // and refs this canvas. Unref the SkBitmapHeap to end the 207 * being sent.
184 // circular reference. When shouldFlattenBitmaps is false, 208 */
185 // there is no circular reference, so the SkBitmapHeap can b e 209 void finish(bool notifyReaders) {
186 // safely unreffed in the destructor. 210 if (fDone) {
187 fBitmapHeap->unref(); 211 return;
188 // This eliminates a similar circular reference (Canvas owns
189 // the FlattenableHeap which holds a ref to the SkBitmapHeap ).
190 fFlattenableHeap.setBitmapStorage(NULL);
191 fBitmapHeap = NULL;
192 }
193 }
194 fDone = true;
195 } 212 }
213 if (notifyReaders && this->needOpBytes()) {
214 this->writeOp(kDone_DrawOp);
215 this->doNotify();
216 }
217 if (shouldFlattenBitmaps(fFlags)) {
218 // The following circular references exist:
219 // fFlattenableHeap -> fWriteBuffer -> fBitmapStorage -> fExternalSt orage -> fCanvas
220 // fBitmapHeap -> fExternalStorage -> fCanvas
221 // fFlattenableHeap -> fBitmapStorage -> fExternalStorage -> fCanvas
222
223 // Break them all by destroying the final link to this SkGPipeCanvas .
224 fBitmapShuttle->removeCanvas();
225 }
226 fDone = true;
196 } 227 }
197 228
198 void flushRecording(bool detachCurrentBlock); 229 void flushRecording(bool detachCurrentBlock);
199 size_t freeMemoryIfPossible(size_t bytesToFree); 230 size_t freeMemoryIfPossible(size_t bytesToFree);
200 231
201 size_t storageAllocatedForRecording() { 232 size_t storageAllocatedForRecording() {
202 return (NULL == fBitmapHeap) ? 0 : fBitmapHeap->bytesAllocated(); 233 return (NULL == fBitmapHeap) ? 0 : fBitmapHeap->bytesAllocated();
203 } 234 }
204 235
205 // overrides from SkCanvas 236 // overrides from SkCanvas
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
299 fController->notifyWritten(bytes); 330 fController->notifyWritten(bytes);
300 fBytesNotified += bytes; 331 fBytesNotified += bytes;
301 } 332 }
302 } 333 }
303 } 334 }
304 335
305 // Should be called after any calls to an SkFlatDictionary::findAndReplace 336 // Should be called after any calls to an SkFlatDictionary::findAndReplace
306 // if a new SkFlatData was added when in cross process mode 337 // if a new SkFlatData was added when in cross process mode
307 void flattenFactoryNames(); 338 void flattenFactoryNames();
308 339
309 FlattenableHeap fFlattenableHeap; 340 FlattenableHeap fFlattenableHeap;
310 FlatDictionary fFlatDictionary; 341 FlatDictionary fFlatDictionary;
311 int fCurrFlatIndex[kCount_PaintFlats]; 342 SkAutoTUnref<BitmapShuttle> fBitmapShuttle;
343 int fCurrFlatIndex[kCount_PaintFlats];
344
312 int flattenToIndex(SkFlattenable* obj, PaintFlats); 345 int flattenToIndex(SkFlattenable* obj, PaintFlats);
313 346
314 // Common code used by drawBitmap*. Behaves differently depending on the 347 // Common code used by drawBitmap*. Behaves differently depending on the
315 // type of SkBitmapHeap being used, which is determined by the flags used. 348 // type of SkBitmapHeap being used, which is determined by the flags used.
316 bool commonDrawBitmap(const SkBitmap& bm, DrawOps op, unsigned flags, 349 bool commonDrawBitmap(const SkBitmap& bm, DrawOps op, unsigned flags,
317 size_t opBytesNeeded, const SkPaint* paint); 350 size_t opBytesNeeded, const SkPaint* paint);
318 351
319 SkPaint fPaint; 352 SkPaint fPaint;
320 void writePaint(const SkPaint&); 353 void writePaint(const SkPaint&);
321 354
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 } 416 }
384 } 417 }
385 if (replaced) { 418 if (replaced) {
386 index = ~index; 419 index = ~index;
387 } 420 }
388 return index; 421 return index;
389 } 422 }
390 423
391 /////////////////////////////////////////////////////////////////////////////// 424 ///////////////////////////////////////////////////////////////////////////////
392 425
393 /**
394 * If SkBitmaps are to be flattened to send to the reader, this class is
395 * provided to the SkBitmapHeap to tell the SkGPipeCanvas to do so.
396 */
397 class BitmapShuttle : public SkBitmapHeap::ExternalStorage {
398 public:
399 BitmapShuttle(SkGPipeCanvas*);
400
401 ~BitmapShuttle();
402
403 virtual bool insert(const SkBitmap& bitmap, int32_t slot) SK_OVERRIDE;
404
405 private:
406 SkGPipeCanvas* fCanvas;
407 };
408
409 ///////////////////////////////////////////////////////////////////////////////
410
411 #define MIN_BLOCK_SIZE (16 * 1024) 426 #define MIN_BLOCK_SIZE (16 * 1024)
412 #define BITMAPS_TO_KEEP 5 427 #define BITMAPS_TO_KEEP 5
413 #define FLATTENABLES_TO_KEEP 10 428 #define FLATTENABLES_TO_KEEP 10
414 429
415 SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller, 430 SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
416 SkWriter32* writer, uint32_t flags, 431 SkWriter32* writer, uint32_t flags,
417 uint32_t width, uint32_t height) 432 uint32_t width, uint32_t height)
418 : fFactorySet(isCrossProcess(flags) ? SkNEW(SkNamedFactorySet) : NULL) 433 : fFactorySet(isCrossProcess(flags) ? SkNEW(SkNamedFactorySet) : NULL)
419 , fWriter(*writer) 434 , fWriter(*writer)
420 , fFlags(flags) 435 , fFlags(flags)
(...skipping 12 matching lines...) Expand all
433 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); 448 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
434 SkBaseDevice* device = SkNEW_ARGS(SkBitmapDevice, (bitmap)); 449 SkBaseDevice* device = SkNEW_ARGS(SkBitmapDevice, (bitmap));
435 this->setDevice(device)->unref(); 450 this->setDevice(device)->unref();
436 451
437 // Tell the reader the appropriate flags to use. 452 // Tell the reader the appropriate flags to use.
438 if (this->needOpBytes()) { 453 if (this->needOpBytes()) {
439 this->writeOp(kReportFlags_DrawOp, fFlags, 0); 454 this->writeOp(kReportFlags_DrawOp, fFlags, 0);
440 } 455 }
441 456
442 if (shouldFlattenBitmaps(flags)) { 457 if (shouldFlattenBitmaps(flags)) {
443 BitmapShuttle* shuttle = SkNEW_ARGS(BitmapShuttle, (this)); 458 fBitmapShuttle.reset(SkNEW_ARGS(BitmapShuttle, (this)));
444 fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, (shuttle, BITMAPS_TO_KEEP)); 459 fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, (fBitmapShuttle.get(), BITMAPS_TO _KEEP));
445 shuttle->unref();
446 } else { 460 } else {
447 fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, 461 fBitmapHeap = SkNEW_ARGS(SkBitmapHeap,
448 (BITMAPS_TO_KEEP, controller->numberOfReaders() )); 462 (BITMAPS_TO_KEEP, controller->numberOfReaders() ));
449 if (this->needOpBytes(sizeof(void*))) { 463 if (this->needOpBytes(sizeof(void*))) {
450 this->writeOp(kShareBitmapHeap_DrawOp); 464 this->writeOp(kShareBitmapHeap_DrawOp);
451 fWriter.writePtr(static_cast<void*>(fBitmapHeap)); 465 fWriter.writePtr(static_cast<void*>(fBitmapHeap));
452 } 466 }
453 } 467 }
454 fFlattenableHeap.setBitmapStorage(fBitmapHeap); 468 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
455 this->doNotify(); 469 this->doNotify();
456 } 470 }
457 471
458 SkGPipeCanvas::~SkGPipeCanvas() { 472 SkGPipeCanvas::~SkGPipeCanvas() {
459 this->finish(); 473 this->finish(true);
460 SkSafeUnref(fFactorySet); 474 SkSafeUnref(fFactorySet);
461 SkSafeUnref(fBitmapHeap); 475 SkSafeUnref(fBitmapHeap);
462 } 476 }
463 477
464 bool SkGPipeCanvas::needOpBytes(size_t needed) { 478 bool SkGPipeCanvas::needOpBytes(size_t needed) {
465 if (fDone) { 479 if (fDone) {
466 return false; 480 return false;
467 } 481 }
468 482
469 needed += 4; // size of DrawOp atom 483 needed += 4; // size of DrawOp atom
470 if (fWriter.bytesWritten() + needed > fBlockSize) { 484 if (fWriter.bytesWritten() + needed > fBlockSize) {
471 // Before we wipe out any data that has already been written, read it 485 // Before we wipe out any data that has already been written, read it
472 // out. 486 // out.
473 this->doNotify(); 487 this->doNotify();
474 size_t blockSize = SkMax32(MIN_BLOCK_SIZE, needed); 488 size_t blockSize = SkMax32(MIN_BLOCK_SIZE, needed);
475 void* block = fController->requestBlock(blockSize, &fBlockSize); 489 void* block = fController->requestBlock(blockSize, &fBlockSize);
476 if (NULL == block) { 490 if (NULL == block) {
477 fDone = true; 491 // Do not notify the readers, which would call this function again.
492 this->finish(false);
478 return false; 493 return false;
479 } 494 }
480 SkASSERT(SkIsAlign4(fBlockSize)); 495 SkASSERT(SkIsAlign4(fBlockSize));
481 fWriter.reset(block, fBlockSize); 496 fWriter.reset(block, fBlockSize);
482 fBytesNotified = 0; 497 fBytesNotified = 0;
483 } 498 }
484 return true; 499 return true;
485 } 500 }
486 501
487 uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) { 502 uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) {
(...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after
1172 if (NULL == fCanvas) { 1187 if (NULL == fCanvas) {
1173 fWriter.reset(NULL, 0); 1188 fWriter.reset(NULL, 0);
1174 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter, flags, width, height)); 1189 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter, flags, width, height));
1175 } 1190 }
1176 controller->setCanvas(fCanvas); 1191 controller->setCanvas(fCanvas);
1177 return fCanvas; 1192 return fCanvas;
1178 } 1193 }
1179 1194
1180 void SkGPipeWriter::endRecording() { 1195 void SkGPipeWriter::endRecording() {
1181 if (fCanvas) { 1196 if (fCanvas) {
1182 fCanvas->finish(); 1197 fCanvas->finish(true);
1183 fCanvas->unref(); 1198 fCanvas->unref();
1184 fCanvas = NULL; 1199 fCanvas = NULL;
1185 } 1200 }
1186 } 1201 }
1187 1202
1188 void SkGPipeWriter::flushRecording(bool detachCurrentBlock) { 1203 void SkGPipeWriter::flushRecording(bool detachCurrentBlock) {
1189 if (fCanvas) { 1204 if (fCanvas) {
1190 fCanvas->flushRecording(detachCurrentBlock); 1205 fCanvas->flushRecording(detachCurrentBlock);
1191 } 1206 }
1192 } 1207 }
(...skipping 11 matching lines...) Expand all
1204 1219
1205 /////////////////////////////////////////////////////////////////////////////// 1220 ///////////////////////////////////////////////////////////////////////////////
1206 1221
1207 BitmapShuttle::BitmapShuttle(SkGPipeCanvas* canvas) { 1222 BitmapShuttle::BitmapShuttle(SkGPipeCanvas* canvas) {
1208 SkASSERT(canvas != NULL); 1223 SkASSERT(canvas != NULL);
1209 fCanvas = canvas; 1224 fCanvas = canvas;
1210 fCanvas->ref(); 1225 fCanvas->ref();
1211 } 1226 }
1212 1227
1213 BitmapShuttle::~BitmapShuttle() { 1228 BitmapShuttle::~BitmapShuttle() {
1214 fCanvas->unref(); 1229 this->removeCanvas();
1215 } 1230 }
1216 1231
1217 bool BitmapShuttle::insert(const SkBitmap& bitmap, int32_t slot) { 1232 bool BitmapShuttle::insert(const SkBitmap& bitmap, int32_t slot) {
1233 SkASSERT(fCanvas != NULL);
1218 return fCanvas->shuttleBitmap(bitmap, slot); 1234 return fCanvas->shuttleBitmap(bitmap, slot);
1219 } 1235 }
1236
1237 void BitmapShuttle::removeCanvas() {
1238 if (NULL == fCanvas) {
1239 return;
1240 }
1241 fCanvas->unref();
1242 fCanvas = NULL;
1243 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698