diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | res/about/license.gmi | 3 | ||||
-rw-r--r-- | res/about/version.gmi | 5 | ||||
-rw-r--r-- | res/fonts/FiraMono-Regular.ttf | bin | 174632 -> 0 bytes | |||
-rw-r--r-- | res/fonts/IosevkaTerm-Extended.ttf | bin | 0 -> 1503504 bytes | |||
-rw-r--r-- | src/ui/text.c | 51 | ||||
-rw-r--r-- | src/ui/text.h | 21 |
7 files changed, 51 insertions, 31 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 995432cb..394f1b6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
@@ -61,7 +61,7 @@ set (EMBED_RESOURCES | |||
61 | res/fonts/Tinos-Regular.ttf | 61 | res/fonts/Tinos-Regular.ttf |
62 | res/fonts/Tinos-Italic.ttf | 62 | res/fonts/Tinos-Italic.ttf |
63 | res/fonts/Tinos-Bold.ttf | 63 | res/fonts/Tinos-Bold.ttf |
64 | res/fonts/FiraMono-Regular.ttf | 64 | res/fonts/IosevkaTerm-Extended.ttf |
65 | res/fonts/FiraSans-Bold.ttf | 65 | res/fonts/FiraSans-Bold.ttf |
66 | res/fonts/FiraSans-Italic.ttf | 66 | res/fonts/FiraSans-Italic.ttf |
67 | res/fonts/FiraSans-Light.ttf | 67 | res/fonts/FiraSans-Light.ttf |
diff --git a/res/about/license.gmi b/res/about/license.gmi index 0ea0897a..d5ffe3c4 100644 --- a/res/about/license.gmi +++ b/res/about/license.gmi | |||
@@ -100,7 +100,8 @@ The libunistring library is covered by the GNU Lesser General Public License (LG | |||
100 | 100 | ||
101 | This application uses fonts licensed under the Open Font License. | 101 | This application uses fonts licensed under the Open Font License. |
102 | 102 | ||
103 | => https://github.com/mozilla/Fira/blob/master/LICENSE Fira Sans, Fira Mono | 103 | => https://github.com/mozilla/Fira/blob/master/LICENSE Fira Sans |
104 | => https://typeof.net/Iosevka/ Iosevka | ||
104 | => https://github.com/googlefonts/literata/blob/master/OFL.txt Literata | 105 | => https://github.com/googlefonts/literata/blob/master/OFL.txt Literata |
105 | => https://github.com/google/fonts/blob/master/ofl/nanumgothic/OFL.txt Nanum Gothic | 106 | => https://github.com/google/fonts/blob/master/ofl/nanumgothic/OFL.txt Nanum Gothic |
106 | => https://www.google.com/get/noto/help/cjk/ Noto Sans CJK JP | 107 | => https://www.google.com/get/noto/help/cjk/ Noto Sans CJK JP |
diff --git a/res/about/version.gmi b/res/about/version.gmi index 42475e13..1932baa1 100644 --- a/res/about/version.gmi +++ b/res/about/version.gmi | |||
@@ -8,9 +8,9 @@ | |||
8 | 8 | ||
9 | ## 0.13 | 9 | ## 0.13 |
10 | * Support for Internationalized Domain Names (IDN) in network requests. | 10 | * Support for Internationalized Domain Names (IDN) in network requests. |
11 | * IDNs show up in decoded form in the UI. | 11 | * UI shows decoded IDNs. |
12 | * Percent-encoded Unicode characters in URL paths are decoded for the UI, and encoded in outgoing requests. | 12 | * Percent-encoded Unicode characters in URL paths are decoded for the UI, and encoded in outgoing requests. |
13 | * Added option to disable decoding of percent-encoded paths. | 13 | * Added option to disable decoding of percent-encoded paths for the UI. |
14 | * Quick search via URL bar shows entries from subscribed feeds. | 14 | * Quick search via URL bar shows entries from subscribed feeds. |
15 | * Added keybindings for zooming. | 15 | * Added keybindings for zooming. |
16 | * Improved usability of page content searching (${CTRL+}F, Escape). | 16 | * Improved usability of page content searching (${CTRL+}F, Escape). |
@@ -19,6 +19,7 @@ | |||
19 | * Fixed handling of Unicode joiners and modifiers (by ignoring them, since we lack the glyphs). | 19 | * Fixed handling of Unicode joiners and modifiers (by ignoring them, since we lack the glyphs). |
20 | * Fixed a layout issue with sidebars where the bottommost content line was occasionally not visible. | 20 | * Fixed a layout issue with sidebars where the bottommost content line was occasionally not visible. |
21 | * Fixed exit when a hook program didn't read its input. | 21 | * Fixed exit when a hook program didn't read its input. |
22 | * Fixed use of variable-width fonts in input fields. | ||
22 | * Fixed crash when using an identity (with LibreSSL on OpenBSD). | 23 | * Fixed crash when using an identity (with LibreSSL on OpenBSD). |
23 | 24 | ||
24 | ## 0.12.1 | 25 | ## 0.12.1 |
diff --git a/res/fonts/FiraMono-Regular.ttf b/res/fonts/FiraMono-Regular.ttf deleted file mode 100644 index 59e1e1a1..00000000 --- a/res/fonts/FiraMono-Regular.ttf +++ /dev/null | |||
Binary files differ | |||
diff --git a/res/fonts/IosevkaTerm-Extended.ttf b/res/fonts/IosevkaTerm-Extended.ttf new file mode 100644 index 00000000..16989a85 --- /dev/null +++ b/res/fonts/IosevkaTerm-Extended.ttf | |||
Binary files differ | |||
diff --git a/src/ui/text.c b/src/ui/text.c index 4229217c..ec240c75 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -120,10 +120,10 @@ static void init_Font(iFont *d, const iBlock *data, int height, float scale, | |||
120 | d->xScale *= floorf(advance) / advance; | 120 | d->xScale *= floorf(advance) / advance; |
121 | } | 121 | } |
122 | } | 122 | } |
123 | d->vertOffset = height * (1.0f - scale) / 2; | 123 | d->vertOffset = height * (1.0f - scale) / 2; |
124 | int ascent; | 124 | int ascent; |
125 | stbtt_GetFontVMetrics(&d->font, &ascent, NULL, NULL); | 125 | stbtt_GetFontVMetrics(&d->font, &ascent, NULL, NULL); |
126 | d->baseline = ceil(ascent * d->yScale); | 126 | d->baseline = /*ceil*/(ascent * d->yScale); |
127 | d->symbolsFont = symbolsFont; | 127 | d->symbolsFont = symbolsFont; |
128 | d->japaneseFont = regularJapanese_FontId; | 128 | d->japaneseFont = regularJapanese_FontId; |
129 | d->koreanFont = regularKorean_FontId; | 129 | d->koreanFont = regularKorean_FontId; |
@@ -176,8 +176,8 @@ static iText text_; | |||
176 | 176 | ||
177 | static void initFonts_Text_(iText *d) { | 177 | static void initFonts_Text_(iText *d) { |
178 | const float textSize = fontSize_UI * d->contentFontSize; | 178 | const float textSize = fontSize_UI * d->contentFontSize; |
179 | const float monoSize = fontSize_UI * d->contentFontSize / contentScale_Text_ * 0.866f; | 179 | const float monoSize = textSize * 0.71f; //fontSize_UI * d->contentFontSize / contentScale_Text_ * 1.0f; //0.866f; |
180 | const float smallMonoSize = monoSize * 0.866f; | 180 | const float smallMonoSize = monoSize * 0.8f; |
181 | const iBlock *regularFont = &fontNunitoRegular_Embedded; | 181 | const iBlock *regularFont = &fontNunitoRegular_Embedded; |
182 | const iBlock *italicFont = &fontNunitoLightItalic_Embedded; | 182 | const iBlock *italicFont = &fontNunitoLightItalic_Embedded; |
183 | const iBlock *h12Font = &fontNunitoExtraBold_Embedded; | 183 | const iBlock *h12Font = &fontNunitoExtraBold_Embedded; |
@@ -226,12 +226,12 @@ static void initFonts_Text_(iText *d) { | |||
226 | { &fontSourceSansProRegular_Embedded, fontSize_UI, 1.0f, defaultSymbols_FontId }, | 226 | { &fontSourceSansProRegular_Embedded, fontSize_UI, 1.0f, defaultSymbols_FontId }, |
227 | { &fontSourceSansProRegular_Embedded, fontSize_UI * 1.125f, 1.0f, defaultMediumSymbols_FontId }, | 227 | { &fontSourceSansProRegular_Embedded, fontSize_UI * 1.125f, 1.0f, defaultMediumSymbols_FontId }, |
228 | { &fontSourceSansProRegular_Embedded, fontSize_UI * 1.666f, 1.0f, defaultLargeSymbols_FontId }, | 228 | { &fontSourceSansProRegular_Embedded, fontSize_UI * 1.666f, 1.0f, defaultLargeSymbols_FontId }, |
229 | { &fontFiraMonoRegular_Embedded, fontSize_UI * 0.866f, 1.0f, defaultSymbols_FontId }, | 229 | { &fontIosevkaTermExtended_Embedded, fontSize_UI * 0.866f, 1.0f, defaultSymbols_FontId }, |
230 | { &fontSourceSansProRegular_Embedded, textSize, scaling, symbols_FontId }, | 230 | { &fontSourceSansProRegular_Embedded, textSize, scaling, symbols_FontId }, |
231 | /* content fonts */ | 231 | /* content fonts */ |
232 | { regularFont, textSize, scaling, symbols_FontId }, | 232 | { regularFont, textSize, scaling, symbols_FontId }, |
233 | { &fontFiraMonoRegular_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, | 233 | { &fontIosevkaTermExtended_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, |
234 | { &fontFiraMonoRegular_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, | 234 | { &fontIosevkaTermExtended_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, |
235 | { regularFont, textSize * 1.200f, scaling, mediumSymbols_FontId }, | 235 | { regularFont, textSize * 1.200f, scaling, mediumSymbols_FontId }, |
236 | { h3Font, textSize * 1.333f, h123Scaling, bigSymbols_FontId }, | 236 | { h3Font, textSize * 1.333f, h123Scaling, bigSymbols_FontId }, |
237 | { italicFont, textSize, scaling, symbols_FontId }, | 237 | { italicFont, textSize, scaling, symbols_FontId }, |
@@ -239,7 +239,7 @@ static void initFonts_Text_(iText *d) { | |||
239 | { h12Font, textSize * 2.000f, h123Scaling, hugeSymbols_FontId }, | 239 | { h12Font, textSize * 2.000f, h123Scaling, hugeSymbols_FontId }, |
240 | { lightFont, textSize * 1.666f, lightScaling, largeSymbols_FontId }, | 240 | { lightFont, textSize * 1.666f, lightScaling, largeSymbols_FontId }, |
241 | /* monospace content fonts */ | 241 | /* monospace content fonts */ |
242 | { &fontFiraMonoRegular_Embedded, textSize, 0.8f, symbols_FontId }, | 242 | { &fontIosevkaTermExtended_Embedded, textSize, 0.866f, symbols_FontId }, |
243 | /* symbol fonts */ | 243 | /* symbol fonts */ |
244 | { &fontSymbola_Embedded, fontSize_UI, 1.0f, defaultSymbols_FontId }, | 244 | { &fontSymbola_Embedded, fontSize_UI, 1.0f, defaultSymbols_FontId }, |
245 | { &fontSymbola_Embedded, fontSize_UI * 1.125f, 1.0f, defaultMediumSymbols_FontId }, | 245 | { &fontSymbola_Embedded, fontSize_UI * 1.125f, 1.0f, defaultMediumSymbols_FontId }, |
@@ -288,7 +288,7 @@ static void initFonts_Text_(iText *d) { | |||
288 | fontData[i].size, | 288 | fontData[i].size, |
289 | fontData[i].scaling, | 289 | fontData[i].scaling, |
290 | fontData[i].symbolsFont, | 290 | fontData[i].symbolsFont, |
291 | fontData[i].ttf == &fontFiraMonoRegular_Embedded); | 291 | fontData[i].ttf == &fontIosevkaTermExtended_Embedded); |
292 | if (i == default_FontId || i == defaultMedium_FontId) { | 292 | if (i == default_FontId || i == defaultMedium_FontId) { |
293 | font->manualKernOnly = iTrue; | 293 | font->manualKernOnly = iTrue; |
294 | } | 294 | } |
@@ -636,6 +636,7 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
636 | iRect bounds = zero_Rect(); | 636 | iRect bounds = zero_Rect(); |
637 | const iInt2 orig = pos; | 637 | const iInt2 orig = pos; |
638 | float xpos = pos.x; | 638 | float xpos = pos.x; |
639 | float xposExtend = pos.x; /* allows wide glyphs to use more space; restored by whitespace */ | ||
639 | float xposMax = xpos; | 640 | float xposMax = xpos; |
640 | float monoAdvance = 0; | 641 | float monoAdvance = 0; |
641 | iAssert(xposLimit == 0 || isMeasuring_(mode)); | 642 | iAssert(xposLimit == 0 || isMeasuring_(mode)); |
@@ -668,6 +669,7 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
668 | } | 669 | } |
669 | } | 670 | } |
670 | iChar ch = nextChar_(&chPos, text.end); | 671 | iChar ch = nextChar_(&chPos, text.end); |
672 | iBool isEmoji = isEmoji_Char(ch); | ||
671 | if (ch == 0x200d) { /* zero-width joiner */ | 673 | if (ch == 0x200d) { /* zero-width joiner */ |
672 | /* We don't have the composited Emojis. */ | 674 | /* We don't have the composited Emojis. */ |
673 | if (isEmoji_Char(prevCh)) { | 675 | if (isEmoji_Char(prevCh)) { |
@@ -676,9 +678,19 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
676 | ch = nextChar_(&chPos, text.end); | 678 | ch = nextChar_(&chPos, text.end); |
677 | } | 679 | } |
678 | } | 680 | } |
681 | #if 0 | ||
682 | iChar nextCh = 0; { | ||
683 | /* TODO: Since we're peeking ahead, should use this on the next loop iteration. */ | ||
684 | const char *ncp = chPos; | ||
685 | nextCh = nextChar_(&ncp, text.end); | ||
686 | } | ||
687 | /* VS15: Peek ahead and treat as Emoji font. */ | ||
688 | if (nextCh == emojiVariationSelector_Char) { | ||
689 | isEmoji = iTrue; | ||
690 | } | ||
691 | #endif | ||
679 | if (isVariationSelector_Char(ch)) { | 692 | if (isVariationSelector_Char(ch)) { |
680 | /* TODO: VS15: Should peek ahead for this and prefer the Emoji font. */ | 693 | ch = nextChar_(&chPos, text.end); /* skip it */ |
681 | ch = nextChar_(&chPos, text.end); /* just ignore */ | ||
682 | } | 694 | } |
683 | /* Special instructions. */ { | 695 | /* Special instructions. */ { |
684 | if (ch == 0xad) { /* soft hyphen */ | 696 | if (ch == 0xad) { /* soft hyphen */ |
@@ -703,7 +715,7 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
703 | } | 715 | } |
704 | } | 716 | } |
705 | if (ch == '\n') { | 717 | if (ch == '\n') { |
706 | xpos = pos.x; | 718 | xpos = xposExtend = pos.x; |
707 | pos.y += d->height; | 719 | pos.y += d->height; |
708 | prevCh = ch; | 720 | prevCh = ch; |
709 | continue; | 721 | continue; |
@@ -711,6 +723,7 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
711 | if (ch == '\t') { | 723 | if (ch == '\t') { |
712 | const int tabStopWidth = d->height * 8; | 724 | const int tabStopWidth = d->height * 8; |
713 | xpos = pos.x + ((int) ((xpos - pos.x) / tabStopWidth) + 1) * tabStopWidth; | 725 | xpos = pos.x + ((int) ((xpos - pos.x) / tabStopWidth) + 1) * tabStopWidth; |
726 | xposExtend = iMax(xposExtend, xpos); | ||
714 | prevCh = 0; | 727 | prevCh = 0; |
715 | continue; | 728 | continue; |
716 | } | 729 | } |
@@ -728,7 +741,7 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
728 | } | 741 | } |
729 | } | 742 | } |
730 | const iGlyph *glyph = glyph_Font_(d, ch); | 743 | const iGlyph *glyph = glyph_Font_(d, ch); |
731 | int x1 = xpos; | 744 | int x1 = iMax(xpos, xposExtend); |
732 | const int hoff = enableHalfPixelGlyphs_Text ? (xpos - x1 > 0.5f ? 1 : 0) : 0; | 745 | const int hoff = enableHalfPixelGlyphs_Text ? (xpos - x1 > 0.5f ? 1 : 0) : 0; |
733 | int x2 = x1 + glyph->rect[hoff].size.x; | 746 | int x2 = x1 + glyph->rect[hoff].size.x; |
734 | /* Out of the allotted space? */ | 747 | /* Out of the allotted space? */ |
@@ -765,11 +778,13 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
765 | bounds.size.x = iMax(bounds.size.x, x2 - orig.x); | 778 | bounds.size.x = iMax(bounds.size.x, x2 - orig.x); |
766 | bounds.size.y = iMax(bounds.size.y, pos.y + glyph->font->height - orig.y); | 779 | bounds.size.y = iMax(bounds.size.y, pos.y + glyph->font->height - orig.y); |
767 | } | 780 | } |
781 | /* Symbols and emojis are NOT monospaced, so must conform when the primary font | ||
782 | is monospaced. Except with Japanese script, that's larger than the normal monospace. */ | ||
768 | const iBool useMonoAdvance = | 783 | const iBool useMonoAdvance = |
769 | monoAdvance > 0 && !isJapanese_FontId(fontId_Text_(glyph->font)); | 784 | monoAdvance > 0 && !isJapanese_FontId(fontId_Text_(glyph->font)); |
770 | const float advance = (useMonoAdvance ? monoAdvance : glyph->advance); | 785 | const float advance = (useMonoAdvance ? monoAdvance : glyph->advance); |
771 | if (!isMeasuring_(mode)) { | 786 | if (!isMeasuring_(mode)) { |
772 | if (useMonoAdvance && dst.w > advance && glyph->font != d) { | 787 | if (useMonoAdvance && dst.w > advance && glyph->font != d && !isEmoji) { |
773 | /* Glyphs from a different font may need recentering to look better. */ | 788 | /* Glyphs from a different font may need recentering to look better. */ |
774 | dst.x -= (dst.w - advance) / 2; | 789 | dst.x -= (dst.w - advance) / 2; |
775 | } | 790 | } |
@@ -784,10 +799,12 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
784 | } | 799 | } |
785 | SDL_RenderCopy(text_.render, text_.cache, &src, &dst); | 800 | SDL_RenderCopy(text_.render, text_.cache, &src, &dst); |
786 | } | 801 | } |
787 | /* Symbols and emojis are NOT monospaced, so must conform when the primary font | ||
788 | is monospaced. Except with Japanese script, that's larger than the normal monospace. */ | ||
789 | xpos += advance; | 802 | xpos += advance; |
790 | xposMax = iMax(xposMax, xpos); | 803 | if (!isSpace_Char(ch)) { |
804 | xposExtend += isEmoji ? glyph->advance : advance; | ||
805 | } | ||
806 | xposExtend = iMax(xposExtend, xpos); | ||
807 | xposMax = iMax(xposMax, xposExtend); | ||
791 | if (continueFrom_out && ((mode & noWrapFlag_RunMode) || isWrapBoundary_(prevCh, ch))) { | 808 | if (continueFrom_out && ((mode & noWrapFlag_RunMode) || isWrapBoundary_(prevCh, ch))) { |
792 | lastWordEnd = chPos; | 809 | lastWordEnd = chPos; |
793 | } | 810 | } |
diff --git a/src/ui/text.h b/src/ui/text.h index 6728bb62..5867a84b 100644 --- a/src/ui/text.h +++ b/src/ui/text.h | |||
@@ -127,7 +127,8 @@ iLocalDef iBool isDefaultIgnorable_Char(iChar c) { | |||
127 | c == 0xfeff; | 127 | c == 0xfeff; |
128 | } | 128 | } |
129 | iLocalDef iBool isEmoji_Char(iChar c) { | 129 | iLocalDef iBool isEmoji_Char(iChar c) { |
130 | return (c >= 0x1f300 && c < 0x1f700) || (c >= 0x1f900 && c <= 0x1f9ff); | 130 | return (c >= 0x1f300 && c < 0x1f700) || (c >= 0x1f7e0 && c <= 0x1f7eb) || |
131 | (c >= 0x1f900 && c <= 0x1f9ff); | ||
131 | } | 132 | } |
132 | 133 | ||
133 | #define emojiVariationSelector_Char ((iChar) 0xfe0f) | 134 | #define emojiVariationSelector_Char ((iChar) 0xfe0f) |
@@ -141,21 +142,21 @@ enum iTextFont { | |||
141 | 142 | ||
142 | extern int gap_Text; /* affected by content font size */ | 143 | extern int gap_Text; /* affected by content font size */ |
143 | 144 | ||
144 | void init_Text (SDL_Renderer *); | 145 | void init_Text (SDL_Renderer *); |
145 | void deinit_Text (void); | 146 | void deinit_Text (void); |
146 | 147 | ||
147 | void setContentFont_Text (enum iTextFont font); | 148 | void setContentFont_Text (enum iTextFont font); |
148 | void setHeadingFont_Text (enum iTextFont font); | 149 | void setHeadingFont_Text (enum iTextFont font); |
149 | void setContentFontSize_Text (float fontSizeFactor); /* affects all except `default*` fonts */ | 150 | void setContentFontSize_Text (float fontSizeFactor); /* affects all except `default*` fonts */ |
150 | void resetFonts_Text (void); | 151 | void resetFonts_Text (void); |
151 | 152 | ||
152 | int lineHeight_Text (int fontId); | 153 | int lineHeight_Text (int fontId); |
153 | iInt2 measure_Text (int fontId, const char *text); | 154 | iInt2 measure_Text (int fontId, const char *text); |
154 | iInt2 measureRange_Text (int fontId, iRangecc text); | 155 | iInt2 measureRange_Text (int fontId, iRangecc text); |
155 | iRect visualBounds_Text (int fontId, iRangecc text); | 156 | iRect visualBounds_Text (int fontId, iRangecc text); |
156 | iInt2 advance_Text (int fontId, const char *text); | 157 | iInt2 advance_Text (int fontId, const char *text); |
157 | iInt2 advanceN_Text (int fontId, const char *text, size_t n); /* `n` in characters */ | 158 | iInt2 advanceN_Text (int fontId, const char *text, size_t n); /* `n` in characters */ |
158 | iInt2 advanceRange_Text (int fontId, iRangecc text); | 159 | iInt2 advanceRange_Text (int fontId, iRangecc text); |
159 | iInt2 advanceWrapRange_Text (int fontId, int maxWidth, iRangecc text); | 160 | iInt2 advanceWrapRange_Text (int fontId, int maxWidth, iRangecc text); |
160 | 161 | ||
161 | iInt2 tryAdvance_Text (int fontId, iRangecc text, int width, const char **endPos); | 162 | iInt2 tryAdvance_Text (int fontId, iRangecc text, int width, const char **endPos); |