📄 harfbuzz-gpos.c
字号:
} _HB_OPEN_Free_Coverage( &cp->Coverage, memory );}static FT_Error Lookup_CursivePos( GPOS_Instance* gpi, HB_GPOS_SubTable* st, HB_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ){ FT_UShort index, property; FT_Error error; HB_GPOSHeader* gpos = gpi->gpos; HB_CursivePos* cp = &st->cursive; HB_EntryExitRecord* eer; FT_Pos entry_x, entry_y; FT_Pos exit_x, exit_y; FT_UNUSED(nesting_level); if ( context_length != 0xFFFF && context_length < 1 ) { gpi->last = 0xFFFF; return HB_Err_Not_Covered; } /* Glyphs not having the right GDEF properties will be ignored, i.e., gpi->last won't be reset (contrary to user defined properties). */ if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) return error; /* We don't handle mark glyphs here. According to Andrei, this isn't possible, but who knows... */ if ( property == HB_GDEF_MARK ) { gpi->last = 0xFFFF; return HB_Err_Not_Covered; } error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index ); if ( error ) { gpi->last = 0xFFFF; return error; } if ( index >= cp->EntryExitCount ) return HB_Err_Invalid_GPOS_SubTable; eer = &cp->EntryExitRecord[index]; /* Now comes the messiest part of the whole OpenType specification. At first glance, cursive connections seem easy to understand, but there are pitfalls! The reason is that the specs don't mention how to compute the advance values resp. glyph offsets. I was told it would be an omission, to be fixed in the next OpenType version... Again many thanks to Andrei Burago <andreib@microsoft.com> for clarifications. Consider the following example: | xadv1 | +---------+ | | +-----+--+ 1 | | | .| | | 0+--+------+ | 2 | | | 0+--------+ | xadv2 | glyph1: advance width = 12 anchor point = (3,1) glyph2: advance width = 11 anchor point = (9,4) LSB is 1 for both glyphs (so the boxes drawn above are glyph bboxes). Writing direction is R2L; `0' denotes the glyph's coordinate origin. Now the surprising part: The advance width of the *left* glyph (resp. of the *bottom* glyph) will be modified, no matter whether the writing direction is L2R or R2L (resp. T2B or B2T)! This assymetry is caused by the fact that the glyph's coordinate origin is always the lower left corner for all writing directions. Continuing the above example, we can compute the new (horizontal) advance width of glyph2 as 9 - 3 = 6 , and the new vertical offset of glyph2 as 1 - 4 = -3 . Vertical writing direction is far more complicated: a) Assuming that we recompute the advance height of the lower glyph: -- +---------+ -- | | +-----+--+ 1 | yadv1 | | .| | yadv2 | 0+--+------+ -- BSB1 -- | 2 | -- -- y_offset | | BSB2 -- 0+--------+ -- -- -- glyph1: advance height = 6 anchor point = (3,1) glyph2: advance height = 7 anchor point = (9,4) TSB is 1 for both glyphs; writing direction is T2B. BSB1 = yadv1 - (TSB1 + ymax1) BSB2 = yadv2 - (TSB2 + ymax2) y_offset = y2 - y1 vertical advance width of glyph2 = y_offset + BSB2 - BSB1 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1)) = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1) = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1 b) Assuming that we recompute the advance height of the upper glyph: -- -- +---------+ -- TSB1 -- -- | | TSB2 -- +-----+--+ 1 | yadv1 ymax1 | | .| | yadv2 | 0+--+------+ -- -- ymax2 | 2 | -- y_offset | | -- 0+--------+ -- -- glyph1: advance height = 6 anchor point = (3,1) glyph2: advance height = 7 anchor point = (9,4) TSB is 1 for both glyphs; writing direction is T2B. y_offset = y2 - y1 vertical advance width of glyph2 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2) = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2 Comparing a) with b) shows that b) is easier to compute. I'll wait for a reply from Andrei to see what should really be implemented... Since horizontal advance widths or vertical advance heights can be used alone but not together, no ambiguity occurs. */ if ( gpi->last == 0xFFFF ) goto end; /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor table. */ error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(), &entry_x, &entry_y ); if ( error == HB_Err_Not_Covered ) goto end; if ( error ) return error; if ( gpi->r2l ) { POSITION( buffer->in_pos )->x_advance = entry_x - gpi->anchor_x; POSITION( buffer->in_pos )->new_advance = TRUE; } else { POSITION( gpi->last )->x_advance = gpi->anchor_x - entry_x; POSITION( gpi->last )->new_advance = TRUE; } if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT ) { POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos; POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y; } else { POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last; POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y; }end: error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(), &exit_x, &exit_y ); if ( error == HB_Err_Not_Covered ) gpi->last = 0xFFFF; else { gpi->last = buffer->in_pos; gpi->anchor_x = exit_x; gpi->anchor_y = exit_y; } if ( error ) return error; (buffer->in_pos)++; return FT_Err_Ok;}/* LookupType 4 *//* BaseArray */static FT_Error Load_BaseArray( HB_BaseArray* ba, FT_UShort num_classes, FT_Stream stream ){ FT_Error error; FT_Memory memory = stream->memory; FT_UShort m, n, k, count; FT_ULong cur_offset, new_offset, base_offset; HB_BaseRecord* br; HB_Anchor* ban; base_offset = FILE_Pos(); if ( ACCESS_Frame( 2L ) ) return error; count = ba->BaseCount = GET_UShort(); FORGET_Frame(); ba->BaseRecord = NULL; if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) ) return error; br = ba->BaseRecord; for ( m = 0; m < count; m++ ) { br[m].BaseAnchor = NULL; if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, HB_Anchor ) ) goto Fail; ban = br[m].BaseAnchor; for ( n = 0; n < num_classes; n++ ) { if ( ACCESS_Frame( 2L ) ) goto Fail0; new_offset = GET_UShort() + base_offset; FORGET_Frame(); if (new_offset == base_offset) { /* Doulos SIL Regular is buggy and has zer offsets here. Skip */ ban[n].PosFormat = 0; continue; } cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Anchor( &ban[n], stream ) ) != FT_Err_Ok ) goto Fail0; (void)FILE_Seek( cur_offset ); } continue; Fail0: for ( k = 0; k < n; k++ ) Free_Anchor( &ban[k], memory ); goto Fail; } return FT_Err_Ok;Fail: for ( k = 0; k < m; k++ ) { ban = br[k].BaseAnchor; for ( n = 0; n < num_classes; n++ ) Free_Anchor( &ban[n], memory ); FREE( ban ); } FREE( br ); return error;}static void Free_BaseArray( HB_BaseArray* ba, FT_UShort num_classes, FT_Memory memory ){ FT_UShort m, n, count; HB_BaseRecord* br; HB_Anchor* ban; if ( ba->BaseRecord ) { count = ba->BaseCount; br = ba->BaseRecord; for ( m = 0; m < count; m++ ) { ban = br[m].BaseAnchor; for ( n = 0; n < num_classes; n++ ) Free_Anchor( &ban[n], memory ); FREE( ban ); } FREE( br ); }}/* MarkBasePosFormat1 */static FT_Error Load_MarkBasePos( HB_GPOS_SubTable* st, FT_Stream stream ){ FT_Error error; FT_Memory memory = stream->memory; HB_MarkBasePos* mbp = &st->markbase; FT_ULong cur_offset, new_offset, base_offset; base_offset = FILE_Pos(); if ( ACCESS_Frame( 4L ) ) return error; mbp->PosFormat = GET_UShort(); new_offset = GET_UShort() + base_offset; FORGET_Frame(); if (mbp->PosFormat != 1) return HB_Err_Invalid_SubTable_Format; cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != FT_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 = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != FT_Err_Ok ) goto Fail3; (void)FILE_Seek( cur_offset ); if ( ACCESS_Frame( 4L ) ) goto Fail2; mbp->ClassCount = GET_UShort(); new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != FT_Err_Ok ) goto Fail2; (void)FILE_Seek( cur_offset ); 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_BaseArray( &mbp->BaseArray, mbp->ClassCount, stream ) ) != FT_Err_Ok ) goto Fail1; return FT_Err_Ok;Fail1: Free_MarkArray( &mbp->MarkArray, memory );Fail2: _HB_OPEN_Free_Coverage( &mbp->BaseCoverage, memory );Fail3: _HB_OPEN_Free_Coverage( &mbp->MarkCoverage, memory ); return error;}static void Free_MarkBasePos( HB_GPOS_SubTable* st, FT_Memory memory ){ HB_MarkBasePos* mbp = &st->markbase; Free_BaseArray( &mbp->BaseArray, mbp->ClassCount, memory ); Free_MarkArray( &mbp->MarkArray, memory ); _HB_OPEN_Free_Coverage( &mbp->BaseCoverage, memory ); _HB_OPEN_Free_Coverage( &mbp->MarkCoverage, memory );}static FT_Error Lookup_MarkBasePos( GPOS_Instance* gpi, HB_GPOS_SubTable* st, HB_Buffer buffer, FT_UShort flags, FT_UShort context_length, int nesting_level ){ FT_UShort i, j, mark_index, base_index, property, class; FT_Pos x_mark_value, y_mark_value, x_base_value, y_base_value; FT_Error error; HB_GPOSHeader* gpos = gpi->gpos; HB_MarkBasePos* mbp = &st->markbase; HB_MarkArray* ma; HB_BaseArray* ba; HB_BaseRecord* br; HB_Anchor* mark_anchor; HB_Anchor* base_anchor; HB_Position o; FT_UNUSED(nesting_level); if ( context_length != 0xFFFF && context_length < 1 ) return HB_Err_Not_Covered; if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS ) return HB_Err_Not_Covered; if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) ) return error; error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(), &mark_index ); if ( error ) return error; /* now we search backwards for a non-mark glyph */ i = 1; j = buffer->in_pos - 1; while ( i <= buffer->in_pos ) { error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), &property ); if ( error ) return error; if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) ) break; i++; j--; } /* The following assertion is too strong -- at least for mangal.ttf. */#if 0 if ( property != HB_GDEF_BASE_GLYPH ) return HB_Err_Not_Covered;#endif if ( i > buffer->in_pos ) return HB_Err_Not_Covered; error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ), &base_index ); if ( error ) return error; ma = &mbp->MarkArray; if ( mark_index >= ma->MarkCount ) return HB_Err_Invalid_GPOS_SubTable; class = ma->MarkRecord[mark_index].Class; mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor; if ( class >= mbp->ClassCount ) return HB_Err_Invalid_GPOS_SubTable; ba = &mbp->BaseArray; if ( base_index >= ba->BaseCount ) return HB_Err_Invalid_GPOS_SubTable; br = &ba->BaseRecord[base_index]; base_anchor = &br->BaseAnchor[class]; error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(), &x_mark_value, &y_mark_value ); if ( error ) return error; error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ), &x_base_value, &y_base_value ); if ( error ) return error; /* anchor points are not cumulative */ o = POSITION( buffer->in_pos ); o->x_pos = x_base_value - x_mark_value; o->y_pos = y_base_value - y_mark_value; o->x_advance = 0; o->y_advance = 0; o->back = i; (buffer->in_pos)++; return FT_Err_Ok;}/* LookupType 5 *//* LigatureAttach */static FT_Error Load_LigatureAttach( HB_LigatureAttach* lat, FT_UShort num_classes, FT_Stream stream ){ FT_Error error; FT_Memory memory = stream->memory; FT_UShort m, n, k, count; FT_ULong cur_offset, new_offset, base_offset; HB_ComponentRecord* cr; HB_Anchor* lan; base_offset = FILE_Pos(); if ( ACCESS_Frame( 2L ) ) return error; count = lat->ComponentCount = GET_UShort(); FORGET_Frame(); lat->ComponentRecord = NULL; if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) ) return error; cr = lat->ComponentRecord; for ( m = 0; m < count; m++ ) { cr[m].LigatureAnchor = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -