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