diff --git a/src/harfbuzz-gsub.c b/src/harfbuzz-gsub.c index 21fec51..996d86d 100644 --- a/src/harfbuzz-gsub.c +++ b/src/harfbuzz-gsub.c @@ -4277,6 +4277,13 @@ HB_Error HB_GSUB_Register_Alternate_Function( HB_GSUBHeader* gsub, return HB_Err_Ok; } +static int _hb_lookup_compare(const void * a, const void * b) +{ + if (*((HB_Short*)a) < *((HB_Short*)b)) return -1; + if (*((HB_Short*)a) > *((HB_Short*)b)) return 1; + return 0; +} + /* returns error if one happened, otherwise returns HB_Err_Not_Covered if no * feature were applied, or HB_Err_Ok otherwise. */ @@ -4285,6 +4292,8 @@ HB_Error HB_GSUB_Apply_String( HB_GSUBHeader* gsub, { HB_Error error, retError = HB_Err_Not_Covered; int i, j, lookup_count, num_features; + size_t active_lookups; + HB_UShort * lookup_indices = NULL; if ( !gsub || !buffer) @@ -4295,31 +4304,73 @@ HB_Error HB_GSUB_Apply_String( HB_GSUBHeader* gsub, lookup_count = gsub->LookupList.LookupCount; num_features = gsub->FeatureList.ApplyCount; - - for ( i = 0; i < num_features; i++) + /* the liga,clig features should be applied in lookup order, not feature by feature */ + if ((num_features < 2 || num_features > 3) || + (num_features == 2 && + !((gsub->FeatureList.FeatureRecord[gsub->FeatureList.ApplyOrder[0]].FeatureTag == HB_MAKE_TAG('l', 'i', 'g', 'a')) && + (gsub->FeatureList.FeatureRecord[gsub->FeatureList.ApplyOrder[1]].FeatureTag == HB_MAKE_TAG('c', 'l', 'i', 'g')))) || + (num_features == 3 && + !((gsub->FeatureList.FeatureRecord[gsub->FeatureList.ApplyOrder[0]].FeatureTag == HB_MAKE_TAG('c', 'c', 'm', 'p')) && + (gsub->FeatureList.FeatureRecord[gsub->FeatureList.ApplyOrder[1]].FeatureTag == HB_MAKE_TAG('l', 'i', 'g', 'a')) && + (gsub->FeatureList.FeatureRecord[gsub->FeatureList.ApplyOrder[2]].FeatureTag == HB_MAKE_TAG('c', 'l', 'i', 'g'))))) { - HB_UShort feature_index = gsub->FeatureList.ApplyOrder[i]; - HB_Feature feature = gsub->FeatureList.FeatureRecord[feature_index].Feature; - - for ( j = 0; j < feature.LookupListCount; j++ ) + for ( i = 0; i < num_features; i++) { - HB_UShort lookup_index = feature.LookupListIndex[j]; + HB_UShort feature_index = gsub->FeatureList.ApplyOrder[i]; + HB_Feature feature = gsub->FeatureList.FeatureRecord[feature_index].Feature; - /* Skip nonexistant lookups */ - if (lookup_index >= lookup_count) - continue; + for ( j = 0; j < feature.LookupListCount; j++ ) + { + HB_UShort lookup_index = feature.LookupListIndex[j]; - error = GSUB_Do_String_Lookup( gsub, lookup_index, buffer ); - if ( error ) - { - if ( error != HB_Err_Not_Covered ) - return error; - } - else - retError = error; + /* Skip nonexistant lookups */ + if (lookup_index >= lookup_count) + continue; + + error = GSUB_Do_String_Lookup( gsub, lookup_index, buffer ); + if ( error ) + { + if ( error != HB_Err_Not_Covered ) + return error; + } + else + retError = error; + } + } + } + else // apply all applied lookups in lookup order ignoreing feature order + { + if (ALLOC_ARRAY(lookup_indices, lookup_count, HB_UShort)) + return error; + active_lookups = 0; + for ( i = 0; i < num_features; i++) + { + HB_UShort feature_index = gsub->FeatureList.ApplyOrder[i]; + HB_Feature feature = gsub->FeatureList.FeatureRecord[feature_index].Feature; + + for ( j = 0; j < feature.LookupListCount; j++ ) + { + HB_UShort lookup_index = feature.LookupListIndex[j]; + + /* Skip nonexistant lookups */ + if (lookup_index >= lookup_count) + continue; + lookup_indices[active_lookups++] = lookup_index; + } + } + qsort(lookup_indices, active_lookups, sizeof(HB_UShort), _hb_lookup_compare); + for (i = 0; i < active_lookups; i++) + { + error = GSUB_Do_String_Lookup( gsub, lookup_indices[i], buffer ); + if ( error ) + { + if ( error != HB_Err_Not_Covered ) + return error; + } + else + retError = error; } } - error = retError; return error;