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
26BLInternalFontFaceFuncs blNullFontFaceFuncs;
27
28static BLWrap<BLInternalFontImpl> blNullFontImpl;
29static BLWrap<BLInternalFontFaceImpl> blNullFontFaceImpl;
30static BLWrap<BLFontDataImpl> blNullFontDataImpl;
31static BLWrap<BLFontLoaderImpl> blNullFontLoaderImpl;
32
33static BLFontFaceVirt blNullFontFaceVirt;
34static BLAtomicUInt64Generator blFontFaceIdGenerator;
35
36// ============================================================================
37// [BLFontData / BLFontLoader - Null]
38// ============================================================================
39
40BL_DIAGNOSTIC_PUSH(BL_DIAGNOSTIC_NO_UNUSED_PARAMETERS)
41
42static BLFontDataVirt blNullFontDataVirt;
43static BLFontLoaderVirt blNullFontLoaderVirt;
44
45static BLResult BL_CDECL blNullFontDataImplDestroy(BLFontDataImpl* impl) noexcept {
46 return BL_SUCCESS;
47}
48
49static BLResult BL_CDECL blNullFontDataImplListTags(const BLFontDataImpl* impl, BLArrayCore* out) noexcept {
50 return blArrayClear(out);
51}
52
53static 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
59static BLResult BL_CDECL blNullFontLoaderImplDestroy(BLFontLoaderImpl* impl) noexcept {
60 return BL_SUCCESS;
61}
62
63static BLFontDataImpl* BL_CDECL blNullFontLoaderImplDataByFaceIndex(BLFontLoaderImpl* impl, uint32_t faceIndex) noexcept {
64 return &blNullFontDataImpl;
65}
66
67BL_DIAGNOSTIC_POP
68
69// ============================================================================
70// [BLFontData / BLFontLoader - Utilities]
71// ============================================================================
72
73static 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
99static BLFontDataVirt blMemFontDataVirt;
100static BLFontLoaderVirt blMemFontLoaderVirt;
101
102struct BLMemFontLoaderImpl : public BLFontLoaderImpl {
103 BLArray<BLFontData> dataArray;
104 volatile size_t backRefCount;
105};
106
107struct BLMemFontDataImpl : public BLFontDataImpl {
108 BLMemFontLoaderImpl* loaderI;
109};
110
111// Destroys `BLMemFontLoaderImpl` - this is a real destructor that would
112// free the impl data.
113static 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.
132static BLResult BL_CDECL blMemFontLoaderImplFakeDestroy(BLFontLoaderImpl* impl_) noexcept {
133 BLMemFontLoaderImpl* impl = static_cast<BLMemFontLoaderImpl*>(impl_);
134 return impl->dataArray.reset();
135}
136
137static 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
144static 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
157static 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
181static 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
232BLResult blFontDataInit(BLFontDataCore* self) noexcept {
233 self->impl = &blNullFontDataImpl;
234 return BL_SUCCESS;
235}
236
237BLResult 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
251BLResult blFontDataReset(BLFontDataCore* self) noexcept {
252 BLFontDataImpl* selfI = self->impl;
253
254 self->impl = &blNullFontDataImpl;
255 return blImplReleaseVirt(selfI);
256}
257
258BLResult 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
268BLResult 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
276BLResult 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
288bool blFontDataEquals(const BLFontDataCore* a, const BLFontDataCore* b) noexcept {
289 return a->impl == b->impl;
290}
291
292BLResult blFontDataListTags(const BLFontDataCore* self, BLArrayCore* dst) noexcept {
293 BLFontDataImpl* selfI = self->impl;
294 return selfI->virt->listTags(selfI, dst);
295}
296
297size_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
306BLResult blFontLoaderInit(BLFontLoaderCore* self) noexcept {
307 self->impl = &blNullFontLoaderImpl;
308 return BL_SUCCESS;
309}
310
311BLResult 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
321BLResult 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
331BLResult 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
343bool 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>()`.
353static void BL_CDECL blDestroyArrayImpl(void* impl, void* arrayI) noexcept {
354 BL_UNUSED(impl);
355 blArrayImplRelease(static_cast<BLArrayImpl*>(arrayI));
356}
357
358BLResult 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
368BLResult 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
377BLResult 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 headerTag = 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* header = 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 ttcHeaderSize = 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
493BL_DIAGNOSTIC_PUSH(BL_DIAGNOSTIC_NO_UNUSED_PARAMETERS)
494
495static BLResult BL_CDECL blNullFontFaceImplDestroy(BLFontFaceImpl* impl) noexcept {
496 return BL_SUCCESS;
497}
498
499static 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
509static 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
519static 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
529static 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
538static 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
547static 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
556static 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
565static 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
576BL_DIAGNOSTIC_POP
577
578// ============================================================================
579// [BLFontFace - Init / Reset]
580// ============================================================================
581
582BLResult blFontFaceInit(BLFontFaceCore* self) noexcept {
583 self->impl = &blNullFontFaceImpl;
584 return BL_SUCCESS;
585}
586
587BLResult 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
597BLResult 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
607BLResult 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
619bool blFontFaceEquals(const BLFontFaceCore* a, const BLFontFaceCore* b) noexcept {
620 return a->impl == b->impl;
621}
622
623// ============================================================================
624// [BLFontFace - Create]
625// ============================================================================
626
627BLResult 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
633BLResult 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
657BLResult blFontFaceGetFaceInfo(const BLFontFaceCore* self, BLFontFaceInfo* out) noexcept {
658 *out = blDownCast(self)->faceInfo();
659 return BL_SUCCESS;
660}
661
662BLResult blFontFaceGetDesignMetrics(const BLFontFaceCore* self, BLFontDesignMetrics* out) noexcept {
663 *out = blDownCast(self)->designMetrics();
664 return BL_SUCCESS;
665}
666
667BLResult blFontFaceGetUnicodeCoverage(const BLFontFaceCore* self, BLFontUnicodeCoverage* out) noexcept {
668 *out = blDownCast(self)->unicodeCoverage();
669 return BL_SUCCESS;
670}
671
672// ============================================================================
673// [BLFont - Utilities]
674// ============================================================================
675
676static 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
700static 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.
720BLResult 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
744static 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
754BLResult blFontInit(BLFontCore* self) noexcept {
755 self->impl = &blNullFontImpl;
756 return BL_SUCCESS;
757}
758
759BLResult 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
769BLResult 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
779BLResult 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
791bool blFontEquals(const BLFontCore* a, const BLFontCore* b) noexcept {
792 return a->impl == b->impl;
793}
794
795// ============================================================================
796// [BLFont - Create]
797// ============================================================================
798
799BLResult 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
832BLResult blFontGetMatrix(const BLFontCore* self, BLFontMatrix* out) noexcept {
833 *out = blDownCast(self)->matrix();
834 return BL_SUCCESS;
835}
836
837BLResult blFontGetMetrics(const BLFontCore* self, BLFontMetrics* out) noexcept {
838 *out = blDownCast(self)->metrics();
839 return BL_SUCCESS;
840}
841
842BLResult blFontGetDesignMetrics(const BLFontCore* self, BLFontDesignMetrics* out) noexcept {
843 *out = blDownCast(self)->designMetrics();
844 return BL_SUCCESS;
845}
846
847// ============================================================================
848// [BLFont - Shaping]
849// ============================================================================
850
851BLResult 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
858BLResult 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
879BLResult 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
902BLResult 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
914BLResult 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
919BLResult 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
931BLResult 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
974BLResult 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
979BLResult 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
988BLResult 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
1003BLResult 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
1103void 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