Browse Source

Merge pull request #124 from tsoding/utf8-support

Initial support for unicode
Alexey Kutepov 5 years ago
parent
commit
a6705556c9
72 changed files with 126 additions and 5 deletions
  1. 10 2
      .github/workflows/ci.yml
  2. 69 1
      src/aids.hpp
  3. 11 2
      src/vodus_image32.cpp
  4. 1 0
      test/utf8/.gitignore
  5. BIN
      test/utf8/expected-frames/0-frame.png
  6. BIN
      test/utf8/expected-frames/1-frame.png
  7. BIN
      test/utf8/expected-frames/10-frame.png
  8. BIN
      test/utf8/expected-frames/11-frame.png
  9. BIN
      test/utf8/expected-frames/12-frame.png
  10. BIN
      test/utf8/expected-frames/13-frame.png
  11. BIN
      test/utf8/expected-frames/14-frame.png
  12. BIN
      test/utf8/expected-frames/15-frame.png
  13. BIN
      test/utf8/expected-frames/16-frame.png
  14. BIN
      test/utf8/expected-frames/17-frame.png
  15. BIN
      test/utf8/expected-frames/18-frame.png
  16. BIN
      test/utf8/expected-frames/19-frame.png
  17. BIN
      test/utf8/expected-frames/2-frame.png
  18. BIN
      test/utf8/expected-frames/20-frame.png
  19. BIN
      test/utf8/expected-frames/21-frame.png
  20. BIN
      test/utf8/expected-frames/22-frame.png
  21. BIN
      test/utf8/expected-frames/23-frame.png
  22. BIN
      test/utf8/expected-frames/24-frame.png
  23. BIN
      test/utf8/expected-frames/25-frame.png
  24. BIN
      test/utf8/expected-frames/26-frame.png
  25. BIN
      test/utf8/expected-frames/27-frame.png
  26. BIN
      test/utf8/expected-frames/28-frame.png
  27. BIN
      test/utf8/expected-frames/29-frame.png
  28. BIN
      test/utf8/expected-frames/3-frame.png
  29. BIN
      test/utf8/expected-frames/30-frame.png
  30. BIN
      test/utf8/expected-frames/31-frame.png
  31. BIN
      test/utf8/expected-frames/32-frame.png
  32. BIN
      test/utf8/expected-frames/33-frame.png
  33. BIN
      test/utf8/expected-frames/34-frame.png
  34. BIN
      test/utf8/expected-frames/35-frame.png
  35. BIN
      test/utf8/expected-frames/36-frame.png
  36. BIN
      test/utf8/expected-frames/37-frame.png
  37. BIN
      test/utf8/expected-frames/38-frame.png
  38. BIN
      test/utf8/expected-frames/39-frame.png
  39. BIN
      test/utf8/expected-frames/4-frame.png
  40. BIN
      test/utf8/expected-frames/40-frame.png
  41. BIN
      test/utf8/expected-frames/41-frame.png
  42. BIN
      test/utf8/expected-frames/42-frame.png
  43. BIN
      test/utf8/expected-frames/43-frame.png
  44. BIN
      test/utf8/expected-frames/44-frame.png
  45. BIN
      test/utf8/expected-frames/45-frame.png
  46. BIN
      test/utf8/expected-frames/46-frame.png
  47. BIN
      test/utf8/expected-frames/47-frame.png
  48. BIN
      test/utf8/expected-frames/48-frame.png
  49. BIN
      test/utf8/expected-frames/49-frame.png
  50. BIN
      test/utf8/expected-frames/5-frame.png
  51. BIN
      test/utf8/expected-frames/50-frame.png
  52. BIN
      test/utf8/expected-frames/51-frame.png
  53. BIN
      test/utf8/expected-frames/52-frame.png
  54. BIN
      test/utf8/expected-frames/53-frame.png
  55. BIN
      test/utf8/expected-frames/54-frame.png
  56. BIN
      test/utf8/expected-frames/55-frame.png
  57. BIN
      test/utf8/expected-frames/56-frame.png
  58. BIN
      test/utf8/expected-frames/57-frame.png
  59. BIN
      test/utf8/expected-frames/58-frame.png
  60. BIN
      test/utf8/expected-frames/59-frame.png
  61. BIN
      test/utf8/expected-frames/6-frame.png
  62. BIN
      test/utf8/expected-frames/60-frame.png
  63. BIN
      test/utf8/expected-frames/61-frame.png
  64. BIN
      test/utf8/expected-frames/62-frame.png
  65. BIN
      test/utf8/expected-frames/7-frame.png
  66. BIN
      test/utf8/expected-frames/8-frame.png
  67. BIN
      test/utf8/expected-frames/9-frame.png
  68. BIN
      test/utf8/fonts-japanese-gothic.ttf
  69. 0 0
      test/utf8/mapping.csv
  70. 8 0
      test/utf8/test.conf
  71. 24 0
      test/utf8/test.sh
  72. 3 0
      test/utf8/utf-8.txt

+ 10 - 2
.github/workflows/ci.yml

@@ -27,8 +27,12 @@ jobs:
           make -B
           ./emote_downloader
           make render
-          cd ./test/pajaWalk/
+          pushd ./test/pajaWalk/
           ./test.sh
+          popd
+          pushd ./test/utf8/
+          ./test.sh
+          popd
         env:
           CC: gcc
           CXX: g++
@@ -61,8 +65,12 @@ jobs:
           make -B
           ./emote_downloader
           make render
-          cd ./test/pajaWalk/
+          pushd ./test/pajaWalk/
+          ./test.sh
+          popd
+          pushd ./test/utf8/
           ./test.sh
+          popd
         env:
           CC: clang
           CXX: clang++

+ 69 - 1
src/aids.hpp

@@ -21,7 +21,7 @@
 //
 // ============================================================
 //
-// aids — 0.12.1 — std replacement for C++. Designed to aid developers
+// aids — 0.13.0 — std replacement for C++. Designed to aid developers
 // to a better programming experience.
 //
 // https://github.com/rexim/aids
@@ -30,6 +30,8 @@
 //
 // ChangeLog (https://semver.org/ is implied)
 //
+//   0.13.0 void print1(FILE *stream, unsigned int x)
+//          Maybe<uint32_t> utf8_get_code(String_View view, size_t *size)
 //   0.12.1 Fix print1 and sprint1 bug for unsigned long long
 //   0.12.0 void print1(FILE *stream, String_Buffer buffer)
 //          void sprint1(String_Buffer *buffer, String_Buffer another_buffer)
@@ -634,6 +636,11 @@ namespace aids
         fprintf(stream, "%lu", x);
     }
 
+    void print1(FILE *stream, unsigned int x)
+    {
+        fprintf(stream, "%u", x);
+    }
+
     void print1(FILE *stream, int x)
     {
         fprintf(stream, "%d", x);
@@ -690,6 +697,67 @@ namespace aids
     {
         print1(stream, buffer.view());
     }
+
+    ////////////////////////////////////////////////////////////
+    // UTF-8
+    ////////////////////////////////////////////////////////////
+
+    Maybe<uint32_t> utf8_get_code(String_View view, size_t *size)
+    {
+#define UTF8_1BYTE_MASK (1 << 7)
+#define UTF8_2BYTES_MASK (1 << 5)
+#define UTF8_3BYTES_MASK (1 << 4)
+#define UTF8_4BYTES_MASK (1 << 3)
+#define UTF8_EXTRA_BYTE_MASK (1 << 6)
+            if (view.count >= 1 &&
+                (*view.data & UTF8_1BYTE_MASK) == 0)
+            {
+                *size = 1;
+                return {true, static_cast<uint32_t>(*view.data)};
+            }
+            if (view.count >= 2 &&
+                (view.data[0] & UTF8_2BYTES_MASK) == 0 &&
+                (view.data[1] & UTF8_EXTRA_BYTE_MASK) == 0)
+            {
+                *size = 2;
+                const auto byte1 = static_cast<uint32_t>((view.data[0] & (UTF8_2BYTES_MASK - 1)) << 6);
+                const auto byte2 = static_cast<uint32_t>(view.data[1] & (UTF8_EXTRA_BYTE_MASK - 1));
+                return {true, byte1 | byte2};
+            }
+            if (view.count >= 3 &&
+                (view.data[0] & UTF8_3BYTES_MASK) == 0 &&
+                (view.data[1] & UTF8_EXTRA_BYTE_MASK) == 0 &&
+                (view.data[2] & UTF8_EXTRA_BYTE_MASK) == 0)
+            {
+                *size = 3;
+                const auto byte1 = static_cast<uint32_t>((view.data[0] & (UTF8_3BYTES_MASK - 1)) << (6 * 2));
+                const auto byte2 = static_cast<uint32_t>((view.data[1] & (UTF8_EXTRA_BYTE_MASK - 1)) << 6);
+                const auto byte3 = static_cast<uint32_t>(view.data[2] & (UTF8_EXTRA_BYTE_MASK - 1));
+                return {true, byte1 | byte2 | byte3};
+            }
+            if (view.count >= 4 &&
+                (view.data[0] & UTF8_4BYTES_MASK) == 0 &&
+                (view.data[1] & UTF8_EXTRA_BYTE_MASK) == 0 &&
+                (view.data[2] & UTF8_EXTRA_BYTE_MASK) == 0 &&
+                (view.data[3] & UTF8_EXTRA_BYTE_MASK) == 0)
+            {
+                *size = 4;
+                const auto byte1 = static_cast<uint32_t>((view.data[0] & (UTF8_3BYTES_MASK - 1)) << (6 * 3));
+                const auto byte2 = static_cast<uint32_t>((view.data[1] & (UTF8_EXTRA_BYTE_MASK - 1)) << (6 * 2));
+                const auto byte3 = static_cast<uint32_t>((view.data[2] & (UTF8_EXTRA_BYTE_MASK - 1)) << 6);
+                const auto byte4 = static_cast<uint32_t>(view.data[3] & (UTF8_EXTRA_BYTE_MASK - 1));
+                return {true, byte1 | byte2 | byte3 | byte4};
+            }
+            else
+            {
+                return {};
+            }
+#undef UTF8_1BYTE_MASK
+#undef UTF8_2BYTES_MASK
+#undef UTF8_3BYTES_MASK
+#undef UTF8_4BYTES_MASK
+#undef UTF8_EXTRA_BYTE_MASK
+    }
 }
 
 #endif  // AIDS_HPP_

+ 11 - 2
src/vodus_image32.cpp

@@ -399,8 +399,17 @@ void slap_text_onto_image32(Image32 surface,
                             Pixel32 color,
                             int *pen_x, int *pen_y)
 {
-    for (size_t i = 0; i < text.count; ++i) {
-        FT_UInt glyph_index = FT_Get_Char_Index(face, text.data[i]);
+    String_View iter = text;
+
+    while (iter.count > 0) {
+        size_t size = 0;
+        auto code = utf8_get_code(iter, &size);
+        if (!code.has_value) {
+            println(stderr, "`", text, "` is not a correct UTF-8 sequence");
+            abort();
+        }
+        FT_UInt glyph_index = FT_Get_Char_Index(face, code.unwrap);
+        iter.chop(size);
 
         auto error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
         assert(!error);

+ 1 - 0
test/utf8/.gitignore

@@ -0,0 +1 @@
+actual-frames/

BIN
test/utf8/expected-frames/0-frame.png


BIN
test/utf8/expected-frames/1-frame.png


BIN
test/utf8/expected-frames/10-frame.png


BIN
test/utf8/expected-frames/11-frame.png


BIN
test/utf8/expected-frames/12-frame.png


BIN
test/utf8/expected-frames/13-frame.png


BIN
test/utf8/expected-frames/14-frame.png


BIN
test/utf8/expected-frames/15-frame.png


BIN
test/utf8/expected-frames/16-frame.png


BIN
test/utf8/expected-frames/17-frame.png


BIN
test/utf8/expected-frames/18-frame.png


BIN
test/utf8/expected-frames/19-frame.png


BIN
test/utf8/expected-frames/2-frame.png


BIN
test/utf8/expected-frames/20-frame.png


BIN
test/utf8/expected-frames/21-frame.png


BIN
test/utf8/expected-frames/22-frame.png


BIN
test/utf8/expected-frames/23-frame.png


BIN
test/utf8/expected-frames/24-frame.png


BIN
test/utf8/expected-frames/25-frame.png


BIN
test/utf8/expected-frames/26-frame.png


BIN
test/utf8/expected-frames/27-frame.png


BIN
test/utf8/expected-frames/28-frame.png


BIN
test/utf8/expected-frames/29-frame.png


BIN
test/utf8/expected-frames/3-frame.png


BIN
test/utf8/expected-frames/30-frame.png


BIN
test/utf8/expected-frames/31-frame.png


BIN
test/utf8/expected-frames/32-frame.png


BIN
test/utf8/expected-frames/33-frame.png


BIN
test/utf8/expected-frames/34-frame.png


BIN
test/utf8/expected-frames/35-frame.png


BIN
test/utf8/expected-frames/36-frame.png


BIN
test/utf8/expected-frames/37-frame.png


BIN
test/utf8/expected-frames/38-frame.png


BIN
test/utf8/expected-frames/39-frame.png


BIN
test/utf8/expected-frames/4-frame.png


BIN
test/utf8/expected-frames/40-frame.png


BIN
test/utf8/expected-frames/41-frame.png


BIN
test/utf8/expected-frames/42-frame.png


BIN
test/utf8/expected-frames/43-frame.png


BIN
test/utf8/expected-frames/44-frame.png


BIN
test/utf8/expected-frames/45-frame.png


BIN
test/utf8/expected-frames/46-frame.png


BIN
test/utf8/expected-frames/47-frame.png


BIN
test/utf8/expected-frames/48-frame.png


BIN
test/utf8/expected-frames/49-frame.png


BIN
test/utf8/expected-frames/5-frame.png


BIN
test/utf8/expected-frames/50-frame.png


BIN
test/utf8/expected-frames/51-frame.png


BIN
test/utf8/expected-frames/52-frame.png


BIN
test/utf8/expected-frames/53-frame.png


BIN
test/utf8/expected-frames/54-frame.png


BIN
test/utf8/expected-frames/55-frame.png


BIN
test/utf8/expected-frames/56-frame.png


BIN
test/utf8/expected-frames/57-frame.png


BIN
test/utf8/expected-frames/58-frame.png


BIN
test/utf8/expected-frames/59-frame.png


BIN
test/utf8/expected-frames/6-frame.png


BIN
test/utf8/expected-frames/60-frame.png


BIN
test/utf8/expected-frames/61-frame.png


BIN
test/utf8/expected-frames/62-frame.png


BIN
test/utf8/expected-frames/7-frame.png


BIN
test/utf8/expected-frames/8-frame.png


BIN
test/utf8/expected-frames/9-frame.png


BIN
test/utf8/fonts-japanese-gothic.ttf


+ 0 - 0
test/utf8/mapping.csv


+ 8 - 0
test/utf8/test.conf

@@ -0,0 +1,8 @@
+output-type = png
+font = ./fonts-japanese-gothic.ttf
+font_size = 10
+fps = 15
+width = 200
+height = 100
+messages_limit = 20
+bitrate = 6000000

+ 24 - 0
test/utf8/test.sh

@@ -0,0 +1,24 @@
+#!/usr/bin/env sh
+
+VODUS=../../vodus.release
+DIFFIMG=../../diffimg
+
+set -xe
+
+rm -rf ./actual-frames/
+mkdir -p ./actual-frames/
+$VODUS ./utf-8.txt actual-frames/ --config ./test.conf
+
+EXPECTED_COUNT=`ls ./expected-frames/ | wc -l`
+ACTUAL_COUNT=`ls ./actual-frames/ | wc -l`
+
+if [ "$EXPECTED_COUNT" != "$ACTUAL_COUNT" ]; then
+    echo "UNEXPECTED AMOUNT OF FRAMES!"
+    echo "Expected: $EXPECTED_COUNT"
+    echo "Actual:   $ACTUAL_COUNT"
+    exit 1
+fi
+
+for frame in `ls ./expected-frames/`; do
+    $DIFFIMG -e "./expected-frames/$frame" -a "./actual-frames/$frame" -t 2
+done

+ 3 - 0
test/utf8/utf-8.txt

@@ -0,0 +1,3 @@
+[0:00:00] <Tsoding> Hello, World!
+[0:00:01] <Tsoding> Привет, Мир!
+[0:00:02] <Tsoding> こんにちは世界!