[pango: 1/2] Issue #322 - Vertical text doesn't fall back to rotated versions ...



commit d2975902a87d3f4a6ff5806c35686c40af48ae70
Author: ONO Yoshio <ohtsuka yoshio gmail com>
Date:   Wed Oct 17 17:37:19 2018 +0900

    Issue #322 - Vertical text doesn't fall back to rotated versions ...
    
    ...of horizontal glyphs when necessary
    
    Implemented UAX#50 to determine whether characters rotate or not
    in vertical layout.

 pango/pango-context.c                     | 75 ++++++++++++++++++++++---------
 tools/gen-vertical-orientation-U-table.py | 54 ++++++++++++++++++++++
 2 files changed, 108 insertions(+), 21 deletions(-)
---
diff --git a/pango/pango-context.c b/pango/pango-context.c
index b48b0eaa..65602bb0 100644
--- a/pango/pango-context.c
+++ b/pango/pango-context.c
@@ -706,7 +706,7 @@ struct _PangoWidthIter
        const gchar *text_end;
        const gchar *start;
        const gchar *end;
-       gboolean wide;
+       gboolean     upright;
 };
 
 typedef struct _ItemizeState ItemizeState;
@@ -853,25 +853,58 @@ update_end (ItemizeState *state)
     state->run_end = state->emoji_iter.end;
 }
 
-/* g_unichar_iswide() uses EastAsianWidth, which is broken.
- * We should switch to using VerticalTextLayout:
- * http://www.unicode.org/reports/tr50/#Data50
- *
- * In the mean time, fixup Hangul jamo to be all wide so we
- * don't break run in the middle.  The EastAsianWidth has
- * 'W' for L-jamo, and 'N' for T and V jamo!
- *
- * https://bugzilla.gnome.org/show_bug.cgi?id=705727
- */
 static gboolean
-width_iter_iswide (gunichar ch)
+width_iter_is_upright (gunichar ch)
 {
-  if ((0x1100u <= ch && ch <= 0x11FFu) ||
-      (0xA960u <= ch && ch <= 0xA97Cu) ||
-      (0xD7B0u <= ch && ch <= 0xD7FBu))
-    return TRUE;
+  /* https://www.unicode.org/Public/11.0.0/ucd/VerticalOrientation.txt
+   * VO=U or Tu table generated by tools/gen-vertical-orientation-U-table.py.
+   *
+   * FIXME: In the future, If GLib supports VerticalOrientation, please use it.
+   */
+  static const gunichar upright[][2] = {
+    {0x00A7, 0x00A7}, {0x00A9, 0x00A9}, {0x00AE, 0x00AE}, {0x00B1, 0x00B1},
+    {0x00BC, 0x00BE}, {0x00D7, 0x00D7}, {0x00F7, 0x00F7}, {0x02EA, 0x02EB},
+    {0x1100, 0x11FF}, {0x1401, 0x167F}, {0x18B0, 0x18FF}, {0x2016, 0x2016},
+    {0x2020, 0x2021}, {0x2030, 0x2031}, {0x203B, 0x203C}, {0x2042, 0x2042},
+    {0x2047, 0x2049}, {0x2051, 0x2051}, {0x2065, 0x2065}, {0x20DD, 0x20E0},
+    {0x20E2, 0x20E4}, {0x2100, 0x2101}, {0x2103, 0x2109}, {0x210F, 0x210F},
+    {0x2113, 0x2114}, {0x2116, 0x2117}, {0x211E, 0x2123}, {0x2125, 0x2125},
+    {0x2127, 0x2127}, {0x2129, 0x2129}, {0x212E, 0x212E}, {0x2135, 0x213F},
+    {0x2145, 0x214A}, {0x214C, 0x214D}, {0x214F, 0x2189}, {0x218C, 0x218F},
+    {0x221E, 0x221E}, {0x2234, 0x2235}, {0x2300, 0x2307}, {0x230C, 0x231F},
+    {0x2324, 0x2328}, {0x232B, 0x232B}, {0x237D, 0x239A}, {0x23BE, 0x23CD},
+    {0x23CF, 0x23CF}, {0x23D1, 0x23DB}, {0x23E2, 0x2422}, {0x2424, 0x24FF},
+    {0x25A0, 0x2619}, {0x2620, 0x2767}, {0x2776, 0x2793}, {0x2B12, 0x2B2F},
+    {0x2B50, 0x2B59}, {0x2BB8, 0x2BD1}, {0x2BD3, 0x2BEB}, {0x2BF0, 0x2BFF},
+    {0x2E80, 0x3007}, {0x3012, 0x3013}, {0x3020, 0x302F}, {0x3031, 0x309F},
+    {0x30A1, 0x30FB}, {0x30FD, 0xA4CF}, {0xA960, 0xA97F}, {0xAC00, 0xD7FF},
+    {0xE000, 0xFAFF}, {0xFE10, 0xFE1F}, {0xFE30, 0xFE48}, {0xFE50, 0xFE57},
+    {0xFE5F, 0xFE62}, {0xFE67, 0xFE6F}, {0xFF01, 0xFF07}, {0xFF0A, 0xFF0C},
+    {0xFF0E, 0xFF19}, {0xFF1F, 0xFF3A}, {0xFF3C, 0xFF3C}, {0xFF3E, 0xFF3E},
+    {0xFF40, 0xFF5A}, {0xFFE0, 0xFFE2}, {0xFFE4, 0xFFE7}, {0xFFF0, 0xFFF8},
+    {0xFFFC, 0xFFFD}, {0x10980, 0x1099F}, {0x11580, 0x115FF}, {0x11A00, 0x11AAF},
+    {0x13000, 0x1342F}, {0x14400, 0x1467F}, {0x16FE0, 0x18AFF}, {0x1B000, 0x1B12F},
+    {0x1B170, 0x1B2FF}, {0x1D000, 0x1D1FF}, {0x1D2E0, 0x1D37F}, {0x1D800, 0x1DAAF},
+    {0x1F000, 0x1F7FF}, {0x1F900, 0x1FA6F}, {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD},
+    {0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD}
+  };
+  static const int max = sizeof(upright) / sizeof(upright[0]);
+  int st = 0;
+  int ed = max;
+
+  while (st <= ed)
+    {
+      int mid = (st + ed) / 2;
+      if (upright[mid][0] <= ch && ch <= upright[mid][1])
+        return TRUE;
+      else
+        if (upright[mid][0] <= ch)
+          st = mid + 1;
+        else
+          ed = mid - 1;
+    }
 
-  return g_unichar_iswide (ch);
+  return FALSE;
 }
 
 static void
@@ -883,7 +916,7 @@ width_iter_next(PangoWidthIter* iter)
   if (iter->end < iter->text_end)
     {
       gunichar ch = g_utf8_get_char (iter->end);
-      iter->wide = width_iter_iswide (ch);
+      iter->upright = width_iter_is_upright (ch);
     }
 
   while (iter->end < iter->text_end)
@@ -898,7 +931,7 @@ width_iter_next(PangoWidthIter* iter)
           continue;
         }
 
-      /* ignore the wide check if met joiner */
+      /* ignore the upright check if met joiner */
       if (met_joiner)
         {
           iter->end = g_utf8_next_char (iter->end);
@@ -915,7 +948,7 @@ width_iter_next(PangoWidthIter* iter)
           continue;
         }
 
-      if (width_iter_iswide (ch) != iter->wide)
+      if (width_iter_is_upright (ch) != iter->upright)
         break;
       iter->end = g_utf8_next_char (iter->end);
     }
@@ -1348,7 +1381,7 @@ itemize_state_update_for_new_run (ItemizeState *state)
            gravity = state->context->resolved_gravity;
 
          state->resolved_gravity = pango_gravity_get_for_script_and_width (state->script,
-                                                                           state->width_iter.wide,
+                                                                           state->width_iter.upright,
                                                                            gravity,
                                                                            gravity_hint);
        }
diff --git a/tools/gen-vertical-orientation-U-table.py b/tools/gen-vertical-orientation-U-table.py
new file mode 100755
index 00000000..4697b319
--- /dev/null
+++ b/tools/gen-vertical-orientation-U-table.py
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+#coding:utf-8
+import os
+import sys
+
+if len(sys.argv) != 2:
+    print('usage;./' + os.path.basename(__file__)  + ' VerticalOrientation.txt')
+    sys.exit(1)
+
+#pick up all data from text
+data = []
+f = open(sys.argv[1], 'r')
+for line in f:
+    line = line.split("#")[0].strip()
+    if len(line) == 0:
+        continue
+
+    coderange, vo = line.split(";")
+    vo = vo.strip()
+
+    codes = coderange.split("..")
+    if len(codes) == 1:
+        st = int(codes[0], 16)
+        ed = st
+    else:
+        st = int(codes[0], 16)
+        ed = int(codes[1], 16)
+
+    data.append([st, ed, vo])
+f.close()
+
+
+#compress all data, replace Tu to U and Tr to R.
+compressed = []
+t = []
+for d in data:
+    if d[2] == 'Tu': d[2] = 'U'
+    if d[2] == 'Tr': d[2] = 'R'
+
+    if t == []:
+        t = d
+    else:
+        if t[2] == d[2] and t[1] + 1 == d[0]:
+            t[1] = d[1]
+        else:
+            compressed.append(t)
+            t = d
+compressed.append(t)
+
+
+#dump vo=U
+for d in compressed:
+    if d[2] == 'U':
+        print('{0x%04X, 0x%04X},' % tuple(d[0:2]))


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]