blob: a20b3c028d0850cd80075b01225422bf30007c74 [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) {
91 fCacheId = SkImageCache::UNINITIALIZED_ID;
92 return NULL;
93 }
94 // Allocate the memory.
95 size_t bytes = ComputeMinRowBytesAndSize(info, &target.fRowBytes);
scroggo@google.comf8d7d272013-02-22 21:38:35 +000096
scroggo@google.comcc690202013-03-04 19:56:21 +000097 target.fAddr = fImageCache->allocAndPinCache(bytes, &fCacheId);
98 if (NULL == target.fAddr) {
99 // Space could not be allocated.
100 fCacheId = SkImageCache::UNINITIALIZED_ID;
101 return NULL;
102 }
103 SkASSERT(SkImageCache::UNINITIALIZED_ID != fCacheId);
104 fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, &target);
105 if (fErrorInDecoding) {
106 fImageCache->throwAwayCache(fCacheId);
107 fCacheId = SkImageCache::UNINITIALIZED_ID;
108 return NULL;
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000109 }
110 return target.fAddr;
111}
112
113void SkLazyPixelRef::onUnlockPixels() {
114 if (fErrorInDecoding) {
115 return;
116 }
117 if (fCacheId != SkImageCache::UNINITIALIZED_ID) {
118 fImageCache->releaseCache(fCacheId);
119 }
120}
121
122SkData* SkLazyPixelRef::onRefEncodedData() {
123 fData->ref();
124 return fData;
125}