summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.c53
-rw-r--r--src/app.h1
-rw-r--r--src/fontpack.c99
-rw-r--r--src/fontpack.h2
-rw-r--r--src/ui/banner.c3
-rw-r--r--src/ui/documentwidget.c1
-rw-r--r--src/ui/text.c40
-rw-r--r--src/ui/text.h2
-rw-r--r--src/ui/util.c48
-rw-r--r--src/ui/util.h1
10 files changed, 229 insertions, 21 deletions
diff --git a/src/app.c b/src/app.c
index 4045610e..31f506b5 100644
--- a/src/app.c
+++ b/src/app.c
@@ -2245,6 +2245,13 @@ void resetFonts_App(void) {
2245 } 2245 }
2246} 2246}
2247 2247
2248void availableFontsChanged_App(void) {
2249 iApp *d = &app_;
2250 iConstForEach(PtrArray, win, listWindows_App_(d, collectNew_PtrArray())) {
2251 resetMissing_Text(text_Window(win.ptr));
2252 }
2253}
2254
2248static void invalidateCachedDocuments_App_(void) { 2255static void invalidateCachedDocuments_App_(void) {
2249 iForEach(ObjectList, i, iClob(listDocuments_App(NULL))) { 2256 iForEach(ObjectList, i, iClob(listDocuments_App(NULL))) {
2250 invalidateCachedLayout_History(history_DocumentWidget(i.object)); 2257 invalidateCachedLayout_History(history_DocumentWidget(i.object));
@@ -2371,24 +2378,42 @@ iBool handleCommand_App(const char *cmd) {
2371 reload_Fonts(); /* also does font cache reset, window invalidation */ 2378 reload_Fonts(); /* also does font cache reset, window invalidation */
2372 return iTrue; 2379 return iTrue;
2373 } 2380 }
2374#if 0 2381 else if (equal_Command(cmd, "font.find")) {
2375 else if (equal_Command(cmd, "font.user")) { 2382 searchOnlineLibraryForCharacters_Fonts(string_Command(cmd, "chars"));
2376 const char *path = suffixPtr_Command(cmd, "path"); 2383 return iTrue;
2377 if (cmp_String(&d->prefs.symbolFontPath, path)) { 2384 }
2378 if (!isFrozen) { 2385 else if (equal_Command(cmd, "font.found")) {
2379 setFreezeDraw_MainWindow(get_MainWindow(), iTrue); 2386 if (hasLabel_Command(cmd, "error")) {
2380 } 2387 makeSimpleMessage_Widget("${heading.glyphfinder}",
2381 setCStr_String(&d->prefs.symbolFontPath, path); 2388 format_CStr("%d %s",
2382 loadUserFonts_Text(); 2389 argLabel_Command(cmd, "error"),
2383 resetFonts_App(d); 2390 suffixPtr_Command(cmd, "msg")));
2384 if (!isFrozen) { 2391 return iTrue;
2385 postCommand_App("font.changed"); 2392 }
2386 postCommand_App("window.unfreeze"); 2393 iString *src = collectNew_String();
2394 setCStr_String(src, "# ${heading.glyphfinder.results}\n\n");
2395 iRangecc path = iNullRange;
2396 iBool isFirst = iTrue;
2397 while (nextSplit_Rangecc(range_Command(cmd, "packs"), ";", &path)) {
2398 if (isFirst) {
2399 appendCStr_String(src, "${glyphfinder.results}\n\n");
2387 } 2400 }
2401 const char *fp = cstr_Rangecc(path);
2402 appendFormat_String(src, "=> gemini://skyjake.fi/fonts/%s %s\n", fp, fp);
2403 isFirst = iFalse;
2404 }
2405 if (isFirst) {
2406 appendFormat_String(src, "${glyphfinder.results.empty}\n");
2388 } 2407 }
2408 appendCStr_String(src, "\n=> about:fonts ${menu.fonts}");
2409 iDocumentWidget *page = newTab_App(NULL, iTrue);
2410 translate_Lang(src);
2411 setUrlAndSource_DocumentWidget(page,
2412 collectNewCStr_String(""),
2413 collectNewCStr_String("text/gemini"),
2414 utf8_String(src));
2389 return iTrue; 2415 return iTrue;
2390 } 2416 }
2391#endif
2392 else if (equal_Command(cmd, "font.set")) { 2417 else if (equal_Command(cmd, "font.set")) {
2393 if (!isFrozen) { 2418 if (!isFrozen) {
2394 setFreezeDraw_MainWindow(get_MainWindow(), iTrue); 2419 setFreezeDraw_MainWindow(get_MainWindow(), iTrue);
diff --git a/src/app.h b/src/app.h
index 5968de0d..1a4aa556 100644
--- a/src/app.h
+++ b/src/app.h
@@ -142,6 +142,7 @@ iDocumentWidget * document_Command (const char *cmd);
142void openInDefaultBrowser_App(const iString *url); 142void openInDefaultBrowser_App(const iString *url);
143void revealPath_App (const iString *path); 143void revealPath_App (const iString *path);
144void resetFonts_App (void); 144void resetFonts_App (void);
145void availableFontsChanged_App(void);
145 146
146iMainWindow * mainWindow_App (void); 147iMainWindow * mainWindow_App (void);
147void closePopups_App (void); 148void closePopups_App (void);
diff --git a/src/fontpack.c b/src/fontpack.c
index a440234e..3faf0e92 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>
@@ -1018,6 +1019,7 @@ void install_Fonts(const iString *packId, const iBlock *data) {
1018 iRelease(f); 1019 iRelease(f);
1019 /* Newly installed fontpacks may have a higher priority that overrides other fonts. */ 1020 /* Newly installed fontpacks may have a higher priority that overrides other fonts. */
1020 reload_Fonts(); 1021 reload_Fonts();
1022 availableFontsChanged_App();
1021} 1023}
1022 1024
1023void installFontFile_Fonts(const iString *fileName, const iBlock *data) { 1025void installFontFile_Fonts(const iString *fileName, const iBlock *data) {
@@ -1028,6 +1030,7 @@ void installFontFile_Fonts(const iString *fileName, const iBlock *data) {
1028 } 1030 }
1029 iRelease(f); 1031 iRelease(f);
1030 reload_Fonts(); 1032 reload_Fonts();
1033 availableFontsChanged_App();
1031} 1034}
1032 1035
1033void enablePack_Fonts(const iString *packId, iBool enable) { 1036void enablePack_Fonts(const iString *packId, iBool enable) {
@@ -1040,6 +1043,7 @@ void enablePack_Fonts(const iString *packId, iBool enable) {
1040 } 1043 }
1041 updateActive_Fonts(); 1044 updateActive_Fonts();
1042 resetFonts_App(); 1045 resetFonts_App();
1046 availableFontsChanged_App();
1043 invalidate_Window(get_MainWindow()); 1047 invalidate_Window(get_MainWindow());
1044} 1048}
1045 1049
@@ -1047,5 +1051,98 @@ void updateActive_Fonts(void) {
1047 sortSpecs_Fonts_(&fonts_); 1051 sortSpecs_Fonts_(&fonts_);
1048} 1052}
1049 1053
1050iDefineClass(FontFile) 1054static void findCharactersInCMap_(iGmRequest *d, iGmRequest *req) {
1055 /* Note: Called in background thread. */
1056 iUnused(req);
1057 const iString *missingChars = userData_Object(d);
1058 if (isSuccess_GmStatusCode(status_GmRequest(d))) {
1059 iStringList *matchingPacks = new_StringList();
1060 iChar needed[20];
1061 iChar minChar = UINT32_MAX, maxChar = 0;
1062 size_t numNeeded = 0;
1063 iConstForEach(String, ch, missingChars) {
1064 needed[numNeeded++] = ch.value;
1065 minChar = iMin(minChar, ch.value);
1066 maxChar = iMax(maxChar, ch.value);
1067 if (numNeeded == iElemCount(needed)) {
1068 /* Shouldn't be that many. */
1069 break;
1070 }
1071 }
1072 iBlock *data = decompressGzip_Block(body_GmRequest(d));
1073 iRangecc line = iNullRange;
1074 while (nextSplit_Rangecc(range_Block(data), "\n", &line)) {
1075 iRangecc fontpackPath = iNullRange;
1076 for (const char *pos = line.start; pos < line.end; pos++) {
1077 if (*pos == ':') {
1078 fontpackPath.start = line.start;
1079 fontpackPath.end = pos;
1080 line.start = pos + 1;
1081 trimStart_Rangecc(&line);
1082 break;
1083 }
1084 }
1085 if (fontpackPath.start) {
1086 /* Parse the character ranges and see if any match what we need. */
1087 const char *pos = line.start;
1088 while (pos < line.end) {
1089 char *endp;
1090 uint32_t first = strtoul(pos, &endp, 10);
1091 uint32_t last = first;
1092 if (*endp == '-') {
1093 last = strtoul(endp + 1, &endp, 10);
1094 }
1095 if (maxChar < first) {
1096 break; /* The rest are even higher. */
1097 }
1098 if (minChar <= last) {
1099 for (size_t i = 0; i < numNeeded; i++) {
1100 if (needed[i] >= first && needed[i] <= last) {
1101 /* Got it. */
1102 pushBackRange_StringList(matchingPacks, fontpackPath);
1103 break;
1104 }
1105 }
1106 }
1107 pos = endp + 1;
1108 }
1109 }
1110 }
1111 delete_Block(data);
1112 iString result;
1113 init_String(&result);
1114 format_String(&result, "font.found chars:%s packs:", cstr_String(missingChars));
1115 iConstForEach(StringList, s, matchingPacks) {
1116 if (s.pos != 0) {
1117 appendCStr_String(&result, ";");
1118 }
1119 append_String(&result, s.value);
1120 }
1121 postCommandString_Root(NULL, &result);
1122 deinit_String(&result);
1123 iRelease(matchingPacks);
1124 }
1125 else {
1126 /* Report error. */
1127 postCommandf_Root(NULL,
1128 "font.found chars:%s error:%d msg:\x1b[1m%s\x1b[0m\n%s",
1129 cstr_String(missingChars),
1130 status_GmRequest(d),
1131 cstr_String(meta_GmRequest(d)),
1132 cstr_String(url_GmRequest(d)));
1133 }
1134 fflush(stdout);
1135 delete_String(userData_Object(d));
1136 iReleaseLater(d);
1137}
1051 1138
1139void searchOnlineLibraryForCharacters_Fonts(const iString *chars) {
1140 /* Fetch the character map from skyjake.fi. */
1141 iGmRequest *req = new_GmRequest(certs_App());
1142 setUrl_GmRequest(req, collectNewCStr_String("gemini://skyjake.fi/fonts/cmap.txt.gz"));
1143 setUserData_Object(req, copy_String(chars));
1144 iConnect(GmRequest, req, finished, req, findCharactersInCMap_);
1145 submit_GmRequest(req);
1146}
1147
1148iDefineClass(FontFile)
diff --git a/src/fontpack.h b/src/fontpack.h
index aa6f2b9f..27ecd087 100644
--- a/src/fontpack.h
+++ b/src/fontpack.h
@@ -186,3 +186,5 @@ void reload_Fonts (void);
186iLocalDef iBool isInstalled_Fonts(const char *packId) { 186iLocalDef iBool isInstalled_Fonts(const char *packId) {
187 return pack_Fonts(packId) != NULL; 187 return pack_Fonts(packId) != NULL;
188} 188}
189
190void searchOnlineLibraryForCharacters_Fonts (const iString *chars);
diff --git a/src/ui/banner.c b/src/ui/banner.c
index 11ae1574..79d70039 100644
--- a/src/ui/banner.c
+++ b/src/ui/banner.c
@@ -327,7 +327,8 @@ iBool processEvent_Banner(iBanner *d, const SDL_Event *ev) {
327 else { 327 else {
328 switch (item->code) { 328 switch (item->code) {
329 case missingGlyphs_GmStatusCode: 329 case missingGlyphs_GmStatusCode:
330 postCommandf_App("open newtab:1 url:about:fonts"); 330 //postCommandf_App("open newtab:1 url:about:fonts");
331 makeGlyphFinder_Widget();
331 break; 332 break;
332 case ansiEscapes_GmStatusCode: 333 case ansiEscapes_GmStatusCode:
333 makeQuestion_Widget( 334 makeQuestion_Widget(
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 6a535882..fdb55232 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -2756,6 +2756,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d,
2756 } 2756 }
2757 d->flags |= drawDownloadCounter_DocumentWidgetFlag; 2757 d->flags |= drawDownloadCounter_DocumentWidgetFlag;
2758 clear_PtrSet(d->view.invalidRuns); 2758 clear_PtrSet(d->view.invalidRuns);
2759 documentRunsInvalidated_DocumentWidget_(d);
2759 deinit_String(&str); 2760 deinit_String(&str);
2760 return; 2761 return;
2761 } 2762 }
diff --git a/src/ui/text.c b/src/ui/text.c
index 7bb418eb..86ac709b 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -247,8 +247,6 @@ struct Impl_CacheRow {
247}; 247};
248 248
249struct Impl_Text { 249struct Impl_Text {
250// enum iTextFont contentFont;
251// enum iTextFont headingFont;
252 float contentFontSize; 250 float contentFontSize;
253 iArray fonts; /* fonts currently selected for use (incl. all styles/sizes) */ 251 iArray fonts; /* fonts currently selected for use (incl. all styles/sizes) */
254 int overrideFontId; /* always checked for glyphs first, regardless of which font is used */ 252 int overrideFontId; /* always checked for glyphs first, regardless of which font is used */
@@ -264,7 +262,8 @@ struct Impl_Text {
264 int ansiFlags; 262 int ansiFlags;
265 int baseFontId; /* base attributes (for restoring via escapes) */ 263 int baseFontId; /* base attributes (for restoring via escapes) */
266 int baseFgColorId; 264 int baseFgColorId;
267 iBool missingGlyphs; /* true if a glyph couldn't be found */ 265 iBool missingGlyphs; /* true if a glyph couldn't be found */
266 iChar missingChars[20]; /* rotating buffer of the latest missing characters */
268}; 267};
269 268
270iDefineTypeConstructionArgs(Text, (SDL_Renderer *render), render) 269iDefineTypeConstructionArgs(Text, (SDL_Renderer *render), render)
@@ -341,6 +340,8 @@ static void initFonts_Text_(iText *d) {
341 printf("[Text] %zu font variants ready\n", size_Array(&d->fonts)); 340 printf("[Text] %zu font variants ready\n", size_Array(&d->fonts));
342#endif 341#endif
343 gap_Text = iRound(gap_UI * d->contentFontSize); 342 gap_Text = iRound(gap_UI * d->contentFontSize);
343// d->missingGlyphs = iFalse;
344// iZap(d->missingChars);
344} 345}
345 346
346static void deinitFonts_Text_(iText *d) { 347static void deinitFonts_Text_(iText *d) {
@@ -403,6 +404,7 @@ void init_Text(iText *d, SDL_Renderer *render) {
403 d->baseFontId = -1; 404 d->baseFontId = -1;
404 d->baseFgColorId = -1; 405 d->baseFgColorId = -1;
405 d->missingGlyphs = iFalse; 406 d->missingGlyphs = iFalse;
407 iZap(d->missingChars);
406 d->render = render; 408 d->render = render;
407 /* A grayscale palette for rasterized glyphs. */ { 409 /* A grayscale palette for rasterized glyphs. */ {
408 SDL_Color colors[256]; 410 SDL_Color colors[256];
@@ -589,8 +591,23 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) {
589 } 591 }
590 } 592 }
591 if (!*glyphIndex) { 593 if (!*glyphIndex) {
592 activeText_->missingGlyphs = iTrue; 594 fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int) ch); fflush(stderr);
593 fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int)ch); fflush(stderr); 595 iText *tx = activeText_;
596 tx->missingGlyphs = iTrue;
597 /* Remember a few of the latest missing characters. */
598 iBool gotIt = iFalse;
599 for (size_t i = 0; i < iElemCount(tx->missingChars); i++) {
600 if (tx->missingChars[i] == ch) {
601 gotIt = iTrue;
602 break;
603 }
604 }
605 if (!gotIt) {
606 memmove(tx->missingChars + 1,
607 tx->missingChars,
608 sizeof(tx->missingChars) - sizeof(tx->missingChars[0]));
609 tx->missingChars[0] = ch;
610 }
594 } 611 }
595 return d; 612 return d;
596} 613}
@@ -2199,6 +2216,19 @@ iBool checkMissing_Text(void) {
2199 return missing; 2216 return missing;
2200} 2217}
2201 2218
2219iChar missing_Text(size_t index) {
2220 const iText *d = activeText_;
2221 if (index >= iElemCount(d->missingChars)) {
2222 return 0;
2223 }
2224 return d->missingChars[index];
2225}
2226
2227void resetMissing_Text(iText *d) {
2228 d->missingGlyphs = iFalse;
2229 iZap(d->missingChars);
2230}
2231
2202SDL_Texture *glyphCache_Text(void) { 2232SDL_Texture *glyphCache_Text(void) {
2203 return activeText_->cache; 2233 return activeText_->cache;
2204} 2234}
diff --git a/src/ui/text.h b/src/ui/text.h
index c8bb6f85..a34cc9bd 100644
--- a/src/ui/text.h
+++ b/src/ui/text.h
@@ -227,6 +227,8 @@ struct Impl_WrapText {
227iTextMetrics measure_WrapText (iWrapText *, int fontId); 227iTextMetrics measure_WrapText (iWrapText *, int fontId);
228iTextMetrics draw_WrapText (iWrapText *, int fontId, iInt2 pos, int color); 228iTextMetrics draw_WrapText (iWrapText *, int fontId, iInt2 pos, int color);
229 229
230iChar missing_Text (size_t index);
231void resetMissing_Text (iText *);
230iBool checkMissing_Text (void); /* returns the flag, and clears it */ 232iBool checkMissing_Text (void); /* returns the flag, and clears it */
231SDL_Texture * glyphCache_Text (void); 233SDL_Texture * glyphCache_Text (void);
232 234
diff --git a/src/ui/util.c b/src/ui/util.c
index 31907721..8e71dcec 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -3451,6 +3451,54 @@ iWidget *makeTranslation_Widget(iWidget *parent) {
3451 return dlg; 3451 return dlg;
3452} 3452}
3453 3453
3454iWidget *makeGlyphFinder_Widget(void) {
3455 iString msg;
3456 iString command;
3457 init_String(&msg);
3458 initCStr_String(&command, "!font.find chars:");
3459 for (size_t i = 0; ; i++) {
3460 iChar ch = missing_Text(i);
3461 if (!ch) break;
3462 appendFormat_String(&msg, " U+%04X", ch);
3463 appendChar_String(&command, ch);
3464 }
3465 iArray items;
3466 init_Array(&items, sizeof(iMenuItem));
3467 if (!isEmpty_String(&msg)) {
3468 prependCStr_String(&msg, "${dlg.glyphfinder.missing} ");
3469 appendCStr_String(&msg, "\n\n${dlg.glyphfinder.help}");
3470 pushBackN_Array(
3471 &items,
3472 (iMenuItem[]){
3473 { "${menu.fonts}", 0, 0, "!open newtab:1 url:about:fonts" },
3474 { "${dlg.glyphfinder.disable}", 0, 0, "prefs.font.warnmissing.changed arg:0" },
3475 { "---" },
3476 { uiTextCaution_ColorEscape magnifyingGlass_Icon " ${dlg.glyphfinder.search}",
3477 0,
3478 0,
3479 cstr_String(&command) },
3480 { "${close}", 0, 0, "cancel" } },
3481 5);
3482 }
3483 else {
3484 setCStr_String(&msg, "${dlg.glyphfinder.help.empty}");
3485 pushBackN_Array(&items,
3486 (iMenuItem[]){ { "${menu.reload}", 0, 0, "navigate.reload" },
3487 { "${close}", 0, 0, "cancel" } },
3488 2);
3489 }
3490 iWidget *dlg = makeQuestion_Widget("${heading.glyphfinder}", cstr_String(&msg),
3491 constData_Array(&items),
3492 size_Array(&items));
3493 arrange_Widget(dlg);
3494 deinit_Array(&items);
3495 deinit_String(&command);
3496 deinit_String(&msg);
3497 return dlg;
3498}
3499
3500/*----------------------------------------------------------------------------------------------*/
3501
3454void init_PerfTimer(iPerfTimer *d) { 3502void init_PerfTimer(iPerfTimer *d) {
3455 d->ticks = SDL_GetPerformanceCounter(); 3503 d->ticks = SDL_GetPerformanceCounter();
3456} 3504}
diff --git a/src/ui/util.h b/src/ui/util.h
index 98ce784c..0289d579 100644
--- a/src/ui/util.h
+++ b/src/ui/util.h
@@ -342,6 +342,7 @@ iWidget * makeBookmarkCreation_Widget (const iString *url, const iString *titl
342iWidget * makeIdentityCreation_Widget (void); 342iWidget * makeIdentityCreation_Widget (void);
343iWidget * makeFeedSettings_Widget (uint32_t bookmarkId); 343iWidget * makeFeedSettings_Widget (uint32_t bookmarkId);
344iWidget * makeTranslation_Widget (iWidget *parent); 344iWidget * makeTranslation_Widget (iWidget *parent);
345iWidget * makeGlyphFinder_Widget (void);
345 346
346const char * languageId_String (const iString *menuItemLabel); 347const char * languageId_String (const iString *menuItemLabel);
347int languageIndex_CStr (const char *langId); 348int languageIndex_CStr (const char *langId);