Handle shaping in non-native direction
authorBehdad Esfahbod <behdad@behdad.org>
Sat, 7 Nov 2009 00:48:16 +0000 (19:48 -0500)
committerBehdad Esfahbod <behdad@behdad.org>
Sat, 7 Nov 2009 00:48:16 +0000 (19:48 -0500)
src/hb-buffer-private.h
src/hb-buffer.c
src/hb-buffer.h
src/hb-common.h
src/hb-shape.c
src/hb-unicode-private.h
src/hb-unicode.c

index dab403b..6ba1a21 100644 (file)
@@ -138,6 +138,7 @@ _hb_buffer_allocate_lig_id (hb_buffer_t *buffer);
 #define IN_NEXTGLYPH()         (buffer->in_string[buffer->in_pos + 1].codepoint)
 #define IN_CURINFO()           (&buffer->in_string[buffer->in_pos])
 #define IN_MASK(pos)           (buffer->in_string[(pos)].mask)
+#define IN_CLUSTER(pos)                (buffer->in_string[(pos)].cluster)
 #define IN_LIGID(pos)          (buffer->in_string[(pos)].lig_id)
 #define IN_COMPONENT(pos)      (buffer->in_string[(pos)].component)
 #define POSITION(pos)          (&buffer->positions[(pos)])
index 76b69c8..723b8bd 100644 (file)
@@ -477,12 +477,14 @@ hb_buffer_get_glyph_positions (hb_buffer_t *buffer)
 }
 
 
-void
-hb_buffer_reverse (hb_buffer_t *buffer)
+static void
+reverse_range (hb_buffer_t *buffer,
+              unsigned int start,
+              unsigned int end)
 {
   unsigned int i, j;
 
-  for (i = 0, j = buffer->in_length - 1; i < buffer->in_length / 2; i++, j--) {
+  for (i = start, j = end - 1; i < j; i++, j--) {
     hb_internal_glyph_info_t t;
 
     t = buffer->in_string[i];
@@ -491,7 +493,7 @@ hb_buffer_reverse (hb_buffer_t *buffer)
   }
 
   if (buffer->positions) {
-    for (i = 0, j = buffer->in_length - 1; i < buffer->in_length / 2; i++, j--) {
+    for (i = 0, j = end - 1; i < j; i++, j--) {
       hb_internal_glyph_position_t t;
 
       t = buffer->positions[i];
@@ -501,6 +503,38 @@ hb_buffer_reverse (hb_buffer_t *buffer)
   }
 }
 
+void
+hb_buffer_reverse (hb_buffer_t *buffer)
+{
+  if (HB_UNLIKELY (!buffer->in_length))
+    return;
+
+  reverse_range (buffer, 0, buffer->in_length);
+}
+
+void
+hb_buffer_reverse_clusters (hb_buffer_t *buffer)
+{
+  unsigned int i, start, count, last_cluster;
+
+  if (HB_UNLIKELY (!buffer->in_length))
+    return;
+
+  hb_buffer_reverse (buffer);
+
+  count = buffer->in_length;
+  start = 0;
+  last_cluster = buffer->in_string[0].cluster;
+  for (i = 1; i < count; i++) {
+    if (last_cluster != buffer->in_string[i].cluster) {
+      reverse_range (buffer, start, i);
+      start = i;
+      last_cluster = buffer->in_string[i].cluster;
+    }
+  }
+  reverse_range (buffer, start, i);
+}
+
 
 #define ADD_UTF(T) \
        HB_STMT_START { \
index fb87220..0bceada 100644 (file)
@@ -36,13 +36,6 @@ HB_BEGIN_DECLS
 
 typedef struct _hb_buffer_t hb_buffer_t;
 
-typedef enum _hb_direction_t {
-  HB_DIRECTION_LTR,
-  HB_DIRECTION_RTL,
-  HB_DIRECTION_TTB,
-  HB_DIRECTION_BTT
-} hb_direction_t;
-
 typedef struct _hb_glyph_info_t {
   hb_codepoint_t codepoint;
   hb_mask_t      mask;
@@ -115,6 +108,9 @@ hb_buffer_ensure (hb_buffer_t  *buffer,
 void
 hb_buffer_reverse (hb_buffer_t *buffer);
 
+void
+hb_buffer_reverse_clusters (hb_buffer_t *buffer);
+
 
 /* Filling the buffer in */
 
index 863d412..d07b204 100644 (file)
@@ -72,4 +72,15 @@ typedef uint32_t hb_mask_t;
 
 typedef void (*hb_destroy_func_t) (void *user_data);
 
+typedef enum _hb_direction_t {
+  HB_DIRECTION_LTR,
+  HB_DIRECTION_RTL,
+  HB_DIRECTION_TTB,
+  HB_DIRECTION_BTT
+} hb_direction_t;
+
+#define HB_DIRECTION_IS_HORIZONTAL(dir)        ((dir) == HB_DIRECTION_LTR || (dir) == HB_DIRECTION_RTL)
+#define HB_DIRECTION_IS_VERTICAL(dir)  ((dir) == HB_DIRECTION_TTB || (dir) == HB_DIRECTION_BTT)
+
+
 #endif /* HB_COMMON_H */
index 130bcc4..01fce83 100644 (file)
@@ -38,6 +38,17 @@ is_variation_selector (hb_codepoint_t unicode)
 }
 
 static void
+hb_form_clusters (hb_buffer_t *buffer)
+{
+  unsigned int count;
+
+  count = buffer->in_length;
+  for (buffer->in_pos = 1; buffer->in_pos < count; buffer->in_pos++)
+    if (buffer->unicode->get_general_category (IN_CURGLYPH()) == HB_CATEGORY_NON_SPACING_MARK)
+      IN_CLUSTER (buffer->in_pos) = IN_CLUSTER (buffer->in_pos - 1);
+}
+
+static void
 hb_map_glyphs (hb_font_t    *font,
               hb_face_t    *face,
               hb_buffer_t  *buffer)
@@ -45,7 +56,6 @@ hb_map_glyphs (hb_font_t    *font,
   unsigned int count;
 
   count = buffer->in_length - 1;
-
   for (buffer->in_pos = 0; buffer->in_pos < count; buffer->in_pos++) {
     if (HB_UNLIKELY (is_variation_selector (IN_NEXTGLYPH()))) {
       IN_CURGLYPH() = hb_font_get_glyph (font, face, IN_CURGLYPH(), IN_NEXTGLYPH());
@@ -67,7 +77,6 @@ hb_position_default (hb_font_t    *font,
   hb_buffer_clear_positions (buffer);
 
   count = buffer->in_length;
-
   for (buffer->in_pos = 0; buffer->in_pos < count; buffer->in_pos++) {
     hb_glyph_metrics_t metrics;
     hb_font_get_glyph_metrics (font, face, IN_CURGLYPH(), &metrics);
@@ -77,6 +86,23 @@ hb_position_default (hb_font_t    *font,
 }
 
 
+static hb_direction_t
+hb_ensure_native_direction (hb_buffer_t *buffer)
+{
+  hb_direction_t original_direction = hb_buffer_get_direction (buffer);
+
+  /* TODO vertical */
+  if (HB_DIRECTION_IS_HORIZONTAL (original_direction) &&
+      original_direction != _hb_script_get_horizontal_direction (hb_buffer_get_script (buffer)))
+  {
+    hb_buffer_reverse_clusters (buffer);
+    hb_buffer_set_direction (buffer, original_direction == HB_DIRECTION_LTR ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
+  }
+
+  return original_direction;
+}
+
+
 void
 hb_shape (hb_font_t    *font,
          hb_face_t    *face,
@@ -84,7 +110,11 @@ hb_shape (hb_font_t    *font,
          hb_feature_t *features,
          unsigned int  num_features)
 {
-  /* form_clusters (buffer); */
+  hb_direction_t original_direction;
+
+  hb_form_clusters (buffer);
+  original_direction = hb_ensure_native_direction (buffer);
+
   /* do_mirroring (buffer); */
   /* natural direction analysis */
   /* OT preprocess */
@@ -99,4 +129,6 @@ hb_shape (hb_font_t    *font,
   hb_position_default (font, face, buffer);
 
   /* GPOS / kern */
+
+  hb_buffer_set_direction (buffer, original_direction);
 }
index 8880245..1a970b4 100644 (file)
@@ -52,6 +52,11 @@ struct _hb_unicode_funcs_t {
 HB_INTERNAL hb_unicode_funcs_t
 _hb_unicode_funcs_nil;
 
+
+HB_INTERNAL hb_direction_t
+_hb_script_get_horizontal_direction (hb_script_t script);
+
+
 HB_END_DECLS
 
 #endif /* HB_UNICODE_PRIVATE_H */
index 01b54f5..d8ea0ea 100644 (file)
@@ -159,3 +159,106 @@ hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
   ufuncs->get_eastasian_width = eastasian_width_func ? eastasian_width_func : hb_unicode_get_eastasian_width_nil;
 }
 
+
+#define LTR HB_DIRECTION_LTR
+#define RTL HB_DIRECTION_RTL
+const hb_direction_t horiz_dir[] =
+{
+  LTR, /* Zyyy */
+  LTR, /* Qaai */
+  RTL, /* Arab */
+  LTR, /* Armn */
+  LTR, /* Beng */
+  LTR, /* Bopo */
+  LTR, /* Cher */
+  LTR, /* Qaac */
+  LTR, /* Cyrl (Cyrs) */
+  LTR, /* Dsrt */
+  LTR, /* Deva */
+  LTR, /* Ethi */
+  LTR, /* Geor (Geon, Geoa) */
+  LTR, /* Goth */
+  LTR, /* Grek */
+  LTR, /* Gujr */
+  LTR, /* Guru */
+  LTR, /* Hani */
+  LTR, /* Hang */
+  RTL, /* Hebr */
+  LTR, /* Hira */
+  LTR, /* Knda */
+  LTR, /* Kana */
+  LTR, /* Khmr */
+  LTR, /* Laoo */
+  LTR, /* Latn (Latf, Latg) */
+  LTR, /* Mlym */
+  LTR, /* Mong */
+  LTR, /* Mymr */
+  LTR, /* Ogam */
+  LTR, /* Ital */
+  LTR, /* Orya */
+  LTR, /* Runr */
+  LTR, /* Sinh */
+  RTL, /* Syrc (Syrj, Syrn, Syre) */
+  LTR, /* Taml */
+  LTR, /* Telu */
+  RTL, /* Thaa */
+  LTR, /* Thai */
+  LTR, /* Tibt */
+  LTR, /* Cans */
+  LTR, /* Yiii */
+  LTR, /* Tglg */
+  LTR, /* Hano */
+  LTR, /* Buhd */
+  LTR, /* Tagb */
+
+  /* Unicode-4.0 additions */
+  LTR, /* Brai */
+  LTR, /* Cprt */
+  LTR, /* Limb */
+  LTR, /* Osma */
+  LTR, /* Shaw */
+  LTR, /* Linb */
+  LTR, /* Tale */
+  LTR, /* Ugar */
+
+  /* Unicode-4.1 additions */
+  LTR, /* Talu */
+  LTR, /* Bugi */
+  LTR, /* Glag */
+  LTR, /* Tfng */
+  LTR, /* Sylo */
+  LTR, /* Xpeo */
+  LTR, /* Khar */
+
+  /* Unicode-5.0 additions */
+  LTR, /* Zzzz */
+  LTR, /* Bali */
+  LTR, /* Xsux */
+  RTL, /* Phnx */
+  LTR, /* Phag */
+  RTL, /* Nkoo */
+
+  /* Unicode-5.1 additions */
+  LTR, /* Kali */
+  LTR, /* Lepc */
+  LTR, /* Rjng */
+  LTR, /* Sund */
+  LTR, /* Saur */
+  LTR, /* Cham */
+  LTR, /* Olck */
+  LTR, /* Vaii */
+  LTR, /* Cari */
+  LTR, /* Lyci */
+  LTR  /* Lydi */
+};
+#undef LTR
+#undef RTL
+
+HB_INTERNAL hb_direction_t
+_hb_script_get_horizontal_direction (hb_script_t script)
+{
+  if (HB_UNLIKELY ((unsigned int) script >= ARRAY_LENGTH (horiz_dir)))
+    return HB_DIRECTION_LTR;
+
+  return horiz_dir[script];
+}