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