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-set-private.hh"
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'),
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'),
62 * Technically speaking, vrt2 and vert are mutually exclusive.
63 * According to the spec, valt and vpal are also mutually exclusive.
64 * But we apply them all for now.
66 static hb_tag_t vertical_features
[] = {
67 HB_TAG('v','a','l','t'),
68 HB_TAG('v','e','r','t'),
69 HB_TAG('v','k','r','n'),
70 HB_TAG('v','p','a','l'),
71 HB_TAG('v','r','t','2'),
77 hb_ot_shape_collect_features (hb_ot_shape_planner_t
*planner
,
78 const hb_segment_properties_t
*props
,
79 const hb_feature_t
*user_features
,
80 unsigned int num_user_features
)
82 hb_ot_map_builder_t
*map
= &planner
->map
;
84 switch (props
->direction
) {
85 case HB_DIRECTION_LTR
:
86 map
->add_global_bool_feature (HB_TAG ('l','t','r','a'));
87 map
->add_global_bool_feature (HB_TAG ('l','t','r','m'));
89 case HB_DIRECTION_RTL
:
90 map
->add_global_bool_feature (HB_TAG ('r','t','l','a'));
91 map
->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE
);
93 case HB_DIRECTION_TTB
:
94 case HB_DIRECTION_BTT
:
95 case HB_DIRECTION_INVALID
:
100 if (planner
->shaper
->collect_features
)
101 planner
->shaper
->collect_features (planner
);
103 for (unsigned int i
= 0; i
< ARRAY_LENGTH (common_features
); i
++)
104 map
->add_global_bool_feature (common_features
[i
]);
106 if (HB_DIRECTION_IS_HORIZONTAL (props
->direction
))
107 for (unsigned int i
= 0; i
< ARRAY_LENGTH (horizontal_features
); i
++)
108 map
->add_feature (horizontal_features
[i
], 1, F_GLOBAL
|
109 (horizontal_features
[i
] == HB_TAG('k','e','r','n') ?
110 F_HAS_FALLBACK
: F_NONE
));
112 for (unsigned int i
= 0; i
< ARRAY_LENGTH (vertical_features
); i
++)
113 map
->add_feature (vertical_features
[i
], 1, F_GLOBAL
|
114 (vertical_features
[i
] == HB_TAG('v','k','r','n') ?
115 F_HAS_FALLBACK
: F_NONE
));
117 if (planner
->shaper
->override_features
)
118 planner
->shaper
->override_features (planner
);
120 for (unsigned int i
= 0; i
< num_user_features
; i
++) {
121 const hb_feature_t
*feature
= &user_features
[i
];
122 map
->add_feature (feature
->tag
, feature
->value
,
123 (feature
->start
== 0 && feature
->end
== (unsigned int) -1) ?
133 hb_ot_shaper_face_data_t
*
134 _hb_ot_shaper_face_data_create (hb_face_t
*face
)
136 return _hb_ot_layout_create (face
);
140 _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t
*data
)
142 _hb_ot_layout_destroy (data
);
150 struct hb_ot_shaper_font_data_t
{};
152 hb_ot_shaper_font_data_t
*
153 _hb_ot_shaper_font_data_create (hb_font_t
*font
)
155 return (hb_ot_shaper_font_data_t
*) HB_SHAPER_DATA_SUCCEEDED
;
159 _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t
*data
)
165 * shaper shape_plan data
168 hb_ot_shaper_shape_plan_data_t
*
169 _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t
*shape_plan
,
170 const hb_feature_t
*user_features
,
171 unsigned int num_user_features
)
173 hb_ot_shape_plan_t
*plan
= (hb_ot_shape_plan_t
*) calloc (1, sizeof (hb_ot_shape_plan_t
));
174 if (unlikely (!plan
))
177 hb_ot_shape_planner_t
planner (shape_plan
);
179 planner
.shaper
= hb_ot_shape_complex_categorize (&planner
);
181 hb_ot_shape_collect_features (&planner
, &shape_plan
->props
, user_features
, num_user_features
);
183 planner
.compile (*plan
);
185 if (plan
->shaper
->data_create
) {
186 plan
->data
= plan
->shaper
->data_create (plan
);
187 if (unlikely (!plan
->data
))
195 _hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t
*plan
)
197 if (plan
->shaper
->data_destroy
)
198 plan
->shaper
->data_destroy (const_cast<void *> (plan
->data
));
210 struct hb_ot_shape_context_t
212 hb_ot_shape_plan_t
*plan
;
216 const hb_feature_t
*user_features
;
217 unsigned int num_user_features
;
219 /* Transient stuff */
220 hb_direction_t target_direction
;
231 hb_set_unicode_props (hb_buffer_t
*buffer
)
233 unsigned int count
= buffer
->len
;
234 for (unsigned int i
= 0; i
< count
; i
++)
235 _hb_glyph_info_set_unicode_props (&buffer
->info
[i
], buffer
->unicode
);
239 hb_insert_dotted_circle (hb_buffer_t
*buffer
, hb_font_t
*font
)
241 if (!(buffer
->flags
& HB_BUFFER_FLAG_BOT
) ||
242 _hb_glyph_info_get_general_category (&buffer
->info
[0]) !=
243 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
)
246 hb_codepoint_t dottedcircle_glyph
;
247 if (!font
->get_glyph (0x25CC, 0, &dottedcircle_glyph
))
250 hb_glyph_info_t dottedcircle
;
251 dottedcircle
.codepoint
= 0x25CC;
252 _hb_glyph_info_set_unicode_props (&dottedcircle
, buffer
->unicode
);
254 buffer
->clear_output ();
257 hb_glyph_info_t info
= dottedcircle
;
258 info
.cluster
= buffer
->cur().cluster
;
259 info
.mask
= buffer
->cur().mask
;
260 buffer
->output_info (info
);
261 while (buffer
->idx
< buffer
->len
)
262 buffer
->next_glyph ();
264 buffer
->swap_buffers ();
268 hb_form_clusters (hb_buffer_t
*buffer
)
270 unsigned int count
= buffer
->len
;
271 for (unsigned int i
= 1; i
< count
; i
++)
272 if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer
->info
[i
])))
273 buffer
->merge_clusters (i
- 1, i
+ 1);
277 hb_ensure_native_direction (hb_buffer_t
*buffer
)
279 hb_direction_t direction
= buffer
->props
.direction
;
282 * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
283 * Ogham fonts are supposed to be implemented BTT or not. Need to research that
285 if ((HB_DIRECTION_IS_HORIZONTAL (direction
) && direction
!= hb_script_get_horizontal_direction (buffer
->props
.script
)) ||
286 (HB_DIRECTION_IS_VERTICAL (direction
) && direction
!= HB_DIRECTION_TTB
))
288 hb_buffer_reverse_clusters (buffer
);
289 buffer
->props
.direction
= HB_DIRECTION_REVERSE (buffer
->props
.direction
);
297 hb_ot_mirror_chars (hb_ot_shape_context_t
*c
)
299 if (HB_DIRECTION_IS_FORWARD (c
->target_direction
))
302 hb_unicode_funcs_t
*unicode
= c
->buffer
->unicode
;
303 hb_mask_t rtlm_mask
= c
->plan
->map
.get_1_mask (HB_TAG ('r','t','l','m'));
305 unsigned int count
= c
->buffer
->len
;
306 for (unsigned int i
= 0; i
< count
; i
++) {
307 hb_codepoint_t codepoint
= unicode
->mirroring (c
->buffer
->info
[i
].codepoint
);
308 if (likely (codepoint
== c
->buffer
->info
[i
].codepoint
))
309 c
->buffer
->info
[i
].mask
|= rtlm_mask
;
311 c
->buffer
->info
[i
].codepoint
= codepoint
;
316 hb_ot_shape_setup_masks (hb_ot_shape_context_t
*c
)
318 hb_ot_map_t
*map
= &c
->plan
->map
;
320 hb_mask_t global_mask
= map
->get_global_mask ();
321 c
->buffer
->reset_masks (global_mask
);
323 if (c
->plan
->shaper
->setup_masks
)
324 c
->plan
->shaper
->setup_masks (c
->plan
, c
->buffer
, c
->font
);
326 for (unsigned int i
= 0; i
< c
->num_user_features
; i
++)
328 const hb_feature_t
*feature
= &c
->user_features
[i
];
329 if (!(feature
->start
== 0 && feature
->end
== (unsigned int)-1)) {
331 hb_mask_t mask
= map
->get_mask (feature
->tag
, &shift
);
332 c
->buffer
->set_masks (feature
->value
<< shift
, mask
, feature
->start
, feature
->end
);
338 hb_ot_map_glyphs_fast (hb_buffer_t
*buffer
)
340 /* Normalization process sets up glyph_index(), we just copy it. */
341 unsigned int count
= buffer
->len
;
342 for (unsigned int i
= 0; i
< count
; i
++)
343 buffer
->info
[i
].codepoint
= buffer
->info
[i
].glyph_index();
347 hb_synthesize_glyph_classes (hb_ot_shape_context_t
*c
)
349 unsigned int count
= c
->buffer
->len
;
350 for (unsigned int i
= 0; i
< count
; i
++)
351 c
->buffer
->info
[i
].glyph_props() = _hb_glyph_info_get_general_category (&c
->buffer
->info
[i
]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
?
352 HB_OT_LAYOUT_GLYPH_PROPS_MARK
:
353 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH
;
357 hb_ot_substitute_default (hb_ot_shape_context_t
*c
)
359 if (c
->plan
->shaper
->preprocess_text
)
360 c
->plan
->shaper
->preprocess_text (c
->plan
, c
->buffer
, c
->font
);
362 hb_ot_mirror_chars (c
);
364 HB_BUFFER_ALLOCATE_VAR (c
->buffer
, glyph_index
);
366 _hb_ot_shape_normalize (c
->plan
, c
->buffer
, c
->font
);
368 hb_ot_shape_setup_masks (c
);
370 /* This is unfortunate to go here, but necessary... */
371 if (!hb_ot_layout_has_positioning (c
->face
))
372 _hb_ot_shape_fallback_position_recategorize_marks (c
->plan
, c
->font
, c
->buffer
);
374 hb_ot_map_glyphs_fast (c
->buffer
);
376 HB_BUFFER_DEALLOCATE_VAR (c
->buffer
, glyph_index
);
380 hb_ot_substitute_complex (hb_ot_shape_context_t
*c
)
382 hb_ot_layout_substitute_start (c
->font
, c
->buffer
);
384 if (!hb_ot_layout_has_glyph_classes (c
->face
))
385 hb_synthesize_glyph_classes (c
);
387 c
->plan
->substitute (c
->font
, c
->buffer
);
389 hb_ot_layout_substitute_finish (c
->font
, c
->buffer
);
395 hb_ot_substitute (hb_ot_shape_context_t
*c
)
397 hb_ot_substitute_default (c
);
398 hb_ot_substitute_complex (c
);
404 zero_mark_widths_by_unicode (hb_buffer_t
*buffer
)
406 unsigned int count
= buffer
->len
;
407 for (unsigned int i
= 0; i
< count
; i
++)
408 if (_hb_glyph_info_get_general_category (&buffer
->info
[i
]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
)
410 buffer
->pos
[i
].x_advance
= 0;
411 buffer
->pos
[i
].y_advance
= 0;
416 zero_mark_widths_by_gdef (hb_buffer_t
*buffer
)
418 unsigned int count
= buffer
->len
;
419 for (unsigned int i
= 0; i
< count
; i
++)
420 if ((buffer
->info
[i
].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK
))
422 buffer
->pos
[i
].x_advance
= 0;
423 buffer
->pos
[i
].y_advance
= 0;
428 hb_ot_position_default (hb_ot_shape_context_t
*c
)
430 hb_ot_layout_position_start (c
->font
, c
->buffer
);
432 unsigned int count
= c
->buffer
->len
;
433 for (unsigned int i
= 0; i
< count
; i
++)
435 c
->font
->get_glyph_advance_for_direction (c
->buffer
->info
[i
].codepoint
,
436 c
->buffer
->props
.direction
,
437 &c
->buffer
->pos
[i
].x_advance
,
438 &c
->buffer
->pos
[i
].y_advance
);
439 c
->font
->subtract_glyph_origin_for_direction (c
->buffer
->info
[i
].codepoint
,
440 c
->buffer
->props
.direction
,
441 &c
->buffer
->pos
[i
].x_offset
,
442 &c
->buffer
->pos
[i
].y_offset
);
446 switch (c
->plan
->shaper
->zero_width_marks
)
448 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY
:
449 zero_mark_widths_by_gdef (c
->buffer
);
452 /* Not currently used for any shaper:
453 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
454 zero_mark_widths_by_unicode (c->buffer);
459 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE
:
460 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
:
461 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
:
467 hb_ot_position_complex (hb_ot_shape_context_t
*c
)
470 unsigned int count
= c
->buffer
->len
;
472 if (hb_ot_layout_has_positioning (c
->face
))
474 /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
476 for (unsigned int i
= 0; i
< count
; i
++) {
477 c
->font
->add_glyph_origin_for_direction (c
->buffer
->info
[i
].codepoint
,
479 &c
->buffer
->pos
[i
].x_offset
,
480 &c
->buffer
->pos
[i
].y_offset
);
483 c
->plan
->position (c
->font
, c
->buffer
);
485 for (unsigned int i
= 0; i
< count
; i
++) {
486 c
->font
->subtract_glyph_origin_for_direction (c
->buffer
->info
[i
].codepoint
,
488 &c
->buffer
->pos
[i
].x_offset
,
489 &c
->buffer
->pos
[i
].y_offset
);
495 switch (c
->plan
->shaper
->zero_width_marks
)
497 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
:
498 zero_mark_widths_by_unicode (c
->buffer
);
501 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
:
502 zero_mark_widths_by_gdef (c
->buffer
);
506 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE
:
507 //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
508 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY
:
512 hb_ot_layout_position_finish (c
->font
, c
->buffer
);
518 hb_ot_position (hb_ot_shape_context_t
*c
)
520 hb_ot_position_default (c
);
522 hb_bool_t fallback
= !hb_ot_position_complex (c
);
524 if (fallback
&& c
->plan
->shaper
->fallback_position
)
525 _hb_ot_shape_fallback_position (c
->plan
, c
->font
, c
->buffer
);
527 if (HB_DIRECTION_IS_BACKWARD (c
->buffer
->props
.direction
))
528 hb_buffer_reverse (c
->buffer
);
530 /* Visual fallback goes here. */
533 _hb_ot_shape_fallback_kern (c
->plan
, c
->font
, c
->buffer
);
540 hb_ot_hide_default_ignorables (hb_ot_shape_context_t
*c
)
542 if (c
->buffer
->flags
& HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES
)
545 hb_codepoint_t space
= 0;
547 unsigned int count
= c
->buffer
->len
;
548 for (unsigned int i
= 0; i
< count
; i
++)
549 if (unlikely (!is_a_ligature (c
->buffer
->info
[i
]) &&
550 _hb_glyph_info_is_default_ignorable (&c
->buffer
->info
[i
])))
553 /* We assume that the space glyph is not gid0. */
554 if (unlikely (!c
->font
->get_glyph (' ', 0, &space
)) || !space
)
555 return; /* No point! */
557 c
->buffer
->info
[i
].codepoint
= space
;
558 c
->buffer
->pos
[i
].x_advance
= 0;
559 c
->buffer
->pos
[i
].y_advance
= 0;
564 /* Pull it all together! */
567 hb_ot_shape_internal (hb_ot_shape_context_t
*c
)
569 c
->buffer
->deallocate_var_all ();
571 /* Save the original direction, we use it later. */
572 c
->target_direction
= c
->buffer
->props
.direction
;
574 HB_BUFFER_ALLOCATE_VAR (c
->buffer
, unicode_props0
);
575 HB_BUFFER_ALLOCATE_VAR (c
->buffer
, unicode_props1
);
577 c
->buffer
->clear_output ();
579 hb_set_unicode_props (c
->buffer
);
580 hb_insert_dotted_circle (c
->buffer
, c
->font
);
581 hb_form_clusters (c
->buffer
);
583 hb_ensure_native_direction (c
->buffer
);
585 hb_ot_substitute (c
);
588 hb_ot_hide_default_ignorables (c
);
590 HB_BUFFER_DEALLOCATE_VAR (c
->buffer
, unicode_props1
);
591 HB_BUFFER_DEALLOCATE_VAR (c
->buffer
, unicode_props0
);
593 c
->buffer
->props
.direction
= c
->target_direction
;
595 c
->buffer
->deallocate_var_all ();
600 _hb_ot_shape (hb_shape_plan_t
*shape_plan
,
603 const hb_feature_t
*features
,
604 unsigned int num_features
)
606 hb_ot_shape_context_t c
= {HB_SHAPER_DATA_GET (shape_plan
), font
, font
->face
, buffer
, features
, num_features
};
607 hb_ot_shape_internal (&c
);
614 hb_ot_shape_plan_collect_lookups (hb_shape_plan_t
*shape_plan
,
616 hb_set_t
*lookup_indexes
/* OUT */)
618 /* XXX Does the first part always succeed? */
619 HB_SHAPER_DATA_GET (shape_plan
)->collect_lookups (table_tag
, lookup_indexes
);
623 /* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
625 add_char (hb_font_t
*font
,
626 hb_unicode_funcs_t
*unicode
,
631 hb_codepoint_t glyph
;
632 if (font
->get_glyph (u
, 0, &glyph
))
636 hb_codepoint_t m
= unicode
->mirroring (u
);
637 if (m
!= u
&& font
->get_glyph (m
, 0, &glyph
))
644 hb_ot_shape_glyphs_closure (hb_font_t
*font
,
646 const hb_feature_t
*features
,
647 unsigned int num_features
,
650 hb_ot_shape_plan_t plan
;
652 const char *shapers
[] = {"ot", NULL
};
653 hb_shape_plan_t
*shape_plan
= hb_shape_plan_create_cached (font
->face
, &buffer
->props
,
654 features
, num_features
, shapers
);
656 bool mirror
= hb_script_get_horizontal_direction (buffer
->props
.script
) == HB_DIRECTION_RTL
;
658 unsigned int count
= buffer
->len
;
659 for (unsigned int i
= 0; i
< count
; i
++)
660 add_char (font
, buffer
->unicode
, mirror
, buffer
->info
[i
].codepoint
, glyphs
);
664 hb_ot_shape_plan_collect_lookups (shape_plan
, HB_OT_TAG_GSUB
, &lookups
);
666 /* And find transitive closure. */
671 for (hb_codepoint_t lookup_index
= -1; hb_set_next (&lookups
, &lookup_index
);)
672 hb_ot_layout_lookup_substitute_closure (font
->face
, lookup_index
, glyphs
);
673 } while (!copy
.is_equal (glyphs
));
675 hb_shape_plan_destroy (shape_plan
);