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.fWidth < 0 ||
20        info.fHeight < 0 ||
21        (unsigned)info.fColorType > (unsigned)kLastEnum_SkColorType ||
22        (unsigned)info.fAlphaType > (unsigned)kLastEnum_SkAlphaType)
23    {
24        return false;
25    }
26
27    // these seem like good checks, but currently we have (at least) tests
28    // that expect the pixelref to succeed even when there is a mismatch
29    // with colortables. fix?
30#if 0
31    if (kIndex8_SkColorType == info.fColorType && NULL == ctable) {
32        return false;
33    }
34    if (kIndex8_SkColorType != info.fColorType && NULL != ctable) {
35        return false;
36    }
37#endif
38    return true;
39}
40
41SkMallocPixelRef* SkMallocPixelRef::NewDirect(const SkImageInfo& info,
42                                              void* addr,
43                                              size_t rowBytes,
44                                              SkColorTable* ctable) {
45    if (!is_valid(info, ctable)) {
46        return NULL;
47    }
48    return SkNEW_ARGS(SkMallocPixelRef,
49                      (info, addr, rowBytes, ctable, NULL, NULL));
50}
51
52
53SkMallocPixelRef* SkMallocPixelRef::NewAllocate(const SkImageInfo& info,
54                                                size_t requestedRowBytes,
55                                                SkColorTable* ctable) {
56    if (!is_valid(info, ctable)) {
57        return NULL;
58    }
59
60    int32_t minRB = SkToS32(info.minRowBytes());
61    if (minRB < 0) {
62        return NULL;    // allocation will be too large
63    }
64    if (requestedRowBytes > 0 && (int32_t)requestedRowBytes < minRB) {
65        return NULL;    // 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.fHeight * rowBytes;
76    if (!sk_64_isS32(bigSize)) {
77        return NULL;
78    }
79
80    size_t size = sk_64_asS32(bigSize);
81    SkASSERT(size >= info.getSafeSize(rowBytes));
82    void* addr = sk_malloc_flags(size, 0);
83    if (NULL == addr) {
84        return NULL;
85    }
86
87    return SkNEW_ARGS(SkMallocPixelRef,
88                      (info, addr, rowBytes, ctable,
89                       sk_free_releaseproc, NULL));
90}
91
92SkMallocPixelRef* SkMallocPixelRef::NewWithProc(const SkImageInfo& info,
93                                                size_t rowBytes,
94                                                SkColorTable* ctable,
95                                                void* addr,
96                                                SkMallocPixelRef::ReleaseProc proc,
97                                                void* context) {
98    if (!is_valid(info, ctable)) {
99        return NULL;
100    }
101    return SkNEW_ARGS(SkMallocPixelRef,
102                      (info, addr, rowBytes, ctable, proc, context));
103}
104
105static void sk_data_releaseproc(void*, void* dataPtr) {
106    (static_cast<SkData*>(dataPtr))->unref();
107}
108
109SkMallocPixelRef* SkMallocPixelRef::NewWithData(const SkImageInfo& info,
110                                                size_t rowBytes,
111                                                SkColorTable* ctable,
112                                                SkData* data) {
113    SkASSERT(data != NULL);
114    if (!is_valid(info, ctable)) {
115        return NULL;
116    }
117    if ((rowBytes < info.minRowBytes())
118        || (data->size() < info.getSafeSize(rowBytes))) {
119        return NULL;
120    }
121    data->ref();
122    SkMallocPixelRef* pr
123        = SkNEW_ARGS(SkMallocPixelRef,
124                     (info, const_cast<void*>(data->data()), rowBytes, ctable,
125                      sk_data_releaseproc, static_cast<void*>(data)));
126    SkASSERT(pr != NULL);
127    // We rely on the immutability of the pixels to make the
128    // const_cast okay.
129    pr->setImmutable();
130    return pr;
131}
132
133///////////////////////////////////////////////////////////////////////////////
134
135SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage,
136                                   size_t rowBytes, SkColorTable* ctable,
137                                   bool ownsPixels)
138    : INHERITED(info)
139    , fReleaseProc(ownsPixels ? sk_free_releaseproc : NULL)
140    , fReleaseProcContext(NULL) {
141    // This constructor is now DEPRICATED.
142    SkASSERT(is_valid(info, ctable));
143    SkASSERT(rowBytes >= info.minRowBytes());
144
145    if (kIndex_8_SkColorType != info.fColorType) {
146        ctable = NULL;
147    }
148
149    fStorage = storage;
150    fCTable = ctable;
151    fRB = rowBytes;
152    SkSafeRef(ctable);
153
154    this->setPreLocked(fStorage, rowBytes, fCTable);
155}
156
157SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage,
158                                   size_t rowBytes, SkColorTable* ctable,
159                                   SkMallocPixelRef::ReleaseProc proc,
160                                   void* context)
161    : INHERITED(info)
162    , fReleaseProc(proc)
163    , fReleaseProcContext(context)
164{
165    SkASSERT(is_valid(info, ctable));
166    SkASSERT(rowBytes >= info.minRowBytes());
167
168    if (kIndex_8_SkColorType != info.fColorType) {
169        ctable = NULL;
170    }
171
172    fStorage = storage;
173    fCTable = ctable;
174    fRB = rowBytes;
175    SkSafeRef(ctable);
176
177    this->setPreLocked(fStorage, rowBytes, fCTable);
178}
179
180
181SkMallocPixelRef::~SkMallocPixelRef() {
182    SkSafeUnref(fCTable);
183    if (fReleaseProc != NULL) {
184        fReleaseProc(fStorage, fReleaseProcContext);
185    }
186}
187
188bool SkMallocPixelRef::onNewLockPixels(LockRec* rec) {
189    rec->fPixels = fStorage;
190    rec->fRowBytes = fRB;
191    rec->fColorTable = fCTable;
192    return true;
193}
194
195void SkMallocPixelRef::onUnlockPixels() {
196    // nothing to do
197}
198
199size_t SkMallocPixelRef::getAllocatedSizeInBytes() const {
200    return this->info().getSafeSize(fRB);
201}
202
203void SkMallocPixelRef::flatten(SkWriteBuffer& buffer) const {
204    this->INHERITED::flatten(buffer);
205
206    buffer.write32(SkToU32(fRB));
207
208    // TODO: replace this bulk write with a chunky one that can trim off any
209    // trailing bytes on each scanline (in case rowbytes > width*size)
210    size_t size = this->info().getSafeSize(fRB);
211    buffer.writeByteArray(fStorage, size);
212    buffer.writeBool(fCTable != NULL);
213    if (fCTable) {
214        fCTable->writeToBuffer(buffer);
215    }
216}
217
218SkMallocPixelRef::SkMallocPixelRef(SkReadBuffer& buffer)
219    : INHERITED(buffer, NULL)
220    , fReleaseProc(sk_free_releaseproc)
221    , fReleaseProcContext(NULL)
222{
223    fRB = buffer.read32();
224    size_t size = buffer.isValid() ? this->info().getSafeSize(fRB) : 0;
225    if (buffer.validateAvailable(size)) {
226        fStorage = sk_malloc_throw(size);
227        buffer.readByteArray(fStorage, size);
228    } else {
229        fStorage = NULL;
230    }
231
232    if (buffer.readBool()) {
233        fCTable = SkNEW_ARGS(SkColorTable, (buffer));
234    } else {
235        fCTable = NULL;
236    }
237
238    this->setPreLocked(fStorage, fRB, fCTable);
239}
240
241///////////////////////////////////////////////////////////////////////////////
242
243SkPixelRef* SkMallocPixelRef::PRFactory::create(const SkImageInfo& info,
244                                                SkColorTable* ctable) {
245    return SkMallocPixelRef::NewAllocate(info, info.minRowBytes(), ctable);
246}
247