[HarfBuzz] harfbuzz-ng: Branch 'master'
Behdad Esfahbod
behdad at kemper.freedesktop.org
Fri May 28 17:27:37 PDT 2010
src/hb-ot-shape.cc | 291 +++++++++++++++++++++++++++++++++--------------------
1 file changed, 186 insertions(+), 105 deletions(-)
New commits:
commit 0e235d0fc9bdeeaffa7215c21abc5d40767a10c7
Author: Behdad Esfahbod <behdad at behdad.org>
Date: Fri May 28 20:21:47 2010 -0400
Towards a mask allocator
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index f998759..2944d31 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009,2010 Red Hat, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -28,6 +28,8 @@
#include "hb-buffer-private.hh"
+#include "hb-open-type-private.hh"
+
#include "hb-ot-layout.h"
/* XXX vertical */
@@ -95,102 +97,159 @@ cmp_lookups (const void *p1, const void *p2)
#define MAX_FEATURES 100
-struct feature_info {
- hb_tag_t tag;
- unsigned int index;
- unsigned int value;
- hb_mask_t mask;
-};
+struct hb_mask_allocator_t {
-struct feature_setup_state {
- hb_mask_t global_mask;
- unsigned int next_bit;
- unsigned int count;
- feature_info info[MAX_FEATURES];
-};
+ struct feature_info_t {
+ hb_tag_t tag;
+ unsigned int value;
+ bool global;
-static void
-collect_feature_info(hb_buffer_t *buffer,
- hb_face_t *face,
- hb_tag_t table_tag,
- unsigned int script_index,
- unsigned int language_index,
- const hb_feature_t &feature,
- feature_setup_state &fss,
- const hb_feature_t *features,
- unsigned int num_features)
-{
- if (fss.count == MAX_FEATURES)
- return; // FIXME - make the feature_info array growable?
+ static int
+ cmp (const void *p1, const void *p2)
+ {
+ const feature_info_t *a = (const feature_info_t *) p1;
+ const feature_info_t *b = (const feature_info_t *) p2;
- unsigned int i, feature_index;
- if (!hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index,
- feature.tag, &feature_index))
- return;
+ if (a->tag != b->tag)
+ return a->tag < b->tag ? -1 : 1;
- fss.info[fss.count].tag = feature.tag;
- fss.info[fss.count].index = feature_index;
+ return p1 < p2 ? -1 : 1;
+ }
+ };
- // check if we have already allocated mask bits for this feature tag
- for (i = 0; i < fss.count; ++i)
- {
- if (fss.info[i].tag == feature.tag)
+ 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)
{
- fss.info[fss.count].mask = fss.info[i].mask;
- fss.info[fss.count].value = feature.value << _hb_ctz(fss.info[fss.count].mask);
- if (feature.start == 0 && feature.end == (unsigned int) -1)
- fss.global_mask |= fss.info[fss.count].value;
- else
- buffer->set_masks(fss.info[fss.count].value, fss.info[fss.count].mask, feature.start, feature.end);
- ++fss.count;
+ const feature_map_t *a = (const feature_map_t *) p1;
+ const feature_map_t *b = (const feature_map_t *) p2;
+
+ return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0;
+ }
+ };
+
+ hb_mask_allocator_t (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+ unsigned int language_index,
+ const hb_feature_t *features,
+ unsigned int num_features) :
+ face (face),
+ table_tag (table_tag),
+ script_index (script_index),
+ language_index (language_index),
+ count (0)
+ {
+ if (!num_features)
return;
+
+ /* Add features in reverse order */
+ for (unsigned int i = num_features - 1, count = 0; count < num_features; i--, count++) {
+ const hb_feature_t *feature = &features[i];
+ feature_info_t *info = &infos[count];
+
+ info->tag = feature->tag;
+ info->value = feature->value;
+ info->global = (feature->start == 0 && feature->end == (unsigned int) -1);
}
}
- // check if the feature occurs in remaining user features, as it might have a larger value there
- hb_bool_t always_on = (feature.value == 1 && feature.start == 0 && feature.end == (unsigned int)-1);
- unsigned int max_value = feature.value;
- for (i = 0; i < num_features; ++i)
+ void add_binary_feature (hb_tag_t tag,
+ bool global)
{
- if (features[i].tag != feature.tag)
- continue;
- if (features[i].value > max_value)
- max_value = features[i].value;
- else if (features[i].value == 0 && features[i].start == 0 && features[i].end == (unsigned int)-1)
- max_value = 0;
+ feature_info_t *info = &infos[count++];
+ info->tag = tag;
+ info->value = 1;
+ info->global = global;
}
- if (always_on && max_value == 1)
+ void compile (void)
{
- fss.info[fss.count].value = 1;
- fss.info[fss.count].mask = 1;
- fss.global_mask |= 1;
- ++fss.count;
- return;
+ global_mask = 0;
+ next_bit = MASK_BITS_USED;
+
+ 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[j].global)
+ 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) {
+ /* Uses 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;
}
- // need to allocate specific mask bit(s) for this feature
- unsigned int bits_needed = _hb_bit_storage(max_value);
- if (!bits_needed || fss.next_bit + bits_needed > 8 * sizeof (hb_mask_t))
- {
- fss.info[fss.count].value = 0;
- fss.info[fss.count].mask = 0;
- ++fss.count;
- return; // feature is disabled, just omit it; or
- // not enough bits available in the mask, ignore this feature :(
+ hb_mask_t get_global_mask (void) { return global_mask; }
+ 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;
}
- // store the newly-allocated mask (in case further feature requests use the same tag)
- // and shift the value into the right position
- fss.info[fss.count].value = feature.value << fss.next_bit;
- fss.info[fss.count].mask = (1 << (fss.next_bit + bits_needed)) - (1 << fss.next_bit);
- if (feature.start == 0 && feature.end == (unsigned int) -1)
- fss.global_mask |= fss.info[fss.count].value;
- else
- buffer->set_masks(fss.info[fss.count].value, fss.info[fss.count].mask, feature.start, feature.end);
- fss.next_bit += bits_needed;
- ++fss.count;
-}
+
+ private:
+ hb_face_t *face;
+ hb_tag_t table_tag;
+ unsigned int script_index;
+ unsigned int language_index;
+
+ unsigned int count;
+ feature_info_t infos[MAX_FEATURES];
+ feature_map_t maps[MAX_FEATURES];
+
+ hb_mask_t global_mask;
+ unsigned int next_bit;
+};
static void
setup_lookups (hb_face_t *face,
@@ -218,29 +277,53 @@ setup_lookups (hb_face_t *face,
&feature_index))
add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups);
- // for features that may be turned on/off or have value > 1,
- // we need to allocate bits in the mask
- feature_setup_state fss;
- fss.global_mask = 0;
- fss.next_bit = MASK_BITS_USED;
- fss.count = 0;
+ hb_mask_allocator_t allocator (face, table_tag, script_index, language_index, features, num_features);
+
+ switch (original_direction) {
+ case HB_DIRECTION_LTR:
+ allocator.add_binary_feature (HB_TAG ('l','t','r','a'), true);
+ allocator.add_binary_feature (HB_TAG ('l','t','r','m'), true);
+ break;
+ case HB_DIRECTION_RTL:
+ allocator.add_binary_feature (HB_TAG ('r','t','l','a'), true);
+ //allocator.add_binary_feature (HB_TAG ('r','t','l','m'), false);
+ allocator.add_binary_feature (HB_TAG ('r','t','l','m'), true);
+ break;
+ case HB_DIRECTION_TTB:
+ case HB_DIRECTION_BTT:
+ default:
+ break;
+ }
+
+ for (i = 0; i < ARRAY_LENGTH (default_features); i++)
+ allocator.add_binary_feature (default_features[i], true);
+
+
+ /* Compile features */
+ allocator.compile ();
+
+
+ /* Gather lookup indices for features and set buffer masks at the same time */
+
+ const hb_mask_allocator_t::feature_map_t *map;
- hb_feature_t feature = { 0, 1, 0, (unsigned int)-1 };
+ hb_mask_t global_mask = allocator.get_global_mask ();
+ if (global_mask)
+ buffer->set_masks (global_mask, global_mask, 0, (unsigned int) -1);
switch (original_direction) {
case HB_DIRECTION_LTR:
- feature.tag = HB_TAG ('l','t','r','a');
- collect_feature_info(buffer, face, table_tag, script_index, language_index,
- feature, fss, features, num_features);
- feature.tag = HB_TAG ('l','t','r','m');
- collect_feature_info(buffer, face, table_tag, script_index, language_index,
- feature, fss, features, num_features);
+ map = allocator.find_feature (HB_TAG ('l','t','r','a'));
+ add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
+ map = allocator.find_feature (HB_TAG ('l','t','r','m'));
+ add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
break;
case HB_DIRECTION_RTL:
- feature.tag = HB_TAG ('r','t','l','a');
- collect_feature_info(buffer, face, table_tag, script_index, language_index,
- feature, fss, features, num_features);
+ map = allocator.find_feature (HB_TAG ('r','t','l','a'));
+ add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
+ //map = allocator.find_feature (HB_TAG ('r','t','l','m'));
+ add_feature (face, table_tag, map->index, MASK_RTLM, lookups, num_lookups, room_lookups);
break;
case HB_DIRECTION_TTB:
case HB_DIRECTION_BTT:
@@ -250,23 +333,21 @@ setup_lookups (hb_face_t *face,
for (i = 0; i < ARRAY_LENGTH (default_features); i++)
{
- feature.tag = default_features[i];
- collect_feature_info(buffer, face, table_tag, script_index, language_index,
- feature, fss, features, num_features);
+ map = allocator.find_feature (default_features[i]);
+ add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
}
for (i = 0; i < num_features; i++)
{
- collect_feature_info(buffer, face, table_tag, script_index, language_index,
- features[i], fss, features + i + 1, num_features - i - 1);
+ hb_feature_t *feature = &features[i];
+ map = allocator.find_feature (feature->tag);
+ add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
+ if (!(feature->start == 0 && feature->end == (unsigned int)-1))
+ buffer->set_masks (features[i].value << map->shift, map->mask, feature->start, feature->end);
}
- for (i = 0; i < fss.count; ++i)
- if (fss.info[i].mask)
- add_feature (face, table_tag, fss.info[i].index, fss.info[i].mask, lookups, num_lookups, room_lookups);
- if (fss.global_mask > 1) // the 0x01 bit was set by clear_masks()
- buffer->set_masks (fss.global_mask, fss.global_mask, 0, (unsigned int) -1);
+ /* Sort lookups and merge duplicates */
qsort (lookups, *num_lookups, sizeof (lookups[0]), cmp_lookups);
More information about the HarfBuzz
mailing list