blob: c262884561bb0c28b543c7c2a502c529396c4cc6 [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
15SkLazyPixelRef::SkLazyPixelRef(SkData* data, SkBitmapFactory::DecodeProc proc, SkImageCache* cache)
16 // Pass NULL for the Mutex so that the default (ring buffer) will be used.
17 : INHERITED(NULL)
18 , fDecodeProc(proc)
19 , fImageCache(cache)
20 , fCacheId(SkImageCache::UNINITIALIZED_ID) {
21 SkASSERT(fDecodeProc != NULL);
22 if (NULL == data) {
23 fData = SkData::NewEmpty();
24 fErrorInDecoding = true;
25 } else {
26 fData = data;
27 fData->ref();
28 fErrorInDecoding = data->size() == 0;
29 }
30 SkASSERT(cache != NULL);
31 cache->ref();
32 // Since this pixel ref bases its data on encoded data, it should never change.
33 this->setImmutable();
34}
35
36SkLazyPixelRef::~SkLazyPixelRef() {
37 SkASSERT(fData != NULL);
38 fData->unref();
39 SkASSERT(fImageCache);
40 if (fCacheId != SkImageCache::UNINITIALIZED_ID) {
41 fImageCache->throwAwayCache(fCacheId);
42 }
43 fImageCache->unref();
44}
45
46static size_t ComputeMinRowBytesAndSize(const SkImage::Info& info, size_t* rowBytes) {
47 *rowBytes = SkImageMinRowBytes(info);
48
49 Sk64 safeSize;
50 safeSize.setZero();
51 if (info.fHeight > 0) {
scroggo@google.come5f48242013-02-25 21:47:41 +000052 safeSize.setMul(info.fHeight, SkToS32(*rowBytes));
scroggo@google.comf8d7d272013-02-22 21:38:35 +000053 }
54 SkASSERT(!safeSize.isNeg());
55 return safeSize.is32() ? safeSize.get32() : 0;
56}
57
58void* SkLazyPixelRef::onLockPixels(SkColorTable**) {
59 if (fErrorInDecoding) {
60 return NULL;
61 }
62 SkBitmapFactory::Target target;
63 // Check to see if the pixels still exist in the cache.
64 target.fAddr = SkImageCache::UNINITIALIZED_ID == fCacheId ?
65 NULL : fImageCache->pinCache(fCacheId);
66 if (NULL == target.fAddr) {
67 SkImage::Info info;
68 SkASSERT(fData != NULL && fData->size() > 0);
69 // FIXME: As an optimization, only do this part once.
70 fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, NULL);
71 if (fErrorInDecoding) {
72 fCacheId = SkImageCache::UNINITIALIZED_ID;
73 return NULL;
74 }
75 // Allocate the memory.
76 size_t bytes = ComputeMinRowBytesAndSize(info, &target.fRowBytes);
77
78 target.fAddr = fImageCache->allocAndPinCache(bytes, &fCacheId);
79 if (NULL == target.fAddr) {
80 // Space could not be allocated.
81 fCacheId = SkImageCache::UNINITIALIZED_ID;
82 return NULL;
83 }
84 SkASSERT(SkImageCache::UNINITIALIZED_ID != fCacheId);
85 fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, &target);
86 if (fErrorInDecoding) {
87 fImageCache->throwAwayCache(fCacheId);
88 fCacheId = SkImageCache::UNINITIALIZED_ID;
89 return NULL;
90 }
91 }
92 return target.fAddr;
93}
94
95void SkLazyPixelRef::onUnlockPixels() {
96 if (fErrorInDecoding) {
97 return;
98 }
99 if (fCacheId != SkImageCache::UNINITIALIZED_ID) {
100 fImageCache->releaseCache(fCacheId);
101 }
102}
103
104SkData* SkLazyPixelRef::onRefEncodedData() {
105 fData->ref();
106 return fData;
107}