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 "SkData.h"
9 #include "SkImageInfo.h"
10 #include "SkMalloc.h"
11 #include "SkMallocPixelRef.h"
12 #include "SkSafeMath.h"
13
sk_calloc_throw(size_t count,size_t elemSize)14 void* sk_calloc_throw(size_t count, size_t elemSize) {
15 return sk_calloc_throw(SkSafeMath::Mul(count, elemSize));
16 }
17
sk_malloc_throw(size_t count,size_t elemSize)18 void* sk_malloc_throw(size_t count, size_t elemSize) {
19 return sk_malloc_throw(SkSafeMath::Mul(count, elemSize));
20 }
21
sk_realloc_throw(void * buffer,size_t count,size_t elemSize)22 void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize) {
23 return sk_realloc_throw(buffer, SkSafeMath::Mul(count, elemSize));
24 }
25
sk_malloc_canfail(size_t count,size_t elemSize)26 void* sk_malloc_canfail(size_t count, size_t elemSize) {
27 return sk_malloc_canfail(SkSafeMath::Mul(count, elemSize));
28 }
29
30 ///////////////////////////////////////////////////////////////////////////////////////////////////
31
32 // assumes ptr was allocated via sk_malloc
sk_free_releaseproc(void * ptr,void *)33 static void sk_free_releaseproc(void* ptr, void*) {
34 sk_free(ptr);
35 }
36
is_valid(const SkImageInfo & info)37 static bool is_valid(const SkImageInfo& info) {
38 if (info.width() < 0 || info.height() < 0 ||
39 (unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType ||
40 (unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType)
41 {
42 return false;
43 }
44 return true;
45 }
46
MakeDirect(const SkImageInfo & info,void * addr,size_t rowBytes)47 sk_sp<SkPixelRef> SkMallocPixelRef::MakeDirect(const SkImageInfo& info,
48 void* addr,
49 size_t rowBytes) {
50 if (!is_valid(info)) {
51 return nullptr;
52 }
53 return sk_sp<SkPixelRef>(new SkMallocPixelRef(info, addr, rowBytes, nullptr, nullptr));
54 }
55
56
MakeUsing(void * (* allocProc)(size_t),const SkImageInfo & info,size_t requestedRowBytes)57 sk_sp<SkPixelRef> SkMallocPixelRef::MakeUsing(void*(*allocProc)(size_t),
58 const SkImageInfo& info,
59 size_t requestedRowBytes) {
60 size_t rowBytes = requestedRowBytes;
61 if (rowBytes == 0) {
62 rowBytes = info.minRowBytes();
63 // rowBytes can still be zero, if it overflowed (width * bytesPerPixel > size_t)
64 // or if colortype is unknown
65 }
66 if (!is_valid(info) || !info.validRowBytes(rowBytes)) {
67 return nullptr;
68 }
69 size_t size = 0;
70 if (!info.isEmpty() && rowBytes) {
71 size = info.computeByteSize(rowBytes);
72 if (SkImageInfo::ByteSizeOverflowed(size)) {
73 return nullptr;
74 }
75 }
76 void* addr = allocProc(size);
77 if (nullptr == addr) {
78 return nullptr;
79 }
80
81 return sk_sp<SkPixelRef>(new SkMallocPixelRef(info, addr, rowBytes,
82 sk_free_releaseproc, nullptr));
83 }
84
MakeAllocate(const SkImageInfo & info,size_t rowBytes)85 sk_sp<SkPixelRef> SkMallocPixelRef::MakeAllocate(const SkImageInfo& info, size_t rowBytes) {
86 return MakeUsing(sk_malloc_canfail, info, rowBytes);
87 }
88
MakeZeroed(const SkImageInfo & info,size_t rowBytes)89 sk_sp<SkPixelRef> SkMallocPixelRef::MakeZeroed(const SkImageInfo& info,
90 size_t rowBytes) {
91 return MakeUsing(sk_calloc_canfail, info, rowBytes);
92 }
93
sk_data_releaseproc(void *,void * dataPtr)94 static void sk_data_releaseproc(void*, void* dataPtr) {
95 (static_cast<SkData*>(dataPtr))->unref();
96 }
97
MakeWithProc(const SkImageInfo & info,size_t rowBytes,void * addr,SkMallocPixelRef::ReleaseProc proc,void * context)98 sk_sp<SkPixelRef> SkMallocPixelRef::MakeWithProc(const SkImageInfo& info,
99 size_t rowBytes,
100 void* addr,
101 SkMallocPixelRef::ReleaseProc proc,
102 void* context) {
103 if (!is_valid(info)) {
104 if (proc) {
105 proc(addr, context);
106 }
107 return nullptr;
108 }
109 return sk_sp<SkPixelRef>(new SkMallocPixelRef(info, addr, rowBytes, proc, context));
110 }
111
MakeWithData(const SkImageInfo & info,size_t rowBytes,sk_sp<SkData> data)112 sk_sp<SkPixelRef> SkMallocPixelRef::MakeWithData(const SkImageInfo& info,
113 size_t rowBytes,
114 sk_sp<SkData> data) {
115 SkASSERT(data != nullptr);
116 if (!is_valid(info)) {
117 return nullptr;
118 }
119 // TODO: what should we return if computeByteSize returns 0?
120 // - the info was empty?
121 // - we overflowed computing the size?
122 if ((rowBytes < info.minRowBytes()) || (data->size() < info.computeByteSize(rowBytes))) {
123 return nullptr;
124 }
125 // must get this address before we call release
126 void* pixels = const_cast<void*>(data->data());
127 SkPixelRef* pr = new SkMallocPixelRef(info, pixels, rowBytes,
128 sk_data_releaseproc, data.release());
129 pr->setImmutable(); // since we were created with (immutable) data
130 return sk_sp<SkPixelRef>(pr);
131 }
132
133 ///////////////////////////////////////////////////////////////////////////////
134
SkMallocPixelRef(const SkImageInfo & info,void * storage,size_t rowBytes,SkMallocPixelRef::ReleaseProc proc,void * context)135 SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage,
136 size_t rowBytes,
137 SkMallocPixelRef::ReleaseProc proc,
138 void* context)
139 : INHERITED(info.width(), info.height(), storage, rowBytes)
140 , fReleaseProc(proc)
141 , fReleaseProcContext(context)
142 {}
143
144
~SkMallocPixelRef()145 SkMallocPixelRef::~SkMallocPixelRef() {
146 if (fReleaseProc != nullptr) {
147 fReleaseProc(this->pixels(), fReleaseProcContext);
148 }
149 }
150