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
sk_free_releaseproc(void * ptr,void *)14 static void sk_free_releaseproc(void* ptr, void*) {
15     sk_free(ptr);
16 }
17 
is_valid(const SkImageInfo & info,SkColorTable * ctable)18 static 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 
NewDirect(const SkImageInfo & info,void * addr,size_t rowBytes,SkColorTable * ctable)40 SkMallocPixelRef* 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 
NewAllocate(const SkImageInfo & info,size_t requestedRowBytes,SkColorTable * ctable)52 SkMallocPixelRef* SkMallocPixelRef::NewAllocate(const SkImageInfo& info,
53                                                 size_t requestedRowBytes,
54                                                 SkColorTable* ctable) {
55     if (!is_valid(info, ctable)) {
56         return NULL;
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 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.height() * 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 
NewWithProc(const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable,void * addr,SkMallocPixelRef::ReleaseProc proc,void * context)92 SkMallocPixelRef* 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 
sk_data_releaseproc(void *,void * dataPtr)105 static void sk_data_releaseproc(void*, void* dataPtr) {
106     (static_cast<SkData*>(dataPtr))->unref();
107 }
108 
NewWithData(const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable,SkData * data)109 SkMallocPixelRef* 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 
SkMallocPixelRef(const SkImageInfo & info,void * storage,size_t rowBytes,SkColorTable * ctable,bool ownsPixels)135 SkMallocPixelRef::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.colorType()) {
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 
SkMallocPixelRef(const SkImageInfo & info,void * storage,size_t rowBytes,SkColorTable * ctable,SkMallocPixelRef::ReleaseProc proc,void * context)157 SkMallocPixelRef::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.colorType()) {
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 
~SkMallocPixelRef()181 SkMallocPixelRef::~SkMallocPixelRef() {
182     SkSafeUnref(fCTable);
183     if (fReleaseProc != NULL) {
184         fReleaseProc(fStorage, fReleaseProcContext);
185     }
186 }
187 
onNewLockPixels(LockRec * rec)188 bool SkMallocPixelRef::onNewLockPixels(LockRec* rec) {
189     rec->fPixels = fStorage;
190     rec->fRowBytes = fRB;
191     rec->fColorTable = fCTable;
192     return true;
193 }
194 
onUnlockPixels()195 void SkMallocPixelRef::onUnlockPixels() {
196     // nothing to do
197 }
198 
getAllocatedSizeInBytes() const199 size_t SkMallocPixelRef::getAllocatedSizeInBytes() const {
200     return this->info().getSafeSize(fRB);
201 }
202 
203 ///////////////////////////////////////////////////////////////////////////////
204 
create(const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable)205 SkPixelRef* SkMallocPixelRef::PRFactory::create(const SkImageInfo& info, size_t rowBytes,
206                                                 SkColorTable* ctable) {
207     return SkMallocPixelRef::NewAllocate(info, rowBytes, ctable);
208 }
209