|
|
|
@ -1,5 +1,5 @@ |
|
|
|
|
/*
|
|
|
|
|
* Copyright © 2010 Google, Inc. |
|
|
|
|
* Copyright © 2010,2012 Google, Inc. |
|
|
|
|
* |
|
|
|
|
* This is part of HarfBuzz, a text shaping library. |
|
|
|
|
* |
|
|
|
@ -99,7 +99,7 @@ static uint16_t get_ligature (hb_codepoint_t first, hb_codepoint_t second) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static const hb_tag_t arabic_syriac_features[] = |
|
|
|
|
static const hb_tag_t arabic_features[] = |
|
|
|
|
{ |
|
|
|
|
HB_TAG('i','n','i','t'), |
|
|
|
|
HB_TAG('m','e','d','i'), |
|
|
|
@ -127,9 +127,7 @@ enum { |
|
|
|
|
|
|
|
|
|
NONE, |
|
|
|
|
|
|
|
|
|
COMMON_NUM_FEATURES = 4, |
|
|
|
|
SYRIAC_NUM_FEATURES = 7, |
|
|
|
|
TOTAL_NUM_FEATURES = NONE |
|
|
|
|
ARABIC_NUM_FEATURES = NONE |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const struct arabic_state_table_entry { |
|
|
|
@ -184,9 +182,8 @@ collect_features_arabic (hb_ot_shape_planner_t *plan) |
|
|
|
|
|
|
|
|
|
map->add_gsub_pause (NULL); |
|
|
|
|
|
|
|
|
|
unsigned int num_features = plan->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES; |
|
|
|
|
for (unsigned int i = 0; i < num_features; i++) |
|
|
|
|
map->add_bool_feature (arabic_syriac_features[i], false); |
|
|
|
|
for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) |
|
|
|
|
map->add_bool_feature (arabic_features[i], false); |
|
|
|
|
|
|
|
|
|
map->add_gsub_pause (NULL); |
|
|
|
|
|
|
|
|
@ -200,10 +197,51 @@ collect_features_arabic (hb_ot_shape_planner_t *plan) |
|
|
|
|
map->add_bool_feature (HB_TAG('c','s','w','h')); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct arabic_shape_plan_t |
|
|
|
|
{ |
|
|
|
|
ASSERT_POD (); |
|
|
|
|
|
|
|
|
|
bool do_fallback; |
|
|
|
|
hb_mask_t mask_array[ARABIC_NUM_FEATURES]; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static void * |
|
|
|
|
data_create_arabic (const hb_ot_shape_plan_t *plan) |
|
|
|
|
{ |
|
|
|
|
arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t)); |
|
|
|
|
if (unlikely (!arabic_plan)) |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
hb_mask_t total_masks = 0; |
|
|
|
|
for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) { |
|
|
|
|
arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]); |
|
|
|
|
total_masks |= arabic_plan->mask_array[i]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Pitfalls:
|
|
|
|
|
* - This path fires if user force-set init/medi/fina/isol off, |
|
|
|
|
* - If font does not declare script 'arab', well, what to do? |
|
|
|
|
* Most probably it's safe to assume that init/medi/fina/isol |
|
|
|
|
* still mean Arabic shaping, although they do not have to. |
|
|
|
|
*/ |
|
|
|
|
arabic_plan->do_fallback = 0 == total_masks; |
|
|
|
|
|
|
|
|
|
return arabic_plan; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
data_destroy_arabic (void *data) |
|
|
|
|
{ |
|
|
|
|
free (data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
arabic_fallback_shape (hb_font_t *font, hb_buffer_t *buffer) |
|
|
|
|
{ |
|
|
|
|
/* Only Arabic has presentation forms encoded in Unicode. */ |
|
|
|
|
if (buffer->props.script != HB_SCRIPT_ARABIC) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
unsigned int count = buffer->len; |
|
|
|
|
hb_codepoint_t glyph; |
|
|
|
|
|
|
|
|
@ -240,6 +278,8 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan, |
|
|
|
|
hb_buffer_t *buffer, |
|
|
|
|
hb_font_t *font) |
|
|
|
|
{ |
|
|
|
|
const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; |
|
|
|
|
|
|
|
|
|
unsigned int count = buffer->len; |
|
|
|
|
unsigned int prev = 0, state = 0; |
|
|
|
|
|
|
|
|
@ -265,28 +305,12 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan, |
|
|
|
|
state = entry->next_state; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
hb_mask_t mask_array[TOTAL_NUM_FEATURES + 1] = {0}; |
|
|
|
|
hb_mask_t total_masks = 0; |
|
|
|
|
unsigned int num_masks = buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES; |
|
|
|
|
for (unsigned int i = 0; i < num_masks; i++) { |
|
|
|
|
mask_array[i] = plan->map.get_1_mask (arabic_syriac_features[i]); |
|
|
|
|
total_masks |= mask_array[i]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (total_masks) { |
|
|
|
|
if (likely (!arabic_plan->do_fallback)) { |
|
|
|
|
/* Has OpenType tables */ |
|
|
|
|
for (unsigned int i = 0; i < count; i++) |
|
|
|
|
buffer->info[i].mask |= mask_array[buffer->info[i].arabic_shaping_action()]; |
|
|
|
|
} else if (buffer->props.script == HB_SCRIPT_ARABIC) { |
|
|
|
|
/* Fallback Arabic shaping to Presentation Forms */ |
|
|
|
|
/* Pitfalls:
|
|
|
|
|
* - This path fires if user force-set init/medi/fina/isol off, |
|
|
|
|
* - If font does not declare script 'arab', well, what to do? |
|
|
|
|
* Most probably it's safe to assume that init/medi/fina/isol |
|
|
|
|
* still mean Arabic shaping, although they do not have to. |
|
|
|
|
*/ |
|
|
|
|
buffer->info[i].mask |= arabic_plan->mask_array[buffer->info[i].arabic_shaping_action()]; |
|
|
|
|
} else |
|
|
|
|
arabic_fallback_shape (font, buffer); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); |
|
|
|
|
} |
|
|
|
@ -296,8 +320,8 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic = |
|
|
|
|
"arabic", |
|
|
|
|
collect_features_arabic, |
|
|
|
|
NULL, /* override_features */ |
|
|
|
|
NULL, /* data_create */ |
|
|
|
|
NULL, /* data_destroy */ |
|
|
|
|
data_create_arabic, |
|
|
|
|
data_destroy_arabic, |
|
|
|
|
NULL, /* normalization_preference */ |
|
|
|
|
setup_masks_arabic, |
|
|
|
|
true, /* zero_width_attached_marks */ |
|
|
|
|