Home | History | Annotate | Download | only in core
      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