diff options
Diffstat (limited to 'src/otlayout/ot-ruleset.c')
-rw-r--r-- | src/otlayout/ot-ruleset.c | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/src/otlayout/ot-ruleset.c b/src/otlayout/ot-ruleset.c new file mode 100644 index 000000000..97dd8b75d --- /dev/null +++ b/src/otlayout/ot-ruleset.c @@ -0,0 +1,312 @@ +/* + * ot-ruleset.c: Shaping using OpenType features + * + * Copyright (C) 2000 Red Hat Software + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ot-ruleset.h" +#include "ot-info.h" + +#define noRULESET_DEBUG_MEMORY + +#include FT_INTERNAL_MEMORY_H /* For FT_Free() */ + +#define OT_SCALE_26_6 (OT_SCALE / (1<<6)) +#define OT_UNITS_26_6(d) (OT_SCALE_26_6 * (d)) + +typedef struct _OTRule OTRule; + +struct _OTRule { + FT_ULong property_bit; + FT_UShort feature_index; + FT_UInt table_type : 1; +}; + +OTRuleset * +ot_ruleset_new (OTInfo *info) +{ + OTRuleset *ruleset; + + ruleset = malloc (sizeof (OTRuleset)); + + ot_ruleset_setup (ruleset, info); + + return ruleset; +} + +OTRuleset * +ot_ruleset_delete (OTRuleset *ruleset) +{ + if (ruleset) { + ot_ruleset_release (ruleset); + free (ruleset); + } + + return NULL; +} + +#ifdef RULESET_DEBUG_MEMORY +static ot_ruleset_count = 0; +#endif + +OTRuleset * +ot_ruleset_setup (OTRuleset *ruleset, OTInfo *info) +{ + FT_Memory memory = FT_FACE_MEMORY( info->face ); + FT_ASSERT (ruleset != NULL); + +#ifdef RULESET_DEBUG_MEMORY + ot_ruleset_count++; + FT_Message("ot_ruleset_setup: %d\n", ot_ruleset_count); +#endif + ruleset->info = info; + + ruleset->rules = OT_Array_New ( sizeof (OTRule), memory ); + + return ruleset; +} + +OTRuleset * +ot_ruleset_release (OTRuleset *ruleset) +{ +#ifdef RULESET_DEBUG_MEMORY + ot_ruleset_count--; + FT_Message("ot_ruleset_release: %d\n", ot_ruleset_count); +#endif + if (ruleset->rules) { + OT_Array_Free ( ruleset->rules ); + ruleset->rules = NULL; + } + + if (ruleset->info) { + ruleset->info = NULL; + } + + return NULL; +} + +void +ot_ruleset_copy ( OTRuleset * from, OTRuleset * to ) +{ + OTArray *from_array; + OTArray *to_array; + FT_UInt from_length; + FT_UInt i; + + to->info = from->info; + from_array = from->rules; + from_length = from_array->length; + to_array = to->rules; + OT_Array_Set_Size( to_array, from_length ); + for ( i = 0; i < from_length; i++ ) + OT_Array_Index(to_array, OTRule, i) = OT_Array_Index(from_array, OTRule, i); +} + +/** + * ot_ruleset_add_feature: + * @ruleset: a #OTRuleset. + * @table_type: the table type to add a feature to. + * @feature_index: the index of the feature to add. + * @property_bit: the property bit to use for this feature. + * + * Adds a feature to the ruleset. See ot_ruleset_shape() + * for an explanation of @property_bit. + **/ +void +ot_ruleset_add_feature (OTRuleset *ruleset, OTTableType table_type, FT_UInt feature_index, FT_ULong property_bit) +{ + OTRule tmp_rule; + + FT_ASSERT (ruleset != NULL); + + tmp_rule.table_type = table_type; + tmp_rule.feature_index = feature_index; + tmp_rule.property_bit = property_bit; + + OT_Array_Append_Val (ruleset->rules, &tmp_rule); +} + +/** + * ot_ruleset_shape: + * @ruleset: a #OTRuleset. + * @glyphs: a pointer to a #OTGlyphString. + * + * Shapes a string of glyphs with the given properties according to @ruleset. + **/ +OTGlyphString * +ot_ruleset_shape ( OTRuleset *ruleset, OTGlyphString *glyphs ) +{ + FT_Error error; + int i; + int last_cluster; + int result; + + TTO_GSUB gsub = NULL; + TTO_GPOS gpos = NULL; + + TTO_GSUB_String *in_string = NULL; + TTO_GSUB_String *out_string = NULL; + TTO_GSUB_String *result_string = NULL; + + FT_Bool need_gsub = 0; + FT_Bool need_gpos = 0; + + FT_ASSERT (ruleset != NULL); + + for (i = 0; i < ruleset->rules->length; i++) + { + OTRule *rule = &OT_Array_Index (ruleset->rules, OTRule, i); + + if (rule->table_type == OT_TABLE_GSUB) + need_gsub = 1; + else + need_gpos = 1; + } + + if (need_gsub) + { + gsub = ot_info_get_gsub (ruleset->info); + + if (gsub) + TT_GSUB_Clear_Features (gsub); + } + + if (need_gpos) + { + gpos = ot_info_get_gpos (ruleset->info); + + if (gpos) + TT_GPOS_Clear_Features (gpos); + } + + for (i = 0; i < ruleset->rules->length; i++) + { + OTRule *rule = &OT_Array_Index (ruleset->rules, OTRule, i); + + if (rule->table_type == OT_TABLE_GSUB) + { + if (gsub) + TT_GSUB_Add_Feature (gsub, rule->feature_index, rule->property_bit); + } + else + { + if (gpos) + TT_GPOS_Add_Feature (gpos, rule->feature_index, rule->property_bit); + } + } + + if (!gsub && !gpos) + return glyphs; + + result = TT_GSUB_String_New (ruleset->info->face->memory, &in_string); + FT_ASSERT (result == FT_Err_Ok); + + result = TT_GSUB_String_Set_Length (in_string, glyphs->length); + FT_ASSERT (result == FT_Err_Ok); + + for (i = 0; i < glyphs->length; i++) + { + in_string->string[i] = glyphs->glyphs[i].gid; + in_string->properties[i] = glyphs->glyphs[i].ot_prop; +#if 0 + in_string->logClusters[i] = glyphs->log_clusters[i]; +#endif + } + in_string->max_ligID = i; + + if (gsub) + { + result = TT_GSUB_String_New (ruleset->info->face->memory, + &out_string); + FT_ASSERT (result == FT_Err_Ok); + result_string = out_string; + + TT_GSUB_Apply_String (gsub, in_string, out_string); + } + else + result_string = in_string; + +#if 0 /* TODO: implement this using nr-glyphs */ + if (gpos) + { + TTO_GPOS_Data *outgpos = NULL; + + if (!TT_GPOS_Apply_String (ruleset->info->face, gpos, 0, result_string, &outgpos, + FALSE /* enable device-dependant values */, + FALSE /* Even though this might be r2l text, RTL is handled elsewhere */)) + { + for (i = 0; i < result_string->length; i++) + { + FT_Pos x_pos = outgpos[i].x_pos; + FT_Pos y_pos = outgpos[i].y_pos; + int back = i; + int j; + + while (outgpos[back].back != 0) + { + back -= outgpos[back].back; + x_pos += outgpos[back].x_pos; + y_pos += outgpos[back].y_pos; + } + + for (j = back; j < i; j++) + glyphs->glyphs[i].geometry.x_offset -= glyphs->glyphs[j].geometry.width; + + glyphs->glyphs[i].geometry.x_offset += OT_UNITS_26_6(x_pos); + glyphs->glyphs[i].geometry.y_offset += OT_UNITS_26_6(y_pos); + + if (outgpos[i].new_advance) + glyphs->glyphs[i].geometry.width = OT_UNITS_26_6(outgpos[i].x_advance); + else + glyphs->glyphs[i].geometry.width += OT_UNITS_26_6(outgpos[i].x_advance); + } + + FT_Free(gpos->memory, (void *)outgpos); + } + } +#endif + + if (glyphs->length != result_string->length) + { + if (( error = FTL_Set_Glyphs_Array_Length( glyphs, result_string->length ) )) + return glyphs; + } + + last_cluster = -1; + for (i = 0; i < result_string->length; i++) + { + glyphs->glyphs[i].gid = result_string->string[i]; + /* TODO: Other fields */ +#if 0 /* TODO: */ + glyphs->log_clusters[i] = result_string->logClusters[i]; + if (glyphs->log_clusters[i] != last_cluster) + glyphs->glyphs[i].attr.is_cluster_start = 1; + else + glyphs->glyphs[i].attr.is_cluster_start = 0; + + last_cluster = glyphs->log_clusters[i]; +#endif + } + + if (in_string) + TT_GSUB_String_Done (in_string); + if (out_string) + TT_GSUB_String_Done (out_string); + + return glyphs; +} |