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 |