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 "SkOnce.h"
11 
malloc_freeproc(void * context)12 static void malloc_freeproc(void* context) {
13     sk_free(context);
14 }
15 
16 // Makes empty table
SkDataTable()17 SkDataTable::SkDataTable() {
18     fCount = 0;
19     fElemSize = 0;   // 0 signals that we use fDir instead of fElems
20     fU.fDir = nullptr;
21     fFreeProc = nullptr;
22     fFreeProcContext = nullptr;
23 }
24 
SkDataTable(const void * array,size_t elemSize,int count,FreeProc proc,void * context)25 SkDataTable::SkDataTable(const void* array, size_t elemSize, int count,
26                          FreeProc proc, void* context) {
27     SkASSERT(count > 0);
28 
29     fCount = count;
30     fElemSize = elemSize;   // non-zero signals we use fElems instead of fDir
31     fU.fElems = (const char*)array;
32     fFreeProc = proc;
33     fFreeProcContext = context;
34 }
35 
SkDataTable(const Dir * dir,int count,FreeProc proc,void * ctx)36 SkDataTable::SkDataTable(const Dir* dir, int count, FreeProc proc, void* ctx) {
37     SkASSERT(count > 0);
38 
39     fCount = count;
40     fElemSize = 0;  // 0 signals that we use fDir instead of fElems
41     fU.fDir = dir;
42     fFreeProc = proc;
43     fFreeProcContext = ctx;
44 }
45 
~SkDataTable()46 SkDataTable::~SkDataTable() {
47     if (fFreeProc) {
48         fFreeProc(fFreeProcContext);
49     }
50 }
51 
atSize(int index) const52 size_t SkDataTable::atSize(int index) const {
53     SkASSERT((unsigned)index < (unsigned)fCount);
54 
55     if (fElemSize) {
56         return fElemSize;
57     } else {
58         return fU.fDir[index].fSize;
59     }
60 }
61 
at(int index,size_t * size) const62 const void* SkDataTable::at(int index, size_t* size) const {
63     SkASSERT((unsigned)index < (unsigned)fCount);
64 
65     if (fElemSize) {
66         if (size) {
67             *size = fElemSize;
68         }
69         return fU.fElems + index * fElemSize;
70     } else {
71         if (size) {
72             *size = fU.fDir[index].fSize;
73         }
74         return fU.fDir[index].fPtr;
75     }
76 }
77 
78 ///////////////////////////////////////////////////////////////////////////////
79 
MakeEmpty()80 sk_sp<SkDataTable> SkDataTable::MakeEmpty() {
81     static SkDataTable* singleton;
82     static SkOnce once;
83     once([]{ singleton = new SkDataTable(); });
84     return sk_ref_sp(singleton);
85 }
86 
MakeCopyArrays(const void * const * ptrs,const size_t sizes[],int count)87 sk_sp<SkDataTable> SkDataTable::MakeCopyArrays(const void * const * ptrs,
88                                                const size_t sizes[], int count) {
89     if (count <= 0) {
90         return SkDataTable::MakeEmpty();
91     }
92 
93     size_t dataSize = 0;
94     for (int i = 0; i < count; ++i) {
95         dataSize += sizes[i];
96     }
97 
98     size_t bufferSize = count * sizeof(Dir) + dataSize;
99     void* buffer = sk_malloc_throw(bufferSize);
100 
101     Dir* dir = (Dir*)buffer;
102     char* elem = (char*)(dir + count);
103     for (int i = 0; i < count; ++i) {
104         dir[i].fPtr = elem;
105         dir[i].fSize = sizes[i];
106         memcpy(elem, ptrs[i], sizes[i]);
107         elem += sizes[i];
108     }
109 
110     return sk_sp<SkDataTable>(new SkDataTable(dir, count, malloc_freeproc, buffer));
111 }
112 
MakeCopyArray(const void * array,size_t elemSize,int count)113 sk_sp<SkDataTable> SkDataTable::MakeCopyArray(const void* array, size_t elemSize, int count) {
114     if (count <= 0) {
115         return SkDataTable::MakeEmpty();
116     }
117 
118     size_t bufferSize = elemSize * count;
119     void* buffer = sk_malloc_throw(bufferSize);
120     memcpy(buffer, array, bufferSize);
121 
122     return sk_sp<SkDataTable>(new SkDataTable(buffer, elemSize, count, malloc_freeproc, buffer));
123 }
124 
MakeArrayProc(const void * array,size_t elemSize,int count,FreeProc proc,void * ctx)125 sk_sp<SkDataTable> SkDataTable::MakeArrayProc(const void* array, size_t elemSize, int count,
126                                               FreeProc proc, void* ctx) {
127     if (count <= 0) {
128         return SkDataTable::MakeEmpty();
129     }
130     return sk_sp<SkDataTable>(new SkDataTable(array, elemSize, count, proc, ctx));
131 }
132