?? ftxgpos.c
字號:
if ( !pvr ) return TTO_Err_Invalid_GPOS_SubTable; glyph2 = in->string[in->pos]; for ( numpvr = ppf1->PairSet[index].PairValueCount; numpvr; numpvr--, pvr++ ) { if ( glyph2 == pvr->SecondGlyph ) { error = Get_ValueRecord( gpi, &pvr->Value1, format1, &out[first_pos] ); if ( error ) return error; return Get_ValueRecord( gpi, &pvr->Value2, format2, &out[in->pos] ); } } return TTO_Err_Not_Covered; } static TT_Error Lookup_PairPos2( GPOS_Instance* gpi, TTO_PairPosFormat2* ppf2, TTO_GSUB_String* in, TTO_GPOS_Data* out, UShort first_pos, UShort format1, UShort format2 ) { TT_Error error; UShort cl1, cl2; TTO_Class1Record* c1r; TTO_Class2Record* c2r; error = Get_Class( &ppf2->ClassDef1, in->string[first_pos], &cl1, NULL ); if ( error ) return error; error = Get_Class( &ppf2->ClassDef2, in->string[in->pos], &cl2, NULL ); if ( error ) return error; c1r = &ppf2->Class1Record[cl1]; if ( !c1r ) return TTO_Err_Invalid_GPOS_SubTable; c2r = &c1r->Class2Record[cl2]; error = Get_ValueRecord( gpi, &c2r->Value1, format1, &out[first_pos] ); if ( error ) return error; return Get_ValueRecord( gpi, &c2r->Value2, format2, &out[in->pos] ); } static TT_Error Lookup_PairPos( GPOS_Instance* gpi, TTO_PairPos* pp, TTO_GSUB_String* in, TTO_GPOS_Data* out, UShort flags, UShort context_length ) { TT_Error error; UShort index, property, first_pos; TTO_GPOSHeader* gpos = gpi->gpos; if ( in->pos >= in->length - 1 ) return TTO_Err_Not_Covered; /* Not enough glyphs in input */ if ( context_length != 0xFFFF && context_length < 2 ) return TTO_Err_Not_Covered; if ( CHECK_Property( gpos->gdef, in->string[in->pos], flags, &property ) ) return error; error = Coverage_Index( &pp->Coverage, in->string[in->pos], &index ); if ( error ) return error; /* second glyph */ first_pos = in->pos; (in->pos)++; while ( CHECK_Property( gpos->gdef, in->string[in->pos], flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; if ( in->pos < in->length ) (in->pos)++; else break; } switch ( pp->PosFormat ) { case 1: error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, in, out, first_pos, index, pp->ValueFormat1, pp->ValueFormat2 ); break; case 2: error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, in, out, first_pos, pp->ValueFormat1, pp->ValueFormat2 ); break; default: return TTO_Err_Invalid_GPOS_SubTable_Format; } /* adjusting the `next' glyph */ if ( pp->ValueFormat2 ) (in->pos)++; return error; } /* LookupType 3 */ /* CursivePosFormat1 */ TT_Error Load_CursivePos( TTO_CursivePos* cp, PFace input ) { DEFINE_LOAD_LOCALS( input->stream ); UShort n, count; ULong cur_offset, new_offset, base_offset; TTO_EntryExitRecord* eer; base_offset = FILE_Pos(); if ( ACCESS_Frame( 4L ) ) return error; cp->PosFormat = GET_UShort(); new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Coverage( &cp->Coverage, input ) ) != TT_Err_Ok ) return error; (void)FILE_Seek( cur_offset ); if ( ACCESS_Frame( 2L ) ) goto Fail2; count = cp->EntryExitCount = GET_UShort(); FORGET_Frame(); cp->EntryExitRecord = NULL; if ( ALLOC_ARRAY( cp->EntryExitRecord, count, TTO_EntryExitRecord ) ) goto Fail2; eer = cp->EntryExitRecord; for ( n = 0; n < count; n++ ) { 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_Anchor( &eer[n].EntryAnchor, input ) ) != TT_Err_Ok ) goto Fail1; (void)FILE_Seek( cur_offset ); } else eer[n].EntryAnchor.PosFormat = 0; 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_Anchor( &eer[n].ExitAnchor, input ) ) != TT_Err_Ok ) goto Fail1; (void)FILE_Seek( cur_offset ); } else eer[n].ExitAnchor.PosFormat = 0; } return TT_Err_Ok; Fail1: for ( n = 0; n < count; n++ ) { Free_Anchor( &eer[n].EntryAnchor ); Free_Anchor( &eer[n].ExitAnchor ); } FREE( eer ); Fail2: Free_Coverage( &cp->Coverage ); return error; } void Free_CursivePos( TTO_CursivePos* cp ) { UShort n, count; TTO_EntryExitRecord* eer; if ( cp->EntryExitRecord ) { count = cp->EntryExitCount; eer = cp->EntryExitRecord; for ( n = 0; n < count; n++ ) { Free_Anchor( &eer[n].EntryAnchor ); Free_Anchor( &eer[n].ExitAnchor ); } FREE( eer ); } Free_Coverage( &cp->Coverage ); } static TT_Error Lookup_CursivePos( GPOS_Instance* gpi, TTO_CursivePos* cp, TTO_GSUB_String* in, TTO_GPOS_Data* out, UShort flags, UShort context_length ) { UShort index, property; TT_Error error; TTO_GPOSHeader* gpos = gpi->gpos; TTO_EntryExitRecord* eer; TT_Pos entry_x, entry_y; TT_Pos exit_x, exit_y; if ( context_length != 0xFFFF && context_length < 1 ) { gpi->last = 0xFFFF; return TTO_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->string[in->pos], flags, &property ) ) return error; /* We don't handle mark glyphs here. According to Andrei, this isn't possible, but who knows... */ if ( property == MARK_GLYPH ) { gpi->last = 0xFFFF; return TTO_Err_Not_Covered; } error = Coverage_Index( &cp->Coverage, in->string[in->pos], &index ); if ( error ) { gpi->last = 0xFFFF; return error; } if ( index >= cp->EntryExitCount ) return TTO_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 TTO_Err_Not_Covered if there is no anchor table. */ error = Get_Anchor( gpi, &eer->EntryAnchor, in->string[in->pos], &entry_x, &entry_y ); if ( error == TTO_Err_Not_Covered ) goto end; if ( error ) return error; if ( gpi->r2l ) { out[in->pos].x_advance = entry_x - gpi->anchor_x; out[in->pos].new_advance = TRUE; } else { out[gpi->last].x_advance = gpi->anchor_x - entry_x; out[gpi->last].new_advance = TRUE; } out[in->pos].y_pos = gpi->anchor_y - entry_y + out[gpi->last].y_pos; end: error = Get_Anchor( gpi, &eer->ExitAnchor, in->string[in->pos], &exit_x, &exit_y ); if ( error == TTO_Err_Not_Covered ) gpi->last = 0xFFFF; else { if ( gpi->first == 0xFFFF ) gpi->first = in->pos; gpi->last = in->pos; gpi->anchor_x = exit_x; gpi->anchor_y = exit_y; } if ( error ) return error; (in->pos)++; return TT_Err_Ok; } /* LookupType 4 */ /* BaseArray */ static TT_Error Load_BaseArray( TTO_BaseArray* ba, UShort num_classes, PFace input ) { DEFINE_LOAD_LOCALS( input->stream ); UShort m, n, count; ULong cur_offset, new_offset, base_offset; TTO_BaseRecord* br; TTO_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, TTO_BaseRecord ) ) return error; br = ba->BaseRecord; for ( m = 0; m < count; m++ ) { br[m].BaseAnchor = NULL; if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, TTO_Anchor ) ) goto Fail; ban = br[m].BaseAnchor; for ( n = 0; n < num_classes; n++ ) { if ( ACCESS_Frame( 2L ) ) goto Fail; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Anchor( &ban[n], input ) ) != TT_Err_Ok ) goto Fail; (void)FILE_Seek( cur_offset ); } } return TT_Err_Ok; Fail: for ( m = 0; m < count; m++ ) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -