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 | |
20 | static const constexpr BLInternalGlyphBufferImpl blGlyphBufferInternalImplNone {}; |
21 | |
22 | template<typename T> |
23 | static 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 | |
30 | static 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 | |
47 | BLResult 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 | |
93 | static 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 | |
111 | static 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 | |
131 | template<typename Reader, typename CharType> |
132 | static 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 | |
172 | BLResult blGlyphBufferInit(BLGlyphBufferCore* self) noexcept { |
173 | self->impl = const_cast<BLInternalGlyphBufferImpl*>(&blGlyphBufferInternalImplNone); |
174 | return BL_SUCCESS; |
175 | } |
176 | |
177 | BLResult 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 | |
191 | BLResult 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 | |
203 | BLResult 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 | |
244 | BLResult 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 | |