blob: 9ae22f22075d5dab30f55e931e761a16759cb6e2 [file] [log] [blame]
scroggo@google.comf8d7d272013-02-22 21:38:35 +00001/*
2 * Copyright 2012 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 "Sk64.h"
9#include "SkLazyPixelRef.h"
10#include "SkColorTable.h"
11#include "SkData.h"
12#include "SkImageCache.h"
13#include "SkImagePriv.h"
14
scroggo@google.comcc690202013-03-04 19:56:21 +000015#if LAZY_CACHE_STATS
16#include "SkThread.h"
17
18int32_t SkLazyPixelRef::gCacheHits;
19int32_t SkLazyPixelRef::gCacheMisses;
20#endif
21
scroggo@google.comf8d7d272013-02-22 21:38:35 +000022SkLazyPixelRef::SkLazyPixelRef(SkData* data, SkBitmapFactory::DecodeProc proc, SkImageCache* cache)
23 // Pass NULL for the Mutex so that the default (ring buffer) will be used.
24 : INHERITED(NULL)
25 , fDecodeProc(proc)
26 , fImageCache(cache)
27 , fCacheId(SkImageCache::UNINITIALIZED_ID) {
28 SkASSERT(fDecodeProc != NULL);
29 if (NULL == data) {
30 fData = SkData::NewEmpty();
31 fErrorInDecoding = true;
32 } else {
33 fData = data;
34 fData->ref();
35 fErrorInDecoding = data->size() == 0;
36 }
37 SkASSERT(cache != NULL);
38 cache->ref();
39 // Since this pixel ref bases its data on encoded data, it should never change.
40 this->setImmutable();
41}
42
43SkLazyPixelRef::~SkLazyPixelRef() {
44 SkASSERT(fData != NULL);
45 fData->unref();
46 SkASSERT(fImageCache);
47 if (fCacheId != SkImageCache::UNINITIALIZED_ID) {
48 fImageCache->throwAwayCache(fCacheId);
49 }
50 fImageCache->unref();
51}
52
53static size_t ComputeMinRowBytesAndSize(const SkImage::Info& info, size_t* rowBytes) {
54 *rowBytes = SkImageMinRowBytes(info);
55
56 Sk64 safeSize;
57 safeSize.setZero();
58 if (info.fHeight > 0) {
scroggo@google.come5f48242013-02-25 21:47:41 +000059 safeSize.setMul(info.fHeight, SkToS32(*rowBytes));
scroggo@google.comf8d7d272013-02-22 21:38:35 +000060 }
61 SkASSERT(!safeSize.isNeg());
62 return safeSize.is32() ? safeSize.get32() : 0;
63}
64
65void* SkLazyPixelRef::onLockPixels(SkColorTable**) {
66 if (fErrorInDecoding) {
67 return NULL;
68 }
69 SkBitmapFactory::Target target;
70 // Check to see if the pixels still exist in the cache.
scroggo@google.comcc690202013-03-04 19:56:21 +000071 if (SkImageCache::UNINITIALIZED_ID == fCacheId) {
72 target.fAddr = NULL;
73 } else {
74 target.fAddr = fImageCache->pinCache(fCacheId);
75 if (NULL != target.fAddr) {
76#if LAZY_CACHE_STATS
77 sk_atomic_inc(&gCacheHits);
78#endif
79 return target.fAddr;
scroggo@google.comf8d7d272013-02-22 21:38:35 +000080 }
scroggo@google.comcc690202013-03-04 19:56:21 +000081#if LAZY_CACHE_STATS
82 sk_atomic_inc(&gCacheMisses);
83#endif
84 }
85 SkASSERT(NULL == target.fAddr);
86 SkImage::Info info;
87 SkASSERT(fData != NULL && fData->size() > 0);
88 // FIXME: As an optimization, only do this part once.
89 fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, NULL);
90 if (fErrorInDecoding) {
scroggo@google.comc75764e2013-03-04 21:38:50 +000091 // In case a previous call to allocAndPinCache succeeded.
92 fImageCache->throwAwayCache(fCacheId);
scroggo@google.comcc690202013-03-04 19:56:21 +000093 fCacheId = SkImageCache::UNINITIALIZED_ID;
94 return NULL;
95 }
96 // Allocate the memory.
97 size_t bytes = ComputeMinRowBytesAndSize(info, &target.fRowBytes);
scroggo@google.comf8d7d272013-02-22 21:38:35 +000098
scroggo@google.comcc690202013-03-04 19:56:21 +000099 target.fAddr = fImageCache->allocAndPinCache(bytes, &fCacheId);
100 if (NULL == target.fAddr) {
101 // Space could not be allocated.
102 fCacheId = SkImageCache::UNINITIALIZED_ID;
103 return NULL;
104 }
105 SkASSERT(SkImageCache::UNINITIALIZED_ID != fCacheId);
106 fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, &target);
107 if (fErrorInDecoding) {
108 fImageCache->throwAwayCache(fCacheId);
109 fCacheId = SkImageCache::UNINITIALIZED_ID;
110 return NULL;
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000111 }
112 return target.fAddr;
113}
114
115void SkLazyPixelRef::onUnlockPixels() {
116 if (fErrorInDecoding) {
117 return;
118 }
119 if (fCacheId != SkImageCache::UNINITIALIZED_ID) {
120 fImageCache->releaseCache(fCacheId);
121 }
122}
123
124SkData* SkLazyPixelRef::onRefEncodedData() {
125 fData->ref();
126 return fData;
127}