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