1// [Blend2D]
2// 2D Vector Graphics Powered by a JIT Compiler.
3//
4// [License]
5// Zlib - See LICENSE.md file in the package.
6
7#include "./blapi-build_p.h"
8#include "./blarray_p.h"
9#include "./blfont_p.h"
10#include "./blglyphbuffer_p.h"
11#include "./blruntime_p.h"
12#include "./blstring_p.h"
13#include "./blsupport_p.h"
14#include "./blunicode_p.h"
15
16// ============================================================================
17// [BLGlyphBuffer - Internals]
18// ============================================================================
19
20static const constexpr BLInternalGlyphBufferImpl blGlyphBufferInternalImplNone {};
21
22template<typename T>
23static BL_INLINE size_t strlenT(const T* str) noexcept {
24 const T* p = str;
25 while (*p)
26 p++;
27 return (size_t)(p - str);
28}
29
30static BL_INLINE BLResult blGlyphBufferEnsureData(BLGlyphBufferCore* self, BLInternalGlyphBufferImpl** impl) noexcept {
31 *impl = blInternalCast(self->impl);
32 if (*impl != &blGlyphBufferInternalImplNone)
33 return BL_SUCCESS;
34
35 *impl = BLInternalGlyphBufferImpl::create();
36 if (BL_UNLIKELY(!*impl))
37 return blTraceError(BL_ERROR_OUT_OF_MEMORY);
38
39 self->impl = *impl;
40 return BL_SUCCESS;
41}
42
43// ============================================================================
44// [BLGlyphBuffer - Private API]
45// ============================================================================
46
47BLResult BLInternalGlyphBufferImpl::ensureBuffer(size_t bufferId, size_t copySize, size_t minCapacity) noexcept {
48 size_t oldCapacity = capacity[bufferId];
49 BL_ASSERT(copySize <= oldCapacity);
50
51 if (minCapacity <= oldCapacity)
52 return BL_SUCCESS;
53
54 size_t newCapacity = minCapacity;
55 if (newCapacity < BL_GLYPH_BUFFER_INITIAL_CAPACITY)
56 newCapacity = BL_GLYPH_BUFFER_INITIAL_CAPACITY;
57 else if (newCapacity < SIZE_MAX - 256)
58 newCapacity = blAlignUp(minCapacity, 64);
59
60 BLOverflowFlag of = 0;
61 size_t dataSize = blMulOverflow<size_t>(newCapacity, BL_GLYPH_BUFFER_ANY_ITEM_SIZE, &of);
62
63 if (BL_UNLIKELY(of))
64 return BL_ERROR_OUT_OF_MEMORY;
65
66 uint8_t* newData = static_cast<uint8_t*>(malloc(dataSize));
67 if (BL_UNLIKELY(!newData))
68 return BL_ERROR_OUT_OF_MEMORY;
69
70 uint8_t* oldData = static_cast<uint8_t*>(buffer[bufferId]);
71 if (copySize) {
72 memcpy(newData,
73 oldData,
74 copySize * sizeof(BLGlyphItem));
75
76 memcpy(newData + newCapacity * sizeof(BLGlyphItem),
77 oldData + oldCapacity * sizeof(BLGlyphItem),
78 copySize * sizeof(BLGlyphInfo));
79 }
80
81 if (oldData)
82 free(oldData);
83
84 buffer[bufferId] = newData;
85 capacity[bufferId] = newCapacity;
86
87 if (bufferId == 0)
88 getGlyphDataPtrs(0, &glyphItemData, &glyphInfoData);
89
90 return BL_SUCCESS;
91}
92
93static BL_INLINE BLResult blInternalGlyphBufferData_setGlyphIds(BLInternalGlyphBufferImpl* d, const uint16_t* ids, intptr_t advance, size_t size) noexcept {
94 BLGlyphItem* itemData = d->glyphItemData;
95 BLGlyphInfo* infoData = d->glyphInfoData;
96
97 for (size_t i = 0; i < size; i++) {
98 itemData[i].value = *ids;
99 infoData[i].cluster = uint32_t(i);
100 infoData[i].reserved[0] = 0;
101 infoData[i].reserved[1] = 0;
102 ids = blOffsetPtr(ids, advance);
103 }
104
105 d->size = size;
106 d->flags = 0;
107
108 return BL_SUCCESS;
109}
110
111static BL_INLINE BLResult blInternalGlyphBufferData_setLatin1Text(BLInternalGlyphBufferImpl* d, const char* input, size_t size) noexcept {
112 BLGlyphItem* itemData = d->glyphItemData;
113 BLGlyphInfo* infoData = d->glyphInfoData;
114
115 for (size_t i = 0; i < size; i++) {
116 itemData[i].value = uint8_t(input[i]);
117 infoData[i].cluster = uint32_t(i);
118 infoData[i].reserved[0] = 0;
119 infoData[i].reserved[1] = 0;
120 }
121
122 d->size = size;
123 d->flags = 0;
124
125 if (d->size)
126 d->flags |= BL_GLYPH_RUN_FLAG_UCS4_CONTENT;
127
128 return BL_SUCCESS;
129}
130
131template<typename Reader, typename CharType>
132static BL_INLINE BLResult blInternalGlyphBufferData_setUnicodeText(BLInternalGlyphBufferImpl* d, const CharType* input, size_t size) noexcept {
133 Reader reader(input, size);
134
135 BLGlyphItem* itemData = d->glyphItemData;
136 BLGlyphInfo* infoData = d->glyphInfoData;
137
138 while (reader.hasNext()) {
139 uint32_t uc;
140 uint32_t cluster = uint32_t(reader.nativeIndex(input));
141 BLResult result = reader.next(uc);
142
143 itemData->value = uc;
144 infoData->cluster = cluster;
145 infoData->reserved[0] = 0;
146 infoData->reserved[1] = 0;
147
148 itemData++;
149 infoData++;
150
151 if (BL_LIKELY(result == BL_SUCCESS))
152 continue;
153
154 itemData[-1].value = BL_CHAR_REPLACEMENT;
155 d->flags |= BL_GLYPH_RUN_FLAG_INVALID_TEXT;
156 reader.skipOneUnit();
157 }
158
159 d->size = (size_t)(itemData - d->glyphItemData);
160 d->flags = BL_GLYPH_RUN_FLAG_UCS4_CONTENT;
161
162 if (d->size)
163 d->flags |= BL_GLYPH_RUN_FLAG_UCS4_CONTENT;
164
165 return BL_SUCCESS;
166}
167
168// ============================================================================
169// [BLGlyphBuffer - Init / Reset]
170// ============================================================================
171
172BLResult blGlyphBufferInit(BLGlyphBufferCore* self) noexcept {
173 self->impl = const_cast<BLInternalGlyphBufferImpl*>(&blGlyphBufferInternalImplNone);
174 return BL_SUCCESS;
175}
176
177BLResult blGlyphBufferReset(BLGlyphBufferCore* self) noexcept {
178 BLInternalGlyphBufferImpl* impl = blInternalCast(self->impl);
179 if (impl == &blGlyphBufferInternalImplNone)
180 return BL_SUCCESS;
181
182 impl->destroy();
183 self->impl = const_cast<BLInternalGlyphBufferImpl*>(&blGlyphBufferInternalImplNone);
184 return BL_SUCCESS;
185}
186
187// ============================================================================
188// [BLGlyphBuffer - Content]
189// ============================================================================
190
191BLResult blGlyphBufferClear(BLGlyphBufferCore* self) noexcept {
192 BLInternalGlyphBufferImpl* selfI = blInternalCast(self->impl);
193
194 // Would be true if the glyph-buffer is built-in 'none' instance or the data
195 // is allocated, but empty.
196 if (selfI->size == 0)
197 return BL_SUCCESS;
198
199 selfI->clear();
200 return BL_SUCCESS;
201}
202
203BLResult blGlyphBufferSetText(BLGlyphBufferCore* self, const void* data, size_t size, uint32_t encoding) noexcept {
204 if (BL_UNLIKELY(encoding >= BL_TEXT_ENCODING_COUNT))
205 return blTraceError(BL_ERROR_INVALID_VALUE);
206
207 BLInternalGlyphBufferImpl* d;
208 BL_PROPAGATE(blGlyphBufferEnsureData(self, &d));
209
210 switch (encoding) {
211 case BL_TEXT_ENCODING_LATIN1:
212 if (size == SIZE_MAX)
213 size = strlen(static_cast<const char*>(data));
214
215 BL_PROPAGATE(d->ensureBuffer(0, 0, size));
216 return blInternalGlyphBufferData_setLatin1Text(d, static_cast<const char*>(data), size);
217
218 case BL_TEXT_ENCODING_UTF8:
219 if (size == SIZE_MAX)
220 size = strlen(static_cast<const char*>(data));
221
222 BL_PROPAGATE(d->ensureBuffer(0, 0, size));
223 return blInternalGlyphBufferData_setUnicodeText<BLUtf8Reader>(d, static_cast<const uint8_t*>(data), size);
224
225 case BL_TEXT_ENCODING_UTF16:
226 if (size == SIZE_MAX)
227 size = strlenT(static_cast<const uint16_t*>(data));
228
229 BL_PROPAGATE(d->ensureBuffer(0, 0, size));
230 return blInternalGlyphBufferData_setUnicodeText<BLUtf16Reader>(d, static_cast<const uint16_t*>(data), size * 2u);
231
232 case BL_TEXT_ENCODING_UTF32:
233 if (size == SIZE_MAX)
234 size = strlenT(static_cast<const uint32_t*>(data));
235
236 BL_PROPAGATE(d->ensureBuffer(0, 0, size));
237 return blInternalGlyphBufferData_setUnicodeText<BLUtf32Reader>(d, static_cast<const uint32_t*>(data), size * 4u);
238
239 default:
240 BL_NOT_REACHED();
241 }
242}
243
244BLResult blGlyphBufferSetGlyphIds(BLGlyphBufferCore* self, const void* data, intptr_t advance, size_t size) noexcept {
245 BLInternalGlyphBufferImpl* d;
246
247 BL_PROPAGATE(blGlyphBufferEnsureData(self, &d));
248 BL_PROPAGATE(d->ensureBuffer(0, 0, size));
249
250 return blInternalGlyphBufferData_setGlyphIds(d, static_cast<const uint16_t*>(data), advance, size);
251}
252