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'),
61 static hb_tag_t vertical_features
[] = {
62 HB_TAG('v','e','r','t'),
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
)
73 hb_ot_map_builder_t
*map
= &planner
->map
;
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'));
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
);
84 case HB_DIRECTION_TTB
:
85 case HB_DIRECTION_BTT
:
86 case HB_DIRECTION_INVALID
:
91 if (planner
->shaper
->collect_features
)
92 planner
->shaper
->collect_features (planner
);
94 for (unsigned int i
= 0; i
< ARRAY_LENGTH (common_features
); i
++)
95 map
->add_global_bool_feature (common_features
[i
]);
97 if (HB_DIRECTION_IS_HORIZONTAL (props
->direction
))
98 for (unsigned int i
= 0; i
< ARRAY_LENGTH (horizontal_features
); i
++)
99 map
->add_feature (horizontal_features
[i
], 1, F_GLOBAL
|
100 (horizontal_features
[i
] == HB_TAG('k','e','r','n') ?
101 F_HAS_FALLBACK
: F_NONE
));
103 for (unsigned int i
= 0; i
< ARRAY_LENGTH (vertical_features
); i
++)
104 map
->add_feature (vertical_features
[i
], 1, F_GLOBAL
|
105 (vertical_features
[i
] == HB_TAG('v','k','r','n') ?
106 F_HAS_FALLBACK
: F_NONE
));
108 if (planner
->shaper
->override_features
)
109 planner
->shaper
->override_features (planner
);
111 for (unsigned int i
= 0; i
< num_user_features
; i
++) {
112 const hb_feature_t
*feature
= &user_features
[i
];
113 map
->add_feature (feature
->tag
, feature
->value
,
114 (feature
->start
== 0 && feature
->end
== (unsigned int) -1) ?
124 hb_ot_shaper_face_data_t
*
125 _hb_ot_shaper_face_data_create (hb_face_t
*face
)
127 return _hb_ot_layout_create (face
);
131 _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t
*data
)
133 _hb_ot_layout_destroy (data
);
141 struct hb_ot_shaper_font_data_t
{};
143 hb_ot_shaper_font_data_t
*
144 _hb_ot_shaper_font_data_create (hb_font_t
*font
)
146 return (hb_ot_shaper_font_data_t
*) HB_SHAPER_DATA_SUCCEEDED
;
150 _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t
*data
)
156 * shaper shape_plan data
159 hb_ot_shaper_shape_plan_data_t
*
160 _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t
*shape_plan
,
161 const hb_feature_t
*user_features
,
162 unsigned int num_user_features
)
164 hb_ot_shape_plan_t
*plan
= (hb_ot_shape_plan_t
*) calloc (1, sizeof (hb_ot_shape_plan_t
));
165 if (unlikely (!plan
))
168 hb_ot_shape_planner_t
planner (shape_plan
);
170 planner
.shaper
= hb_ot_shape_complex_categorize (&planner
);
172 hb_ot_shape_collect_features (&planner
, &shape_plan
->props
, user_features
, num_user_features
);
174 planner
.compile (*plan
);
176 if (plan
->shaper
->data_create
) {
177 plan
->data
= plan
->shaper
->data_create (plan
);
178 if (unlikely (!plan
->data
))
186 _hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t
*plan
)
188 if (plan
->shaper
->data_destroy
)
189 plan
->shaper
->data_destroy (const_cast<void *> (plan
->data
));
201 struct hb_ot_shape_context_t
203 hb_ot_shape_plan_t
*plan
;
207 const hb_feature_t
*user_features
;
208 unsigned int num_user_features
;
210 /* Transient stuff */
211 hb_direction_t target_direction
;
222 hb_set_unicode_props (hb_buffer_t
*buffer
)
224 unsigned int count
= buffer
->len
;
225 for (unsigned int i
= 0; i
< count
; i
++)
226 _hb_glyph_info_set_unicode_props (&buffer
->info
[i
], buffer
->unicode
);
230 hb_insert_dotted_circle (hb_buffer_t
*buffer
, hb_font_t
*font
)
232 if (!(buffer
->flags
& HB_BUFFER_FLAG_BOT
) ||
233 _hb_glyph_info_get_general_category (&buffer
->info
[0]) !=
234 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
)
237 hb_codepoint_t dottedcircle_glyph
;
238 if (!font
->get_glyph (0x25CC, 0, &dottedcircle_glyph
))
241 hb_glyph_info_t dottedcircle
;
242 dottedcircle
.codepoint
= 0x25CC;
243 _hb_glyph_info_set_unicode_props (&dottedcircle
, buffer
->unicode
);
245 buffer
->clear_output ();
248 hb_glyph_info_t info
= dottedcircle
;
249 info
.cluster
= buffer
->cur().cluster
;
250 info
.mask
= buffer
->cur().mask
;
251 buffer
->output_info (info
);
252 while (buffer
->idx
< buffer
->len
)
253 buffer
->next_glyph ();
255 buffer
->swap_buffers ();
259 hb_form_clusters (hb_buffer_t
*buffer
)
261 unsigned int count
= buffer
->len
;
262 for (unsigned int i
= 1; i
< count
; i
++)
263 if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer
->info
[i
])))
264 buffer
->merge_clusters (i
- 1, i
+ 1);
268 hb_ensure_native_direction (hb_buffer_t
*buffer
)
270 hb_direction_t direction
= buffer
->props
.direction
;
273 * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
274 * Ogham fonts are supposed to be implemented BTT or not. Need to research that
276 if ((HB_DIRECTION_IS_HORIZONTAL (direction
) && direction
!= hb_script_get_horizontal_direction (buffer
->props
.script
)) ||
277 (HB_DIRECTION_IS_VERTICAL (direction
) && direction
!= HB_DIRECTION_TTB
))
279 hb_buffer_reverse_clusters (buffer
);
280 buffer
->props
.direction
= HB_DIRECTION_REVERSE (buffer
->props
.direction
);
288 hb_ot_mirror_chars (hb_ot_shape_context_t
*c
)
290 if (HB_DIRECTION_IS_FORWARD (c
->target_direction
))
293 hb_buffer_t
*buffer
= c
->buffer
;
294 hb_unicode_funcs_t
*unicode
= buffer
->unicode
;
295 hb_mask_t rtlm_mask
= c
->plan
->map
.get_1_mask (HB_TAG ('r','t','l','m'));
297 unsigned int count
= buffer
->len
;
298 hb_glyph_info_t
*info
= buffer
->info
;
299 for (unsigned int i
= 0; i
< count
; i
++) {
300 hb_codepoint_t codepoint
= unicode
->mirroring (info
[i
].codepoint
);
301 if (likely (codepoint
== info
[i
].codepoint
))
302 info
[i
].mask
|= rtlm_mask
;
304 info
[i
].codepoint
= codepoint
;
309 hb_ot_shape_setup_masks (hb_ot_shape_context_t
*c
)
311 hb_ot_map_t
*map
= &c
->plan
->map
;
312 hb_buffer_t
*buffer
= c
->buffer
;
314 hb_mask_t global_mask
= map
->get_global_mask ();
315 buffer
->reset_masks (global_mask
);
317 if (c
->plan
->shaper
->setup_masks
)
318 c
->plan
->shaper
->setup_masks (c
->plan
, buffer
, c
->font
);
320 for (unsigned int i
= 0; i
< c
->num_user_features
; i
++)
322 const hb_feature_t
*feature
= &c
->user_features
[i
];
323 if (!(feature
->start
== 0 && feature
->end
== (unsigned int)-1)) {
325 hb_mask_t mask
= map
->get_mask (feature
->tag
, &shift
);
326 buffer
->set_masks (feature
->value
<< shift
, mask
, feature
->start
, feature
->end
);
332 hb_ot_map_glyphs_fast (hb_buffer_t
*buffer
)
334 /* Normalization process sets up glyph_index(), we just copy it. */
335 unsigned int count
= buffer
->len
;
336 for (unsigned int i
= 0; i
< count
; i
++)
337 buffer
->info
[i
].codepoint
= buffer
->info
[i
].glyph_index();
341 hb_synthesize_glyph_classes (hb_ot_shape_context_t
*c
)
343 unsigned int count
= c
->buffer
->len
;
344 hb_glyph_info_t
*info
= c
->buffer
->info
;
345 for (unsigned int i
= 0; i
< count
; i
++)
346 _hb_glyph_info_set_glyph_props (&info
[i
],
347 _hb_glyph_info_get_general_category (&info
[i
])
348 == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
?
349 HB_OT_LAYOUT_GLYPH_PROPS_MARK
:
350 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH
);
354 hb_ot_substitute_default (hb_ot_shape_context_t
*c
)
356 hb_buffer_t
*buffer
= c
->buffer
;
358 if (c
->plan
->shaper
->preprocess_text
)
359 c
->plan
->shaper
->preprocess_text (c
->plan
, buffer
, c
->font
);
361 hb_ot_mirror_chars (c
);
363 HB_BUFFER_ALLOCATE_VAR (buffer
, glyph_index
);
365 _hb_ot_shape_normalize (c
->plan
, buffer
, c
->font
);
367 hb_ot_shape_setup_masks (c
);
369 /* This is unfortunate to go here, but necessary... */
370 if (!hb_ot_layout_has_positioning (c
->face
))
371 _hb_ot_shape_fallback_position_recategorize_marks (c
->plan
, c
->font
, buffer
);
373 hb_ot_map_glyphs_fast (buffer
);
375 HB_BUFFER_DEALLOCATE_VAR (buffer
, glyph_index
);
379 hb_ot_substitute_complex (hb_ot_shape_context_t
*c
)
381 hb_buffer_t
*buffer
= c
->buffer
;
383 hb_ot_layout_substitute_start (c
->font
, buffer
);
385 if (!hb_ot_layout_has_glyph_classes (c
->face
))
386 hb_synthesize_glyph_classes (c
);
388 c
->plan
->substitute (c
->font
, buffer
);
390 hb_ot_layout_substitute_finish (c
->font
, buffer
);
396 hb_ot_substitute (hb_ot_shape_context_t
*c
)
398 hb_ot_substitute_default (c
);
399 hb_ot_substitute_complex (c
);
405 zero_mark_widths_by_unicode (hb_buffer_t
*buffer
)
407 unsigned int count
= buffer
->len
;
408 for (unsigned int i
= 0; i
< count
; i
++)
409 if (_hb_glyph_info_get_general_category (&buffer
->info
[i
]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
)
411 buffer
->pos
[i
].x_advance
= 0;
412 buffer
->pos
[i
].y_advance
= 0;
417 zero_mark_widths_by_gdef (hb_buffer_t
*buffer
)
419 unsigned int count
= buffer
->len
;
420 for (unsigned int i
= 0; i
< count
; i
++)
421 if (_hb_glyph_info_is_mark (&buffer
->info
[i
]))
423 buffer
->pos
[i
].x_advance
= 0;
424 buffer
->pos
[i
].y_advance
= 0;
429 hb_ot_position_default (hb_ot_shape_context_t
*c
)
431 hb_direction_t direction
= c
->buffer
->props
.direction
;
432 unsigned int count
= c
->buffer
->len
;
433 hb_glyph_info_t
*info
= c
->buffer
->info
;
434 hb_glyph_position_t
*pos
= c
->buffer
->pos
;
435 for (unsigned int i
= 0; i
< count
; i
++)
437 c
->font
->get_glyph_advance_for_direction (info
[i
].codepoint
,
441 c
->font
->subtract_glyph_origin_for_direction (info
[i
].codepoint
,
450 hb_ot_position_complex (hb_ot_shape_context_t
*c
)
453 unsigned int count
= c
->buffer
->len
;
455 switch (c
->plan
->shaper
->zero_width_marks
)
457 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY
:
458 zero_mark_widths_by_gdef (c
->buffer
);
461 /* Not currently used for any shaper:
462 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
463 zero_mark_widths_by_unicode (c->buffer);
468 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE
:
469 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
:
470 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
:
474 if (hb_ot_layout_has_positioning (c
->face
))
476 hb_glyph_info_t
*info
= c
->buffer
->info
;
477 hb_glyph_position_t
*pos
= c
->buffer
->pos
;
479 /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
481 for (unsigned int i
= 0; i
< count
; i
++) {
482 c
->font
->add_glyph_origin_for_direction (info
[i
].codepoint
,
488 c
->plan
->position (c
->font
, c
->buffer
);
490 for (unsigned int i
= 0; i
< count
; i
++) {
491 c
->font
->subtract_glyph_origin_for_direction (info
[i
].codepoint
,
500 switch (c
->plan
->shaper
->zero_width_marks
)
502 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
:
503 zero_mark_widths_by_unicode (c
->buffer
);
506 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
:
507 zero_mark_widths_by_gdef (c
->buffer
);
511 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE
:
512 //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
513 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY
:
521 hb_ot_position (hb_ot_shape_context_t
*c
)
523 hb_ot_layout_position_start (c
->font
, c
->buffer
);
525 hb_ot_position_default (c
);
527 hb_bool_t fallback
= !hb_ot_position_complex (c
);
529 hb_ot_layout_position_finish (c
->font
, c
->buffer
);
531 if (fallback
&& c
->plan
->shaper
->fallback_position
)
532 _hb_ot_shape_fallback_position (c
->plan
, c
->font
, c
->buffer
);
534 if (HB_DIRECTION_IS_BACKWARD (c
->buffer
->props
.direction
))
535 hb_buffer_reverse (c
->buffer
);
537 /* Visual fallback goes here. */
540 _hb_ot_shape_fallback_kern (c
->plan
, c
->font
, c
->buffer
);
547 hb_ot_hide_default_ignorables (hb_ot_shape_context_t
*c
)
549 if (c
->buffer
->flags
& HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES
)
552 hb_codepoint_t space
;
557 } space_status
= SPACE_DONT_KNOW
;
559 unsigned int count
= c
->buffer
->len
;
560 hb_glyph_info_t
*info
= c
->buffer
->info
;
561 hb_glyph_position_t
*pos
= c
->buffer
->pos
;
563 for (unsigned int i
= 0; i
< count
; i
++)
565 if (unlikely (!_hb_glyph_info_ligated (&info
[i
]) &&
566 _hb_glyph_info_is_default_ignorable (&info
[i
])))
568 if (space_status
== SPACE_DONT_KNOW
)
569 space_status
= c
->font
->get_glyph (' ', 0, &space
) ? SPACE_AVAILABLE
: SPACE_UNAVAILABLE
;
571 if (space_status
== SPACE_AVAILABLE
)
573 info
[i
].codepoint
= space
;
574 pos
[i
].x_advance
= 0;
575 pos
[i
].y_advance
= 0;
578 continue; /* Delete it. */
591 /* Pull it all together! */
594 hb_ot_shape_internal (hb_ot_shape_context_t
*c
)
596 c
->buffer
->deallocate_var_all ();
598 /* Save the original direction, we use it later. */
599 c
->target_direction
= c
->buffer
->props
.direction
;
601 _hb_buffer_allocate_unicode_vars (c
->buffer
);
603 c
->buffer
->clear_output ();
605 hb_set_unicode_props (c
->buffer
);
606 hb_insert_dotted_circle (c
->buffer
, c
->font
);
607 hb_form_clusters (c
->buffer
);
609 hb_ensure_native_direction (c
->buffer
);
611 hb_ot_substitute (c
);
614 hb_ot_hide_default_ignorables (c
);
616 _hb_buffer_deallocate_unicode_vars (c
->buffer
);
618 c
->buffer
->props
.direction
= c
->target_direction
;
620 c
->buffer
->deallocate_var_all ();
625 _hb_ot_shape (hb_shape_plan_t
*shape_plan
,
628 const hb_feature_t
*features
,
629 unsigned int num_features
)
631 hb_ot_shape_context_t c
= {HB_SHAPER_DATA_GET (shape_plan
), font
, font
->face
, buffer
, features
, num_features
};
632 hb_ot_shape_internal (&c
);
639 hb_ot_shape_plan_collect_lookups (hb_shape_plan_t
*shape_plan
,
641 hb_set_t
*lookup_indexes
/* OUT */)
643 /* XXX Does the first part always succeed? */
644 HB_SHAPER_DATA_GET (shape_plan
)->collect_lookups (table_tag
, lookup_indexes
);
648 /* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
650 add_char (hb_font_t
*font
,
651 hb_unicode_funcs_t
*unicode
,
656 hb_codepoint_t glyph
;
657 if (font
->get_glyph (u
, 0, &glyph
))
661 hb_codepoint_t m
= unicode
->mirroring (u
);
662 if (m
!= u
&& font
->get_glyph (m
, 0, &glyph
))
669 hb_ot_shape_glyphs_closure (hb_font_t
*font
,
671 const hb_feature_t
*features
,
672 unsigned int num_features
,
675 hb_ot_shape_plan_t plan
;
677 const char *shapers
[] = {"ot", NULL
};
678 hb_shape_plan_t
*shape_plan
= hb_shape_plan_create_cached (font
->face
, &buffer
->props
,
679 features
, num_features
, shapers
);
681 bool mirror
= hb_script_get_horizontal_direction (buffer
->props
.script
) == HB_DIRECTION_RTL
;
683 unsigned int count
= buffer
->len
;
684 for (unsigned int i
= 0; i
< count
; i
++)
685 add_char (font
, buffer
->unicode
, mirror
, buffer
->info
[i
].codepoint
, glyphs
);
689 hb_ot_shape_plan_collect_lookups (shape_plan
, HB_OT_TAG_GSUB
, &lookups
);
691 /* And find transitive closure. */
696 for (hb_codepoint_t lookup_index
= -1; hb_set_next (&lookups
, &lookup_index
);)
697 hb_ot_layout_lookup_substitute_closure (font
->face
, lookup_index
, glyphs
);
698 } while (!copy
.is_equal (glyphs
));
700 hb_shape_plan_destroy (shape_plan
);