summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-10-17 11:15:14 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-10-17 11:15:14 +0300
commit2e2b823bfb5d34d42c6b6c1b289193c854459b45 (patch)
tree345f37aa1b84d8dedb98ff260265b41495e10878
parent2f3987f5e54d95658f95c6991b0644bc15eedabf (diff)
Media and FontPacks (work in progress)
Saving this as the last point of progress. This direction is too complicated: Media needs to be a lot more sophisticated to allow dynamic and interactive media at the level of FontPacks. (A bit like Player handles audio playback.) This will be reverted. FontPack management will happen using an another method.
-rw-r--r--res/arabic.fontpack/fontpack.ini2
-rw-r--r--res/cjk.fontpack/fontpack.ini2
-rw-r--r--res/default.fontpack/fontpack.ini2
-rw-r--r--res/firasans.fontpack/fontpack.ini2
-rw-r--r--res/literata.fontpack/fontpack.ini2
-rw-r--r--res/nunito.fontpack/fontpack.ini2
-rw-r--r--res/tinos.fontpack/fontpack.ini2
-rw-r--r--src/app.c61
-rw-r--r--src/app.h2
-rw-r--r--src/fontpack.c69
-rw-r--r--src/fontpack.h10
-rw-r--r--src/media.c32
-rw-r--r--src/media.h2
-rw-r--r--src/prefs.c2
-rw-r--r--src/prefs.h3
-rw-r--r--src/ui/documentwidget.c43
-rw-r--r--src/ui/documentwidget.h3
-rw-r--r--src/ui/mediaui.c48
-rw-r--r--src/ui/mediaui.h7
19 files changed, 240 insertions, 56 deletions
diff --git a/res/arabic.fontpack/fontpack.ini b/res/arabic.fontpack/fontpack.ini
index 48b40d82..d9087161 100644
--- a/res/arabic.fontpack/fontpack.ini
+++ b/res/arabic.fontpack/fontpack.ini
@@ -1,4 +1,4 @@
1version = 1 1version = 1
2 2
3[arabic] 3[arabic]
4name = "Noto Sans Arabic UI" 4name = "Noto Sans Arabic UI"
diff --git a/res/cjk.fontpack/fontpack.ini b/res/cjk.fontpack/fontpack.ini
index 6e0d274c..0d74c634 100644
--- a/res/cjk.fontpack/fontpack.ini
+++ b/res/cjk.fontpack/fontpack.ini
@@ -1,4 +1,4 @@
1version = 1 1version = 1
2 2
3[notosansjp] 3[notosansjp]
4name = "Noto Sans JP" 4name = "Noto Sans JP"
diff --git a/res/default.fontpack/fontpack.ini b/res/default.fontpack/fontpack.ini
index f8ef31ce..68316ef6 100644
--- a/res/default.fontpack/fontpack.ini
+++ b/res/default.fontpack/fontpack.ini
@@ -17,8 +17,6 @@
17# `glyphscale` and `voffset` can also be specified separately for the UI and 17# `glyphscale` and `voffset` can also be specified separately for the UI and
18# document domains by prefixing `ui.` or `doc.` to the key. 18# document domains by prefixing `ui.` or `doc.` to the key.
19 19
20version = 1
21
22[default] 20[default]
23name = "Source Sans" 21name = "Source Sans"
24regular = "SourceSans3-Regular.ttf" 22regular = "SourceSans3-Regular.ttf"
diff --git a/res/firasans.fontpack/fontpack.ini b/res/firasans.fontpack/fontpack.ini
index c6eb4c77..682cad94 100644
--- a/res/firasans.fontpack/fontpack.ini
+++ b/res/firasans.fontpack/fontpack.ini
@@ -1,4 +1,4 @@
1version = 1 1version = 1
2 2
3[firasans] 3[firasans]
4name = "Fira Sans" 4name = "Fira Sans"
diff --git a/res/literata.fontpack/fontpack.ini b/res/literata.fontpack/fontpack.ini
index 7c29491d..4a264fbf 100644
--- a/res/literata.fontpack/fontpack.ini
+++ b/res/literata.fontpack/fontpack.ini
@@ -1,4 +1,4 @@
1version = 1 1version = 1
2 2
3[literata] 3[literata]
4name = "Literata" 4name = "Literata"
diff --git a/res/nunito.fontpack/fontpack.ini b/res/nunito.fontpack/fontpack.ini
index 2f2471e1..10ae9516 100644
--- a/res/nunito.fontpack/fontpack.ini
+++ b/res/nunito.fontpack/fontpack.ini
@@ -1,4 +1,4 @@
1version = 1 1version = 1
2 2
3[nunito] 3[nunito]
4name = "Nunito" 4name = "Nunito"
diff --git a/res/tinos.fontpack/fontpack.ini b/res/tinos.fontpack/fontpack.ini
index a2cf811e..f7b61c9d 100644
--- a/res/tinos.fontpack/fontpack.ini
+++ b/res/tinos.fontpack/fontpack.ini
@@ -1,4 +1,4 @@
1version = 1 1version = 1
2 2
3[tinos] 3[tinos]
4name = "Tinos" 4name = "Tinos"
diff --git a/src/app.c b/src/app.c
index 6282ade2..70b611c2 100644
--- a/src/app.c
+++ b/src/app.c
@@ -231,6 +231,9 @@ static iString *serializePrefs_App_(const iApp *d) {
231 appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth); 231 appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth);
232 appendFormat_String(str, "linespacing.set arg:%f\n", d->prefs.lineSpacing); 232 appendFormat_String(str, "linespacing.set arg:%f\n", d->prefs.lineSpacing);
233 appendFormat_String(str, "returnkey.set arg:%d\n", d->prefs.returnKey); 233 appendFormat_String(str, "returnkey.set arg:%d\n", d->prefs.returnKey);
234 iConstForEach(StringSet, fp, d->prefs.disabledFontPacks) {
235 appendFormat_String(str, "fontpack.disable id:%s\n", cstr_String(fp.value));
236 }
234 /* TODO: This array belongs in Prefs. It can then be used for command handling as well. */ 237 /* TODO: This array belongs in Prefs. It can then be used for command handling as well. */
235 const struct { 238 const struct {
236 const char * id; 239 const char * id;
@@ -256,21 +259,6 @@ static iString *serializePrefs_App_(const iApp *d) {
256 iForIndices(i, boolPrefs) { 259 iForIndices(i, boolPrefs) {
257 appendFormat_String(str, "%s.changed arg:%d\n", boolPrefs[i].id, *boolPrefs[i].value); 260 appendFormat_String(str, "%s.changed arg:%d\n", boolPrefs[i].id, *boolPrefs[i].value);
258 } 261 }
259// appendFormat_String(str, "prefs.animate.changed arg:%d\n", d->prefs.uiAnimations);
260// appendFormat_String(str, "prefs.font.smooth.changed arg:%d\n", d->prefs.fontSmoothing);
261// appendFormat_String(str, "prefs.gemtext.ansi.changed arg:%d\n", d->prefs.gemtextAnsiEscapes);
262// appendFormat_String(str, "prefs.mono.gemini.changed arg:%d\n", d->prefs.monospaceGemini);
263// appendFormat_String(str, "prefs.mono.gopher.changed arg:%d\n", d->prefs.monospaceGopher);
264// appendFormat_String(str, "prefs.boldlink.dark.changed arg:%d\n", d->prefs.boldLinkDark);
265// appendFormat_String(str, "prefs.boldlink.light.changed arg:%d\n", d->prefs.boldLinkLight);
266// appendFormat_String(str, "prefs.biglede.changed arg:%d\n", d->prefs.bigFirstParagraph);
267// appendFormat_String(str, "prefs.plaintext.wrap.changed arg:%d\n", d->prefs.plainTextWrap);
268// appendFormat_String(str, "prefs.sideicon.changed arg:%d\n", d->prefs.sideIcon);
269// appendFormat_String(str, "prefs.centershort.changed arg:%d\n", d->prefs.centerShortDocs);
270// appendFormat_String(str, "prefs.collapsepreonload.changed arg:%d\n", d->prefs.collapsePreOnLoad);
271// appendFormat_String(str, "prefs.hoverlink.changed arg:%d\n", d->prefs.hoverLink);
272// appendFormat_String(str, "prefs.bookmarks.addbottom arg:%d\n", d->prefs.addBookmarksToBottom);
273// appendFormat_String(str, "prefs.archive.openindex.changed arg:%d\n", d->prefs.openArchiveIndexPages);
274 appendFormat_String(str, "quoteicon.set arg:%d\n", d->prefs.quoteIcon ? 1 : 0); 262 appendFormat_String(str, "quoteicon.set arg:%d\n", d->prefs.quoteIcon ? 1 : 0);
275 appendFormat_String(str, "theme.set arg:%d auto:1\n", d->prefs.theme); 263 appendFormat_String(str, "theme.set arg:%d auto:1\n", d->prefs.theme);
276 appendFormat_String(str, "accent.set arg:%d\n", d->prefs.accent); 264 appendFormat_String(str, "accent.set arg:%d\n", d->prefs.accent);
@@ -381,6 +369,10 @@ static void loadPrefs_App_(iApp *d) {
381 d->initialWindowRect = init_Rect( 369 d->initialWindowRect = init_Rect(
382 pos.x, pos.y, argLabel_Command(cmd, "width"), argLabel_Command(cmd, "height")); 370 pos.x, pos.y, argLabel_Command(cmd, "width"), argLabel_Command(cmd, "height"));
383 } 371 }
372 else if (equal_Command(cmd, "fontpack.disable")) {
373 insert_StringSet(d->prefs.disabledFontPacks,
374 collect_String(suffix_Command(cmd, "id")));
375 }
384#if !defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT) 376#if !defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT)
385 else if (equal_Command(cmd, "downloads")) { 377 else if (equal_Command(cmd, "downloads")) {
386 continue; /* can't change downloads directory */ 378 continue; /* can't change downloads directory */
@@ -1119,6 +1111,18 @@ void trimMemory_App(void) {
1119 iRelease(docs); 1111 iRelease(docs);
1120} 1112}
1121 1113
1114iBool findCachedContent_App(const iString *url, iString *mime_out, iBlock *data_out) {
1115 /* Cached content can be found in MediaRequests of DocumentWidgets (loaded on the currently
1116 open page) and the DocumentWidget itself. `Media` doesn't store source data, only
1117 presentation data. */
1118 iConstForEach(ObjectList, i, iClob(listDocuments_App(NULL))) {
1119 if (findCachedContent_DocumentWidget(i.object, url, mime_out, data_out)) {
1120 return iTrue;
1121 }
1122 }
1123 return iFalse;
1124}
1125
1122iLocalDef iBool isWaitingAllowed_App_(iApp *d) { 1126iLocalDef iBool isWaitingAllowed_App_(iApp *d) {
1123 if (!isEmpty_Periodic(&d->periodic)) { 1127 if (!isEmpty_Periodic(&d->periodic)) {
1124 return iFalse; 1128 return iFalse;
@@ -2086,7 +2090,8 @@ const iString *searchQueryUrl_App(const iString *queryStringUnescaped) {
2086 "%s?%s", cstr_String(&d->prefs.strings[searchUrl_PrefsString]), cstr_String(escaped)); 2090 "%s?%s", cstr_String(&d->prefs.strings[searchUrl_PrefsString]), cstr_String(escaped));
2087} 2091}
2088 2092
2089static void resetFonts_App_(iApp *d) { 2093void resetFonts_App(void) {
2094 iApp *d = &app_;
2090 iConstForEach(PtrArray, win, listWindows_App_(d)) { 2095 iConstForEach(PtrArray, win, listWindows_App_(d)) {
2091 resetFonts_Text(text_Window(win.ptr)); 2096 resetFonts_Text(text_Window(win.ptr));
2092 } 2097 }
@@ -2163,7 +2168,11 @@ iBool handleCommand_App(const char *cmd) {
2163 return iTrue; 2168 return iTrue;
2164 } 2169 }
2165 else if (equal_Command(cmd, "font.reset")) { 2170 else if (equal_Command(cmd, "font.reset")) {
2166 resetFonts_App_(d); 2171 resetFonts_App();
2172 return iTrue;
2173 }
2174 else if (equal_Command(cmd, "font.reload")) {
2175 reload_Fonts(); /* also does font cache reset, window invalidation */
2167 return iTrue; 2176 return iTrue;
2168 } 2177 }
2169#if 0 2178#if 0
@@ -2175,7 +2184,7 @@ iBool handleCommand_App(const char *cmd) {
2175 } 2184 }
2176 setCStr_String(&d->prefs.symbolFontPath, path); 2185 setCStr_String(&d->prefs.symbolFontPath, path);
2177 loadUserFonts_Text(); 2186 loadUserFonts_Text();
2178 resetFonts_App_(d); 2187 resetFonts_App(d);
2179 if (!isFrozen) { 2188 if (!isFrozen) {
2180 postCommand_App("font.changed"); 2189 postCommand_App("font.changed");
2181 postCommand_App("window.unfreeze"); 2190 postCommand_App("window.unfreeze");
@@ -3034,6 +3043,22 @@ iBool handleCommand_App(const char *cmd) {
3034 } 3043 }
3035 return iFalse; 3044 return iFalse;
3036 } 3045 }
3046 else if (equal_Command(cmd, "media.fontpack.enable")) {
3047 const iString *packId = collect_String(suffix_Command(cmd, "packid"));
3048 if (arg_Command(cmd)) {
3049 remove_StringSet(d->prefs.disabledFontPacks, packId);
3050 }
3051 else {
3052 insert_StringSet(d->prefs.disabledFontPacks, packId);
3053 }
3054 resetFonts_App();
3055 const iMedia *media = pointerLabel_Command(cmd, "media");
3056 if (media) {
3057 postCommandf_App("media.fontpack.updated id:%u media:%p",
3058 argU32Label_Command(cmd, "mediaid"), media);
3059 }
3060 return iTrue;
3061 }
3037#if defined (LAGRANGE_ENABLE_IPC) 3062#if defined (LAGRANGE_ENABLE_IPC)
3038 else if (equal_Command(cmd, "ipc.list.urls")) { 3063 else if (equal_Command(cmd, "ipc.list.urls")) {
3039 iProcessId pid = argLabel_Command(cmd, "pid"); 3064 iProcessId pid = argLabel_Command(cmd, "pid");
diff --git a/src/app.h b/src/app.h
index 2313ec15..8543f3b5 100644
--- a/src/app.h
+++ b/src/app.h
@@ -99,6 +99,7 @@ iStringSet * listOpenURLs_App (void); /* all tabs */
99iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf, iBool switchToNew); 99iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf, iBool switchToNew);
100void trimCache_App (void); 100void trimCache_App (void);
101void trimMemory_App (void); 101void trimMemory_App (void);
102iBool findCachedContent_App(const iString *url, iString *mime_out, iBlock *data_out);
102 103
103iDocumentWidget * document_Root (iRoot *); 104iDocumentWidget * document_Root (iRoot *);
104 105
@@ -137,6 +138,7 @@ iDocumentWidget * document_Command (const char *cmd);
137 138
138void openInDefaultBrowser_App(const iString *url); 139void openInDefaultBrowser_App(const iString *url);
139void revealPath_App (const iString *path); 140void revealPath_App (const iString *path);
141void resetFonts_App (void);
140 142
141iMainWindow * mainWindow_App (void); 143iMainWindow * mainWindow_App (void);
142void closePopups_App (void); 144void closePopups_App (void);
diff --git a/src/fontpack.c b/src/fontpack.c
index b135ea43..9603bded 100644
--- a/src/fontpack.c
+++ b/src/fontpack.c
@@ -22,6 +22,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22 22
23#include "fontpack.h" 23#include "fontpack.h"
24#include "embedded.h" 24#include "embedded.h"
25#include "ui/window.h"
25#include "app.h" 26#include "app.h"
26 27
27#include <the_Foundation/archive.h> 28#include <the_Foundation/archive.h>
@@ -396,6 +397,24 @@ static iBool load_FontPack_(iFontPack *d, const iString *ini) {
396 return ok; 397 return ok;
397} 398}
398 399
400iBool detect_FontPack(const iBlock *data) {
401 iBool ok = iFalse;
402 iArchive *zip = new_Archive();
403 if (openData_Archive(zip, data)) {
404 iString ini;
405 initBlock_String(&ini, dataCStr_Archive(zip, "fontpack.ini"));
406 if (isUtf8_Rangecc(range_String(&ini))) {
407 /* Validate the TOML syntax without actually checking any values. */
408 iTomlParser *toml = new_TomlParser();
409 ok = parse_TomlParser(toml, &ini);
410 delete_TomlParser(toml);
411 }
412 deinit_String(&ini);
413 }
414 iRelease(zip);
415 return ok;
416}
417
399iBool loadArchive_FontPack(iFontPack *d, const iArchive *zip) { 418iBool loadArchive_FontPack(iFontPack *d, const iArchive *zip) {
400 d->archive = zip; 419 d->archive = zip;
401 iBool ok = iFalse; 420 iBool ok = iFalse;
@@ -467,16 +486,24 @@ static void sortSpecs_Fonts_(iFonts *d) {
467 clear_PtrArray(&d->specOrder); 486 clear_PtrArray(&d->specOrder);
468 iConstForEach(PtrArray, p, &d->packs) { 487 iConstForEach(PtrArray, p, &d->packs) {
469 const iFontPack *pack = p.ptr; 488 const iFontPack *pack = p.ptr;
470 iConstForEach(Array, i, &pack->fonts) { 489 if (!contains_StringSet(prefs_App()->disabledFontPacks, &pack->id)) {
471 pushBack_PtrArray(&d->specOrder, i.value); 490 iConstForEach(Array, i, &pack->fonts) {
491 pushBack_PtrArray(&d->specOrder, i.value);
492 }
472 } 493 }
473 } 494 }
474 sort_Array(&d->specOrder, cmpPriority_FontSpecPtr_); 495 sort_Array(&d->specOrder, cmpPriority_FontSpecPtr_);
475} 496}
476 497
498static const iString *userFontsDirectory_Fonts_(const iFonts *d) {
499 return collect_String(concatCStr_Path(&d->userDir, "fonts"));
500}
501
477void init_Fonts(const char *userDir) { 502void init_Fonts(const char *userDir) {
478 iFonts *d = &fonts_; 503 iFonts *d = &fonts_;
479 initCStr_String(&d->userDir, userDir); 504 initCStr_String(&d->userDir, userDir);
505 const iString *userFontsDir = userFontsDirectory_Fonts_(d);
506 makeDirs_Path(userFontsDir);
480 init_PtrArray(&d->packs); 507 init_PtrArray(&d->packs);
481 d->files = new_ObjectList(); 508 d->files = new_ObjectList();
482 init_PtrArray(&d->specOrder); 509 init_PtrArray(&d->specOrder);
@@ -496,7 +523,7 @@ void init_Fonts(const char *userDir) {
496 "./fonts", 523 "./fonts",
497 "../share/lagrange", /* Note: These must match CMakeLists.txt install destination */ 524 "../share/lagrange", /* Note: These must match CMakeLists.txt install destination */
498 "../../share/lagrange", 525 "../../share/lagrange",
499 concatPath_CStr(userDir, "fonts"), 526 cstr_String(userFontsDir),
500 userDir, 527 userDir,
501 }; 528 };
502 const iString *execDir = collectNewRange_String(dirName_Path(execPath_App())); 529 const iString *execDir = collectNewRange_String(dirName_Path(execPath_App()));
@@ -555,7 +582,6 @@ void init_Fonts(const char *userDir) {
555void deinit_Fonts(void) { 582void deinit_Fonts(void) {
556 iFonts *d = &fonts_; 583 iFonts *d = &fonts_;
557 unloadFonts_Fonts_(d); 584 unloadFonts_Fonts_(d);
558 //unloadFiles_Fonts_(d);
559 iAssert(isEmpty_ObjectList(d->files)); 585 iAssert(isEmpty_ObjectList(d->files));
560 deinit_PtrArray(&d->specOrder); 586 deinit_PtrArray(&d->specOrder);
561 deinit_PtrArray(&d->packs); 587 deinit_PtrArray(&d->packs);
@@ -617,7 +643,18 @@ const iString *infoPage_Fonts(void) {
617 return str; 643 return str;
618} 644}
619 645
620const iFontPack *findPack_Fonts(const iString *path) { 646const iFontPack *pack_Fonts(const char *packId) {
647 iFonts *d = &fonts_;
648 iConstForEach(PtrArray, i, &d->packs) {
649 const iFontPack *pack = i.ptr;
650 if (!cmp_String(&pack->id, packId)) {
651 return pack;
652 }
653 }
654 return NULL;
655}
656
657const iFontPack *packByPath_Fonts(const iString *path) {
621 iFonts *d = &fonts_; 658 iFonts *d = &fonts_;
622 iConstForEach(PtrArray, i, &d->packs) { 659 iConstForEach(PtrArray, i, &d->packs) {
623 const iFontPack *pack = i.ptr; 660 const iFontPack *pack = i.ptr;
@@ -628,6 +665,28 @@ const iFontPack *findPack_Fonts(const iString *path) {
628 return NULL; 665 return NULL;
629} 666}
630 667
668void reload_Fonts(void) {
669 iFonts *d = &fonts_;
670 iString *userDir = copy_String(&d->userDir);
671 deinit_Fonts(); /* `d->userDir` is freed */
672 init_Fonts(cstr_String(userDir));
673 resetFonts_App();
674 invalidate_Window(get_MainWindow());
675 delete_String(userDir);
676}
677
678void install_Fonts(const iString *fontId, const iBlock *data) {
679 iFonts *d = &fonts_;
680 iFile *f = new_File(collect_String(concatCStr_Path(
681 userFontsDirectory_Fonts_(d), format_CStr("%s.fontpack", cstr_String(fontId)))));
682 if (open_File(f, writeOnly_FileMode)) {
683 write_File(f, data);
684 }
685 iRelease(f);
686 /* Newly installed fontpacks may have a higher priority that overrides other fonts. */
687 reload_Fonts();
688}
689
631iBool preloadLocalFontpackForPreview_Fonts(iGmDocument *doc) { 690iBool preloadLocalFontpackForPreview_Fonts(iGmDocument *doc) {
632 iBool wasLoaded = iFalse; 691 iBool wasLoaded = iFalse;
633 for (size_t linkId = 1; ; linkId++) { 692 for (size_t linkId = 1; ; linkId++) {
diff --git a/src/fontpack.h b/src/fontpack.h
index f69e2adc..2fdfa9ab 100644
--- a/src/fontpack.h
+++ b/src/fontpack.h
@@ -149,6 +149,7 @@ void setReadOnly_FontPack (iFontPack *, iBool readOnly);
149void setStandalone_FontPack (iFontPack *, iBool standalone); 149void setStandalone_FontPack (iFontPack *, iBool standalone);
150void setLoadPath_FontPack (iFontPack *, const iString *path); 150void setLoadPath_FontPack (iFontPack *, const iString *path);
151iBool loadArchive_FontPack (iFontPack *, const iArchive *zip); 151iBool loadArchive_FontPack (iFontPack *, const iArchive *zip);
152iBool detect_FontPack (const iBlock *data);
152 153
153iFontPackId id_FontPack (const iFontPack *); 154iFontPackId id_FontPack (const iFontPack *);
154const iPtrArray * listSpecs_FontPack (const iFontPack *); 155const iPtrArray * listSpecs_FontPack (const iFontPack *);
@@ -159,11 +160,18 @@ iDeclareType(GmDocument)
159void init_Fonts (const char *userDir); 160void init_Fonts (const char *userDir);
160void deinit_Fonts (void); 161void deinit_Fonts (void);
161 162
162const iFontPack * findPack_Fonts (const iString *path); 163const iFontPack * pack_Fonts (const char *packId);
164const iFontPack * packByPath_Fonts (const iString *path);
163const iFontSpec * findSpec_Fonts (const char *fontId); 165const iFontSpec * findSpec_Fonts (const char *fontId);
164const iPtrArray * listPacks_Fonts (void); 166const iPtrArray * listPacks_Fonts (void);
165const iPtrArray * listSpecs_Fonts (iBool (*filterFunc)(const iFontSpec *)); 167const iPtrArray * listSpecs_Fonts (iBool (*filterFunc)(const iFontSpec *));
166const iPtrArray * listSpecsByPriority_Fonts (void); 168const iPtrArray * listSpecsByPriority_Fonts (void);
167const iString * infoPage_Fonts (void); 169const iString * infoPage_Fonts (void);
170void install_Fonts (const iString *fontId, const iBlock *data);
171void reload_Fonts (void);
168 172
169iBool preloadLocalFontpackForPreview_Fonts (iGmDocument *doc); 173iBool preloadLocalFontpackForPreview_Fonts (iGmDocument *doc);
174
175iLocalDef iBool isInstalled_Fonts(const char *packId) {
176 return pack_Fonts(packId) != NULL;
177}
diff --git a/src/media.c b/src/media.c
index 0ce2ac5c..412205a7 100644
--- a/src/media.c
+++ b/src/media.c
@@ -312,15 +312,19 @@ void deinit_GmFontpack(iGmFontpack *d) {
312 312
313static void loadData_GmFontpack_(iGmFontpack *d, const iBlock *data) { 313static void loadData_GmFontpack_(iGmFontpack *d, const iBlock *data) {
314 const iString *loadPath = collect_String(localFilePathFromUrl_String(&d->props.url)); 314 const iString *loadPath = collect_String(localFilePathFromUrl_String(&d->props.url));
315 const iFontPack *pack = findPack_Fonts(loadPath); 315 const iFontPack *pack = packByPath_Fonts(loadPath);
316 d->info.isValid = d->info.isInstalled = pack != NULL; 316 d->info.isValid = d->info.isInstalled = pack != NULL;
317 d->info.isReadOnly = iFalse; 317 d->info.isReadOnly = iFalse;
318 d->info.isDisabled = iFalse;
319 clear_StringList(d->info.names);
320 clear_String(&d->packId);
318 if (!pack) { 321 if (!pack) {
319 /* Let's load it now temporarily and see what's inside. */ 322 /* Let's load it now temporarily and see what's inside. */
320 iArchive *zip = new_Archive(); 323 iArchive *zip = new_Archive();
321 if (openData_Archive(zip, data)) { 324 if (openData_Archive(zip, data)) {
322 iFontPack *fp = collect_FontPack(new_FontPack()); 325 iFontPack *fp = collect_FontPack(new_FontPack());
323 setLoadPath_FontPack(fp, loadPath); 326 setLoadPath_FontPack(fp, loadPath);
327 /* TODO: No need to load all the font files here, just the metadata. */
324 setStandalone_FontPack(fp, iTrue); 328 setStandalone_FontPack(fp, iTrue);
325 if (loadArchive_FontPack(fp, zip)) { 329 if (loadArchive_FontPack(fp, zip)) {
326 d->info.isValid = iTrue; 330 d->info.isValid = iTrue;
@@ -334,6 +338,7 @@ static void loadData_GmFontpack_(iGmFontpack *d, const iBlock *data) {
334 d->info.packId.id = &d->packId; /* we own this String */ 338 d->info.packId.id = &d->packId; /* we own this String */
335 d->info.packId.version = id_FontPack(pack).version; 339 d->info.packId.version = id_FontPack(pack).version;
336 d->info.isReadOnly = isReadOnly_FontPack(pack); 340 d->info.isReadOnly = isReadOnly_FontPack(pack);
341 d->info.isDisabled = contains_StringSet(prefs_App()->disabledFontPacks, &d->packId);
337 } 342 }
338 iPtrSet *unique = new_PtrSet(); 343 iPtrSet *unique = new_PtrSet();
339 iConstForEach(PtrArray, i, listSpecs_FontPack(pack)) { 344 iConstForEach(PtrArray, i, listSpecs_FontPack(pack)) {
@@ -455,7 +460,7 @@ iBool setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo
455 const iBool isPartial = (flags & partialData_MediaFlag) != 0; 460 const iBool isPartial = (flags & partialData_MediaFlag) != 0;
456 const iBool allowHide = (flags & allowHide_MediaFlag) != 0; 461 const iBool allowHide = (flags & allowHide_MediaFlag) != 0;
457 const iBool isDeleting = (!mime || !data); 462 const iBool isDeleting = (!mime || !data);
458 iMediaId existing = findMediaForLink_Media(d, linkId, none_MediaType);// findLinkImage_Media(d, linkId); 463 iMediaId existing = findMediaForLink_Media(d, linkId, none_MediaType);
459 const size_t existingIndex = index_MediaId(existing); 464 const size_t existingIndex = index_MediaId(existing);
460 iBool isNew = iFalse; 465 iBool isNew = iFalse;
461 if (existing.type == image_MediaType) { 466 if (existing.type == image_MediaType) {
@@ -574,17 +579,34 @@ static iMediaId findMediaPtr_Media_(const iPtrArray *items, enum iMediaType medi
574 579
575iMediaId findMediaForLink_Media(const iMedia *d, iGmLinkId linkId, enum iMediaType mediaType) { 580iMediaId findMediaForLink_Media(const iMedia *d, iGmLinkId linkId, enum iMediaType mediaType) {
576 /* TODO: Use hashes, this will get very slow if there is a large number of media items. */ 581 /* TODO: Use hashes, this will get very slow if there is a large number of media items. */
577 iMediaId mid; 582 iMediaId mid = iInvalidMediaId;
578 for (int i = 0; i < max_MediaType; i++) { 583 for (int i = 0; i < max_MediaType; i++) {
579 if (mediaType == i || !mediaType) { 584 if (mediaType == i || !mediaType) {
580 mid = findMediaPtr_Media_(&d->items[i], i, linkId); 585 mid = findMediaPtr_Media_(&d->items[i], i, linkId);
581 if (mid.type) { 586 if (mid.type) {
582 return mid; 587 break;
583 } 588 }
584 } 589 }
585 } 590 }
586 return iInvalidMediaId; 591 return mid;
592}
593
594#if 0
595iMediaId findUrl_Media(const iMedia *d, const iString *url) {
596 iMediaId mid = iInvalidMediaId;
597 for (int i = 0; i < max_MediaType; i++) {
598 for (int j = 0; j < size_PtrArray(&d->items[i]); j++) {
599 const iGmMediaProps *props = constAt_PtrArray(&d->items[i], j);
600 if (equal_String(&props->url, url)) {
601 mid.type = i;
602 mid.id = j + 1;
603 break;
604 }
605 }
606 }
607 return mid;
587} 608}
609#endif
588 610
589size_t numAudio_Media(const iMedia *d) { 611size_t numAudio_Media(const iMedia *d) {
590 return size_PtrArray(&d->items[audio_MediaType]); 612 return size_PtrArray(&d->items[audio_MediaType]);
diff --git a/src/media.h b/src/media.h
index 47a4da93..92a46cd3 100644
--- a/src/media.h
+++ b/src/media.h
@@ -74,6 +74,7 @@ iBool setData_Media (iMedia *, uint16_t linkId, const iStrin
74 74
75size_t memorySize_Media (const iMedia *); 75size_t memorySize_Media (const iMedia *);
76iMediaId findMediaForLink_Media (const iMedia *, uint16_t linkId, enum iMediaType mediaType); 76iMediaId findMediaForLink_Media (const iMedia *, uint16_t linkId, enum iMediaType mediaType);
77//iMediaId findUrl_Media (const iMedia *, const iString *url);
77 78
78iMediaId id_Media (const iMedia *, uint16_t linkId, enum iMediaType type); 79iMediaId id_Media (const iMedia *, uint16_t linkId, enum iMediaType type);
79iBool info_Media (const iMedia *, iMediaId mediaId, iGmMediaInfo *info_out); 80iBool info_Media (const iMedia *, iMediaId mediaId, iGmMediaInfo *info_out);
@@ -114,6 +115,7 @@ struct Impl_FontpackMediaInfo {
114 iFontPackId packId; 115 iFontPackId packId;
115 iBool isValid; 116 iBool isValid;
116 iBool isInstalled; 117 iBool isInstalled;
118 iBool isDisabled;
117 iBool isReadOnly; 119 iBool isReadOnly;
118 size_t sizeInBytes; 120 size_t sizeInBytes;
119 iStringList *names; 121 iStringList *names;
diff --git a/src/prefs.c b/src/prefs.c
index 673470d6..523ec649 100644
--- a/src/prefs.c
+++ b/src/prefs.c
@@ -60,6 +60,7 @@ void init_Prefs(iPrefs *d) {
60 setCStr_String(&d->strings[bodyFont_PrefsString], "default"); 60 setCStr_String(&d->strings[bodyFont_PrefsString], "default");
61 setCStr_String(&d->strings[monospaceFont_PrefsString], "iosevka"); 61 setCStr_String(&d->strings[monospaceFont_PrefsString], "iosevka");
62 setCStr_String(&d->strings[monospaceDocumentFont_PrefsString], "iosevka-body"); 62 setCStr_String(&d->strings[monospaceDocumentFont_PrefsString], "iosevka-body");
63 d->disabledFontPacks = new_StringSet();
63 d->fontSmoothing = iTrue; 64 d->fontSmoothing = iTrue;
64 d->gemtextAnsiEscapes = iFalse; 65 d->gemtextAnsiEscapes = iFalse;
65 d->monospaceGemini = iFalse; 66 d->monospaceGemini = iFalse;
@@ -88,6 +89,7 @@ void init_Prefs(iPrefs *d) {
88} 89}
89 90
90void deinit_Prefs(iPrefs *d) { 91void deinit_Prefs(iPrefs *d) {
92 iRelease(d->disabledFontPacks);
91 iForIndices(i, d->strings) { 93 iForIndices(i, d->strings) {
92 deinit_String(&d->strings[i]); 94 deinit_String(&d->strings[i]);
93 } 95 }
diff --git a/src/prefs.h b/src/prefs.h
index 70846be4..bbf98370 100644
--- a/src/prefs.h
+++ b/src/prefs.h
@@ -22,7 +22,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22 22
23#pragma once 23#pragma once
24 24
25#include <the_Foundation/string.h> 25#include <the_Foundation/stringset.h>
26 26
27#include "gmdocument.h" 27#include "gmdocument.h"
28#include "ui/color.h" 28#include "ui/color.h"
@@ -87,6 +87,7 @@ struct Impl_Prefs {
87 int maxCacheSize; /* MB */ 87 int maxCacheSize; /* MB */
88 int maxMemorySize; /* MB */ 88 int maxMemorySize; /* MB */
89 /* Style */ 89 /* Style */
90 iStringSet * disabledFontPacks;
90 iBool fontSmoothing; 91 iBool fontSmoothing;
91 iBool gemtextAnsiEscapes; 92 iBool gemtextAnsiEscapes;
92 iBool monospaceGemini; 93 iBool monospaceGemini;
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 924dc0c4..1aca895c 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -2916,6 +2916,27 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2916 updateMedia_DocumentWidget_(d); 2916 updateMedia_DocumentWidget_(d);
2917 return iFalse; 2917 return iFalse;
2918 } 2918 }
2919 else if (equal_Command(cmd, "media.fontpack.updated")) {
2920 iMedia *media = pointerLabel_Command(cmd, "media");
2921 if (media == media_GmDocument(d->doc)) {
2922 /*iGmMediaInfo info;
2923 if (info_Media(media,
2924 (iMediaId){ fontpack_MediaType, argU32Label_Command(cmd, "id")},
2925 &info)) {
2926
2927 }*/
2928
2929// findCachedContent_App(<#const iString *url#>, <#iString *mime_out#>, <#iBlock *data_out#>)
2930// setData_Media(media,
2931 }
2932 return iFalse;
2933 }
2934 else if (equal_Command(cmd, "media.fontpack.install")) {
2935 if (pointerLabel_Command(cmd, "media") == media_GmDocument(d->doc)) {
2936 /* TODO: This is ours, we may have a MediaRequest with the data in memory. */
2937 }
2938 return iFalse;
2939 }
2919 else if (equal_Command(cmd, "document.stop") && document_App() == d) { 2940 else if (equal_Command(cmd, "document.stop") && document_App() == d) {
2920 if (cancelRequest_DocumentWidget_(d, iTrue /* navigate back */)) { 2941 if (cancelRequest_DocumentWidget_(d, iTrue /* navigate back */)) {
2921 return iTrue; 2942 return iTrue;
@@ -5169,6 +5190,28 @@ void updateSize_DocumentWidget(iDocumentWidget *d) {
5169 invalidate_DocumentWidget_(d); 5190 invalidate_DocumentWidget_(d);
5170} 5191}
5171 5192
5193iBool findCachedContent_DocumentWidget(const iDocumentWidget *d, const iString *url,
5194 iString *mime_out, iBlock *data_out) {
5195 if (equal_String(d->mod.url, url) && !isRequestOngoing_DocumentWidget(d)) {
5196 /* It's the currently open page. */
5197 set_String(mime_out, &d->sourceMime);
5198 set_Block(data_out, &d->sourceContent);
5199 return iTrue;
5200 }
5201 /* Finished media requests are kept in memory while the page is open. */
5202 iConstForEach(ObjectList, i, d->media) {
5203 const iMediaRequest *mr = i.object;
5204 if (mr->req &&
5205 isFinished_GmRequest(mr->req) &&
5206 equal_String(linkUrl_GmDocument(d->doc, mr->linkId), url)) {
5207 set_String(mime_out, meta_GmRequest(mr->req));
5208 set_Block(data_out, body_GmRequest(mr->req));
5209 return iTrue;
5210 }
5211 }
5212 return iFalse;
5213}
5214
5172iBeginDefineSubclass(DocumentWidget, Widget) 5215iBeginDefineSubclass(DocumentWidget, Widget)
5173 .processEvent = (iAny *) processEvent_DocumentWidget_, 5216 .processEvent = (iAny *) processEvent_DocumentWidget_,
5174 .draw = (iAny *) draw_DocumentWidget_, 5217 .draw = (iAny *) draw_DocumentWidget_,
diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h
index 1f2ecfc0..9bfab57a 100644
--- a/src/ui/documentwidget.h
+++ b/src/ui/documentwidget.h
@@ -48,6 +48,9 @@ const iString * bookmarkTitle_DocumentWidget (const iDocumentWidget *);
48const iString * feedTitle_DocumentWidget (const iDocumentWidget *); 48const iString * feedTitle_DocumentWidget (const iDocumentWidget *);
49int documentWidth_DocumentWidget (const iDocumentWidget *); 49int documentWidth_DocumentWidget (const iDocumentWidget *);
50 50
51iBool findCachedContent_DocumentWidget(const iDocumentWidget *, const iString *url,
52 iString *mime_out, iBlock *data_out);
53
51enum iDocumentWidgetSetUrlFlags { 54enum iDocumentWidgetSetUrlFlags {
52 useCachedContentIfAvailable_DocumentWidgetSetUrlFlag = iBit(1), 55 useCachedContentIfAvailable_DocumentWidgetSetUrlFlag = iBit(1),
53 openedFromSidebar_DocumentWidgetSetUrlFlag = iBit(2), 56 openedFromSidebar_DocumentWidgetSetUrlFlag = iBit(2),
diff --git a/src/ui/mediaui.c b/src/ui/mediaui.c
index aa45d73a..ac9475dd 100644
--- a/src/ui/mediaui.c
+++ b/src/ui/mediaui.c
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
28#include "paint.h" 28#include "paint.h"
29#include "util.h" 29#include "util.h"
30#include "lang.h" 30#include "lang.h"
31#include "app.h"
31 32
32#include <the_Foundation/path.h> 33#include <the_Foundation/path.h>
33#include <the_Foundation/stringlist.h> 34#include <the_Foundation/stringlist.h>
@@ -281,14 +282,28 @@ void draw_DownloadUI(const iDownloadUI *d, iPaint *p) {
281 282
282/*----------------------------------------------------------------------------------------------*/ 283/*----------------------------------------------------------------------------------------------*/
283 284
285static iMenuItem action_FontpackUI_(const iFontpackUI *d) {
286 if (d->info.isInstalled) {
287 return (iMenuItem){ d->info.isDisabled ? "${media.fontpack.enable}"
288 : close_Icon " ${media.fontpack.disable}",
289 0, 0, format_CStr("media.fontpack.enable arg:%d", d->info.isDisabled) };
290 }
291 return (iMenuItem){ d->info.isInstalled ? close_Icon " ${media.fontpack.disable}"
292 : "${media.fontpack.install}",
293 0, 0,
294 d->info.isInstalled ? "media.fontpack.enable arg:0" : "media.fontpack.install" };
295}
296
284void init_FontpackUI(iFontpackUI *d, const iMedia *media, uint16_t mediaId, iRect bounds) { 297void init_FontpackUI(iFontpackUI *d, const iMedia *media, uint16_t mediaId, iRect bounds) {
285 d->media = media; 298 d->media = media;
286 d->mediaId = mediaId; 299 d->mediaId = mediaId;
300 fontpackInfo_Media(d->media, (iMediaId){ fontpack_MediaType, d->mediaId }, &d->info);
287 d->bounds = bounds; 301 d->bounds = bounds;
288 d->installRect.size = add_I2(measure_Text(uiLabel_FontId, "${media.fontpack.install}").bounds.size, 302 iMenuItem action = action_FontpackUI_(d);
289 muli_I2(gap2_UI, 3)); 303 d->buttonRect.size = add_I2(measure_Text(uiLabel_FontId, action.label).bounds.size,
290 d->installRect.pos.x = right_Rect(d->bounds) - gap_UI - d->installRect.size.x; 304 muli_I2(gap2_UI, 3));
291 d->installRect.pos.y = mid_Rect(d->bounds).y - d->installRect.size.y / 2; 305 d->buttonRect.pos.x = right_Rect(d->bounds) - gap_UI - d->buttonRect.size.x;
306 d->buttonRect.pos.y = mid_Rect(d->bounds).y - d->buttonRect.size.y / 2;
292} 307}
293 308
294iBool processEvent_FontpackUI(iFontpackUI *d, const SDL_Event *ev) { 309iBool processEvent_FontpackUI(iFontpackUI *d, const SDL_Event *ev) {
@@ -296,7 +311,12 @@ iBool processEvent_FontpackUI(iFontpackUI *d, const SDL_Event *ev) {
296 case SDL_MOUSEBUTTONDOWN: 311 case SDL_MOUSEBUTTONDOWN:
297 case SDL_MOUSEBUTTONUP: { 312 case SDL_MOUSEBUTTONUP: {
298 const iInt2 pos = init_I2(ev->button.x, ev->button.y); 313 const iInt2 pos = init_I2(ev->button.x, ev->button.y);
299 if (contains_Rect(d->installRect, pos)) { 314 if (contains_Rect(d->buttonRect, pos)) {
315 if (ev->type == SDL_MOUSEBUTTONUP) {
316 postCommandf_App("%s media:%p mediaid:%u packid:%s",
317 action_FontpackUI_(d).command,
318 d->media, d->mediaId, cstr_String(d->info.packId.id));
319 }
300 return iTrue; 320 return iTrue;
301 } 321 }
302 break; 322 break;
@@ -322,24 +342,22 @@ void draw_FontpackUI(const iFontpackUI *d, iPaint *p) {
322 /* Draw a background box. */ 342 /* Draw a background box. */
323 fillRect_Paint(p, d->bounds, uiBackground_ColorId); 343 fillRect_Paint(p, d->bounds, uiBackground_ColorId);
324 drawRect_Paint(p, d->bounds, uiSeparator_ColorId); 344 drawRect_Paint(p, d->bounds, uiSeparator_ColorId);
325 iFontpackMediaInfo info;
326 fontpackInfo_Media(d->media, (iMediaId){ fontpack_MediaType, d->mediaId }, &info);
327 iInt2 pos = topLeft_Rect(d->bounds); 345 iInt2 pos = topLeft_Rect(d->bounds);
328 const char *checks[] = { "\u2610", "\u2611" }; 346 const char *checks[] = { "\u2610", "\u2611" };
329 draw_Text(uiContentBold_FontId, pos, uiHeading_ColorId, "\"%s\" v%d", 347 draw_Text(uiContentBold_FontId, pos,
330 cstr_String(info.packId.id), info.packId.version); 348 d->info.isDisabled ? uiText_ColorId : uiHeading_ColorId, "\"%s\" v%d",
349 cstr_String(d->info.packId.id), d->info.packId.version);
331 pos.y += lineHeight_Text(uiContentBold_FontId); 350 pos.y += lineHeight_Text(uiContentBold_FontId);
332 draw_Text(uiLabelBold_FontId, pos, uiText_ColorId, "%.1f MB, %d fonts %s %s %s", 351 draw_Text(uiLabelBold_FontId, pos, uiText_ColorId, "%.1f MB, %d fonts %s %s %s",
333 info.sizeInBytes / 1.0e6, size_StringList(info.names), 352 d->info.sizeInBytes / 1.0e6, size_StringList(d->info.names),
334// checks[info.isValid], info.isValid ? "No errors" : "Errors detected", 353// checks[info.isValid], info.isValid ? "No errors" : "Errors detected",
335 checks[info.isInstalled], info.isInstalled ? "Installed" : "Not installed", 354 checks[d->info.isInstalled], d->info.isInstalled ? "Installed" : "Not installed",
336 info.isReadOnly ? "Read-Only" : ""); 355 d->info.isReadOnly ? "Read-Only" : "");
337 pos.y += lineHeight_Text(uiLabelBold_FontId); 356 pos.y += lineHeight_Text(uiLabelBold_FontId);
338 iConstForEach(StringList, i, info.names) { 357 iConstForEach(StringList, i, d->info.names) {
339 drawRange_Text(uiLabel_FontId, pos, uiText_ColorId, range_String(i.value)); 358 drawRange_Text(uiLabel_FontId, pos, uiText_ColorId, range_String(i.value));
340 pos.y += lineHeight_Text(uiLabel_FontId); 359 pos.y += lineHeight_Text(uiLabel_FontId);
341 } 360 }
342 /* Buttons. */ 361 /* Buttons. */
343 drawInlineButton_(p, d->installRect, 362 drawInlineButton_(p, d->buttonRect, action_FontpackUI_(d).label, uiLabel_FontId);
344 "${media.fontpack.install}", uiLabel_FontId);
345} 363}
diff --git a/src/ui/mediaui.h b/src/ui/mediaui.h
index 73de1994..03ea0afc 100644
--- a/src/ui/mediaui.h
+++ b/src/ui/mediaui.h
@@ -22,6 +22,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22 22
23#pragma once 23#pragma once
24 24
25#include "../media.h"
26
25#include <the_Foundation/rect.h> 27#include <the_Foundation/rect.h>
26#include <SDL_events.h> 28#include <SDL_events.h>
27 29
@@ -46,8 +48,6 @@ void draw_PlayerUI (iPlayerUI *, iPaint *p);
46 48
47/*----------------------------------------------------------------------------------------------*/ 49/*----------------------------------------------------------------------------------------------*/
48 50
49iDeclareType(DocumentWidget)
50iDeclareType(Media)
51iDeclareType(DownloadUI) 51iDeclareType(DownloadUI)
52 52
53struct Impl_DownloadUI { 53struct Impl_DownloadUI {
@@ -67,8 +67,9 @@ iDeclareType(FontpackUI)
67struct Impl_FontpackUI { 67struct Impl_FontpackUI {
68 const iMedia *media; 68 const iMedia *media;
69 uint16_t mediaId; 69 uint16_t mediaId;
70 iFontpackMediaInfo info;
70 iRect bounds; 71 iRect bounds;
71 iRect installRect; 72 iRect buttonRect;
72}; 73};
73 74
74void init_FontpackUI (iFontpackUI *, const iMedia *media, uint16_t mediaId, iRect bounds); 75void init_FontpackUI (iFontpackUI *, const iMedia *media, uint16_t mediaId, iRect bounds);