summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-10-06 12:16:43 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-10-06 12:16:43 +0300
commit61a3dc017067be43472dadb7909094aa04d1fe9d (patch)
tree18b87895489844b4e516f79cd1588038f1d49494 /src/ui/documentwidget.c
parentf6a54d5375aab9c41af3f7c8a5e8fcbd1e0c9287 (diff)
Revised runtime font management
The built-in fonts are loaded via FontPack, and the font table is now constructed dynamically based on available fonts. A full set of variants (style, size) are prepared for each font, but some of the data gets allocated lazily when needed. GmRun needed a larger allocation for fonts, so now all the fields are combined into a single bit field. TODO: Glyph scaling, vertical offsets, and symbol lookup are still not fully working.
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c49
1 files changed, 25 insertions, 24 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 589b9e56..b83490f9 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -928,8 +928,9 @@ static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) {
928 pushBackCStr_StringArray(title, "Lagrange"); 928 pushBackCStr_StringArray(title, "Lagrange");
929 } 929 }
930 /* Take away parts if it doesn't fit. */ 930 /* Take away parts if it doesn't fit. */
931 const int avail = bounds_Widget(as_Widget(tabButton)).size.x - 3 * gap_UI; 931 const int avail = bounds_Widget(as_Widget(tabButton)).size.x - 3 * gap_UI;
932 iBool setWindow = (document_App() == d && isUnderKeyRoot_Widget(d)); 932 iBool setWindow = (document_App() == d && isUnderKeyRoot_Widget(d));
933 const int font = uiLabel_FontId;
933 for (;;) { 934 for (;;) {
934 iString *text = collect_String(joinCStr_StringArray(title, " \u2014 ")); 935 iString *text = collect_String(joinCStr_StringArray(title, " \u2014 "));
935 if (setWindow) { 936 if (setWindow) {
@@ -945,7 +946,7 @@ static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) {
945 prependChar_String(text, siteIcon); 946 prependChar_String(text, siteIcon);
946 prependCStr_String(text, escape_Color(uiIcon_ColorId)); 947 prependCStr_String(text, escape_Color(uiIcon_ColorId));
947 } 948 }
948 const int width = measureRange_Text(default_FontId, range_String(text)).advance.x; 949 const int width = measureRange_Text(font, range_String(text)).advance.x;
949 if (width <= avail || 950 if (width <= avail ||
950 isEmpty_StringArray(title)) { 951 isEmpty_StringArray(title)) {
951 updateText_LabelWidget(tabButton, text); 952 updateText_LabelWidget(tabButton, text);
@@ -954,9 +955,9 @@ static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) {
954 if (size_StringArray(title) == 1) { 955 if (size_StringArray(title) == 1) {
955 /* Just truncate to fit. */ 956 /* Just truncate to fit. */
956 const char *endPos; 957 const char *endPos;
957 tryAdvanceNoWrap_Text(default_FontId, 958 tryAdvanceNoWrap_Text(font,
958 range_String(text), 959 range_String(text),
959 avail - measure_Text(default_FontId, "...").advance.x, 960 avail - measure_Text(font, "...").advance.x,
960 &endPos); 961 &endPos);
961 updateText_LabelWidget( 962 updateText_LabelWidget(
962 tabButton, 963 tabButton,
@@ -1619,7 +1620,7 @@ static void parseUser_DocumentWidget_(iDocumentWidget *d) {
1619static void cacheRunGlyphs_(void *data, const iGmRun *run) { 1620static void cacheRunGlyphs_(void *data, const iGmRun *run) {
1620 iUnused(data); 1621 iUnused(data);
1621 if (!isEmpty_Range(&run->text)) { 1622 if (!isEmpty_Range(&run->text)) {
1622 cache_Text(run->textParams.font, run->text); 1623 cache_Text(run->font, run->text);
1623 } 1624 }
1624} 1625}
1625 1626
@@ -4020,14 +4021,14 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol
4020 contains_Range(&mark, run->text.start))) { 4021 contains_Range(&mark, run->text.start))) {
4021 int x = 0; 4022 int x = 0;
4022 if (!*isInside) { 4023 if (!*isInside) {
4023 x = measureRange_Text(run->textParams.font, 4024 x = measureRange_Text(run->font,
4024 (iRangecc){ run->text.start, iMax(run->text.start, mark.start) }) 4025 (iRangecc){ run->text.start, iMax(run->text.start, mark.start) })
4025 .advance.x; 4026 .advance.x;
4026 } 4027 }
4027 int w = width_Rect(run->visBounds) - x; 4028 int w = width_Rect(run->visBounds) - x;
4028 if (contains_Range(&run->text, mark.end) || mark.end < run->text.start) { 4029 if (contains_Range(&run->text, mark.end) || mark.end < run->text.start) {
4029 w = measureRange_Text( 4030 w = measureRange_Text(
4030 run->textParams.font, 4031 run->font,
4031 !*isInside ? mark 4032 !*isInside ? mark
4032 : (iRangecc){ run->text.start, iMax(run->text.start, mark.end) }) 4033 : (iRangecc){ run->text.start, iMax(run->text.start, mark.end) })
4033 .advance.x; 4034 .advance.x;
@@ -4083,15 +4084,15 @@ static void drawBannerRun_DrawContext_(iDrawContext *d, const iGmRun *run, iInt2
4083 iInt2 bpos = add_I2(visPos, init_I2(0, lineHeight_Text(banner_FontId) / 2)); 4084 iInt2 bpos = add_I2(visPos, init_I2(0, lineHeight_Text(banner_FontId) / 2));
4084 if (icon) { 4085 if (icon) {
4085 appendChar_String(&str, icon); 4086 appendChar_String(&str, icon);
4086 const iRect iconRect = visualBounds_Text(run->textParams.font, range_String(&str)); 4087 const iRect iconRect = visualBounds_Text(run->font, range_String(&str));
4087 drawRange_Text( 4088 drawRange_Text(
4088 run->textParams.font, 4089 run->font,
4089 addY_I2(bpos, -mid_Rect(iconRect).y + lineHeight_Text(run->textParams.font) / 2), 4090 addY_I2(bpos, -mid_Rect(iconRect).y + lineHeight_Text(run->font) / 2),
4090 tmBannerIcon_ColorId, 4091 tmBannerIcon_ColorId,
4091 range_String(&str)); 4092 range_String(&str));
4092 bpos.x += right_Rect(iconRect) + 3 * gap_Text; 4093 bpos.x += right_Rect(iconRect) + 3 * gap_Text;
4093 } 4094 }
4094 drawRange_Text(run->textParams.font, 4095 drawRange_Text(run->font,
4095 bpos, 4096 bpos,
4096 tmBannerTitle_ColorId, 4097 tmBannerTitle_ColorId,
4097 bannerText_DocumentWidget_(d->widget)); 4098 bannerText_DocumentWidget_(d->widget));
@@ -4198,7 +4199,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
4198 /* Media UIs are drawn afterwards as a dynamic overlay. */ 4199 /* Media UIs are drawn afterwards as a dynamic overlay. */
4199 return; 4200 return;
4200 } 4201 }
4201 enum iColorId fg = run->textParams.color; 4202 enum iColorId fg = run->color;
4202 const iGmDocument *doc = d->widget->doc; 4203 const iGmDocument *doc = d->widget->doc;
4203 const int linkFlags = linkFlags_GmDocument(doc, run->linkId); 4204 const int linkFlags = linkFlags_GmDocument(doc, run->linkId);
4204 /* Hover state of a link. */ 4205 /* Hover state of a link. */
@@ -4265,10 +4266,10 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
4265 const iInt2 margin = preRunMargin_GmDocument(doc, run->preId); 4266 const iInt2 margin = preRunMargin_GmDocument(doc, run->preId);
4266 fillRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmBackgroundAltText_ColorId); 4267 fillRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmBackgroundAltText_ColorId);
4267 drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmQuoteIcon_ColorId); 4268 drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmQuoteIcon_ColorId);
4268 drawWrapRange_Text(run->textParams.font, 4269 drawWrapRange_Text(run->font,
4269 add_I2(visPos, margin), 4270 add_I2(visPos, margin),
4270 run->visBounds.size.x - 2 * margin.x, 4271 run->visBounds.size.x - 2 * margin.x,
4271 run->textParams.color, 4272 run->color,
4272 run->text); 4273 run->text);
4273 } 4274 }
4274 else if (run->flags & siteBanner_GmRunFlag) { 4275 else if (run->flags & siteBanner_GmRunFlag) {
@@ -4287,17 +4288,17 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
4287 linkOrdinalChar_DocumentWidget_(d->widget, ord - d->widget->ordinalBase); 4288 linkOrdinalChar_DocumentWidget_(d->widget, ord - d->widget->ordinalBase);
4288 if (ordChar) { 4289 if (ordChar) {
4289 const char *circle = "\u25ef"; /* Large Circle */ 4290 const char *circle = "\u25ef"; /* Large Circle */
4290 const int circleFont = defaultContentRegular_FontId; 4291 const int circleFont = FONT_ID(default_FontId, regular_FontStyle, contentRegular_FontSize);
4291 iRect nbArea = { init_I2(d->viewPos.x - gap_UI / 3, visPos.y), 4292 iRect nbArea = { init_I2(d->viewPos.x - gap_UI / 3, visPos.y),
4292 init_I2(3.95f * gap_Text, 1.0f * lineHeight_Text(circleFont)) }; 4293 init_I2(3.95f * gap_Text, 1.0f * lineHeight_Text(circleFont)) };
4293 drawRange_Text( 4294 drawRange_Text(
4294 circleFont, topLeft_Rect(nbArea), tmQuote_ColorId, range_CStr(circle)); 4295 circleFont, topLeft_Rect(nbArea), tmQuote_ColorId, range_CStr(circle));
4295 iRect circleArea = visualBounds_Text(circleFont, range_CStr(circle)); 4296 iRect circleArea = visualBounds_Text(circleFont, range_CStr(circle));
4296 addv_I2(&circleArea.pos, topLeft_Rect(nbArea)); 4297 addv_I2(&circleArea.pos, topLeft_Rect(nbArea));
4297 drawCentered_Text(defaultContentSmall_FontId, 4298 drawCentered_Text(FONT_ID(default_FontId, regular_FontStyle, contentSmall_FontSize),
4298 circleArea, 4299 circleArea,
4299 iTrue, 4300 iTrue,
4300 tmQuote_ColorId, 4301 tmQuote_ColorId,
4301 "%lc", 4302 "%lc",
4302 (int) ordChar); 4303 (int) ordChar);
4303 goto runDrawn; 4304 goto runDrawn;
@@ -4307,15 +4308,15 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
4307 if (run->flags & quoteBorder_GmRunFlag) { 4308 if (run->flags & quoteBorder_GmRunFlag) {
4308 drawVLine_Paint(&d->paint, 4309 drawVLine_Paint(&d->paint,
4309 addX_I2(visPos, 4310 addX_I2(visPos,
4310 !run->textParams.isRTL 4311 !run->isRTL
4311 ? -gap_Text * 5 / 2 4312 ? -gap_Text * 5 / 2
4312 : (width_Rect(run->visBounds) + gap_Text * 5 / 2)), 4313 : (width_Rect(run->visBounds) + gap_Text * 5 / 2)),
4313 height_Rect(run->visBounds), 4314 height_Rect(run->visBounds),
4314 tmQuoteIcon_ColorId); 4315 tmQuoteIcon_ColorId);
4315 } 4316 }
4316 drawBoundRange_Text(run->textParams.font, 4317 drawBoundRange_Text(run->font,
4317 visPos, 4318 visPos,
4318 (run->textParams.isRTL ? -1 : 1) * width_Rect(run->visBounds), 4319 (run->isRTL ? -1 : 1) * width_Rect(run->visBounds),
4319 fg, 4320 fg,
4320 run->text); 4321 run->text);
4321 runDrawn:; 4322 runDrawn:;
@@ -4431,7 +4432,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
4431 append_String(&str, collect_String(format_Date(&date, "%b %d"))); 4432 append_String(&str, collect_String(format_Date(&date, "%b %d")));
4432 } 4433 }
4433 if (!isEmpty_String(&str)) { 4434 if (!isEmpty_String(&str)) {
4434 if (run->textParams.isRTL) { 4435 if (run->isRTL) {
4435 appendCStr_String(&str, " \u2014 "); 4436 appendCStr_String(&str, " \u2014 ");
4436 } 4437 }
4437 else { 4438 else {
@@ -4440,7 +4441,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
4440 const iInt2 textSize = measure_Text(metaFont, cstr_String(&str)).bounds.size; 4441 const iInt2 textSize = measure_Text(metaFont, cstr_String(&str)).bounds.size;
4441 int tx = topRight_Rect(linkRect).x; 4442 int tx = topRight_Rect(linkRect).x;
4442 const char *msg = cstr_String(&str); 4443 const char *msg = cstr_String(&str);
4443 if (run->textParams.isRTL) { 4444 if (run->isRTL) {
4444 tx = topLeft_Rect(linkRect).x - textSize.x; 4445 tx = topLeft_Rect(linkRect).x - textSize.x;
4445 } 4446 }
4446 if (tx + textSize.x > right_Rect(d->widgetBounds)) { 4447 if (tx + textSize.x > right_Rect(d->widgetBounds)) {
@@ -4909,7 +4910,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
4909 } 4910 }
4910 /* Pinch zoom indicator. */ 4911 /* Pinch zoom indicator. */
4911 if (d->flags & pinchZoom_DocumentWidgetFlag) { 4912 if (d->flags & pinchZoom_DocumentWidgetFlag) {
4912 const int font = defaultLargeBold_FontId; 4913 const int font = uiLabelLargeBold_FontId;
4913 const int height = lineHeight_Text(font) * 2; 4914 const int height = lineHeight_Text(font) * 2;
4914 const iInt2 size = init_I2(height * 2, height); 4915 const iInt2 size = init_I2(height * 2, height);
4915 const iRect rect = { sub_I2(mid_Rect(bounds), divi_I2(size, 2)), size }; 4916 const iRect rect = { sub_I2(mid_Rect(bounds), divi_I2(size, 2)), size };