📄 harfbuzz-gpos.c
字号:
/* * Copyright (C) 1998-2004 David Turner and Werner Lemberg * Copyright (C) 2006 Behdad Esfahbod * Copyright (C) 2007 Red Hat, Inc. * * This is part of HarfBuzz, an OpenType Layout engine library. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. * * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod */#include "harfbuzz-impl.h"#include "harfbuzz-gpos-private.h"#include "harfbuzz-open-private.h"#include "harfbuzz-gdef-private.h"struct GPOS_Instance_{ HB_GPOSHeader* gpos; HB_Font font; HB_Bool dvi; HB_UShort load_flags; /* how the glyph should be loaded */ HB_Bool r2l; HB_UShort last; /* the last valid glyph -- used with cursive positioning */ HB_Fixed anchor_x; /* the coordinates of the anchor point */ HB_Fixed anchor_y; /* of the last valid glyph */};typedef struct GPOS_Instance_ GPOS_Instance;static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi, HB_UShort lookup_index, HB_Buffer buffer, HB_UShort context_length, int nesting_level );/* the client application must replace this with something more meaningful if multiple master fonts are to be supported. */static HB_Error default_mmfunc( HB_Font font, HB_UShort metric_id, HB_Fixed* metric_value, void* data ){ HB_UNUSED(font); HB_UNUSED(metric_id); HB_UNUSED(metric_value); HB_UNUSED(data); return ERR(HB_Err_Not_Covered); /* ERR() call intended */}HB_Error HB_Load_GPOS_Table( HB_Font font, HB_GPOSHeader** retptr, HB_GDEFHeader* gdef ){ HB_UInt cur_offset, new_offset, base_offset; HB_GPOSHeader* gpos; HB_Stream stream = font->stream; HB_Error error; if ( !retptr ) return ERR(HB_Err_Invalid_Argument); if ( GOTO_Table( TTAG_GPOS ) ) return error; base_offset = FILE_Pos(); if ( ALLOC ( gpos, sizeof( *gpos ) ) ) return error; 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 = _HB_OPEN_Load_ScriptList( &gpos->ScriptList, stream ) ) != HB_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 = _HB_OPEN_Load_FeatureList( &gpos->FeatureList, stream ) ) != HB_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 = _HB_OPEN_Load_LookupList( &gpos->LookupList, stream, HB_Type_GPOS ) ) != HB_Err_Ok ) goto Fail2; gpos->gdef = gdef; /* can be NULL */ if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, stream, gpos->LookupList.Lookup, gpos->LookupList.LookupCount ) ) ) goto Fail1; *retptr = gpos; return HB_Err_Ok;Fail1: _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );Fail2: _HB_OPEN_Free_FeatureList( &gpos->FeatureList );Fail3: _HB_OPEN_Free_ScriptList( &gpos->ScriptList );Fail4: FREE( gpos ); return error;}HB_Error HB_Done_GPOS_Table( HB_GPOSHeader* gpos ){ _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS ); _HB_OPEN_Free_FeatureList( &gpos->FeatureList ); _HB_OPEN_Free_ScriptList( &gpos->ScriptList ); FREE( gpos ); return HB_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 HB_Error Load_ValueRecord( HB_ValueRecord* vr, HB_UShort format, HB_UInt base_offset, HB_Stream stream ){ HB_Error error; HB_UInt cur_offset, new_offset; if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT ) { if ( ACCESS_Frame( 2L ) ) return error; vr->XPlacement = GET_Short(); FORGET_Frame(); } else vr->XPlacement = 0; if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT ) { if ( ACCESS_Frame( 2L ) ) return error; vr->YPlacement = GET_Short(); FORGET_Frame(); } else vr->YPlacement = 0; if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE ) { if ( ACCESS_Frame( 2L ) ) return error; vr->XAdvance = GET_Short(); FORGET_Frame(); } else vr->XAdvance = 0; if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE ) { if ( ACCESS_Frame( 2L ) ) return error; vr->YAdvance = GET_Short(); FORGET_Frame(); } else vr->YAdvance = 0; if ( format & HB_GPOS_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 = _HB_OPEN_Load_Device( &vr->XPlacementDevice, stream ) ) != HB_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 & HB_GPOS_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 = _HB_OPEN_Load_Device( &vr->YPlacementDevice, stream ) ) != HB_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 & HB_GPOS_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 = _HB_OPEN_Load_Device( &vr->XAdvanceDevice, stream ) ) != HB_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 & HB_GPOS_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 = _HB_OPEN_Load_Device( &vr->YAdvanceDevice, stream ) ) != HB_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 & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT ) { if ( ACCESS_Frame( 2L ) ) goto Fail1; vr->XIdPlacement = GET_UShort(); FORGET_Frame(); } else vr->XIdPlacement = 0; if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT ) { if ( ACCESS_Frame( 2L ) ) goto Fail1; vr->YIdPlacement = GET_UShort(); FORGET_Frame(); } else vr->YIdPlacement = 0; if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE ) { if ( ACCESS_Frame( 2L ) ) goto Fail1; vr->XIdAdvance = GET_UShort(); FORGET_Frame(); } else vr->XIdAdvance = 0; if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE ) { if ( ACCESS_Frame( 2L ) ) goto Fail1; vr->YIdAdvance = GET_UShort(); FORGET_Frame(); } else vr->YIdAdvance = 0; return HB_Err_Ok;Fail1: _HB_OPEN_Free_Device( &vr->YAdvanceDevice );Fail2: _HB_OPEN_Free_Device( &vr->XAdvanceDevice );Fail3: _HB_OPEN_Free_Device( &vr->YPlacementDevice ); return error;}static void Free_ValueRecord( HB_ValueRecord* vr, HB_UShort format ){ if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE ) _HB_OPEN_Free_Device( &vr->YAdvanceDevice ); if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE ) _HB_OPEN_Free_Device( &vr->XAdvanceDevice ); if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE ) _HB_OPEN_Free_Device( &vr->YPlacementDevice ); if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE ) _HB_OPEN_Free_Device( &vr->XPlacementDevice );}static HB_Error Get_ValueRecord( GPOS_Instance* gpi, HB_ValueRecord* vr, HB_UShort format, HB_Position gd ){ HB_Fixed value; HB_Short pixel_value; HB_Error error = HB_Err_Ok; HB_GPOSHeader* gpos = gpi->gpos; HB_UShort x_ppem, y_ppem; HB_16Dot16 x_scale, y_scale; if ( !format ) return HB_Err_Ok; x_ppem = gpi->font->size->metrics.x_ppem; y_ppem = gpi->font->size->metrics.y_ppem; x_scale = gpi->font->size->metrics.x_scale; y_scale = gpi->font->size->metrics.y_scale; /* design units -> fractional pixel */ if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT ) gd->x_pos += x_scale * vr->XPlacement / 0x10000; if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT ) gd->y_pos += y_scale * vr->YPlacement / 0x10000; if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE ) gd->x_advance += x_scale * vr->XAdvance / 0x10000; if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE ) gd->y_advance += y_scale * vr->YAdvance / 0x10000; if ( !gpi->dvi ) { /* pixel -> fractional pixel */ if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE ) { _HB_OPEN_Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value ); gd->x_pos += pixel_value << 6; } if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE ) { _HB_OPEN_Get_Device( &vr->YPlacementDevice, y_ppem, &pixel_value ); gd->y_pos += pixel_value << 6; } if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE ) { _HB_OPEN_Get_Device( &vr->XAdvanceDevice, x_ppem, &pixel_value ); gd->x_advance += pixel_value << 6; } if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE ) { _HB_OPEN_Get_Device( &vr->YAdvanceDevice, y_ppem, &pixel_value ); gd->y_advance += pixel_value << 6; } } /* values returned from mmfunc() are already in fractional pixels */ if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT ) { error = (gpos->mmfunc)( gpi->font, vr->XIdPlacement, &value, gpos->data ); if ( error ) return error; gd->x_pos += value; } if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT ) { error = (gpos->mmfunc)( gpi->font, vr->YIdPlacement, &value, gpos->data ); if ( error ) return error; gd->y_pos += value; } if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE ) { error = (gpos->mmfunc)( gpi->font, vr->XIdAdvance, &value, gpos->data ); if ( error ) return error; gd->x_advance += value; } if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE ) { error = (gpos->mmfunc)( gpi->font, vr->YIdAdvance, &value, gpos->data ); if ( error ) return error; gd->y_advance += value; } return error;}/* AnchorFormat1 *//* AnchorFormat2 *//* AnchorFormat3 *//* AnchorFormat4 */static HB_Error Load_Anchor( HB_Anchor* an, HB_Stream stream ){ HB_Error error; HB_UInt 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();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -