|
1 /* |
|
2 * Copyright © 2009,2010 Red Hat, Inc. |
|
3 * Copyright © 2010,2011,2012 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 #define HB_SHAPER ot |
|
30 #define hb_ot_shaper_face_data_t hb_ot_layout_t |
|
31 #define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t |
|
32 #include "hb-shaper-impl-private.hh" |
|
33 |
|
34 #include "hb-ot-shape-private.hh" |
|
35 #include "hb-ot-shape-complex-private.hh" |
|
36 #include "hb-ot-shape-fallback-private.hh" |
|
37 #include "hb-ot-shape-normalize-private.hh" |
|
38 |
|
39 #include "hb-ot-layout-private.hh" |
|
40 #include "hb-set-private.hh" |
|
41 |
|
42 |
|
43 static hb_tag_t common_features[] = { |
|
44 HB_TAG('c','c','m','p'), |
|
45 HB_TAG('l','i','g','a'), |
|
46 HB_TAG('l','o','c','l'), |
|
47 HB_TAG('m','a','r','k'), |
|
48 HB_TAG('m','k','m','k'), |
|
49 HB_TAG('r','l','i','g'), |
|
50 }; |
|
51 |
|
52 |
|
53 static hb_tag_t horizontal_features[] = { |
|
54 HB_TAG('c','a','l','t'), |
|
55 HB_TAG('c','l','i','g'), |
|
56 HB_TAG('c','u','r','s'), |
|
57 HB_TAG('k','e','r','n'), |
|
58 HB_TAG('r','c','l','t'), |
|
59 }; |
|
60 |
|
61 static hb_tag_t vertical_features[] = { |
|
62 HB_TAG('v','e','r','t'), |
|
63 }; |
|
64 |
|
65 |
|
66 |
|
67 static void |
|
68 hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, |
|
69 const hb_segment_properties_t *props, |
|
70 const hb_feature_t *user_features, |
|
71 unsigned int num_user_features) |
|
72 { |
|
73 hb_ot_map_builder_t *map = &planner->map; |
|
74 |
|
75 switch (props->direction) { |
|
76 case HB_DIRECTION_LTR: |
|
77 map->add_global_bool_feature (HB_TAG ('l','t','r','a')); |
|
78 map->add_global_bool_feature (HB_TAG ('l','t','r','m')); |
|
79 break; |
|
80 case HB_DIRECTION_RTL: |
|
81 map->add_global_bool_feature (HB_TAG ('r','t','l','a')); |
|
82 map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE); |
|
83 break; |
|
84 case HB_DIRECTION_TTB: |
|
85 case HB_DIRECTION_BTT: |
|
86 case HB_DIRECTION_INVALID: |
|
87 default: |
|
88 break; |
|
89 } |
|
90 |
|
91 map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE); |
|
92 map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE); |
|
93 map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE); |
|
94 |
|
95 if (planner->shaper->collect_features) |
|
96 planner->shaper->collect_features (planner); |
|
97 |
|
98 for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++) |
|
99 map->add_global_bool_feature (common_features[i]); |
|
100 |
|
101 if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) |
|
102 for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++) |
|
103 map->add_feature (horizontal_features[i], 1, F_GLOBAL | |
|
104 (horizontal_features[i] == HB_TAG('k','e','r','n') ? |
|
105 F_HAS_FALLBACK : F_NONE)); |
|
106 else |
|
107 for (unsigned int i = 0; i < ARRAY_LENGTH (vertical_features); i++) |
|
108 map->add_feature (vertical_features[i], 1, F_GLOBAL | |
|
109 (vertical_features[i] == HB_TAG('v','k','r','n') ? |
|
110 F_HAS_FALLBACK : F_NONE)); |
|
111 |
|
112 if (planner->shaper->override_features) |
|
113 planner->shaper->override_features (planner); |
|
114 |
|
115 for (unsigned int i = 0; i < num_user_features; i++) { |
|
116 const hb_feature_t *feature = &user_features[i]; |
|
117 map->add_feature (feature->tag, feature->value, |
|
118 (feature->start == 0 && feature->end == (unsigned int) -1) ? |
|
119 F_GLOBAL : F_NONE); |
|
120 } |
|
121 } |
|
122 |
|
123 |
|
124 /* |
|
125 * shaper face data |
|
126 */ |
|
127 |
|
128 hb_ot_shaper_face_data_t * |
|
129 _hb_ot_shaper_face_data_create (hb_face_t *face) |
|
130 { |
|
131 return _hb_ot_layout_create (face); |
|
132 } |
|
133 |
|
134 void |
|
135 _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data) |
|
136 { |
|
137 _hb_ot_layout_destroy (data); |
|
138 } |
|
139 |
|
140 |
|
141 /* |
|
142 * shaper font data |
|
143 */ |
|
144 |
|
145 struct hb_ot_shaper_font_data_t {}; |
|
146 |
|
147 hb_ot_shaper_font_data_t * |
|
148 _hb_ot_shaper_font_data_create (hb_font_t *font) |
|
149 { |
|
150 return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; |
|
151 } |
|
152 |
|
153 void |
|
154 _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data) |
|
155 { |
|
156 } |
|
157 |
|
158 |
|
159 /* |
|
160 * shaper shape_plan data |
|
161 */ |
|
162 |
|
163 hb_ot_shaper_shape_plan_data_t * |
|
164 _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan, |
|
165 const hb_feature_t *user_features, |
|
166 unsigned int num_user_features) |
|
167 { |
|
168 hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t)); |
|
169 if (unlikely (!plan)) |
|
170 return NULL; |
|
171 |
|
172 hb_ot_shape_planner_t planner (shape_plan); |
|
173 |
|
174 planner.shaper = hb_ot_shape_complex_categorize (&planner); |
|
175 |
|
176 hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features); |
|
177 |
|
178 planner.compile (*plan); |
|
179 |
|
180 if (plan->shaper->data_create) { |
|
181 plan->data = plan->shaper->data_create (plan); |
|
182 if (unlikely (!plan->data)) |
|
183 return NULL; |
|
184 } |
|
185 |
|
186 return plan; |
|
187 } |
|
188 |
|
189 void |
|
190 _hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan) |
|
191 { |
|
192 if (plan->shaper->data_destroy) |
|
193 plan->shaper->data_destroy (const_cast<void *> (plan->data)); |
|
194 |
|
195 plan->finish (); |
|
196 |
|
197 free (plan); |
|
198 } |
|
199 |
|
200 |
|
201 /* |
|
202 * shaper |
|
203 */ |
|
204 |
|
205 struct hb_ot_shape_context_t |
|
206 { |
|
207 hb_ot_shape_plan_t *plan; |
|
208 hb_font_t *font; |
|
209 hb_face_t *face; |
|
210 hb_buffer_t *buffer; |
|
211 const hb_feature_t *user_features; |
|
212 unsigned int num_user_features; |
|
213 |
|
214 /* Transient stuff */ |
|
215 hb_direction_t target_direction; |
|
216 }; |
|
217 |
|
218 |
|
219 |
|
220 /* Main shaper */ |
|
221 |
|
222 |
|
223 /* Prepare */ |
|
224 |
|
225 static void |
|
226 hb_set_unicode_props (hb_buffer_t *buffer) |
|
227 { |
|
228 unsigned int count = buffer->len; |
|
229 for (unsigned int i = 0; i < count; i++) |
|
230 _hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode); |
|
231 } |
|
232 |
|
233 static void |
|
234 hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) |
|
235 { |
|
236 if (!(buffer->flags & HB_BUFFER_FLAG_BOT) || |
|
237 _hb_glyph_info_get_general_category (&buffer->info[0]) != |
|
238 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
|
239 return; |
|
240 |
|
241 if (!font->has_glyph (0x25CC)) |
|
242 return; |
|
243 |
|
244 hb_glyph_info_t dottedcircle; |
|
245 dottedcircle.codepoint = 0x25CC; |
|
246 _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode); |
|
247 |
|
248 buffer->clear_output (); |
|
249 |
|
250 buffer->idx = 0; |
|
251 hb_glyph_info_t info = dottedcircle; |
|
252 info.cluster = buffer->cur().cluster; |
|
253 info.mask = buffer->cur().mask; |
|
254 buffer->output_info (info); |
|
255 while (buffer->idx < buffer->len) |
|
256 buffer->next_glyph (); |
|
257 |
|
258 buffer->swap_buffers (); |
|
259 } |
|
260 |
|
261 static void |
|
262 hb_form_clusters (hb_buffer_t *buffer) |
|
263 { |
|
264 unsigned int count = buffer->len; |
|
265 for (unsigned int i = 1; i < count; i++) |
|
266 if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i]))) |
|
267 buffer->merge_clusters (i - 1, i + 1); |
|
268 } |
|
269 |
|
270 static void |
|
271 hb_ensure_native_direction (hb_buffer_t *buffer) |
|
272 { |
|
273 hb_direction_t direction = buffer->props.direction; |
|
274 |
|
275 /* TODO vertical: |
|
276 * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType |
|
277 * Ogham fonts are supposed to be implemented BTT or not. Need to research that |
|
278 * first. */ |
|
279 if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) || |
|
280 (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB)) |
|
281 { |
|
282 hb_buffer_reverse_clusters (buffer); |
|
283 buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction); |
|
284 } |
|
285 } |
|
286 |
|
287 |
|
288 /* Substitute */ |
|
289 |
|
290 static inline void |
|
291 hb_ot_mirror_chars (hb_ot_shape_context_t *c) |
|
292 { |
|
293 if (HB_DIRECTION_IS_FORWARD (c->target_direction)) |
|
294 return; |
|
295 |
|
296 hb_buffer_t *buffer = c->buffer; |
|
297 hb_unicode_funcs_t *unicode = buffer->unicode; |
|
298 hb_mask_t rtlm_mask = c->plan->rtlm_mask; |
|
299 |
|
300 unsigned int count = buffer->len; |
|
301 hb_glyph_info_t *info = buffer->info; |
|
302 for (unsigned int i = 0; i < count; i++) { |
|
303 hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint); |
|
304 if (likely (codepoint == info[i].codepoint)) |
|
305 info[i].mask |= rtlm_mask; |
|
306 else |
|
307 info[i].codepoint = codepoint; |
|
308 } |
|
309 } |
|
310 |
|
311 static inline void |
|
312 hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c) |
|
313 { |
|
314 if (!c->plan->has_frac) |
|
315 return; |
|
316 |
|
317 hb_buffer_t *buffer = c->buffer; |
|
318 |
|
319 /* TODO look in pre/post context text also. */ |
|
320 unsigned int count = buffer->len; |
|
321 hb_glyph_info_t *info = buffer->info; |
|
322 for (unsigned int i = 0; i < count; i++) |
|
323 { |
|
324 if (info[i].codepoint == 0x2044) /* FRACTION SLASH */ |
|
325 { |
|
326 unsigned int start = i, end = i + 1; |
|
327 while (start && |
|
328 _hb_glyph_info_get_general_category (&info[start - 1]) == |
|
329 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) |
|
330 start--; |
|
331 while (end < count && |
|
332 _hb_glyph_info_get_general_category (&info[end]) == |
|
333 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) |
|
334 end++; |
|
335 |
|
336 for (unsigned int j = start; j < i; j++) |
|
337 info[j].mask |= c->plan->numr_mask | c->plan->frac_mask; |
|
338 info[i].mask |= c->plan->frac_mask; |
|
339 for (unsigned int j = i + 1; j < end; j++) |
|
340 info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask; |
|
341 |
|
342 i = end - 1; |
|
343 } |
|
344 } |
|
345 } |
|
346 |
|
347 static inline void |
|
348 hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c) |
|
349 { |
|
350 hb_ot_map_t *map = &c->plan->map; |
|
351 hb_buffer_t *buffer = c->buffer; |
|
352 |
|
353 hb_mask_t global_mask = map->get_global_mask (); |
|
354 buffer->reset_masks (global_mask); |
|
355 } |
|
356 |
|
357 static inline void |
|
358 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) |
|
359 { |
|
360 hb_ot_map_t *map = &c->plan->map; |
|
361 hb_buffer_t *buffer = c->buffer; |
|
362 |
|
363 hb_ot_shape_setup_masks_fraction (c); |
|
364 |
|
365 if (c->plan->shaper->setup_masks) |
|
366 c->plan->shaper->setup_masks (c->plan, buffer, c->font); |
|
367 |
|
368 for (unsigned int i = 0; i < c->num_user_features; i++) |
|
369 { |
|
370 const hb_feature_t *feature = &c->user_features[i]; |
|
371 if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { |
|
372 unsigned int shift; |
|
373 hb_mask_t mask = map->get_mask (feature->tag, &shift); |
|
374 buffer->set_masks (feature->value << shift, mask, feature->start, feature->end); |
|
375 } |
|
376 } |
|
377 } |
|
378 |
|
379 static inline void |
|
380 hb_ot_map_glyphs_fast (hb_buffer_t *buffer) |
|
381 { |
|
382 /* Normalization process sets up glyph_index(), we just copy it. */ |
|
383 unsigned int count = buffer->len; |
|
384 for (unsigned int i = 0; i < count; i++) |
|
385 buffer->info[i].codepoint = buffer->info[i].glyph_index(); |
|
386 } |
|
387 |
|
388 static inline void |
|
389 hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) |
|
390 { |
|
391 unsigned int count = c->buffer->len; |
|
392 hb_glyph_info_t *info = c->buffer->info; |
|
393 for (unsigned int i = 0; i < count; i++) |
|
394 _hb_glyph_info_set_glyph_props (&info[i], |
|
395 _hb_glyph_info_get_general_category (&info[i]) |
|
396 == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ? |
|
397 HB_OT_LAYOUT_GLYPH_PROPS_MARK : |
|
398 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH); |
|
399 } |
|
400 |
|
401 static inline void |
|
402 hb_ot_substitute_default (hb_ot_shape_context_t *c) |
|
403 { |
|
404 hb_buffer_t *buffer = c->buffer; |
|
405 |
|
406 if (c->plan->shaper->preprocess_text) |
|
407 c->plan->shaper->preprocess_text (c->plan, buffer, c->font); |
|
408 |
|
409 hb_ot_shape_initialize_masks (c); |
|
410 |
|
411 hb_ot_mirror_chars (c); |
|
412 |
|
413 HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index); |
|
414 |
|
415 _hb_ot_shape_normalize (c->plan, buffer, c->font); |
|
416 |
|
417 hb_ot_shape_setup_masks (c); |
|
418 |
|
419 /* This is unfortunate to go here, but necessary... */ |
|
420 if (!hb_ot_layout_has_positioning (c->face)) |
|
421 _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer); |
|
422 |
|
423 hb_ot_map_glyphs_fast (buffer); |
|
424 |
|
425 HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index); |
|
426 } |
|
427 |
|
428 static inline void |
|
429 hb_ot_substitute_complex (hb_ot_shape_context_t *c) |
|
430 { |
|
431 hb_buffer_t *buffer = c->buffer; |
|
432 |
|
433 hb_ot_layout_substitute_start (c->font, buffer); |
|
434 |
|
435 if (!hb_ot_layout_has_glyph_classes (c->face)) |
|
436 hb_synthesize_glyph_classes (c); |
|
437 |
|
438 c->plan->substitute (c->font, buffer); |
|
439 |
|
440 hb_ot_layout_substitute_finish (c->font, buffer); |
|
441 |
|
442 return; |
|
443 } |
|
444 |
|
445 static inline void |
|
446 hb_ot_substitute (hb_ot_shape_context_t *c) |
|
447 { |
|
448 hb_ot_substitute_default (c); |
|
449 hb_ot_substitute_complex (c); |
|
450 } |
|
451 |
|
452 /* Position */ |
|
453 |
|
454 static inline void |
|
455 zero_mark_widths_by_unicode (hb_buffer_t *buffer) |
|
456 { |
|
457 unsigned int count = buffer->len; |
|
458 for (unsigned int i = 0; i < count; i++) |
|
459 if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
|
460 { |
|
461 buffer->pos[i].x_advance = 0; |
|
462 buffer->pos[i].y_advance = 0; |
|
463 } |
|
464 } |
|
465 |
|
466 static inline void |
|
467 zero_mark_widths_by_gdef (hb_buffer_t *buffer) |
|
468 { |
|
469 unsigned int count = buffer->len; |
|
470 for (unsigned int i = 0; i < count; i++) |
|
471 if (_hb_glyph_info_is_mark (&buffer->info[i])) |
|
472 { |
|
473 buffer->pos[i].x_advance = 0; |
|
474 buffer->pos[i].y_advance = 0; |
|
475 } |
|
476 } |
|
477 |
|
478 static inline void |
|
479 hb_ot_position_default (hb_ot_shape_context_t *c) |
|
480 { |
|
481 hb_direction_t direction = c->buffer->props.direction; |
|
482 unsigned int count = c->buffer->len; |
|
483 hb_glyph_info_t *info = c->buffer->info; |
|
484 hb_glyph_position_t *pos = c->buffer->pos; |
|
485 for (unsigned int i = 0; i < count; i++) |
|
486 { |
|
487 c->font->get_glyph_advance_for_direction (info[i].codepoint, |
|
488 direction, |
|
489 &pos[i].x_advance, |
|
490 &pos[i].y_advance); |
|
491 c->font->subtract_glyph_origin_for_direction (info[i].codepoint, |
|
492 direction, |
|
493 &pos[i].x_offset, |
|
494 &pos[i].y_offset); |
|
495 |
|
496 } |
|
497 } |
|
498 |
|
499 static inline bool |
|
500 hb_ot_position_complex (hb_ot_shape_context_t *c) |
|
501 { |
|
502 bool ret = false; |
|
503 unsigned int count = c->buffer->len; |
|
504 |
|
505 switch (c->plan->shaper->zero_width_marks) |
|
506 { |
|
507 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: |
|
508 zero_mark_widths_by_gdef (c->buffer); |
|
509 break; |
|
510 |
|
511 /* Not currently used for any shaper: |
|
512 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY: |
|
513 zero_mark_widths_by_unicode (c->buffer); |
|
514 break; |
|
515 */ |
|
516 |
|
517 default: |
|
518 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: |
|
519 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE: |
|
520 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: |
|
521 break; |
|
522 } |
|
523 |
|
524 if (hb_ot_layout_has_positioning (c->face)) |
|
525 { |
|
526 hb_glyph_info_t *info = c->buffer->info; |
|
527 hb_glyph_position_t *pos = c->buffer->pos; |
|
528 |
|
529 /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */ |
|
530 |
|
531 for (unsigned int i = 0; i < count; i++) { |
|
532 c->font->add_glyph_origin_for_direction (info[i].codepoint, |
|
533 HB_DIRECTION_LTR, |
|
534 &pos[i].x_offset, |
|
535 &pos[i].y_offset); |
|
536 } |
|
537 |
|
538 c->plan->position (c->font, c->buffer); |
|
539 |
|
540 for (unsigned int i = 0; i < count; i++) { |
|
541 c->font->subtract_glyph_origin_for_direction (info[i].codepoint, |
|
542 HB_DIRECTION_LTR, |
|
543 &pos[i].x_offset, |
|
544 &pos[i].y_offset); |
|
545 } |
|
546 |
|
547 ret = true; |
|
548 } |
|
549 |
|
550 switch (c->plan->shaper->zero_width_marks) |
|
551 { |
|
552 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE: |
|
553 zero_mark_widths_by_unicode (c->buffer); |
|
554 break; |
|
555 |
|
556 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: |
|
557 zero_mark_widths_by_gdef (c->buffer); |
|
558 break; |
|
559 |
|
560 default: |
|
561 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: |
|
562 //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY: |
|
563 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: |
|
564 break; |
|
565 } |
|
566 |
|
567 return ret; |
|
568 } |
|
569 |
|
570 static inline void |
|
571 hb_ot_position (hb_ot_shape_context_t *c) |
|
572 { |
|
573 hb_ot_layout_position_start (c->font, c->buffer); |
|
574 |
|
575 hb_ot_position_default (c); |
|
576 |
|
577 hb_bool_t fallback = !hb_ot_position_complex (c); |
|
578 |
|
579 hb_ot_layout_position_finish (c->font, c->buffer); |
|
580 |
|
581 if (fallback && c->plan->shaper->fallback_position) |
|
582 _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); |
|
583 |
|
584 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) |
|
585 hb_buffer_reverse (c->buffer); |
|
586 |
|
587 /* Visual fallback goes here. */ |
|
588 |
|
589 if (fallback) |
|
590 _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); |
|
591 } |
|
592 |
|
593 |
|
594 /* Post-process */ |
|
595 |
|
596 static void |
|
597 hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) |
|
598 { |
|
599 if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) |
|
600 return; |
|
601 |
|
602 hb_codepoint_t space; |
|
603 enum { |
|
604 SPACE_DONT_KNOW, |
|
605 SPACE_AVAILABLE, |
|
606 SPACE_UNAVAILABLE |
|
607 } space_status = SPACE_DONT_KNOW; |
|
608 |
|
609 unsigned int count = c->buffer->len; |
|
610 hb_glyph_info_t *info = c->buffer->info; |
|
611 hb_glyph_position_t *pos = c->buffer->pos; |
|
612 unsigned int j = 0; |
|
613 for (unsigned int i = 0; i < count; i++) |
|
614 { |
|
615 if (unlikely (!_hb_glyph_info_ligated (&info[i]) && |
|
616 _hb_glyph_info_is_default_ignorable (&info[i]))) |
|
617 { |
|
618 if (space_status == SPACE_DONT_KNOW) |
|
619 space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE; |
|
620 |
|
621 if (space_status == SPACE_AVAILABLE) |
|
622 { |
|
623 info[i].codepoint = space; |
|
624 pos[i].x_advance = 0; |
|
625 pos[i].y_advance = 0; |
|
626 } |
|
627 else |
|
628 continue; /* Delete it. */ |
|
629 } |
|
630 if (j != i) |
|
631 { |
|
632 info[j] = info[i]; |
|
633 pos[j] = pos[i]; |
|
634 } |
|
635 j++; |
|
636 } |
|
637 c->buffer->len = j; |
|
638 } |
|
639 |
|
640 |
|
641 /* Pull it all together! */ |
|
642 |
|
643 static void |
|
644 hb_ot_shape_internal (hb_ot_shape_context_t *c) |
|
645 { |
|
646 c->buffer->deallocate_var_all (); |
|
647 |
|
648 /* Save the original direction, we use it later. */ |
|
649 c->target_direction = c->buffer->props.direction; |
|
650 |
|
651 _hb_buffer_allocate_unicode_vars (c->buffer); |
|
652 |
|
653 c->buffer->clear_output (); |
|
654 |
|
655 hb_set_unicode_props (c->buffer); |
|
656 hb_insert_dotted_circle (c->buffer, c->font); |
|
657 hb_form_clusters (c->buffer); |
|
658 |
|
659 hb_ensure_native_direction (c->buffer); |
|
660 |
|
661 hb_ot_substitute (c); |
|
662 hb_ot_position (c); |
|
663 |
|
664 hb_ot_hide_default_ignorables (c); |
|
665 |
|
666 _hb_buffer_deallocate_unicode_vars (c->buffer); |
|
667 |
|
668 c->buffer->props.direction = c->target_direction; |
|
669 |
|
670 c->buffer->deallocate_var_all (); |
|
671 } |
|
672 |
|
673 |
|
674 hb_bool_t |
|
675 _hb_ot_shape (hb_shape_plan_t *shape_plan, |
|
676 hb_font_t *font, |
|
677 hb_buffer_t *buffer, |
|
678 const hb_feature_t *features, |
|
679 unsigned int num_features) |
|
680 { |
|
681 hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features}; |
|
682 hb_ot_shape_internal (&c); |
|
683 |
|
684 return true; |
|
685 } |
|
686 |
|
687 |
|
688 void |
|
689 hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, |
|
690 hb_tag_t table_tag, |
|
691 hb_set_t *lookup_indexes /* OUT */) |
|
692 { |
|
693 /* XXX Does the first part always succeed? */ |
|
694 HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes); |
|
695 } |
|
696 |
|
697 |
|
698 /* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */ |
|
699 static void |
|
700 add_char (hb_font_t *font, |
|
701 hb_unicode_funcs_t *unicode, |
|
702 hb_bool_t mirror, |
|
703 hb_codepoint_t u, |
|
704 hb_set_t *glyphs) |
|
705 { |
|
706 hb_codepoint_t glyph; |
|
707 if (font->get_glyph (u, 0, &glyph)) |
|
708 glyphs->add (glyph); |
|
709 if (mirror) |
|
710 { |
|
711 hb_codepoint_t m = unicode->mirroring (u); |
|
712 if (m != u && font->get_glyph (m, 0, &glyph)) |
|
713 glyphs->add (glyph); |
|
714 } |
|
715 } |
|
716 |
|
717 |
|
718 void |
|
719 hb_ot_shape_glyphs_closure (hb_font_t *font, |
|
720 hb_buffer_t *buffer, |
|
721 const hb_feature_t *features, |
|
722 unsigned int num_features, |
|
723 hb_set_t *glyphs) |
|
724 { |
|
725 hb_ot_shape_plan_t plan; |
|
726 |
|
727 const char *shapers[] = {"ot", NULL}; |
|
728 hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, |
|
729 features, num_features, shapers); |
|
730 |
|
731 bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL; |
|
732 |
|
733 unsigned int count = buffer->len; |
|
734 for (unsigned int i = 0; i < count; i++) |
|
735 add_char (font, buffer->unicode, mirror, buffer->info[i].codepoint, glyphs); |
|
736 |
|
737 hb_set_t lookups; |
|
738 lookups.init (); |
|
739 hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups); |
|
740 |
|
741 /* And find transitive closure. */ |
|
742 hb_set_t copy; |
|
743 copy.init (); |
|
744 do { |
|
745 copy.set (glyphs); |
|
746 for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);) |
|
747 hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs); |
|
748 } while (!copy.is_equal (glyphs)); |
|
749 |
|
750 hb_shape_plan_destroy (shape_plan); |
|
751 } |