diff options
-rw-r--r-- | CMakeLists.txt | 13 | ||||
-rw-r--r-- | Embed.cmake | 6 | ||||
-rw-r--r-- | src/gmdocument.c | 8 | ||||
-rw-r--r-- | src/gmutil.c | 22 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 3 | ||||
-rw-r--r-- | src/ui/text.c | 9 | ||||
-rw-r--r-- | src/ui/text.h | 1 |
7 files changed, 43 insertions, 19 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 5465ae58..03d253ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
@@ -7,6 +7,10 @@ project (Lagrange | |||
7 | ) | 7 | ) |
8 | set (COPYRIGHT_YEAR 2020) | 8 | set (COPYRIGHT_YEAR 2020) |
9 | 9 | ||
10 | # Build configuration. | ||
11 | option (ENABLE_KERNING "Enable kerning in font renderer (slower)" ON) | ||
12 | option (ENABLE_RESOURCE_EMBED "Embed resources inside the executable" OFF) | ||
13 | |||
10 | include (Embed.cmake) | 14 | include (Embed.cmake) |
11 | find_package (the_Foundation REQUIRED) | 15 | find_package (the_Foundation REQUIRED) |
12 | find_package (PkgConfig REQUIRED) | 16 | find_package (PkgConfig REQUIRED) |
@@ -15,7 +19,6 @@ pkg_check_modules (SDL2 REQUIRED sdl2) | |||
15 | # Embedded resources are written to a generated source file. | 19 | # Embedded resources are written to a generated source file. |
16 | message (STATUS "Preparing embedded resources...") | 20 | message (STATUS "Preparing embedded resources...") |
17 | # Fonts are too large to comfortably embed as a C source. | 21 | # Fonts are too large to comfortably embed as a C source. |
18 | set (EMBED_IN_EXECUTABLE OFF CACHE BOOL "Embed resources inside the executable") | ||
19 | set (EMBED_RESOURCES | 22 | set (EMBED_RESOURCES |
20 | res/about/help.gmi | 23 | res/about/help.gmi |
21 | res/about/lagrange.gmi | 24 | res/about/lagrange.gmi |
@@ -113,9 +116,13 @@ target_include_directories (app PUBLIC | |||
113 | ) | 116 | ) |
114 | target_compile_options (app PUBLIC | 117 | target_compile_options (app PUBLIC |
115 | -Werror=implicit-function-declaration | 118 | -Werror=implicit-function-declaration |
119 | -Werror=incompatible-pointer-types | ||
116 | ${SDL2_CFLAGS} | 120 | ${SDL2_CFLAGS} |
117 | ) | 121 | ) |
118 | target_compile_definitions (app PUBLIC LAGRANGE_APP_VERSION="${PROJECT_VERSION}") | 122 | target_compile_definitions (app PUBLIC LAGRANGE_APP_VERSION="${PROJECT_VERSION}") |
123 | if (ENABLE_KERNING) | ||
124 | target_compile_definitions (app PUBLIC LAGRANGE_ENABLE_KERNING=1) | ||
125 | endif () | ||
119 | target_link_libraries (app PUBLIC the_Foundation::the_Foundation) | 126 | target_link_libraries (app PUBLIC the_Foundation::the_Foundation) |
120 | target_link_libraries (app PUBLIC ${SDL2_LDFLAGS}) | 127 | target_link_libraries (app PUBLIC ${SDL2_LDFLAGS}) |
121 | if (APPLE) | 128 | if (APPLE) |
@@ -145,7 +152,7 @@ endif () | |||
145 | # Deployment. | 152 | # Deployment. |
146 | if (MSYS) | 153 | if (MSYS) |
147 | install (TARGETS app DESTINATION .) | 154 | install (TARGETS app DESTINATION .) |
148 | if (NOT EMBED_IN_EXECUTABLE) | 155 | if (NOT ENABLE_RESOURCE_EMBED) |
149 | install (FILES ${EMB_BIN} DESTINATION .) | 156 | install (FILES ${EMB_BIN} DESTINATION .) |
150 | endif () | 157 | endif () |
151 | install (PROGRAMS | 158 | install (PROGRAMS |
@@ -172,7 +179,7 @@ Icon=fi.skyjake.lagrange") | |||
172 | DESTINATION share/icons/hicolor/256x256/apps | 179 | DESTINATION share/icons/hicolor/256x256/apps |
173 | RENAME fi.skyjake.lagrange.png | 180 | RENAME fi.skyjake.lagrange.png |
174 | ) | 181 | ) |
175 | if (NOT EMBED_IN_EXECUTABLE) | 182 | if (NOT ENABLE_RESOURCE_EMBED) |
176 | install (FILES ${EMB_BIN} DESTINATION share/lagrange) | 183 | install (FILES ${EMB_BIN} DESTINATION share/lagrange) |
177 | endif () | 184 | endif () |
178 | endif () | 185 | endif () |
diff --git a/Embed.cmake b/Embed.cmake index 242002f0..f714de02 100644 --- a/Embed.cmake +++ b/Embed.cmake | |||
@@ -2,7 +2,7 @@ | |||
2 | # Copyright: 2020 Jaakko Keränen <jaakko.keranen@iki.fi> | 2 | # Copyright: 2020 Jaakko Keränen <jaakko.keranen@iki.fi> |
3 | # License: BSD 2-Clause | 3 | # License: BSD 2-Clause |
4 | 4 | ||
5 | option (EMBED_IN_EXECUTABLE "Embed resources inside the executable" OFF) | 5 | option (ENABLE_RESOURCE_EMBED "Embed resources inside the executable" OFF) |
6 | # Note: If disabled, the Unix "cat" tool is required for concatenating | 6 | # Note: If disabled, the Unix "cat" tool is required for concatenating |
7 | # the resources into a single "resources.binary" file. | 7 | # the resources into a single "resources.binary" file. |
8 | 8 | ||
@@ -50,7 +50,7 @@ endfunction (embed_write) | |||
50 | function (embed_make) | 50 | function (embed_make) |
51 | set (EMB_H ${CMAKE_CURRENT_BINARY_DIR}/embedded.h) | 51 | set (EMB_H ${CMAKE_CURRENT_BINARY_DIR}/embedded.h) |
52 | set (EMB_C ${CMAKE_CURRENT_BINARY_DIR}/embedded.c) | 52 | set (EMB_C ${CMAKE_CURRENT_BINARY_DIR}/embedded.c) |
53 | if (EMBED_IN_EXECUTABLE) | 53 | if (ENABLE_RESOURCE_EMBED) |
54 | set (needGen NO) | 54 | set (needGen NO) |
55 | if (NOT EXISTS ${EMB_H} OR NOT EXISTS ${EMB_C}) | 55 | if (NOT EXISTS ${EMB_H} OR NOT EXISTS ${EMB_C}) |
56 | set (needGen YES) | 56 | set (needGen YES) |
@@ -68,7 +68,7 @@ function (embed_make) | |||
68 | set (needGen YES) | 68 | set (needGen YES) |
69 | endif () | 69 | endif () |
70 | if (needGen) | 70 | if (needGen) |
71 | if (EMBED_IN_EXECUTABLE) | 71 | if (ENABLE_RESOURCE_EMBED) |
72 | # Compose a source file with the resource data in an array. | 72 | # Compose a source file with the resource data in an array. |
73 | file (WRITE ${EMB_H} "#include <the_Foundation/block.h>\n") | 73 | file (WRITE ${EMB_H} "#include <the_Foundation/block.h>\n") |
74 | file (WRITE ${EMB_C} "#include \"embedded.h\"\n") | 74 | file (WRITE ${EMB_C} "#include \"embedded.h\"\n") |
diff --git a/src/gmdocument.c b/src/gmdocument.c index 42aec9e6..89d567b0 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -192,9 +192,12 @@ iInt2 measurePreformattedBlock_GmDocument_(const iGmDocument *d, const char *sta | |||
192 | } | 192 | } |
193 | 193 | ||
194 | static iRangecc addLink_GmDocument_(iGmDocument *d, iRangecc line, iGmLinkId *linkId) { | 194 | static iRangecc addLink_GmDocument_(iGmDocument *d, iRangecc line, iGmLinkId *linkId) { |
195 | iRegExp *pattern = new_RegExp("=>\\s*([^\\s]+)(\\s.*)?", caseInsensitive_RegExpOption); | 195 | static iRegExp *pattern_; |
196 | if (!pattern_) { | ||
197 | pattern_ = new_RegExp("=>\\s*([^\\s]+)(\\s.*)?", caseInsensitive_RegExpOption); | ||
198 | } | ||
196 | iRegExpMatch m; | 199 | iRegExpMatch m; |
197 | if (matchRange_RegExp(pattern, line, &m)) { | 200 | if (matchRange_RegExp(pattern_, line, &m)) { |
198 | iGmLink *link = new_GmLink(); | 201 | iGmLink *link = new_GmLink(); |
199 | setRange_String(&link->url, capturedRange_RegExpMatch(&m, 1)); | 202 | setRange_String(&link->url, capturedRange_RegExpMatch(&m, 1)); |
200 | set_String(&link->url, absoluteUrl_String(&d->url, &link->url)); | 203 | set_String(&link->url, absoluteUrl_String(&d->url, &link->url)); |
@@ -254,7 +257,6 @@ static iRangecc addLink_GmDocument_(iGmDocument *d, iRangecc line, iGmLinkId *li | |||
254 | line = capturedRange_RegExpMatch(&m, 1); /* Show the URL. */ | 257 | line = capturedRange_RegExpMatch(&m, 1); /* Show the URL. */ |
255 | } | 258 | } |
256 | } | 259 | } |
257 | iRelease(pattern); | ||
258 | return line; | 260 | return line; |
259 | } | 261 | } |
260 | 262 | ||
diff --git a/src/gmutil.c b/src/gmutil.c index d278669d..cd00eb1d 100644 --- a/src/gmutil.c +++ b/src/gmutil.c | |||
@@ -27,12 +27,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
27 | #include <the_Foundation/path.h> | 27 | #include <the_Foundation/path.h> |
28 | 28 | ||
29 | void init_Url(iUrl *d, const iString *text) { | 29 | void init_Url(iUrl *d, const iString *text) { |
30 | iRegExp *absPat = | 30 | static iRegExp *absoluteUrlPattern_; |
31 | new_RegExp("([a-z]+:)?(//[^/:?]*)(:[0-9]+)?([^?]*)(\\?.*)?", caseInsensitive_RegExpOption); | 31 | static iRegExp *relativeUrlPattern_; |
32 | if (!absoluteUrlPattern_) { | ||
33 | absoluteUrlPattern_ = new_RegExp("([a-z]+:)?(//[^/:?]*)(:[0-9]+)?([^?]*)(\\?.*)?", | ||
34 | caseInsensitive_RegExpOption); | ||
35 | } | ||
32 | iRegExpMatch m; | 36 | iRegExpMatch m; |
33 | if (matchString_RegExp(absPat, text, &m)) { | 37 | if (matchString_RegExp(absoluteUrlPattern_, text, &m)) { |
34 | d->protocol = capturedRange_RegExpMatch(&m, 1); | 38 | d->protocol = capturedRange_RegExpMatch(&m, 1); |
35 | d->host = capturedRange_RegExpMatch(&m, 2); | 39 | d->host = capturedRange_RegExpMatch(&m, 2); |
36 | if (!isEmpty_Range(&d->host)) { | 40 | if (!isEmpty_Range(&d->host)) { |
37 | d->host.start += 2; /* skip the double slash */ | 41 | d->host.start += 2; /* skip the double slash */ |
38 | } | 42 | } |
@@ -40,21 +44,21 @@ void init_Url(iUrl *d, const iString *text) { | |||
40 | if (!isEmpty_Range(&d->port)) { | 44 | if (!isEmpty_Range(&d->port)) { |
41 | d->port.start++; /* omit the colon */ | 45 | d->port.start++; /* omit the colon */ |
42 | } | 46 | } |
43 | d->path = capturedRange_RegExpMatch(&m, 4); | 47 | d->path = capturedRange_RegExpMatch(&m, 4); |
44 | d->query = capturedRange_RegExpMatch(&m, 5); | 48 | d->query = capturedRange_RegExpMatch(&m, 5); |
45 | } | 49 | } |
46 | else { | 50 | else { |
47 | /* Must be a relative path. */ | 51 | /* Must be a relative path. */ |
48 | iZap(*d); | 52 | iZap(*d); |
49 | iRegExp *relPat = new_RegExp("([a-z]+:)?([^?]*)(\\?.*)?", 0); | 53 | if (!relativeUrlPattern_) { |
50 | if (matchString_RegExp(relPat, text, &m)) { | 54 | relativeUrlPattern_ = new_RegExp("([a-z]+:)?([^?]*)(\\?.*)?", 0); |
55 | } | ||
56 | if (matchString_RegExp(relativeUrlPattern_, text, &m)) { | ||
51 | d->protocol = capturedRange_RegExpMatch(&m, 1); | 57 | d->protocol = capturedRange_RegExpMatch(&m, 1); |
52 | d->path = capturedRange_RegExpMatch(&m, 2); | 58 | d->path = capturedRange_RegExpMatch(&m, 2); |
53 | d->query = capturedRange_RegExpMatch(&m, 3); | 59 | d->query = capturedRange_RegExpMatch(&m, 3); |
54 | } | 60 | } |
55 | iRelease(relPat); | ||
56 | } | 61 | } |
57 | iRelease(absPat); | ||
58 | if (!isEmpty_Range(&d->protocol)) { | 62 | if (!isEmpty_Range(&d->protocol)) { |
59 | d->protocol.end--; /* omit the colon */ | 63 | d->protocol.end--; /* omit the colon */ |
60 | } | 64 | } |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 45bd4868..c39d9f12 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -1731,11 +1731,14 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
1731 | visBuf->index = vbDst; | 1731 | visBuf->index = vbDst; |
1732 | } | 1732 | } |
1733 | /* Dynamic content. */ { | 1733 | /* Dynamic content. */ { |
1734 | extern int enableKerning_Text; | ||
1735 | enableKerning_Text = iFalse; /* need to be fast, these is redone on every redraw */ | ||
1734 | iPaint *p = &ctxDynamic.paint; | 1736 | iPaint *p = &ctxDynamic.paint; |
1735 | init_Paint(p); | 1737 | init_Paint(p); |
1736 | setClip_Paint(p, bounds); | 1738 | setClip_Paint(p, bounds); |
1737 | render_GmDocument(d->doc, visRange, drawRun_DrawContext_, &ctxDynamic); | 1739 | render_GmDocument(d->doc, visRange, drawRun_DrawContext_, &ctxDynamic); |
1738 | unsetClip_Paint(p); | 1740 | unsetClip_Paint(p); |
1741 | enableKerning_Text = iTrue; | ||
1739 | } | 1742 | } |
1740 | 1743 | ||
1741 | // drawRect_Paint(&ctx.paint, | 1744 | // drawRect_Paint(&ctx.paint, |
diff --git a/src/ui/text.c b/src/ui/text.c index b4b7fb0c..40956e29 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -48,6 +48,7 @@ iDeclareTypeConstructionArgs(Glyph, iChar ch) | |||
48 | 48 | ||
49 | int gap_Text; /* cf. gap_UI in metrics.h */ | 49 | int gap_Text; /* cf. gap_UI in metrics.h */ |
50 | int enableHalfPixelGlyphs_Text = iTrue; /* debug setting */ | 50 | int enableHalfPixelGlyphs_Text = iTrue; /* debug setting */ |
51 | int enableKerning_Text = iTrue; /* looking up kern pairs is slow */ | ||
51 | 52 | ||
52 | struct Impl_Glyph { | 53 | struct Impl_Glyph { |
53 | iHashNode node; | 54 | iHashNode node; |
@@ -85,6 +86,7 @@ struct Impl_Font { | |||
85 | int baseline; | 86 | int baseline; |
86 | iHash glyphs; | 87 | iHash glyphs; |
87 | iBool isMonospaced; | 88 | iBool isMonospaced; |
89 | iBool manualKernOnly; | ||
88 | enum iFontId symbolsFont; /* font to use for symbols */ | 90 | enum iFontId symbolsFont; /* font to use for symbols */ |
89 | }; | 91 | }; |
90 | 92 | ||
@@ -176,6 +178,9 @@ static void initFonts_Text_(iText *d) { | |||
176 | if (fontData[i].ttf == &fontFiraMonoRegular_Embedded) { | 178 | if (fontData[i].ttf == &fontFiraMonoRegular_Embedded) { |
177 | font->isMonospaced = iTrue; | 179 | font->isMonospaced = iTrue; |
178 | } | 180 | } |
181 | if (i == default_FontId || i == defaultMedium_FontId) { | ||
182 | font->manualKernOnly = iTrue; | ||
183 | } | ||
179 | } | 184 | } |
180 | gap_Text = iRound(gap_UI * d->contentFontSize); | 185 | gap_Text = iRound(gap_UI * d->contentFontSize); |
181 | } | 186 | } |
@@ -511,9 +516,11 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
511 | /* Manual kerning for double-slash. */ | 516 | /* Manual kerning for double-slash. */ |
512 | xpos -= glyph->rect[hoff].size.x * 0.5f; | 517 | xpos -= glyph->rect[hoff].size.x * 0.5f; |
513 | } | 518 | } |
514 | else if (next) { | 519 | #if defined (LAGRANGE_ENABLE_KERNING) |
520 | else if (enableKerning_Text && !d->manualKernOnly && next) { | ||
515 | xpos += d->scale * stbtt_GetCodepointKernAdvance(&d->font, ch, next); | 521 | xpos += d->scale * stbtt_GetCodepointKernAdvance(&d->font, ch, next); |
516 | } | 522 | } |
523 | #endif | ||
517 | } | 524 | } |
518 | prevCh = ch; | 525 | prevCh = ch; |
519 | if (--maxLen == 0) { | 526 | if (--maxLen == 0) { |
diff --git a/src/ui/text.h b/src/ui/text.h index edd7ed4e..2b4ec5c3 100644 --- a/src/ui/text.h +++ b/src/ui/text.h | |||
@@ -58,6 +58,7 @@ enum iFontId { | |||
58 | hugeEmoji_FontId, | 58 | hugeEmoji_FontId, |
59 | smallEmoji_FontId, | 59 | smallEmoji_FontId, |
60 | max_FontId, | 60 | max_FontId, |
61 | |||
61 | /* Meta: */ | 62 | /* Meta: */ |
62 | fromSymbolsToEmojiOffset_FontId = 7, | 63 | fromSymbolsToEmojiOffset_FontId = 7, |
63 | /* UI fonts: */ | 64 | /* UI fonts: */ |