diff options
Diffstat (limited to 'src/fontpack.c')
-rw-r--r-- | src/fontpack.c | 120 |
1 files changed, 114 insertions, 6 deletions
diff --git a/src/fontpack.c b/src/fontpack.c index a440234e..96006226 100644 --- a/src/fontpack.c +++ b/src/fontpack.c | |||
@@ -23,6 +23,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
23 | #include "fontpack.h" | 23 | #include "fontpack.h" |
24 | #include "resources.h" | 24 | #include "resources.h" |
25 | #include "ui/window.h" | 25 | #include "ui/window.h" |
26 | #include "gmrequest.h" | ||
26 | #include "app.h" | 27 | #include "app.h" |
27 | 28 | ||
28 | #include <the_Foundation/archive.h> | 29 | #include <the_Foundation/archive.h> |
@@ -748,7 +749,7 @@ const iPtrArray *listSpecsByPriority_Fonts(void) { | |||
748 | return &fonts_.specOrder; | 749 | return &fonts_.specOrder; |
749 | } | 750 | } |
750 | 751 | ||
751 | iString *infoText_FontPack(const iFontPack *d) { | 752 | iString *infoText_FontPack(const iFontPack *d, iBool isFull) { |
752 | const iFontPack *installed = pack_Fonts(cstr_String(&d->id)); | 753 | const iFontPack *installed = pack_Fonts(cstr_String(&d->id)); |
753 | const iBool isInstalled = (installed != NULL); | 754 | const iBool isInstalled = (installed != NULL); |
754 | const int installedVersion = installed ? installed->version : 0; | 755 | const int installedVersion = installed ? installed->version : 0; |
@@ -757,9 +758,17 @@ iString *infoText_FontPack(const iFontPack *d) { | |||
757 | size_t sizeInBytes = 0; | 758 | size_t sizeInBytes = 0; |
758 | iPtrSet *uniqueFiles = new_PtrSet(); | 759 | iPtrSet *uniqueFiles = new_PtrSet(); |
759 | iStringList *names = new_StringList(); | 760 | iStringList *names = new_StringList(); |
761 | size_t numNames = 0; | ||
762 | iBool isAbbreviated = iFalse; | ||
760 | iConstForEach(PtrArray, i, listSpecs_FontPack(d)) { | 763 | iConstForEach(PtrArray, i, listSpecs_FontPack(d)) { |
761 | const iFontSpec *spec = i.ptr; | 764 | const iFontSpec *spec = i.ptr; |
762 | pushBack_StringList(names, &spec->name); | 765 | numNames++; |
766 | if (isFull || size_StringList(names) < 20) { | ||
767 | pushBack_StringList(names, &spec->name); | ||
768 | } | ||
769 | else { | ||
770 | isAbbreviated = iTrue; | ||
771 | } | ||
763 | iForIndices(j, spec->styles) { | 772 | iForIndices(j, spec->styles) { |
764 | insert_PtrSet(uniqueFiles, spec->styles[j]->sourceData.i); | 773 | insert_PtrSet(uniqueFiles, spec->styles[j]->sourceData.i); |
765 | } | 774 | } |
@@ -777,11 +786,12 @@ iString *infoText_FontPack(const iFontPack *d) { | |||
777 | if (!endsWith_String(str, "(")) { | 786 | if (!endsWith_String(str, "(")) { |
778 | appendCStr_String(str, ", "); | 787 | appendCStr_String(str, ", "); |
779 | } | 788 | } |
780 | appendCStr_String(str, formatCStrs_Lang("num.fonts.n", size_StringList(names))); | 789 | appendCStr_String(str, formatCStrs_Lang("num.fonts.n", numNames)); |
781 | } | 790 | } |
782 | appendFormat_String(str, ")"); | 791 | appendFormat_String(str, ")"); |
783 | } | 792 | } |
784 | appendFormat_String(str, " \u2014 %s\n", cstrCollect_String(joinCStr_StringList(names, ", "))); | 793 | appendFormat_String(str, " \u2014 %s%s\n", cstrCollect_String(joinCStr_StringList(names, ", ")), |
794 | isAbbreviated ? ", ..." : ""); | ||
785 | if (isInstalled && installedVersion != d->version) { | 795 | if (isInstalled && installedVersion != d->version) { |
786 | appendCStr_String(str, format_Lang("${fontpack.meta.version}\n", d->version)); | 796 | appendCStr_String(str, format_Lang("${fontpack.meta.version}\n", d->version)); |
787 | } | 797 | } |
@@ -945,7 +955,7 @@ const iString *infoPage_Fonts(iRangecc query) { | |||
945 | appendFormat_String(str, "### %s\n", | 955 | appendFormat_String(str, "### %s\n", |
946 | isEmpty_String(packId) ? "fonts.ini" : | 956 | isEmpty_String(packId) ? "fonts.ini" : |
947 | cstr_String(packId)); | 957 | cstr_String(packId)); |
948 | append_String(str, collect_String(infoText_FontPack(pack))); | 958 | append_String(str, collect_String(infoText_FontPack(pack, iFalse))); |
949 | appendFormat_String(str, "=> %s ${fontpack.meta.viewfile}\n", | 959 | appendFormat_String(str, "=> %s ${fontpack.meta.viewfile}\n", |
950 | cstrCollect_String(makeFileUrl_String(&spec->sourcePath))); | 960 | cstrCollect_String(makeFileUrl_String(&spec->sourcePath))); |
951 | if (pack->isStandalone) { | 961 | if (pack->isStandalone) { |
@@ -1018,6 +1028,7 @@ void install_Fonts(const iString *packId, const iBlock *data) { | |||
1018 | iRelease(f); | 1028 | iRelease(f); |
1019 | /* Newly installed fontpacks may have a higher priority that overrides other fonts. */ | 1029 | /* Newly installed fontpacks may have a higher priority that overrides other fonts. */ |
1020 | reload_Fonts(); | 1030 | reload_Fonts(); |
1031 | availableFontsChanged_App(); | ||
1021 | } | 1032 | } |
1022 | 1033 | ||
1023 | void installFontFile_Fonts(const iString *fileName, const iBlock *data) { | 1034 | void installFontFile_Fonts(const iString *fileName, const iBlock *data) { |
@@ -1028,6 +1039,7 @@ void installFontFile_Fonts(const iString *fileName, const iBlock *data) { | |||
1028 | } | 1039 | } |
1029 | iRelease(f); | 1040 | iRelease(f); |
1030 | reload_Fonts(); | 1041 | reload_Fonts(); |
1042 | availableFontsChanged_App(); | ||
1031 | } | 1043 | } |
1032 | 1044 | ||
1033 | void enablePack_Fonts(const iString *packId, iBool enable) { | 1045 | void enablePack_Fonts(const iString *packId, iBool enable) { |
@@ -1040,6 +1052,7 @@ void enablePack_Fonts(const iString *packId, iBool enable) { | |||
1040 | } | 1052 | } |
1041 | updateActive_Fonts(); | 1053 | updateActive_Fonts(); |
1042 | resetFonts_App(); | 1054 | resetFonts_App(); |
1055 | availableFontsChanged_App(); | ||
1043 | invalidate_Window(get_MainWindow()); | 1056 | invalidate_Window(get_MainWindow()); |
1044 | } | 1057 | } |
1045 | 1058 | ||
@@ -1047,5 +1060,100 @@ void updateActive_Fonts(void) { | |||
1047 | sortSpecs_Fonts_(&fonts_); | 1060 | sortSpecs_Fonts_(&fonts_); |
1048 | } | 1061 | } |
1049 | 1062 | ||
1050 | iDefineClass(FontFile) | 1063 | static void findCharactersInCMap_(iGmRequest *d, iGmRequest *req) { |
1064 | /* Note: Called in background thread. */ | ||
1065 | iUnused(req); | ||
1066 | const iString *missingChars = userData_Object(d); | ||
1067 | if (isSuccess_GmStatusCode(status_GmRequest(d))) { | ||
1068 | iStringList *matchingPacks = new_StringList(); | ||
1069 | iChar needed[20]; | ||
1070 | iChar minChar = UINT32_MAX, maxChar = 0; | ||
1071 | size_t numNeeded = 0; | ||
1072 | iConstForEach(String, ch, missingChars) { | ||
1073 | needed[numNeeded++] = ch.value; | ||
1074 | minChar = iMin(minChar, ch.value); | ||
1075 | maxChar = iMax(maxChar, ch.value); | ||
1076 | if (numNeeded == iElemCount(needed)) { | ||
1077 | /* Shouldn't be that many. */ | ||
1078 | break; | ||
1079 | } | ||
1080 | } | ||
1081 | iBlock *data = decompressGzip_Block(body_GmRequest(d)); | ||
1082 | iRangecc line = iNullRange; | ||
1083 | while (nextSplit_Rangecc(range_Block(data), "\n", &line)) { | ||
1084 | iRangecc fontpackPath = iNullRange; | ||
1085 | for (const char *pos = line.start; pos < line.end; pos++) { | ||
1086 | if (*pos == ':') { | ||
1087 | fontpackPath.start = line.start; | ||
1088 | fontpackPath.end = pos; | ||
1089 | line.start = pos + 1; | ||
1090 | trimStart_Rangecc(&line); | ||
1091 | break; | ||
1092 | } | ||
1093 | } | ||
1094 | if (fontpackPath.start) { | ||
1095 | /* Parse the character ranges and see if any match what we need. */ | ||
1096 | const char *pos = line.start; | ||
1097 | while (pos < line.end) { | ||
1098 | char *endp; | ||
1099 | uint32_t first = strtoul(pos, &endp, 10); | ||
1100 | uint32_t last = first; | ||
1101 | if (*endp == '-') { | ||
1102 | last = strtoul(endp + 1, &endp, 10); | ||
1103 | } | ||
1104 | if (maxChar < first) { | ||
1105 | break; /* The rest are even higher. */ | ||
1106 | } | ||
1107 | if (minChar <= last) { | ||
1108 | for (size_t i = 0; i < numNeeded; i++) { | ||
1109 | if (needed[i] >= first && needed[i] <= last) { | ||
1110 | /* Got it. */ | ||
1111 | pushBackRange_StringList(matchingPacks, fontpackPath); | ||
1112 | break; | ||
1113 | } | ||
1114 | } | ||
1115 | } | ||
1116 | pos = endp + 1; | ||
1117 | } | ||
1118 | } | ||
1119 | } | ||
1120 | delete_Block(data); | ||
1121 | iString result; | ||
1122 | init_String(&result); | ||
1123 | format_String(&result, "font.found chars:%s packs:", cstr_String(missingChars)); | ||
1124 | iConstForEach(StringList, s, matchingPacks) { | ||
1125 | if (s.pos != 0) { | ||
1126 | appendCStr_String(&result, ","); | ||
1127 | } | ||
1128 | append_String(&result, s.value); | ||
1129 | } | ||
1130 | postCommandString_Root(NULL, &result); | ||
1131 | deinit_String(&result); | ||
1132 | iRelease(matchingPacks); | ||
1133 | } | ||
1134 | else { | ||
1135 | /* Report error. */ | ||
1136 | postCommandf_Root(NULL, | ||
1137 | "font.found chars:%s error:%d msg:\x1b[1m%s\x1b[0m\n%s", | ||
1138 | cstr_String(missingChars), | ||
1139 | status_GmRequest(d), | ||
1140 | cstr_String(meta_GmRequest(d)), | ||
1141 | cstr_String(url_GmRequest(d))); | ||
1142 | } | ||
1143 | // fflush(stdout); | ||
1144 | delete_String(userData_Object(d)); | ||
1145 | /* We can't delete ourselves; threads must be joined from another thread. */ | ||
1146 | SDL_PushEvent((SDL_Event *) &(SDL_UserEvent){ | ||
1147 | .type = SDL_USEREVENT, .code = releaseObject_UserEventCode, .data1 = d }); | ||
1148 | } | ||
1051 | 1149 | ||
1150 | void searchOnlineLibraryForCharacters_Fonts(const iString *chars) { | ||
1151 | /* Fetch the character map from skyjake.fi. */ | ||
1152 | iGmRequest *req = new_GmRequest(certs_App()); | ||
1153 | setUrl_GmRequest(req, collectNewCStr_String("gemini://skyjake.fi/fonts/cmap.txt.gz")); | ||
1154 | setUserData_Object(req, copy_String(chars)); | ||
1155 | iConnect(GmRequest, req, finished, req, findCharactersInCMap_); | ||
1156 | submit_GmRequest(req); | ||
1157 | } | ||
1158 | |||
1159 | iDefineClass(FontFile) | ||