2 * Copyright © 2009,2010 Red Hat, Inc.
3 * Copyright © 2010,2011,2012 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
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"
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"
39 #include "hb-ot-layout-private.hh"
40 #include "hb-unicode-private.hh"
41 #include "hb-set-private.hh"
44 static hb_tag_t common_features
[] = {
45 HB_TAG('c','c','m','p'),
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'),
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('l','i','g','a'),
59 HB_TAG('r','c','l','t'),
62 static hb_tag_t vertical_features
[] = {
63 HB_TAG('v','e','r','t'),
69 hb_ot_shape_collect_features (hb_ot_shape_planner_t
*planner
,
70 const hb_segment_properties_t
*props
,
71 const hb_feature_t
*user_features
,
72 unsigned int num_user_features
)
74 hb_ot_map_builder_t
*map
= &planner
->map
;
76 switch (props
->direction
) {
77 case HB_DIRECTION_LTR
:
78 map
->add_global_bool_feature (HB_TAG ('l','t','r','a'));
79 map
->add_global_bool_feature (HB_TAG ('l','t','r','m'));
81 case HB_DIRECTION_RTL
:
82 map
->add_global_bool_feature (HB_TAG ('r','t','l','a'));
83 map
->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE
);
85 case HB_DIRECTION_TTB
:
86 case HB_DIRECTION_BTT
:
87 case HB_DIRECTION_INVALID
:
92 map
->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE
);
93 map
->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE
);
94 map
->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE
);
96 if (planner
->shaper
->collect_features
)
97 planner
->shaper
->collect_features (planner
);
99 for (unsigned int i
= 0; i
< ARRAY_LENGTH (common_features
); i
++)
100 map
->add_global_bool_feature (common_features
[i
]);
102 if (HB_DIRECTION_IS_HORIZONTAL (props
->direction
))
103 for (unsigned int i
= 0; i
< ARRAY_LENGTH (horizontal_features
); i
++)
104 map
->add_feature (horizontal_features
[i
], 1, F_GLOBAL
|
105 (horizontal_features
[i
] == HB_TAG('k','e','r','n') ?
106 F_HAS_FALLBACK
: F_NONE
));
108 for (unsigned int i
= 0; i
< ARRAY_LENGTH (vertical_features
); i
++)
109 map
->add_feature (vertical_features
[i
], 1, F_GLOBAL
|
110 (vertical_features
[i
] == HB_TAG('v','k','r','n') ?
111 F_HAS_FALLBACK
: F_NONE
));
113 if (planner
->shaper
->override_features
)
114 planner
->shaper
->override_features (planner
);
116 for (unsigned int i
= 0; i
< num_user_features
; i
++) {
117 const hb_feature_t
*feature
= &user_features
[i
];
118 map
->add_feature (feature
->tag
, feature
->value
,
119 (feature
->start
== 0 && feature
->end
== (unsigned int) -1) ?
129 hb_ot_shaper_face_data_t
*
130 _hb_ot_shaper_face_data_create (hb_face_t
*face
)
132 return _hb_ot_layout_create (face
);
136 _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t
*data
)
138 _hb_ot_layout_destroy (data
);
146 struct hb_ot_shaper_font_data_t
{};
148 hb_ot_shaper_font_data_t
*
149 _hb_ot_shaper_font_data_create (hb_font_t
*font
)
151 return (hb_ot_shaper_font_data_t
*) HB_SHAPER_DATA_SUCCEEDED
;
155 _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t
*data
)
161 * shaper shape_plan data
164 hb_ot_shaper_shape_plan_data_t
*
165 _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t
*shape_plan
,
166 const hb_feature_t
*user_features
,
167 unsigned int num_user_features
)
169 hb_ot_shape_plan_t
*plan
= (hb_ot_shape_plan_t
*) calloc (1, sizeof (hb_ot_shape_plan_t
));
170 if (unlikely (!plan
))
173 hb_ot_shape_planner_t
planner (shape_plan
);
175 planner
.shaper
= hb_ot_shape_complex_categorize (&planner
);
177 hb_ot_shape_collect_features (&planner
, &shape_plan
->props
, user_features
, num_user_features
);
179 planner
.compile (*plan
);
181 if (plan
->shaper
->data_create
) {
182 plan
->data
= plan
->shaper
->data_create (plan
);
183 if (unlikely (!plan
->data
))
191 _hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t
*plan
)
193 if (plan
->shaper
->data_destroy
)
194 plan
->shaper
->data_destroy (const_cast<void *> (plan
->data
));
206 struct hb_ot_shape_context_t
208 hb_ot_shape_plan_t
*plan
;
212 const hb_feature_t
*user_features
;
213 unsigned int num_user_features
;
215 /* Transient stuff */
216 hb_direction_t target_direction
;
227 hb_set_unicode_props (hb_buffer_t
*buffer
)
229 unsigned int count
= buffer
->len
;
230 hb_glyph_info_t
*info
= buffer
->info
;
231 for (unsigned int i
= 0; i
< count
; i
++)
232 _hb_glyph_info_set_unicode_props (&info
[i
], buffer
->unicode
);
236 hb_insert_dotted_circle (hb_buffer_t
*buffer
, hb_font_t
*font
)
238 if (!(buffer
->flags
& HB_BUFFER_FLAG_BOT
) ||
239 buffer
->context_len
[0] ||
240 _hb_glyph_info_get_general_category (&buffer
->info
[0]) !=
241 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
)
244 if (!font
->has_glyph (0x25CCu
))
247 hb_glyph_info_t dottedcircle
= {0};
248 dottedcircle
.codepoint
= 0x25CCu
;
249 _hb_glyph_info_set_unicode_props (&dottedcircle
, buffer
->unicode
);
251 buffer
->clear_output ();
254 hb_glyph_info_t info
= dottedcircle
;
255 info
.cluster
= buffer
->cur().cluster
;
256 info
.mask
= buffer
->cur().mask
;
257 buffer
->output_info (info
);
258 while (buffer
->idx
< buffer
->len
)
259 buffer
->next_glyph ();
261 buffer
->swap_buffers ();
265 hb_form_clusters (hb_buffer_t
*buffer
)
267 unsigned int count
= buffer
->len
;
268 hb_glyph_info_t
*info
= buffer
->info
;
269 for (unsigned int i
= 1; i
< count
; i
++)
270 if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info
[i
])))
271 buffer
->merge_clusters (i
- 1, i
+ 1);
275 hb_ensure_native_direction (hb_buffer_t
*buffer
)
277 hb_direction_t direction
= buffer
->props
.direction
;
280 * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
281 * Ogham fonts are supposed to be implemented BTT or not. Need to research that
283 if ((HB_DIRECTION_IS_HORIZONTAL (direction
) && direction
!= hb_script_get_horizontal_direction (buffer
->props
.script
)) ||
284 (HB_DIRECTION_IS_VERTICAL (direction
) && direction
!= HB_DIRECTION_TTB
))
286 hb_buffer_reverse_clusters (buffer
);
287 buffer
->props
.direction
= HB_DIRECTION_REVERSE (buffer
->props
.direction
);
295 hb_ot_mirror_chars (hb_ot_shape_context_t
*c
)
297 if (HB_DIRECTION_IS_FORWARD (c
->target_direction
))
300 hb_buffer_t
*buffer
= c
->buffer
;
301 hb_unicode_funcs_t
*unicode
= buffer
->unicode
;
302 hb_mask_t rtlm_mask
= c
->plan
->rtlm_mask
;
304 unsigned int count
= buffer
->len
;
305 hb_glyph_info_t
*info
= buffer
->info
;
306 for (unsigned int i
= 0; i
< count
; i
++) {
307 hb_codepoint_t codepoint
= unicode
->mirroring (info
[i
].codepoint
);
308 if (likely (codepoint
== info
[i
].codepoint
))
309 info
[i
].mask
|= rtlm_mask
;
311 info
[i
].codepoint
= codepoint
;
316 hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t
*c
)
318 if (!c
->plan
->has_frac
)
321 hb_buffer_t
*buffer
= c
->buffer
;
323 /* TODO look in pre/post context text also. */
324 unsigned int count
= buffer
->len
;
325 hb_glyph_info_t
*info
= buffer
->info
;
326 for (unsigned int i
= 0; i
< count
; i
++)
328 if (info
[i
].codepoint
== 0x2044u
) /* FRACTION SLASH */
330 unsigned int start
= i
, end
= i
+ 1;
332 _hb_glyph_info_get_general_category (&info
[start
- 1]) ==
333 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER
)
335 while (end
< count
&&
336 _hb_glyph_info_get_general_category (&info
[end
]) ==
337 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER
)
340 for (unsigned int j
= start
; j
< i
; j
++)
341 info
[j
].mask
|= c
->plan
->numr_mask
| c
->plan
->frac_mask
;
342 info
[i
].mask
|= c
->plan
->frac_mask
;
343 for (unsigned int j
= i
+ 1; j
< end
; j
++)
344 info
[j
].mask
|= c
->plan
->frac_mask
| c
->plan
->dnom_mask
;
352 hb_ot_shape_initialize_masks (hb_ot_shape_context_t
*c
)
354 hb_ot_map_t
*map
= &c
->plan
->map
;
355 hb_buffer_t
*buffer
= c
->buffer
;
357 hb_mask_t global_mask
= map
->get_global_mask ();
358 buffer
->reset_masks (global_mask
);
362 hb_ot_shape_setup_masks (hb_ot_shape_context_t
*c
)
364 hb_ot_map_t
*map
= &c
->plan
->map
;
365 hb_buffer_t
*buffer
= c
->buffer
;
367 hb_ot_shape_setup_masks_fraction (c
);
369 if (c
->plan
->shaper
->setup_masks
)
370 c
->plan
->shaper
->setup_masks (c
->plan
, buffer
, c
->font
);
372 for (unsigned int i
= 0; i
< c
->num_user_features
; i
++)
374 const hb_feature_t
*feature
= &c
->user_features
[i
];
375 if (!(feature
->start
== 0 && feature
->end
== (unsigned int)-1)) {
377 hb_mask_t mask
= map
->get_mask (feature
->tag
, &shift
);
378 buffer
->set_masks (feature
->value
<< shift
, mask
, feature
->start
, feature
->end
);
384 hb_ot_map_glyphs_fast (hb_buffer_t
*buffer
)
386 /* Normalization process sets up glyph_index(), we just copy it. */
387 unsigned int count
= buffer
->len
;
388 hb_glyph_info_t
*info
= buffer
->info
;
389 for (unsigned int i
= 0; i
< count
; i
++)
390 info
[i
].codepoint
= info
[i
].glyph_index();
394 hb_synthesize_glyph_classes (hb_ot_shape_context_t
*c
)
396 unsigned int count
= c
->buffer
->len
;
397 hb_glyph_info_t
*info
= c
->buffer
->info
;
398 for (unsigned int i
= 0; i
< count
; i
++)
400 hb_ot_layout_glyph_class_mask_t klass
;
402 /* Never mark default-ignorables as marks.
403 * They won't get in the way of lookups anyway,
404 * but having them as mark will cause them to be skipped
405 * over if the lookup-flag says so, but at least for the
406 * Mongolian variation selectors, looks like Uniscribe
407 * marks them as non-mark. Some Mongolian fonts without
408 * GDEF rely on this. Another notable character that
409 * this applies to is COMBINING GRAPHEME JOINER. */
410 klass
= (_hb_glyph_info_get_general_category (&info
[i
]) !=
411 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
||
412 _hb_glyph_info_is_default_ignorable (&info
[i
])) ?
413 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH
:
414 HB_OT_LAYOUT_GLYPH_PROPS_MARK
;
415 _hb_glyph_info_set_glyph_props (&info
[i
], klass
);
420 hb_ot_substitute_default (hb_ot_shape_context_t
*c
)
422 hb_buffer_t
*buffer
= c
->buffer
;
424 if (c
->plan
->shaper
->preprocess_text
)
425 c
->plan
->shaper
->preprocess_text (c
->plan
, buffer
, c
->font
);
427 hb_ot_shape_initialize_masks (c
);
429 hb_ot_mirror_chars (c
);
431 HB_BUFFER_ALLOCATE_VAR (buffer
, glyph_index
);
433 _hb_ot_shape_normalize (c
->plan
, buffer
, c
->font
);
435 hb_ot_shape_setup_masks (c
);
437 /* This is unfortunate to go here, but necessary... */
438 if (!hb_ot_layout_has_positioning (c
->face
))
439 _hb_ot_shape_fallback_position_recategorize_marks (c
->plan
, c
->font
, buffer
);
441 hb_ot_map_glyphs_fast (buffer
);
443 HB_BUFFER_DEALLOCATE_VAR (buffer
, glyph_index
);
447 hb_ot_substitute_complex (hb_ot_shape_context_t
*c
)
449 hb_buffer_t
*buffer
= c
->buffer
;
451 _hb_buffer_allocate_gsubgpos_vars (buffer
);
452 hb_ot_layout_substitute_start (c
->font
, buffer
);
454 if (!hb_ot_layout_has_glyph_classes (c
->face
))
455 hb_synthesize_glyph_classes (c
);
457 c
->plan
->substitute (c
->font
, buffer
);
459 hb_ot_layout_substitute_finish (c
->font
, buffer
);
465 hb_ot_substitute (hb_ot_shape_context_t
*c
)
467 hb_ot_substitute_default (c
);
468 hb_ot_substitute_complex (c
);
474 adjust_mark_offsets (hb_glyph_position_t
*pos
)
476 pos
->x_offset
-= pos
->x_advance
;
477 pos
->y_offset
-= pos
->y_advance
;
481 zero_mark_width (hb_glyph_position_t
*pos
)
488 zero_mark_widths_by_unicode (hb_buffer_t
*buffer
, bool adjust_offsets
)
490 unsigned int count
= buffer
->len
;
491 hb_glyph_info_t
*info
= buffer
->info
;
492 for (unsigned int i
= 0; i
< count
; i
++)
493 if (_hb_glyph_info_get_general_category (&info
[i
]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
)
496 adjust_mark_offsets (&buffer
->pos
[i
]);
497 zero_mark_width (&buffer
->pos
[i
]);
502 zero_mark_widths_by_gdef (hb_buffer_t
*buffer
, bool adjust_offsets
)
504 unsigned int count
= buffer
->len
;
505 hb_glyph_info_t
*info
= buffer
->info
;
506 for (unsigned int i
= 0; i
< count
; i
++)
507 if (_hb_glyph_info_is_mark (&info
[i
]))
510 adjust_mark_offsets (&buffer
->pos
[i
]);
511 zero_mark_width (&buffer
->pos
[i
]);
516 hb_ot_position_default (hb_ot_shape_context_t
*c
)
518 hb_direction_t direction
= c
->buffer
->props
.direction
;
519 unsigned int count
= c
->buffer
->len
;
520 hb_glyph_info_t
*info
= c
->buffer
->info
;
521 hb_glyph_position_t
*pos
= c
->buffer
->pos
;
522 for (unsigned int i
= 0; i
< count
; i
++)
524 c
->font
->get_glyph_advance_for_direction (info
[i
].codepoint
,
528 c
->font
->subtract_glyph_origin_for_direction (info
[i
].codepoint
,
537 hb_ot_position_complex (hb_ot_shape_context_t
*c
)
540 unsigned int count
= c
->buffer
->len
;
541 bool has_positioning
= hb_ot_layout_has_positioning (c
->face
);
542 /* If the font has no GPOS, AND, no fallback positioning will
543 * happen, AND, direction is forward, then when zeroing mark
544 * widths, we shift the mark with it, such that the mark
545 * is positioned hanging over the previous glyph. When
546 * direction is backward we don't shift and it will end up
547 * hanging over the next glyph after the final reordering.
548 * If fallback positinoing happens or GPOS is present, we don't
551 bool adjust_offsets_when_zeroing
= !(has_positioning
|| c
->plan
->shaper
->fallback_position
||
552 HB_DIRECTION_IS_BACKWARD (c
->buffer
->props
.direction
));
554 switch (c
->plan
->shaper
->zero_width_marks
)
556 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY
:
557 zero_mark_widths_by_gdef (c
->buffer
, adjust_offsets_when_zeroing
);
560 /* Not currently used for any shaper:
561 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
562 zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
567 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE
:
568 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
:
569 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
:
575 hb_glyph_info_t
*info
= c
->buffer
->info
;
576 hb_glyph_position_t
*pos
= c
->buffer
->pos
;
578 /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
580 for (unsigned int i
= 0; i
< count
; i
++) {
581 c
->font
->add_glyph_origin_for_direction (info
[i
].codepoint
,
587 c
->plan
->position (c
->font
, c
->buffer
);
589 for (unsigned int i
= 0; i
< count
; i
++) {
590 c
->font
->subtract_glyph_origin_for_direction (info
[i
].codepoint
,
599 switch (c
->plan
->shaper
->zero_width_marks
)
601 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
:
602 zero_mark_widths_by_unicode (c
->buffer
, adjust_offsets_when_zeroing
);
605 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
:
606 zero_mark_widths_by_gdef (c
->buffer
, adjust_offsets_when_zeroing
);
610 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE
:
611 //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
612 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY
:
620 hb_ot_position (hb_ot_shape_context_t
*c
)
622 hb_ot_layout_position_start (c
->font
, c
->buffer
);
624 hb_ot_position_default (c
);
626 hb_bool_t fallback
= !hb_ot_position_complex (c
);
628 hb_ot_layout_position_finish (c
->font
, c
->buffer
);
630 if (fallback
&& c
->plan
->shaper
->fallback_position
)
631 _hb_ot_shape_fallback_position (c
->plan
, c
->font
, c
->buffer
);
633 if (HB_DIRECTION_IS_BACKWARD (c
->buffer
->props
.direction
))
634 hb_buffer_reverse (c
->buffer
);
636 /* Visual fallback goes here. */
639 _hb_ot_shape_fallback_kern (c
->plan
, c
->font
, c
->buffer
);
641 _hb_buffer_deallocate_gsubgpos_vars (c
->buffer
);
648 hb_ot_hide_default_ignorables (hb_ot_shape_context_t
*c
)
650 if (c
->buffer
->flags
& HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES
)
653 hb_codepoint_t space
;
658 } space_status
= SPACE_DONT_KNOW
;
660 unsigned int count
= c
->buffer
->len
;
661 hb_glyph_info_t
*info
= c
->buffer
->info
;
662 hb_glyph_position_t
*pos
= c
->buffer
->pos
;
664 for (unsigned int i
= 0; i
< count
; i
++)
666 if (unlikely (!_hb_glyph_info_ligated (&info
[i
]) &&
667 _hb_glyph_info_is_default_ignorable (&info
[i
])))
669 if (space_status
== SPACE_DONT_KNOW
)
670 space_status
= c
->font
->get_glyph (' ', 0, &space
) ? SPACE_AVAILABLE
: SPACE_UNAVAILABLE
;
672 if (space_status
== SPACE_AVAILABLE
)
674 info
[i
].codepoint
= space
;
675 pos
[i
].x_advance
= 0;
676 pos
[i
].y_advance
= 0;
679 continue; /* Delete it. XXX Merge clusters? */
692 /* Pull it all together! */
695 hb_ot_shape_internal (hb_ot_shape_context_t
*c
)
697 c
->buffer
->deallocate_var_all ();
699 /* Save the original direction, we use it later. */
700 c
->target_direction
= c
->buffer
->props
.direction
;
702 _hb_buffer_allocate_unicode_vars (c
->buffer
);
704 c
->buffer
->clear_output ();
706 hb_set_unicode_props (c
->buffer
);
707 hb_insert_dotted_circle (c
->buffer
, c
->font
);
708 hb_form_clusters (c
->buffer
);
710 hb_ensure_native_direction (c
->buffer
);
712 hb_ot_substitute (c
);
715 hb_ot_hide_default_ignorables (c
);
717 _hb_buffer_deallocate_unicode_vars (c
->buffer
);
719 c
->buffer
->props
.direction
= c
->target_direction
;
721 c
->buffer
->deallocate_var_all ();
726 _hb_ot_shape (hb_shape_plan_t
*shape_plan
,
729 const hb_feature_t
*features
,
730 unsigned int num_features
)
732 hb_ot_shape_context_t c
= {HB_SHAPER_DATA_GET (shape_plan
), font
, font
->face
, buffer
, features
, num_features
};
733 hb_ot_shape_internal (&c
);
740 hb_ot_shape_plan_collect_lookups (hb_shape_plan_t
*shape_plan
,
742 hb_set_t
*lookup_indexes
/* OUT */)
744 /* XXX Does the first part always succeed? */
745 HB_SHAPER_DATA_GET (shape_plan
)->collect_lookups (table_tag
, lookup_indexes
);
749 /* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
751 add_char (hb_font_t
*font
,
752 hb_unicode_funcs_t
*unicode
,
757 hb_codepoint_t glyph
;
758 if (font
->get_glyph (u
, 0, &glyph
))
762 hb_codepoint_t m
= unicode
->mirroring (u
);
763 if (m
!= u
&& font
->get_glyph (m
, 0, &glyph
))
770 hb_ot_shape_glyphs_closure (hb_font_t
*font
,
772 const hb_feature_t
*features
,
773 unsigned int num_features
,
776 hb_ot_shape_plan_t plan
;
778 const char *shapers
[] = {"ot", NULL
};
779 hb_shape_plan_t
*shape_plan
= hb_shape_plan_create_cached (font
->face
, &buffer
->props
,
780 features
, num_features
, shapers
);
782 bool mirror
= hb_script_get_horizontal_direction (buffer
->props
.script
) == HB_DIRECTION_RTL
;
784 unsigned int count
= buffer
->len
;
785 hb_glyph_info_t
*info
= buffer
->info
;
786 for (unsigned int i
= 0; i
< count
; i
++)
787 add_char (font
, buffer
->unicode
, mirror
, info
[i
].codepoint
, glyphs
);
791 hb_ot_shape_plan_collect_lookups (shape_plan
, HB_OT_TAG_GSUB
, &lookups
);
793 /* And find transitive closure. */
798 for (hb_codepoint_t lookup_index
= -1; hb_set_next (&lookups
, &lookup_index
);)
799 hb_ot_layout_lookup_substitute_closure (font
->face
, lookup_index
, glyphs
);
800 } while (!copy
.is_equal (glyphs
));
802 hb_shape_plan_destroy (shape_plan
);