SkCachingPixelRef.cpp revision bae704b050491a8a98c67cb23eaccb10852d2bd5
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
11bool 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
27SkCachingPixelRef::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}
37SkCachingPixelRef::~SkCachingPixelRef() {
38    SkDELETE(fImageGenerator);
39    SkASSERT(NULL == fScaledCacheId);
40    // Assert always unlock before unref.
41}
42
43bool 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.allocPixels(info, fRowBytes)) {
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
93void SkCachingPixelRef::onUnlockPixels() {
94    SkASSERT(fScaledCacheId != NULL);
95    SkScaledImageCache::Unlock( static_cast<SkScaledImageCache::ID*>(fScaledCacheId));
96    fScaledCacheId = NULL;
97}
98