Lagrange [work/v1.15]

Added Kosugi Maru for Japanese text

=> b505a32d5e3dc6f8405cf48a5f854b1c09534038

diff --git a/CMakeLists.txt b/CMakeLists.txt
index f0968831..2d7128ed 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,6 +41,7 @@ set (EMBED_RESOURCES
     res/FiraSans-Italic.ttf
     res/FiraSans-Light.ttf
     res/FiraSans-Regular.ttf
+    res/KosugiMaru-Regular.ttf
     res/NotoEmoji-Regular.ttf
     res/Nunito-ExtraBold.ttf
     res/Nunito-ExtraLight.ttf
diff --git a/res/KosugiMaru-Regular.ttf b/res/KosugiMaru-Regular.ttf
new file mode 100644
index 00000000..44dcbff6
Binary files /dev/null and b/res/KosugiMaru-Regular.ttf differ
diff --git a/res/LICENSE_KosugiMaru.txt b/res/LICENSE_KosugiMaru.txt
new file mode 100644
index 00000000..75b52484
--- /dev/null
+++ b/res/LICENSE_KosugiMaru.txt
@@ -0,0 +1,202 @@
+

+                                 Apache License

+                           Version 2.0, January 2004

+                        http://www.apache.org/licenses/

+

+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

+

+   1. Definitions.

+

+      "License" shall mean the terms and conditions for use, reproduction,

+      and distribution as defined by Sections 1 through 9 of this document.

+

+      "Licensor" shall mean the copyright owner or entity authorized by

+      the copyright owner that is granting the License.

+

+      "Legal Entity" shall mean the union of the acting entity and all

+      other entities that control, are controlled by, or are under common

+      control with that entity. For the purposes of this definition,

+      "control" means (i) the power, direct or indirect, to cause the

+      direction or management of such entity, whether by contract or

+      otherwise, or (ii) ownership of fifty percent (50%) or more of the

+      outstanding shares, or (iii) beneficial ownership of such entity.

+

+      "You" (or "Your") shall mean an individual or Legal Entity

+      exercising permissions granted by this License.

+

+      "Source" form shall mean the preferred form for making modifications,

+      including but not limited to software source code, documentation

+      source, and configuration files.

+

+      "Object" form shall mean any form resulting from mechanical

+      transformation or translation of a Source form, including but

+      not limited to compiled object code, generated documentation,

+      and conversions to other media types.

+

+      "Work" shall mean the work of authorship, whether in Source or

+      Object form, made available under the License, as indicated by a

+      copyright notice that is included in or attached to the work

+      (an example is provided in the Appendix below).

+

+      "Derivative Works" shall mean any work, whether in Source or Object

+      form, that is based on (or derived from) the Work and for which the

+      editorial revisions, annotations, elaborations, or other modifications

+      represent, as a whole, an original work of authorship. For the purposes

+      of this License, Derivative Works shall not include works that remain

+      separable from, or merely link (or bind by name) to the interfaces of,

+      the Work and Derivative Works thereof.

+

+      "Contribution" shall mean any work of authorship, including

+      the original version of the Work and any modifications or additions

+      to that Work or Derivative Works thereof, that is intentionally

+      submitted to Licensor for inclusion in the Work by the copyright owner

+      or by an individual or Legal Entity authorized to submit on behalf of

+      the copyright owner. For the purposes of this definition, "submitted"

+      means any form of electronic, verbal, or written communication sent

+      to the Licensor or its representatives, including but not limited to

+      communication on electronic mailing lists, source code control systems,

+      and issue tracking systems that are managed by, or on behalf of, the

+      Licensor for the purpose of discussing and improving the Work, but

+      excluding communication that is conspicuously marked or otherwise

+      designated in writing by the copyright owner as "Not a Contribution."

+

+      "Contributor" shall mean Licensor and any individual or Legal Entity

+      on behalf of whom a Contribution has been received by Licensor and

+      subsequently incorporated within the Work.

+

+   2. Grant of Copyright License. Subject to the terms and conditions of

+      this License, each Contributor hereby grants to You a perpetual,

+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+      copyright license to reproduce, prepare Derivative Works of,

+      publicly display, publicly perform, sublicense, and distribute the

+      Work and such Derivative Works in Source or Object form.

+

+   3. Grant of Patent License. Subject to the terms and conditions of

+      this License, each Contributor hereby grants to You a perpetual,

+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+      (except as stated in this section) patent license to make, have made,

+      use, offer to sell, sell, import, and otherwise transfer the Work,

+      where such license applies only to those patent claims licensable

+      by such Contributor that are necessarily infringed by their

+      Contribution(s) alone or by combination of their Contribution(s)

+      with the Work to which such Contribution(s) was submitted. If You

+      institute patent litigation against any entity (including a

+      cross-claim or counterclaim in a lawsuit) alleging that the Work

+      or a Contribution incorporated within the Work constitutes direct

+      or contributory patent infringement, then any patent licenses

+      granted to You under this License for that Work shall terminate

+      as of the date such litigation is filed.

+

+   4. Redistribution. You may reproduce and distribute copies of the

+      Work or Derivative Works thereof in any medium, with or without

+      modifications, and in Source or Object form, provided that You

+      meet the following conditions:

+

+      (a) You must give any other recipients of the Work or

+          Derivative Works a copy of this License; and

+

+      (b) You must cause any modified files to carry prominent notices

+          stating that You changed the files; and

+

+      (c) You must retain, in the Source form of any Derivative Works

+          that You distribute, all copyright, patent, trademark, and

+          attribution notices from the Source form of the Work,

+          excluding those notices that do not pertain to any part of

+          the Derivative Works; and

+

+      (d) If the Work includes a "NOTICE" text file as part of its

+          distribution, then any Derivative Works that You distribute must

+          include a readable copy of the attribution notices contained

+          within such NOTICE file, excluding those notices that do not

+          pertain to any part of the Derivative Works, in at least one

+          of the following places: within a NOTICE text file distributed

+          as part of the Derivative Works; within the Source form or

+          documentation, if provided along with the Derivative Works; or,

+          within a display generated by the Derivative Works, if and

+          wherever such third-party notices normally appear. The contents

+          of the NOTICE file are for informational purposes only and

+          do not modify the License. You may add Your own attribution

+          notices within Derivative Works that You distribute, alongside

+          or as an addendum to the NOTICE text from the Work, provided

+          that such additional attribution notices cannot be construed

+          as modifying the License.

+

+      You may add Your own copyright statement to Your modifications and

+      may provide additional or different license terms and conditions

+      for use, reproduction, or distribution of Your modifications, or

+      for any such Derivative Works as a whole, provided Your use,

+      reproduction, and distribution of the Work otherwise complies with

+      the conditions stated in this License.

+

+   5. Submission of Contributions. Unless You explicitly state otherwise,

+      any Contribution intentionally submitted for inclusion in the Work

+      by You to the Licensor shall be under the terms and conditions of

+      this License, without any additional terms or conditions.

+      Notwithstanding the above, nothing herein shall supersede or modify

+      the terms of any separate license agreement you may have executed

+      with Licensor regarding such Contributions.

+

+   6. Trademarks. This License does not grant permission to use the trade

+      names, trademarks, service marks, or product names of the Licensor,

+      except as required for reasonable and customary use in describing the

+      origin of the Work and reproducing the content of the NOTICE file.

+

+   7. Disclaimer of Warranty. Unless required by applicable law or

+      agreed to in writing, Licensor provides the Work (and each

+      Contributor provides its Contributions) on an "AS IS" BASIS,

+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or

+      implied, including, without limitation, any warranties or conditions

+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A

+      PARTICULAR PURPOSE. You are solely responsible for determining the

+      appropriateness of using or redistributing the Work and assume any

+      risks associated with Your exercise of permissions under this License.

+

+   8. Limitation of Liability. In no event and under no legal theory,

+      whether in tort (including negligence), contract, or otherwise,

+      unless required by applicable law (such as deliberate and grossly

+      negligent acts) or agreed to in writing, shall any Contributor be

+      liable to You for damages, including any direct, indirect, special,

+      incidental, or consequential damages of any character arising as a

+      result of this License or out of the use or inability to use the

+      Work (including but not limited to damages for loss of goodwill,

+      work stoppage, computer failure or malfunction, or any and all

+      other commercial damages or losses), even if such Contributor

+      has been advised of the possibility of such damages.

+

+   9. Accepting Warranty or Additional Liability. While redistributing

+      the Work or Derivative Works thereof, You may choose to offer,

+      and charge a fee for, acceptance of support, warranty, indemnity,

+      or other liability obligations and/or rights consistent with this

+      License. However, in accepting such obligations, You may act only

+      on Your own behalf and on Your sole responsibility, not on behalf

+      of any other Contributor, and only if You agree to indemnify,

+      defend, and hold each Contributor harmless for any liability

+      incurred by, or claims asserted against, such Contributor by reason

+      of your accepting any such warranty or additional liability.

+

+   END OF TERMS AND CONDITIONS

+

+   APPENDIX: How to apply the Apache License to your work.

+

+      To apply the Apache License to your work, attach the following

+      boilerplate notice, with the fields enclosed by brackets "[]"

+      replaced with your own identifying information. (Don't include

+      the brackets!)  The text should be enclosed in the appropriate

+      comment syntax for the file format. We also recommend that a

+      file or class name and description of purpose be included on the

+      same "printed page" as the copyright notice for easier

+      identification within third-party archives.

+

+   Copyright [yyyy] [name of copyright owner]

+

+   Licensed under the Apache License, Version 2.0 (the "License");

+   you may not use this file except in compliance with the License.

+   You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

diff --git a/res/OFL.txt b/res/LICENSE_Nunito.txt
similarity index 100%
rename from res/OFL.txt
rename to res/LICENSE_Nunito.txt
diff --git a/res/about/help.gmi b/res/about/help.gmi
index 1be94132..9f394e5a 100644
--- a/res/about/help.gmi
+++ b/res/about/help.gmi
@@ -199,5 +199,6 @@ This application uses fonts licensed under the Open Font License.
 
 Additional fonts:
 
+=> https://fonts.google.com/specimen/Kosugi+Maru#license  Kosugi Maru (Apache License 2.0)
 => https://github.com/googlefonts/noto-emoji/blob/master/LICENSE  Noto Emoji (Apache License 2.0)
 => https://dn-works.com/ufas/  Symbola (Public Domain)
\ No newline at end of file
diff --git a/src/ui/text.c b/src/ui/text.c
index 3de1c83b..a48d0e0e 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -92,6 +92,7 @@ struct Impl_Font {
     iBool          isMonospaced;
     iBool          manualKernOnly;
     enum iFontId   symbolsFont; /* font to use for symbols */
+    enum iFontId   japaneseFont; /* font to use for Japanese glyphs */
     uint32_t       indexTable[128 - 32];
 };
 
@@ -108,6 +109,7 @@ static void init_Font(iFont *d, const iBlock *data, int height, enum iFontId sym
     stbtt_GetFontVMetrics(&d->font, &ascent, NULL, NULL);
     d->baseline = (int) ascent * d->scale;
     d->symbolsFont = symbolsFont;
+    d->japaneseFont = regularJapanese_FontId;
     d->isMonospaced = iFalse;
     memset(d->indexTable, 0xff, sizeof(d->indexTable));
 }
@@ -189,6 +191,11 @@ static void initFonts_Text_(iText *d) {
         { &fontNotoEmojiRegular_Embedded,     textSize * 1.666f,    largeSymbols_FontId },
         { &fontNotoEmojiRegular_Embedded,     textSize * 2.000f,    hugeSymbols_FontId },
         { &fontNotoEmojiRegular_Embedded,     textSize * 0.866f,    smallSymbols_FontId },
+        { &fontKosugiMaruRegular_Embedded,    textSize * 0.666f,    smallSymbols_FontId },
+        { &fontKosugiMaruRegular_Embedded,    textSize,             symbols_FontId },
+        { &fontKosugiMaruRegular_Embedded,    textSize * 1.333f,    mediumSymbols_FontId },
+        { &fontKosugiMaruRegular_Embedded,    textSize * 1.666f,    largeSymbols_FontId },
+        { &fontKosugiMaruRegular_Embedded,    textSize * 2.000f,    hugeSymbols_FontId },
     };
     iForIndices(i, fontData) {
         iFont *font = &d->fonts[i];
@@ -200,6 +207,18 @@ static void initFonts_Text_(iText *d) {
             font->manualKernOnly = iTrue;
         }
     }
+    /* Japanese script. */ {
+        /* Everything defaults to the regular sized japanese font, so these are just
+           the other sizes. */
+        /* TODO: Add these to the table above... */
+        font_Text_(monospace_FontId)->japaneseFont      = smallJapanese_FontId;
+        font_Text_(monospaceSmall_FontId)->japaneseFont = smallJapanese_FontId;
+        font_Text_(medium_FontId)->japaneseFont         = mediumJapanese_FontId;
+        font_Text_(mediumBold_FontId)->japaneseFont     = mediumJapanese_FontId;
+        font_Text_(largeBold_FontId)->japaneseFont      = largeJapanese_FontId;
+        font_Text_(largeLight_FontId)->japaneseFont     = largeJapanese_FontId;
+        font_Text_(hugeBold_FontId)->japaneseFont       = hugeJapanese_FontId;
+    }
     gap_Text = iRound(gap_UI * d->contentFontSize);
 }
 
@@ -344,13 +363,19 @@ static void cache_Font_(iFont *d, iGlyph *glyph, int hoff) {
     SDL_Renderer *render = txt->render;
     SDL_Texture *tex = NULL;
     SDL_Surface *surface = NULL;
-    const iChar ch = char_Glyph(glyph);
     iRect *glRect = &glyph->rect[hoff];
     /* Rasterize the glyph using stbtt. */ {
         surface = rasterizeGlyph_Font_(d, glyph->glyphIndex, hoff * 0.5f);
         if (hoff == 0) {
             int adv;
-            stbtt_GetGlyphHMetrics(&d->font, glyph->glyphIndex, &adv, NULL);
+            const uint32_t gIndex = glyph->glyphIndex;
+//            float advScale = d->scale;
+//            if (isJapanese_FontId(d - text_.fonts)) {
+                /* Treat as monospace. */
+//                gIndex = stbtt_FindGlyphIndex(&d->font, 0x5712);
+//                advScale *= 2.0f;
+//            }
+            stbtt_GetGlyphHMetrics(&d->font, gIndex, &adv, NULL);
             glyph->advance = d->scale * adv;
         }
         stbtt_GetGlyphBitmapBoxSubpixel(&d->font,
@@ -389,6 +414,13 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) {
             return emoji;
         }
     }
+    /* Japanese perhaps? */
+    if (ch > 0x3040) {
+        iFont *japanese = font_Text_(d->japaneseFont);
+        if (japanese != d && (*glyphIndex = glyphIndex_Font_(japanese, ch)) != 0) {
+            return japanese;
+        }
+    }
     /* Fall back to Symbola for anything else. */
     iFont *font = font_Text_(d->symbolsFont);
     *glyphIndex = glyphIndex_Font_(font, ch);
@@ -437,6 +469,10 @@ static iChar nextChar_(const char **chPos, const char *end) {
     return ch;
 }
 
+static enum iFontId fontId_Text_(const iFont *font) {
+    return font - text_.fonts;
+}
+
 iLocalDef iBool isWrapBoundary_(iChar a, iChar b) {
     if (b == '/' || b == '-' || b == ',' || b == ';' || b == ':') {
         return iTrue;
@@ -540,29 +576,24 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
             SDL_RenderCopy(text_.render, text_.cache, (const SDL_Rect *) &glyph->rect[hoff], &dst);
         }
         /* Symbols and emojis are NOT monospaced, so must conform when the primary font
-           is monospaced. */
-        xpos += (d->isMonospaced && glyph->font != d ? monoAdvance : glyph->advance);
+           is monospaced. Except with Japanese script, that's larger than the normal monospace. */
+        xpos += (monoAdvance > 0 && !isJapanese_FontId(fontId_Text_(glyph->font)) ? monoAdvance
+                                                                                  : glyph->advance);
         xposMax = iMax(xposMax, xpos);
         if (continueFrom_out && (mode == measureNoWrap_RunMode || isWrapBoundary_(prevCh, ch))) {
             lastWordEnd = chPos;
         }
+#if defined (LAGRANGE_ENABLE_KERNING)
         /* Check the next character. */
         if (!d->isMonospaced && glyph->font == d) {
             /* TODO: No need to decode the next char twice; check this on the next iteration. */
             const char *peek = chPos;
             const iChar next = nextChar_(&peek, text.end);
-#if 0
-            if (ch == '/' && next == '/') {
-                /* Manual kerning for double-slash. */
-                xpos -= glyph->rect[hoff].size.x * 0.5f;
-            } else
-#endif
-#if defined (LAGRANGE_ENABLE_KERNING)
             if (enableKerning_Text && !d->manualKernOnly && next) {
                 xpos += d->scale * stbtt_GetGlyphKernAdvance(&d->font, glyph->glyphIndex, next);
             }
-#endif
         }
+#endif
         prevCh = ch;
         if (--maxLen == 0) {
             break;
diff --git a/src/ui/text.h b/src/ui/text.h
index 2b4ec5c3..9a22620f 100644
--- a/src/ui/text.h
+++ b/src/ui/text.h
@@ -40,7 +40,7 @@ enum iFontId {
     mediumBold_FontId,
     largeBold_FontId,
     hugeBold_FontId,
-    largeLight_FontId,
+    largeLight_FontId,    
     /* symbol fonts */
     defaultSymbols_FontId,
     defaultMediumSymbols_FontId,
@@ -57,10 +57,17 @@ enum iFontId {
     largeEmoji_FontId,
     hugeEmoji_FontId,
     smallEmoji_FontId,
+    /* japanese script */
+    smallJapanese_FontId,
+    regularJapanese_FontId,
+    mediumJapanese_FontId,
+    largeJapanese_FontId,
+    hugeJapanese_FontId,
     max_FontId,
 
     /* Meta: */
     fromSymbolsToEmojiOffset_FontId = 7,
+
     /* UI fonts: */
     uiLabel_FontId        = default_FontId,
     uiShortcuts_FontId    = default_FontId,
@@ -78,6 +85,10 @@ enum iFontId {
     banner_FontId            = largeLight_FontId,
 };
 
+iLocalDef iBool isJapanese_FontId(enum iFontId id) {
+    return id >= smallJapanese_FontId && id <= hugeJapanese_FontId;
+}
+
 #define variationSelectorEmoji_Char     ((iChar) 0xfe0f)
 
 extern int gap_Text; /* affected by content font size */
Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/work%2Fv1.15/cdiff/b505a32d5e3dc6f8405cf48a5f854b1c09534038
Status Code
Success (20)
Meta
text/gemini; charset=utf-8
Capsule Response Time
197.94858 milliseconds
Gemini-to-HTML Time
0.894616 milliseconds

This content has been proxied by September (ba2dc).