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
14static void sk_free_releaseproc(void* ptr, void*) {
15    sk_free(ptr);
16}
17
18static 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
40SkMallocPixelRef* 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
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
90SkMallocPixelRef* 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
97SkMallocPixelRef* SkMallocPixelRef::NewZeroed(const SkImageInfo& info,
98                                              size_t rowBytes,
99                                              SkColorTable* ctable) {
100    return NewUsing(sk_calloc, info, rowBytes, ctable);
101}
102
103SkMallocPixelRef* 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        return nullptr;
111    }
112    return new SkMallocPixelRef(info, addr, rowBytes, ctable, proc, context);
113}
114
115static void sk_data_releaseproc(void*, void* dataPtr) {
116    (static_cast<SkData*>(dataPtr))->unref();
117}
118
119SkMallocPixelRef* SkMallocPixelRef::NewWithData(const SkImageInfo& info,
120                                                size_t rowBytes,
121                                                SkColorTable* ctable,
122                                                SkData* data) {
123    SkASSERT(data != nullptr);
124    if (!is_valid(info, ctable)) {
125        return nullptr;
126    }
127    if ((rowBytes < info.minRowBytes())
128        || (data->size() < info.getSafeSize(rowBytes))) {
129        return nullptr;
130    }
131    data->ref();
132    SkMallocPixelRef* pr =
133            new SkMallocPixelRef(info, const_cast<void*>(data->data()), rowBytes, ctable,
134                                 sk_data_releaseproc, static_cast<void*>(data));
135    SkASSERT(pr != nullptr);
136    // We rely on the immutability of the pixels to make the
137    // const_cast okay.
138    pr->setImmutable();
139    return pr;
140}
141
142///////////////////////////////////////////////////////////////////////////////
143
144SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage,
145                                   size_t rowBytes, SkColorTable* ctable,
146                                   bool ownsPixels)
147    : INHERITED(info)
148    , fReleaseProc(ownsPixels ? sk_free_releaseproc : nullptr)
149    , fReleaseProcContext(nullptr) {
150    // This constructor is now DEPRICATED.
151    SkASSERT(is_valid(info, ctable));
152    SkASSERT(rowBytes >= info.minRowBytes());
153
154    if (kIndex_8_SkColorType != info.colorType()) {
155        ctable = nullptr;
156    }
157
158    fStorage = storage;
159    fCTable = ctable;
160    fRB = rowBytes;
161    SkSafeRef(ctable);
162
163    this->setPreLocked(fStorage, rowBytes, fCTable);
164}
165
166SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage,
167                                   size_t rowBytes, SkColorTable* ctable,
168                                   SkMallocPixelRef::ReleaseProc proc,
169                                   void* context)
170    : INHERITED(info)
171    , fReleaseProc(proc)
172    , fReleaseProcContext(context)
173{
174    SkASSERT(is_valid(info, ctable));
175    SkASSERT(rowBytes >= info.minRowBytes());
176
177    if (kIndex_8_SkColorType != info.colorType()) {
178        ctable = nullptr;
179    }
180
181    fStorage = storage;
182    fCTable = ctable;
183    fRB = rowBytes;
184    SkSafeRef(ctable);
185
186    this->setPreLocked(fStorage, rowBytes, fCTable);
187}
188
189
190SkMallocPixelRef::~SkMallocPixelRef() {
191    SkSafeUnref(fCTable);
192    if (fReleaseProc != nullptr) {
193        fReleaseProc(fStorage, fReleaseProcContext);
194    }
195}
196
197bool SkMallocPixelRef::onNewLockPixels(LockRec* rec) {
198    rec->fPixels = fStorage;
199    rec->fRowBytes = fRB;
200    rec->fColorTable = fCTable;
201    return true;
202}
203
204void SkMallocPixelRef::onUnlockPixels() {
205    // nothing to do
206}
207
208size_t SkMallocPixelRef::getAllocatedSizeInBytes() const {
209    return this->info().getSafeSize(fRB);
210}
211
212///////////////////////////////////////////////////////////////////////////////
213
214SkPixelRef* SkMallocPixelRef::PRFactory::create(const SkImageInfo& info, size_t rowBytes,
215                                                SkColorTable* ctable) {
216    return SkMallocPixelRef::NewAllocate(info, rowBytes, ctable);
217}
218
219SkPixelRef* SkMallocPixelRef::ZeroedPRFactory::create(const SkImageInfo& info, size_t rowBytes,
220                                                      SkColorTable* ctable) {
221    return SkMallocPixelRef::NewZeroed(info, rowBytes, ctable);
222}
223