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
;
46 len
= ARRAY_LENGTH (lookup_indices
);
47 hb_ot_layout_feature_get_lookups (face
,
48 table_tags
[table_index
],
53 for (unsigned int i
= 0; i
< len
; i
++) {
54 hb_ot_map_t::lookup_map_t
*lookup
= lookups
[table_index
].push ();
55 if (unlikely (!lookup
))
58 lookup
->index
= lookup_indices
[i
];
59 lookup
->auto_zwj
= auto_zwj
;
63 } while (len
== ARRAY_LENGTH (lookup_indices
));
66 hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t
*face_
,
67 const hb_segment_properties_t
*props_
)
69 memset (this, 0, sizeof (*this));
75 /* Fetch script/language indices for GSUB/GPOS. We need these later to skip
76 * features not available in either table and not waste precious bits for them. */
78 hb_tag_t script_tags
[3] = {HB_TAG_NONE
, HB_TAG_NONE
, HB_TAG_NONE
};
79 hb_tag_t language_tag
;
81 hb_ot_tags_from_script (props
.script
, &script_tags
[0], &script_tags
[1]);
82 language_tag
= hb_ot_tag_from_language (props
.language
);
84 for (unsigned int table_index
= 0; table_index
< 2; table_index
++) {
85 hb_tag_t table_tag
= table_tags
[table_index
];
86 found_script
[table_index
] = hb_ot_layout_table_choose_script (face
, table_tag
, script_tags
, &script_index
[table_index
], &chosen_script
[table_index
]);
87 hb_ot_layout_script_find_language (face
, table_tag
, script_index
[table_index
], language_tag
, &language_index
[table_index
]);
91 void hb_ot_map_builder_t::add_feature (hb_tag_t tag
, unsigned int value
,
92 hb_ot_map_feature_flags_t flags
)
94 feature_info_t
*info
= feature_infos
.push();
95 if (unlikely (!info
)) return;
97 info
->seq
= feature_infos
.len
;
98 info
->max_value
= value
;
100 info
->default_value
= (flags
& F_GLOBAL
) ? value
: 0;
101 info
->stage
[0] = current_stage
[0];
102 info
->stage
[1] = current_stage
[1];
105 inline void hb_ot_map_t::apply (unsigned int table_index
,
106 const hb_ot_shape_plan_t
*plan
,
108 hb_buffer_t
*buffer
) const
112 for (unsigned int stage_index
= 0; stage_index
< stages
[table_index
].len
; stage_index
++) {
113 const stage_map_t
*stage
= &stages
[table_index
][stage_index
];
114 for (; i
< stage
->last_lookup
; i
++)
118 hb_ot_layout_substitute_lookup (font
, buffer
, lookups
[table_index
][i
].index
,
119 lookups
[table_index
][i
].mask
,
120 lookups
[table_index
][i
].auto_zwj
);
124 hb_ot_layout_position_lookup (font
, buffer
, lookups
[table_index
][i
].index
,
125 lookups
[table_index
][i
].mask
,
126 lookups
[table_index
][i
].auto_zwj
);
130 if (stage
->pause_func
)
132 buffer
->clear_output ();
133 stage
->pause_func (plan
, font
, buffer
);
138 void hb_ot_map_t::substitute (const hb_ot_shape_plan_t
*plan
, hb_font_t
*font
, hb_buffer_t
*buffer
) const
140 apply (0, plan
, font
, buffer
);
143 void hb_ot_map_t::position (const hb_ot_shape_plan_t
*plan
, hb_font_t
*font
, hb_buffer_t
*buffer
) const
145 apply (1, plan
, font
, buffer
);
149 void hb_ot_map_t::collect_lookups (unsigned int table_index
, hb_set_t
*lookups_out
) const
151 for (unsigned int i
= 0; i
< lookups
[table_index
].len
; i
++)
152 hb_set_add (lookups_out
, lookups
[table_index
][i
].index
);
155 void hb_ot_map_builder_t::add_pause (unsigned int table_index
, hb_ot_map_t::pause_func_t pause_func
)
157 stage_info_t
*s
= stages
[table_index
].push ();
159 s
->index
= current_stage
[table_index
];
160 s
->pause_func
= pause_func
;
163 current_stage
[table_index
]++;
167 hb_ot_map_builder_t::compile (hb_ot_map_t
&m
)
171 for (unsigned int table_index
= 0; table_index
< 2; table_index
++) {
172 m
.chosen_script
[table_index
] = chosen_script
[table_index
];
173 m
.found_script
[table_index
] = found_script
[table_index
];
176 if (!feature_infos
.len
)
179 /* Sort features and merge duplicates */
181 feature_infos
.sort ();
183 for (unsigned int i
= 1; i
< feature_infos
.len
; i
++)
184 if (feature_infos
[i
].tag
!= feature_infos
[j
].tag
)
185 feature_infos
[++j
] = feature_infos
[i
];
187 if (feature_infos
[i
].flags
& F_GLOBAL
) {
188 feature_infos
[j
].flags
|= F_GLOBAL
;
189 feature_infos
[j
].max_value
= feature_infos
[i
].max_value
;
190 feature_infos
[j
].default_value
= feature_infos
[i
].default_value
;
192 feature_infos
[j
].flags
&= ~F_GLOBAL
;
193 feature_infos
[j
].max_value
= MAX (feature_infos
[j
].max_value
, feature_infos
[i
].max_value
);
194 /* Inherit default_value from j */
196 feature_infos
[j
].flags
|= (feature_infos
[i
].flags
& F_HAS_FALLBACK
);
197 feature_infos
[j
].stage
[0] = MIN (feature_infos
[j
].stage
[0], feature_infos
[i
].stage
[0]);
198 feature_infos
[j
].stage
[1] = MIN (feature_infos
[j
].stage
[1], feature_infos
[i
].stage
[1]);
200 feature_infos
.shrink (j
+ 1);
204 /* Allocate bits now */
205 unsigned int next_bit
= 1;
206 for (unsigned int i
= 0; i
< feature_infos
.len
; i
++) {
207 const feature_info_t
*info
= &feature_infos
[i
];
209 unsigned int bits_needed
;
211 if ((info
->flags
& F_GLOBAL
) && info
->max_value
== 1)
212 /* Uses the global bit */
215 bits_needed
= _hb_bit_storage (info
->max_value
);
217 if (!info
->max_value
|| next_bit
+ bits_needed
> 8 * sizeof (hb_mask_t
))
218 continue; /* Feature disabled, or not enough bits. */
222 unsigned int feature_index
[2];
223 for (unsigned int table_index
= 0; table_index
< 2; table_index
++)
224 found
|= hb_ot_layout_language_find_feature (face
,
225 table_tags
[table_index
],
226 script_index
[table_index
],
227 language_index
[table_index
],
229 &feature_index
[table_index
]);
230 if (!found
&& !(info
->flags
& F_HAS_FALLBACK
))
234 hb_ot_map_t::feature_map_t
*map
= m
.features
.push ();
238 map
->tag
= info
->tag
;
239 map
->index
[0] = feature_index
[0];
240 map
->index
[1] = feature_index
[1];
241 map
->stage
[0] = info
->stage
[0];
242 map
->stage
[1] = info
->stage
[1];
243 map
->auto_zwj
= !(info
->flags
& F_MANUAL_ZWJ
);
244 if ((info
->flags
& F_GLOBAL
) && info
->max_value
== 1) {
245 /* Uses the global bit */
249 map
->shift
= next_bit
;
250 map
->mask
= (1 << (next_bit
+ bits_needed
)) - (1 << next_bit
);
251 next_bit
+= bits_needed
;
252 m
.global_mask
|= (info
->default_value
<< map
->shift
) & map
->mask
;
254 map
->_1_mask
= (1 << map
->shift
) & map
->mask
;
255 map
->needs_fallback
= !found
;
258 feature_infos
.shrink (0); /* Done with these */
261 add_gsub_pause (NULL
);
262 add_gpos_pause (NULL
);
264 for (unsigned int table_index
= 0; table_index
< 2; table_index
++) {
265 hb_tag_t table_tag
= table_tags
[table_index
];
267 /* Collect lookup indices for features */
269 unsigned int required_feature_index
;
270 if (hb_ot_layout_language_get_required_feature_index (face
,
272 script_index
[table_index
],
273 language_index
[table_index
],
274 &required_feature_index
))
275 m
.add_lookups (face
, table_index
, required_feature_index
, 1, true);
277 unsigned int stage_index
= 0;
278 unsigned int last_num_lookups
= 0;
279 for (unsigned stage
= 0; stage
< current_stage
[table_index
]; stage
++)
281 for (unsigned i
= 0; i
< m
.features
.len
; i
++)
282 if (m
.features
[i
].stage
[table_index
] == stage
)
283 m
.add_lookups (face
, table_index
,
284 m
.features
[i
].index
[table_index
],
286 m
.features
[i
].auto_zwj
);
288 /* Sort lookups and merge duplicates */
289 if (last_num_lookups
< m
.lookups
[table_index
].len
)
291 m
.lookups
[table_index
].sort (last_num_lookups
, m
.lookups
[table_index
].len
);
293 unsigned int j
= last_num_lookups
;
294 for (unsigned int i
= j
+ 1; i
< m
.lookups
[table_index
].len
; i
++)
295 if (m
.lookups
[table_index
][i
].index
!= m
.lookups
[table_index
][j
].index
)
296 m
.lookups
[table_index
][++j
] = m
.lookups
[table_index
][i
];
299 m
.lookups
[table_index
][j
].mask
|= m
.lookups
[table_index
][i
].mask
;
300 m
.lookups
[table_index
][j
].auto_zwj
&= m
.lookups
[table_index
][i
].auto_zwj
;
302 m
.lookups
[table_index
].shrink (j
+ 1);
305 last_num_lookups
= m
.lookups
[table_index
].len
;
307 if (stage_index
< stages
[table_index
].len
&& stages
[table_index
][stage_index
].index
== stage
) {
308 hb_ot_map_t::stage_map_t
*stage_map
= m
.stages
[table_index
].push ();
309 if (likely (stage_map
)) {
310 stage_map
->last_lookup
= last_num_lookups
;
311 stage_map
->pause_func
= stages
[table_index
][stage_index
].pause_func
;