From 18789bfe9f5b350b37fe5e9fbca36393d5dd777a Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 15 Feb 2000 12:53:31 +0000 Subject: [PATCH] Added prototype OpenType Layout support sources. This is not a port of the OTL extension of FT 1.x, as it uses a very different design. These sources are placed here for comments and peer-review --- src/otlayout/oltypes.c | 496 +++++++++++++++++++++++++++++++++++++++++ src/otlayout/oltypes.h | 238 ++++++++++++++++++++ 2 files changed, 734 insertions(+) create mode 100644 src/otlayout/oltypes.c create mode 100644 src/otlayout/oltypes.h diff --git a/src/otlayout/oltypes.c b/src/otlayout/oltypes.c new file mode 100644 index 000000000..19b34a3ab --- /dev/null +++ b/src/otlayout/oltypes.c @@ -0,0 +1,496 @@ +#include + + LOCAL_FUNC + TT_Error OTL_Table_Init( OTL_Table* table, + FT_Memory memory ) + { + MEM_Set( table, 0, sizeof(*table) ); + table->memory = memory; + } + + /* read a script list table */ + /* use with any table */ + LOCAL_FUNC + TT_Error OTL_Table_Set_Scripts( OTL_Table* table, + TT_Byte* bytes, + TT_Long len, + OTL_Type otl_type ) + { + TT_Byte* p; + TT_Byte* start = bytes; + TT_UInt count, max_langs; + TT_Error error; + + /* skip version of the JSTF table */ + if (otl_type == otl_jstf) + start += 4; + + p = start; + + /* we must allocate the script_tags and language_tags arrays */ + /* this requires that we compute the maximum number of languages */ + /* per script.. */ + + count = table->num_scripts = OTL_UShort(p); + max_langs = 0; + for ( ; count > 0; count++ ) + { + TT_Byte* script; + TT_UInt num_langs; + + p += 4; /* skip tag */ + script = bytes + OTL_UShort(p); + + /* skip the baseValues or extenders field of the BASE and JSTF table */ + if (otl_type == otl_type_base || otl_type == otl_type_jstf) + script += 2; + + /* test if there is a default language system */ + if ( OTL_UShort(script) ) + num_langs++; + + /* test other language systems */ + num_langs += OTL_UShort(script); /* add other lang sys */ + + if (num_langs > max_langs) + max_langs = num_langs; + } + + /* good, now allocate the tag arrays */ + if ( !ALLOC_ARRAY( table->script_tags, + table->num_scripts + max_langs, + TT_ULong ) ) + { + table->language_tags = table->script_tags + table->num_scripts; + table->max_languages = max_langs; + table->num_languages = 0; + table->otl_type = otl_type; + + table->scripts_table = bytes; + table->scripts_len = len; + + /* fill the script_tags array */ + { + TT_UInt n; + TT_Byte* p = start + 2; /* skip count */ + + for ( n = 0; n < table->num_scripts; n++ ) + { + table->script_tags[n] = OTL_ULong(p); + p += 2; /* skip offset */ + } + } + } + return error; + } + + + + /* add a features list to the table */ + /* use only with a GSUB or GPOS table */ + LOCAL_FUNC + TT_Error OTL_Table_Set_Features( OTL_Table* table, + TT_Byte* bytes, + TT_Long len ) + { + TT_Error error; + TT_Byte* p = bytes; + TT_UInt count; + + table->max_features = count = OTL_UShort(p); + if ( !ALLOC_ARRAY( table->feature_tags, count, TT_ULong ) && + !ALLOC_ARRAY( table->features, count, TT_Bool ) ) + { + table->features_table = bytes; + table->features_len = len; + } + return error; + } + + + /* add a lookup list to the table */ + /* use only with a GSUB or GPOS table */ + LOCAL_FUNC + TT_Error OTL_Table_Set_Lookups( OTL_Table* table, + TT_Byte* bytes, + TT_Long len ) + { + TT_Error error; + TT_Byte* p = bytes; + TT_UInt count; + + table->max_lookups = count = OTL_UShort(p); + if ( !ALLOC_ARRAY( table->lookups, count, TT_Bool ) ) + { + table->lookups_table = bytes; + table->lookups_len = len; + } + return error; + } + + /* discard table arrays */ + LOCAL_FUNC + void OTL_Table_Done( OTL_Table* table ) + { + FREE( table->scrip_tags ); + FREE( table->language_tags ); + FREE( table->feature_tags ); + FREE( table->lookups ); + } + + + /* return the list of available languages for a given script */ + /* use with any table.. */ + LOCAL_FUNC + void OTL_Get_Languages_List( OTL_Table* table, + TT_ULong script_tag ) + { + TT_UInt n; + TT_Byte* p; + TT_Byte* script = 0; + TT_Byte* start = table->scripts_table; + + if ( table->otl_type == otl_type_jstf ) /* skip version for JSTF */ + start += 4; + + p = start + 6; /* skip count+first tag */ + + for ( n = 0; n < table->num_scripts; n++, p += 6 ) + { + if ( table->script_tags[n] == script_tag ) + { + script = table->scripts_table + OTL_UShort(p); + break; + } + } + + table->cur_script = script; + if (!script) + table->num_languages = 0; + else + { + /* now fill the language_tags array with the appropriate values */ + /* not that we put a '0' tag in front of the list to indicate that */ + /* there is a default language for this script.. */ + TT_ULong* tags = table->language_tags; + + switch (table->otl_type) + { + case otl_type_base: + case otl_type_jstf: + script += 2; /* skip basevalue or extenders */ + /* fall-through */ + + default: + if ( OTL_UShort(script) ) + *tags++ = 0; + } + + count = OTL_UShort(script); + for ( ; count > 0; count-- ) + { + *tags++ = OTL_ULong(script); + script += 2; /* skip offset */ + } + + table->num_langs = tags - table->language_tags; + } + } + + + /* return the list of available features for the current script/language */ + /* use with a GPOS or GSUB script table */ + LOCAL_FUNC + void OTL_Get_Features_List( OTL_Table* table, + TT_ULong language_tag ) + { + TT_UInt n; + TT_Byte* script = table->cur_script; + TT_Byte* language = 0; + TT_UShort offset; + + /* clear feature selection table */ + for ( n = 0; n < table->max_features; n++ ) + table->features[n] = 0; + + /* now, look for the current language */ + if ( language_tag == 0 ) + { + offset = OTL_UShort(script); + if (!offset) return; /* if there is no default language, exit */ + + language = script - 2 + offset; + } + else + { + TT_Byte* p = script + 8; /* skip default+count+1st tag */ + TT_UShort index; + + for ( n = 0; n < table->num_languages; n++, p+=6 ) + { + if ( table->language_tags[n] == language_tag ) + { + language = script + OTL_UShort(p); + break; + } + } + + table->cur_language = language; + if (!language) return; + + p = language + 2; /* skip lookup order */ + index = OTL_UShort(p); /* required feature index */ + if (index != 0xFFFF) + { + if (index < table->max_features) + table->features[index] = 1; + } + + count = OTL_UShort(p); + for ( ; count > 0; count-- ) + { + index = OTL_UShort(p); + if (index < table->max_features) + table->features[index] = 1; + } + } + } + + + /* return the list of lookups for the current features list */ + /* use only with a GSUB or GPOS table */ + LOCAL_FUNC + void OTL_Get_Lookups_List( OTL_Table* table ) + { + TT_UInt n; + TT_Byte* features = table->features_table; + TT_Byte* p = features + 6; /* skip count+1st tag */ + + /* clear lookup list */ + for ( n = 0; n < table->max_lookups; n++ ) + table->lookups[n] = 0; + + /* now, parse the features list */ + for ( n = 0; n < table->features; n++ ) + { + if (table->features[n]) + { + TT_UInt count; + TT_UShort index; + TT_Byte* feature; + + feature = features + OTL_UShort(p); + p += 4; /* skip tag */ + + /* now, select all lookups from this feature */ + count = OTL_UShort(feature); + for ( ; count > 0; count-- ) + { + index = OTL_UShort(feature); + if (index < table->max_lookups) + table->lookups[index] = 1; + } + } + } + } + + + /* find the basevalues and minmax for the current script/language */ + /* only use it with a BASE table.. */ + LOCAL_FUNC + void OTL_Get_Baseline_Values( OTL_Table* table, + TT_ULong language_tag ) + { + TT_Byte* script = table->cur_script; + TT_Byte* p = script; + TT_UShort offset, count; + + table->cur_basevalues = 0; + table->cur_minmax = 0; + + /* read basevalues */ + offset = OTL_UShort(p); + if (offset) + table->cur_basevalues = script + offset; + + offset = OTL_UShort(p); + if (offset) + table->cur_minmax = script + offset; + + count = OTL_UShort(p); + for ( ; count > 0; count-- ) + { + TT_ULong tag; + + tag = OTL_ULong(p); + if ( language_tag == tag ) + { + table->cur_minmax = script + OTL_UShort(p); + break; + } + p += 2; /* skip offset */ + } + } + + + /* compute the coverage value of a given glyph id */ + LOCAL_FUNC + TT_Long OTL_Get_Coverage_Index( TT_Byte* coverage, + TT_UInt glyph_id ) + { + TT_Long result = -1; + TT_UInt count, index, start, end; + TT_Byte* p = coverage; + + switch ( OTL_UShort(p) ) + { + case 1: /* coverage format 1 - array of glyph indices */ + { + count = OTL_UShort(p); + for ( index = 0; index < count; index++ ) + { + if ( OTL_UShort(p) == glyph_id ) + { + result = index; + break; + } + } + } + break; + + case 2: + { + count = OTL_UShort(p); + for ( ; count > 0; count-- ) + { + start = OTL_UShort(p); + end = OTL_UShort(p); + index = OTL_UShort(p); + if (start <= glyph_id && glyph_id <= end) + { + result = glyph_id - start + index; + break; + } + } + } + break; + } + return result; + } + + + /* compute the class value of a given glyph_id */ + LOCAL_FUNC + TT_UInt OTL_Get_Glyph_Class( TT_Byte* class_def, + TT_UInt glyph_id ) + { + TT_Byte* p = class_def; + TT_UInt result = 0; + TT_UInt start, end, count, index; + + switch ( OTL_UShort(p) ) + { + case 1: + { + start = OTL_UShort(p); + count = OTL_UShort(p); + + glyph_id -= start; + if (glyph_id < count) + { + p += 2*glyph_id; + result = OTL_UShort(p); + } + } + break; + + case 2: + { + count = OTL_UShort(p); + for ( ; count > 0; count-- ) + { + start = OTL_UShort(p); + end = OTL_UShort(p); + index = OTL_UShort(p); + if ( start <= glyph_id && glyph_id <= end ) + { + result = index; + break; + } + } + } + break; + } + return result; + } + + + /* compute the adjustement necessary for a given device size */ + LOCAL_FUNC + TT_Int OTL_Get_Device_Adjustment( TT_Byte* device, + TT_UInt size ) + { + TT_Byte* p = device; + TT_Int result = 0; + TT_UInt start, end; + TT_Short value; + + start = OTL_UShort(p); + end = OTL_UShort(p); + if (size >= start && size <= end) + { + /* I know we could do all of this without a switch, with */ + /* clever shifts and everything, but it makes the code */ + /* really difficult to understand.. */ + + size -= start; + switch ( OTL_UShort(p) ) + { + case 1: /* 2-bits per value */ + { + p += 2*(size >> 3); + size = (size & 7) << 1; + value = (TT_Short)((TT_Short)OTL_UShort(p) << size); + result = value >> 14; + } + break; + + case 2: /* 4-bits per value */ + { + p += 2*(size >> 2); + size = (size & 3) << 2; + value = (TT_Short)((TT_Short)OTL_UShort(p) << size); + result = value >> 12; + } + break; + + case 3: /* 8-bits per value */ + { + p += 2*(size >> 1); + size = (size & 1) << 3; + value = (TT_Short)((TT_Short)OTL_UShort(p) << size); + result = value >> 8; + } + break; + } + } + return result; + } + + /* compute a BaseCoord value */ + LOCAL_FUNC + TT_Int OTL_Get_Base_Coordinate( TT_Byte* base_coord, + TT_UShort *format + TT_UShort *ref_glyph_id, + TT_Byte* *device ) + { + TT_Byte* p =base_coord; + TT_Int result = 0; + + *format = OTL_UShort(p); + + switch (*format) + { + case + } + } diff --git a/src/otlayout/oltypes.h b/src/otlayout/oltypes.h new file mode 100644 index 000000000..eb140775a --- /dev/null +++ b/src/otlayout/oltypes.h @@ -0,0 +1,238 @@ +#ifndef OLTYPES_H +#define OLTYPES_H + +#include +#include + + /************************************************************* + * + * OTL_Table + * + * + * The base table of most OpenType Layout sub-tables. + * Provides a simple way to scan a table for script, + * languages, features and lookups.. + * + * + * num_scripts :: number of scripts in table's script list + * script_tags :: array of tags for each table script + * + * max_languages :: max number of languages for any script in + * the table. + * num_languages :: number of languages available for current script + * language_tags :: tags of all languages available for current script. + * + * max_features :: total number of features in table + * feature_tags :: tags of all features for current script/language + * + * max_lookups :: total number of lookups in table + * lookups :: selection flags for all lookups for current + * feature list. + * + ****************************************************************/ + + typedef enum OTL_Type_ + { + otl_type_none = 0, + otl_type_base, + otl_type_gdef, + otl_type_gpos, + otl_type_gsub, + otl_type_jstf + + } OTL_Type; + + + typedef struct OTL_Table_ + { + FT_Memory memory; + + TT_Int num_scripts; + TT_Tag* script_tags; + + TT_Int max_languages; + TT_Int num_languages; + TT_Tag* language_tags; + + TT_Int max_features; + TT_Tag* feature_tags; + TT_Bool* features; + + TT_Int max_lookups; + TT_Bool* lookups; + + TT_Byte* scripts_table; + TT_Long scripts_len; + + TT_Byte* features_table; + TT_Long* features_len; + + TT_Byte* lookups_table; + TT_Byte* lookups_len; + + TT_Byte* cur_script; /* current script */ + TT_Byte* cur_language; /* current language */ + + TT_Byte* cur_base_values; + TT_Byte* cur_min_max; + + OTL_Type otl_type; + + } OTL_Table; + + + LOCAL_DEF + TT_Error OTL_Table_Init( OTL_Table* table, + FT_Memory memory ); + + LOCAL_DEF + TT_Error OTL_Table_Set_Scripts( OTL_Table* table, + TT_Byte* bytes, + TT_Long len, + OTL_Type otl_type ); + + LOCAL_DEF + TT_Error OTL_Table_Set_Features( OTL_Table* table, + TT_Byte* bytes, + TT_Long len ); + + LOCAL_DEF + TT_Error OTL_Table_Set_Lookups( OTL_Table* table, + TT_Byte* bytes, + TT_Long len ); + + LOCAL_DEF + void OTL_Table_Done( OTL_Table* table ); + + + +/***************************************************** + * + * Typical uses: + * + * - after OTL_Table_Set_Scripts have been called : + * + * table->script_tags contains the list of tags of all + * scripts defined for this table. + * + * table->num_scripts is the number of scripts + * + */ + +/******************************************************** + * + * - after calling OTL_Table_Set_Features: + * + * table->max_features is the number of all features + * in the table + * + * table->feature_tags is the list of tags of all + * features in the table + * + * table->features[] is an array of boolean used to + * indicate which feature is active for a given script/language + * it is empty (zero-filled) by default. + * + */ + +/******************************************************************* + * + * - after calling OTL_Get_Languages_List(script_tag): + * + * table->num_languages is the number of language systems + * available for the script, including the default + * langsys if there is one + * + * table->language_tags contains the list of tags of all + * languages for the script. Note that the default langsys + * has tag "0" and is always placed first in "language_tags". + * + * + * + */ + LOCAL_DEF + void OTL_Get_Languages_List( OTL_Table* table, + TT_ULong script_tag ); + + +/******************************************************************* + * + * - after calling OTL_Get_Features_List(language_tag): + * + * table->features[] is an array of booleans used to indicate + * which features are active for the current script/language + * + * note that this function must be called after OTL_Get_Languages + * which remembers the last "script_tag" used.. + * + * A client application can change the table->features[] array + * to add or remove features from the list. + * + * + * + */ + LOCAL_DEF + void OTL_Get_Features_List( OTL_Table* table, + TT_ULong language_tag ); + + LOCAL_DEF + void OTL_Get_Baseline_Values( OTL_Table* table, + TT_ULong language_tag ); + + LOCAL_DEF + void OTL_Get_Justification( OTL_Table* table, + TT_ULong language_tag ); + +/******************************************************************* + * + * - after calling OTL_Get_Lookups_List(): + * + * The function uses the table->features[] array of boolean + * to determine which lookups must be processed. + * + * It fills the table->lookups[] array accordingly. It is also + * an array of booleans (one for each lookup). + * + * + */ + + LOCAL_DEF + void OTL_Get_Lookups_List( OTL_Table* table ); + + +/*************************************************************** + * + * So the whole thing looks like: + * + * + * 1. A client specifies a given script and requests available + * language through OTL_Get_Languages_List() + * + * 2. It selects the language tag it needs, then calls + * OTL_Get_Features_List() + * + * 3. It updates the list of active features if it needs to + * + * 4. It calls OTL_Get_Lookups_List() + * It now has a list of active lookups in "table->lookups[]" + * + * 5. The lookups are processed according to the table's type.. + * + */ + + + + LOCAL_DEF + TT_Long OTL_Get_Coverage_Index( TT_Byte* coverage, + TT_UInt glyph_id ); + + +#define OTL_Byte(p) (p++, p[-1]) + +#define OTL_UShort(p) (p+=2, ((TT_UShort)p[-2] << 8) | p[-1]) + +#define OTL_ULong(p) (p+=4, ((TT_ULong)p[-4] << 24) | \ + ((TT_ULong)p[-3] << 16) | \ + ((TT_ULong)p[-2] << 8 ) | p[-1] ) + +#endif /* OLTYPES_H */