gfx/harfbuzz/src/hb-ot-shape.cc

branch
TOR_BUG_9701
changeset 14
925c144e1f1f
equal deleted inserted replaced
-1:000000000000 0:ad9087f6d2a2
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 }

mercurial