From ff44f88df2c46920f3ec2384ef321a4c7bb0f6ef Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 6 Nov 2009 19:48:16 -0500 Subject: [PATCH] Handle shaping in non-native direction --- src/hb-buffer-private.h | 1 + src/hb-buffer.c | 42 ++++++++++++++-- src/hb-buffer.h | 10 ++-- src/hb-common.h | 11 +++++ src/hb-shape.c | 38 +++++++++++++-- src/hb-unicode-private.h | 5 ++ src/hb-unicode.c | 103 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 196 insertions(+), 14 deletions(-) diff --git a/src/hb-buffer-private.h b/src/hb-buffer-private.h index dab403b80..6ba1a21a5 100644 --- a/src/hb-buffer-private.h +++ b/src/hb-buffer-private.h @@ -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)]) diff --git a/src/hb-buffer.c b/src/hb-buffer.c index 76b69c883..723b8bdb7 100644 --- a/src/hb-buffer.c +++ b/src/hb-buffer.c @@ -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 { \ diff --git a/src/hb-buffer.h b/src/hb-buffer.h index fb872207c..0bceadafa 100644 --- a/src/hb-buffer.h +++ b/src/hb-buffer.h @@ -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 */ diff --git a/src/hb-common.h b/src/hb-common.h index 863d4123f..d07b204c0 100644 --- a/src/hb-common.h +++ b/src/hb-common.h @@ -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 */ diff --git a/src/hb-shape.c b/src/hb-shape.c index 130bcc4a6..01fce83b9 100644 --- a/src/hb-shape.c +++ b/src/hb-shape.c @@ -37,6 +37,17 @@ is_variation_selector (hb_codepoint_t unicode) (unicode >= 0xE0100 && unicode <= 0xE01EF); } +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, @@ -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); } diff --git a/src/hb-unicode-private.h b/src/hb-unicode-private.h index 888024556..1a970b46e 100644 --- a/src/hb-unicode-private.h +++ b/src/hb-unicode-private.h @@ -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 */ diff --git a/src/hb-unicode.c b/src/hb-unicode.c index 01b54f58e..d8ea0ea64 100644 --- a/src/hb-unicode.c +++ b/src/hb-unicode.c @@ -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]; +}