From 960df03c17091aca37f53eaab8fc27c669d26a5e Mon Sep 17 00:00:00 2001

From: =?UTF-8?q?Jaakko=20Kera=CC=88nen?= jaakko.keranen@iki.fi

Date: Mon, 11 Oct 2021 12:22:54 +0300

Subject: [PATCH 1/1] Media refactoring; working on FontPack management

Media still needs more work to get rid of redundancies and make lookups faster.

FontPacks are manipulated as Media items (not unlike images) so they can be previewed on page, and installed via a click.

FontPack management is not trivial as it includes such details as versioning and whether individual packs are enabled or disabled.


res/arabic.fontpack/fontpack.ini | 2 +

res/cjk.fontpack/fontpack.ini | 2 +

res/default.fontpack/fontpack.ini | 2 +

res/firasans.fontpack/fontpack.ini | 2 +

res/literata.fontpack/fontpack.ini | 2 +

res/nunito.fontpack/fontpack.ini | 2 +

res/tinos.fontpack/fontpack.ini | 2 +

src/app.c | 1 +

src/defs.h | 4 +-

src/fontpack.c | 299 ++++++++++++++------

src/fontpack.h | 65 ++++-

src/gempub.c | 2 +-

src/gmdocument.c | 159 +++++------

src/gmdocument.h | 16 +-

src/gmrequest.c | 9 +-

src/gmutil.c | 8 +-

src/media.c | 349 +++++++++++++++--------

src/media.h | 92 +++++--

src/ui/documentwidget.c | 429 ++++++++++++++++-------------

src/ui/documentwidget.h | 2 +

src/ui/mediaui.c | 88 +++++-

src/ui/mediaui.h | 20 +-

22 files changed, 1030 insertions(+), 527 deletions(-)

diff --git a/res/arabic.fontpack/fontpack.ini b/res/arabic.fontpack/fontpack.ini

index 00ad5241..305878ce 100644

--- a/res/arabic.fontpack/fontpack.ini

+++ b/res/arabic.fontpack/fontpack.ini

@@ -1,3 +1,5 @@

+version = 1

[arabic]

name = "Noto Sans Arabic UI"

auxiliary = true

diff --git a/res/cjk.fontpack/fontpack.ini b/res/cjk.fontpack/fontpack.ini

index fbac54be..6e0d274c 100644

--- a/res/cjk.fontpack/fontpack.ini

+++ b/res/cjk.fontpack/fontpack.ini

@@ -1,3 +1,5 @@

+version = 1

[notosansjp]

name = "Noto Sans JP"

auxiliary = true

diff --git a/res/default.fontpack/fontpack.ini b/res/default.fontpack/fontpack.ini

index 68316ef6..f8ef31ce 100644

--- a/res/default.fontpack/fontpack.ini

+++ b/res/default.fontpack/fontpack.ini

@@ -17,6 +17,8 @@

glyphscale and voffset can also be specified separately for the UI and

document domains by prefixing ui. or doc. to the key.

+version = 1

[default]

name = "Source Sans"

regular = "SourceSans3-Regular.ttf"

diff --git a/res/firasans.fontpack/fontpack.ini b/res/firasans.fontpack/fontpack.ini

index 4378a757..c6eb4c77 100644

--- a/res/firasans.fontpack/fontpack.ini

+++ b/res/firasans.fontpack/fontpack.ini

@@ -1,3 +1,5 @@

+version = 1

[firasans]

name = "Fira Sans"

glyphscale = 0.85

diff --git a/res/literata.fontpack/fontpack.ini b/res/literata.fontpack/fontpack.ini

index e4e49bcb..7c29491d 100644

--- a/res/literata.fontpack/fontpack.ini

+++ b/res/literata.fontpack/fontpack.ini

@@ -1,3 +1,5 @@

+version = 1

[literata]

name = "Literata"

regular = "Literata-Regular-opsz=14.ttf"

diff --git a/res/nunito.fontpack/fontpack.ini b/res/nunito.fontpack/fontpack.ini

index ea4a12b8..2f2471e1 100644

--- a/res/nunito.fontpack/fontpack.ini

+++ b/res/nunito.fontpack/fontpack.ini

@@ -1,3 +1,5 @@

+version = 1

[nunito]

name = "Nunito"

tweaks = 0x1 # some hardcoded kerning changes (Th, etc.)

diff --git a/res/tinos.fontpack/fontpack.ini b/res/tinos.fontpack/fontpack.ini

index 8759b752..a2cf811e 100644

--- a/res/tinos.fontpack/fontpack.ini

+++ b/res/tinos.fontpack/fontpack.ini

@@ -1,3 +1,5 @@

+version = 1

[tinos]

name = "Tinos"

glyphscale = 0.850

diff --git a/src/app.c b/src/app.c

index b317e7b3..cb5479e8 100644

--- a/src/app.c

+++ b/src/app.c

@@ -2669,6 +2669,7 @@ iBool handleCommand_App(const char *cmd) {

     const iBool isSplit = numRoots_Window(get_Window()) > 1;

     if (tabCount_Widget(tabs) > 1 || isSplit) {

         iWidget *closed = removeTabPage_Widget(tabs, index);

         destroy_Widget(closed); /* released later */

         if (index == tabCount_Widget(tabs)) {

             index--;

diff --git a/src/defs.h b/src/defs.h

index 65096389..f5479cf3 100644

--- a/src/defs.h

+++ b/src/defs.h

@@ -125,11 +125,13 @@ iLocalDef int acceptKeyMod_ReturnKeyBehavior(int behavior) {

#define delete_Icon "\u232b"

#define copy_Icon "\u2398" //"\u2bba"

#define check_Icon "\u2714"

-#define ballotCheck_Icon "\U0001f5f9"

+#define ballotChecked_Icon "\U0001f5f9"

+#define ballotUnchecked_Icon "\U0001f5f9"

#define inbox_Icon "\U0001f4e5"

#define book_Icon "\U0001f56e"

#define bookmark_Icon "\U0001f516"

#define folder_Icon "\U0001f4c1"

+#define file_Icon "\U0001f5ce"

#define openTab_Icon "\u2750"

#define openTabBg_Icon "\u2b1a"

#define openExt_Icon "\u27a0"

diff --git a/src/fontpack.c b/src/fontpack.c

index ca1d1582..fb1c98ee 100644

--- a/src/fontpack.c

+++ b/src/fontpack.c

@@ -33,7 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#include <the_Foundation/string.h>

#include <the_Foundation/toml.h>

-/* TODO: Clean up and/or reorder this file, it's a bit unorganized. */

+const char *mimeType_FontPack = "application/lagrange-fontpack+zip";

float scale_FontSize(enum iFontSize size) {

 static const float sizes[max_FontSize] = {

@@ -57,38 +57,9 @@ float scale_FontSize(enum iFontSize size) {

 return sizes[size];

}

-iDeclareType(Fonts)

-struct Impl_Fonts {

-};

-static iFonts fonts_;

-static void unloadFiles_Fonts_(iFonts *d) {

-}

-static iFontFile *findFile_Fonts_(iFonts *d, const iString *id) {

-}

/----------------------------------------------------------------------------------------------/

-iDefineTypeConstruction(FontFile)

+iDefineObjectConstruction(FontFile)

void init_FontFile(iFontFile *d) {

 init_String(&d->id);

@@ -114,7 +85,7 @@ static void load_FontFile_(iFontFile *d, const iBlock *data) {

                            HB_MEMORY_MODE_READONLY, NULL, NULL);

 d->hbFace = hb_face_create(d->hbBlob, 0);

 d->hbFont = hb_font_create(d->hbFace);

-#endif

+#endif

}

static void unload_FontFile_(iFontFile *d) {

@@ -126,12 +97,13 @@ static void unload_FontFile_(iFontFile *d) {

 d->hbFont = NULL;

 d->hbFace = NULL;

 d->hbBlob = NULL;

-#endif

+#endif

 clear_Block(&d->sourceData);

 iZap(d->stbInfo);

}

void deinit_FontFile(iFontFile *d) {

 unload_FontFile_(d);

 deinit_Block(&d->sourceData);

 deinit_String(&d->id);

@@ -156,12 +128,12 @@ void measureGlyph_FontFile(const iFontFile *d, uint32_t glyphIndex,

/----------------------------------------------------------------------------------------------/

iDefineTypeConstruction(FontSpec)

void init_FontSpec(iFontSpec *d) {

 init_String(&d->id);

 init_String(&d->name);

 d->flags      = 0;

 d->priority   = 0;

 for (int i = 0; i < 2; ++i) {

@@ -173,52 +145,119 @@ void init_FontSpec(iFontSpec *d) {

}

void deinit_FontSpec(iFontSpec *d) {

 deinit_String(&d->name);

 deinit_String(&d->id);

}

/----------------------------------------------------------------------------------------------/

-iDeclareType(FontPack)

-iDeclareTypeConstruction(FontPack)

+iDeclareType(Fonts)

+struct Impl_Fonts {

+};

+static iFonts fonts_;

+static void unloadFiles_Fonts_(iFonts *d) {

+}

+static iFontFile *findFile_Fonts_(iFonts *d, const iString *id) {

+}

+static void releaseUnusedFiles_Fonts_(iFonts *d) {

+}

+/----------------------------------------------------------------------------------------------/

struct Impl_FontPack {

 iArray          fonts;   /* array of FontSpecs */

 iString *       loadPath;

 iFontSpec *     loadSpec;

};

+iDefineTypeConstruction(FontPack)

void init_FontPack(iFontPack *d) {

 init_Array(&d->fonts, sizeof(iFontSpec));

 d->loadSpec = NULL;

 d->loadPath = NULL;

}

void deinit_FontPack(iFontPack *d) {

 delete_String(d->loadPath);

 iForEach(Array, i, &d->fonts) {

     deinit_FontSpec(i.value);

 }

 deinit_Array(&d->fonts);

}

-iDefineTypeConstruction(FontPack)

+iFontPackId id_FontPack(const iFontPack *d) {

+}

+const iPtrArray *listSpecs_FontPack(const iFontPack *d) {

+}

void handleIniTable_FontPack_(void *context, const iString *table, iBool isStart) {

 iFontPack *d = context;

 if (isStart) {

     iAssert(!d->loadSpec);

         d->loadSpec = new_FontSpec();

         set_String(&d->loadSpec->id, table);

     }

 }

     /* Set fallback font files. */ {

         const iFontFile **styles = d->loadSpec->styles;

         if (!styles[regular_FontStyle]) {

@@ -229,11 +268,11 @@ void handleIniTable_FontPack_(void *context, const iString *table, iBool isStart

             return;

         }

         if (!styles[semiBold_FontStyle]) {

         }

         for (size_t s = 0; s < max_FontStyle; s++) {

             if (!styles[s]) {

             }

         }

     }

@@ -263,7 +302,15 @@ static iBlock *readFile_FontPack_(const iFontPack *d, const iString *path) {

void handleIniKeyValue_FontPack_(void *context, const iString *table, const iString *key,

                              const iTomlValue *value) {

 iFontPack *d = context;

 iUnused(table);

 if (!cmp_String(key, "name") && value->type == string_TomlType) {

     set_String(&d->loadSpec->name, value->value.string);        

@@ -322,12 +369,13 @@ void handleIniKeyValue_FontPack_(void *context, const iString *table, const iStr

                     ff = new_FontFile();

                     set_String(&ff->id, fontFileId);

                     load_FontFile_(ff, data);

                     delete_Block(data);

// printf("[FontPack] loaded file: %s\n", cstr_String(fontFileId));

                 }

             }

             delete_String(fontFileId);

             break;

         }

@@ -348,29 +396,6 @@ static iBool load_FontPack_(iFontPack *d, const iString *ini) {

 return ok;

}

-#if 0

-iBool loadIniFile_FontPack(iFontPack *d, const iString *iniPath) {

-}

-#endif

iBool loadArchive_FontPack(iFontPack *d, const iArchive *zip) {

 d->archive = zip;

 iBool ok = iFalse;

@@ -387,6 +412,28 @@ iBool loadArchive_FontPack(iFontPack *d, const iArchive *zip) {

 return ok;

}

+void setLoadPath_FontPack(iFontPack *d, const iString *path) {

+}

+void setStandalone_FontPack(iFontPack *d, iBool standalone) {

+}

+void setReadOnly_FontPack(iFontPack *d, iBool readOnly) {

+}

+iBool isReadOnly_FontPack(const iFontPack *d) {

+}

/----------------------------------------------------------------------------------------------/

static void unloadFonts_Fonts_(iFonts *d) {

@@ -397,14 +444,23 @@ static void unloadFonts_Fonts_(iFonts *d) {

 clear_PtrArray(&d->packs);

}

+static int cmpName_FontSpecPtr_(const void *a, const void *b) {

+}

static int cmpPriority_FontSpecPtr_(const void *a, const void *b) {

 const iFontSpec **p1 = (const iFontSpec **) a, **p2 = (const iFontSpec **) b;

}

-static int cmpName_FontSpecPtr_(const void *a, const void *b) {

+static int cmpSourceAndPriority_FontSpecPtr_(const void *a, const void *b) {

 const iFontSpec **p1 = (const iFontSpec **) a, **p2 = (const iFontSpec **) b;

}

static void sortSpecs_Fonts_(iFonts *d) {

@@ -422,11 +478,13 @@ void init_Fonts(const char *userDir) {

 iFonts *d = &fonts_;

 initCStr_String(&d->userDir, userDir);

 init_PtrArray(&d->packs);

 init_PtrArray(&d->specOrder);

 /* Load the required fonts. */ {

     iFontPack *pack = new_FontPack();

     iArchive *arch = new_Archive();

     openData_Archive(arch, &fontpackDefault_Embedded);

     loadArchive_FontPack(pack, arch); /* should never fail if we've made it this far */

     iRelease(arch);

@@ -436,7 +494,7 @@ void init_Fonts(const char *userDir) {

     const char *locations[] = {

         ".",

         "./fonts",

         "../../share/lagrange",

         concatPath_CStr(userDir, "fonts"),

         userDir,

@@ -450,7 +508,13 @@ void init_Fonts(const char *userDir) {

                 iArchive *arch = new_Archive();

                 if (openFile_Archive(arch, entryPath)) {

                     iFontPack *pack = new_FontPack();

+#if defined (iPlatformApple)

+#endif

                     if (loadArchive_FontPack(pack, arch)) {

                         pushBack_PtrArray(&d->packs, pack);

                     }

@@ -491,13 +555,18 @@ void init_Fonts(const char *userDir) {

void deinit_Fonts(void) {

 iFonts *d = &fonts_;

 unloadFonts_Fonts_(d);

 deinit_PtrArray(&d->specOrder);

 deinit_PtrArray(&d->packs);

 deinit_String(&d->userDir);

}

+const iPtrArray *listPacks_Fonts(void) {

+}

const iFontSpec *findSpec_Fonts(const char *fontId) {

 iFonts *d = &fonts_;

 iConstForEach(PtrArray, i, &d->specOrder) {

@@ -524,3 +593,73 @@ const iPtrArray *listSpecs_Fonts(iBool (*filterFunc)(const iFontSpec *)) {

const iPtrArray *listSpecsByPriority_Fonts(void) {

 return &fonts_.specOrder;

}

+const iString *infoPage_Fonts(void) {

+}

+const iFontPack *findPack_Fonts(const iString *path) {

+}

+iBool preloadLocalFontpackForPreview_Fonts(iGmDocument *doc) {

+}

+iDefineClass(FontFile)

diff --git a/src/fontpack.h b/src/fontpack.h

index e59154e3..429afb5d 100644

--- a/src/fontpack.h

+++ b/src/fontpack.h

@@ -30,6 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

include <hb.h>

#endif

+extern const char *mimeType_FontPack;

/* Fontpacks are ZIP archives that contain a configuration file and one of more font

files. The fontpack format is used instead of plain TTF/OTF because the text renderer

uses additional metadata about each font.

@@ -68,21 +70,13 @@ enum iFontStyle {

float scale_FontSize (enum iFontSize size);

-iDeclareType(FontSpec)

-iDeclareTypeConstruction(FontSpec)

+/----------------------------------------------------------------------------------------------/

-enum iFontSpecFlags {

-};

-iDeclareType(FontFile)

-iDeclareTypeConstruction(FontFile)

+iDeclareClass(FontFile)

+iDeclareObjectConstruction(FontFile)

struct Impl_FontFile {

 iString         id; /* for detecting when the same file is used in many places */

 enum iFontStyle style;

 iBlock          sourceData;

@@ -107,9 +101,26 @@ uint8_t * rasterizeGlyph_FontFile(const iFontFile *, float xScale, float yScal

void measureGlyph_FontFile (const iFontFile *, uint32_t glyphIndex,

                                 float xScale, float yScale, float xShift,

                                 int *x0, int *y0, int *x1, int *y1);

+/----------------------------------------------------------------------------------------------/

+/* FontSpec describes a typeface, combining multiple fonts into a group.

+iDeclareType(FontSpec)

+iDeclareTypeConstruction(FontSpec)

+enum iFontSpecFlags {

+};

struct Impl_FontSpec {

 iString id;   /* unique ID */

 iString name; /* human-readable label */

 int     flags;

 int     priority;

 float   heightScale[2];     /* overall height scaling; ui, document */

@@ -121,10 +132,38 @@ struct Impl_FontSpec {

iLocalDef int scaleType_FontSpec(enum iFontSize sizeId) {

 return sizeId / contentRegular_FontSize;

}

+/----------------------------------------------------------------------------------------------/

+iDeclareType(FontPack)

+iDeclareTypeConstruction(FontPack)

+iDeclareType(FontPackId)

+struct Impl_FontPackId {

+};

+void setReadOnly_FontPack (iFontPack *, iBool readOnly);

+void setStandalone_FontPack (iFontPack *, iBool standalone);

+void setLoadPath_FontPack (iFontPack *, const iString *path);

+iBool loadArchive_FontPack (iFontPack *, const iArchive *zip);

+iFontPackId id_FontPack (const iFontPack *);

+const iPtrArray * listSpecs_FontPack (const iFontPack *);

+iBool isReadOnly_FontPack (const iFontPack *);

+iDeclareType(GmDocument)

void init_Fonts (const char *userDir);

void deinit_Fonts (void);

+const iFontPack * findPack_Fonts (const iString *path);

const iFontSpec * findSpec_Fonts (const char *fontId);

+const iPtrArray * listPacks_Fonts (void);

const iPtrArray * listSpecs_Fonts (iBool (*filterFunc)(const iFontSpec *));

const iPtrArray * listSpecsByPriority_Fonts (void);

+const iString * infoPage_Fonts (void);

+iBool preloadLocalFontpackForPreview_Fonts (iGmDocument *doc);

diff --git a/src/gempub.c b/src/gempub.c

index 23846414..952d72a1 100644

--- a/src/gempub.c

+++ b/src/gempub.c

@@ -337,7 +337,7 @@ iBool preloadCoverImage_Gempub(const iGempub *d, iGmDocument *doc) {

 for (size_t linkId = 1; ; linkId++) {

     const iString *linkUrl = linkUrl_GmDocument(doc, linkId);

     if (!linkUrl) break;

         continue; /* got this already */

     }

     if (linkFlags_GmDocument(doc, linkId) & imageFileExtension_GmLinkFlag) {

diff --git a/src/gmdocument.c b/src/gmdocument.c

index c98b0bb8..c271ad94 100644

--- a/src/gmdocument.c

+++ b/src/gmdocument.c

@@ -27,6 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#include "ui/color.h"

#include "ui/text.h"

#include "ui/metrics.h"

+#include "ui/mediaui.h"

#include "ui/window.h"

#include "visited.h"

#include "bookmarks.h"

@@ -224,7 +225,7 @@ static iRangecc addLink_GmDocument_(iGmDocument *d, iRangecc line, iGmLinkId *li

             setScheme_GmLink_(link, finger_GmLinkScheme);

         }

         else if (equalCase_Rangecc(parts.scheme, "file")) {

         }

         else if (equalCase_Rangecc(parts.scheme, "data")) {

             setScheme_GmLink_(link, data_GmLinkScheme);

@@ -251,6 +252,9 @@ static iRangecc addLink_GmDocument_(iGmDocument *d, iRangecc line, iGmLinkId *li

                      endsWithCase_String(path, ".mid") || endsWithCase_String(path, ".ogg")) {

                 link->flags |= audioFileExtension_GmLinkFlag;

             }

             delete_String(path);

         }

         /* Check if visited. */

@@ -503,7 +507,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {

 static const char *arrow           = rightArrowhead_Icon;

 static const char *envelope        = envelope_Icon;

 static const char *bullet          = "\u2022";

 static const char *globe           = globe_Icon;

 static const char *quote           = "\u201c";

 static const char *magnifyingGlass = "\U0001f50d";

@@ -900,77 +904,77 @@ static void doLayout_GmDocument_(iGmDocument *d) {

     ((iGmRun *) back_Array(&d->layout))->flags |= endOfLine_GmRunFlag;

     /* Image or audio content. */

     if (type == link_GmLineType) {

+// enum iMediaType mediaType = none_MediaType;

             pos.y += margin;

             linkContentWasLaidOut_GmDocument_(d, &info, run.linkId);

         }

             pos.y += run.bounds.size.y + margin;

         }

     }

@@ -1057,21 +1061,6 @@ const iString *url_GmDocument(const iGmDocument *d) {

 return &d->url;

}

-#if 0

-void reset_GmDocument(iGmDocument *d) {

-}

-#endif

static void setDerivedThemeColors_(enum iGmDocumentTheme theme) {

 set_Color(tmQuoteIcon_ColorId,

           mix_Color(get_Color(tmQuote_ColorId), get_Color(tmBackground_ColorId), 0.55f));

diff --git a/src/gmdocument.h b/src/gmdocument.h

index b2c6d9b7..20bc9890 100644

--- a/src/gmdocument.h

+++ b/src/gmdocument.h

@@ -90,6 +90,7 @@ enum iGmLinkFlag {

 query_GmLinkFlag              = iBit(14), /* Gopher query link */

 iconFromLabel_GmLinkFlag      = iBit(15), /* use an Emoji/special character from label */

 isOpen_GmLinkFlag             = iBit(16), /* currently open in a tab */

};

iLocalDef enum iGmLinkScheme scheme_GmLinkFlag(int flags) {

@@ -126,13 +127,6 @@ enum iGmRunFlags {

 altText_GmRunFlag     = iBit(8),

};

-enum iGmRunMediaType {

-};

/* This structure is tightly packed because GmDocuments are mostly composed of

a large number of GmRuns. */

struct Impl_GmRun {

@@ -146,12 +140,16 @@ struct Impl_GmRun {

     uint32_t color     : 7; /* see max_ColorId */

     uint32_t font      : 10;

     uint32_t preId     : 10; /* preformatted block ID (sequential); merge with mediaId? */

 };

};

+iLocalDef iMediaId mediaId_GmRun(const iGmRun *d) {

+}

iDeclareType(GmRunRange)

struct Impl_GmRunRange {

diff --git a/src/gmrequest.c b/src/gmrequest.c

index 1a9e83a9..f7a22e0a 100644

--- a/src/gmrequest.c

+++ b/src/gmrequest.c

@@ -361,6 +361,9 @@ static const iBlock *aboutPageSource_(iRangecc path, iRangecc query) {

 if (equalCase_Rangecc(path, "debug")) {

     return utf8_String(debugInfo_App());

 }

 if (equalCase_Rangecc(path, "feeds")) {

     return utf8_String(entryListPage_Feeds());

 }

@@ -710,8 +713,9 @@ void submit_GmRequest(iGmRequest *d) {

         sort_Array(sortedInfo, (int (*)(const void *, const void *)) cmp_FileInfoPtr_);

         iForEach(PtrArray, s, sortedInfo) {

             const iFileInfo *entry = s.ptr;

                                 cstrCollect_String(makeFileUrl_String(path_FileInfo(entry))),

                                 cstr_Rangecc(baseName_Path(path_FileInfo(entry))),

                                 isDirectory_FileInfo(entry) ? iPathSeparator : "");

             iRelease(entry);

@@ -808,9 +812,10 @@ void submit_GmRequest(iGmRequest *d) {

                         const iString *subPath = e.value;

                         iRangecc relSub = range_String(subPath);

                         relSub.start += size_String(entryPath);

                                             cstr_String(&d->url),

                                             cstr_String(withSpacesEncoded_String(collectNewRange_String(relSub))),

                                             cstr_Rangecc(relSub));

                     }

                     resp->statusCode = success_GmStatusCode;

diff --git a/src/gmutil.c b/src/gmutil.c

index 971747d4..5be7e198 100644

--- a/src/gmutil.c

+++ b/src/gmutil.c

@@ -21,6 +21,7 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#include "gmutil.h"

+#include "fontpack.h"

#include <the_Foundation/file.h>

#include <the_Foundation/fileinfo.h>

@@ -511,7 +512,8 @@ const iString *findContainerArchive_Path(const iString *path) {

 while (!isEmpty_String(path) && cmp_String(path, ".")) {

     iString *dir = newRange_String(dirName_Path(path));

     if (endsWithCase_String(dir, ".zip") ||

         iEndCollect();

         return collect_String(dir);

     }

@@ -534,6 +536,9 @@ const char *mediaTypeFromFileExtension_String(const iString *d) {

 else if (endsWithCase_String(d, ".gpub")) {

     return "application/gpub+zip";

 }

 else if (endsWithCase_String(d, ".xml")) {

     return "text/xml";

 }

@@ -562,6 +567,7 @@ const char *mediaTypeFromFileExtension_String(const iString *d) {

     return "audio/midi";

 }

 else if (endsWithCase_String(d, ".txt") ||

          endsWithCase_String(d, ".md") ||

          endsWithCase_String(d, ".c") ||

          endsWithCase_String(d, ".h") ||

diff --git a/src/media.c b/src/media.c

index 26f0af4b..0ce2ac5c 100644

--- a/src/media.c

+++ b/src/media.c

@@ -36,6 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#include <the_Foundation/file.h>

#include <the_Foundation/ptrarray.h>

+#include <the_Foundation/stringlist.h>

#include <SDL_hints.h>

#include <SDL_render.h>

#include <SDL_timer.h>

@@ -287,45 +288,112 @@ iDefineTypeConstruction(GmDownload)

/----------------------------------------------------------------------------------------------/

+iDeclareType(GmFontpack)

+struct Impl_GmFontpack {

+};

+void init_GmFontpack(iGmFontpack *d) {

+}

+void deinit_GmFontpack(iGmFontpack *d) {

+}

+static void loadData_GmFontpack_(iGmFontpack *d, const iBlock *data) {

+}

+iDefineTypeConstruction(GmFontpack)

+/----------------------------------------------------------------------------------------------/

struct Impl_Media {

};

iDefineTypeConstruction(Media)

void init_Media(iMedia *d) {

}

void deinit_Media(iMedia *d) {

 clear_Media(d);

}

void clear_Media(iMedia *d) {

     deinit_GmImage(i.ptr);

 }

     deinit_GmAudio(a.ptr);

 }

     deinit_GmDownload(n.ptr);

 }

}

size_t memorySize_Media(const iMedia *d) {

 size_t memSize = 0;

     const iGmImage *img = i.ptr;

     if (img->texture) {

         const iInt2 texSize = size_SDLTexture(img->texture);

@@ -335,34 +403,49 @@ size_t memorySize_Media(const iMedia *d) {

         memSize += size_Block(&img->partialData);

     }

 }

     const iGmAudio *audio = a.ptr;

     if (audio->player) {

         memSize += sourceDataSize_Player(audio->player);

     }

 }

     const iGmDownload *down = n.ptr;

     memSize += down->numBytes;

 }

 return memSize; 

}

-iBool setDownloadUrl_Media(iMedia *d, iGmLinkId linkId, const iString *url) {

+iBool setUrl_Media(iMedia *d, iGmLinkId linkId, enum iMediaType mediaType, const iString *url) {

 }

 }

 return isNew;

}

@@ -372,16 +455,17 @@ iBool setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo

 const iBool isPartial  = (flags & partialData_MediaFlag) != 0;

 const iBool allowHide  = (flags & allowHide_MediaFlag) != 0;

 const iBool isDeleting = (!mime || !data);

 iBool       isNew      = iFalse;

     iGmImage *img;

     if (isDeleting) {

         delete_GmImage(img);

     }

     else {

         iAssert(equal_String(&img->props.mime, mime)); /* MIME cannot change */

         set_Block(&img->partialData, data);

         if (!isPartial) {

@@ -389,14 +473,14 @@ iBool setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo

         }

     }

 }

     iGmAudio *audio;

     if (isDeleting) {

         delete_GmAudio(audio);

     }

     else {

         iAssert(equal_String(&audio->props.mime, mime)); /* MIME cannot change */

         updateSourceData_Player(audio->player, mime, data, append_PlayerUpdate);

         if (!isPartial) {

@@ -408,14 +492,14 @@ iBool setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo

         }

     }

 }

     iGmDownload *dl;

     if (isDeleting) {

         delete_GmDownload(dl);

     }

     else {

         if (isEmpty_String(&dl->props.mime)) {

             set_String(&dl->props.mime, mime);

         }

@@ -428,6 +512,21 @@ iBool setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo

         }

     }

 }

 else if (!isDeleting) {

     if (startsWith_String(mime, "image/")) {

         /* Copy the image to a texture. */

@@ -435,7 +534,7 @@ iBool setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo

         img->props.linkId = linkId; /* TODO: use a hash? */

         img->props.isPermanent = !allowHide;

         set_String(&img->props.mime, mime);

         if (!isPartial) {

             makeTexture_GmImage(img);

         }

@@ -450,7 +549,7 @@ iBool setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo

         if (!isPartial) {

             updateSourceData_Player(audio->player, NULL, NULL, complete_PlayerUpdate);

         }

         /* Start playing right away. */

         start_Player(audio->player);

         postCommandf_App("media.player.started player:%p", audio->player);

@@ -460,125 +559,135 @@ iBool setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo

 return isNew;

}

-iMediaId findLinkImage_Media(const iMedia *d, iGmLinkId linkId) {

+static iMediaId findMediaPtr_Media_(const iPtrArray *items, enum iMediaType mediaType, iGmLinkId linkId) {

     }

 }

-}

-size_t numAudio_Media(const iMedia *d) {

}

-iMediaId findLinkAudio_Media(const iMedia *d, iGmLinkId linkId) {

+iMediaId findMediaForLink_Media(const iMedia *d, iGmLinkId linkId, enum iMediaType mediaType) {

     }

 }

}

-iMediaId findLinkDownload_Media(const iMedia *d, uint16_t linkId) {

+size_t numAudio_Media(const iMedia *d) {

}

iInt2 imageSize_Media(const iMedia *d, iMediaId imageId) {

     return img->size;

 }

 return zero_I2();

}

-SDL_Texture *imageTexture_Media(const iMedia *d, uint16_t imageId) {

+SDL_Texture *imageTexture_Media(const iMedia *d, iMediaId imageId) {

     return img->texture;

 }

 return NULL;

}

-iBool imageInfo_Media(const iMedia *d, iMediaId imageId, iGmMediaInfo *info_out) {

+iBool info_Media(const iMedia *d, iMediaId mediaId, iGmMediaInfo *info_out) {

 }

 iZap(*info_out);

 return iFalse;

}

iPlayer *audioData_Media(const iMedia *d, iMediaId audioId) {

     return audio->player;

 }

 return NULL;

}

-iBool audioInfo_Media(const iMedia *d, iMediaId audioId, iGmMediaInfo *info_out) {

-}

iPlayer *audioPlayer_Media(const iMedia *d, iMediaId audioId) {

     return audio->player;

 }

 return NULL;

}

void pauseAllPlayers_Media(const iMedia *d, iBool setPaused) {

     if (audio->player) {

         setPaused_Player(audio->player, setPaused);

     }

 }

}

-iBool downloadInfo_Media(const iMedia *d, iMediaId downloadId, iGmMediaInfo *info_out) {

-}

void downloadStats_Media(const iMedia *d, iMediaId downloadId, const iString **path_out,

                      float *bytesPerSecond_out, iBool *isFinished_out) {

 *bytesPerSecond_out = 0.0f;

     if (dl->path) {

         *path_out = dl->path;

     }

@@ -587,6 +696,16 @@ void downloadStats_Media(const iMedia *d, iMediaId downloadId, const iString **p

 }

}

+void fontpackInfo_Media(const iMedia *d, iMediaId fontpackId, iFontpackMediaInfo *info_out) {

+}

/----------------------------------------------------------------------------------------------/

static void updated_MediaRequest_(iAnyObject *obj) {

diff --git a/src/media.h b/src/media.h

index f7ad6efd..47a4da93 100644

--- a/src/media.h

+++ b/src/media.h

@@ -22,13 +22,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#pragma once

+#include "fontpack.h"

#include <the_Foundation/block.h>

#include <the_Foundation/string.h>

#include <the_Foundation/vec2.h>

#include <SDL_render.h>

-typedef uint16_t iMediaId;

iDeclareType(Player)

iDeclareType(GmMediaInfo)

@@ -38,6 +38,7 @@ struct Impl_GmMediaInfo {

 iBool       isPermanent;

};

+iDeclareType(MediaId)

iDeclareType(Media)

iDeclareTypeConstruction(Media)

@@ -46,28 +47,81 @@ enum iMediaFlags {

 partialData_MediaFlag = iBit(2),

};

-void clear_Media (iMedia *);

-iBool setDownloadUrl_Media (iMedia *, uint16_t linkId, const iString *url);

-iBool setData_Media (iMedia *, uint16_t linkId, const iString *mime, const iBlock *data, int flags);

-size_t memorySize_Media (const iMedia *);

+enum iMediaType { /* Note: There is a limited number of bits for these; see GmRun below. */

+};

-iMediaId findLinkImage_Media (const iMedia *, uint16_t linkId);

-iBool imageInfo_Media (const iMedia *, iMediaId imageId, iGmMediaInfo *info_out);

-iInt2 imageSize_Media (const iMedia *, iMediaId imageId);

-SDL_Texture * imageTexture_Media (const iMedia *, iMediaId imageId);

+struct Impl_MediaId {

+};

-size_t numAudio_Media (const iMedia *);

-iMediaId findLinkAudio_Media (const iMedia *, uint16_t linkId);

-iBool audioInfo_Media (const iMedia *, iMediaId audioId, iGmMediaInfo *info_out);

-iPlayer * audioPlayer_Media (const iMedia *, iMediaId audioId);

-void pauseAllPlayers_Media(const iMedia *, iBool setPaused);

+iLocalDef size_t index_MediaId(const iMediaId mediaId) {

+}

+#define iInvalidMediaId (iMediaId){ none_MediaType, 0 }

+void clear_Media (iMedia *);

+iBool setUrl_Media (iMedia *, uint16_t linkId, enum iMediaType mediaType, const iString *url);

+iBool setData_Media (iMedia *, uint16_t linkId, const iString *mime, const iBlock *data, int flags);

+size_t memorySize_Media (const iMedia *);

+iMediaId findMediaForLink_Media (const iMedia *, uint16_t linkId, enum iMediaType mediaType);

+iMediaId id_Media (const iMedia *, uint16_t linkId, enum iMediaType type);

+iBool info_Media (const iMedia *, iMediaId mediaId, iGmMediaInfo *info_out);

+iLocalDef iMediaId findLinkImage_Media(const iMedia *d, uint16_t linkId) {

+}

+iLocalDef iMediaId findLinkAudio_Media (const iMedia *d, uint16_t linkId) {

+}

+iLocalDef iMediaId findLinkDownload_Media(const iMedia *d, uint16_t linkId) {

+}

+iLocalDef iBool imageInfo_Media(const iMedia *d, uint16_t mediaId, iGmMediaInfo *info_out) {

+}

+iLocalDef iBool audioInfo_Media(const iMedia *d, uint16_t mediaId, iGmMediaInfo *info_out) {

+}

+iLocalDef iBool downloadInfo_Media(const iMedia *d, uint16_t mediaId, iGmMediaInfo *info_out) {

+}

+iInt2 imageSize_Media (const iMedia *, iMediaId imageId);

+SDL_Texture * imageTexture_Media (const iMedia *, iMediaId imageId);

+size_t numAudio_Media (const iMedia *);

+iPlayer * audioPlayer_Media (const iMedia *, iMediaId audioId);

+void pauseAllPlayers_Media (const iMedia *, iBool setPaused);

-iMediaId findLinkDownload_Media (const iMedia *, uint16_t linkId);

-iBool downloadInfo_Media (const iMedia *, iMediaId downloadId, iGmMediaInfo *info_out);

void downloadStats_Media (const iMedia *, iMediaId downloadId, const iString **path_out,

                                      float *bytesPerSecond_out, iBool *isFinished_out);

+iDeclareType(FontpackMediaInfo)

+struct Impl_FontpackMediaInfo {

+};

+void fontpackInfo_Media (const iMedia *, iMediaId fontpackId,

/----------------------------------------------------------------------------------------------/

iDeclareType(GmRequest)

@@ -78,7 +132,7 @@ iDeclareClass(MediaRequest)

struct Impl_MediaRequest {

 iObject          object;

 iDocumentWidget *doc;

 iGmRequest *     req;

};

diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c

index 45a8cf2d..44db3e5b 100644

--- a/src/ui/documentwidget.c

+++ b/src/ui/documentwidget.c

@@ -400,7 +400,18 @@ void init_DocumentWidget(iDocumentWidget *d) {

 addAction_Widget(w, navigateRoot_KeyShortcut, "navigate.root");

}

+void cancelAllRequests_DocumentWidget(iDocumentWidget *d) {

+}

void deinit_DocumentWidget(iDocumentWidget *d) {

 pauseAllPlayers_Media(media_GmDocument(d->doc), iTrue);

 removeTicker_App(animate_DocumentWidget_, d);

 removeTicker_App(prerender_DocumentWidget_, d);

@@ -564,7 +575,8 @@ static void addVisible_DocumentWidget_(void *context, const iGmRun *run) {

         pushBack_PtrArray(&d->visibleWideRuns, run);

     }

 }

     iAssert(run->mediaId);

     pushBack_PtrArray(&d->visibleMedia, run);

 }

@@ -758,14 +770,14 @@ static uint32_t mediaUpdateInterval_DocumentWidget_(const iDocumentWidget *d) {

 uint32_t interval = invalidInterval_;

 iConstForEach(PtrArray, i, &d->visibleMedia) {

     const iGmRun *run = i.ptr;

         if (flags_Player(plr) & adjustingVolume_PlayerFlag ||

             (isStarted_Player(plr) && !isPaused_Player(plr))) {

             interval = iMin(interval, 1000 / 15);

         }

     }

         interval = iMin(interval, 1000);

     }

 }

@@ -784,8 +796,8 @@ static void updateMedia_DocumentWidget_(iDocumentWidget *d) {

     refresh_Widget(d);

     iConstForEach(PtrArray, i, &d->visibleMedia) {

         const iGmRun *run = i.ptr;

             if (idleTimeMs_Player(plr) > 3000 && ~flags_Player(plr) & volumeGrabbed_PlayerFlag &&

                 flags_Player(plr) & adjustingVolume_PlayerFlag) {

                 setFlags_Player(plr, adjustingVolume_PlayerFlag, iFalse);

@@ -1244,6 +1256,9 @@ static const char *zipPageHeading_(const iRangecc mime) {

 if (equalCase_Rangecc(mime, "application/gpub+zip")) {

     return book_Icon " Gempub";

 }

 iRangecc type = iNullRange;

 nextSplit_Rangecc(mime, "/", &type); /* skip the part before the slash */

 nextSplit_Rangecc(mime, "/", &type);

@@ -1258,165 +1273,175 @@ static const char *zipPageHeading_(const iRangecc mime) {

static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool isCached) {

 iWidget *w = as_Widget(d);

         iGempub *gempub = new_Gempub();

             d->sourceGempub = gempub;

         }

         else {

             delete_Gempub(gempub);

         }

     }

         }

         }

     }

                 pushBack_Array(

                     items,

             }

             }

             }

         }

         }

                 }

             }

             }

         }

     }

 }

}

static void updateDocument_DocumentWidget_(iDocumentWidget *d,

@@ -1484,7 +1509,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d,

                 }

                 delete_String(localPath);

                 if (equalCase_Rangecc(urlScheme_String(d->mod.url), "file")) {

                                         cstr_String(withSpacesEncoded_String(d->mod.url)));

                 }

                 translate_Lang(&str);

@@ -2089,7 +2114,7 @@ static iBool requestMedia_DocumentWidget_(iDocumentWidget *d, iGmLinkId linkId,

}

static iBool isDownloadRequest_DocumentWidget(const iDocumentWidget *d, const iMediaRequest *req) {

}

static iBool handleMediaCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) {

@@ -2174,7 +2199,7 @@ static void allocVisBuffer_DocumentWidget_(const iDocumentWidget *d) {

static iBool fetchNextUnfetchedImage_DocumentWidget_(iDocumentWidget *d) {

 iConstForEach(PtrArray, i, &d->visibleLinks) {

     const iGmRun *run = i.ptr;

         ~run->flags & decoration_GmRunFlag) {

         const int linkFlags = linkFlags_GmDocument(d->doc, run->linkId);

         if (isMediaLink_GmDocument(d->doc, run->linkId) &&

@@ -2763,8 +2788,10 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)

 else if (equalWidget_Command(cmd, w, "document.downloadlink")) {

     if (d->contextLink) {

         const iGmLinkId linkId = d->contextLink->linkId;

         requestMedia_DocumentWidget_(d, linkId, iFalse /* no filters */);

         redoLayout_GmDocument(d->doc); /* inline downloader becomes visible */

         updateVisible_DocumentWidget_(d);

@@ -2874,7 +2901,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)

     const iMedia * media  = media_GmDocument(d->doc);

     const size_t   num    = numAudio_Media(media);

     for (size_t id = 1; id <= num; id++) {

         if (plr != startedPlr) {

             setPaused_Player(plr, iTrue);

         }

@@ -3212,8 +3239,8 @@ static iRect runRect_DocumentWidget_(const iDocumentWidget *d, const iGmRun *run

}

static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *run) {

     setFlags_Player(plr, volumeGrabbed_PlayerFlag, iTrue);

     d->grabbedStartVolume = volume_Player(plr);

     d->grabbedPlayer      = run;

@@ -3221,7 +3248,7 @@ static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *r

 }

 else if (d->grabbedPlayer) {

     setFlags_Player(

         volumeGrabbed_PlayerFlag,

         iFalse);

     d->grabbedPlayer = NULL;

@@ -3249,11 +3276,21 @@ static iBool processMediaEvents_DocumentWidget_(iDocumentWidget *d, const SDL_Ev

 const iInt2 mouse = init_I2(ev->button.x, ev->button.y);

 iConstForEach(PtrArray, i, &d->visibleMedia) {

     const iGmRun *run  = i.ptr;

         continue;

     }

     const iRect rect = runRect_DocumentWidget_(d, run);

     if (contains_Rect(rect, mouse)) {

         iPlayerUI ui;

         init_PlayerUI(&ui, plr, rect);

@@ -3633,7 +3670,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e

                                                              cstr_String(linkUrl)) },

                                                },

                                 3);

                     pushBackN_Array(&items, (iMenuItem[]){

                         { "---" },

                         { download_Icon " ${link.download}", 0, 0, "document.downloadlink" },

@@ -3641,7 +3678,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e

                 }

                 iMediaRequest *mediaReq;

                 if ((mediaReq = findMediaRequest_DocumentWidget_(d, d->contextLink->linkId)) != NULL &&

                     if (isFinished_GmRequest(mediaReq->req)) {

                         pushBack_Array(&items,

                                        &(iMenuItem){ download_Icon " " saveToDownloads_Label,

@@ -3763,7 +3800,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e

     case drag_ClickResult: {

         if (d->grabbedPlayer) {

             iPlayer *plr =

             iPlayerUI ui;

             init_PlayerUI(&ui, plr, runRect_DocumentWidget_(d, d->grabbedPlayer));

             float off = (float) delta_Click(&d->click).x / (float) width_Rect(ui.volumeSlider);

@@ -3883,8 +3920,9 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e

             }

             if (d->hoverLink) {

                 /* TODO: Move this to a method. */

                 iAssert(linkId);

                 /* Media links are opened inline by default. */

                 if (isMediaLink_GmDocument(d->doc, linkId)) {

@@ -3937,6 +3975,12 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e

                     }

                     refresh_Widget(w);

                 }

                 else if (linkFlags & supportedScheme_GmLinkFlag) {

                     int tabMode = openTabMode_Sym(modState_Keys());

                     if (isPinned_DocumentWidget_(d)) {

@@ -4071,7 +4115,7 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol

static void drawMark_DrawContext_(void *context, const iGmRun *run) {

 iDrawContext *d = context;

     fillRange_DrawContext_(d, run, uiMatching_ColorId, d->widget->foundMark, &d->inFoundMark);

     fillRange_DrawContext_(d, run, uiMarked_ColorId, d->widget->selectMark, &d->inSelectMark);

 }

@@ -4178,8 +4222,8 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {

         d->runsDrawn.end = run;

     }

 }

     const iRect dst = moved_Rect(run->visBounds, origin);

     if (tex) {

         fillRect_Paint(&d->paint, dst, tmBackground_ColorId); /* in case the image has alpha */

@@ -4334,31 +4378,31 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {

         fg = linkColor_GmDocument(doc, run->linkId, textHover_GmLinkPart);

         iString text;

         init_String(&text);

         }

             appendFormat_String(

                 &text, "  %s" close_Icon, isHover ? escape_Color(tmLinkText_ColorId) : "");

         }

@@ -4589,18 +4633,25 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) {

static void drawMedia_DocumentWidget_(const iDocumentWidget *d, iPaint *p) {

 iConstForEach(PtrArray, i, &d->visibleMedia) {

     const iGmRun * run = i.ptr;

         iPlayerUI ui;

         init_PlayerUI(&ui,

                       runRect_DocumentWidget_(d, run));

         draw_PlayerUI(&ui, p);

     }

         iDownloadUI ui;

         draw_DownloadUI(&ui, p);

     }

 }

}

diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h

index cc09c72d..1f2ecfc0 100644

--- a/src/ui/documentwidget.h

+++ b/src/ui/documentwidget.h

@@ -32,6 +32,8 @@ iDeclareType(History)

iDeclareWidgetClass(DocumentWidget)

iDeclareObjectConstruction(DocumentWidget)

+void cancelAllRequests_DocumentWidget(iDocumentWidget *);

void serializeState_DocumentWidget (const iDocumentWidget *, iStream *outs);

void deserializeState_DocumentWidget (iDocumentWidget *, iStream *ins);

diff --git a/src/ui/mediaui.c b/src/ui/mediaui.c

index 22552027..aa45d73a 100644

--- a/src/ui/mediaui.c

+++ b/src/ui/mediaui.c

@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#include "lang.h"

#include <the_Foundation/path.h>

+#include <the_Foundation/stringlist.h>

static const char *volumeChar_(float volume) {

 if (volume <= 0) {

@@ -61,7 +62,7 @@ void init_PlayerUI(iPlayerUI *d, const iPlayer *player, iRect bounds) {

 }

}

-static void drawPlayerButton_(iPaint *p, iRect rect, const char *label, int font) {

+static void drawInlineButton_(iPaint *p, iRect rect, const char *label, int font) {

 const iInt2 mouse     = mouseCoord_Window(get_Window(), 0);

 const iBool isHover   = contains_Rect(rect, mouse);

 const iBool isPressed = isHover && (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_LEFT) != 0;

@@ -113,14 +114,14 @@ void draw_PlayerUI(iPlayerUI *d, iPaint *p) {

 const iBool isAdjusting = (flags_Player(d->player) & adjustingVolume_PlayerFlag) != 0;

 fillRect_Paint(p, d->bounds, playerBackground_ColorId);

 drawRect_Paint(p, d->bounds, playerFrame_ColorId);

                   d->playPauseRect,

                   isPaused_Player(d->player) ? "\U0001f782" : "\u23f8",

                   uiContent_FontId);

 if (!isAdjusting) {

         p, d->volumeRect, volumeChar_(volume_Player(d->player)), uiContentSymbols_FontId);

 }

 const int   hgt       = lineHeight_Text(uiLabelBig_FontId);

@@ -228,24 +229,26 @@ static void drawSevenSegmentBytes_(iInt2 pos, int color, size_t numBytes) {

 deinit_String(&digits);

}

-void init_DownloadUI(iDownloadUI *d, const iDocumentWidget *doc, uint16_t mediaId, iRect bounds) {

+void init_DownloadUI(iDownloadUI *d, const iMedia *media, uint16_t mediaId, iRect bounds) {

 d->mediaId = mediaId;

 d->bounds  = bounds;

}

+/----------------------------------------------------------------------------------------------/

iBool processEvent_DownloadUI(iDownloadUI *d, const SDL_Event *ev) {

 return iFalse;

}

void draw_DownloadUI(const iDownloadUI *d, iPaint *p) {

 iGmMediaInfo info;

 float bytesPerSecond;

 const iString *path;

 iBool isFinished;

 fillRect_Paint(p, d->bounds, uiBackground_ColorId);

 drawRect_Paint(p, d->bounds, uiSeparator_ColorId);

 iRect rect = d->bounds;

@@ -275,3 +278,68 @@ void draw_DownloadUI(const iDownloadUI *d, iPaint *p) {

                    translateCStr_Lang("\u2014 ${mb.per.sec}"));

 }

}

+/----------------------------------------------------------------------------------------------/

+void init_FontpackUI(iFontpackUI *d, const iMedia *media, uint16_t mediaId, iRect bounds) {

+}

+iBool processEvent_FontpackUI(iFontpackUI *d, const SDL_Event *ev) {

+}

+int height_FontpackUI(const iMedia *media, uint16_t mediaId, int width) {

+}

+void draw_FontpackUI(const iFontpackUI *d, iPaint *p) {

+// checks[info.isValid], info.isValid ? "No errors" : "Errors detected",

+}

diff --git a/src/ui/mediaui.h b/src/ui/mediaui.h

index e79dedc0..73de1994 100644

--- a/src/ui/mediaui.h

+++ b/src/ui/mediaui.h

@@ -51,11 +51,27 @@ iDeclareType(Media)

iDeclareType(DownloadUI)

struct Impl_DownloadUI {

 uint16_t mediaId;

 iRect bounds;

};

-void init_DownloadUI (iDownloadUI *, const iDocumentWidget *doc, uint16_t mediaId, iRect bounds);

+void init_DownloadUI (iDownloadUI *, const iMedia *media, uint16_t mediaId, iRect bounds);

iBool processEvent_DownloadUI (iDownloadUI *, const SDL_Event *ev);

void draw_DownloadUI (const iDownloadUI *, iPaint *p);

+/----------------------------------------------------------------------------------------------/

+iDeclareType(FontpackUI)

+struct Impl_FontpackUI {

+};

+void init_FontpackUI (iFontpackUI *, const iMedia *media, uint16_t mediaId, iRect bounds);

+int height_FontpackUI (const iMedia *media, uint16_t mediaId, int width);

+iBool processEvent_FontpackUI (iFontpackUI *, const SDL_Event *ev);

+void draw_FontpackUI (const iFontpackUI *, iPaint *p);

--

2.25.1

Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/work%2Fv1.8/patch/960df03c17091aca37f53eaab8fc27c669d26a5e.patch
Status Code
Success (20)
Meta
text/plain
Capsule Response Time
99.304478 milliseconds
Gemini-to-HTML Time
25.945137 milliseconds

This content has been proxied by September (ba2dc).