1 /*
2 * Copyright 2011 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 "SkMallocPixelRef.h"
9 #include "SkBitmap.h"
10 #include "SkReadBuffer.h"
11 #include "SkWriteBuffer.h"
12
13 // assumes ptr was allocated via sk_malloc
sk_free_releaseproc(void * ptr,void *)14 static void sk_free_releaseproc(void* ptr, void*) {
15 sk_free(ptr);
16 }
17
is_valid(const SkImageInfo & info,SkColorTable * ctable)18 static bool is_valid(const SkImageInfo& info, SkColorTable* ctable) {
19 if (info.width() < 0 || info.height() < 0 ||
20 (unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType ||
21 (unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType)
22 {
23 return false;
24 }
25
26 // these seem like good checks, but currently we have (at least) tests
27 // that expect the pixelref to succeed even when there is a mismatch
28 // with colortables. fix?
29 #if 0
30 if (kIndex8_SkColorType == info.fColorType && nullptr == ctable) {
31 return false;
32 }
33 if (kIndex8_SkColorType != info.fColorType && ctable) {
34 return false;
35 }
36 #endif
37 return true;
38 }
39
NewDirect(const SkImageInfo & info,void * addr,size_t rowBytes,SkColorTable * ctable)40 SkMallocPixelRef* SkMallocPixelRef::NewDirect(const SkImageInfo& info,
41 void* addr,
42 size_t rowBytes,
43 SkColorTable* ctable) {
44 if (!is_valid(info, ctable)) {
45 return nullptr;
46 }
47 return new SkMallocPixelRef(info, addr, rowBytes, ctable, nullptr, nullptr);
48 }
49
50
NewUsing(void * (* alloc)(size_t),const SkImageInfo & info,size_t requestedRowBytes,SkColorTable * ctable)51 SkMallocPixelRef* SkMallocPixelRef::NewUsing(void*(*alloc)(size_t),
52 const SkImageInfo& info,
53 size_t requestedRowBytes,
54 SkColorTable* ctable) {
55 if (!is_valid(info, ctable)) {
56 return nullptr;
57 }
58
59 // only want to permit 31bits of rowBytes
60 int64_t minRB = (int64_t)info.minRowBytes64();
61 if (minRB < 0 || !sk_64_isS32(minRB)) {
62 return nullptr; // allocation will be too large
63 }
64 if (requestedRowBytes > 0 && (int32_t)requestedRowBytes < minRB) {
65 return nullptr; // cannot meet requested rowbytes
66 }
67
68 int32_t rowBytes;
69 if (requestedRowBytes) {
70 rowBytes = SkToS32(requestedRowBytes);
71 } else {
72 rowBytes = minRB;
73 }
74
75 int64_t bigSize = (int64_t)info.height() * rowBytes;
76 if (!sk_64_isS32(bigSize)) {
77 return nullptr;
78 }
79
80 size_t size = sk_64_asS32(bigSize);
81 SkASSERT(size >= info.getSafeSize(rowBytes));
82 void* addr = alloc(size);
83 if (nullptr == addr) {
84 return nullptr;
85 }
86
87 return new SkMallocPixelRef(info, addr, rowBytes, ctable, sk_free_releaseproc, nullptr);
88 }
89
NewAllocate(const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable)90 SkMallocPixelRef* SkMallocPixelRef::NewAllocate(const SkImageInfo& info,
91 size_t rowBytes,
92 SkColorTable* ctable) {
93 auto sk_malloc_nothrow = [](size_t size) { return sk_malloc_flags(size, 0); };
94 return NewUsing(sk_malloc_nothrow, info, rowBytes, ctable);
95 }
96
NewZeroed(const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable)97 SkMallocPixelRef* SkMallocPixelRef::NewZeroed(const SkImageInfo& info,
98 size_t rowBytes,
99 SkColorTable* ctable) {
100 return NewUsing(sk_calloc, info, rowBytes, ctable);
101 }
102
NewWithProc(const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable,void * addr,SkMallocPixelRef::ReleaseProc proc,void * context)103 SkMallocPixelRef* SkMallocPixelRef::NewWithProc(const SkImageInfo& info,
104 size_t rowBytes,
105 SkColorTable* ctable,
106 void* addr,
107 SkMallocPixelRef::ReleaseProc proc,
108 void* context) {
109 if (!is_valid(info, ctable)) {
110 if (proc) {
111 proc(addr, context);
112 }
113 return nullptr;
114 }
115 return new SkMallocPixelRef(info, addr, rowBytes, ctable, proc, context);
116 }
117
sk_data_releaseproc(void *,void * dataPtr)118 static void sk_data_releaseproc(void*, void* dataPtr) {
119 (static_cast<SkData*>(dataPtr))->unref();
120 }
121
NewWithData(const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable,SkData * data)122 SkMallocPixelRef* SkMallocPixelRef::NewWithData(const SkImageInfo& info,
123 size_t rowBytes,
124 SkColorTable* ctable,
125 SkData* data) {
126 SkASSERT(data != nullptr);
127 if (!is_valid(info, ctable)) {
128 return nullptr;
129 }
130 if ((rowBytes < info.minRowBytes())
131 || (data->size() < info.getSafeSize(rowBytes))) {
132 return nullptr;
133 }
134 data->ref();
135 SkMallocPixelRef* pr =
136 new SkMallocPixelRef(info, const_cast<void*>(data->data()), rowBytes, ctable,
137 sk_data_releaseproc, static_cast<void*>(data));
138 SkASSERT(pr != nullptr);
139 // We rely on the immutability of the pixels to make the
140 // const_cast okay.
141 pr->setImmutable();
142 return pr;
143 }
144
145 ///////////////////////////////////////////////////////////////////////////////
146
SkMallocPixelRef(const SkImageInfo & info,void * storage,size_t rowBytes,SkColorTable * ctable,bool ownsPixels)147 SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage,
148 size_t rowBytes, SkColorTable* ctable,
149 bool ownsPixels)
150 : INHERITED(info)
151 , fReleaseProc(ownsPixels ? sk_free_releaseproc : nullptr)
152 , fReleaseProcContext(nullptr) {
153 // This constructor is now DEPRICATED.
154 SkASSERT(is_valid(info, ctable));
155 SkASSERT(rowBytes >= info.minRowBytes());
156
157 if (kIndex_8_SkColorType != info.colorType()) {
158 ctable = nullptr;
159 }
160
161 fStorage = storage;
162 fCTable = ctable;
163 fRB = rowBytes;
164 SkSafeRef(ctable);
165
166 this->setPreLocked(fStorage, rowBytes, fCTable);
167 }
168
SkMallocPixelRef(const SkImageInfo & info,void * storage,size_t rowBytes,SkColorTable * ctable,SkMallocPixelRef::ReleaseProc proc,void * context)169 SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage,
170 size_t rowBytes, SkColorTable* ctable,
171 SkMallocPixelRef::ReleaseProc proc,
172 void* context)
173 : INHERITED(info)
174 , fReleaseProc(proc)
175 , fReleaseProcContext(context)
176 {
177 SkASSERT(is_valid(info, ctable));
178 SkASSERT(rowBytes >= info.minRowBytes());
179
180 if (kIndex_8_SkColorType != info.colorType()) {
181 ctable = nullptr;
182 }
183
184 fStorage = storage;
185 fCTable = ctable;
186 fRB = rowBytes;
187 SkSafeRef(ctable);
188
189 this->setPreLocked(fStorage, rowBytes, fCTable);
190 }
191
192
~SkMallocPixelRef()193 SkMallocPixelRef::~SkMallocPixelRef() {
194 SkSafeUnref(fCTable);
195 if (fReleaseProc != nullptr) {
196 fReleaseProc(fStorage, fReleaseProcContext);
197 }
198 }
199
onNewLockPixels(LockRec * rec)200 bool SkMallocPixelRef::onNewLockPixels(LockRec* rec) {
201 rec->fPixels = fStorage;
202 rec->fRowBytes = fRB;
203 rec->fColorTable = fCTable;
204 return true;
205 }
206
onUnlockPixels()207 void SkMallocPixelRef::onUnlockPixels() {
208 // nothing to do
209 }
210
getAllocatedSizeInBytes() const211 size_t SkMallocPixelRef::getAllocatedSizeInBytes() const {
212 return this->info().getSafeSize(fRB);
213 }
214
215 ///////////////////////////////////////////////////////////////////////////////
216
create(const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable)217 SkPixelRef* SkMallocPixelRef::PRFactory::create(const SkImageInfo& info, size_t rowBytes,
218 SkColorTable* ctable) {
219 return SkMallocPixelRef::NewAllocate(info, rowBytes, ctable);
220 }
221
create(const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable)222 SkPixelRef* SkMallocPixelRef::ZeroedPRFactory::create(const SkImageInfo& info, size_t rowBytes,
223 SkColorTable* ctable) {
224 return SkMallocPixelRef::NewZeroed(info, rowBytes, ctable);
225 }
226