mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-03 10:33:33 +00:00
bug 644184 - ensure basic arabic shaping features are applied before ligature formation. r=jdaggett
This commit is contained in:
parent
8e56197a44
commit
ecba336667
@ -39,6 +39,14 @@ HB_BEGIN_DECLS
|
||||
#define MAX_FEATURES 100 /* FIXME */
|
||||
#define MAX_LOOKUPS 1000 /* FIXME */
|
||||
|
||||
/* some constants for feature-ordering priorities; intermediate values can also be
|
||||
used if required for shapers that want precise control. */
|
||||
#define FIRST_PRIORITY 100
|
||||
#define EARLY_PRIORITY 300
|
||||
#define DEFAULT_PRIORITY 500
|
||||
#define LATE_PRIORITY 700
|
||||
#define LAST_PRIORITY 900
|
||||
|
||||
static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS};
|
||||
|
||||
struct hb_ot_map_t {
|
||||
@ -50,7 +58,8 @@ struct hb_ot_map_t {
|
||||
unsigned int seq; /* sequence#, used for stable sorting only */
|
||||
unsigned int max_value;
|
||||
bool global; /* whether the feature applies value to every glyph in the buffer */
|
||||
unsigned int default_value; /* for non-global features, what should the unset glyphs take */
|
||||
unsigned short default_value; /* for non-global features, what should the unset glyphs take */
|
||||
unsigned short priority; /* feature ordering priority, for cases such as Arabic */
|
||||
|
||||
static int cmp (const feature_info_t *a, const feature_info_t *b)
|
||||
{ return (a->tag != b->tag) ? (a->tag < b->tag ? -1 : 1) : (a->seq < b->seq ? -1 : 1); }
|
||||
@ -59,7 +68,8 @@ struct hb_ot_map_t {
|
||||
struct feature_map_t {
|
||||
hb_tag_t tag; /* should be first for our bsearch to work */
|
||||
unsigned int index[2]; /* GSUB, GPOS */
|
||||
unsigned int shift;
|
||||
unsigned short shift;
|
||||
unsigned short priority;
|
||||
hb_mask_t mask;
|
||||
hb_mask_t _1_mask; /* mask for value=1, for quick access */
|
||||
|
||||
@ -68,16 +78,22 @@ struct hb_ot_map_t {
|
||||
};
|
||||
|
||||
struct lookup_map_t {
|
||||
unsigned int index;
|
||||
unsigned short index;
|
||||
unsigned short priority;
|
||||
hb_mask_t mask;
|
||||
|
||||
static int cmp (const lookup_map_t *a, const lookup_map_t *b)
|
||||
{ return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; }
|
||||
{
|
||||
unsigned int a_key = (a->priority << 16) + a->index;
|
||||
unsigned int b_key = (b->priority << 16) + b->index;
|
||||
return a_key < b_key ? -1 : a_key > b_key ? 1 : 0;
|
||||
}
|
||||
};
|
||||
|
||||
HB_INTERNAL void add_lookups (hb_face_t *face,
|
||||
unsigned int table_index,
|
||||
unsigned int feature_index,
|
||||
unsigned short priority,
|
||||
hb_mask_t mask);
|
||||
|
||||
|
||||
@ -85,7 +101,7 @@ struct hb_ot_map_t {
|
||||
|
||||
hb_ot_map_t (void) : feature_count (0) {}
|
||||
|
||||
void add_feature (hb_tag_t tag, unsigned int value, bool global)
|
||||
void add_feature (hb_tag_t tag, unsigned int value, unsigned short priority, bool global)
|
||||
{
|
||||
feature_info_t *info = &feature_infos[feature_count++];
|
||||
info->tag = tag;
|
||||
@ -93,17 +109,18 @@ struct hb_ot_map_t {
|
||||
info->max_value = value;
|
||||
info->global = global;
|
||||
info->default_value = global ? value : 0;
|
||||
info->priority = priority;
|
||||
}
|
||||
|
||||
inline void add_bool_feature (hb_tag_t tag, bool global = true)
|
||||
{ add_feature (tag, 1, global); }
|
||||
inline void add_bool_feature (hb_tag_t tag, unsigned short priority, bool global = true)
|
||||
{ add_feature (tag, 1, priority, global); }
|
||||
|
||||
HB_INTERNAL void compile (hb_face_t *face,
|
||||
const hb_segment_properties_t *props);
|
||||
|
||||
inline hb_mask_t get_global_mask (void) const { return global_mask; }
|
||||
|
||||
inline hb_mask_t get_mask (hb_tag_t tag, unsigned int *shift = NULL) const {
|
||||
inline hb_mask_t get_mask (hb_tag_t tag, unsigned short *shift = NULL) const {
|
||||
const feature_map_t *map = (const feature_map_t *) bsearch (&tag, feature_maps, feature_count, sizeof (feature_maps[0]), (hb_compare_func_t) feature_map_t::cmp);
|
||||
if (shift) *shift = map ? map->shift : 0;
|
||||
return map ? map->mask : 0;
|
||||
|
@ -37,6 +37,7 @@ void
|
||||
hb_ot_map_t::add_lookups (hb_face_t *face,
|
||||
unsigned int table_index,
|
||||
unsigned int feature_index,
|
||||
unsigned short priority,
|
||||
hb_mask_t mask)
|
||||
{
|
||||
unsigned int i = MAX_LOOKUPS - lookup_count[table_index];
|
||||
@ -55,6 +56,7 @@ hb_ot_map_t::add_lookups (hb_face_t *face,
|
||||
while (i--) {
|
||||
lookups[i].mask = mask;
|
||||
lookups[i].index = lookup_indices[i];
|
||||
lookups[i].priority = priority;
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,7 +155,7 @@ hb_ot_map_t::compile (hb_face_t *face,
|
||||
global_mask |= (info->default_value << map->shift) & map->mask;
|
||||
}
|
||||
map->_1_mask = (1 << map->shift) & map->mask;
|
||||
|
||||
map->priority = info->priority;
|
||||
}
|
||||
feature_count = j;
|
||||
|
||||
@ -169,10 +171,10 @@ hb_ot_map_t::compile (hb_face_t *face,
|
||||
script_index[table_index],
|
||||
language_index[table_index],
|
||||
&required_feature_index))
|
||||
add_lookups (face, table_index, required_feature_index, 1);
|
||||
add_lookups (face, table_index, required_feature_index, DEFAULT_PRIORITY, 1);
|
||||
|
||||
for (unsigned i = 0; i < feature_count; i++)
|
||||
add_lookups (face, table_index, feature_maps[i].index[table_index], feature_maps[i].mask);
|
||||
add_lookups (face, table_index, feature_maps[i].index[table_index], feature_maps[i].priority, feature_maps[i].mask);
|
||||
|
||||
/* Sort lookups and merge duplicates */
|
||||
qsort (lookup_maps[table_index], lookup_count[table_index], sizeof (lookup_maps[table_index][0]), (hb_compare_func_t) lookup_map_t::cmp);
|
||||
|
@ -148,7 +148,7 @@ _hb_ot_shape_complex_collect_features_arabic (hb_ot_shape_plan_t *plan, const hb
|
||||
{
|
||||
unsigned int num_features = props->script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
|
||||
for (unsigned int i = 0; i < num_features; i++)
|
||||
plan->map.add_bool_feature (arabic_syriac_features[i], false);
|
||||
plan->map.add_bool_feature (arabic_syriac_features[i], EARLY_PRIORITY, false);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -33,18 +33,21 @@ HB_BEGIN_DECLS
|
||||
|
||||
|
||||
/* XXX vertical */
|
||||
hb_tag_t default_features[] = {
|
||||
HB_TAG('c','a','l','t'),
|
||||
HB_TAG('c','c','m','p'),
|
||||
HB_TAG('c','l','i','g'),
|
||||
HB_TAG('c','s','w','h'),
|
||||
HB_TAG('c','u','r','s'),
|
||||
HB_TAG('k','e','r','n'),
|
||||
HB_TAG('l','i','g','a'),
|
||||
HB_TAG('l','o','c','l'),
|
||||
HB_TAG('m','a','r','k'),
|
||||
HB_TAG('m','k','m','k'),
|
||||
HB_TAG('r','l','i','g')
|
||||
struct {
|
||||
hb_tag_t tag;
|
||||
unsigned short priority;
|
||||
} default_features[] = {
|
||||
{ HB_TAG('c','a','l','t'), DEFAULT_PRIORITY },
|
||||
{ HB_TAG('c','c','m','p'), FIRST_PRIORITY },
|
||||
{ HB_TAG('c','l','i','g'), DEFAULT_PRIORITY },
|
||||
{ HB_TAG('c','s','w','h'), DEFAULT_PRIORITY },
|
||||
{ HB_TAG('c','u','r','s'), DEFAULT_PRIORITY },
|
||||
{ HB_TAG('k','e','r','n'), DEFAULT_PRIORITY },
|
||||
{ HB_TAG('l','i','g','a'), DEFAULT_PRIORITY },
|
||||
{ HB_TAG('l','o','c','l'), DEFAULT_PRIORITY },
|
||||
{ HB_TAG('m','a','r','k'), DEFAULT_PRIORITY },
|
||||
{ HB_TAG('m','k','m','k'), DEFAULT_PRIORITY },
|
||||
{ HB_TAG('r','l','i','g'), DEFAULT_PRIORITY }
|
||||
};
|
||||
|
||||
static void
|
||||
@ -55,12 +58,12 @@ hb_ot_shape_collect_features (hb_ot_shape_plan_t *plan,
|
||||
{
|
||||
switch (props->direction) {
|
||||
case HB_DIRECTION_LTR:
|
||||
plan->map.add_bool_feature (HB_TAG ('l','t','r','a'));
|
||||
plan->map.add_bool_feature (HB_TAG ('l','t','r','m'));
|
||||
plan->map.add_bool_feature (HB_TAG ('l','t','r','a'), DEFAULT_PRIORITY);
|
||||
plan->map.add_bool_feature (HB_TAG ('l','t','r','m'), DEFAULT_PRIORITY);
|
||||
break;
|
||||
case HB_DIRECTION_RTL:
|
||||
plan->map.add_bool_feature (HB_TAG ('r','t','l','a'));
|
||||
plan->map.add_bool_feature (HB_TAG ('r','t','l','m'), false);
|
||||
plan->map.add_bool_feature (HB_TAG ('r','t','l','a'), DEFAULT_PRIORITY);
|
||||
plan->map.add_bool_feature (HB_TAG ('r','t','l','m'), DEFAULT_PRIORITY, false);
|
||||
break;
|
||||
case HB_DIRECTION_TTB:
|
||||
case HB_DIRECTION_BTT:
|
||||
@ -69,13 +72,13 @@ hb_ot_shape_collect_features (hb_ot_shape_plan_t *plan,
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (default_features); i++)
|
||||
plan->map.add_bool_feature (default_features[i]);
|
||||
plan->map.add_bool_feature (default_features[i].tag, default_features[i].priority);
|
||||
|
||||
hb_ot_shape_complex_collect_features (plan, props);
|
||||
|
||||
for (unsigned int i = 0; i < num_user_features; i++) {
|
||||
const hb_feature_t *feature = &user_features[i];
|
||||
plan->map.add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
|
||||
plan->map.add_feature (feature->tag, feature->value, DEFAULT_PRIORITY, (feature->start == 0 && feature->end == (unsigned int) -1));
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,7 +95,7 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
|
||||
{
|
||||
const hb_feature_t *feature = &c->user_features[i];
|
||||
if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
|
||||
unsigned int shift;
|
||||
unsigned short shift;
|
||||
hb_mask_t mask = c->plan->map.get_mask (feature->tag, &shift);
|
||||
c->buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user