2 * Copyright © 2009,2010 Red Hat, Inc.
3 * Copyright © 2010,2011,2013 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
29 #include "hb-ot-map-private.hh"
31 #include "hb-ot-layout-private.hh"
35 hb_ot_map_t::add_lookups (hb_face_t
*face
,
36 unsigned int table_index
,
37 unsigned int feature_index
,
41 unsigned int lookup_indices
[32];
42 unsigned int offset
, len
;
43 unsigned int table_lookup_count
;
45 table_lookup_count
= hb_ot_layout_table_get_lookup_count (face
, table_tags
[table_index
]);
49 len
= ARRAY_LENGTH (lookup_indices
);
50 hb_ot_layout_feature_get_lookups (face
,
51 table_tags
[table_index
],
56 for (unsigned int i
= 0; i
< len
; i
++)
58 if (lookup_indices
[i
] >= table_lookup_count
)
60 hb_ot_map_t::lookup_map_t
*lookup
= lookups
[table_index
].push ();
61 if (unlikely (!lookup
))
64 lookup
->index
= lookup_indices
[i
];
65 lookup
->auto_zwj
= auto_zwj
;
69 } while (len
== ARRAY_LENGTH (lookup_indices
));
72 hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t
*face_
,
73 const hb_segment_properties_t
*props_
)
75 memset (this, 0, sizeof (*this));
81 /* Fetch script/language indices for GSUB/GPOS. We need these later to skip
82 * features not available in either table and not waste precious bits for them. */
84 hb_tag_t script_tags
[3] = {HB_TAG_NONE
, HB_TAG_NONE
, HB_TAG_NONE
};
85 hb_tag_t language_tag
;
87 hb_ot_tags_from_script (props
.script
, &script_tags
[0], &script_tags
[1]);
88 language_tag
= hb_ot_tag_from_language (props
.language
);
90 for (unsigned int table_index
= 0; table_index
< 2; table_index
++) {
91 hb_tag_t table_tag
= table_tags
[table_index
];
92 found_script
[table_index
] = hb_ot_layout_table_choose_script (face
, table_tag
, script_tags
, &script_index
[table_index
], &chosen_script
[table_index
]);
93 hb_ot_layout_script_find_language (face
, table_tag
, script_index
[table_index
], language_tag
, &language_index
[table_index
]);
97 void hb_ot_map_builder_t::add_feature (hb_tag_t tag
, unsigned int value
,
98 hb_ot_map_feature_flags_t flags
)
100 feature_info_t
*info
= feature_infos
.push();
101 if (unlikely (!info
)) return;
102 if (unlikely (!tag
)) return;
104 info
->seq
= feature_infos
.len
;
105 info
->max_value
= value
;
107 info
->default_value
= (flags
& F_GLOBAL
) ? value
: 0;
108 info
->stage
[0] = current_stage
[0];
109 info
->stage
[1] = current_stage
[1];
113 void hb_ot_map_t::collect_lookups (unsigned int table_index
, hb_set_t
*lookups_out
) const
115 for (unsigned int i
= 0; i
< lookups
[table_index
].len
; i
++)
116 hb_set_add (lookups_out
, lookups
[table_index
][i
].index
);
119 void hb_ot_map_builder_t::add_pause (unsigned int table_index
, hb_ot_map_t::pause_func_t pause_func
)
121 stage_info_t
*s
= stages
[table_index
].push ();
123 s
->index
= current_stage
[table_index
];
124 s
->pause_func
= pause_func
;
127 current_stage
[table_index
]++;
131 hb_ot_map_builder_t::compile (hb_ot_map_t
&m
)
135 unsigned int required_feature_index
[2];
136 hb_tag_t required_feature_tag
[2];
137 /* We default to applying required feature in stage 0. If the required
138 * feature has a tag that is known to the shaper, we apply required feature
139 * in the stage for that tag.
141 unsigned int required_feature_stage
[2] = {0, 0};
143 for (unsigned int table_index
= 0; table_index
< 2; table_index
++)
145 m
.chosen_script
[table_index
] = chosen_script
[table_index
];
146 m
.found_script
[table_index
] = found_script
[table_index
];
148 hb_ot_layout_language_get_required_feature (face
,
149 table_tags
[table_index
],
150 script_index
[table_index
],
151 language_index
[table_index
],
152 &required_feature_index
[table_index
],
153 &required_feature_tag
[table_index
]);
156 if (!feature_infos
.len
)
159 /* Sort features and merge duplicates */
161 feature_infos
.qsort ();
163 for (unsigned int i
= 1; i
< feature_infos
.len
; i
++)
164 if (feature_infos
[i
].tag
!= feature_infos
[j
].tag
)
165 feature_infos
[++j
] = feature_infos
[i
];
167 if (feature_infos
[i
].flags
& F_GLOBAL
) {
168 feature_infos
[j
].flags
|= F_GLOBAL
;
169 feature_infos
[j
].max_value
= feature_infos
[i
].max_value
;
170 feature_infos
[j
].default_value
= feature_infos
[i
].default_value
;
172 feature_infos
[j
].flags
&= ~F_GLOBAL
;
173 feature_infos
[j
].max_value
= MAX (feature_infos
[j
].max_value
, feature_infos
[i
].max_value
);
174 /* Inherit default_value from j */
176 feature_infos
[j
].flags
|= (feature_infos
[i
].flags
& F_HAS_FALLBACK
);
177 feature_infos
[j
].stage
[0] = MIN (feature_infos
[j
].stage
[0], feature_infos
[i
].stage
[0]);
178 feature_infos
[j
].stage
[1] = MIN (feature_infos
[j
].stage
[1], feature_infos
[i
].stage
[1]);
180 feature_infos
.shrink (j
+ 1);
184 /* Allocate bits now */
185 unsigned int next_bit
= 1;
186 for (unsigned int i
= 0; i
< feature_infos
.len
; i
++)
188 const feature_info_t
*info
= &feature_infos
[i
];
190 unsigned int bits_needed
;
192 if ((info
->flags
& F_GLOBAL
) && info
->max_value
== 1)
193 /* Uses the global bit */
196 bits_needed
= _hb_bit_storage (info
->max_value
);
198 if (!info
->max_value
|| next_bit
+ bits_needed
> 8 * sizeof (hb_mask_t
))
199 continue; /* Feature disabled, or not enough bits. */
202 hb_bool_t found
= false;
203 unsigned int feature_index
[2];
204 for (unsigned int table_index
= 0; table_index
< 2; table_index
++)
206 if (required_feature_tag
[table_index
] == info
->tag
)
208 required_feature_stage
[table_index
] = info
->stage
[table_index
];
212 found
|= hb_ot_layout_language_find_feature (face
,
213 table_tags
[table_index
],
214 script_index
[table_index
],
215 language_index
[table_index
],
217 &feature_index
[table_index
]);
219 if (!found
&& (info
->flags
& F_GLOBAL_SEARCH
))
221 for (unsigned int table_index
= 0; table_index
< 2; table_index
++)
223 found
|= hb_ot_layout_table_find_feature (face
,
224 table_tags
[table_index
],
226 &feature_index
[table_index
]);
229 if (!found
&& !(info
->flags
& F_HAS_FALLBACK
))
233 hb_ot_map_t::feature_map_t
*map
= m
.features
.push ();
237 map
->tag
= info
->tag
;
238 map
->index
[0] = feature_index
[0];
239 map
->index
[1] = feature_index
[1];
240 map
->stage
[0] = info
->stage
[0];
241 map
->stage
[1] = info
->stage
[1];
242 map
->auto_zwj
= !(info
->flags
& F_MANUAL_ZWJ
);
243 if ((info
->flags
& F_GLOBAL
) && info
->max_value
== 1) {
244 /* Uses the global bit */
248 map
->shift
= next_bit
;
249 map
->mask
= (1 << (next_bit
+ bits_needed
)) - (1 << next_bit
);
250 next_bit
+= bits_needed
;
251 m
.global_mask
|= (info
->default_value
<< map
->shift
) & map
->mask
;
253 map
->_1_mask
= (1 << map
->shift
) & map
->mask
;
254 map
->needs_fallback
= !found
;
257 feature_infos
.shrink (0); /* Done with these */
260 add_gsub_pause (NULL
);
261 add_gpos_pause (NULL
);
263 for (unsigned int table_index
= 0; table_index
< 2; table_index
++)
265 /* Collect lookup indices for features */
267 unsigned int stage_index
= 0;
268 unsigned int last_num_lookups
= 0;
269 for (unsigned stage
= 0; stage
< current_stage
[table_index
]; stage
++)
271 if (required_feature_index
[table_index
] != HB_OT_LAYOUT_NO_FEATURE_INDEX
&&
272 required_feature_stage
[table_index
] == stage
)
273 m
.add_lookups (face
, table_index
,
274 required_feature_index
[table_index
],
276 true /* auto_zwj */);
278 for (unsigned i
= 0; i
< m
.features
.len
; i
++)
279 if (m
.features
[i
].stage
[table_index
] == stage
)
280 m
.add_lookups (face
, table_index
,
281 m
.features
[i
].index
[table_index
],
283 m
.features
[i
].auto_zwj
);
285 /* Sort lookups and merge duplicates */
286 if (last_num_lookups
< m
.lookups
[table_index
].len
)
288 m
.lookups
[table_index
].qsort (last_num_lookups
, m
.lookups
[table_index
].len
);
290 unsigned int j
= last_num_lookups
;
291 for (unsigned int i
= j
+ 1; i
< m
.lookups
[table_index
].len
; i
++)
292 if (m
.lookups
[table_index
][i
].index
!= m
.lookups
[table_index
][j
].index
)
293 m
.lookups
[table_index
][++j
] = m
.lookups
[table_index
][i
];
296 m
.lookups
[table_index
][j
].mask
|= m
.lookups
[table_index
][i
].mask
;
297 m
.lookups
[table_index
][j
].auto_zwj
&= m
.lookups
[table_index
][i
].auto_zwj
;
299 m
.lookups
[table_index
].shrink (j
+ 1);
302 last_num_lookups
= m
.lookups
[table_index
].len
;
304 if (stage_index
< stages
[table_index
].len
&& stages
[table_index
][stage_index
].index
== stage
) {
305 hb_ot_map_t::stage_map_t
*stage_map
= m
.stages
[table_index
].push ();
306 if (likely (stage_map
)) {
307 stage_map
->last_lookup
= last_num_lookups
;
308 stage_map
->pause_func
= stages
[table_index
][stage_index
].pause_func
;