hb-ot-map-private.hh revision ecc4550ed7bc900a61081edfbcd0ad09cbf29b36
1/* 2 * Copyright (C) 2009,2010 Red Hat, Inc. 3 * Copyright (C) 2010 Google, Inc. 4 * 5 * This is part of HarfBuzz, a text shaping library. 6 * 7 * Permission is hereby granted, without written agreement and without 8 * license or royalty fees, to use, copy, modify, and distribute this 9 * software and its documentation for any purpose, provided that the 10 * above copyright notice and the following two paragraphs appear in 11 * all copies of this software. 12 * 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17 * DAMAGE. 18 * 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24 * 25 * Red Hat Author(s): Behdad Esfahbod 26 * Google Author(s): Behdad Esfahbod 27 */ 28 29#ifndef HB_OT_MAP_PRIVATE_HH 30#define HB_OT_MAP_PRIVATE_HH 31 32#include "hb-ot-shape-private.hh" 33 34#include "hb-ot-layout.h" 35 36HB_BEGIN_DECLS 37 38 39#define MAX_FEATURES 100 /* FIXME */ 40#define MAX_LOOKUPS 1000 /* FIXME */ 41 42static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS}; 43 44struct hb_mask_allocator_t { 45 46 private: 47 48 struct feature_info_t { 49 hb_tag_t tag; 50 unsigned int value; 51 unsigned int seq; 52 bool global; 53 54 static int cmp (const feature_info_t *a, const feature_info_t *b) 55 { return (a->tag != b->tag) ? (a->tag < b->tag ? -1 : 1) : (a->seq < b->seq ? -1 : 1); } 56 }; 57 58 struct feature_map_t { 59 hb_tag_t tag; /* should be first for our bsearch to work */ 60 unsigned int index[2]; /* GSUB, GPOS */ 61 unsigned int shift; 62 hb_mask_t mask; 63 64 static int cmp (const feature_map_t *a, const feature_map_t *b) 65 { return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; } 66 }; 67 68 struct lookup_map_t { 69 unsigned int index; 70 hb_mask_t mask; 71 72 static int cmp (const lookup_map_t *a, const lookup_map_t *b) 73 { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; } 74 }; 75 76 77 void 78 add_lookups (hb_ot_shape_context_t *c, 79 unsigned int table_index, 80 unsigned int feature_index, 81 hb_mask_t mask) 82 { 83 unsigned int i = MAX_LOOKUPS - lookup_count[table_index]; 84 lookup_map_t *lookups = lookup_maps[table_index] + lookup_count[table_index]; 85 86 unsigned int *lookup_indices = (unsigned int *) lookups; 87 88 hb_ot_layout_feature_get_lookup_indexes (c->face, 89 table_tags[table_index], 90 feature_index, 91 0, &i, 92 lookup_indices); 93 94 lookup_count[table_index] += i; 95 96 while (i--) { 97 lookups[i].mask = mask; 98 lookups[i].index = lookup_indices[i]; 99 } 100 } 101 102 103 104 public: 105 106 hb_mask_allocator_t (void) : feature_count (0) {} 107 108 void add_feature (hb_tag_t tag, 109 unsigned int value, 110 bool global) 111 { 112 feature_info_t *info = &feature_infos[feature_count++]; 113 info->tag = tag; 114 info->value = value; 115 info->seq = feature_count; 116 info->global = global; 117 } 118 119 void compile (hb_ot_shape_context_t *c) 120 { 121 global_mask = 0; 122 lookup_count[0] = lookup_count[1] = 0; 123 124 if (!feature_count) 125 return; 126 127 128 /* Fetch script/language indices for GSUB/GPOS. We need these later to skip 129 * features not available in either table and not waste precious bits for them. */ 130 131 const hb_tag_t *script_tags; 132 hb_tag_t language_tag; 133 134 script_tags = hb_ot_tags_from_script (c->buffer->props.script); 135 language_tag = hb_ot_tag_from_language (c->buffer->props.language); 136 137 unsigned int script_index[2], language_index[2]; 138 for (unsigned int table_index = 0; table_index < 2; table_index++) { 139 hb_tag_t table_tag = table_tags[table_index]; 140 hb_ot_layout_table_choose_script (c->face, table_tag, script_tags, &script_index[table_index]); 141 hb_ot_layout_script_find_language (c->face, table_tag, script_index[table_index], language_tag, &language_index[table_index]); 142 } 143 144 145 /* Sort features and merge duplicates */ 146 qsort (feature_infos, feature_count, sizeof (feature_infos[0]), (hb_compare_func_t) feature_info_t::cmp); 147 unsigned int j = 0; 148 for (unsigned int i = 1; i < feature_count; i++) 149 if (feature_infos[i].tag != feature_infos[j].tag) 150 feature_infos[++j] = feature_infos[i]; 151 else { 152 if (feature_infos[i].global) 153 feature_infos[j] = feature_infos[i]; 154 else { 155 feature_infos[j].global = false; 156 feature_infos[j].value = MAX (feature_infos[j].value, feature_infos[i].value); 157 } 158 } 159 feature_count = j + 1; 160 161 162 /* Allocate bits now */ 163 unsigned int next_bit = 1; 164 j = 0; 165 for (unsigned int i = 0; i < feature_count; i++) { 166 const feature_info_t *info = &feature_infos[i]; 167 168 unsigned int bits_needed; 169 170 if (info->global && info->value == 1) 171 /* Uses the global bit */ 172 bits_needed = 0; 173 else 174 bits_needed = _hb_bit_storage (info->value); 175 176 if (!info->value || next_bit + bits_needed > 8 * sizeof (hb_mask_t)) 177 continue; /* Feature disabled, or not enough bits. */ 178 179 180 bool found = false; 181 unsigned int feature_index[2]; 182 for (unsigned int table_index = 0; table_index < 2; table_index++) 183 found |= hb_ot_layout_language_find_feature (c->face, 184 table_tags[table_index], 185 script_index[table_index], 186 language_index[table_index], 187 info->tag, 188 &feature_index[table_index]); 189 if (!found) 190 continue; 191 192 193 feature_map_t *map = &feature_maps[j++]; 194 195 map->tag = info->tag; 196 map->index[0] = feature_index[0]; 197 map->index[1] = feature_index[1]; 198 if (info->global && info->value == 1) { 199 /* Uses the global bit */ 200 map->shift = 0; 201 map->mask = 1; 202 } else { 203 map->shift = next_bit; 204 map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit); 205 next_bit += bits_needed; 206 if (info->global) 207 global_mask |= map->mask; 208 } 209 210 } 211 feature_count = j; 212 213 214 for (unsigned int table_index = 0; table_index < 2; table_index++) { 215 hb_tag_t table_tag = table_tags[table_index]; 216 217 /* Collect lookup indices for features */ 218 219 unsigned int required_feature_index; 220 if (hb_ot_layout_language_get_required_feature_index (c->face, 221 table_tag, 222 script_index[table_index], 223 language_index[table_index], 224 &required_feature_index)) 225 add_lookups (c, table_index, required_feature_index, 1); 226 227 for (unsigned i = 0; i < feature_count; i++) 228 add_lookups (c, table_index, feature_maps[i].index[table_index], feature_maps[i].mask); 229 230 /* Sort lookups and merge duplicates */ 231 qsort (lookup_maps[table_index], lookup_count[table_index], sizeof (lookup_maps[table_index][0]), (hb_compare_func_t) lookup_map_t::cmp); 232 if (lookup_count[table_index]) 233 { 234 unsigned int j = 0; 235 for (unsigned int i = 1; i < lookup_count[table_index]; i++) 236 if (lookup_maps[table_index][i].index != lookup_maps[table_index][j].index) 237 lookup_maps[table_index][++j] = lookup_maps[table_index][i]; 238 else 239 lookup_maps[table_index][j].mask |= lookup_maps[table_index][i].mask; 240 j++; 241 lookup_count[table_index] = j; 242 } 243 } 244 } 245 246 hb_mask_t get_global_mask (void) { return global_mask; } 247 248 hb_mask_t get_mask (hb_tag_t tag, unsigned int *shift) const { 249 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); 250 if (shift) *shift = map ? map->shift : 0; 251 return map ? map->mask : 0; 252 } 253 254 inline void substitute (hb_ot_shape_context_t *c) const { 255 for (unsigned int i = 0; i < lookup_count[0]; i++) 256 hb_ot_layout_substitute_lookup (c->face, c->buffer, lookup_maps[0][i].index, lookup_maps[0][i].mask); 257 } 258 259 inline void position (hb_ot_shape_context_t *c) const { 260 for (unsigned int i = 0; i < lookup_count[1]; i++) 261 hb_ot_layout_position_lookup (c->font, c->face, c->buffer, lookup_maps[1][i].index, lookup_maps[1][i].mask); 262 } 263 264 private: 265 266 hb_mask_t global_mask; 267 268 unsigned int feature_count; 269 feature_info_t feature_infos[MAX_FEATURES]; /* used before compile() only */ 270 feature_map_t feature_maps[MAX_FEATURES]; 271 272 lookup_map_t lookup_maps[2][MAX_LOOKUPS]; /* GSUB/GPOS */ 273 unsigned int lookup_count[2]; 274}; 275 276 277 278HB_END_DECLS 279 280#endif /* HB_OT_MAP_PRIVATE_HH */ 281