26#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
35#define FT_COMPONENT afshaper
60#define COVERAGE( name, NAME, description, \
61 tag1, tag2, tag3, tag4 ) \
62 static const hb_tag_t name ## _coverage[] = \
64 HB_TAG( tag1, tag2, tag3, tag4 ), \
74#define COVERAGE( name, NAME, description, \
75 tag1, tag2, tag3, tag4 ) \
79 static const hb_tag_t* coverages[] =
89#define SCRIPT( s, S, d, h, H, ss ) h,
100 af_shaper_get_coverage_hb( AF_FaceGlobals globals,
101 AF_StyleClass style_class,
103 FT_Bool default_script )
107 hb_set_t* gsub_lookups = NULL;
108 hb_set_t* gsub_glyphs = NULL;
109 hb_set_t* gpos_lookups = NULL;
110 hb_set_t* gpos_glyphs = NULL;
113 const hb_tag_t* coverage_tags;
114 hb_tag_t script_tags[] = { HB_TAG_NONE,
120#ifdef FT_DEBUG_LEVEL_TRACE
125 if ( !globals || !style_class || !gstyles )
126 return FT_THROW( Invalid_Argument );
128 face = hb( font_get_face )( globals->hb_font );
130 coverage_tags = coverages[style_class->coverage];
131 script = af_hb_scripts[style_class->script];
137 unsigned int tags_count = 3;
141 hb( ot_tags_from_script_and_language )( script,
147 script_tags[0] = tags_count > 0 ? tags[0] : HB_TAG_NONE;
148 script_tags[1] = tags_count > 1 ? tags[1] : HB_TAG_NONE;
149 script_tags[2] = tags_count > 2 ? tags[2] : HB_TAG_NONE;
154 if ( default_script )
156 if ( script_tags[0] == HB_TAG_NONE )
157 script_tags[0] = HB_OT_TAG_DEFAULT_SCRIPT;
160 if ( script_tags[1] == HB_TAG_NONE )
161 script_tags[1] = HB_OT_TAG_DEFAULT_SCRIPT;
162 else if ( script_tags[1] != HB_OT_TAG_DEFAULT_SCRIPT )
163 script_tags[2] = HB_OT_TAG_DEFAULT_SCRIPT;
170 if ( script_tags[0] == HB_OT_TAG_DEFAULT_SCRIPT )
174 gsub_lookups = hb( set_create )();
175 hb( ot_layout_collect_lookups )( face,
182 if ( hb( set_is_empty )( gsub_lookups ) )
185 FT_TRACE4((
"GSUB lookups (style `%s'):\n",
186 af_style_names[style_class->style] ));
189#ifdef FT_DEBUG_LEVEL_TRACE
193 gsub_glyphs = hb( set_create )();
194 for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_lookups, &idx ); )
196#ifdef FT_DEBUG_LEVEL_TRACE
197 FT_TRACE4((
" %u", idx ));
202 hb( ot_layout_lookup_collect_glyphs )( face,
211#ifdef FT_DEBUG_LEVEL_TRACE
213 FT_TRACE4((
" (none)" ));
218 FT_TRACE4((
"GPOS lookups (style `%s'):\n",
219 af_style_names[style_class->style] ));
222 gpos_lookups = hb( set_create )();
223 hb( ot_layout_collect_lookups )( face,
230#ifdef FT_DEBUG_LEVEL_TRACE
234 gpos_glyphs = hb( set_create )();
235 for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gpos_lookups, &idx ); )
237#ifdef FT_DEBUG_LEVEL_TRACE
238 FT_TRACE4((
" %u", idx ));
243 hb( ot_layout_lookup_collect_glyphs )( face,
252#ifdef FT_DEBUG_LEVEL_TRACE
254 FT_TRACE4((
" (none)" ));
265 if ( style_class->coverage != AF_COVERAGE_DEFAULT )
267 AF_Blue_Stringset bss = style_class->blue_stringset;
268 const AF_Blue_StringRec* bs = &af_blue_stringsets[bss];
273 for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
275 const char* p = &af_blue_strings[bs->string];
283 GET_UTF8_CHAR( ch, p );
285 for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_lookups,
288 hb_codepoint_t gidx = FT_Get_Char_Index( globals->face, ch );
291 if ( hb( ot_layout_lookup_would_substitute )( face, idx,
303 FT_TRACE4((
" no blue characters found; style skipped\n" ));
355 if ( style_class->coverage != AF_COVERAGE_DEFAULT )
356 hb( set_subtract )( gsub_glyphs, gpos_glyphs );
358#ifdef FT_DEBUG_LEVEL_TRACE
359 FT_TRACE4((
" glyphs without GPOS data (`*' means already assigned)" ));
363 for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_glyphs, &idx ); )
365#ifdef FT_DEBUG_LEVEL_TRACE
366 if ( !( count % 10 ) )
372 FT_TRACE4((
" %u", idx ));
379 if ( idx >= (hb_codepoint_t)globals->glyph_count )
382 if ( gstyles[idx] == AF_STYLE_UNASSIGNED )
383 gstyles[idx] = (FT_UShort)style_class->style;
384#ifdef FT_DEBUG_LEVEL_TRACE
390#ifdef FT_DEBUG_LEVEL_TRACE
394 FT_TRACE4((
" (none)" ));
401 hb( set_destroy )( gsub_lookups );
402 hb( set_destroy )( gsub_glyphs );
403 hb( set_destroy )( gpos_lookups );
404 hb( set_destroy )( gpos_glyphs );
412#define COVERAGE( name, NAME, description, \
413 tag1, tag2, tag3, tag4 ) \
414 static const hb_feature_t name ## _feature[] = \
417 HB_TAG( tag1, tag2, tag3, tag4 ), \
418 1, 0, (unsigned int)-1 \
428#define COVERAGE( name, NAME, description, \
429 tag1, tag2, tag3, tag4 ) \
442 af_shaper_buf_create_hb( AF_FaceGlobals globals )
444 FT_UNUSED( globals );
446 return (
void*)hb( buffer_create )();
451 af_shaper_buf_destroy_hb( AF_FaceGlobals globals,
454 FT_UNUSED( globals );
456 hb( buffer_destroy )( (hb_buffer_t*)buf );
461 af_shaper_get_cluster_hb(
const char* p,
462 AF_StyleMetrics metrics,
464 unsigned int* count )
466 AF_FaceGlobals globals = metrics->globals;
468 AF_StyleClass style_class;
474 hb_buffer_t* buf = (hb_buffer_t*)buf_;
476 hb_codepoint_t dummy;
478 FT_UNUSED( globals );
481 upem = (FT_Int)metrics->globals->face->units_per_EM;
482 style_class = metrics->style_class;
483 feature = features[style_class->coverage];
485 font = metrics->globals->hb_font;
488 hb( font_set_scale )( font, upem, upem );
495 while ( !( *q ==
' ' || *q ==
'\0' ) )
496 GET_UTF8_CHAR( dummy, q );
497 len = (int)( q - p );
500 hb( buffer_clear_contents )( buf );
501 hb( buffer_add_utf8 )( buf, p, len, 0, len );
504 hb( buffer_guess_segment_properties )( buf );
508 hb( shape )( font, buf, feature, feature ? 1 : 0 );
512 hb_buffer_t* hb_buf = metrics->globals->hb_buf;
517 unsigned int hb_gcount;
525 hb( buffer_clear_contents )( hb_buf );
526 hb( buffer_add_utf8 )( hb_buf, p, len, 0, len );
527 hb( buffer_guess_segment_properties )( hb_buf );
528 hb( shape )( font, hb_buf, NULL, 0 );
530 ginfo = hb( buffer_get_glyph_infos )( buf, &gcount );
531 hb_ginfo = hb( buffer_get_glyph_infos )( hb_buf, &hb_gcount );
533 if ( gcount == hb_gcount )
538 for (i = 0; i < gcount; i++ )
539 if ( ginfo[i].codepoint != hb_ginfo[i].codepoint )
545 hb( buffer_clear_contents )( buf );
550 *count = hb( buffer_get_length )( buf );
552#ifdef FT_DEBUG_LEVEL_TRACE
553 if ( feature && *count > 1 )
554 FT_TRACE1((
"af_shaper_get_cluster:"
555 " input character mapped to multiple glyphs\n" ));
563 af_shaper_get_elem_hb( AF_StyleMetrics metrics,
569 AF_FaceGlobals globals = metrics->globals;
571 hb_buffer_t* buf = (hb_buffer_t*)buf_;
576 FT_UNUSED( globals );
579 ginfo = hb( buffer_get_glyph_infos )( buf, &gcount );
580 gpos = hb( buffer_get_glyph_positions )( buf, &gcount );
586 *advance = gpos[idx].x_advance;
588 *y_offset = gpos[idx].y_offset;
590 return ginfo[idx].codepoint;
598 af_shaper_get_coverage_nohb( AF_FaceGlobals globals,
599 AF_StyleClass style_class,
601 FT_Bool default_script )
603 FT_UNUSED( globals );
604 FT_UNUSED( style_class );
605 FT_UNUSED( gstyles );
606 FT_UNUSED( default_script );
613 af_shaper_buf_create_nohb( AF_FaceGlobals globals )
615 FT_UNUSED( globals );
622 af_shaper_buf_destroy_nohb( AF_FaceGlobals globals,
625 FT_UNUSED( globals );
631 af_shaper_get_cluster_nohb(
const char* p,
632 AF_StyleMetrics metrics,
634 unsigned int* count )
636 FT_Face face = metrics->globals->face;
637 FT_ULong ch, dummy = 0;
638 FT_ULong* buf = (FT_ULong*)buf_;
644 GET_UTF8_CHAR( ch, p );
648 while ( !( *p ==
' ' || *p ==
'\0' ) )
649 GET_UTF8_CHAR( dummy, p );
658 *buf = FT_Get_Char_Index( face, ch );
667 af_shaper_get_elem_nohb( AF_StyleMetrics metrics,
673 FT_Face face = metrics->globals->face;
674 FT_ULong glyph_index = *(FT_ULong*)buf_;
680 FT_Get_Advance( face,
684 FT_LOAD_IGNORE_TRANSFORM,
697 af_shaper_get_coverage( AF_FaceGlobals globals,
698 AF_StyleClass style_class,
700 FT_Bool default_script )
702#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
703 if ( ft_hb_enabled( globals ) )
704 return af_shaper_get_coverage_hb( globals,
710 return af_shaper_get_coverage_nohb( globals,
718 af_shaper_buf_create( AF_FaceGlobals globals )
720#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
721 if ( ft_hb_enabled( globals ) )
722 return af_shaper_buf_create_hb( globals );
725 return af_shaper_buf_create_nohb( globals );
730 af_shaper_buf_destroy( AF_FaceGlobals globals,
733#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
734 if ( ft_hb_enabled( globals ) )
735 af_shaper_buf_destroy_hb( globals, buf );
738 af_shaper_buf_destroy_nohb( globals, buf );
743 af_shaper_get_cluster(
const char* p,
744 AF_StyleMetrics metrics,
746 unsigned int* count )
748#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
749 if ( ft_hb_enabled( metrics->globals ) )
750 return af_shaper_get_cluster_hb( p, metrics, buf_, count );
753 return af_shaper_get_cluster_nohb( p, metrics, buf_, count );
758 af_shaper_get_elem( AF_StyleMetrics metrics,
764#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
765 if ( ft_hb_enabled( metrics->globals ) )
766 return af_shaper_get_elem_hb( metrics,
772 return af_shaper_get_elem_nohb( metrics,