1 /* 2 * Copyright 2013 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 "SkData.h" 9 #include "SkDataTable.h" 10 #include "SkFlattenableBuffers.h" 11 12 SK_DEFINE_INST_COUNT(SkDataTable) 13 14 static void malloc_freeproc(void* context) { 15 sk_free(context); 16 } 17 18 // Makes empty table 19 SkDataTable::SkDataTable() { 20 fCount = 0; 21 fElemSize = 0; // 0 signals that we use fDir instead of fElems 22 fU.fDir = NULL; 23 fFreeProc = NULL; 24 fFreeProcContext = NULL; 25 } 26 27 SkDataTable::SkDataTable(const void* array, size_t elemSize, int count, 28 FreeProc proc, void* context) { 29 SkASSERT(count > 0); 30 31 fCount = count; 32 fElemSize = elemSize; // non-zero signals we use fElems instead of fDir 33 fU.fElems = (const char*)array; 34 fFreeProc = proc; 35 fFreeProcContext = context; 36 } 37 38 SkDataTable::SkDataTable(const Dir* dir, int count, FreeProc proc, void* ctx) { 39 SkASSERT(count > 0); 40 41 fCount = count; 42 fElemSize = 0; // 0 signals that we use fDir instead of fElems 43 fU.fDir = dir; 44 fFreeProc = proc; 45 fFreeProcContext = ctx; 46 } 47 48 SkDataTable::~SkDataTable() { 49 if (fFreeProc) { 50 fFreeProc(fFreeProcContext); 51 } 52 } 53 54 size_t SkDataTable::atSize(int index) const { 55 SkASSERT((unsigned)index < (unsigned)fCount); 56 57 if (fElemSize) { 58 return fElemSize; 59 } else { 60 return fU.fDir[index].fSize; 61 } 62 } 63 64 const void* SkDataTable::at(int index, size_t* size) const { 65 SkASSERT((unsigned)index < (unsigned)fCount); 66 67 if (fElemSize) { 68 if (size) { 69 *size = fElemSize; 70 } 71 return fU.fElems + index * fElemSize; 72 } else { 73 if (size) { 74 *size = fU.fDir[index].fSize; 75 } 76 return fU.fDir[index].fPtr; 77 } 78 } 79 80 SkDataTable::SkDataTable(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { 81 fElemSize = 0; 82 fU.fElems = NULL; 83 fFreeProc = NULL; 84 fFreeProcContext = NULL; 85 86 fCount = buffer.read32(); 87 if (fCount) { 88 fElemSize = buffer.read32(); 89 if (fElemSize) { 90 size_t size = buffer.getArrayCount(); 91 // size is the size of our elems data 92 SkASSERT(fCount * fElemSize == size); 93 void* addr = sk_malloc_throw(size); 94 if (buffer.readByteArray(addr) != size) { 95 sk_throw(); 96 } 97 fU.fElems = (const char*)addr; 98 fFreeProcContext = addr; 99 } else { 100 size_t dataSize = buffer.read32(); 101 102 size_t allocSize = fCount * sizeof(Dir) + dataSize; 103 void* addr = sk_malloc_throw(allocSize); 104 Dir* dir = (Dir*)addr; 105 char* elem = (char*)(dir + fCount); 106 for (int i = 0; i < fCount; ++i) { 107 dir[i].fPtr = elem; 108 dir[i].fSize = buffer.readByteArray(elem); 109 elem += dir[i].fSize; 110 } 111 fU.fDir = dir; 112 fFreeProcContext = addr; 113 } 114 fFreeProc = malloc_freeproc; 115 } 116 } 117 118 void SkDataTable::flatten(SkFlattenableWriteBuffer& buffer) const { 119 this->INHERITED::flatten(buffer); 120 121 buffer.write32(fCount); 122 if (fCount) { 123 buffer.write32(fElemSize); 124 if (fElemSize) { 125 buffer.writeByteArray(fU.fElems, fCount * fElemSize); 126 } else { 127 size_t dataSize = 0; 128 for (int i = 0; i < fCount; ++i) { 129 dataSize += fU.fDir[i].fSize; 130 } 131 buffer.write32(dataSize); 132 for (int i = 0; i < fCount; ++i) { 133 buffer.writeByteArray(fU.fDir[i].fPtr, fU.fDir[i].fSize); 134 } 135 } 136 } 137 } 138 139 /////////////////////////////////////////////////////////////////////////////// 140 141 SkDataTable* SkDataTable::NewEmpty() { 142 static SkDataTable* gEmpty; 143 if (NULL == gEmpty) { 144 gEmpty = SkNEW(SkDataTable); 145 } 146 gEmpty->ref(); 147 return gEmpty; 148 } 149 150 SkDataTable* SkDataTable::NewCopyArrays(const void * const * ptrs, 151 const size_t sizes[], int count) { 152 if (count <= 0) { 153 return SkDataTable::NewEmpty(); 154 } 155 156 size_t dataSize = 0; 157 for (int i = 0; i < count; ++i) { 158 dataSize += sizes[i]; 159 } 160 161 size_t bufferSize = count * sizeof(Dir) + dataSize; 162 void* buffer = sk_malloc_throw(bufferSize); 163 164 Dir* dir = (Dir*)buffer; 165 char* elem = (char*)(dir + count); 166 for (int i = 0; i < count; ++i) { 167 dir[i].fPtr = elem; 168 dir[i].fSize = sizes[i]; 169 memcpy(elem, ptrs[i], sizes[i]); 170 elem += sizes[i]; 171 } 172 173 return SkNEW_ARGS(SkDataTable, (dir, count, malloc_freeproc, buffer)); 174 } 175 176 SkDataTable* SkDataTable::NewCopyArray(const void* array, size_t elemSize, 177 int count) { 178 if (count <= 0) { 179 return SkDataTable::NewEmpty(); 180 } 181 182 size_t bufferSize = elemSize * count; 183 void* buffer = sk_malloc_throw(bufferSize); 184 memcpy(buffer, array, bufferSize); 185 186 return SkNEW_ARGS(SkDataTable, 187 (buffer, elemSize, count, malloc_freeproc, buffer)); 188 } 189 190 SkDataTable* SkDataTable::NewArrayProc(const void* array, size_t elemSize, 191 int count, FreeProc proc, void* ctx) { 192 if (count <= 0) { 193 return SkDataTable::NewEmpty(); 194 } 195 return SkNEW_ARGS(SkDataTable, (array, elemSize, count, proc, ctx)); 196 } 197 198 /////////////////////////////////////////////////////////////////////////////// 199 200 static void chunkalloc_freeproc(void* context) { 201 SkDELETE((SkChunkAlloc*)context); 202 } 203 204 SkDataTableBuilder::SkDataTableBuilder(size_t minChunkSize) 205 : fHeap(NULL) 206 , fMinChunkSize(minChunkSize) {} 207 208 SkDataTableBuilder::~SkDataTableBuilder() { this->reset(); } 209 210 void SkDataTableBuilder::reset(size_t minChunkSize) { 211 fMinChunkSize = minChunkSize; 212 fDir.reset(); 213 if (fHeap) { 214 SkDELETE(fHeap); 215 fHeap = NULL; 216 } 217 } 218 219 void SkDataTableBuilder::append(const void* src, size_t size) { 220 if (NULL == fHeap) { 221 fHeap = SkNEW_ARGS(SkChunkAlloc, (fMinChunkSize)); 222 } 223 224 void* dst = fHeap->alloc(size, SkChunkAlloc::kThrow_AllocFailType); 225 memcpy(dst, src, size); 226 227 SkDataTable::Dir* dir = fDir.append(); 228 dir->fPtr = dst; 229 dir->fSize = size; 230 } 231 232 SkDataTable* SkDataTableBuilder::detachDataTable() { 233 const int count = fDir.count(); 234 if (0 == count) { 235 return SkDataTable::NewEmpty(); 236 } 237 238 // Copy the dir into the heap; 239 void* dir = fHeap->alloc(count * sizeof(SkDataTable::Dir), 240 SkChunkAlloc::kThrow_AllocFailType); 241 memcpy(dir, fDir.begin(), count * sizeof(SkDataTable::Dir)); 242 243 SkDataTable* table = SkNEW_ARGS(SkDataTable, 244 ((SkDataTable::Dir*)dir, count, 245 chunkalloc_freeproc, fHeap)); 246 // we have to detach our fHeap, since we are giving that to the table 247 fHeap = NULL; 248 fDir.reset(); 249 return table; 250 } 251