1 /*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkCachingPixelRef.h"
9 #include "SkScaledImageCache.h"
10
Install(SkImageGenerator * generator,SkBitmap * dst)11 bool SkCachingPixelRef::Install(SkImageGenerator* generator,
12 SkBitmap* dst) {
13 SkImageInfo info;
14 SkASSERT(dst != NULL);
15 if ((NULL == generator)
16 || !(generator->getInfo(&info))
17 || !dst->setInfo(info)) {
18 SkDELETE(generator);
19 return false;
20 }
21 SkAutoTUnref<SkCachingPixelRef> ref(SkNEW_ARGS(SkCachingPixelRef,
22 (info, generator, dst->rowBytes())));
23 dst->setPixelRef(ref);
24 return true;
25 }
26
SkCachingPixelRef(const SkImageInfo & info,SkImageGenerator * generator,size_t rowBytes)27 SkCachingPixelRef::SkCachingPixelRef(const SkImageInfo& info,
28 SkImageGenerator* generator,
29 size_t rowBytes)
30 : INHERITED(info)
31 , fImageGenerator(generator)
32 , fErrorInDecoding(false)
33 , fScaledCacheId(NULL)
34 , fRowBytes(rowBytes) {
35 SkASSERT(fImageGenerator != NULL);
36 }
~SkCachingPixelRef()37 SkCachingPixelRef::~SkCachingPixelRef() {
38 SkDELETE(fImageGenerator);
39 SkASSERT(NULL == fScaledCacheId);
40 // Assert always unlock before unref.
41 }
42
onNewLockPixels(LockRec * rec)43 bool SkCachingPixelRef::onNewLockPixels(LockRec* rec) {
44 if (fErrorInDecoding) {
45 return false; // don't try again.
46 }
47
48 const SkImageInfo& info = this->info();
49 SkBitmap bitmap;
50 SkASSERT(NULL == fScaledCacheId);
51 fScaledCacheId = SkScaledImageCache::FindAndLock(this->getGenerationID(),
52 info.fWidth,
53 info.fHeight,
54 &bitmap);
55 if (NULL == fScaledCacheId) {
56 // Cache has been purged, must re-decode.
57 if ((!bitmap.setInfo(info, fRowBytes)) || !bitmap.allocPixels()) {
58 fErrorInDecoding = true;
59 return false;
60 }
61 SkAutoLockPixels autoLockPixels(bitmap);
62 if (!fImageGenerator->getPixels(info, bitmap.getPixels(), fRowBytes)) {
63 fErrorInDecoding = true;
64 return false;
65 }
66 fScaledCacheId = SkScaledImageCache::AddAndLock(this->getGenerationID(),
67 info.fWidth,
68 info.fHeight,
69 bitmap);
70 SkASSERT(fScaledCacheId != NULL);
71 }
72
73 // Now bitmap should contain a concrete PixelRef of the decoded
74 // image.
75 SkAutoLockPixels autoLockPixels(bitmap);
76 void* pixels = bitmap.getPixels();
77 SkASSERT(pixels != NULL);
78
79 // At this point, the autoLockPixels will unlockPixels()
80 // to remove bitmap's lock on the pixels. We will then
81 // destroy bitmap. The *only* guarantee that this pointer
82 // remains valid is the guarantee made by
83 // SkScaledImageCache that it will not destroy the *other*
84 // bitmap (SkScaledImageCache::Rec.fBitmap) that holds a
85 // reference to the concrete PixelRef while this record is
86 // locked.
87 rec->fPixels = pixels;
88 rec->fColorTable = NULL;
89 rec->fRowBytes = bitmap.rowBytes();
90 return true;
91 }
92
onUnlockPixels()93 void SkCachingPixelRef::onUnlockPixels() {
94 SkASSERT(fScaledCacheId != NULL);
95 SkScaledImageCache::Unlock( static_cast<SkScaledImageCache::ID*>(fScaledCacheId));
96 fScaledCacheId = NULL;
97 }
98