hb-ot-map.cc revision 6fddf2d7397411bba8a23ac535e8b851495d3105
1/*
2 * Copyright © 2009,2010  Red Hat, Inc.
3 * Copyright © 2010,2011  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#include "hb-ot-map-private.hh"
30
31
32void
33hb_ot_map_t::add_lookups (hb_face_t    *face,
34			  unsigned int  table_index,
35			  unsigned int  feature_index,
36			  hb_mask_t     mask)
37{
38  unsigned int lookup_indices[32];
39  unsigned int offset, len;
40
41  offset = 0;
42  do {
43    len = ARRAY_LENGTH (lookup_indices);
44    hb_ot_layout_feature_get_lookup_indexes (face,
45					     table_tags[table_index],
46					     feature_index,
47					     offset, &len,
48					     lookup_indices);
49
50    for (unsigned int i = 0; i < len; i++) {
51      hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push ();
52      if (unlikely (!lookup))
53        return;
54      lookup->mask = mask;
55      lookup->index = lookup_indices[i];
56    }
57
58    offset += len;
59  } while (len == ARRAY_LENGTH (lookup_indices));
60}
61
62hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
63					  const hb_segment_properties_t *props_)
64{
65  memset (this, 0, sizeof (*this));
66
67  face = face_;
68  props = *props_;
69
70
71  /* Fetch script/language indices for GSUB/GPOS.  We need these later to skip
72   * features not available in either table and not waste precious bits for them. */
73
74  hb_tag_t script_tags[3] = {HB_TAG_NONE, HB_TAG_NONE, HB_TAG_NONE};
75  hb_tag_t language_tag;
76
77  hb_ot_tags_from_script (props.script, &script_tags[0], &script_tags[1]);
78  language_tag = hb_ot_tag_from_language (props.language);
79
80  for (unsigned int table_index = 0; table_index < 2; table_index++) {
81    hb_tag_t table_tag = table_tags[table_index];
82    hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
83    hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
84  }
85}
86
87void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback)
88{
89  feature_info_t *info = feature_infos.push();
90  if (unlikely (!info)) return;
91  info->tag = tag;
92  info->seq = feature_infos.len;
93  info->max_value = value;
94  info->global = global;
95  info->has_fallback = has_fallback;
96  info->default_value = global ? value : 0;
97  info->stage[0] = current_stage[0];
98  info->stage[1] = current_stage[1];
99}
100
101/* Keep the next two functions in sync. */
102
103void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
104{
105  const unsigned int table_index = 0;
106  unsigned int i = 0;
107
108  for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) {
109    const pause_map_t *pause = &pauses[table_index][pause_index];
110    for (; i < pause->num_lookups; i++)
111      hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
112
113    buffer->clear_output ();
114
115    if (pause->callback)
116      pause->callback (plan, font, buffer);
117  }
118
119  for (; i < lookups[table_index].len; i++)
120    hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
121}
122
123void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
124{
125  const unsigned int table_index = 1;
126  unsigned int i = 0;
127
128  for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) {
129    const pause_map_t *pause = &pauses[table_index][pause_index];
130    for (; i < pause->num_lookups; i++)
131      hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
132
133    if (pause->callback)
134      pause->callback (plan, font, buffer);
135  }
136
137  for (; i < lookups[table_index].len; i++)
138    hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
139}
140
141void hb_ot_map_t::substitute_closure (const hb_ot_shape_plan_t *plan, hb_face_t *face, hb_set_t *glyphs) const
142{
143  unsigned int table_index = 0;
144  for (unsigned int i = 0; i < lookups[table_index].len; i++)
145    hb_ot_layout_substitute_closure_lookup (face, lookups[table_index][i].index, glyphs);
146}
147
148void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
149{
150  pause_info_t *p = pauses[table_index].push ();
151  if (likely (p)) {
152    p->stage = current_stage[table_index];
153    p->callback = pause_func;
154  }
155
156  current_stage[table_index]++;
157}
158
159void
160hb_ot_map_builder_t::compile (hb_ot_map_t &m)
161{
162  m.global_mask = 1;
163
164  for (unsigned int table_index = 0; table_index < 2; table_index++)
165    m.chosen_script[table_index] = chosen_script[table_index];
166
167  if (!feature_infos.len)
168    return;
169
170  /* Sort features and merge duplicates */
171  {
172    feature_infos.sort ();
173    unsigned int j = 0;
174    for (unsigned int i = 1; i < feature_infos.len; i++)
175      if (feature_infos[i].tag != feature_infos[j].tag)
176	feature_infos[++j] = feature_infos[i];
177      else {
178	if (feature_infos[i].global) {
179	  feature_infos[j].global = true;
180	  feature_infos[j].max_value = feature_infos[i].max_value;
181	  feature_infos[j].default_value = feature_infos[i].default_value;
182	} else {
183	  feature_infos[j].global = false;
184	  feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value);
185	}
186	feature_infos[j].has_fallback = feature_infos[j].has_fallback || feature_infos[i].has_fallback;
187	feature_infos[j].stage[0] = MIN (feature_infos[j].stage[0], feature_infos[i].stage[0]);
188	feature_infos[j].stage[1] = MIN (feature_infos[j].stage[1], feature_infos[i].stage[1]);
189	/* Inherit default_value from j */
190      }
191    feature_infos.shrink (j + 1);
192  }
193
194
195  /* Allocate bits now */
196  unsigned int next_bit = 1;
197  for (unsigned int i = 0; i < feature_infos.len; i++) {
198    const feature_info_t *info = &feature_infos[i];
199
200    unsigned int bits_needed;
201
202    if (info->global && info->max_value == 1)
203      /* Uses the global bit */
204      bits_needed = 0;
205    else
206      bits_needed = _hb_bit_storage (info->max_value);
207
208    if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
209      continue; /* Feature disabled, or not enough bits. */
210
211
212    bool found = false;
213    unsigned int feature_index[2];
214    for (unsigned int table_index = 0; table_index < 2; table_index++)
215      found |= hb_ot_layout_language_find_feature (face,
216						   table_tags[table_index],
217						   script_index[table_index],
218						   language_index[table_index],
219						   info->tag,
220						   &feature_index[table_index]);
221    if (!found && !info->has_fallback)
222      continue;
223
224
225    hb_ot_map_t::feature_map_t *map = m.features.push ();
226    if (unlikely (!map))
227      break;
228
229    map->tag = info->tag;
230    map->index[0] = feature_index[0];
231    map->index[1] = feature_index[1];
232    map->stage[0] = info->stage[0];
233    map->stage[1] = info->stage[1];
234    if (info->global && info->max_value == 1) {
235      /* Uses the global bit */
236      map->shift = 0;
237      map->mask = 1;
238    } else {
239      map->shift = next_bit;
240      map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
241      next_bit += bits_needed;
242      if (info->global)
243	m.global_mask |= (info->default_value << map->shift) & map->mask;
244    }
245    map->_1_mask = (1 << map->shift) & map->mask;
246    map->needs_fallback = !found;
247
248  }
249  feature_infos.shrink (0); /* Done with these */
250
251
252  add_gsub_pause (NULL);
253  add_gpos_pause (NULL);
254
255  for (unsigned int table_index = 0; table_index < 2; table_index++) {
256    hb_tag_t table_tag = table_tags[table_index];
257
258    /* Collect lookup indices for features */
259
260    unsigned int required_feature_index;
261    if (hb_ot_layout_language_get_required_feature_index (face,
262							  table_tag,
263							  script_index[table_index],
264							  language_index[table_index],
265							  &required_feature_index))
266      m.add_lookups (face, table_index, required_feature_index, 1);
267
268    unsigned int pause_index = 0;
269    unsigned int last_num_lookups = 0;
270    for (unsigned stage = 0; stage < current_stage[table_index]; stage++)
271    {
272      for (unsigned i = 0; i < m.features.len; i++)
273        if (m.features[i].stage[table_index] == stage)
274	  m.add_lookups (face, table_index, m.features[i].index[table_index], m.features[i].mask);
275
276      /* Sort lookups and merge duplicates */
277      if (last_num_lookups < m.lookups[table_index].len)
278      {
279	m.lookups[table_index].sort (last_num_lookups, m.lookups[table_index].len);
280
281	unsigned int j = last_num_lookups;
282	for (unsigned int i = j + 1; i < m.lookups[table_index].len; i++)
283	  if (m.lookups[table_index][i].index != m.lookups[table_index][j].index)
284	    m.lookups[table_index][++j] = m.lookups[table_index][i];
285	  else
286	    m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask;
287	m.lookups[table_index].shrink (j + 1);
288      }
289
290      last_num_lookups = m.lookups[table_index].len;
291
292      if (pause_index < pauses[table_index].len && pauses[table_index][pause_index].stage == stage) {
293	hb_ot_map_t::pause_map_t *pause_map = m.pauses[table_index].push ();
294	if (likely (pause_map)) {
295	  pause_map->num_lookups = last_num_lookups;
296	  pause_map->callback = pauses[table_index][pause_index].callback;
297	}
298
299	pause_index++;
300      }
301    }
302  }
303}
304