1 /*
2  * Copyright 2017 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 "SkAtomics.h"
9 #include "SkVertices.h"
10 #include "SkData.h"
11 #include "SkReader32.h"
12 #include "SkSafeMath.h"
13 #include "SkSafeRange.h"
14 #include "SkWriter32.h"
15 
16 static int32_t gNextID = 1;
next_id()17 static int32_t next_id() {
18     int32_t id;
19     do {
20         id = sk_atomic_inc(&gNextID);
21     } while (id == SK_InvalidGenID);
22     return id;
23 }
24 
25 struct SkVertices::Sizes {
SizesSkVertices::Sizes26     Sizes(int vertexCount, int indexCount, bool hasTexs, bool hasColors) {
27         SkSafeMath safe;
28 
29         fVSize = safe.mul(vertexCount, sizeof(SkPoint));
30         fTSize = hasTexs ? safe.mul(vertexCount, sizeof(SkPoint)) : 0;
31         fCSize = hasColors ? safe.mul(vertexCount, sizeof(SkColor)) : 0;
32         fISize = safe.mul(indexCount, sizeof(uint16_t));
33         fTotal = safe.add(sizeof(SkVertices),
34                  safe.add(fVSize,
35                  safe.add(fTSize,
36                  safe.add(fCSize,
37                           fISize))));
38 
39         if (safe.ok()) {
40             fArrays = fTotal - sizeof(SkVertices);  // just the sum of the arrays
41         } else {
42             sk_bzero(this, sizeof(*this));
43         }
44     }
45 
isValidSkVertices::Sizes46     bool isValid() const { return fTotal != 0; }
47 
48     size_t fTotal;  // size of entire SkVertices allocation (obj + arrays)
49     size_t fArrays; // size of all the arrays (V + T + C + I)
50     size_t fVSize;
51     size_t fTSize;
52     size_t fCSize;
53     size_t fISize;
54 };
55 
Builder(VertexMode mode,int vertexCount,int indexCount,uint32_t builderFlags)56 SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount,
57                              uint32_t builderFlags) {
58     bool hasTexs = SkToBool(builderFlags & SkVertices::kHasTexCoords_BuilderFlag);
59     bool hasColors = SkToBool(builderFlags & SkVertices::kHasColors_BuilderFlag);
60     this->init(mode, vertexCount, indexCount,
61                SkVertices::Sizes(vertexCount, indexCount, hasTexs, hasColors));
62 }
63 
Builder(VertexMode mode,int vertexCount,int indexCount,const SkVertices::Sizes & sizes)64 SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount,
65                              const SkVertices::Sizes& sizes) {
66     this->init(mode, vertexCount, indexCount, sizes);
67 }
68 
init(VertexMode mode,int vertexCount,int indexCount,const SkVertices::Sizes & sizes)69 void SkVertices::Builder::init(VertexMode mode, int vertexCount, int indexCount,
70                                const SkVertices::Sizes& sizes) {
71     if (!sizes.isValid()) {
72         return; // fVertices will already be null
73     }
74 
75     void* storage = ::operator new (sizes.fTotal);
76     fVertices.reset(new (storage) SkVertices);
77 
78     // need to point past the object to store the arrays
79     char* ptr = (char*)storage + sizeof(SkVertices);
80 
81     fVertices->fPositions = (SkPoint*)ptr;                          ptr += sizes.fVSize;
82     fVertices->fTexs = sizes.fTSize ? (SkPoint*)ptr : nullptr;      ptr += sizes.fTSize;
83     fVertices->fColors = sizes.fCSize ? (SkColor*)ptr : nullptr;    ptr += sizes.fCSize;
84     fVertices->fIndices = sizes.fISize ? (uint16_t*)ptr : nullptr;
85     fVertices->fVertexCnt = vertexCount;
86     fVertices->fIndexCnt = indexCount;
87     fVertices->fMode = mode;
88     // We defer assigning fBounds and fUniqueID until detach() is called
89 }
90 
detach()91 sk_sp<SkVertices> SkVertices::Builder::detach() {
92     if (fVertices) {
93         fVertices->fBounds.set(fVertices->fPositions, fVertices->fVertexCnt);
94         fVertices->fUniqueID = next_id();
95         return std::move(fVertices);        // this will null fVertices after the return
96     }
97     return nullptr;
98 }
99 
vertexCount() const100 int SkVertices::Builder::vertexCount() const {
101     return fVertices ? fVertices->vertexCount() : 0;
102 }
103 
indexCount() const104 int SkVertices::Builder::indexCount() const {
105     return fVertices ? fVertices->indexCount() : 0;
106 }
107 
positions()108 SkPoint* SkVertices::Builder::positions() {
109     return fVertices ? const_cast<SkPoint*>(fVertices->positions()) : nullptr;
110 }
111 
texCoords()112 SkPoint* SkVertices::Builder::texCoords() {
113     return fVertices ? const_cast<SkPoint*>(fVertices->texCoords()) : nullptr;
114 }
115 
colors()116 SkColor* SkVertices::Builder::colors() {
117     return fVertices ? const_cast<SkColor*>(fVertices->colors()) : nullptr;
118 }
119 
indices()120 uint16_t* SkVertices::Builder::indices() {
121     return fVertices ? const_cast<uint16_t*>(fVertices->indices()) : nullptr;
122 }
123 
124 ///////////////////////////////////////////////////////////////////////////////////////////////////
125 
MakeCopy(VertexMode mode,int vertexCount,const SkPoint pos[],const SkPoint texs[],const SkColor colors[],int indexCount,const uint16_t indices[])126 sk_sp<SkVertices> SkVertices::MakeCopy(VertexMode mode, int vertexCount,
127                                        const SkPoint pos[], const SkPoint texs[],
128                                        const SkColor colors[], int indexCount,
129                                        const uint16_t indices[]) {
130     Sizes sizes(vertexCount, indexCount, texs != nullptr, colors != nullptr);
131     if (!sizes.isValid()) {
132         return nullptr;
133     }
134 
135     Builder builder(mode, vertexCount, indexCount, sizes);
136     SkASSERT(builder.isValid());
137 
138     sk_careful_memcpy(builder.positions(), pos, sizes.fVSize);
139     sk_careful_memcpy(builder.texCoords(), texs, sizes.fTSize);
140     sk_careful_memcpy(builder.colors(), colors, sizes.fCSize);
141     sk_careful_memcpy(builder.indices(), indices, sizes.fISize);
142 
143     return builder.detach();
144 }
145 
approximateSize() const146 size_t SkVertices::approximateSize() const {
147     Sizes sizes(fVertexCnt, fIndexCnt, this->hasTexCoords(), this->hasColors());
148     SkASSERT(sizes.isValid());
149     return sizeof(SkVertices) + sizes.fArrays;
150 }
151 
152 ///////////////////////////////////////////////////////////////////////////////////////////////////
153 
154 // storage = packed | vertex_count | index_count | pos[] | texs[] | colors[] | indices[]
155 //         = header + arrays
156 
157 #define kMode_Mask          0x0FF
158 #define kHasTexs_Mask       0x100
159 #define kHasColors_Mask     0x200
160 #define kHeaderSize         (3 * sizeof(uint32_t))
161 
encode() const162 sk_sp<SkData> SkVertices::encode() const {
163     // packed has room for addtional flags in the future (e.g. versioning)
164     uint32_t packed = static_cast<uint32_t>(fMode);
165     SkASSERT((packed & ~kMode_Mask) == 0);  // our mode fits in the mask bits
166     if (this->hasTexCoords()) {
167         packed |= kHasTexs_Mask;
168     }
169     if (this->hasColors()) {
170         packed |= kHasColors_Mask;
171     }
172 
173     Sizes sizes(fVertexCnt, fIndexCnt, this->hasTexCoords(), this->hasColors());
174     SkASSERT(sizes.isValid());
175     // need to force alignment to 4 for SkWriter32 -- will pad w/ 0s as needed
176     const size_t size = SkAlign4(kHeaderSize + sizes.fArrays);
177 
178     sk_sp<SkData> data = SkData::MakeUninitialized(size);
179     SkWriter32 writer(data->writable_data(), data->size());
180 
181     writer.write32(packed);
182     writer.write32(fVertexCnt);
183     writer.write32(fIndexCnt);
184     writer.write(fPositions, sizes.fVSize);
185     writer.write(fTexs, sizes.fTSize);
186     writer.write(fColors, sizes.fCSize);
187     // if index-count is odd, we won't be 4-bytes aligned, so we call the pad version
188     writer.writePad(fIndices, sizes.fISize);
189 
190     return data;
191 }
192 
Decode(const void * data,size_t length)193 sk_sp<SkVertices> SkVertices::Decode(const void* data, size_t length) {
194     if (length < kHeaderSize) {
195         return nullptr;
196     }
197 
198     SkReader32 reader(data, length);
199     SkSafeRange safe;
200 
201     const uint32_t packed = reader.readInt();
202     const int vertexCount = safe.checkGE(reader.readInt(), 0);
203     const int indexCount = safe.checkGE(reader.readInt(), 0);
204     const VertexMode mode = safe.checkLE<VertexMode>(packed & kMode_Mask,
205                                                      SkVertices::kLast_VertexMode);
206     if (!safe) {
207         return nullptr;
208     }
209     const bool hasTexs = SkToBool(packed & kHasTexs_Mask);
210     const bool hasColors = SkToBool(packed & kHasColors_Mask);
211     Sizes sizes(vertexCount, indexCount, hasTexs, hasColors);
212     if (!sizes.isValid()) {
213         return nullptr;
214     }
215     // logically we can be only 2-byte aligned, but our buffer is always 4-byte aligned
216     if (SkAlign4(kHeaderSize + sizes.fArrays) != length) {
217         return nullptr;
218     }
219 
220     Builder builder(mode, vertexCount, indexCount, sizes);
221 
222     reader.read(builder.positions(), sizes.fVSize);
223     reader.read(builder.texCoords(), sizes.fTSize);
224     reader.read(builder.colors(), sizes.fCSize);
225     reader.read(builder.indices(), sizes.fISize);
226     if (indexCount > 0) {
227         // validate that the indicies are in range
228         SkASSERT(indexCount == builder.indexCount());
229         const uint16_t* indices = builder.indices();
230         for (int i = 0; i < indexCount; ++i) {
231             if (indices[i] >= (unsigned)vertexCount) {
232                 return nullptr;
233             }
234         }
235     }
236     return builder.detach();
237 }
238