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 "./blglyphbuffer_p.h" |
10 | #include "./blfilesystem.h" |
11 | #include "./blfont_p.h" |
12 | #include "./blmatrix.h" |
13 | #include "./blpath.h" |
14 | #include "./blruntime_p.h" |
15 | #include "./blstring_p.h" |
16 | #include "./blsupport_p.h" |
17 | #include "./blthreading_p.h" |
18 | #include "./blunicode_p.h" |
19 | #include "./opentype/blotcore_p.h" |
20 | #include "./opentype/blotface_p.h" |
21 | |
22 | // ============================================================================ |
23 | // [Global Variables] |
24 | // ============================================================================ |
25 | |
26 | BLInternalFontFaceFuncs blNullFontFaceFuncs; |
27 | |
28 | static BLWrap<BLInternalFontImpl> blNullFontImpl; |
29 | static BLWrap<BLInternalFontFaceImpl> blNullFontFaceImpl; |
30 | static BLWrap<BLFontDataImpl> blNullFontDataImpl; |
31 | static BLWrap<BLFontLoaderImpl> blNullFontLoaderImpl; |
32 | |
33 | static BLFontFaceVirt blNullFontFaceVirt; |
34 | static BLAtomicUInt64Generator blFontFaceIdGenerator; |
35 | |
36 | // ============================================================================ |
37 | // [BLFontData / BLFontLoader - Null] |
38 | // ============================================================================ |
39 | |
40 | BL_DIAGNOSTIC_PUSH(BL_DIAGNOSTIC_NO_UNUSED_PARAMETERS) |
41 | |
42 | static BLFontDataVirt blNullFontDataVirt; |
43 | static BLFontLoaderVirt blNullFontLoaderVirt; |
44 | |
45 | static BLResult BL_CDECL blNullFontDataImplDestroy(BLFontDataImpl* impl) noexcept { |
46 | return BL_SUCCESS; |
47 | } |
48 | |
49 | static BLResult BL_CDECL blNullFontDataImplListTags(const BLFontDataImpl* impl, BLArrayCore* out) noexcept { |
50 | return blArrayClear(out); |
51 | } |
52 | |
53 | static size_t BL_CDECL blNullFontDataImplQueryTables(const BLFontDataImpl* impl, BLFontTable* dst, const BLTag* tags, size_t n) noexcept { |
54 | for (size_t i = 0; i < n; i++) |
55 | dst[i].reset(); |
56 | return 0; |
57 | } |
58 | |
59 | static BLResult BL_CDECL blNullFontLoaderImplDestroy(BLFontLoaderImpl* impl) noexcept { |
60 | return BL_SUCCESS; |
61 | } |
62 | |
63 | static BLFontDataImpl* BL_CDECL blNullFontLoaderImplDataByFaceIndex(BLFontLoaderImpl* impl, uint32_t faceIndex) noexcept { |
64 | return &blNullFontDataImpl; |
65 | } |
66 | |
67 | BL_DIAGNOSTIC_POP |
68 | |
69 | // ============================================================================ |
70 | // [BLFontData / BLFontLoader - Utilities] |
71 | // ============================================================================ |
72 | |
73 | static BL_INLINE bool isOpenTypeVersionTag(uint32_t tag) noexcept { |
74 | return tag == BL_MAKE_TAG('O', 'T', 'T', 'O') || |
75 | tag == BL_MAKE_TAG( 0, 1 , 0 , 0 ) || |
76 | tag == BL_MAKE_TAG('t', 'r', 'u', 'e') ; |
77 | } |
78 | |
79 | // ============================================================================ |
80 | // [BLFontData / BLFontLoader - Memory] |
81 | // ============================================================================ |
82 | |
83 | // Users can pass their own buffer with a destroy function that gets called when |
84 | // the `BLMemFontLoaderImpl` gets destroyed. However, the impl stores an array |
85 | // of `BLFontData` where each of them is implemented by `BLMemFontDataImpl` and |
86 | // stores a back-reference to the loader. So how to avoid a circular dependency |
87 | // that would prevent the destruction of the loader? We simply add an another |
88 | // reference count to the loader, which counts how many `BLMemFontDataImpl` |
89 | // instances back-reference it. |
90 | // |
91 | // The loader destructor is not a real destructor and it can be considered an |
92 | // interceptor instead. It intercepts the destroy call that is caused by the |
93 | // reference-count going to zero. When this happens we destroy all data, which |
94 | // would call a real-destructor when the `backRefCount` goes to zero. We take |
95 | // advantage of the fact that BLMemFontLoaderImpl's destroy function will be |
96 | // called always before its data is destroyed as `BLArray<BLFontData>` holds |
97 | // it. |
98 | |
99 | static BLFontDataVirt blMemFontDataVirt; |
100 | static BLFontLoaderVirt blMemFontLoaderVirt; |
101 | |
102 | struct BLMemFontLoaderImpl : public BLFontLoaderImpl { |
103 | BLArray<BLFontData> dataArray; |
104 | volatile size_t backRefCount; |
105 | }; |
106 | |
107 | struct BLMemFontDataImpl : public BLFontDataImpl { |
108 | BLMemFontLoaderImpl* loaderI; |
109 | }; |
110 | |
111 | // Destroys `BLMemFontLoaderImpl` - this is a real destructor that would |
112 | // free the impl data. |
113 | static BLResult blMemFontLoaderImplRealDestroy(BLMemFontLoaderImpl* impl) noexcept { |
114 | uint8_t* implBase = reinterpret_cast<uint8_t*>(impl); |
115 | size_t implSize = sizeof(BLMemFontLoaderImpl); |
116 | uint32_t implTraits = impl->implTraits; |
117 | uint32_t memPoolData = impl->memPoolData; |
118 | |
119 | if (implTraits & BL_IMPL_TRAIT_EXTERNAL) { |
120 | implSize += sizeof(BLExternalImplPreface); |
121 | implBase -= sizeof(BLExternalImplPreface); |
122 | blImplDestroyExternal(impl); |
123 | } |
124 | |
125 | return blRuntimeFreeImpl(implBase, implSize, memPoolData); |
126 | } |
127 | |
128 | // A fake `BLMemFontLoaderImpl` destructor that just intercepts when the loader |
129 | // reference-count gets to zero. This resets the data-array and would destroy |
130 | // all BLMemFontDataImpl's it holds. If user doesn't hold an of them then this |
131 | // would automatically call the real destructor. |
132 | static BLResult BL_CDECL blMemFontLoaderImplFakeDestroy(BLFontLoaderImpl* impl_) noexcept { |
133 | BLMemFontLoaderImpl* impl = static_cast<BLMemFontLoaderImpl*>(impl_); |
134 | return impl->dataArray.reset(); |
135 | } |
136 | |
137 | static BLFontDataImpl* BL_CDECL blMemFontLoaderImplDataByFaceIndex(BLFontLoaderImpl* impl_, uint32_t faceIndex) noexcept { |
138 | BLMemFontLoaderImpl* impl = static_cast<BLMemFontLoaderImpl*>(impl_); |
139 | if (faceIndex >= impl->dataArray.size()) |
140 | return &blNullFontDataImpl; |
141 | return blImplIncRef(impl->dataArray[faceIndex].impl); |
142 | } |
143 | |
144 | static BLResult BL_CDECL blMemFontDataImplDestroy(BLFontDataImpl* impl_) noexcept { |
145 | BLMemFontDataImpl* impl = static_cast<BLMemFontDataImpl*>(impl_); |
146 | uint32_t memPoolData = impl->memPoolData; |
147 | |
148 | BLMemFontLoaderImpl* loaderI = impl->loaderI; |
149 | blRuntimeFreeImpl(impl, sizeof(BLMemFontDataImpl), memPoolData); |
150 | |
151 | if (blAtomicFetchSub(&loaderI->backRefCount) != 1) |
152 | return BL_SUCCESS; |
153 | |
154 | return blMemFontLoaderImplRealDestroy(loaderI); |
155 | } |
156 | |
157 | static BLResult BL_CDECL blMemFontDataImplListTags(const BLFontDataImpl* impl_, BLArrayCore* out) noexcept { |
158 | using namespace BLOpenType; |
159 | |
160 | const BLMemFontDataImpl* impl = static_cast<const BLMemFontDataImpl*>(impl_); |
161 | |
162 | // We can safely multiply `tableCount` as SFNTHeader::numTables is `UInt16`. |
163 | const SFNTHeader* sfnt = static_cast<const SFNTHeader*>(impl->data); |
164 | size_t tableCount = sfnt->numTables(); |
165 | size_t minDataSize = sizeof(SFNTHeader) + tableCount * sizeof(SFNTHeader::TableRecord); |
166 | |
167 | if (BL_UNLIKELY(impl->size < minDataSize)) { |
168 | blArrayClear(out); |
169 | return blTraceError(BL_ERROR_INVALID_DATA); |
170 | } |
171 | |
172 | uint32_t* dst; |
173 | BL_PROPAGATE(blArrayModifyOp(out, BL_MODIFY_OP_ASSIGN_FIT, tableCount, (void**)&dst)); |
174 | |
175 | const SFNTHeader::TableRecord* tables = sfnt->tableRecords(); |
176 | for (size_t tableIndex = 0; tableIndex < tableCount; tableIndex++) |
177 | dst[tableIndex] = tables[tableIndex].tag(); |
178 | return BL_SUCCESS; |
179 | } |
180 | |
181 | static size_t BL_CDECL blMemFontDataImplQueryTables(const BLFontDataImpl* impl_, BLFontTable* dst, const BLTag* tags, size_t n) noexcept { |
182 | using namespace BLOpenType; |
183 | |
184 | const BLMemFontDataImpl* impl = static_cast<const BLMemFontDataImpl*>(impl_); |
185 | |
186 | const void* data = impl->data; |
187 | size_t dataSize = impl->size; |
188 | |
189 | // We can safely multiply `tableCount` as SFNTHeader::numTables is `UInt16`. |
190 | const SFNTHeader* sfnt = static_cast<const SFNTHeader*>(data); |
191 | size_t tableCount = sfnt->numTables(); |
192 | size_t minDataSize = sizeof(SFNTHeader) + tableCount * sizeof(SFNTHeader::TableRecord); |
193 | |
194 | if (BL_UNLIKELY(dataSize < minDataSize)) { |
195 | memset(dst, 0, n * sizeof(BLFontTable)); |
196 | return 0; |
197 | } |
198 | |
199 | size_t matchCount = 0; |
200 | const SFNTHeader::TableRecord* tables = sfnt->tableRecords(); |
201 | |
202 | // Iterate over all tables and try to find all tables as specified by `tags`. |
203 | for (size_t tagIndex = 0; tagIndex < n; tagIndex++) { |
204 | uint32_t tag = blByteSwap32BE(tags[tagIndex]); |
205 | dst[tagIndex].reset(); |
206 | |
207 | for (size_t tableIndex = 0; tableIndex < tableCount; tableIndex++) { |
208 | const SFNTHeader::TableRecord& table = tables[tableIndex]; |
209 | |
210 | if (table.tag.rawValue() == tag) { |
211 | uint32_t tableOffset = table.offset(); |
212 | uint32_t tableSize = table.length(); |
213 | |
214 | if (tableOffset < dataSize && tableSize && tableSize <= dataSize - tableOffset) { |
215 | matchCount++; |
216 | dst[tagIndex].data = blOffsetPtr<uint8_t>(data, tableOffset); |
217 | dst[tagIndex].size = tableSize; |
218 | } |
219 | |
220 | break; |
221 | } |
222 | } |
223 | } |
224 | |
225 | return matchCount; |
226 | } |
227 | |
228 | // ============================================================================ |
229 | // [BLFontData] |
230 | // ============================================================================ |
231 | |
232 | BLResult blFontDataInit(BLFontDataCore* self) noexcept { |
233 | self->impl = &blNullFontDataImpl; |
234 | return BL_SUCCESS; |
235 | } |
236 | |
237 | BLResult blFontDataInitFromLoader(BLFontDataCore* self, const BLFontLoaderCore* loader, uint32_t faceIndex) noexcept { |
238 | BLFontLoaderImpl* loaderI = loader->impl; |
239 | BLFontDataImpl* dataI = loaderI->virt->dataByFaceIndex(loaderI, faceIndex); |
240 | |
241 | // Always assign the impl as this is what INIT would always do. If this is |
242 | // NONE impl then the object would be default initialized, otherwise the |
243 | // impl has been already ref-counted by calling `dataByFaceIndex()`. |
244 | self->impl = dataI; |
245 | |
246 | if (dataI->implTraits & BL_IMPL_TRAIT_NULL) |
247 | return blTraceError(blDownCast(loader)->empty() ? BL_ERROR_NOT_INITIALIZED : BL_ERROR_INVALID_VALUE); |
248 | return BL_SUCCESS; |
249 | } |
250 | |
251 | BLResult blFontDataReset(BLFontDataCore* self) noexcept { |
252 | BLFontDataImpl* selfI = self->impl; |
253 | |
254 | self->impl = &blNullFontDataImpl; |
255 | return blImplReleaseVirt(selfI); |
256 | } |
257 | |
258 | BLResult blFontDataAssignMove(BLFontDataCore* self, BLFontDataCore* other) noexcept { |
259 | BLFontDataImpl* selfI = self->impl; |
260 | BLFontDataImpl* otherI = other->impl; |
261 | |
262 | self->impl = otherI; |
263 | other->impl = &blNullFontDataImpl; |
264 | |
265 | return blImplReleaseVirt(selfI); |
266 | } |
267 | |
268 | BLResult blFontDataAssignWeak(BLFontDataCore* self, const BLFontDataCore* other) noexcept { |
269 | BLFontDataImpl* selfI = self->impl; |
270 | BLFontDataImpl* otherI = other->impl; |
271 | |
272 | self->impl = blImplIncRef(otherI); |
273 | return blImplReleaseVirt(selfI); |
274 | } |
275 | |
276 | BLResult blFontDataCreateFromLoader(BLFontDataCore* self, const BLFontLoaderCore* loader, uint32_t faceIndex) noexcept { |
277 | BLFontLoaderImpl* loaderI = loader->impl; |
278 | BLFontDataImpl* oldI = self->impl; |
279 | BLFontDataImpl* newI = loaderI->virt->dataByFaceIndex(loaderI, faceIndex); |
280 | |
281 | if (newI->implTraits & BL_IMPL_TRAIT_NULL) |
282 | return blTraceError(blDownCast(loader)->empty() ? BL_ERROR_NOT_INITIALIZED : BL_ERROR_INVALID_VALUE); |
283 | |
284 | self->impl = newI; |
285 | return blImplReleaseVirt(oldI); |
286 | } |
287 | |
288 | bool blFontDataEquals(const BLFontDataCore* a, const BLFontDataCore* b) noexcept { |
289 | return a->impl == b->impl; |
290 | } |
291 | |
292 | BLResult blFontDataListTags(const BLFontDataCore* self, BLArrayCore* dst) noexcept { |
293 | BLFontDataImpl* selfI = self->impl; |
294 | return selfI->virt->listTags(selfI, dst); |
295 | } |
296 | |
297 | size_t blFontDataQueryTables(const BLFontDataCore* self, BLFontTable* dst, const BLTag* tags, size_t count) noexcept { |
298 | BLFontDataImpl* selfI = self->impl; |
299 | return selfI->virt->queryTables(selfI, dst, tags, count); |
300 | } |
301 | |
302 | // ============================================================================ |
303 | // [BLFontLoader - Init / Reset] |
304 | // ============================================================================ |
305 | |
306 | BLResult blFontLoaderInit(BLFontLoaderCore* self) noexcept { |
307 | self->impl = &blNullFontLoaderImpl; |
308 | return BL_SUCCESS; |
309 | } |
310 | |
311 | BLResult blFontLoaderReset(BLFontLoaderCore* self) noexcept { |
312 | BLFontLoaderImpl* selfI = self->impl; |
313 | self->impl = &blNullFontLoaderImpl; |
314 | return blImplReleaseVirt(selfI); |
315 | } |
316 | |
317 | // ============================================================================ |
318 | // [BLFontLoader - Assign] |
319 | // ============================================================================ |
320 | |
321 | BLResult blFontLoaderAssignMove(BLFontLoaderCore* self, BLFontLoaderCore* other) noexcept { |
322 | BLFontLoaderImpl* selfI = self->impl; |
323 | BLFontLoaderImpl* otherI = other->impl; |
324 | |
325 | self->impl = otherI; |
326 | other->impl = &blNullFontLoaderImpl; |
327 | |
328 | return blImplReleaseVirt(selfI); |
329 | } |
330 | |
331 | BLResult blFontLoaderAssignWeak(BLFontLoaderCore* self, const BLFontLoaderCore* other) noexcept { |
332 | BLFontLoaderImpl* selfI = self->impl; |
333 | BLFontLoaderImpl* otherI = other->impl; |
334 | |
335 | self->impl = blImplIncRef(otherI); |
336 | return blImplReleaseVirt(selfI); |
337 | } |
338 | |
339 | // ============================================================================ |
340 | // [BLFontLoader - Equals] |
341 | // ============================================================================ |
342 | |
343 | bool blFontLoaderEquals(const BLFontLoaderCore* a, const BLFontLoaderCore* b) noexcept { |
344 | return a->impl == b->impl; |
345 | } |
346 | |
347 | // ============================================================================ |
348 | // [BLFontLoader - Create] |
349 | // ============================================================================ |
350 | |
351 | // A callback that we use to destroy an array-impl we keep if `BLMemFontLoaderImpl` |
352 | // was created from `BLArray<T>()`. |
353 | static void BL_CDECL blDestroyArrayImpl(void* impl, void* arrayI) noexcept { |
354 | BL_UNUSED(impl); |
355 | blArrayImplRelease(static_cast<BLArrayImpl*>(arrayI)); |
356 | } |
357 | |
358 | BLResult blFontLoaderCreateFromFile(BLFontLoaderCore* self, const char* fileName, uint32_t readFlags) noexcept { |
359 | BLArray<uint8_t> buffer; |
360 | BL_PROPAGATE(BLFileSystem::readFile(fileName, buffer, 0, readFlags)); |
361 | |
362 | if (buffer.empty()) |
363 | return blTraceError(BL_ERROR_FILE_EMPTY); |
364 | |
365 | return blFontLoaderCreateFromDataArray(self, &buffer); |
366 | } |
367 | |
368 | BLResult blFontLoaderCreateFromDataArray(BLFontLoaderCore* self, const BLArrayCore* dataArray) noexcept { |
369 | BLArrayImpl* arrI = dataArray->impl; |
370 | BLResult result = blFontLoaderCreateFromData(self, arrI->data, arrI->size * arrI->itemSize, blDestroyArrayImpl, arrI); |
371 | |
372 | if (result == BL_SUCCESS) |
373 | blImplIncRef(arrI); |
374 | return result; |
375 | } |
376 | |
377 | BLResult blFontLoaderCreateFromData(BLFontLoaderCore* self, const void* data, size_t size, BLDestroyImplFunc destroyFunc, void* destroyData) noexcept { |
378 | using namespace BLOpenType; |
379 | |
380 | constexpr uint32_t kMinSize = blMin<uint32_t>(SFNTHeader::kMinSize, TTCFHeader::kMinSize); |
381 | if (BL_UNLIKELY(size < kMinSize)) |
382 | return blTraceError(BL_ERROR_INVALID_DATA); |
383 | |
384 | uint32_t = blOffsetPtr<const UInt32>(data, 0)->value(); |
385 | uint32_t faceCount = 1; |
386 | uint32_t loaderFlags = 0; |
387 | |
388 | const UInt32* offsetArray = nullptr; |
389 | if (headerTag == BL_MAKE_TAG('t', 't', 'c', 'f')) { |
390 | if (BL_UNLIKELY(size < TTCFHeader::kMinSize)) |
391 | return blTraceError(BL_ERROR_INVALID_DATA); |
392 | |
393 | const TTCFHeader* = blOffsetPtr<const TTCFHeader>(data, 0); |
394 | |
395 | faceCount = header->fonts.count(); |
396 | if (BL_UNLIKELY(!faceCount || faceCount > BL_FONT_LOADER_MAX_FACE_COUNT)) |
397 | return blTraceError(BL_ERROR_INVALID_DATA); |
398 | |
399 | size_t = header->calcSize(faceCount); |
400 | if (BL_UNLIKELY(ttcHeaderSize < size)) |
401 | return blTraceError(BL_ERROR_INVALID_DATA); |
402 | |
403 | offsetArray = header->fonts.array(); |
404 | loaderFlags |= BL_FONT_LOADER_FLAG_COLLECTION; |
405 | } |
406 | else { |
407 | if (!isOpenTypeVersionTag(headerTag)) |
408 | return blTraceError(BL_ERROR_INVALID_SIGNATURE); |
409 | } |
410 | |
411 | uint16_t memPoolData; |
412 | uint32_t faceIndex; |
413 | |
414 | BLArray<BLFontData> fontDataArray; |
415 | BL_PROPAGATE(fontDataArray.reserve(faceCount)); |
416 | |
417 | for (faceIndex = 0; faceIndex < faceCount; faceIndex++) { |
418 | uint32_t faceOffset = 0; |
419 | if (offsetArray) |
420 | faceOffset = offsetArray[faceIndex].value(); |
421 | |
422 | if (BL_UNLIKELY(faceOffset >= size)) |
423 | return blTraceError(BL_ERROR_INVALID_DATA); |
424 | |
425 | size_t faceDataSize = size - faceOffset; |
426 | if (BL_UNLIKELY(faceDataSize < SFNTHeader::kMinSize)) |
427 | return blTraceError(BL_ERROR_INVALID_DATA); |
428 | |
429 | const SFNTHeader* sfnt = blOffsetPtr<const SFNTHeader>(data, faceOffset); |
430 | uint32_t versionTag = sfnt->versionTag(); |
431 | uint32_t tableCount = sfnt->numTables(); |
432 | |
433 | if (!isOpenTypeVersionTag(versionTag)) |
434 | return blTraceError(BL_ERROR_INVALID_DATA); |
435 | |
436 | if (faceDataSize < sizeof(SFNTHeader) + tableCount * sizeof(SFNTHeader::TableRecord)) |
437 | return blTraceError(BL_ERROR_INVALID_DATA); |
438 | |
439 | BLMemFontDataImpl* fontDataI = blRuntimeAllocImplT<BLMemFontDataImpl>(sizeof(BLMemFontDataImpl), &memPoolData); |
440 | if (BL_UNLIKELY(!fontDataI)) |
441 | return blTraceError(BL_ERROR_OUT_OF_MEMORY); |
442 | |
443 | blImplInit(fontDataI, BL_IMPL_TYPE_FONT_DATA, BL_IMPL_TRAIT_MUTABLE | BL_IMPL_TRAIT_VIRT, memPoolData); |
444 | fontDataI->virt = &blMemFontDataVirt; |
445 | fontDataI->data = const_cast<void*>(static_cast<const void*>(sfnt)); |
446 | fontDataI->size = size - faceOffset; |
447 | fontDataI->flags = 0; |
448 | fontDataI->loaderI = nullptr; |
449 | |
450 | // Cannot fail as we reserved enough space for data for all faces. |
451 | fontDataArray.append(BLFontData(fontDataI)); |
452 | } |
453 | |
454 | // Finally - allocate the BLMemFontLoaderImpl and assign `fontDataArray` to it. |
455 | size_t loaderSize = sizeof(BLMemFontLoaderImpl); |
456 | uint32_t loaderTraits = BL_IMPL_TRAIT_MUTABLE | BL_IMPL_TRAIT_VIRT; |
457 | |
458 | if (destroyFunc) { |
459 | loaderSize += sizeof(BLExternalImplPreface); |
460 | loaderTraits |= BL_IMPL_TRAIT_EXTERNAL; |
461 | } |
462 | |
463 | BLMemFontLoaderImpl* loaderI = blRuntimeAllocImplT<BLMemFontLoaderImpl>(loaderSize, &memPoolData); |
464 | if (BL_UNLIKELY(!loaderI)) |
465 | return blTraceError(BL_ERROR_OUT_OF_MEMORY); |
466 | |
467 | if (destroyFunc) |
468 | loaderI = blImplInitExternal(loaderI, destroyFunc, destroyData); |
469 | |
470 | blImplInit(loaderI, BL_IMPL_TYPE_FONT_LOADER, loaderTraits, memPoolData); |
471 | loaderI->virt = &blMemFontLoaderVirt; |
472 | loaderI->data = const_cast<void*>(static_cast<const void*>(data));; |
473 | loaderI->size = size; |
474 | loaderI->faceType = uint8_t(BL_FONT_FACE_TYPE_OPENTYPE); |
475 | loaderI->faceCount = faceCount; |
476 | loaderI->loaderFlags = loaderFlags; |
477 | loaderI->dataArray.impl = blImplIncRef(fontDataArray.impl); |
478 | loaderI->backRefCount = faceCount; |
479 | |
480 | // Now fix all `BLMemFontDataImpl` instances to point to the newly created loader. |
481 | for (faceIndex = 0; faceIndex < faceCount; faceIndex++) |
482 | static_cast<BLMemFontDataImpl*>(fontDataArray[faceIndex].impl)->loaderI = loaderI; |
483 | |
484 | BLFontLoaderImpl* oldI = self->impl; |
485 | self->impl = loaderI; |
486 | return blImplReleaseVirt(oldI); |
487 | }; |
488 | |
489 | // ============================================================================ |
490 | // [BLFontFace - Null] |
491 | // ============================================================================ |
492 | |
493 | BL_DIAGNOSTIC_PUSH(BL_DIAGNOSTIC_NO_UNUSED_PARAMETERS) |
494 | |
495 | static BLResult BL_CDECL blNullFontFaceImplDestroy(BLFontFaceImpl* impl) noexcept { |
496 | return BL_SUCCESS; |
497 | } |
498 | |
499 | static BLResult BL_CDECL blNullFontFaceMapTextToGlyphs( |
500 | const BLFontFaceImpl* impl, |
501 | BLGlyphItem* itemData, |
502 | size_t count, |
503 | BLGlyphMappingState* state) noexcept { |
504 | |
505 | state->reset(); |
506 | return blTraceError(BL_ERROR_NOT_INITIALIZED); |
507 | } |
508 | |
509 | static BLResult BL_CDECL blNullFontFaceGetGlyphBounds( |
510 | const BLFontFaceImpl* impl, |
511 | const BLGlyphId* glyphIdData, |
512 | intptr_t glyphIdAdvance, |
513 | BLBoxI* boxes, |
514 | size_t count) noexcept { |
515 | |
516 | return blTraceError(BL_ERROR_NOT_INITIALIZED); |
517 | } |
518 | |
519 | static BLResult BL_CDECL blNullFontFaceGetGlyphAdvances( |
520 | const BLFontFaceImpl* impl, |
521 | const BLGlyphId* glyphIdData, |
522 | intptr_t glyphIdAdvance, |
523 | BLGlyphPlacement* placementData, |
524 | size_t count) noexcept { |
525 | |
526 | return blTraceError(BL_ERROR_NOT_INITIALIZED); |
527 | } |
528 | |
529 | static BLResult BL_CDECL blNullFontFaceApplyKern( |
530 | const BLFontFaceImpl* faceI, |
531 | BLGlyphItem* itemData, |
532 | BLGlyphPlacement* placementData, |
533 | size_t count) noexcept { |
534 | |
535 | return blTraceError(BL_ERROR_NOT_INITIALIZED); |
536 | } |
537 | |
538 | static BLResult BL_CDECL blNullFontFaceApplyGSub( |
539 | const BLFontFaceImpl* impl, |
540 | BLGlyphBuffer* gb, |
541 | size_t index, |
542 | BLBitWord lookups) noexcept { |
543 | |
544 | return blTraceError(BL_ERROR_NOT_INITIALIZED); |
545 | } |
546 | |
547 | static BLResult BL_CDECL blNullFontFaceApplyGPos( |
548 | const BLFontFaceImpl* impl, |
549 | BLGlyphBuffer* gb, |
550 | size_t index, |
551 | BLBitWord lookups) noexcept { |
552 | |
553 | return blTraceError(BL_ERROR_NOT_INITIALIZED); |
554 | } |
555 | |
556 | static BLResult BL_CDECL blNullFontFacePositionGlyphs( |
557 | const BLFontFaceImpl* impl, |
558 | BLGlyphItem* itemData, |
559 | BLGlyphPlacement* placementData, |
560 | size_t count) noexcept { |
561 | |
562 | return blTraceError(BL_ERROR_NOT_INITIALIZED); |
563 | } |
564 | |
565 | static BLResult BL_CDECL blNullFontFaceDecodeGlyph( |
566 | const BLFontFaceImpl* impl, |
567 | uint32_t glyphId, |
568 | const BLMatrix2D* userMatrix, |
569 | BLPath* out, |
570 | BLMemBuffer* tmpBuffer, |
571 | BLPathSinkFunc sink, size_t sinkGlyphIndex, void* closure) noexcept { |
572 | |
573 | return blTraceError(BL_ERROR_NOT_INITIALIZED); |
574 | } |
575 | |
576 | BL_DIAGNOSTIC_POP |
577 | |
578 | // ============================================================================ |
579 | // [BLFontFace - Init / Reset] |
580 | // ============================================================================ |
581 | |
582 | BLResult blFontFaceInit(BLFontFaceCore* self) noexcept { |
583 | self->impl = &blNullFontFaceImpl; |
584 | return BL_SUCCESS; |
585 | } |
586 | |
587 | BLResult blFontFaceReset(BLFontFaceCore* self) noexcept { |
588 | BLInternalFontFaceImpl* selfI = blInternalCast(self->impl); |
589 | self->impl = &blNullFontFaceImpl; |
590 | return blImplReleaseVirt(selfI); |
591 | } |
592 | |
593 | // ============================================================================ |
594 | // [BLFontFace - Assign] |
595 | // ============================================================================ |
596 | |
597 | BLResult blFontFaceAssignMove(BLFontFaceCore* self, BLFontFaceCore* other) noexcept { |
598 | BLInternalFontFaceImpl* selfI = blInternalCast(self->impl); |
599 | BLInternalFontFaceImpl* otherI = blInternalCast(other->impl); |
600 | |
601 | self->impl = otherI; |
602 | other->impl = &blNullFontFaceImpl; |
603 | |
604 | return blImplReleaseVirt(selfI); |
605 | } |
606 | |
607 | BLResult blFontFaceAssignWeak(BLFontFaceCore* self, const BLFontFaceCore* other) noexcept { |
608 | BLInternalFontFaceImpl* selfI = blInternalCast(self->impl); |
609 | BLInternalFontFaceImpl* otherI = blInternalCast(other->impl); |
610 | |
611 | self->impl = blImplIncRef(otherI); |
612 | return blImplReleaseVirt(selfI); |
613 | } |
614 | |
615 | // ============================================================================ |
616 | // [BLFontFace - Equals] |
617 | // ============================================================================ |
618 | |
619 | bool blFontFaceEquals(const BLFontFaceCore* a, const BLFontFaceCore* b) noexcept { |
620 | return a->impl == b->impl; |
621 | } |
622 | |
623 | // ============================================================================ |
624 | // [BLFontFace - Create] |
625 | // ============================================================================ |
626 | |
627 | BLResult blFontFaceCreateFromFile(BLFontFaceCore* self, const char* fileName, uint32_t readFlags) noexcept { |
628 | BLFontLoader loader; |
629 | BL_PROPAGATE(loader.createFromFile(fileName, readFlags)); |
630 | return blFontFaceCreateFromLoader(self, &loader, 0); |
631 | } |
632 | |
633 | BLResult blFontFaceCreateFromLoader(BLFontFaceCore* self, const BLFontLoaderCore* loader, uint32_t faceIndex) noexcept { |
634 | if (BL_UNLIKELY(blDownCast(loader)->isNone())) |
635 | return blTraceError(BL_ERROR_NOT_INITIALIZED); |
636 | |
637 | if (BL_UNLIKELY(faceIndex >= loader->impl->faceCount)) |
638 | return blTraceError(BL_ERROR_INVALID_VALUE); |
639 | |
640 | BLFontData fontData = blDownCast(loader)->dataByFaceIndex(faceIndex); |
641 | if (BL_UNLIKELY(fontData.empty())) |
642 | return blTraceError(BL_ERROR_OUT_OF_MEMORY); |
643 | |
644 | BLOTFaceImpl* newI; |
645 | BL_PROPAGATE(blOTFaceImplNew(&newI, static_cast<const BLFontLoader*>(loader), &fontData, faceIndex)); |
646 | newI->faceUniqueId = blFontFaceIdGenerator.next(); |
647 | |
648 | BLInternalFontFaceImpl* oldI = blInternalCast(self->impl); |
649 | self->impl = newI; |
650 | return blImplReleaseVirt(oldI); |
651 | } |
652 | |
653 | // ============================================================================ |
654 | // [BLFontFace - Properties] |
655 | // ============================================================================ |
656 | |
657 | BLResult blFontFaceGetFaceInfo(const BLFontFaceCore* self, BLFontFaceInfo* out) noexcept { |
658 | *out = blDownCast(self)->faceInfo(); |
659 | return BL_SUCCESS; |
660 | } |
661 | |
662 | BLResult blFontFaceGetDesignMetrics(const BLFontFaceCore* self, BLFontDesignMetrics* out) noexcept { |
663 | *out = blDownCast(self)->designMetrics(); |
664 | return BL_SUCCESS; |
665 | } |
666 | |
667 | BLResult blFontFaceGetUnicodeCoverage(const BLFontFaceCore* self, BLFontUnicodeCoverage* out) noexcept { |
668 | *out = blDownCast(self)->unicodeCoverage(); |
669 | return BL_SUCCESS; |
670 | } |
671 | |
672 | // ============================================================================ |
673 | // [BLFont - Utilities] |
674 | // ============================================================================ |
675 | |
676 | static void blFontImplCalcProperties(BLFontImpl* fontI, const BLFontFaceImpl* faceI, float size) noexcept { |
677 | const BLFontDesignMetrics& dm = faceI->designMetrics; |
678 | double yScale = dm.unitsPerEm ? double(size) / double(dm.unitsPerEm) : 0.0; |
679 | double xScale = yScale; |
680 | |
681 | fontI->metrics.size = size; |
682 | fontI->metrics.ascent = float(double(dm.ascent ) * yScale); |
683 | fontI->metrics.descent = float(double(dm.descent ) * yScale); |
684 | fontI->metrics.lineGap = float(double(dm.lineGap ) * yScale); |
685 | fontI->metrics.xHeight = float(double(dm.xHeight ) * yScale); |
686 | fontI->metrics.capHeight = float(double(dm.capHeight ) * yScale); |
687 | fontI->metrics.vAscent = float(double(dm.vAscent ) * yScale); |
688 | fontI->metrics.vDescent = float(double(dm.vDescent ) * yScale); |
689 | fontI->metrics.underlinePosition = float(double(dm.underlinePosition ) * yScale); |
690 | fontI->metrics.underlineThickness = float(double(dm.underlineThickness ) * yScale); |
691 | fontI->metrics.strikethroughPosition = float(double(dm.strikethroughPosition ) * yScale); |
692 | fontI->metrics.strikethroughThickness = float(double(dm.strikethroughThickness) * yScale); |
693 | fontI->matrix.reset(xScale, 0.0, 0.0, -yScale); |
694 | } |
695 | |
696 | // ============================================================================ |
697 | // [BLFont - Internals] |
698 | // ============================================================================ |
699 | |
700 | static BL_INLINE BLInternalFontImpl* blFontImplNew(BLFontFaceImpl* faceI, float size) noexcept { |
701 | uint16_t memPoolData; |
702 | BLInternalFontImpl* impl = blRuntimeAllocImplT<BLInternalFontImpl>(sizeof(BLInternalFontImpl), &memPoolData); |
703 | |
704 | if (BL_UNLIKELY(!impl)) |
705 | return impl; |
706 | |
707 | blImplInit(impl, BL_IMPL_TYPE_FONT, BL_IMPL_TRAIT_MUTABLE, memPoolData); |
708 | impl->face.impl = blImplIncRef(faceI); |
709 | impl->features.impl = BLArray<BLFontFeature>::none().impl; |
710 | impl->variations.impl = BLArray<BLFontVariation>::none().impl; |
711 | impl->weight = 0; |
712 | impl->stretch = 0; |
713 | impl->style = 0; |
714 | blFontImplCalcProperties(impl, faceI, size); |
715 | |
716 | return impl; |
717 | } |
718 | |
719 | // Cannot be static, called by `BLVariant` implementation. |
720 | BLResult blFontImplDelete(BLFontImpl* impl_) noexcept { |
721 | BLInternalFontImpl* impl = blInternalCast(impl_); |
722 | |
723 | impl->face.reset(); |
724 | impl->features.reset(); |
725 | impl->variations.reset(); |
726 | |
727 | uint8_t* implBase = reinterpret_cast<uint8_t*>(impl); |
728 | size_t implSize = sizeof(BLInternalFontImpl); |
729 | uint32_t implTraits = impl->implTraits; |
730 | uint32_t memPoolData = impl->memPoolData; |
731 | |
732 | if (implTraits & BL_IMPL_TRAIT_EXTERNAL) { |
733 | implSize += sizeof(BLExternalImplPreface); |
734 | implBase -= sizeof(BLExternalImplPreface); |
735 | blImplDestroyExternal(impl); |
736 | } |
737 | |
738 | if (implTraits & BL_IMPL_TRAIT_FOREIGN) |
739 | return BL_SUCCESS; |
740 | else |
741 | return blRuntimeFreeImpl(implBase, implSize, memPoolData); |
742 | } |
743 | |
744 | static BL_INLINE BLResult blFontImplRelease(BLInternalFontImpl* impl) noexcept { |
745 | if (blAtomicFetchSub(&impl->refCount) != 1) |
746 | return BL_SUCCESS; |
747 | return blFontImplDelete(impl); |
748 | } |
749 | |
750 | // ============================================================================ |
751 | // [BLFont - Init / Reset] |
752 | // ============================================================================ |
753 | |
754 | BLResult blFontInit(BLFontCore* self) noexcept { |
755 | self->impl = &blNullFontImpl; |
756 | return BL_SUCCESS; |
757 | } |
758 | |
759 | BLResult blFontReset(BLFontCore* self) noexcept { |
760 | BLInternalFontImpl* selfI = blInternalCast(self->impl); |
761 | self->impl = &blNullFontImpl; |
762 | return blFontImplRelease(selfI); |
763 | } |
764 | |
765 | // ============================================================================ |
766 | // [BLFont - Assign] |
767 | // ============================================================================ |
768 | |
769 | BLResult blFontAssignMove(BLFontCore* self, BLFontCore* other) noexcept { |
770 | BLInternalFontImpl* selfI = blInternalCast(self->impl); |
771 | BLInternalFontImpl* otherI = blInternalCast(other->impl); |
772 | |
773 | self->impl = otherI; |
774 | other->impl = &blNullFontImpl; |
775 | |
776 | return blFontImplRelease(selfI); |
777 | } |
778 | |
779 | BLResult blFontAssignWeak(BLFontCore* self, const BLFontCore* other) noexcept { |
780 | BLInternalFontImpl* selfI = blInternalCast(self->impl); |
781 | BLInternalFontImpl* otherI = blInternalCast(other->impl); |
782 | |
783 | self->impl = blImplIncRef(otherI); |
784 | return blFontImplRelease(selfI); |
785 | } |
786 | |
787 | // ============================================================================ |
788 | // [BLFont - Equals] |
789 | // ============================================================================ |
790 | |
791 | bool blFontEquals(const BLFontCore* a, const BLFontCore* b) noexcept { |
792 | return a->impl == b->impl; |
793 | } |
794 | |
795 | // ============================================================================ |
796 | // [BLFont - Create] |
797 | // ============================================================================ |
798 | |
799 | BLResult blFontCreateFromFace(BLFontCore* self, const BLFontFaceCore* face, float size) noexcept { |
800 | if (blDownCast(face)->isNone()) |
801 | return blTraceError(BL_ERROR_NOT_INITIALIZED); |
802 | |
803 | BLInternalFontImpl* selfI = blInternalCast(self->impl); |
804 | if (selfI->refCount == 1) { |
805 | BLFontFaceImpl* oldFaceI = selfI->face.impl; |
806 | BLFontFaceImpl* newFaceI = face->impl; |
807 | |
808 | selfI->face.impl = blImplIncRef(newFaceI); |
809 | selfI->features.clear(); |
810 | selfI->variations.clear(); |
811 | selfI->weight = 0; |
812 | selfI->stretch = 0; |
813 | selfI->style = 0; |
814 | blFontImplCalcProperties(selfI, newFaceI, size); |
815 | |
816 | return blImplReleaseVirt(oldFaceI); |
817 | } |
818 | else { |
819 | BLInternalFontImpl* newI = blFontImplNew(face->impl, size); |
820 | if (BL_UNLIKELY(!newI)) |
821 | return blTraceError(BL_ERROR_OUT_OF_MEMORY); |
822 | |
823 | self->impl = newI; |
824 | return blFontImplRelease(selfI); |
825 | } |
826 | } |
827 | |
828 | // ============================================================================ |
829 | // [BLFont - Properties] |
830 | // ============================================================================ |
831 | |
832 | BLResult blFontGetMatrix(const BLFontCore* self, BLFontMatrix* out) noexcept { |
833 | *out = blDownCast(self)->matrix(); |
834 | return BL_SUCCESS; |
835 | } |
836 | |
837 | BLResult blFontGetMetrics(const BLFontCore* self, BLFontMetrics* out) noexcept { |
838 | *out = blDownCast(self)->metrics(); |
839 | return BL_SUCCESS; |
840 | } |
841 | |
842 | BLResult blFontGetDesignMetrics(const BLFontCore* self, BLFontDesignMetrics* out) noexcept { |
843 | *out = blDownCast(self)->designMetrics(); |
844 | return BL_SUCCESS; |
845 | } |
846 | |
847 | // ============================================================================ |
848 | // [BLFont - Shaping] |
849 | // ============================================================================ |
850 | |
851 | BLResult blFontShape(const BLFontCore* self, BLGlyphBufferCore* gb) noexcept { |
852 | BL_PROPAGATE(blFontMapTextToGlyphs(self, gb, nullptr)); |
853 | BL_PROPAGATE(blFontPositionGlyphs(self, gb, 0xFFFFFFFFu)); |
854 | |
855 | return BL_SUCCESS; |
856 | } |
857 | |
858 | BLResult blFontMapTextToGlyphs(const BLFontCore* self, BLGlyphBufferCore* gb, BLGlyphMappingState* stateOut) noexcept { |
859 | BLInternalGlyphBufferImpl* gbI = blInternalCast(gb->impl); |
860 | if (!gbI->size) |
861 | return BL_SUCCESS; |
862 | |
863 | if (BL_UNLIKELY(!(gbI->flags & BL_GLYPH_RUN_FLAG_UCS4_CONTENT))) |
864 | return blTraceError(BL_ERROR_INVALID_STATE); |
865 | |
866 | BLGlyphMappingState state; |
867 | if (!stateOut) |
868 | stateOut = &state; |
869 | |
870 | BLInternalFontFaceImpl* faceI = blInternalCast(self->impl->face.impl); |
871 | BL_PROPAGATE(faceI->funcs.mapTextToGlyphs(faceI, gbI->glyphItemData, gbI->size, stateOut)); |
872 | |
873 | gbI->flags = gbI->flags & ~BL_GLYPH_RUN_FLAG_UCS4_CONTENT; |
874 | if (stateOut->undefinedCount == 0) |
875 | gbI->flags |= BL_GLYPH_RUN_FLAG_UNDEFINED_GLYPHS; |
876 | return BL_SUCCESS; |
877 | } |
878 | |
879 | BLResult blFontPositionGlyphs(const BLFontCore* self, BLGlyphBufferCore* gb, uint32_t positioningFlags) noexcept { |
880 | BLInternalGlyphBufferImpl* gbI = blInternalCast(gb->impl); |
881 | if (!gbI->size) |
882 | return BL_SUCCESS; |
883 | |
884 | if (BL_UNLIKELY(gbI->flags & BL_GLYPH_RUN_FLAG_UCS4_CONTENT)) |
885 | return blTraceError(BL_ERROR_INVALID_STATE); |
886 | |
887 | BLInternalFontFaceImpl* faceI = blInternalCast(self->impl->face.impl); |
888 | if (!(gbI->flags & BL_GLYPH_BUFFER_GLYPH_ADVANCES)) { |
889 | BL_PROPAGATE(gbI->ensurePlacement()); |
890 | faceI->funcs.getGlyphAdvances(faceI, &gbI->glyphItemData->glyphId, sizeof(BLGlyphItem), gbI->placementData, gbI->size); |
891 | gbI->glyphRun.placementType = uint8_t(BL_GLYPH_PLACEMENT_TYPE_ADVANCE_OFFSET); |
892 | gbI->flags |= BL_GLYPH_BUFFER_GLYPH_ADVANCES; |
893 | } |
894 | |
895 | if (positioningFlags) { |
896 | faceI->funcs.applyKern(faceI, gbI->glyphItemData, gbI->placementData, gbI->size); |
897 | } |
898 | |
899 | return BL_SUCCESS; |
900 | } |
901 | |
902 | BLResult blFontApplyKerning(const BLFontCore* self, BLGlyphBufferCore* gb) noexcept { |
903 | BLInternalGlyphBufferImpl* gbI = blInternalCast(gb->impl); |
904 | if (!gbI->size) |
905 | return BL_SUCCESS; |
906 | |
907 | if (BL_UNLIKELY(!(gbI->placementData))) |
908 | return blTraceError(BL_ERROR_INVALID_STATE); |
909 | |
910 | BLInternalFontFaceImpl* faceI = blInternalCast(self->impl->face.impl); |
911 | return faceI->funcs.applyKern(faceI, gbI->glyphItemData, gbI->placementData, gbI->size); |
912 | } |
913 | |
914 | BLResult blFontApplyGSub(const BLFontCore* self, BLGlyphBufferCore* gb, size_t index, BLBitWord lookups) noexcept { |
915 | BLInternalFontFaceImpl* faceI = blInternalCast(self->impl->face.impl); |
916 | return faceI->funcs.applyGSub(faceI, static_cast<BLGlyphBuffer*>(gb), index, lookups); |
917 | } |
918 | |
919 | BLResult blFontApplyGPos(const BLFontCore* self, BLGlyphBufferCore* gb, size_t index, BLBitWord lookups) noexcept { |
920 | BLInternalGlyphBufferImpl* gbI = blInternalCast(gb->impl); |
921 | if (!gbI->size) |
922 | return BL_SUCCESS; |
923 | |
924 | if (BL_UNLIKELY(!(gbI->placementData))) |
925 | return blTraceError(BL_ERROR_INVALID_STATE); |
926 | |
927 | BLInternalFontFaceImpl* faceI = blInternalCast(self->impl->face.impl); |
928 | return faceI->funcs.applyGPos(faceI, static_cast<BLGlyphBuffer*>(gb), index, lookups); |
929 | } |
930 | |
931 | BLResult blFontGetTextMetrics(const BLFontCore* self, BLGlyphBufferCore* gb, BLTextMetrics* out) noexcept { |
932 | BLInternalFontImpl* selfI = blInternalCast(self->impl); |
933 | BLInternalGlyphBufferImpl* gbI = blInternalCast(gb->impl); |
934 | |
935 | out->reset(); |
936 | if (!(gbI->flags & BL_GLYPH_BUFFER_GLYPH_ADVANCES)) { |
937 | BL_PROPAGATE(blFontShape(self, gb)); |
938 | gbI = blInternalCast(gb->impl); |
939 | } |
940 | |
941 | size_t size = gbI->size; |
942 | if (!size) |
943 | return BL_SUCCESS; |
944 | |
945 | double advanceX = 0.0; |
946 | double advanceY = 0.0; |
947 | |
948 | const BLGlyphItem* glyphItemData = gbI->glyphItemData; |
949 | const BLGlyphPlacement* placementData = gbI->placementData; |
950 | |
951 | for (size_t i = 0; i < size; i++) { |
952 | advanceX += double(placementData[i].advance.x); |
953 | advanceY += double(placementData[i].advance.y); |
954 | } |
955 | |
956 | BLBoxI glyphBounds[2]; |
957 | BLGlyphId borderGlyphs[2] = { BLGlyphId(glyphItemData[0].glyphId), BLGlyphId(glyphItemData[size - 1].glyphId) }; |
958 | |
959 | BL_PROPAGATE(blFontGetGlyphBounds(self, borderGlyphs, intptr_t(sizeof(BLGlyphId)), glyphBounds, 2)); |
960 | out->advance.reset(advanceX, advanceY); |
961 | out->boundingBox.reset(glyphBounds[0].x0, 0.0, advanceX - placementData[size - 1].advance.x + glyphBounds[1].x1, 0.0); |
962 | |
963 | const BLFontMatrix& m = selfI->matrix; |
964 | out->advance *= BLPoint(m.m00, m.m11); |
965 | out->boundingBox *= BLPoint(m.m00, m.m11); |
966 | |
967 | return BL_SUCCESS; |
968 | } |
969 | |
970 | // ============================================================================ |
971 | // [BLFont - Low-Level API] |
972 | // ============================================================================ |
973 | |
974 | BLResult blFontGetGlyphBounds(const BLFontCore* self, const void* glyphIdData, intptr_t glyphIdAdvance, BLBoxI* out, size_t count) noexcept { |
975 | BLInternalFontFaceImpl* faceI = blInternalCast(self->impl->face.impl); |
976 | return faceI->funcs.getGlyphBounds(faceI, static_cast<const BLGlyphId*>(glyphIdData), glyphIdAdvance, out, count); |
977 | } |
978 | |
979 | BLResult blFontGetGlyphAdvances(const BLFontCore* self, const void* glyphIdData, intptr_t glyphIdAdvance, BLGlyphPlacement* out, size_t count) noexcept { |
980 | BLInternalFontFaceImpl* faceI = blInternalCast(self->impl->face.impl); |
981 | return faceI->funcs.getGlyphAdvances(faceI, static_cast<const BLGlyphId*>(glyphIdData), glyphIdAdvance, out, count); |
982 | } |
983 | |
984 | // ============================================================================ |
985 | // [BLFont - Glyph Outlines] |
986 | // ============================================================================ |
987 | |
988 | BLResult blFontGetGlyphOutlines(const BLFontCore* self, uint32_t glyphId, const BLMatrix2D* userMatrix, BLPathCore* out, BLPathSinkFunc sink, void* closure) noexcept { |
989 | BLMatrix2D finalMatrix; |
990 | const BLFontMatrix& fMat = self->impl->matrix; |
991 | |
992 | if (userMatrix) |
993 | blFontMatrixMultiply(&finalMatrix, &fMat, userMatrix); |
994 | else |
995 | finalMatrix.reset(fMat.m00, fMat.m01, fMat.m10, fMat.m11, 0.0, 0.0); |
996 | |
997 | const BLInternalFontFaceImpl* faceI = blInternalCast(self->impl->face.impl); |
998 | |
999 | BLMemBufferTmp<BL_FONT_GET_GLYPH_OUTLINE_BUFFER_SIZE> tmpBuffer; |
1000 | return faceI->funcs.decodeGlyph(faceI, glyphId, &finalMatrix, static_cast<BLPath*>(out), &tmpBuffer, sink, 0, closure); |
1001 | } |
1002 | |
1003 | BLResult blFontGetGlyphRunOutlines(const BLFontCore* self, const BLGlyphRun* glyphRun, const BLMatrix2D* userMatrix, BLPathCore* out, BLPathSinkFunc sink, void* closure) noexcept { |
1004 | if (!glyphRun->size) |
1005 | return BL_SUCCESS; |
1006 | |
1007 | BLMatrix2D finalMatrix; |
1008 | const BLFontMatrix& fMat = self->impl->matrix; |
1009 | |
1010 | if (userMatrix) { |
1011 | blFontMatrixMultiply(&finalMatrix, &fMat, userMatrix); |
1012 | } |
1013 | else { |
1014 | userMatrix = &blMatrix2DIdentity; |
1015 | finalMatrix.reset(fMat.m00, fMat.m01, fMat.m10, fMat.m11, 0.0, 0.0); |
1016 | } |
1017 | |
1018 | const BLInternalFontFaceImpl* faceI = blInternalCast(self->impl->face.impl); |
1019 | |
1020 | BLResult result = BL_SUCCESS; |
1021 | uint32_t placementType = glyphRun->placementType; |
1022 | |
1023 | BLMemBufferTmp<BL_FONT_GET_GLYPH_OUTLINE_BUFFER_SIZE> tmpBuffer; |
1024 | BLGlyphRunIterator it(*glyphRun); |
1025 | |
1026 | auto decodeFunc = faceI->funcs.decodeGlyph; |
1027 | if (it.hasPlacement() && placementType != BL_GLYPH_PLACEMENT_TYPE_NONE) { |
1028 | BLMatrix2D offsetMatrix(1.0, 0.0, 0.0, 1.0, finalMatrix.m20, finalMatrix.m21); |
1029 | |
1030 | switch (placementType) { |
1031 | case BL_GLYPH_PLACEMENT_TYPE_ADVANCE_OFFSET: |
1032 | case BL_GLYPH_PLACEMENT_TYPE_DESIGN_UNITS: |
1033 | offsetMatrix.m00 = finalMatrix.m00; |
1034 | offsetMatrix.m01 = finalMatrix.m01; |
1035 | offsetMatrix.m10 = finalMatrix.m10; |
1036 | offsetMatrix.m11 = finalMatrix.m11; |
1037 | break; |
1038 | |
1039 | case BL_GLYPH_PLACEMENT_TYPE_USER_UNITS: |
1040 | offsetMatrix.m00 = userMatrix->m00; |
1041 | offsetMatrix.m01 = userMatrix->m01; |
1042 | offsetMatrix.m10 = userMatrix->m10; |
1043 | offsetMatrix.m11 = userMatrix->m11; |
1044 | break; |
1045 | } |
1046 | |
1047 | if (placementType == BL_GLYPH_PLACEMENT_TYPE_ADVANCE_OFFSET) { |
1048 | double ox = finalMatrix.m20; |
1049 | double oy = finalMatrix.m21; |
1050 | double px; |
1051 | double py; |
1052 | |
1053 | while (!it.atEnd()) { |
1054 | const BLGlyphPlacement& pos = it.placement<BLGlyphPlacement>(); |
1055 | |
1056 | px = pos.placement.x; |
1057 | py = pos.placement.y; |
1058 | finalMatrix.m20 = px * offsetMatrix.m00 + py * offsetMatrix.m10 + ox; |
1059 | finalMatrix.m21 = px * offsetMatrix.m01 + py * offsetMatrix.m11 + oy; |
1060 | |
1061 | result = decodeFunc(faceI, it.glyphId(), &finalMatrix, static_cast<BLPath*>(out), &tmpBuffer, sink, it.index, closure); |
1062 | if (BL_UNLIKELY(result != BL_SUCCESS)) |
1063 | break; |
1064 | |
1065 | px = pos.advance.x; |
1066 | py = pos.advance.y; |
1067 | ox += px * offsetMatrix.m00 + py * offsetMatrix.m10; |
1068 | oy += px * offsetMatrix.m01 + py * offsetMatrix.m11; |
1069 | |
1070 | it.advance(); |
1071 | } |
1072 | } |
1073 | else { |
1074 | while (!it.atEnd()) { |
1075 | const BLPoint& placement = it.placement<BLPoint>(); |
1076 | finalMatrix.m20 = placement.x * offsetMatrix.m00 + placement.y * offsetMatrix.m10 + offsetMatrix.m20; |
1077 | finalMatrix.m21 = placement.x * offsetMatrix.m01 + placement.y * offsetMatrix.m11 + offsetMatrix.m21; |
1078 | |
1079 | result = decodeFunc(faceI, it.glyphId(), &finalMatrix, static_cast<BLPath*>(out), &tmpBuffer, sink, it.index, closure); |
1080 | if (BL_UNLIKELY(result != BL_SUCCESS)) |
1081 | break; |
1082 | |
1083 | it.advance(); |
1084 | } |
1085 | } |
1086 | } |
1087 | else { |
1088 | while (!it.atEnd()) { |
1089 | result = decodeFunc(faceI, it.glyphId(), &finalMatrix, static_cast<BLPath*>(out), &tmpBuffer, sink, it.index, closure); |
1090 | if (BL_UNLIKELY(result != BL_SUCCESS)) |
1091 | break; |
1092 | it.advance(); |
1093 | } |
1094 | } |
1095 | |
1096 | return result; |
1097 | } |
1098 | |
1099 | // ============================================================================ |
1100 | // [Runtime Init] |
1101 | // ============================================================================ |
1102 | |
1103 | void blFontRtInit(BLRuntimeContext* rt) noexcept { |
1104 | BL_UNUSED(rt); |
1105 | |
1106 | // Initialize BLFontData virtual functions. |
1107 | blNullFontDataVirt.destroy = blNullFontDataImplDestroy; |
1108 | blNullFontDataVirt.listTags = blNullFontDataImplListTags; |
1109 | blNullFontDataVirt.queryTables = blNullFontDataImplQueryTables; |
1110 | |
1111 | blMemFontDataVirt.destroy = blMemFontDataImplDestroy; |
1112 | blMemFontDataVirt.listTags = blMemFontDataImplListTags; |
1113 | blMemFontDataVirt.queryTables = blMemFontDataImplQueryTables; |
1114 | |
1115 | // Initialize BLFontData built-in null instance. |
1116 | BLFontDataImpl* fontDataI = &blNullFontDataImpl; |
1117 | fontDataI->implType = uint8_t(BL_IMPL_TYPE_FONT_DATA); |
1118 | fontDataI->implTraits = uint8_t(BL_IMPL_TRAIT_NULL | BL_IMPL_TRAIT_VIRT); |
1119 | fontDataI->virt = &blNullFontDataVirt; |
1120 | blAssignBuiltInNull(fontDataI); |
1121 | |
1122 | // Initialize BLFontLoader virtual functions. |
1123 | blNullFontLoaderVirt.destroy = blNullFontLoaderImplDestroy; |
1124 | blNullFontLoaderVirt.dataByFaceIndex = blNullFontLoaderImplDataByFaceIndex; |
1125 | |
1126 | blMemFontLoaderVirt.destroy = blMemFontLoaderImplFakeDestroy; |
1127 | blMemFontLoaderVirt.dataByFaceIndex = blMemFontLoaderImplDataByFaceIndex; |
1128 | |
1129 | // Initialize BLFontLoader built-in null instance. |
1130 | BLFontLoaderImpl* fontLoaderI = &blNullFontLoaderImpl; |
1131 | fontLoaderI->implType = uint8_t(BL_IMPL_TYPE_FONT_LOADER); |
1132 | fontLoaderI->implTraits = uint8_t(BL_IMPL_TRAIT_NULL | BL_IMPL_TRAIT_VIRT); |
1133 | fontLoaderI->virt = &blNullFontLoaderVirt; |
1134 | blAssignBuiltInNull(fontLoaderI); |
1135 | |
1136 | // Initialize BLFontFace virtual functions. |
1137 | blNullFontFaceVirt.destroy = blNullFontFaceImplDestroy; |
1138 | |
1139 | blNullFontFaceFuncs.mapTextToGlyphs = blNullFontFaceMapTextToGlyphs; |
1140 | blNullFontFaceFuncs.getGlyphBounds = blNullFontFaceGetGlyphBounds; |
1141 | blNullFontFaceFuncs.getGlyphAdvances = blNullFontFaceGetGlyphAdvances; |
1142 | blNullFontFaceFuncs.applyKern = blNullFontFaceApplyKern; |
1143 | blNullFontFaceFuncs.applyGSub = blNullFontFaceApplyGSub; |
1144 | blNullFontFaceFuncs.applyGPos = blNullFontFaceApplyGPos; |
1145 | blNullFontFaceFuncs.positionGlyphs = blNullFontFacePositionGlyphs; |
1146 | blNullFontFaceFuncs.decodeGlyph = blNullFontFaceDecodeGlyph; |
1147 | |
1148 | // Initialize BLFontFace built-in null instance. |
1149 | BLInternalFontFaceImpl* fontFaceI = &blNullFontFaceImpl; |
1150 | fontFaceI->implType = uint8_t(BL_IMPL_TYPE_FONT_FACE); |
1151 | fontFaceI->implTraits = uint8_t(BL_IMPL_TRAIT_NULL | BL_IMPL_TRAIT_VIRT); |
1152 | fontFaceI->virt = &blNullFontFaceVirt; |
1153 | fontFaceI->data.impl = fontDataI; |
1154 | fontFaceI->loader.impl = fontLoaderI; |
1155 | blCallCtor(fontFaceI->fullName); |
1156 | blCallCtor(fontFaceI->familyName); |
1157 | blCallCtor(fontFaceI->subfamilyName); |
1158 | blCallCtor(fontFaceI->postScriptName); |
1159 | fontFaceI->funcs = blNullFontFaceFuncs; |
1160 | blAssignBuiltInNull(fontFaceI); |
1161 | |
1162 | // Initialize BLFont built-in null instance. |
1163 | BLInternalFontImpl* fontI = &blNullFontImpl; |
1164 | fontI->implType = uint8_t(BL_IMPL_TYPE_FONT); |
1165 | fontI->implTraits = uint8_t(BL_IMPL_TRAIT_NULL); |
1166 | fontI->face.impl = fontFaceI; |
1167 | blCallCtor(fontI->features); |
1168 | blCallCtor(fontI->variations); |
1169 | blAssignBuiltInNull(fontI); |
1170 | |
1171 | // Initialize implementations. |
1172 | blOTFaceImplRtInit(rt); |
1173 | } |
1174 | |