📄 ftxgpos.c
字号:
/******************************************************************* * * ftxgpos.c * * TrueType Open GPOS table support. * * 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. * ******************************************************************//* XXX There is *a lot* of duplicated code (cf. formats 7 and 8), but I don't care currently. I believe that it would be possible to save about 50% of TTO code by carefully designing the structures, sharing as much as possible with extensive use of macros. This is something for a volunteer :-) */#include "tttypes.h"#include "tttags.h"#include "ttload.h"#include "ttextend.h"#include "ttmemory.h"#include "ttfile.h"#include "ftxopen.h"#include "ftxopenf.h"#define GPOS_ID Build_Extension_ID( 'G', 'P', 'O', 'S' ) /********************** * Extension Functions **********************/ static TT_Error GPOS_Create( void* ext, PFace face ) { DEFINE_LOAD_LOCALS( face->stream ); TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext; Long table; /* by convention */ if ( !gpos ) return TT_Err_Ok; /* a null offset indicates that there is no GPOS table */ gpos->offset = 0; /* we store the start offset and the size of the subtable */ table = TT_LookUp_Table( face, TTAG_GPOS ); if ( table < 0 ) return TT_Err_Ok; /* The table is optional */ if ( FILE_Seek( face->dirTables[table].Offset ) || ACCESS_Frame( 4L ) ) return error; gpos->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */ gpos->Version = GET_ULong(); FORGET_Frame(); gpos->loaded = FALSE; return TT_Err_Ok; } static TT_Error GPOS_Destroy( void* ext, PFace face ) { TTO_GPOSHeader* gpos = (TTO_GPOSHeader*)ext; /* by convention */ if ( !gpos ) return TT_Err_Ok; if ( gpos->loaded ) { Free_LookupList( &gpos->LookupList, GPOS ); Free_FeatureList( &gpos->FeatureList ); Free_ScriptList( &gpos->ScriptList ); } return TT_Err_Ok; } EXPORT_FUNC TT_Error TT_Init_GPOS_Extension( TT_Engine engine ) { PEngine_Instance _engine = HANDLE_Engine( engine ); if ( !_engine ) return TT_Err_Invalid_Engine; return TT_Register_Extension( _engine, GPOS_ID, sizeof ( TTO_GPOSHeader ), GPOS_Create, GPOS_Destroy ); } EXPORT_FUNC TT_Error TT_Load_GPOS_Table( TT_Face face, TTO_GPOSHeader* retptr, TTO_GDEFHeader* gdef ) { ULong cur_offset, new_offset, base_offset; TT_UShort i, num_lookups; TT_Error error; TT_Stream stream; TTO_GPOSHeader* gpos; TTO_Lookup* lo; PFace faze = HANDLE_Face( face ); if ( !retptr ) return TT_Err_Invalid_Argument; if ( !faze ) return TT_Err_Invalid_Face_Handle; error = TT_Extension_Get( faze, GPOS_ID, (void**)&gpos ); if ( error ) return error; if ( gpos->offset == 0 ) return TT_Err_Table_Missing; /* no GPOS table; nothing to do */ /* now access stream */ if ( USE_Stream( faze->stream, stream ) ) return error; base_offset = gpos->offset; /* skip version */ if ( FILE_Seek( base_offset + 4L ) || ACCESS_Frame( 2L ) ) return error; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_ScriptList( &gpos->ScriptList, faze ) ) != TT_Err_Ok ) return error; (void)FILE_Seek( cur_offset ); if ( ACCESS_Frame( 2L ) ) goto Fail3; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_FeatureList( &gpos->FeatureList, faze ) ) != TT_Err_Ok ) goto Fail3; (void)FILE_Seek( cur_offset ); if ( ACCESS_Frame( 2L ) ) goto Fail2; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_LookupList( &gpos->LookupList, faze, GPOS ) ) != TT_Err_Ok ) goto Fail2; gpos->gdef = gdef; /* can be NULL */ /* We now check the LookupFlags for values larger than 0xFF to find out whether we need to load the `MarkAttachClassDef' field of the GDEF table -- this hack is necessary for OpenType 1.2 tables since the version field of the GDEF table hasn't been incremented. For constructed GDEF tables, we only load it if `MarkAttachClassDef_offset' is not zero (nevertheless, a build of a constructed mark attach table is not supported currently). */ if ( gdef && gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded ) { lo = gpos->LookupList.Lookup; num_lookups = gpos->LookupList.LookupCount; for ( i = 0; i < num_lookups; i++ ) { if ( lo[i].LookupFlag & IGNORE_SPECIAL_MARKS ) { if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) || ACCESS_Frame( 2L ) ) goto Fail1; new_offset = GET_UShort(); FORGET_Frame(); if ( !new_offset ) return TTO_Err_Invalid_GDEF_SubTable; new_offset += base_offset; if ( FILE_Seek( new_offset ) || ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef, 256, faze ) ) != TT_Err_Ok ) goto Fail1; break; } } } gpos->loaded = TRUE; *retptr = *gpos; DONE_Stream( stream ); return TT_Err_Ok; Fail1: Free_LookupList( &gpos->LookupList, GPOS ); Fail2: Free_FeatureList( &gpos->FeatureList ); Fail3: Free_ScriptList( &gpos->ScriptList ); /* release stream */ DONE_Stream( stream ); return error; } /***************************** * SubTable related functions *****************************/ /* shared tables */ /* ValueRecord */ static TT_Error Load_ValueRecord( TTO_ValueRecord* vr, TT_UShort format, PFace input ) { DEFINE_LOAD_LOCALS( input->stream ); ULong cur_offset, new_offset, base_offset; base_offset = FILE_Pos(); if ( format & HAVE_X_PLACEMENT ) { if ( ACCESS_Frame( 2L ) ) return error; vr->XPlacement = GET_Short(); FORGET_Frame(); } else vr->XPlacement = 0; if ( format & HAVE_Y_PLACEMENT ) { if ( ACCESS_Frame( 2L ) ) return error; vr->YPlacement = GET_Short(); FORGET_Frame(); } else vr->YPlacement = 0; if ( format & HAVE_X_ADVANCE ) { if ( ACCESS_Frame( 2L ) ) return error; vr->XAdvance = GET_Short(); FORGET_Frame(); } else vr->XAdvance = 0; if ( format & HAVE_Y_ADVANCE ) { if ( ACCESS_Frame( 2L ) ) return error; vr->YAdvance = GET_Short(); FORGET_Frame(); } else vr->YAdvance = 0; if ( format & HAVE_X_PLACEMENT_DEVICE ) { if ( ACCESS_Frame( 2L ) ) return error; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Device( &vr->XPlacementDevice, input ) ) != TT_Err_Ok ) return error; (void)FILE_Seek( cur_offset ); } else { vr->XPlacementDevice.StartSize = 0; vr->XPlacementDevice.EndSize = 0; vr->XPlacementDevice.DeltaValue = NULL; } if ( format & HAVE_Y_PLACEMENT_DEVICE ) { if ( ACCESS_Frame( 2L ) ) goto Fail3; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Device( &vr->YPlacementDevice, input ) ) != TT_Err_Ok ) goto Fail3; (void)FILE_Seek( cur_offset ); } else { vr->YPlacementDevice.StartSize = 0; vr->YPlacementDevice.EndSize = 0; vr->YPlacementDevice.DeltaValue = NULL; } if ( format & HAVE_X_ADVANCE_DEVICE ) { if ( ACCESS_Frame( 2L ) ) goto Fail2; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Device( &vr->XAdvanceDevice, input ) ) != TT_Err_Ok ) goto Fail2; (void)FILE_Seek( cur_offset ); } else { vr->XAdvanceDevice.StartSize = 0; vr->XAdvanceDevice.EndSize = 0; vr->XAdvanceDevice.DeltaValue = NULL; } if ( format & HAVE_Y_ADVANCE_DEVICE ) { if ( ACCESS_Frame( 2L ) ) goto Fail1; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Device( &vr->YAdvanceDevice, input ) ) != TT_Err_Ok ) goto Fail1; (void)FILE_Seek( cur_offset ); } else { vr->YAdvanceDevice.StartSize = 0; vr->YAdvanceDevice.EndSize = 0; vr->YAdvanceDevice.DeltaValue = NULL; } if ( format & HAVE_X_ID_PLACEMENT ) { if ( ACCESS_Frame( 2L ) ) goto Fail1; vr->XIdPlacement = GET_UShort(); FORGET_Frame(); } else vr->XIdPlacement = 0; if ( format & HAVE_Y_ID_PLACEMENT ) { if ( ACCESS_Frame( 2L ) ) goto Fail1; vr->YIdPlacement = GET_UShort(); FORGET_Frame(); } else vr->YIdPlacement = 0; if ( format & HAVE_X_ID_ADVANCE ) { if ( ACCESS_Frame( 2L ) ) goto Fail1; vr->XIdAdvance = GET_UShort(); FORGET_Frame(); } else vr->XIdAdvance = 0; if ( format & HAVE_Y_ID_ADVANCE ) { if ( ACCESS_Frame( 2L ) ) goto Fail1; vr->YIdAdvance = GET_UShort(); FORGET_Frame(); } else vr->YIdAdvance = 0; return TT_Err_Ok; Fail1: Free_Device( &vr->YAdvanceDevice ); Fail2: Free_Device( &vr->XAdvanceDevice ); Fail3: Free_Device( &vr->YPlacementDevice ); return error; } static void Free_ValueRecord( TTO_ValueRecord* vr, UShort format ) { if ( format & HAVE_Y_ADVANCE_DEVICE ) Free_Device( &vr->YAdvanceDevice ); if ( format & HAVE_X_ADVANCE_DEVICE ) Free_Device( &vr->XAdvanceDevice ); if ( format & HAVE_Y_PLACEMENT_DEVICE ) Free_Device( &vr->YPlacementDevice ); if ( format & HAVE_X_PLACEMENT_DEVICE ) Free_Device( &vr->XPlacementDevice ); } /* AnchorFormat1 */ /* AnchorFormat2 */ /* AnchorFormat3 */ /* AnchorFormat4 */ static TT_Error Load_Anchor( TTO_Anchor* an, PFace input ) { DEFINE_LOAD_LOCALS( input->stream ); ULong cur_offset, new_offset, base_offset; base_offset = FILE_Pos(); if ( ACCESS_Frame( 2L ) ) return error; an->PosFormat = GET_UShort(); FORGET_Frame(); switch ( an->PosFormat ) { case 1: if ( ACCESS_Frame( 4L ) ) return error; an->af.af1.XCoordinate = GET_Short(); an->af.af1.YCoordinate = GET_Short(); FORGET_Frame(); break; case 2: if ( ACCESS_Frame( 6L ) ) return error; an->af.af2.XCoordinate = GET_Short(); an->af.af2.YCoordinate = GET_Short(); an->af.af2.AnchorPoint = GET_UShort(); FORGET_Frame(); break; case 3: if ( ACCESS_Frame( 6L ) ) return error; an->af.af3.XCoordinate = GET_Short(); an->af.af3.YCoordinate = GET_Short(); new_offset = GET_UShort(); FORGET_Frame(); if ( new_offset ) { new_offset += base_offset; cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Device( &an->af.af3.XDeviceTable, input ) ) != TT_Err_Ok ) return error; (void)FILE_Seek( cur_offset ); } else { an->af.af3.XDeviceTable.StartSize = 0; an->af.af3.XDeviceTable.EndSize = 0; an->af.af3.XDeviceTable.DeltaValue = 0; } if ( ACCESS_Frame( 2L ) ) goto Fail; new_offset = GET_UShort(); FORGET_Frame(); if ( new_offset ) { new_offset += base_offset; cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Device( &an->af.af3.YDeviceTable, input ) ) != TT_Err_Ok ) goto Fail; (void)FILE_Seek( cur_offset ); } else { an->af.af3.YDeviceTable.StartSize = 0; an->af.af3.YDeviceTable.EndSize = 0; an->af.af3.YDeviceTable.DeltaValue = 0; } break; case 4: if ( ACCESS_Frame( 4L ) ) return error; an->af.af4.XIdAnchor = GET_UShort(); an->af.af4.YIdAnchor = GET_UShort(); FORGET_Frame(); break; default: return TTO_Err_Invalid_GPOS_SubTable_Format; } return TT_Err_Ok; Fail:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -