diff --git a/ChangeLog b/ChangeLog index 90364bb62..ec4890fb6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,42 @@ +2015-12-06 Werner Lemberg + + [autofit] Rewrite HarfBuzz interface to support character clusters. + + Scripts like Khmer have blue zones that can't be directly + represented by Unicode characters. Instead, it is necessary to let + HarfBuzz convert character clusters into proper glyph representation + forms, then deriving the blue zone information from the resulting + glyphs. + + * src/autofit/hbshim.c, src/autofit/hbshim.h: Replaced by... + * src/autofit/afshaper.c, src/autofit/afshaper.h: ... these two new + files, providing a new API to access HarfBuzz. + + The new API manages a HarfBuzz buffer with `af_shaper_buf_create' + and `af_shaper_buf_destroy'. The buffer receives a UTF8 encoded + string with function `af_shaper_get_cluster', and the resulting + glyph data (indices, advance widths, vertical offsets) can be + iteratively accessed with function `af_shaper_get_elem'. + + * src/autofit/afcjk.c (af_cjk_metrics_init_widths, + af_cjk_metrics_init_blues, af_cjk_metrics_check_digits): Updated. + + * src/autofit/aflatin.c (af_latin_metrics_init_widths, + af_latin_metrics_init_blues, af_latin_metrics_check_digits): + Updated. + + * include/freetype/internal/fttrace.h: s/afharfbuzz/afshaper/. + + * src/autofit/afglobal.c: s/hbshim.h/afshaper.h/. + (af_face_globals_compute_style_coverage): Updated. + + * src/autofit/afglocal.h: s/hbshim.h/afshaper.h/. + + * src/autofit/autofit.c: s/hbshim.c/afshaper.c/. + + * src/autofit/Jamfile, src/autofit/rules.mk (AUTOF_DRV_SRC): + Updated. + 2015-12-06 Werner Lemberg [autofit] Prepare forthcoming changes. diff --git a/include/freetype/internal/fttrace.h b/include/freetype/internal/fttrace.h index 9d28d214d..2b0bf9d53 100644 --- a/include/freetype/internal/fttrace.h +++ b/include/freetype/internal/fttrace.h @@ -148,7 +148,7 @@ FT_TRACE_DEF( afcjk ) FT_TRACE_DEF( aflatin ) FT_TRACE_DEF( aflatin2 ) FT_TRACE_DEF( afwarp ) -FT_TRACE_DEF( afharfbuzz ) +FT_TRACE_DEF( afshaper ) FT_TRACE_DEF( afglobal ) /* END */ diff --git a/src/autofit/Jamfile b/src/autofit/Jamfile index 5cd0b4610..a7641b417 100644 --- a/src/autofit/Jamfile +++ b/src/autofit/Jamfile @@ -33,8 +33,8 @@ SubDir FT2_TOP src autofit ; afmodule afpic afranges + afshaper afwarp - hbshim ; if $(FT2_AUTOFIT2) diff --git a/src/autofit/afcjk.c b/src/autofit/afcjk.c index 089e66d16..73d75ae92 100644 --- a/src/autofit/afcjk.c +++ b/src/autofit/afcjk.c @@ -88,7 +88,6 @@ { FT_Error error; FT_ULong glyph_index; - FT_Long y_offset; int dim; AF_CJKMetricsRec dummy[1]; AF_Scaler scaler = &dummy->root.scaler; @@ -101,31 +100,56 @@ AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET [style_class->script]; + void* shaper_buf; const char* p; +#ifdef FT_DEBUG_LEVEL_TRACE FT_ULong ch; +#endif - - p = script_class->standard_charstring; + p = script_class->standard_charstring; + shaper_buf = af_shaper_buf_create( face ); /* We check a list of standard characters. The first match wins. */ glyph_index = 0; while ( *p ) { + unsigned int num_idx; + +#ifdef FT_DEBUG_LEVEL_TRACE + const char* p_old; +#endif + + while ( *p == ' ' ) p++; - GET_UTF8_CHAR( ch, p ); +#ifdef FT_DEBUG_LEVEL_TRACE + p_old = p; + GET_UTF8_CHAR( ch, p_old ); +#endif - af_get_char_index( &metrics->root, - ch, - &glyph_index, - &y_offset ); + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) + continue; + + /* otherwise exit loop if we have a result */ + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + NULL, + NULL ); if ( glyph_index ) break; } + af_shaper_buf_destroy( face, shaper_buf ); + + if ( !glyph_index ) + goto Exit; + if ( !glyph_index ) goto Exit; @@ -168,6 +192,12 @@ if ( error ) goto Exit; + /* + * We assume that the glyphs selected for the stem width + * computation are `featureless' enough so that the linking + * algorithm works fine without adjustments of its scoring + * function. + */ af_latin_hints_link_segments( hints, 0, NULL, @@ -266,6 +296,8 @@ AF_Blue_Stringset bss = sc->blue_stringset; const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; + void* shaper_buf; + /* we walk over the blue character strings as specified in the */ /* style's entry in the `af_blue_stringset' array, computing its */ @@ -275,6 +307,8 @@ "==========================\n" "\n" )); + shaper_buf = af_shaper_buf_create( face ); + for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) { const char* p = &af_blue_strings[bs->string]; @@ -313,26 +347,47 @@ while ( *p ) { - FT_ULong ch; FT_ULong glyph_index; - FT_Long y_offset; FT_Pos best_pos; /* same as points.y or points.x, resp. */ FT_Int best_point; FT_Vector* points; + unsigned int num_idx; - GET_UTF8_CHAR( ch, p ); +#ifdef FT_DEBUG_LEVEL_TRACE + const char* p_old; + FT_ULong ch; +#endif + + + while ( *p == ' ' ) + p++; + +#ifdef FT_DEBUG_LEVEL_TRACE + p_old = p; + GET_UTF8_CHAR( ch, p_old ); +#endif /* switch to characters that define flat values */ - if ( ch == '|' ) + if ( *p == '|' ) { fill = 0; FT_TRACE5(( " [reference values]\n" )); + p++; continue; } + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) + continue; + /* load the character in the face -- skip unknown or empty ones */ - af_get_char_index( &metrics->root, ch, &glyph_index, &y_offset ); + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + NULL, + NULL ); if ( glyph_index == 0 ) { FT_TRACE5(( " U+%04lX unavailable\n", ch )); @@ -341,9 +396,9 @@ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); outline = face->glyph->outline; - if ( error || outline.n_points <= 0 ) + if ( error || outline.n_points <= 2 ) { - FT_TRACE5(( " U+%04lX contains no outlines\n", ch )); + FT_TRACE5(( " U+%04lX contains no (usable) outlines\n", ch )); continue; } @@ -422,7 +477,8 @@ fills[num_fills++] = best_pos; else flats[num_flats++] = best_pos; - } + + } /* end while loop */ if ( num_flats == 0 && num_fills == 0 ) { @@ -489,7 +545,10 @@ FT_TRACE5(( " -> reference = %ld\n" " overshoot = %ld\n", *blue_ref, *blue_shoot )); - } + + } /* end for loop */ + + af_shaper_buf_destroy( face, shaper_buf ); FT_TRACE5(( "\n" )); @@ -503,27 +562,36 @@ af_cjk_metrics_check_digits( AF_CJKMetrics metrics, FT_Face face ) { - FT_UInt i; FT_Bool started = 0, same_width = 1; FT_Fixed advance, old_advance = 0; + void* shaper_buf; - /* digit `0' is 0x30 in all supported charmaps */ - for ( i = 0x30; i <= 0x39; i++ ) + /* in all supported charmaps, digits have character codes 0x30-0x39 */ + const char digits[] = "0 1 2 3 4 5 6 7 8 9"; + const char* p; + + + p = digits; + shaper_buf = af_shaper_buf_create( face ); + + while ( *p ) { - FT_ULong glyph_index; - FT_Long y_offset; + FT_ULong glyph_index; + unsigned int num_idx; - af_get_char_index( &metrics->root, i, &glyph_index, &y_offset ); - if ( glyph_index == 0 ) + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) continue; - if ( FT_Get_Advance( face, glyph_index, - FT_LOAD_NO_SCALE | - FT_LOAD_NO_HINTING | - FT_LOAD_IGNORE_TRANSFORM, - &advance ) ) + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + &advance, + NULL ); + if ( !glyph_index ) continue; if ( started ) @@ -541,6 +609,8 @@ } } + af_shaper_buf_destroy( face, shaper_buf ); + metrics->root.digits_have_same_width = same_width; } diff --git a/src/autofit/afglobal.c b/src/autofit/afglobal.c index ecd333eac..207b41cb7 100644 --- a/src/autofit/afglobal.c +++ b/src/autofit/afglobal.c @@ -18,7 +18,7 @@ #include "afglobal.h" #include "afranges.h" -#include "hbshim.h" +#include "afshaper.h" #include FT_INTERNAL_DEBUG_H @@ -240,12 +240,12 @@ else { /* get glyphs not directly addressable by cmap */ - af_get_coverage( globals, style_class, gstyles ); + af_shaper_get_coverage( globals, style_class, gstyles ); } } /* handle the default OpenType features of the default script ... */ - af_get_coverage( globals, AF_STYLE_CLASSES_GET[dflt], gstyles ); + af_shaper_get_coverage( globals, AF_STYLE_CLASSES_GET[dflt], gstyles ); /* ... and the remaining default OpenType features */ for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) @@ -254,7 +254,7 @@ if ( ss != dflt && style_class->coverage == AF_COVERAGE_DEFAULT ) - af_get_coverage( globals, style_class, gstyles ); + af_shaper_get_coverage( globals, style_class, gstyles ); } /* mark ASCII digits */ diff --git a/src/autofit/afglobal.h b/src/autofit/afglobal.h index 0a54a96a9..c1170d4d6 100644 --- a/src/autofit/afglobal.h +++ b/src/autofit/afglobal.h @@ -23,7 +23,7 @@ #include "aftypes.h" #include "afmodule.h" -#include "hbshim.h" +#include "afshaper.h" FT_BEGIN_HEADER diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c index 608959918..495a32a76 100644 --- a/src/autofit/aflatin.c +++ b/src/autofit/aflatin.c @@ -79,7 +79,6 @@ { FT_Error error; FT_ULong glyph_index; - FT_Long y_offset; int dim; AF_LatinMetricsRec dummy[1]; AF_Scaler scaler = &dummy->root.scaler; @@ -92,12 +91,15 @@ AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET [style_class->script]; + void* shaper_buf; const char* p; +#ifdef FT_DEBUG_LEVEL_TRACE FT_ULong ch; +#endif - - p = script_class->standard_charstring; + p = script_class->standard_charstring; + shaper_buf = af_shaper_buf_create( face ); /* * We check a list of standard characters to catch features like @@ -109,19 +111,41 @@ glyph_index = 0; while ( *p ) { + unsigned int num_idx; + +#ifdef FT_DEBUG_LEVEL_TRACE + const char* p_old; +#endif + + while ( *p == ' ' ) p++; - GET_UTF8_CHAR( ch, p ); +#ifdef FT_DEBUG_LEVEL_TRACE + p_old = p; + GET_UTF8_CHAR( ch, p_old ); +#endif - af_get_char_index( &metrics->root, - ch, - &glyph_index, - &y_offset ); + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) + continue; + + /* otherwise exit loop if we have a result */ + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + NULL, + NULL ); if ( glyph_index ) break; } + af_shaper_buf_destroy( face, shaper_buf ); + + if ( !glyph_index ) + goto Exit; + if ( !glyph_index ) goto Exit; @@ -269,6 +293,8 @@ FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em ); + void* shaper_buf; + /* we walk over the blue character strings as specified in the */ /* style's entry in the `af_blue_stringset' array */ @@ -277,6 +303,8 @@ "============================\n" "\n" )); + shaper_buf = af_shaper_buf_create( face ); + for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) { const char* p = &af_blue_strings[bs->string]; @@ -340,24 +368,51 @@ while ( *p ) { - FT_ULong ch; FT_ULong glyph_index; FT_Long y_offset; - FT_Pos best_y; /* same as points.y */ FT_Int best_point, best_contour_first, best_contour_last; FT_Vector* points; - FT_Bool round = 0; + + FT_Pos best_y_extremum; /* same as points.y */ + FT_Bool best_round = 0; unsigned int i, num_idx; +#ifdef FT_DEBUG_LEVEL_TRACE + const char* p_old; + FT_ULong ch; +#endif - GET_UTF8_CHAR( ch, p ); - num_idx = 1; + while ( *p == ' ' ) + p++; + +#ifdef FT_DEBUG_LEVEL_TRACE + p_old = p; + GET_UTF8_CHAR( ch, p_old ); +#endif + + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + + if ( AF_LATIN_IS_TOP_BLUE( bs ) ) + best_y_extremum = FT_INT_MIN; + else + best_y_extremum = FT_INT_MAX; + + /* iterate over all glyph elements of the character cluster */ + /* and get the data of the `biggest' one */ for ( i = 0; i < num_idx; i++ ) { + FT_Pos best_y; + FT_Bool round = 0; + + /* load the character in the face -- skip unknown or empty ones */ - af_get_char_index( &metrics->root, ch, &glyph_index, &y_offset ); + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + i, + NULL, + &y_offset ); if ( glyph_index == 0 ) { FT_TRACE5(( " U+%04lX unavailable\n", ch )); @@ -369,7 +424,13 @@ /* reject glyphs that don't produce any rendering */ if ( error || outline.n_points <= 2 ) { - FT_TRACE5(( " U+%04lX contains no (usable) outlines\n", ch )); +#ifdef FT_DEBUG_LEVEL_TRACE + if ( num_idx == 1 ) + FT_TRACE5(( " U+%04lX contains no (usable) outlines\n", ch )); + else + FT_TRACE5(( " component %d of cluster starting with U+%04lX" + " contains no (usable) outlines\n", i, ch )); +#endif continue; } @@ -394,9 +455,10 @@ last = outline.contours[nn]; - /* Avoid single-point contours since they are never rasterized. */ - /* In some fonts, they correspond to mark attachment points */ - /* that are way outside of the glyph's real outline. */ + /* Avoid single-point contours since they are never */ + /* rasterized. In some fonts, they correspond to mark */ + /* attachment points that are way outside of the glyph's */ + /* real outline. */ if ( last <= first ) continue; @@ -648,8 +710,8 @@ if ( l2r == left2right && d >= length_threshold ) { - /* all constraints are met; update segment after finding */ - /* its end */ + /* all constraints are met; update segment after */ + /* finding its end */ do { if ( last < best_contour_last ) @@ -735,12 +797,31 @@ FT_TRACE5(( " (%s)\n", round ? "round" : "flat" )); } - if ( round ) - rounds[num_rounds++] = best_y; + if ( AF_LATIN_IS_TOP_BLUE( bs ) ) + { + if ( best_y > best_y_extremum ) + { + best_y_extremum = best_y; + best_round = round; + } + } else - flats[num_flats++] = best_y; - } - } + { + if ( best_y < best_y_extremum ) + { + best_y_extremum = best_y; + best_round = round; + } + } + + } /* end for loop */ + + if ( best_round ) + rounds[num_rounds++] = best_y_extremum; + else + flats[num_flats++] = best_y_extremum; + + } /* end while loop */ if ( num_flats == 0 && num_rounds == 0 ) { @@ -820,7 +901,10 @@ FT_TRACE5(( " -> reference = %ld\n" " overshoot = %ld\n", *blue_ref, *blue_shoot )); - } + + } /* end for loop */ + + af_shaper_buf_destroy( face, shaper_buf ); FT_TRACE5(( "\n" )); @@ -834,27 +918,36 @@ af_latin_metrics_check_digits( AF_LatinMetrics metrics, FT_Face face ) { - FT_UInt i; FT_Bool started = 0, same_width = 1; FT_Fixed advance, old_advance = 0; + void* shaper_buf; - /* digit `0' is 0x30 in all supported charmaps */ - for ( i = 0x30; i <= 0x39; i++ ) + /* in all supported charmaps, digits have character codes 0x30-0x39 */ + const char digits[] = "0 1 2 3 4 5 6 7 8 9"; + const char* p; + + + p = digits; + shaper_buf = af_shaper_buf_create( face ); + + while ( *p ) { - FT_ULong glyph_index; - FT_Long y_offset; + FT_ULong glyph_index; + unsigned int num_idx; - af_get_char_index( &metrics->root, i, &glyph_index, &y_offset ); - if ( glyph_index == 0 ) + /* reject input that maps to more than a single glyph */ + p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx ); + if ( num_idx > 1 ) continue; - if ( FT_Get_Advance( face, glyph_index, - FT_LOAD_NO_SCALE | - FT_LOAD_NO_HINTING | - FT_LOAD_IGNORE_TRANSFORM, - &advance ) ) + glyph_index = af_shaper_get_elem( &metrics->root, + shaper_buf, + 0, + &advance, + NULL ); + if ( !glyph_index ) continue; if ( started ) @@ -872,6 +965,8 @@ } } + af_shaper_buf_destroy( face, shaper_buf ); + metrics->root.digits_have_same_width = same_width; } diff --git a/src/autofit/hbshim.c b/src/autofit/afshaper.c similarity index 75% rename from src/autofit/hbshim.c rename to src/autofit/afshaper.c index 7b05823a5..f7c518a3b 100644 --- a/src/autofit/hbshim.c +++ b/src/autofit/afshaper.c @@ -1,6 +1,6 @@ /***************************************************************************/ /* */ -/* hbshim.c */ +/* afshaper.c */ /* */ /* HarfBuzz interface for accessing OpenType features (body). */ /* */ @@ -20,7 +20,7 @@ #include FT_FREETYPE_H #include "afglobal.h" #include "aftypes.h" -#include "hbshim.h" +#include "afshaper.h" #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ @@ -32,7 +32,7 @@ /* messages during execution. */ /* */ #undef FT_COMPONENT -#define FT_COMPONENT trace_afharfbuzz +#define FT_COMPONENT trace_afshaper /* @@ -96,9 +96,9 @@ FT_Error - af_get_coverage( AF_FaceGlobals globals, - AF_StyleClass style_class, - FT_UShort* gstyles ) + af_shaper_get_coverage( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles ) { hb_face_t* face; @@ -418,88 +418,110 @@ }; - FT_Error - af_get_char_index( AF_StyleMetrics metrics, - FT_ULong charcode, - FT_ULong *codepoint, - FT_Long *y_offset ) + void* + af_shaper_buf_create( FT_Face face ) { - AF_StyleClass style_class; + FT_UNUSED( face ); + return (void*)hb_buffer_create(); + } + + + void + af_shaper_buf_destroy( FT_Face face, + void* buf ) + { + FT_UNUSED( face ); + + hb_buffer_destroy( (hb_buffer_t*)buf ); + } + + + const char* + af_shaper_get_cluster( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ) + { + AF_StyleClass style_class; const hb_feature_t* feature; + FT_Int upem; + const char* q; + int len; - FT_ULong in_idx, out_idx; + hb_buffer_t* buf = (hb_buffer_t*)buf_; + hb_font_t* font; + hb_codepoint_t dummy; - if ( !metrics ) - return FT_THROW( Invalid_Argument ); - - in_idx = FT_Get_Char_Index( metrics->globals->face, charcode ); - + upem = (FT_Int)metrics->globals->face->units_per_EM; style_class = metrics->style_class; + feature = features[style_class->coverage]; - feature = features[style_class->coverage]; + font = metrics->globals->hb_font; - if ( feature ) - { - FT_Int upem = (FT_Int)metrics->globals->face->units_per_EM; + /* we shape at a size of units per EM; this means font units */ + hb_font_set_scale( font, upem, upem ); - hb_font_t* font = metrics->globals->hb_font; - hb_buffer_t* buf = hb_buffer_create(); + while ( *p == ' ' ) + p++; - uint32_t c = (uint32_t)charcode; + /* count characters up to next space (or end of buffer) */ + q = p; + while ( !( *q == ' ' || *q == '\0' ) ) + GET_UTF8_CHAR( dummy, q ); + len = (int)( q - p ); - hb_glyph_info_t* ginfo; - hb_glyph_position_t* gpos; - unsigned int gcount; + /* feed character(s) to the HarfBuzz buffer */ + hb_buffer_clear_contents( buf ); + hb_buffer_add_utf8( buf, p, len, 0, len ); + /* we let HarfBuzz guess the script and writing direction */ + hb_buffer_guess_segment_properties( buf ); - /* we shape at a size of units per EM; this means font units */ - hb_font_set_scale( font, upem, upem ); + /* shape buffer, which means conversion from character codes to */ + /* glyph indices, possibly applying a feature */ + hb_shape( font, buf, feature, feature ? 1 : 0 ); - /* XXX: is this sufficient for a single character of any script? */ - hb_buffer_set_direction( buf, HB_DIRECTION_LTR ); - hb_buffer_set_script( buf, scripts[style_class->script] ); - - /* we add one character to `buf' ... */ - hb_buffer_add_utf32( buf, &c, 1, 0, 1 ); - - /* ... and apply one feature */ - hb_shape( font, buf, feature, 1 ); - - ginfo = hb_buffer_get_glyph_infos( buf, &gcount ); - gpos = hb_buffer_get_glyph_positions( buf, &gcount ); - - out_idx = ginfo[0].codepoint; - - /* getting the same index indicates no substitution, */ - /* which means that the glyph isn't available in the feature */ - if ( in_idx == out_idx ) - { - *codepoint = 0; - *y_offset = 0; - } - else - { - *codepoint = out_idx; - *y_offset = gpos[0].y_offset; - } - - hb_buffer_destroy( buf ); + *count = hb_buffer_get_length( buf ); #ifdef FT_DEBUG_LEVEL_TRACE - if ( gcount > 1 ) + if ( feature && *count > 1 ) FT_TRACE1(( "af_get_char_index:" " input character mapped to multiple glyphs\n" )); #endif - } - else - { - *codepoint = in_idx; - *y_offset = 0; - } - return FT_Err_Ok; + return q; + } + + + FT_ULong + af_shaper_get_elem( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* advance, + FT_Long* y_offset ) + { + hb_buffer_t* buf = (hb_buffer_t*)buf_; + hb_glyph_info_t* ginfo; + hb_glyph_position_t* gpos; + unsigned int gcount; + + FT_UNUSED( metrics ); + + + ginfo = hb_buffer_get_glyph_infos( buf, &gcount ); + gpos = hb_buffer_get_glyph_positions( buf, &gcount ); + + if ( idx >= gcount ) + return 0; + + if ( advance ) + *advance = gpos[idx].x_advance; + if ( y_offset ) + *y_offset = gpos[idx].y_offset; + + return ginfo[idx].codepoint; } @@ -507,9 +529,9 @@ FT_Error - af_get_coverage( AF_FaceGlobals globals, - AF_StyleClass style_class, - FT_UShort* gstyles ) + af_shaper_get_coverage( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles ) { FT_UNUSED( globals ); FT_UNUSED( style_class ); @@ -519,24 +541,91 @@ } - FT_Error - af_get_char_index( AF_StyleMetrics metrics, - FT_ULong charcode, - FT_ULong *codepoint, - FT_Long *y_offset ) + void* + af_shaper_buf_create( FT_Face face ) { - FT_Face face; + FT_Memory memory = face->memory; + FT_ULong* buf; - if ( !metrics ) - return FT_THROW( Invalid_Argument ); + FT_ALLOC( buf, sizeof ( FT_ULong ) ); - face = metrics->globals->face; + return (void*)buf; + } - *codepoint = FT_Get_Char_Index( face, charcode ); - *y_offset = 0; - return FT_Err_Ok; + void + af_shaper_buf_destroy( FT_Face face, + void* buf ) + { + FT_Memory memory = face->memory; + + + FT_FREE( buf ); + } + + + const char* + af_shaper_get_cluster( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ) + { + FT_Face face = metrics->globals->face; + FT_ULong ch, dummy = 0; + FT_ULong* buf = (FT_ULong*)buf_; + + + while ( *p == ' ' ) + p++; + + GET_UTF8_CHAR( ch, p ); + + /* since we don't have an engine to handle clusters, */ + /* we scan the characters but return zero */ + while ( !( *p == ' ' || *p == '\0' ) ) + GET_UTF8_CHAR( dummy, p ); + + if ( dummy ) + { + *buf = 0; + *count = 0; + } + else + { + *buf = FT_Get_Char_Index( face, ch ); + *count = 1; + } + + return p; + } + + + FT_ULong + af_shaper_get_elem( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* advance, + FT_Long* y_offset ) + { + FT_Face face = metrics->globals->face; + FT_ULong glyph_index = *(FT_ULong*)buf_; + + FT_UNUSED( idx ); + + + if ( advance ) + FT_Get_Advance( face, + glyph_index, + FT_LOAD_NO_SCALE | + FT_LOAD_NO_HINTING | + FT_LOAD_IGNORE_TRANSFORM, + advance ) ) + + if ( y_offset ) + *y_offset = 0; + + return glyph_index; } diff --git a/src/autofit/hbshim.h b/src/autofit/afshaper.h similarity index 61% rename from src/autofit/hbshim.h rename to src/autofit/afshaper.h index 3824941ca..db1b4e03e 100644 --- a/src/autofit/hbshim.h +++ b/src/autofit/afshaper.h @@ -1,6 +1,6 @@ /***************************************************************************/ /* */ -/* hbshim.h */ +/* afshaper.h */ /* */ /* HarfBuzz interface for accessing OpenType features (specification). */ /* */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __HBSHIM_H__ -#define __HBSHIM_H__ +#ifndef __AFSHAPER_H__ +#define __AFSHAPER_H__ #include @@ -36,21 +36,36 @@ FT_BEGIN_HEADER FT_Error - af_get_coverage( AF_FaceGlobals globals, - AF_StyleClass style_class, - FT_UShort* gstyles ); + af_shaper_get_coverage( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles ); - FT_Error - af_get_char_index( AF_StyleMetrics metrics, - FT_ULong charcode, - FT_ULong *codepoint, - FT_Long *y_offset ); + + void* + af_shaper_buf_create( FT_Face face ); + + void + af_shaper_buf_destroy( FT_Face face, + void* buf ); + + const char* + af_shaper_get_cluster( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ); + + FT_ULong + af_shaper_get_elem( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* x_advance, + FT_Long* y_offset ); /* */ FT_END_HEADER -#endif /* __HBSHIM_H__ */ +#endif /* __AFSHAPER_H__ */ /* END */ diff --git a/src/autofit/autofit.c b/src/autofit/autofit.c index b6ed4a0ff..a971a2476 100644 --- a/src/autofit/autofit.c +++ b/src/autofit/autofit.c @@ -34,7 +34,7 @@ #include "afcjk.c" #include "afindic.c" -#include "hbshim.c" +#include "afshaper.c" #include "afloader.c" #include "afmodule.c" diff --git a/src/autofit/rules.mk b/src/autofit/rules.mk index 6ef959f1b..57a24bd74 100644 --- a/src/autofit/rules.mk +++ b/src/autofit/rules.mk @@ -40,8 +40,8 @@ AUTOF_DRV_SRC := $(AUTOF_DIR)/afangles.c \ $(AUTOF_DIR)/afmodule.c \ $(AUTOF_DIR)/afpic.c \ $(AUTOF_DIR)/afranges.c \ - $(AUTOF_DIR)/afwarp.c \ - $(AUTOF_DIR)/hbshim.c + $(AUTOF_DIR)/afshaper.c \ + $(AUTOF_DIR)/afwarp.c # AUTOF driver headers #