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 && NULL == 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 NULL;
46    }
47    return SkNEW_ARGS(SkMallocPixelRef,
48                      (info, addr, rowBytes, ctable, NULL, NULL));
49}
50
51
52SkMallocPixelRef* SkMallocPixelRef::NewAllocate(const SkImageInfo& info,
53                                                size_t requestedRowBytes,
54                                                SkColorTable* ctable) {
55    if (!is_valid(info, ctable)) {
56        return NULL;
57    }
58
59    int32_t minRB = SkToS32(info.minRowBytes());
60    if (minRB < 0) {
61        return NULL;    // allocation will be too large
62    }
63    if (requestedRowBytes > 0 && (int32_t)requestedRowBytes < minRB) {
64        return NULL;    // cannot meet requested rowbytes
65    }
66
67    int32_t rowBytes;
68    if (requestedRowBytes) {
69        rowBytes = SkToS32(requestedRowBytes);
70    } else {
71        rowBytes = minRB;
72    }
73
74    int64_t bigSize = (int64_t)info.height() * rowBytes;
75    if (!sk_64_isS32(bigSize)) {
76        return NULL;
77    }
78
79    size_t size = sk_64_asS32(bigSize);
80    SkASSERT(size >= info.getSafeSize(rowBytes));
81    void* addr = sk_malloc_flags(size, 0);
82    if (NULL == addr) {
83        return NULL;
84    }
85
86    return SkNEW_ARGS(SkMallocPixelRef,
87                      (info, addr, rowBytes, ctable,
88                       sk_free_releaseproc, NULL));
89}
90
91SkMallocPixelRef* SkMallocPixelRef::NewWithProc(const SkImageInfo& info,
92                                                size_t rowBytes,
93                                                SkColorTable* ctable,
94                                                void* addr,
95                                                SkMallocPixelRef::ReleaseProc proc,
96                                                void* context) {
97    if (!is_valid(info, ctable)) {
98        return NULL;
99    }
100    return SkNEW_ARGS(SkMallocPixelRef,
101                      (info, addr, rowBytes, ctable, proc, context));
102}
103
104static void sk_data_releaseproc(void*, void* dataPtr) {
105    (static_cast<SkData*>(dataPtr))->unref();
106}
107
108SkMallocPixelRef* SkMallocPixelRef::NewWithData(const SkImageInfo& info,
109                                                size_t rowBytes,
110                                                SkColorTable* ctable,
111                                                SkData* data) {
112    SkASSERT(data != NULL);
113    if (!is_valid(info, ctable)) {
114        return NULL;
115    }
116    if ((rowBytes < info.minRowBytes())
117        || (data->size() < info.getSafeSize(rowBytes))) {
118        return NULL;
119    }
120    data->ref();
121    SkMallocPixelRef* pr
122        = SkNEW_ARGS(SkMallocPixelRef,
123                     (info, const_cast<void*>(data->data()), rowBytes, ctable,
124                      sk_data_releaseproc, static_cast<void*>(data)));
125    SkASSERT(pr != NULL);
126    // We rely on the immutability of the pixels to make the
127    // const_cast okay.
128    pr->setImmutable();
129    return pr;
130}
131
132///////////////////////////////////////////////////////////////////////////////
133
134SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage,
135                                   size_t rowBytes, SkColorTable* ctable,
136                                   bool ownsPixels)
137    : INHERITED(info)
138    , fReleaseProc(ownsPixels ? sk_free_releaseproc : NULL)
139    , fReleaseProcContext(NULL) {
140    // This constructor is now DEPRICATED.
141    SkASSERT(is_valid(info, ctable));
142    SkASSERT(rowBytes >= info.minRowBytes());
143
144    if (kIndex_8_SkColorType != info.colorType()) {
145        ctable = NULL;
146    }
147
148    fStorage = storage;
149    fCTable = ctable;
150    fRB = rowBytes;
151    SkSafeRef(ctable);
152
153    this->setPreLocked(fStorage, rowBytes, fCTable);
154}
155
156SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage,
157                                   size_t rowBytes, SkColorTable* ctable,
158                                   SkMallocPixelRef::ReleaseProc proc,
159                                   void* context)
160    : INHERITED(info)
161    , fReleaseProc(proc)
162    , fReleaseProcContext(context)
163{
164    SkASSERT(is_valid(info, ctable));
165    SkASSERT(rowBytes >= info.minRowBytes());
166
167    if (kIndex_8_SkColorType != info.colorType()) {
168        ctable = NULL;
169    }
170
171    fStorage = storage;
172    fCTable = ctable;
173    fRB = rowBytes;
174    SkSafeRef(ctable);
175
176    this->setPreLocked(fStorage, rowBytes, fCTable);
177}
178
179
180SkMallocPixelRef::~SkMallocPixelRef() {
181    SkSafeUnref(fCTable);
182    if (fReleaseProc != NULL) {
183        fReleaseProc(fStorage, fReleaseProcContext);
184    }
185}
186
187bool SkMallocPixelRef::onNewLockPixels(LockRec* rec) {
188    rec->fPixels = fStorage;
189    rec->fRowBytes = fRB;
190    rec->fColorTable = fCTable;
191    return true;
192}
193
194void SkMallocPixelRef::onUnlockPixels() {
195    // nothing to do
196}
197
198size_t SkMallocPixelRef::getAllocatedSizeInBytes() const {
199    return this->info().getSafeSize(fRB);
200}
201
202///////////////////////////////////////////////////////////////////////////////
203
204SkPixelRef* SkMallocPixelRef::PRFactory::create(const SkImageInfo& info, size_t rowBytes,
205                                                SkColorTable* ctable) {
206    return SkMallocPixelRef::NewAllocate(info, rowBytes, ctable);
207}
208