summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-10-29 14:00:41 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-10-29 14:00:41 +0300
commitd98604ca3bd3f3986a42c4e9e1c4228089e39024 (patch)
tree9d3fdd5115d86300027476882417fb5127278963
parentb99c6e693b8ade1fa117f4cb54105366a7768da0 (diff)
FontPack: Loading fonts from TTC files
-rw-r--r--src/fontpack.c80
-rw-r--r--src/fontpack.h1
-rw-r--r--src/gmdocument.h4
-rw-r--r--src/ui/text.c131
4 files changed, 63 insertions, 153 deletions
diff --git a/src/fontpack.c b/src/fontpack.c
index 96d973f7..ec62702f 100644
--- a/src/fontpack.c
+++ b/src/fontpack.c
@@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
31#include <the_Foundation/fileinfo.h> 31#include <the_Foundation/fileinfo.h>
32#include <the_Foundation/path.h> 32#include <the_Foundation/path.h>
33#include <the_Foundation/ptrarray.h> 33#include <the_Foundation/ptrarray.h>
34#include <the_Foundation/regexp.h>
34#include <the_Foundation/string.h> 35#include <the_Foundation/string.h>
35#include <the_Foundation/stringlist.h> 36#include <the_Foundation/stringlist.h>
36#include <the_Foundation/toml.h> 37#include <the_Foundation/toml.h>
@@ -65,6 +66,7 @@ iDefineObjectConstruction(FontFile)
65 66
66void init_FontFile(iFontFile *d) { 67void init_FontFile(iFontFile *d) {
67 init_String(&d->id); 68 init_String(&d->id);
69 d->colIndex = 0;
68 d->style = regular_FontStyle; 70 d->style = regular_FontStyle;
69 init_Block(&d->sourceData, 0); 71 init_Block(&d->sourceData, 0);
70 iZap(d->stbInfo); 72 iZap(d->stbInfo);
@@ -77,15 +79,17 @@ void init_FontFile(iFontFile *d) {
77 79
78static void load_FontFile_(iFontFile *d, const iBlock *data) { 80static void load_FontFile_(iFontFile *d, const iBlock *data) {
79 set_Block(&d->sourceData, data); 81 set_Block(&d->sourceData, data);
80 stbtt_InitFont(&d->stbInfo, constData_Block(&d->sourceData), 0); 82 const size_t offset = stbtt_GetFontOffsetForIndex(constData_Block(&d->sourceData),
83 d->colIndex);
84 stbtt_InitFont(&d->stbInfo, constData_Block(data), offset);
81 /* Basic metrics. */ 85 /* Basic metrics. */
82 stbtt_GetFontVMetrics(&d->stbInfo, &d->ascent, &d->descent, NULL); 86 stbtt_GetFontVMetrics(&d->stbInfo, &d->ascent, &d->descent, NULL);
83 stbtt_GetCodepointHMetrics(&d->stbInfo, 'M', &d->emAdvance, NULL); 87 stbtt_GetCodepointHMetrics(&d->stbInfo, 'M', &d->emAdvance, NULL);
84#if defined(LAGRANGE_ENABLE_HARFBUZZ) 88#if defined(LAGRANGE_ENABLE_HARFBUZZ)
85 /* HarfBuzz will read the font data. */ 89 /* HarfBuzz will read the font data. */
86 d->hbBlob = hb_blob_create(constData_Block(&d->sourceData), size_Block(&d->sourceData), 90 d->hbBlob = hb_blob_create(constData_Block(data), size_Block(&d->sourceData),
87 HB_MEMORY_MODE_READONLY, NULL, NULL); 91 HB_MEMORY_MODE_READONLY, NULL, NULL);
88 d->hbFace = hb_face_create(d->hbBlob, 0); 92 d->hbFace = hb_face_create(d->hbBlob, d->colIndex);
89 d->hbFont = hb_font_create(d->hbFace); 93 d->hbFont = hb_font_create(d->hbFace);
90#endif 94#endif
91} 95}
@@ -173,6 +177,7 @@ struct Impl_Fonts {
173 iPtrArray packs; 177 iPtrArray packs;
174 iObjectList *files; 178 iObjectList *files;
175 iPtrArray specOrder; /* specs sorted by priority */ 179 iPtrArray specOrder; /* specs sorted by priority */
180 iRegExp *indexPattern; /* collection index filename suffix */
176}; 181};
177 182
178static iFonts fonts_; 183static iFonts fonts_;
@@ -371,22 +376,40 @@ void handleIniKeyValue_FontPack_(void *context, const iString *table, const iStr
371 else if (value->type == string_TomlType) { 376 else if (value->type == string_TomlType) {
372 iForIndices(i, styles_) { 377 iForIndices(i, styles_) {
373 if (!cmp_String(key, styles_[i]) && !d->loadSpec->styles[i]) { 378 if (!cmp_String(key, styles_[i]) && !d->loadSpec->styles[i]) {
379 iBeginCollect();
374 iFontFile *ff = NULL; 380 iFontFile *ff = NULL;
375 iString *fontFileId = concat_Path(d->loadPath, value->value.string); 381 iString *cleanPath = collect_String(copy_String(value->value.string));
376 if (!(ff = findFile_Fonts_(&fonts_, fontFileId))) { 382 int colIndex = 0;
377 iBlock *data = readFile_FontPack_(d, value->value.string); 383 /* Remove the collection index from the path. */ {
378 if (data) { 384 iRegExpMatch m;
379 ff = new_FontFile(); 385 init_RegExpMatch(&m);
380 set_String(&ff->id, fontFileId); 386 if (matchString_RegExp(fonts_.indexPattern, cleanPath, &m)) {
381 load_FontFile_(ff, data); 387 colIndex = toInt_String(collect_String(captured_RegExpMatch(&m, 1)));
382 pushBack_ObjectList(fonts_.files, ff); /* centralized ownership */ 388 removeEnd_String(cleanPath, size_Range(&m.range));
383 iRelease(ff);
384 delete_Block(data);
385// printf("[FontPack] loaded file: %s\n", cstr_String(fontFileId));
386 } 389 }
387 } 390 }
391 iString *fontFileId = concat_Path(d->loadPath, cleanPath);
392 /* FontFiles share source data blocks. The entire FontFiles can be reused, too,
393 if have the same collection index is in use. */
394 iBlock *data = NULL;
395 ff = findFile_Fonts_(&fonts_, fontFileId);
396 if (ff) {
397 data = &ff->sourceData;
398 }
399 if (!ff || ff->colIndex != colIndex) {
400 if (!data) {
401 data = collect_Block(readFile_FontPack_(d, cleanPath));
402 }
403 ff = new_FontFile();
404 set_String(&ff->id, fontFileId);
405 ff->colIndex = colIndex;
406 load_FontFile_(ff, data);
407 pushBack_ObjectList(fonts_.files, ff); /* centralized ownership */
408 iRelease(ff);
409 }
388 d->loadSpec->styles[i] = ref_Object(ff); 410 d->loadSpec->styles[i] = ref_Object(ff);
389 delete_String(fontFileId); 411 delete_String(fontFileId);
412 iEndCollect();
390 break; 413 break;
391 } 414 }
392 } 415 }
@@ -528,6 +551,7 @@ static const iString *userFontsDirectory_Fonts_(const iFonts *d) {
528 551
529void init_Fonts(const char *userDir) { 552void init_Fonts(const char *userDir) {
530 iFonts *d = &fonts_; 553 iFonts *d = &fonts_;
554 d->indexPattern = new_RegExp(":([0-9]+)$", 0);
531 initCStr_String(&d->userDir, userDir); 555 initCStr_String(&d->userDir, userDir);
532 const iString *userFontsDir = userFontsDirectory_Fonts_(d); 556 const iString *userFontsDir = userFontsDirectory_Fonts_(d);
533 makeDirs_Path(userFontsDir); 557 makeDirs_Path(userFontsDir);
@@ -659,6 +683,7 @@ void deinit_Fonts(void) {
659 deinit_PtrArray(&d->specOrder); 683 deinit_PtrArray(&d->specOrder);
660 deinit_PtrArray(&d->packs); 684 deinit_PtrArray(&d->packs);
661 iRelease(d->files); 685 iRelease(d->files);
686 iRelease(d->indexPattern);
662 deinit_String(&d->userDir); 687 deinit_String(&d->userDir);
663} 688}
664 689
@@ -706,18 +731,27 @@ iString *infoText_FontPack(const iFontPack *d) {
706 const iFontSpec *spec = i.ptr; 731 const iFontSpec *spec = i.ptr;
707 pushBack_StringList(names, &spec->name); 732 pushBack_StringList(names, &spec->name);
708 iForIndices(j, spec->styles) { 733 iForIndices(j, spec->styles) {
709 insert_PtrSet(uniqueFiles, spec->styles[j]); 734 insert_PtrSet(uniqueFiles, spec->styles[j]->sourceData.i);
710 } 735 }
711 } 736 }
712 iConstForEach(PtrSet, j, uniqueFiles) { 737 iConstForEach(PtrSet, j, uniqueFiles) {
713 sizeInBytes += size_Block(&((const iFontFile *) *j.value)->sourceData); 738 sizeInBytes += ((const iBlockData *) *j.value)->size;
714 } 739 }
715 appendFormat_String(str, "%.1f ${mb} (%s) \u2014 %s\n", 740 appendFormat_String(str, "%.1f ${mb} ", sizeInBytes / 1.0e6);
716 sizeInBytes / 1.0e6, 741 if (size_PtrSet(uniqueFiles) > 1 || size_StringList(names) > 1) {
717 formatCStrs_Lang("num.files.n", size_PtrSet(uniqueFiles)), 742 appendFormat_String(str, "(");
718// formatCStrs_Lang("num.fonts.n", size_StringList(names)), 743 if (size_PtrSet(uniqueFiles) > 1) {
719 cstrCollect_String(joinCStr_StringList(names, ", ")), 744 appendCStr_String(str, formatCStrs_Lang("num.files.n", size_PtrSet(uniqueFiles)));
720 d->version); 745 }
746 if (size_StringList(names) > 1) {
747 if (!endsWith_String(str, "(")) {
748 appendCStr_String(str, ", ");
749 }
750 appendCStr_String(str, formatCStrs_Lang("num.fonts.n", size_StringList(names)));
751 }
752 appendFormat_String(str, ")");
753 }
754 appendFormat_String(str, " \u2014 %s\n", cstrCollect_String(joinCStr_StringList(names, ", ")));
721 if (isInstalled && installedVersion != d->version) { 755 if (isInstalled && installedVersion != d->version) {
722 appendCStr_String(str, format_Lang("${fontpack.meta.version}\n", d->version)); 756 appendCStr_String(str, format_Lang("${fontpack.meta.version}\n", d->version));
723 } 757 }
diff --git a/src/fontpack.h b/src/fontpack.h
index d86de945..aa6f2b9f 100644
--- a/src/fontpack.h
+++ b/src/fontpack.h
@@ -78,6 +78,7 @@ iDeclareObjectConstruction(FontFile)
78struct Impl_FontFile { 78struct Impl_FontFile {
79 iObject object; /* reference-counted */ 79 iObject object; /* reference-counted */
80 iString id; /* for detecting when the same file is used in many places */ 80 iString id; /* for detecting when the same file is used in many places */
81 int colIndex;
81 enum iFontStyle style; 82 enum iFontStyle style;
82 iBlock sourceData; 83 iBlock sourceData;
83 stbtt_fontinfo stbInfo; 84 stbtt_fontinfo stbInfo;
diff --git a/src/gmdocument.h b/src/gmdocument.h
index 0c24302f..444520c6 100644
--- a/src/gmdocument.h
+++ b/src/gmdocument.h
@@ -139,9 +139,9 @@ struct Impl_GmRun {
139 uint32_t isRTL : 1; 139 uint32_t isRTL : 1;
140 uint32_t color : 7; /* see max_ColorId */ 140 uint32_t color : 7; /* see max_ColorId */
141 141
142 uint32_t font : 13; 142 uint32_t font : 14;
143 uint32_t mediaType : 3; /* note: max_MediaType means preformatted block */ 143 uint32_t mediaType : 3; /* note: max_MediaType means preformatted block */
144 uint32_t mediaId : 12; /* zero if not an image */ 144 uint32_t mediaId : 11; /* zero if not an image */
145 uint32_t lineType : 3; 145 uint32_t lineType : 3;
146 uint32_t isLede : 1; 146 uint32_t isLede : 1;
147 }; 147 };
diff --git a/src/ui/text.c b/src/ui/text.c
index 436ec208..09c01d46 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -318,134 +318,6 @@ static const iFontSpec *tryFindSpec_(enum iPrefsString ps, const char *fallback)
318} 318}
319 319
320static void initFonts_Text_(iText *d) { 320static void initFonts_Text_(iText *d) {
321#if 0
322 const iBlock *regularFont = &fontNunitoRegular_Embedded;
323 const iBlock *boldFont = &fontNunitoBold_Embedded;
324 const iBlock *italicFont = &fontNunitoLightItalic_Embedded;
325 const iBlock *h12Font = &fontNunitoExtraBold_Embedded;
326 const iBlock *h3Font = &fontNunitoRegular_Embedded;
327 const iBlock *lightFont = &fontNunitoExtraLight_Embedded;
328 float scaling = 1.0f; /* glyph scaling (<=1.0), for increasing line spacing */
329 float italicScaling = 1.0f;
330 float lightScaling = 1.0f;
331 float h123Scaling = 1.0f; /* glyph scaling (<=1.0), for increasing line spacing */
332 if (d->contentFont == firaSans_TextFont) {
333 regularFont = &fontFiraSansRegular_Embedded;
334 boldFont = &fontFiraSansSemiBold_Embedded;
335 lightFont = &fontFiraSansLight_Embedded;
336 italicFont = &fontFiraSansItalic_Embedded;
337 scaling = italicScaling = lightScaling = 0.85f;
338 }
339 else if (d->contentFont == tinos_TextFont) {
340 regularFont = &fontTinosRegular_Embedded;
341 boldFont = &fontTinosBold_Embedded;
342 lightFont = &fontLiterataExtraLightopsz18_Embedded;
343 italicFont = &fontTinosItalic_Embedded;
344 scaling = italicScaling = 0.85f;
345 }
346 else if (d->contentFont == literata_TextFont) {
347 regularFont = &fontLiterataRegularopsz14_Embedded;
348 boldFont = &fontLiterataBoldopsz36_Embedded;
349 italicFont = &fontLiterataLightItalicopsz10_Embedded;
350 lightFont = &fontLiterataExtraLightopsz18_Embedded;
351 }
352 else if (d->contentFont == sourceSans3_TextFont) {
353 regularFont = &fontSourceSans3Regular_Embedded;
354 boldFont = &fontSourceSans3Semibold_Embedded;
355 italicFont = &fontSourceSans3It_Embedded;
356 lightFont = &fontSourceSans3ExtraLight_Embedded;
357 }
358 else if (d->contentFont == iosevka_TextFont) {
359 regularFont = &fontIosevkaTermExtended_Embedded;
360 boldFont = &fontIosevkaTermExtended_Embedded;
361 italicFont = &fontIosevkaTermExtended_Embedded;
362 lightFont = &fontIosevkaTermExtended_Embedded;
363 scaling = italicScaling = lightScaling = 0.866f;
364 }
365 if (d->headingFont == firaSans_TextFont) {
366 h12Font = &fontFiraSansBold_Embedded;
367 h3Font = &fontFiraSansRegular_Embedded;
368 h123Scaling = 0.85f;
369 }
370 else if (d->headingFont == tinos_TextFont) {
371 h12Font = &fontTinosBold_Embedded;
372 h3Font = &fontTinosRegular_Embedded;
373 h123Scaling = 0.85f;
374 }
375 else if (d->headingFont == literata_TextFont) {
376 h12Font = &fontLiterataBoldopsz36_Embedded;
377 h3Font = &fontLiterataRegularopsz14_Embedded;
378 }
379 else if (d->headingFont == sourceSans3_TextFont) {
380 h12Font = &fontSourceSans3Bold_Embedded;
381 h3Font = &fontSourceSans3Regular_Embedded;
382 }
383 else if (d->headingFont == iosevka_TextFont) {
384 h12Font = &fontIosevkaTermExtended_Embedded;
385 h3Font = &fontIosevkaTermExtended_Embedded;
386 }
387 const struct {
388 const iFontFile *fontFile;
389 int size; /* pixels */
390// float scaling;
391 enum iFontSize sizeId;
392 /* UI sizes: 1.0, 1.125, 1.333, 1.666 */
393 /* Content sizes: smallmono, mono, 1.0, 1.2, 1.333, 1.666, 2.0 */
394 } fontData[max_FontId] = {
395 /* UI fonts: normal weight */
396 { &fontSourceSans3Regular_Embedded, uiSize, 1.0f, uiNormal_FontSize },
397 { &fontSourceSans3Regular_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize },
398 { &fontSourceSans3Regular_Embedded, uiSize * 1.333f, 1.0f, uiBig_FontSize },
399 { &fontSourceSans3Regular_Embedded, uiSize * 1.666f, 1.0f, uiLarge_FontSize },
400 { &fontSourceSans3Semibold_Embedded, uiSize * 0.800f, 1.0f, uiTiny_FontSize },
401 { &fontSourceSans3Regular_Embedded, uiSize * 0.900f, 1.0f, uiSmall_FontSize },
402 /* UI fonts: bold weight */
403 { &fontSourceSans3Bold_Embedded, uiSize, 1.0f, uiNormal_FontSize },
404 { &fontSourceSans3Bold_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize },
405 { &fontSourceSans3Bold_Embedded, uiSize * 1.333f, 1.0f, uiBig_FontSize },
406 { &fontSourceSans3Bold_Embedded, uiSize * 1.666f, 1.0f, uiLarge_FontSize },
407 /* content fonts */
408 { regularFont, textSize, scaling, contentRegular_FontSize },
409 { boldFont, textSize, scaling, contentRegular_FontSize },
410 { italicFont, textSize, italicScaling,contentRegular_FontSize },
411 { regularFont, textSize * 1.200f, scaling, contentMedium_FontSize },
412 { h3Font, textSize * 1.333f, h123Scaling, contentBig_FontSize },
413 { h12Font, textSize * 1.666f, h123Scaling, contentLarge_FontSize },
414 { lightFont, textSize * 1.666f, lightScaling, contentLarge_FontSize },
415 { h12Font, textSize * 2.000f, h123Scaling, contentHuge_FontSize },
416 { &fontIosevkaTermExtended_Embedded, smallMonoSize, 1.0f, contentMonoSmall_FontSize },
417 { &fontIosevkaTermExtended_Embedded, monoSize, 1.0f, contentMono_FontSize },
418 /* extra content fonts */
419 { &fontSourceSans3Regular_Embedded, textSize, scaling, contentRegular_FontSize },
420 { &fontSourceSans3Regular_Embedded, textSize * 0.80f, scaling, contentRegular_FontSize },
421 /* symbols and scripts */
422#define DEFINE_FONT_SET(data, glyphScale) \
423 { (data), uiSize * 0.800f, glyphScale, uiTiny_FontSize }, \
424 { (data), uiSize * 0.900f, glyphScale, uiSmall_FontSize }, \
425 { (data), uiSize, glyphScale, uiNormal_FontSize }, \
426 { (data), uiSize * 1.125f, glyphScale, uiMedium_FontSize }, \
427 { (data), uiSize * 1.333f, glyphScale, uiBig_FontSize }, \
428 { (data), uiSize * 1.666f, glyphScale, uiLarge_FontSize }, \
429 { (data), textSize, glyphScale, contentRegular_FontSize }, \
430 { (data), textSize * 1.200f, glyphScale, contentMedium_FontSize }, \
431 { (data), textSize * 1.333f, glyphScale, contentBig_FontSize }, \
432 { (data), textSize * 1.666f, glyphScale, contentLarge_FontSize }, \
433 { (data), textSize * 2.000f, glyphScale, contentHuge_FontSize }, \
434 { (data), smallMonoSize, glyphScale, contentMonoSmall_FontSize }, \
435 { (data), monoSize, glyphScale, contentMono_FontSize }
436 DEFINE_FONT_SET(userFont_ ? userFont_ : &fontIosevkaTermExtended_Embedded, 1.0f),
437 DEFINE_FONT_SET(&fontIosevkaTermExtended_Embedded, 0.866f),
438 DEFINE_FONT_SET(&fontNotoSansSymbolsRegular_Embedded, 2.0f),
439 DEFINE_FONT_SET(&fontNotoSansSymbols2Regular_Embedded, 1.45f),
440 DEFINE_FONT_SET(&fontSmolEmojiRegular_Embedded, 1.0f),
441 DEFINE_FONT_SET(&fontNotoEmojiRegular_Embedded, 1.10f),
442 DEFINE_FONT_SET(&fontNotoSansJPRegular_Embedded, 1.0f),
443 DEFINE_FONT_SET(&fontNotoSansSCRegular_Embedded, 1.0f),
444 DEFINE_FONT_SET(&fontNanumGothicRegular_Embedded, 1.0f), /* TODO: should use Noto Sans here, too */
445 DEFINE_FONT_SET(&fontNotoSansArabicUIRegular_Embedded, 1.0f),
446// DEFINE_FONT_SET(&fontScheherazadeNewRegular_Embedded, 1.0f),
447 };
448#endif
449 /* The `fonts` array has precomputed scaling factors and other parameters in all sizes 321 /* The `fonts` array has precomputed scaling factors and other parameters in all sizes
450 and styles for each available font. Indices to `fonts` act as font runtime IDs. */ 322 and styles for each available font. Indices to `fonts` act as font runtime IDs. */
451 /* First the mandatory fonts. */ 323 /* First the mandatory fonts. */
@@ -465,6 +337,9 @@ static void initFonts_Text_(iText *d) {
465 setupFontVariants_Text_(d, spec, fontId); 337 setupFontVariants_Text_(d, spec, fontId);
466 } 338 }
467 } 339 }
340#if !defined (NDEBUG)
341 printf("[Text] %zu fonts ready\n", size_Array(&d->fonts));
342#endif
468 gap_Text = iRound(gap_UI * d->contentFontSize); 343 gap_Text = iRound(gap_UI * d->contentFontSize);
469} 344}
470 345