📄 ftxgpos.c
字号:
/******************************************************************* * * ftxgpos.c * * TrueType Open GPOS table support. * * Copyright 1996-2000 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 "ftxopen.h"#include "ftxopenf.h"#include "ftglue.h"#include FT_TRUETYPE_TAGS_H#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' ) struct GPOS_Instance_ { TTO_GPOSHeader* gpos; FT_Face face; FT_Bool dvi; FT_UShort load_flags; /* how the glyph should be loaded */ FT_Bool r2l; FT_UShort last; /* the last valid glyph -- used with cursive positioning */ FT_Pos anchor_x; /* the coordinates of the anchor point */ FT_Pos anchor_y; /* of the last valid glyph */ }; typedef struct GPOS_Instance_ GPOS_Instance; static FT_Error GPos_Do_Glyph_Lookup( GPOS_Instance* gpi, FT_UShort lookup_index, OTL_Buffer buffer, FT_UShort context_length, int nesting_level );// #define IN_GLYPH( pos ) (buffer->in_string[(pos)].gindex)// #define IN_ITEM( pos ) (&buffer->in_string[(pos)])// #define IN_CURGLYPH() (buffer->in_string[buffer->in_pos].gindex)// #define IN_CURITEM() (&buffer->in_string[buffer->in_pos])// #define IN_PROPERTIES( pos ) (buffer->in_string[(pos)].properties)// #define IN_LIGID( pos ) (buffer->in_string[(pos)].ligID)// #define IN_COMPONENT( pos ) (buffer->in_string[(pos)].component)/* the client application must replace this with something more meaningful if multiple master fonts are to be supported. */ static FT_Error default_mmfunc( FT_Face face, FT_UShort metric_id, FT_Pos* metric_value, void* data ) { FT_UNUSED(face); FT_UNUSED(metric_id); FT_UNUSED(metric_value); FT_UNUSED(data); return TTO_Err_No_MM_Interpreter; } EXPORT_FUNC FT_Error TT_Load_GPOS_Table( FT_Face face, TTO_GPOSHeader** retptr, TTO_GDEFHeader* gdef ) { FT_ULong cur_offset, new_offset, base_offset; FT_UShort i, num_lookups; TTO_GPOSHeader* gpos; TTO_Lookup* lo; FT_Stream stream = face->stream; FT_Error error; FT_Memory memory = face->memory; if ( !retptr ) return TT_Err_Invalid_Argument; if ( !stream ) return TT_Err_Invalid_Face_Handle; if (( error = ftglue_face_goto_table( face, TTAG_GPOS, stream ) )) return error; base_offset = FILE_Pos(); if ( ALLOC ( gpos, sizeof( *gpos ) ) ) return error; gpos->memory = memory; gpos->gfunc = FT_Load_Glyph; gpos->mmfunc = default_mmfunc; /* skip version */ if ( FILE_Seek( base_offset + 4L ) || ACCESS_Frame( 2L ) ) goto Fail4; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_ScriptList( &gpos->ScriptList, stream ) ) != TT_Err_Ok ) goto Fail4; (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, stream ) ) != 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, stream, 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 ) || ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef, 256, stream ) ) != TT_Err_Ok ) goto Fail1; break; } } } *retptr = gpos; return TT_Err_Ok; Fail1: Free_LookupList( &gpos->LookupList, GPOS, memory ); Fail2: Free_FeatureList( &gpos->FeatureList, memory ); Fail3: Free_ScriptList( &gpos->ScriptList, memory ); Fail4: FREE( gpos ); return error; } EXPORT_FUNC FT_Error TT_Done_GPOS_Table( TTO_GPOSHeader* gpos ) { FT_Memory memory = gpos->memory; Free_LookupList( &gpos->LookupList, GPOS, memory ); Free_FeatureList( &gpos->FeatureList, memory ); Free_ScriptList( &gpos->ScriptList, memory ); return FT_Err_Ok; } /***************************** * SubTable related functions *****************************/ /* shared tables */ /* ValueRecord */ /* There is a subtle difference in the specs between a `table' and a `record' -- offsets for device tables in ValueRecords are taken from the parent table and not the parent record. */ static FT_Error Load_ValueRecord( TTO_ValueRecord* vr, FT_UShort format, FT_ULong base_offset, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_ULong cur_offset, new_offset; 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(); FORGET_Frame(); if ( new_offset ) { new_offset += base_offset; cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Device( &vr->XPlacementDevice, stream ) ) != TT_Err_Ok ) return error; (void)FILE_Seek( cur_offset ); } else goto empty1; } else { empty1: 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(); FORGET_Frame(); if ( new_offset ) { new_offset += base_offset; cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Device( &vr->YPlacementDevice, stream ) ) != TT_Err_Ok ) goto Fail3; (void)FILE_Seek( cur_offset ); } else goto empty2; } else { empty2: 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(); FORGET_Frame(); if ( new_offset ) { new_offset += base_offset; cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Device( &vr->XAdvanceDevice, stream ) ) != TT_Err_Ok ) goto Fail2; (void)FILE_Seek( cur_offset ); } else goto empty3; } else { empty3: 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(); FORGET_Frame(); if ( new_offset ) { new_offset += base_offset; cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Device( &vr->YAdvanceDevice, stream ) ) != TT_Err_Ok ) goto Fail1; (void)FILE_Seek( cur_offset ); } else goto empty4; } else { empty4: 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, memory ); Fail2: Free_Device( &vr->XAdvanceDevice, memory ); Fail3: Free_Device( &vr->YPlacementDevice, memory ); return error; } static void Free_ValueRecord( TTO_ValueRecord* vr, FT_UShort format, FT_Memory memory ) { if ( format & HAVE_Y_ADVANCE_DEVICE ) Free_Device( &vr->YAdvanceDevice, memory ); if ( format & HAVE_X_ADVANCE_DEVICE ) Free_Device( &vr->XAdvanceDevice, memory ); if ( format & HAVE_Y_PLACEMENT_DEVICE ) Free_Device( &vr->YPlacementDevice, memory ); if ( format & HAVE_X_PLACEMENT_DEVICE ) Free_Device( &vr->XPlacementDevice, memory ); } static FT_Error Get_ValueRecord( GPOS_Instance* gpi, TTO_ValueRecord* vr, FT_UShort format, OTL_Position gd ) { FT_Pos value; FT_Short pixel_value; FT_Error error = TT_Err_Ok; TTO_GPOSHeader* gpos = gpi->gpos; FT_UShort x_ppem, y_ppem; FT_Fixed x_scale, y_scale; if ( !format ) return TT_Err_Ok; x_ppem = gpi->face->size->metrics.x_ppem; y_ppem = gpi->face->size->metrics.y_ppem; x_scale = gpi->face->size->metrics.x_scale; y_scale = gpi->face->size->metrics.y_scale; /* design units -> fractional pixel */ if ( format & HAVE_X_PLACEMENT ) gd->x_pos += x_scale * vr->XPlacement / 0x10000; if ( format & HAVE_Y_PLACEMENT ) gd->y_pos += y_scale * vr->YPlacement / 0x10000; if ( format & HAVE_X_ADVANCE ) gd->x_advance += x_scale * vr->XAdvance / 0x10000; if ( format & HAVE_Y_ADVANCE ) gd->y_advance += y_scale * vr->YAdvance / 0x10000; if ( !gpi->dvi ) { /* pixel -> fractional pixel */ if ( format & HAVE_X_PLACEMENT_DEVICE ) { Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -