| /***************************************************************************/ |
| /* */ |
| /* otload.c */ |
| /* */ |
| /* OpenType Layout loader (body). */ |
| /* */ |
| /* Copyright 1996-1999 by */ |
| /* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
| /* */ |
| /* This file is part of the FreeType project, and may only be used */ |
| /* modified and distributed under the terms of the FreeType project */ |
| /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
| /* this file you indicate that you have read the license and */ |
| /* understand and accept it fully. */ |
| /* */ |
| /***************************************************************************/ |
| |
| |
| #include <otlayout.h> |
| #include <otload.h> |
| |
| #include <tterrors.h> |
| |
| |
| /*************************** |
| * Script related functions |
| ***************************/ |
| |
| |
| /*************************************************************************/ |
| /* */ |
| /* <Function> */ |
| /* OTL_Free_Script_List */ |
| /* */ |
| /* <Description> */ |
| /* Releases a given OpenType Script list. */ |
| /* */ |
| /* <Input> */ |
| /* list :: The target script list. */ |
| /* system :: The current system object. */ |
| /* */ |
| LOCAL_FUNC |
| void OTL_Free_Script_List( OTL_Script_List* list, |
| FT_System system ) |
| { |
| if ( list ) |
| { |
| if ( list->scripts ) |
| { |
| OTL_Script* script = list->scripts; |
| OTL_Script* script_limit = script + list->num_scripts; |
| |
| |
| for ( ; script < script_limit; script++ ) |
| { |
| if ( script->langsys ) |
| { |
| OTL_LangSys* langsys = script->langsys; |
| OTL_LangSys* langsys_limit = langsys + script->num_langsys; |
| |
| |
| for ( ; langsys < langsys_limit; langsys++ ) |
| { |
| FREE( langsys->feature_indices ); |
| langsys->num_feature_indices = 0; |
| } |
| FREE( script->langsys ); |
| } |
| script->langsys_default = NULL; |
| script->num_langsys = 0; |
| } |
| FREE( list->scripts ); |
| } |
| list->num_scripts = 0; |
| } |
| } |
| |
| |
| static |
| TT_Error Load_OTL_LangSys_List( OTL_Script* script, |
| FT_Stream stream, |
| TT_ULong default_offset ) |
| { |
| FT_System system = stream->system; |
| TT_Error error; |
| |
| TT_UShort n, count; |
| OTL_LangSys* langsys; |
| |
| |
| /* read the langsys tags and offsets */ |
| { |
| count = script->num_langsys; |
| langsys = script->langsys; |
| |
| if ( ACCESS_Frame( 6L * count ) ) |
| goto Exit; |
| |
| for ( n = 0; n < count; n++, langsys++ ) |
| { |
| TT_ULong offset; |
| |
| |
| langsys->lang_tag = GET_ULong(); |
| offset = GET_UShort(); |
| |
| if ( langsys->lang_offset == default_offset ) |
| script->langsys_default = langsys; |
| |
| langsys->lang_offset = offset + script->script_offset; |
| } |
| |
| FORGET_Frame(); |
| } |
| |
| /* now read each langsys record */ |
| { |
| count = script->num_langsys; |
| langsys = script->langsys; |
| |
| for ( n = 0; n < count; n++, langsys++ ) |
| { |
| TT_UShort num_feature_indices, i; |
| |
| |
| if ( FILE_Seek( langsys->lang_offset ) || |
| ACCESS_Frame( 8L ) ) |
| goto Exit; |
| |
| langsys->lookup_order = GET_ULong(); |
| langsys->req_feature_index = GET_UShort(); |
| langsys->num_feature_indices = GET_UShort(); |
| |
| FORGET_Frame(); |
| |
| num_feature_indices = langsys->num_feature_indices; |
| |
| if ( ALLOC_ARRAY ( langsys->feature_indices, |
| num_feature_indices, TT_UShort ) || |
| ACCESS_Frame( num_feature_indices * 2L ) ) |
| goto Exit; |
| |
| for ( i = 0; i < num_feature_indices; i++ ) |
| langsys->feature_indices[i] = GET_UShort(); |
| |
| FORGET_Frame(); |
| } |
| } |
| |
| Exit: |
| return error; |
| } |
| |
| |
| /*************************************************************************/ |
| /* */ |
| /* <Function> */ |
| /* OTL_Load_Script_List */ |
| /* */ |
| /* <Description> */ |
| /* Loads an OpenType Script List from a font resource. */ |
| /* */ |
| /* <Input> */ |
| /* list :: The target script list. */ |
| /* stream :: The input stream. */ |
| /* */ |
| /* <Return> */ |
| /* TrueType error code. 0 means success. */ |
| /* */ |
| LOCAL_FUNC |
| TT_Error OTL_Load_Script_List( OTL_Script_List* list, |
| FT_Stream stream ) |
| { |
| FT_System system = stream->system; |
| TT_Error error; |
| |
| TT_ULong start_pos; |
| TT_UShort num_scripts; |
| OTL_Script* scripts; |
| |
| |
| start_pos = FILE_Pos(); |
| |
| if ( READ_UShort( list->num_scripts ) ) |
| goto Exit; |
| |
| num_scripts = list->num_scripts; |
| |
| /* Allocate the scripts table, read their tags and offsets */ |
| { |
| TT_UShort n; |
| |
| |
| if ( ALLOC_ARRAY( list->scripts, num_scripts, OTL_Script ) || |
| ACCESS_Frame( num_scripts * 6L ) ) |
| goto Exit; |
| |
| scripts = list->scripts; |
| |
| for ( n = 0; n < num_scripts; n++ ) |
| { |
| scripts[n].script_tag = GET_ULong(); |
| scripts[n].script_offset = GET_UShort() + start_pos; |
| } |
| |
| FORGET_Frame(); |
| } |
| |
| /* now read each script in the table */ |
| { |
| TT_UShort n; |
| OTL_Script* script = scripts; |
| |
| |
| for ( n = num_scripts; n > 0; n--, script++ ) |
| { |
| TT_ULong default_langsys_offset; |
| |
| |
| if ( FILE_Seek ( script->script_offset ) || |
| READ_ULong ( default_langsys_offset ) || |
| READ_UShort( script->num_langsys ) || |
| ALLOC_ARRAY( script->langsys, |
| script->num_langsys, OTL_LangSys ) ) |
| goto Exit; |
| |
| /* read the corresponding langsys list */ |
| error = Load_OTL_LangSys_List( |
| script, |
| stream, |
| default_langsys_offset + script->script_offset ); |
| if ( error ) |
| goto Exit; |
| } |
| } |
| |
| Exit: |
| if ( error ) |
| OTL_Free_Script_List( list, system ); |
| |
| return error; |
| } |
| |
| |
| /********************************* |
| * Feature List related functions |
| *********************************/ |
| |
| |
| /*************************************************************************/ |
| /* */ |
| /* <Function> */ |
| /* OTL_Free_Features_List */ |
| /* */ |
| /* <Description> */ |
| /* Releases a given OpenType Features list. */ |
| /* */ |
| /* <Input> */ |
| /* list :: The target feature list. */ |
| /* system :: The current system object. */ |
| /* */ |
| LOCAL_FUNC |
| void OTL_Free_Features_List( OTL_Feature_List* list, |
| FT_System system ) |
| { |
| if ( list ) |
| { |
| if ( list->features ) |
| { |
| OTL_Feature* feature = list->features; |
| OTL_Feature* feature_limit = feature + list->num_features; |
| |
| |
| for ( ; feature < feature_limit; feature++ ) |
| { |
| FREE( feature->lookups ); |
| feature->num_lookups = 0; |
| } |
| |
| FREE( list->features ); |
| } |
| list->num_features = 0; |
| } |
| } |
| |
| |
| /*************************************************************************/ |
| /* */ |
| /* <Function> */ |
| /* OTL_Load_Feature_List */ |
| /* */ |
| /* <Description> */ |
| /* Loads an OpenType Feature List from a font resource. */ |
| /* */ |
| /* <Input> */ |
| /* list :: The target feature list. */ |
| /* stream :: The input stream. */ |
| /* */ |
| /* <Return> */ |
| /* TrueType error code. 0 means success. */ |
| /* */ |
| LOCAL_FUNC |
| TT_Error OTL_Load_Feature_List( OTL_Feature_List* list, |
| FT_Stream stream ) |
| { |
| FT_System system = stream->system; |
| TT_Error error; |
| TT_ULong start_pos; |
| TT_UShort num_features, n; |
| |
| |
| start_pos = FILE_Pos(); |
| |
| if ( READ_UShort( num_features ) ) |
| goto Exit; |
| |
| /* allocate the features array and read their tag and offset */ |
| { |
| OTL_Feature* feature; |
| OTL_Feature* feature_limit; |
| |
| |
| if ( ALLOC_ARRAY ( list->features, num_features, OTL_Feature ) || |
| ACCESS_Frame( num_features * 6L ) ) |
| goto Exit; |
| |
| list->num_features = num_features; |
| feature = list->features; |
| feature_limit = feature + num_features; |
| |
| for ( ; feature < feature_limit; feature++ ) |
| { |
| feature->feature_tag = GET_ULong(); |
| feature->feature_offset = GET_UShort() + start_pos; |
| } |
| |
| FORGET_Frame(); |
| } |
| |
| /* now read each feature */ |
| { |
| OTL_Feature* feature; |
| OTL_Feature* feature_limit; |
| |
| |
| feature = list->features; |
| feature_limit = feature + num_features; |
| |
| for ( ; feature < feature_limit; feature++ ) |
| { |
| TT_UShort num_lookups; |
| TT_UShort* lookup; |
| TT_UShort* lookup_limit; |
| |
| |
| if ( FILE_Seek ( feature->feature_offset ) || |
| READ_ULong ( feature->feature_params ) || |
| READ_UShort ( num_lookups ) || |
| ALLOC_ARRAY ( feature->lookups, |
| num_lookups, TT_UShort ) || |
| ACCESS_Frame( num_lookups * 2L ) ) |
| goto Exit; |
| |
| feature->num_lookups = num_lookups; |
| lookup = feature->lookups; |
| lookup_limit = lookup + num_lookups; |
| |
| for ( ; lookup < lookup_limit; lookup++ ) |
| lookup[0] = GET_UShort(); |
| |
| FORGET_Frame(); |
| } |
| } |
| |
| Exit: |
| if ( error ) |
| OTL_Free_Feature_List( list, system ); |
| |
| return error; |
| } |
| |
| |
| /******************************** |
| * Lookup List related functions |
| ********************************/ |
| |
| |
| /*************************************************************************/ |
| /* */ |
| /* <Function> */ |
| /* OTL_Iterate_Lookup_List */ |
| /* */ |
| /* <Description> */ |
| /* Scans an OpenType Lookup List. This can be used to load the */ |
| /* Lookup sub-tables in a GSUB or GPOS loader. */ |
| /* */ |
| /* <Input> */ |
| /* list :: The source list. */ |
| /* iterator :: The iterator -- a function which is called on each */ |
| /* element of the list. */ |
| /* closure :: User-specified data which is passed to each iterator */ |
| /* with the lookup element pointer. */ |
| /* */ |
| /* <Return> */ |
| /* If one iterator call returns a non-zero `result', the list parsing */ |
| /* is aborted and the value is returned to the caller. Otherwise, */ |
| /* the function returns 0 when the list has been parsed completely. */ |
| /* */ |
| LOCAL_FUNC |
| TT_Error OTL_Iterate_Lookup_List( OTL_Lookup_List* list, |
| OTL_Lookup_Iterator iterator, |
| void* closure ) |
| { |
| int result = 0; |
| |
| |
| if ( list->lookups ) |
| { |
| OTL_Lookup* lookup = list->lookups; |
| OTL_Lookup* limit = lookup + list->num_lookups; |
| |
| |
| for ( ; lookup < limit; lookup++ ) |
| { |
| result = iterator( lookup, closure ); |
| if ( result ) |
| break; |
| } |
| } |
| |
| return 0; |
| } |
| |
| |
| /*************************************************************************/ |
| /* */ |
| /* <Function> */ |
| /* OTL_Free_Lookup_List */ |
| /* */ |
| /* <Description> */ |
| /* Releases a given OpenType Lookup list. Uses a destructor called */ |
| /* to destroy the Lookup sub-tables. */ |
| /* */ |
| /* <Input> */ |
| /* list :: The target lookup list. */ |
| /* system :: The current system object. */ |
| /* destructor :: A destructor function called on each lookup element. */ |
| /* Can be used to destroy sub-tables. Ignored if NULL. */ |
| /* */ |
| LOCAL_FUNC |
| void OTL_Free_Lookup_List( OTL_Lookup_List* list, |
| FT_System system, |
| OTL_Lookup_Destructor destroy ) |
| { |
| if ( list ) |
| { |
| if ( list->lookups ) |
| { |
| OTL_Lookup* lookup = list->lookups; |
| OTL_Lookup* limit = lookup + list->num_lookups; |
| |
| |
| for ( ; lookup < limit; lookup++ ) |
| { |
| if ( destroy ) |
| destroy( lookup, system ); |
| |
| FREE( lookup->subtable_offsets ); |
| lookup->num_subtables = 0; |
| } |
| |
| FREE( list->lookups ); |
| } |
| } |
| } |
| |
| |
| /*************************************************************************/ |
| /* */ |
| /* <Function> */ |
| /* OTL_Load_Lookup_List */ |
| /* */ |
| /* <Description> */ |
| /* Loads an OpenType Lookup List from a font resource. */ |
| /* */ |
| /* <Input> */ |
| /* list :: The target lookup list. */ |
| /* stream :: The input stream. */ |
| /* */ |
| /* <Return> */ |
| /* TrueType error code. 0 means success. */ |
| /* */ |
| /* <Note> */ |
| /* This function does NOT load the lookup sub-tables. Instead, it */ |
| /* stores the file offsets of the particular table in each lookup */ |
| /* element. It is up to the caller to load these sub-tables. This */ |
| /* can be done more easily with OTL_Iterate_Lookup_List(). */ |
| /* */ |
| LOCAL_FUNC |
| TT_Error OTL_Load_Lookup_List( OTL_Lookup_List* list, |
| FT_Stream stream ) |
| { |
| FT_System system = stream->system; |
| TT_Error error; |
| |
| TT_UShort num_lookups; |
| TT_ULong start_pos; |
| |
| |
| start_pos = GET_ULong(); |
| |
| if ( READ_UShort( num_lookups ) ) |
| goto Exit; |
| |
| /* allocate the lookups array and read their tags and offset */ |
| { |
| TT_UShort n; |
| |
| |
| if ( ALLOC_ARRAY ( list->lookups, num_lookups, OTL_Lookup ) || |
| ACCESS_Frame( num_lookups * 2L ) ) |
| goto Exit; |
| |
| list->num_lookups = num_lookups; |
| for ( n = 0; n < num_lookups; n++ ) |
| list->lookups[n].lookup_offset = start_pos + GET_UShort(); |
| |
| FORGET_Frame(); |
| } |
| |
| /* now read each lookup table */ |
| /* NOTE that we don't load the sub-tables here, but simply */ |
| /* store their file offsets in the `subtable_offsets' array */ |
| { |
| OTL_Lookup* lookup = list->lookups; |
| OTL_Lookup* lookup_limit = lookup + num_lookups; |
| |
| |
| for ( ; lookup < lookup_limit; lookup++ ) |
| { |
| TT_UShort n, num_subtables; |
| TT_ULong* offsets; |
| |
| |
| if ( FILE_Seek ( lookup->lookup_offset ) || |
| ACCESS_Frame( 6L ) ) |
| goto Exit; |
| |
| lookup->lookup_type = GET_UShort(); |
| lookup->lookup_flag = GET_UShort(); |
| lookup->num_subtables = GET_UShort(); |
| |
| num_subtables = lookup->num_subtables; |
| |
| FORGET_Frame(); |
| |
| if ( ALLOC_ARRAY ( lookup->subtable_offsets, |
| num_subtables, TT_ULong ) || |
| ACCESS_Frame( num_subtables * 2L ) ) |
| goto Exit; |
| |
| offsets = lookup->subtable_offsets; |
| for ( n = 0; n < num_subtables; n++ ) |
| offsets[n] = lookup->lookup_offset + GET_UShort(); |
| |
| FORGET_Frame(); |
| } |
| } |
| |
| Exit: |
| if ( error ) |
| OTL_Free_Lookup_List( list, system, 0 ); |
| |
| return error; |
| } |
| |
| |
| /* generic sub-table freeing and loading */ |
| |
| static |
| void Free_SubTable( OTL_SubTable* subtable, |
| FT_System system ) |
| { |
| if ( subtable ) |
| { |
| switch ( subtable->format ) |
| { |
| case 1: |
| { |
| OTL_SubTable1* st = &subtable->set.format1; |
| |
| |
| FREE( st->indices ); |
| st->num_indices = 0; |
| FREE( st ); |
| } |
| break; |
| |
| case 2: |
| { |
| OTL_SubTable2* st = &subtable->set.format2; |
| |
| |
| FREE( st->ranges ); |
| st->num_ranges = 0; |
| FREE( st ); |
| } |
| break; |
| |
| default: |
| break; |
| } |
| |
| FREE( subtable ); |
| } |
| } |
| |
| |
| static |
| TT_Error Load_SubTable( OTL_SubTable* subtable, |
| FT_Stream stream ) |
| { |
| FT_System system = stream->system; |
| TT_Error error; |
| |
| |
| if ( READ_UShort( subtable->format ) ) |
| goto Exit; |
| |
| switch ( subtable->format ) |
| { |
| case 1: |
| { |
| OTL_SubTable1* st = &subtable->set.format1; |
| TT_UShort num_indices, n; |
| |
| |
| if ( READ_UShort ( num_indices ) || |
| ALLOC_ARRAY ( st->indices, num_indices, TT_UShort ) || |
| ACCESS_Frame( num_indices * 2L ) ) |
| goto Exit; |
| |
| st->num_indices = num_indices; |
| for ( n = 0; n < num_indices; n++ ) |
| st->indices[n] = GET_UShort(); |
| |
| FORGET_Frame(); |
| } |
| |
| case 2: |
| { |
| OTL_SubTable2* st = &subtable->set.format2; |
| TT_UShort num_ranges, n; |
| OTL_SubTable2_Rec* range; |
| |
| |
| if ( READ_UShort( num_ranges ) || |
| ALLOC_ARRAY( st->ranges, num_ranges, OTL_SubTable2_Rec ) || |
| ACCESS_Frame( num_ranges * 6L ) ) |
| goto Exit; |
| |
| st->num_ranges = num_ranges; |
| range = st->ranges; |
| for ( ; num_ranges > 0; num_ranges--, range++ ) |
| { |
| range->start = GET_UShort(); |
| range->end = GET_UShort(); |
| range->data = GET_UShort(); |
| } |
| |
| FORGET_Frame(); |
| } |
| break; |
| |
| default: |
| error = TT_Err_Invalid_File_Format; |
| } |
| |
| Exit: |
| if ( error ) |
| Free_SubTable( subtable, system ); |
| |
| return error; |
| } |
| |
| |
| /***************************** |
| * Coverage related functions |
| *****************************/ |
| |
| |
| /*************************************************************************/ |
| /* */ |
| /* <Function> */ |
| /* OTL_Free_Coverage */ |
| /* */ |
| /* <Description> */ |
| /* Releases a given OpenType Coverage table. */ |
| /* */ |
| /* <Input> */ |
| /* coverage :: The target coverage. */ |
| /* system :: The current system object. */ |
| /* */ |
| LOCAL_FUNC |
| void OTL_Free_Coverage( OTL_Coverage* coverage, |
| FT_System system ) |
| { |
| Free_SubTable( (OTL_SubTable*)coverage, system ); |
| } |
| |
| |
| /*************************************************************************/ |
| /* */ |
| /* <Function> */ |
| /* OTL_Load_Coverage */ |
| /* */ |
| /* <Description> */ |
| /* Loads an OpenType Coverage table from a font resource. */ |
| /* */ |
| /* <Input> */ |
| /* coverage :: The target coverage. */ |
| /* stream :: The input stream. */ |
| /* */ |
| /* <Return> */ |
| /* TrueType error code. 0 means success. */ |
| /* */ |
| LOCAL_FUNC |
| TT_Error OTL_Load_Coverage( OTL_Coverage* coverage, |
| FT_Stream stream ) |
| { |
| return Load_SubTable( (OTL_SubTable*)coverage, stream ); |
| } |
| |
| |
| /************************************* |
| * Class Definition related functions |
| *************************************/ |
| |
| |
| /*************************************************************************/ |
| /* */ |
| /* <Function> */ |
| /* OTL_Free_Class_Def */ |
| /* */ |
| /* <Description> */ |
| /* Releases a given OpenType Class Definition table. */ |
| /* */ |
| /* <Input> */ |
| /* class_def :: The target class definition. */ |
| /* system :: The current system object. */ |
| /* */ |
| LOCAL_FUNC |
| void OTL_Free_Class_Def( OTL_Class_Def* class_def, |
| FT_System system ) |
| { |
| Free_SubTable( (OTL_SubTable*)class_def, system ); |
| } |
| |
| |
| /*************************************************************************/ |
| /* */ |
| /* <Function> */ |
| /* OTL_Load_Class_Def */ |
| /* */ |
| /* <Description> */ |
| /* Loads an OpenType Class Definition table from a resource. */ |
| /* */ |
| /* <Input> */ |
| /* class_def :: The target class definition. */ |
| /* stream :: The input stream. */ |
| /* */ |
| /* <Return> */ |
| /* TrueType error code. 0 means success. */ |
| /* */ |
| LOCAL_FUNC |
| TT_Error OTL_Load_Class_Def( OTL_Class_Def* class_def, |
| FT_Stream stream ) |
| { |
| return OTL_Load_SubTable( (OTL_SubTable*)class_def, stream ); |
| } |
| |
| |
| /************************************* |
| * Device related functions |
| *************************************/ |
| |
| |
| /*************************************************************************/ |
| /* */ |
| /* <Function> */ |
| /* OTL_Free_Device */ |
| /* */ |
| /* <Description> */ |
| /* Releases a given OpenType Layout Device table. */ |
| /* */ |
| /* <Input> */ |
| /* device :: The target device table. */ |
| /* system :: The current system object. */ |
| /* */ |
| LOCAL_FUNC |
| void OTL_Free_Device( OTL_Device* device, |
| FT_System system ) |
| { |
| if ( device ) |
| { |
| FREE( device->delta_values ); |
| FREE( device ); |
| } |
| } |
| |
| |
| /*************************************************************************/ |
| /* */ |
| /* <Function> */ |
| /* OTL_Load_Device */ |
| /* */ |
| /* <Description> */ |
| /* Loads an OpenType Device table from a font resource. */ |
| /* */ |
| /* <Input> */ |
| /* device :: The target device table. */ |
| /* stream :: The input stream. */ |
| /* */ |
| /* <Return> */ |
| /* TrueType error code. 0 means success. */ |
| /* */ |
| LOCAL_FUNC |
| TT_Error OTL_Load_Device( OTL_Device* device, |
| FT_Stream stream ) |
| { |
| FT_System system = stream->system; |
| TT_Error error; |
| TT_UShort* deltas; |
| TT_UShort num_deltas, num_values; |
| |
| |
| if ( ACCESS_Frame( 6L ) ) |
| goto Exit; |
| |
| device->start_size = GET_UShort(); |
| device->end_size = GET_UShort(); |
| device->delta_format = GET_UShort(); |
| |
| FORGET_Frame(); |
| |
| num_deltas = device->end_size - device->start_size + 1; |
| |
| switch ( device->delta_format ) |
| { |
| case 1: |
| num_values = ( num_deltas + 7 ) >> 3; |
| break; |
| |
| case 2: |
| num_values = ( num_deltas + 3 ) >> 2; |
| break; |
| |
| case 3: |
| num_values = ( num_deltas + 1 ) >> 1; |
| break; |
| |
| default: |
| error = TT_Err_Invalid_File_Format; |
| goto Exit; |
| } |
| |
| if ( ALLOC_ARRAY( deltas, num_values, TT_UShort ) ) |
| goto Exit; |
| |
| if ( !ACCESS_Frame( num_values * 2L ) ) |
| { |
| TT_UShort n; |
| |
| |
| for ( n = 0; n < num_values; n++ ) |
| deltas[n] = GET_UShort(); |
| |
| FORGET_Frame(); |
| |
| device->delta_values = deltas; |
| } |
| else |
| FREE( deltas ); |
| |
| Exit: |
| return error; |
| } |
| |
| |
| /* END */ |