-
-static void
-add_lookups (hb_face_t *face,
- hb_tag_t table_tag,
- unsigned int feature_index,
- hb_mask_t mask,
- lookup_map *lookups,
- unsigned int *num_lookups,
- unsigned int room_lookups)
-{
- unsigned int i = room_lookups - *num_lookups;
- lookups += *num_lookups;
-
- unsigned int *lookup_indices = (unsigned int *) lookups;
-
- hb_ot_layout_feature_get_lookup_indexes (face, table_tag, feature_index, 0,
- &i,
- lookup_indices);
-
- *num_lookups += i;
-
- while (i--) {
- lookups[i].mask = mask;
- lookups[i].index = lookup_indices[i];
- }
-}
-
-static int
-cmp_lookups (const void *p1, const void *p2)
-{
- const lookup_map *a = (const lookup_map *) p1;
- const lookup_map *b = (const lookup_map *) p2;
-
- return a->index - b->index;
-}
-
-
-#define MAX_FEATURES 100 /* FIXME */
-
-struct hb_mask_allocator_t {
-
- struct feature_info_t {
- hb_tag_t tag;
- unsigned int value;
- unsigned int seq;
- bool global;
-
- static int
- cmp (const void *p1, const void *p2)
- {
- const feature_info_t *a = reinterpret_cast<const feature_info_t *>(p1);
- const feature_info_t *b = reinterpret_cast<const feature_info_t *>(p2);
-
- if (a->tag != b->tag)
- return a->tag < b->tag ? -1 : 1;
-
- return a->seq < b->seq ? -1 : 1;
- }
- };
-
- struct feature_map_t {
- hb_tag_t tag; /* should be first */
- unsigned int index;
- unsigned int shift;
- hb_mask_t mask;
-
- static int
- cmp (const void *p1, const void *p2)
- {
- const feature_map_t *a = reinterpret_cast<const feature_map_t *>(p1);
- const feature_map_t *b = reinterpret_cast<const feature_map_t *>(p2);
-
- return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0;
- }
- };
-
- hb_mask_allocator_t (void) : count (0) {}
-
- void add_feature (hb_tag_t tag,
- unsigned int value,
- bool global)
- {
- feature_info_t *info = &infos[count++];
- info->tag = tag;
- info->value = value;
- info->seq = count;
- info->global = global;
- }
-
- void compile (hb_face_t *face,
- hb_tag_t table_tag,
- unsigned int script_index,
- unsigned int language_index)
- {
- global_mask = 0;
- unsigned int next_bit = 1;
-
- if (!count)
- return;
-
- qsort (infos, count, sizeof (infos[0]), feature_info_t::cmp);
-
- unsigned int j = 0;
- for (unsigned int i = 1; i < count; i++)
- if (infos[i].tag != infos[j].tag)
- infos[++j] = infos[i];
- else {
- if (infos[i].global)
- infos[j] = infos[i];
- else {
- infos[j].global = infos[j].global && (infos[j].value == infos[i].value);
- infos[j].value = MAX (infos[j].value, infos[i].value);
- }
- }
- count = j + 1;
-
- /* Allocate bits now */
- j = 0;
- for (unsigned int i = 0; i < count; i++) {
- const feature_info_t *info = &infos[i];
-
- unsigned int bits_needed;
-
- if (info->global && info->value == 1)
- /* Uses the global bit */
- bits_needed = 0;
- else
- bits_needed = _hb_bit_storage (info->value);
-
- if (!info->value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
- continue; /* Feature disabled, or not enough bits. */
-
- unsigned int feature_index;
- if (!hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index,
- info->tag, &feature_index))
- continue;
-
- feature_map_t *map = &maps[j++];
-
- map->tag = info->tag;
- map->index = feature_index;
- if (info->global && info->value == 1) {
- /* Use the global bit */
- map->shift = 0;
- map->mask = 1;
- } else {
- map->shift = next_bit;
- map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
- next_bit += bits_needed;
- }
-
- if (info->global && map->mask != 1)
- global_mask |= map->mask;
- }
- count = j;
- }
-
- hb_mask_t get_global_mask (void) { return global_mask; }
-
- const feature_map_t *get_features (unsigned int *num_features) const {
- *num_features = count;
- return maps;
- }
-
-
- const feature_map_t *find_feature (hb_tag_t tag) const {
- static const feature_map_t off_map = { HB_TAG_NONE, Index::NOT_FOUND_INDEX, 0, 0 };
- const feature_map_t *map = (const feature_map_t *) bsearch (&tag, maps, count, sizeof (maps[0]), feature_map_t::cmp);
- return map ? map : &off_map;
- }
-
-
- private:
-
- unsigned int count;
- feature_info_t infos[MAX_FEATURES];
-
- feature_map_t maps[MAX_FEATURES];
- hb_mask_t global_mask;
+/* Note:
+ * Technically speaking, vrt2 and vert are mutually exclusive.
+ * According to the spec, valt and vpal are also mutually exclusive.
+ * But we apply them all for now.
+ */
+hb_tag_t vertical_features[] = {
+ HB_TAG('v','a','l','t'),
+ HB_TAG('v','e','r','t'),
+ HB_TAG('v','k','r','n'),
+ HB_TAG('v','p','a','l'),
+ HB_TAG('v','r','t','2'),