18c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com/*
28c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com * Copyright 2013 Google Inc.
38c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com *
48c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com * Use of this source code is governed by a BSD-style license that can be
58c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com * found in the LICENSE file.
68c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com */
78c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
88c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com#include "SkData.h"
98c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com#include "SkDataTable.h"
10feb3c1a57faee39dc10ac904f6b215ba50e286b4bungeman#include "SkOnce.h"
118c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
12cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgstatic void malloc_freeproc(void* context) {
13cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    sk_free(context);
14cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org}
158c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
16cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org// Makes empty table
17cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgSkDataTable::SkDataTable() {
18cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fCount = 0;
19cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fElemSize = 0;   // 0 signals that we use fDir instead of fElems
2096fcdcc219d2a0d3579719b84b28bede76efba64halcanary    fU.fDir = nullptr;
2196fcdcc219d2a0d3579719b84b28bede76efba64halcanary    fFreeProc = nullptr;
2296fcdcc219d2a0d3579719b84b28bede76efba64halcanary    fFreeProcContext = nullptr;
238c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com}
248c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
25cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgSkDataTable::SkDataTable(const void* array, size_t elemSize, int count,
26cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org                         FreeProc proc, void* context) {
27cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    SkASSERT(count > 0);
28c9f3b38f67893b22c3e02a6a934bc676e36c5cfcrmistry@google.com
29cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fCount = count;
30cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fElemSize = elemSize;   // non-zero signals we use fElems instead of fDir
31cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fU.fElems = (const char*)array;
32cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fFreeProc = proc;
33cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fFreeProcContext = context;
34cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org}
358c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
36cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgSkDataTable::SkDataTable(const Dir* dir, int count, FreeProc proc, void* ctx) {
37cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    SkASSERT(count > 0);
38c9f3b38f67893b22c3e02a6a934bc676e36c5cfcrmistry@google.com
39cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fCount = count;
40cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fElemSize = 0;  // 0 signals that we use fDir instead of fElems
41cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fU.fDir = dir;
42cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fFreeProc = proc;
43cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    fFreeProcContext = ctx;
44cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org}
45cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org
46cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgSkDataTable::~SkDataTable() {
47cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (fFreeProc) {
48cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        fFreeProc(fFreeProcContext);
498c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    }
50cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org}
518c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
528c5c7a905b708f7c0a991ca7c872af645544afefreed@google.comsize_t SkDataTable::atSize(int index) const {
538c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    SkASSERT((unsigned)index < (unsigned)fCount);
54cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org
55cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (fElemSize) {
56cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        return fElemSize;
57cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    } else {
58cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        return fU.fDir[index].fSize;
59cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    }
608c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com}
618c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
62cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.orgconst void* SkDataTable::at(int index, size_t* size) const {
638c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    SkASSERT((unsigned)index < (unsigned)fCount);
64cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org
65cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (fElemSize) {
66cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        if (size) {
67cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org            *size = fElemSize;
68cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        }
69cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        return fU.fElems + index * fElemSize;
70cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    } else {
71cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        if (size) {
72cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org            *size = fU.fDir[index].fSize;
73cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        }
74cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        return fU.fDir[index].fPtr;
758c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    }
768c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com}
778c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
783cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.com///////////////////////////////////////////////////////////////////////////////
793cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.com
80feb3c1a57faee39dc10ac904f6b215ba50e286b4bungemansk_sp<SkDataTable> SkDataTable::MakeEmpty() {
81feb3c1a57faee39dc10ac904f6b215ba50e286b4bungeman    static SkDataTable* singleton;
82feb3c1a57faee39dc10ac904f6b215ba50e286b4bungeman    static SkOnce once;
83feb3c1a57faee39dc10ac904f6b215ba50e286b4bungeman    once([]{ singleton = new SkDataTable(); });
84feb3c1a57faee39dc10ac904f6b215ba50e286b4bungeman    return sk_ref_sp(singleton);
853cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.com}
863cceb9f400583be4ec70da526c23fe81b68dc6eereed@google.com
87feb3c1a57faee39dc10ac904f6b215ba50e286b4bungemansk_sp<SkDataTable> SkDataTable::MakeCopyArrays(const void * const * ptrs,
88feb3c1a57faee39dc10ac904f6b215ba50e286b4bungeman                                               const size_t sizes[], int count) {
89cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (count <= 0) {
90feb3c1a57faee39dc10ac904f6b215ba50e286b4bungeman        return SkDataTable::MakeEmpty();
918c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    }
928c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
938c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    size_t dataSize = 0;
948c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    for (int i = 0; i < count; ++i) {
958c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com        dataSize += sizes[i];
968c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    }
978c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
98cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    size_t bufferSize = count * sizeof(Dir) + dataSize;
998c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    void* buffer = sk_malloc_throw(bufferSize);
1008c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
101cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    Dir* dir = (Dir*)buffer;
102cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    char* elem = (char*)(dir + count);
1038c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    for (int i = 0; i < count; ++i) {
104cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        dir[i].fPtr = elem;
105cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        dir[i].fSize = sizes[i];
106cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        memcpy(elem, ptrs[i], sizes[i]);
107cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org        elem += sizes[i];
1088c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    }
109c9f3b38f67893b22c3e02a6a934bc676e36c5cfcrmistry@google.com
110feb3c1a57faee39dc10ac904f6b215ba50e286b4bungeman    return sk_sp<SkDataTable>(new SkDataTable(dir, count, malloc_freeproc, buffer));
1118c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com}
1128c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com
113feb3c1a57faee39dc10ac904f6b215ba50e286b4bungemansk_sp<SkDataTable> SkDataTable::MakeCopyArray(const void* array, size_t elemSize, int count) {
114cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (count <= 0) {
115feb3c1a57faee39dc10ac904f6b215ba50e286b4bungeman        return SkDataTable::MakeEmpty();
1168c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    }
11764b682ca42c75667e49251d3ab04f192f92d0dd8skia.committer@gmail.com
118cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    size_t bufferSize = elemSize * count;
1198c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com    void* buffer = sk_malloc_throw(bufferSize);
120cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    memcpy(buffer, array, bufferSize);
12164b682ca42c75667e49251d3ab04f192f92d0dd8skia.committer@gmail.com
122feb3c1a57faee39dc10ac904f6b215ba50e286b4bungeman    return sk_sp<SkDataTable>(new SkDataTable(buffer, elemSize, count, malloc_freeproc, buffer));
123cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org}
12464b682ca42c75667e49251d3ab04f192f92d0dd8skia.committer@gmail.com
125feb3c1a57faee39dc10ac904f6b215ba50e286b4bungemansk_sp<SkDataTable> SkDataTable::MakeArrayProc(const void* array, size_t elemSize, int count,
126feb3c1a57faee39dc10ac904f6b215ba50e286b4bungeman                                              FreeProc proc, void* ctx) {
127cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    if (count <= 0) {
128feb3c1a57faee39dc10ac904f6b215ba50e286b4bungeman        return SkDataTable::MakeEmpty();
129cac3ae37522bf070244c723960d1689e53da4dcdmike@reedtribe.org    }
130feb3c1a57faee39dc10ac904f6b215ba50e286b4bungeman    return sk_sp<SkDataTable>(new SkDataTable(array, elemSize, count, proc, ctx));
1318c5c7a905b708f7c0a991ca7c872af645544afefreed@google.com}
132