PageRenderTime 59ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/freetype-1.3.1/lib/extend/ftxgsub.c

https://bitbucket.org/davaeron/uplink
C | 4307 lines | 2863 code | 1286 blank | 158 comment | 640 complexity | 8cdfdcbf31649071a2b97cfae54d35fa MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1
  1. /*******************************************************************
  2. *
  3. * ftxgsub.c
  4. *
  5. * TrueType Open GSUB table support.
  6. *
  7. * Copyright 1996-1999 by
  8. * David Turner, Robert Wilhelm, and Werner Lemberg.
  9. *
  10. * This file is part of the FreeType project, and may only be used
  11. * modified and distributed under the terms of the FreeType project
  12. * license, LICENSE.TXT. By continuing to use, modify, or distribute
  13. * this file you indicate that you have read the license and
  14. * understand and accept it fully.
  15. *
  16. ******************************************************************/
  17. /* XXX There is *a lot* of duplicated code (cf. formats 5 and 6), but
  18. I don't care currently. I believe that it would be possible to
  19. save about 50% of TTO code by carefully designing the structures,
  20. sharing as much as possible with extensive use of macros. This
  21. is something for a volunteer :-) */
  22. #include "tttypes.h"
  23. #include "tttags.h"
  24. #include "ttload.h"
  25. #include "ttextend.h"
  26. #include "ttmemory.h"
  27. #include "ttfile.h"
  28. #include "ftxopen.h"
  29. #include "ftxopenf.h"
  30. #define GSUB_ID Build_Extension_ID( 'G', 'S', 'U', 'B' )
  31. #define ADD_String( in, num_in, out, num_out, data ) \
  32. ( ( error = TT_GSUB_Add_String( (in), (num_in), \
  33. (out), (num_out), \
  34. (data) ) ) != TT_Err_Ok )
  35. #define CHECK_Property( gdef, index, flags, property ) \
  36. ( ( error = Check_Property( (gdef), (index), (flags), \
  37. (property) ) ) != TT_Err_Ok )
  38. static TT_Error Do_Glyph_Lookup( TTO_GSUBHeader* gsub,
  39. UShort lookup_index,
  40. TTO_GSUB_String* in,
  41. TTO_GSUB_String* out,
  42. UShort context_length,
  43. int nesting_level );
  44. /**********************
  45. * Auxiliary functions
  46. **********************/
  47. /* The following function copies `num_out' elements from `data' to
  48. `out', advancing the array pointer in the `in' structure by `num_in'
  49. elements and in `out' by `num_out' elements. If the string (resp.
  50. the properties) array in `out' is empty or too small, it allocates
  51. resp. reallocates the string (and properties) array. Finally, it
  52. sets the `length' field of `out' equal to `pos' of the `out'
  53. structure.
  54. The properties (if defined) for all replaced glyphs are taken from
  55. the glyph at position `in->pos'. */
  56. EXPORT_FUNC
  57. TT_Error TT_GSUB_Add_String( TTO_GSUB_String* in,
  58. UShort num_in,
  59. TTO_GSUB_String* out,
  60. UShort num_out,
  61. UShort* data )
  62. {
  63. TT_Error error;
  64. UShort i;
  65. UShort p_in;
  66. UShort* p_out;
  67. /* sanity check */
  68. if ( !in || !out ||
  69. in->length == 0 || in->pos >= in->length ||
  70. in->length < in->pos + num_in )
  71. return TT_Err_Invalid_Argument;
  72. if ( out->pos + num_out >= out->allocated )
  73. {
  74. ULong size = out->pos + num_out + 256L;
  75. /* The following works because all fields in `out' must be
  76. initialized to zero (including the `string' field) for the
  77. first use. */
  78. if ( REALLOC( out->string, size * sizeof ( UShort ) ) )
  79. return error;
  80. if ( in->properties )
  81. if ( REALLOC( out->properties, size * sizeof ( UShort ) ) )
  82. return error;
  83. out->allocated = size;
  84. }
  85. if ( num_out )
  86. {
  87. MEM_Copy( &out->string[out->pos], data, num_out * sizeof ( UShort ) );
  88. if ( in->properties )
  89. {
  90. p_in = in->properties[in->pos];
  91. p_out = out->properties;
  92. for ( i = out->pos; i < out->pos + num_out; i++ )
  93. p_out[i] = p_in;
  94. }
  95. }
  96. in->pos += num_in;
  97. out->pos += num_out;
  98. out->length = out->pos;
  99. return TT_Err_Ok;
  100. }
  101. static TT_Error Check_Property( TTO_GDEFHeader* gdef,
  102. UShort index,
  103. UShort flags,
  104. UShort* property )
  105. {
  106. TT_Error error;
  107. if ( gdef )
  108. {
  109. error = TT_GDEF_Get_Glyph_Property( gdef, index, property );
  110. if ( error )
  111. return error;
  112. /* This is OpenType 1.2 */
  113. if ( flags & IGNORE_SPECIAL_MARKS )
  114. if ( (flags & 0xFF00) != *property )
  115. return TTO_Err_Not_Covered;
  116. if ( flags & *property )
  117. return TTO_Err_Not_Covered;
  118. }
  119. return TT_Err_Ok;
  120. }
  121. /**********************
  122. * Extension Functions
  123. **********************/
  124. static TT_Error GSUB_Create( void* ext,
  125. PFace face )
  126. {
  127. DEFINE_LOAD_LOCALS( face->stream );
  128. TTO_GSUBHeader* gsub = (TTO_GSUBHeader*)ext;
  129. Long table;
  130. /* by convention */
  131. if ( !gsub )
  132. return TT_Err_Ok;
  133. /* a null offset indicates that there is no GSUB table */
  134. gsub->offset = 0;
  135. /* we store the start offset and the size of the subtable */
  136. table = TT_LookUp_Table( face, TTAG_GSUB );
  137. if ( table < 0 )
  138. return TT_Err_Ok; /* The table is optional */
  139. if ( FILE_Seek( face->dirTables[table].Offset ) ||
  140. ACCESS_Frame( 4L ) )
  141. return error;
  142. gsub->offset = FILE_Pos() - 4L; /* undo ACCESS_Frame() */
  143. gsub->Version = GET_ULong();
  144. FORGET_Frame();
  145. gsub->loaded = FALSE;
  146. return TT_Err_Ok;
  147. }
  148. static TT_Error GSUB_Destroy( void* ext,
  149. PFace face )
  150. {
  151. TTO_GSUBHeader* gsub = (TTO_GSUBHeader*)ext;
  152. /* by convention */
  153. if ( !gsub )
  154. return TT_Err_Ok;
  155. if ( gsub->loaded )
  156. {
  157. Free_LookupList( &gsub->LookupList, GSUB );
  158. Free_FeatureList( &gsub->FeatureList );
  159. Free_ScriptList( &gsub->ScriptList );
  160. }
  161. return TT_Err_Ok;
  162. }
  163. EXPORT_FUNC
  164. TT_Error TT_Init_GSUB_Extension( TT_Engine engine )
  165. {
  166. PEngine_Instance _engine = HANDLE_Engine( engine );
  167. if ( !_engine )
  168. return TT_Err_Invalid_Engine;
  169. return TT_Register_Extension( _engine,
  170. GSUB_ID,
  171. sizeof ( TTO_GSUBHeader ),
  172. GSUB_Create,
  173. GSUB_Destroy );
  174. }
  175. EXPORT_FUNC
  176. TT_Error TT_Load_GSUB_Table( TT_Face face,
  177. TTO_GSUBHeader* retptr,
  178. TTO_GDEFHeader* gdef )
  179. {
  180. ULong cur_offset, new_offset, base_offset;
  181. TT_UShort i, num_lookups;
  182. TT_Error error;
  183. TT_Stream stream;
  184. TTO_GSUBHeader* gsub;
  185. TTO_Lookup* lo;
  186. PFace faze = HANDLE_Face( face );
  187. if ( !retptr )
  188. return TT_Err_Invalid_Argument;
  189. if ( !faze )
  190. return TT_Err_Invalid_Face_Handle;
  191. error = TT_Extension_Get( faze, GSUB_ID, (void**)&gsub );
  192. if ( error )
  193. return error;
  194. if ( gsub->offset == 0 )
  195. return TT_Err_Table_Missing; /* no GSUB table; nothing to do */
  196. /* now access stream */
  197. if ( USE_Stream( faze->stream, stream ) )
  198. return error;
  199. base_offset = gsub->offset;
  200. /* skip version */
  201. if ( FILE_Seek( base_offset + 4L ) ||
  202. ACCESS_Frame( 2L ) )
  203. return error;
  204. new_offset = GET_UShort() + base_offset;
  205. FORGET_Frame();
  206. cur_offset = FILE_Pos();
  207. if ( FILE_Seek( new_offset ) ||
  208. ( error = Load_ScriptList( &gsub->ScriptList,
  209. faze ) ) != TT_Err_Ok )
  210. return error;
  211. (void)FILE_Seek( cur_offset );
  212. if ( ACCESS_Frame( 2L ) )
  213. goto Fail3;
  214. new_offset = GET_UShort() + base_offset;
  215. FORGET_Frame();
  216. cur_offset = FILE_Pos();
  217. if ( FILE_Seek( new_offset ) ||
  218. ( error = Load_FeatureList( &gsub->FeatureList,
  219. faze ) ) != TT_Err_Ok )
  220. goto Fail3;
  221. (void)FILE_Seek( cur_offset );
  222. if ( ACCESS_Frame( 2L ) )
  223. goto Fail2;
  224. new_offset = GET_UShort() + base_offset;
  225. FORGET_Frame();
  226. cur_offset = FILE_Pos();
  227. if ( FILE_Seek( new_offset ) ||
  228. ( error = Load_LookupList( &gsub->LookupList,
  229. faze, GSUB ) ) != TT_Err_Ok )
  230. goto Fail2;
  231. gsub->gdef = gdef; /* can be NULL */
  232. /* We now check the LookupFlags for values larger than 0xFF to find
  233. out whether we need to load the `MarkAttachClassDef' field of the
  234. GDEF table -- this hack is necessary for OpenType 1.2 tables since
  235. the version field of the GDEF table hasn't been incremented.
  236. For constructed GDEF tables, we only load it if
  237. `MarkAttachClassDef_offset' is not zero (nevertheless, a build of
  238. a constructed mark attach table is not supported currently). */
  239. if ( gdef &&
  240. gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
  241. {
  242. lo = gsub->LookupList.Lookup;
  243. num_lookups = gsub->LookupList.LookupCount;
  244. for ( i = 0; i < num_lookups; i++ )
  245. {
  246. if ( lo[i].LookupFlag & IGNORE_SPECIAL_MARKS )
  247. {
  248. if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
  249. ACCESS_Frame( 2L ) )
  250. goto Fail1;
  251. new_offset = GET_UShort();
  252. FORGET_Frame();
  253. if ( !new_offset )
  254. return TTO_Err_Invalid_GDEF_SubTable;
  255. new_offset += base_offset;
  256. if ( FILE_Seek( new_offset ) ||
  257. ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef,
  258. 256, faze ) ) != TT_Err_Ok )
  259. goto Fail1;
  260. break;
  261. }
  262. }
  263. }
  264. gsub->loaded = TRUE;
  265. *retptr = *gsub;
  266. DONE_Stream( stream );
  267. return TT_Err_Ok;
  268. Fail1:
  269. Free_LookupList( &gsub->LookupList, GSUB );
  270. Fail2:
  271. Free_FeatureList( &gsub->FeatureList );
  272. Fail3:
  273. Free_ScriptList( &gsub->ScriptList );
  274. /* release stream */
  275. DONE_Stream( stream );
  276. return error;
  277. }
  278. /*****************************
  279. * SubTable related functions
  280. *****************************/
  281. /* LookupType 1 */
  282. /* SingleSubstFormat1 */
  283. /* SingleSubstFormat2 */
  284. TT_Error Load_SingleSubst( TTO_SingleSubst* ss,
  285. PFace input )
  286. {
  287. DEFINE_LOAD_LOCALS( input->stream );
  288. UShort n, count;
  289. ULong cur_offset, new_offset, base_offset;
  290. UShort* s;
  291. base_offset = FILE_Pos();
  292. if ( ACCESS_Frame( 4L ) )
  293. return error;
  294. ss->SubstFormat = GET_UShort();
  295. new_offset = GET_UShort() + base_offset;
  296. FORGET_Frame();
  297. cur_offset = FILE_Pos();
  298. if ( FILE_Seek( new_offset ) ||
  299. ( error = Load_Coverage( &ss->Coverage, input ) ) != TT_Err_Ok )
  300. return error;
  301. (void)FILE_Seek( cur_offset );
  302. switch ( ss->SubstFormat )
  303. {
  304. case 1:
  305. if ( ACCESS_Frame( 2L ) )
  306. goto Fail2;
  307. ss->ssf.ssf1.DeltaGlyphID = GET_UShort();
  308. FORGET_Frame();
  309. break;
  310. case 2:
  311. if ( ACCESS_Frame( 2L ) )
  312. goto Fail2;
  313. count = ss->ssf.ssf2.GlyphCount = GET_UShort();
  314. FORGET_Frame();
  315. ss->ssf.ssf2.Substitute = NULL;
  316. if ( ALLOC_ARRAY( ss->ssf.ssf2.Substitute, count, UShort ) )
  317. goto Fail2;
  318. s = ss->ssf.ssf2.Substitute;
  319. if ( ACCESS_Frame( count * 2L ) )
  320. goto Fail1;
  321. for ( n = 0; n < count; n++ )
  322. s[n] = GET_UShort();
  323. FORGET_Frame();
  324. break;
  325. default:
  326. return TTO_Err_Invalid_GSUB_SubTable_Format;
  327. }
  328. return TT_Err_Ok;
  329. Fail1:
  330. FREE( s );
  331. Fail2:
  332. Free_Coverage( &ss->Coverage );
  333. return error;
  334. }
  335. void Free_SingleSubst( TTO_SingleSubst* ss )
  336. {
  337. switch ( ss->SubstFormat )
  338. {
  339. case 1:
  340. break;
  341. case 2:
  342. FREE( ss->ssf.ssf2.Substitute );
  343. break;
  344. }
  345. Free_Coverage( &ss->Coverage );
  346. }
  347. static TT_Error Lookup_SingleSubst( TTO_SingleSubst* ss,
  348. TTO_GSUB_String* in,
  349. TTO_GSUB_String* out,
  350. UShort flags,
  351. UShort context_length,
  352. TTO_GDEFHeader* gdef )
  353. {
  354. UShort index, value[1], property;
  355. TT_Error error;
  356. if ( context_length != 0xFFFF && context_length < 1 )
  357. return TTO_Err_Not_Covered;
  358. if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
  359. return error;
  360. error = Coverage_Index( &ss->Coverage, in->string[in->pos], &index );
  361. if ( error )
  362. return error;
  363. switch ( ss->SubstFormat )
  364. {
  365. case 1:
  366. value[0] = ( in->string[in->pos] + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF;
  367. if ( ADD_String( in, 1, out, 1, value ) )
  368. return error;
  369. break;
  370. case 2:
  371. if ( index >= ss->ssf.ssf2.GlyphCount )
  372. return TTO_Err_Invalid_GSUB_SubTable;
  373. value[0] = ss->ssf.ssf2.Substitute[index];
  374. if ( ADD_String( in, 1, out, 1, value ) )
  375. return error;
  376. break;
  377. default:
  378. return TTO_Err_Invalid_GSUB_SubTable;
  379. }
  380. if ( gdef && gdef->NewGlyphClasses )
  381. {
  382. /* we inherit the old glyph class to the substituted glyph */
  383. error = Add_Glyph_Property( gdef, value[0], property );
  384. if ( error && error != TTO_Err_Not_Covered )
  385. return error;
  386. }
  387. return TT_Err_Ok;
  388. }
  389. /* LookupType 2 */
  390. /* Sequence */
  391. static TT_Error Load_Sequence( TTO_Sequence* s,
  392. PFace input )
  393. {
  394. DEFINE_LOAD_LOCALS( input->stream );
  395. UShort n, count;
  396. UShort* sub;
  397. if ( ACCESS_Frame( 2L ) )
  398. return error;
  399. count = s->GlyphCount = GET_UShort();
  400. FORGET_Frame();
  401. s->Substitute = NULL;
  402. if ( count )
  403. {
  404. if ( ALLOC_ARRAY( s->Substitute, count, UShort ) )
  405. return error;
  406. sub = s->Substitute;
  407. if ( ACCESS_Frame( count * 2L ) )
  408. {
  409. FREE( sub );
  410. return error;
  411. }
  412. for ( n = 0; n < count; n++ )
  413. sub[n] = GET_UShort();
  414. FORGET_Frame();
  415. }
  416. return TT_Err_Ok;
  417. }
  418. static void Free_Sequence( TTO_Sequence* s )
  419. {
  420. FREE( s->Substitute );
  421. }
  422. /* MultipleSubstFormat1 */
  423. TT_Error Load_MultipleSubst( TTO_MultipleSubst* ms,
  424. PFace input )
  425. {
  426. DEFINE_LOAD_LOCALS( input->stream );
  427. UShort n, count;
  428. ULong cur_offset, new_offset, base_offset;
  429. TTO_Sequence* s;
  430. base_offset = FILE_Pos();
  431. if ( ACCESS_Frame( 4L ) )
  432. return error;
  433. ms->SubstFormat = GET_UShort(); /* should be 1 */
  434. new_offset = GET_UShort() + base_offset;
  435. FORGET_Frame();
  436. cur_offset = FILE_Pos();
  437. if ( FILE_Seek( new_offset ) ||
  438. ( error = Load_Coverage( &ms->Coverage, input ) ) != TT_Err_Ok )
  439. return error;
  440. (void)FILE_Seek( cur_offset );
  441. if ( ACCESS_Frame( 2L ) )
  442. goto Fail2;
  443. count = ms->SequenceCount = GET_UShort();
  444. FORGET_Frame();
  445. ms->Sequence = NULL;
  446. if ( ALLOC_ARRAY( ms->Sequence, count, TTO_Sequence ) )
  447. goto Fail2;
  448. s = ms->Sequence;
  449. for ( n = 0; n < count; n++ )
  450. {
  451. if ( ACCESS_Frame( 2L ) )
  452. goto Fail1;
  453. new_offset = GET_UShort() + base_offset;
  454. FORGET_Frame();
  455. cur_offset = FILE_Pos();
  456. if ( FILE_Seek( new_offset ) ||
  457. ( error = Load_Sequence( &s[n], input ) ) != TT_Err_Ok )
  458. goto Fail1;
  459. (void)FILE_Seek( cur_offset );
  460. }
  461. return TT_Err_Ok;
  462. Fail1:
  463. for ( n = 0; n < count; n++ )
  464. Free_Sequence( &s[n] );
  465. FREE( s );
  466. Fail2:
  467. Free_Coverage( &ms->Coverage );
  468. return error;
  469. }
  470. void Free_MultipleSubst( TTO_MultipleSubst* ms )
  471. {
  472. UShort n, count;
  473. TTO_Sequence* s;
  474. if ( ms->Sequence )
  475. {
  476. count = ms->SequenceCount;
  477. s = ms->Sequence;
  478. for ( n = 0; n < count; n++ )
  479. Free_Sequence( &s[n] );
  480. FREE( s );
  481. }
  482. Free_Coverage( &ms->Coverage );
  483. }
  484. static TT_Error Lookup_MultipleSubst( TTO_MultipleSubst* ms,
  485. TTO_GSUB_String* in,
  486. TTO_GSUB_String* out,
  487. UShort flags,
  488. UShort context_length,
  489. TTO_GDEFHeader* gdef )
  490. {
  491. TT_Error error;
  492. UShort index, property, n, count;
  493. UShort* s;
  494. if ( context_length != 0xFFFF && context_length < 1 )
  495. return TTO_Err_Not_Covered;
  496. if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
  497. return error;
  498. error = Coverage_Index( &ms->Coverage, in->string[in->pos], &index );
  499. if ( error )
  500. return error;
  501. if ( index >= ms->SequenceCount )
  502. return TTO_Err_Invalid_GSUB_SubTable;
  503. count = ms->Sequence[index].GlyphCount;
  504. s = ms->Sequence[index].Substitute;
  505. if ( ADD_String( in, 1, out, count, s ) )
  506. return error;
  507. if ( gdef && gdef->NewGlyphClasses )
  508. {
  509. /* this is a guess only ... */
  510. if ( property == TTO_LIGATURE )
  511. property = TTO_BASE_GLYPH;
  512. for ( n = 0; n < count; n++ )
  513. {
  514. error = Add_Glyph_Property( gdef, s[n], property );
  515. if ( error && error != TTO_Err_Not_Covered )
  516. return error;
  517. }
  518. }
  519. return TT_Err_Ok;
  520. }
  521. /* LookupType 3 */
  522. /* AlternateSet */
  523. static TT_Error Load_AlternateSet( TTO_AlternateSet* as,
  524. PFace input )
  525. {
  526. DEFINE_LOAD_LOCALS( input->stream );
  527. UShort n, count;
  528. UShort* a;
  529. if ( ACCESS_Frame( 2L ) )
  530. return error;
  531. count = as->GlyphCount = GET_UShort();
  532. FORGET_Frame();
  533. as->Alternate = NULL;
  534. if ( ALLOC_ARRAY( as->Alternate, count, UShort ) )
  535. return error;
  536. a = as->Alternate;
  537. if ( ACCESS_Frame( count * 2L ) )
  538. {
  539. FREE( a );
  540. return error;
  541. }
  542. for ( n = 0; n < count; n++ )
  543. a[n] = GET_UShort();
  544. FORGET_Frame();
  545. return TT_Err_Ok;
  546. }
  547. static void Free_AlternateSet( TTO_AlternateSet* as )
  548. {
  549. FREE( as->Alternate );
  550. }
  551. /* AlternateSubstFormat1 */
  552. TT_Error Load_AlternateSubst( TTO_AlternateSubst* as,
  553. PFace input )
  554. {
  555. DEFINE_LOAD_LOCALS( input->stream );
  556. UShort n, count;
  557. ULong cur_offset, new_offset, base_offset;
  558. TTO_AlternateSet* aset;
  559. base_offset = FILE_Pos();
  560. if ( ACCESS_Frame( 4L ) )
  561. return error;
  562. as->SubstFormat = GET_UShort(); /* should be 1 */
  563. new_offset = GET_UShort() + base_offset;
  564. FORGET_Frame();
  565. cur_offset = FILE_Pos();
  566. if ( FILE_Seek( new_offset ) ||
  567. ( error = Load_Coverage( &as->Coverage, input ) ) != TT_Err_Ok )
  568. return error;
  569. (void)FILE_Seek( cur_offset );
  570. if ( ACCESS_Frame( 2L ) )
  571. goto Fail2;
  572. count = as->AlternateSetCount = GET_UShort();
  573. FORGET_Frame();
  574. as->AlternateSet = NULL;
  575. if ( ALLOC_ARRAY( as->AlternateSet, count, TTO_AlternateSet ) )
  576. goto Fail2;
  577. aset = as->AlternateSet;
  578. for ( n = 0; n < count; n++ )
  579. {
  580. if ( ACCESS_Frame( 2L ) )
  581. goto Fail1;
  582. new_offset = GET_UShort() + base_offset;
  583. FORGET_Frame();
  584. cur_offset = FILE_Pos();
  585. if ( FILE_Seek( new_offset ) ||
  586. ( error = Load_AlternateSet( &aset[n], input ) ) != TT_Err_Ok )
  587. goto Fail1;
  588. (void)FILE_Seek( cur_offset );
  589. }
  590. return TT_Err_Ok;
  591. Fail1:
  592. for ( n = 0; n < count; n++ )
  593. Free_AlternateSet( &aset[n] );
  594. FREE( aset );
  595. Fail2:
  596. Free_Coverage( &as->Coverage );
  597. return error;
  598. }
  599. void Free_AlternateSubst( TTO_AlternateSubst* as )
  600. {
  601. UShort n, count;
  602. TTO_AlternateSet* aset;
  603. if ( as->AlternateSet )
  604. {
  605. count = as->AlternateSetCount;
  606. aset = as->AlternateSet;
  607. for ( n = 0; n < count; n++ )
  608. Free_AlternateSet( &aset[n] );
  609. FREE( aset );
  610. }
  611. Free_Coverage( &as->Coverage );
  612. }
  613. static TT_Error Lookup_AlternateSubst( TTO_GSUBHeader* gsub,
  614. TTO_AlternateSubst* as,
  615. TTO_GSUB_String* in,
  616. TTO_GSUB_String* out,
  617. UShort flags,
  618. UShort context_length,
  619. TTO_GDEFHeader* gdef )
  620. {
  621. TT_Error error;
  622. UShort index, alt_index, property;
  623. TTO_AlternateSet aset;
  624. if ( context_length != 0xFFFF && context_length < 1 )
  625. return TTO_Err_Not_Covered;
  626. if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
  627. return error;
  628. error = Coverage_Index( &as->Coverage, in->string[in->pos], &index );
  629. if ( error )
  630. return error;
  631. aset = as->AlternateSet[index];
  632. /* we use a user-defined callback function to get the alternate index */
  633. if ( gsub->alt )
  634. alt_index = (gsub->alt)( out->pos, in->string[in->pos],
  635. aset.GlyphCount, aset.Alternate,
  636. gsub->data );
  637. else
  638. alt_index = 0;
  639. if ( ADD_String( in, 1, out, 1, &aset.Alternate[alt_index] ) )
  640. return error;
  641. if ( gdef && gdef->NewGlyphClasses )
  642. {
  643. /* we inherit the old glyph class to the substituted glyph */
  644. error = Add_Glyph_Property( gdef, aset.Alternate[alt_index],
  645. property );
  646. if ( error && error != TTO_Err_Not_Covered )
  647. return error;
  648. }
  649. return TT_Err_Ok;
  650. }
  651. /* LookupType 4 */
  652. /* Ligature */
  653. static TT_Error Load_Ligature( TTO_Ligature* l,
  654. PFace input )
  655. {
  656. DEFINE_LOAD_LOCALS( input->stream );
  657. UShort n, count;
  658. UShort* c;
  659. if ( ACCESS_Frame( 4L ) )
  660. return error;
  661. l->LigGlyph = GET_UShort();
  662. l->ComponentCount = GET_UShort();
  663. FORGET_Frame();
  664. l->Component = NULL;
  665. count = l->ComponentCount - 1; /* only ComponentCount - 1 elements */
  666. if ( ALLOC_ARRAY( l->Component, count, UShort ) )
  667. return error;
  668. c = l->Component;
  669. if ( ACCESS_Frame( count * 2L ) )
  670. {
  671. FREE( c );
  672. return error;
  673. }
  674. for ( n = 0; n < count; n++ )
  675. c[n] = GET_UShort();
  676. FORGET_Frame();
  677. return TT_Err_Ok;
  678. }
  679. static void Free_Ligature( TTO_Ligature* l )
  680. {
  681. FREE( l->Component );
  682. }
  683. /* LigatureSet */
  684. static TT_Error Load_LigatureSet( TTO_LigatureSet* ls,
  685. PFace input )
  686. {
  687. DEFINE_LOAD_LOCALS( input->stream );
  688. UShort n, count;
  689. ULong cur_offset, new_offset, base_offset;
  690. TTO_Ligature* l;
  691. base_offset = FILE_Pos();
  692. if ( ACCESS_Frame( 2L ) )
  693. return error;
  694. count = ls->LigatureCount = GET_UShort();
  695. FORGET_Frame();
  696. ls->Ligature = NULL;
  697. if ( ALLOC_ARRAY( ls->Ligature, count, TTO_Ligature ) )
  698. return error;
  699. l = ls->Ligature;
  700. for ( n = 0; n < count; n++ )
  701. {
  702. if ( ACCESS_Frame( 2L ) )
  703. goto Fail;
  704. new_offset = GET_UShort() + base_offset;
  705. FORGET_Frame();
  706. cur_offset = FILE_Pos();
  707. if ( FILE_Seek( new_offset ) ||
  708. ( error = Load_Ligature( &l[n], input ) ) != TT_Err_Ok )
  709. goto Fail;
  710. (void)FILE_Seek( cur_offset );
  711. }
  712. return TT_Err_Ok;
  713. Fail:
  714. for ( n = 0; n < count; n++ )
  715. Free_Ligature( &l[n] );
  716. FREE( l );
  717. return error;
  718. }
  719. static void Free_LigatureSet( TTO_LigatureSet* ls )
  720. {
  721. UShort n, count;
  722. TTO_Ligature* l;
  723. if ( ls->Ligature )
  724. {
  725. count = ls->LigatureCount;
  726. l = ls->Ligature;
  727. for ( n = 0; n < count; n++ )
  728. Free_Ligature( &l[n] );
  729. FREE( l );
  730. }
  731. }
  732. /* LigatureSubstFormat1 */
  733. TT_Error Load_LigatureSubst( TTO_LigatureSubst* ls,
  734. PFace input )
  735. {
  736. DEFINE_LOAD_LOCALS( input->stream );
  737. UShort n, count;
  738. ULong cur_offset, new_offset, base_offset;
  739. TTO_LigatureSet* lset;
  740. base_offset = FILE_Pos();
  741. if ( ACCESS_Frame( 4L ) )
  742. return error;
  743. ls->SubstFormat = GET_UShort(); /* should be 1 */
  744. new_offset = GET_UShort() + base_offset;
  745. FORGET_Frame();
  746. cur_offset = FILE_Pos();
  747. if ( FILE_Seek( new_offset ) ||
  748. ( error = Load_Coverage( &ls->Coverage, input ) ) != TT_Err_Ok )
  749. return error;
  750. (void)FILE_Seek( cur_offset );
  751. if ( ACCESS_Frame( 2L ) )
  752. goto Fail2;
  753. count = ls->LigatureSetCount = GET_UShort();
  754. FORGET_Frame();
  755. ls->LigatureSet = NULL;
  756. if ( ALLOC_ARRAY( ls->LigatureSet, count, TTO_LigatureSet ) )
  757. goto Fail2;
  758. lset = ls->LigatureSet;
  759. for ( n = 0; n < count; n++ )
  760. {
  761. if ( ACCESS_Frame( 2L ) )
  762. goto Fail1;
  763. new_offset = GET_UShort() + base_offset;
  764. FORGET_Frame();
  765. cur_offset = FILE_Pos();
  766. if ( FILE_Seek( new_offset ) ||
  767. ( error = Load_LigatureSet( &lset[n], input ) ) != TT_Err_Ok )
  768. goto Fail1;
  769. (void)FILE_Seek( cur_offset );
  770. }
  771. return TT_Err_Ok;
  772. Fail1:
  773. for ( n = 0; n < count; n++ )
  774. Free_LigatureSet( &lset[n] );
  775. FREE( lset );
  776. Fail2:
  777. Free_Coverage( &ls->Coverage );
  778. return error;
  779. }
  780. void Free_LigatureSubst( TTO_LigatureSubst* ls )
  781. {
  782. UShort n, count;
  783. TTO_LigatureSet* lset;
  784. if ( ls->LigatureSet )
  785. {
  786. count = ls->LigatureSetCount;
  787. lset = ls->LigatureSet;
  788. for ( n = 0; n < count; n++ )
  789. Free_LigatureSet( &lset[n] );
  790. FREE( lset );
  791. }
  792. Free_Coverage( &ls->Coverage );
  793. }
  794. static TT_Error Lookup_LigatureSubst( TTO_LigatureSubst* ls,
  795. TTO_GSUB_String* in,
  796. TTO_GSUB_String* out,
  797. UShort flags,
  798. UShort context_length,
  799. TTO_GDEFHeader* gdef )
  800. {
  801. UShort index, property;
  802. TT_Error error;
  803. UShort numlig, i, j;
  804. UShort* s_in;
  805. UShort* c;
  806. TTO_Ligature* lig;
  807. if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
  808. return error;
  809. error = Coverage_Index( &ls->Coverage, in->string[in->pos], &index );
  810. if ( error )
  811. return error;
  812. if ( index >= ls->LigatureSetCount )
  813. return TTO_Err_Invalid_GSUB_SubTable;
  814. lig = ls->LigatureSet[index].Ligature;
  815. for ( numlig = ls->LigatureSet[index].LigatureCount;
  816. numlig;
  817. numlig--, lig++ )
  818. {
  819. if ( in->pos + lig->ComponentCount > in->length )
  820. continue; /* Not enough glyphs in input */
  821. s_in = &in->string[in->pos];
  822. c = lig->Component;
  823. if ( context_length != 0xFFFF && context_length < lig->ComponentCount )
  824. break;
  825. for ( i = 1, j = 1; i < lig->ComponentCount; i++, j++ )
  826. {
  827. while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
  828. {
  829. if ( error && error != TTO_Err_Not_Covered )
  830. return error;
  831. if ( in->pos + j < in->length )
  832. j++;
  833. else
  834. break;
  835. }
  836. if ( s_in[j] != c[i - 1] )
  837. break;
  838. }
  839. if ( i == lig->ComponentCount )
  840. {
  841. if ( ADD_String( in, lig->ComponentCount, out, 1, &lig->LigGlyph ) )
  842. return error;
  843. if ( gdef && gdef->NewGlyphClasses )
  844. {
  845. /* this is just a guess ... */
  846. error = Add_Glyph_Property( gdef, lig->LigGlyph, TTO_LIGATURE );
  847. if ( error && error != TTO_Err_Not_Covered )
  848. return error;
  849. }
  850. return TT_Err_Ok;
  851. }
  852. }
  853. return TTO_Err_Not_Covered;
  854. }
  855. /* Do the actual substitution for a context substitution (either format
  856. 5 or 6). This is only called after we've determined that the input
  857. matches the subrule. */
  858. static TT_Error Do_ContextSubst( TTO_GSUBHeader* gsub,
  859. UShort GlyphCount,
  860. UShort SubstCount,
  861. TTO_SubstLookupRecord* subst,
  862. TTO_GSUB_String* in,
  863. TTO_GSUB_String* out,
  864. int nesting_level )
  865. {
  866. TT_Error error;
  867. UShort i, old_pos;
  868. i = 0;
  869. while ( i < GlyphCount )
  870. {
  871. if ( SubstCount && i == subst->SequenceIndex )
  872. {
  873. old_pos = in->pos;
  874. /* Do a substitution */
  875. error = Do_Glyph_Lookup( gsub, subst->LookupListIndex, in, out,
  876. GlyphCount, nesting_level );
  877. subst++;
  878. SubstCount--;
  879. i += in->pos - old_pos;
  880. if ( error == TTO_Err_Not_Covered )
  881. {
  882. /* XXX "can't happen" -- but don't count on it */
  883. if ( ADD_String( in, 1, out, 1, &in->string[in->pos] ) )
  884. return error;
  885. i++;
  886. }
  887. else if ( error )
  888. return error;
  889. }
  890. else
  891. {
  892. /* No substitution for this index */
  893. if ( ADD_String( in, 1, out, 1, &in->string[in->pos] ) )
  894. return error;
  895. i++;
  896. }
  897. }
  898. return TT_Err_Ok;
  899. }
  900. /* LookupType 5 */
  901. /* SubRule */
  902. static TT_Error Load_SubRule( TTO_SubRule* sr,
  903. PFace input )
  904. {
  905. DEFINE_LOAD_LOCALS( input->stream );
  906. UShort n, count;
  907. UShort* i;
  908. TTO_SubstLookupRecord* slr;
  909. if ( ACCESS_Frame( 4L ) )
  910. return error;
  911. sr->GlyphCount = GET_UShort();
  912. sr->SubstCount = GET_UShort();
  913. FORGET_Frame();
  914. sr->Input = NULL;
  915. count = sr->GlyphCount - 1; /* only GlyphCount - 1 elements */
  916. if ( ALLOC_ARRAY( sr->Input, count, UShort ) )
  917. return error;
  918. i = sr->Input;
  919. if ( ACCESS_Frame( count * 2L ) )
  920. goto Fail2;
  921. for ( n = 0; n < count; n++ )
  922. i[n] = GET_UShort();
  923. FORGET_Frame();
  924. sr->SubstLookupRecord = NULL;
  925. count = sr->SubstCount;
  926. if ( ALLOC_ARRAY( sr->SubstLookupRecord, count, TTO_SubstLookupRecord ) )
  927. goto Fail2;
  928. slr = sr->SubstLookupRecord;
  929. if ( ACCESS_Frame( count * 4L ) )
  930. goto Fail1;
  931. for ( n = 0; n < count; n++ )
  932. {
  933. slr[n].SequenceIndex = GET_UShort();
  934. slr[n].LookupListIndex = GET_UShort();
  935. }
  936. FORGET_Frame();
  937. return TT_Err_Ok;
  938. Fail1:
  939. FREE( slr );
  940. Fail2:
  941. FREE( i );
  942. return error;
  943. }
  944. static void Free_SubRule( TTO_SubRule* sr )
  945. {
  946. FREE( sr->SubstLookupRecord );
  947. FREE( sr->Input );
  948. }
  949. /* SubRuleSet */
  950. static TT_Error Load_SubRuleSet( TTO_SubRuleSet* srs,
  951. PFace input )
  952. {
  953. DEFINE_LOAD_LOCALS( input->stream );
  954. UShort n, count;
  955. ULong cur_offset, new_offset, base_offset;
  956. TTO_SubRule* sr;
  957. base_offset = FILE_Pos();
  958. if ( ACCESS_Frame( 2L ) )
  959. return error;
  960. count = srs->SubRuleCount = GET_UShort();
  961. FORGET_Frame();
  962. srs->SubRule = NULL;
  963. if ( ALLOC_ARRAY( srs->SubRule, count, TTO_SubRule ) )
  964. return error;
  965. sr = srs->SubRule;
  966. for ( n = 0; n < count; n++ )
  967. {
  968. if ( ACCESS_Frame( 2L ) )
  969. goto Fail;
  970. new_offset = GET_UShort() + base_offset;
  971. FORGET_Frame();
  972. cur_offset = FILE_Pos();
  973. if ( FILE_Seek( new_offset ) ||
  974. ( error = Load_SubRule( &sr[n], input ) ) != TT_Err_Ok )
  975. goto Fail;
  976. (void)FILE_Seek( cur_offset );
  977. }
  978. return TT_Err_Ok;
  979. Fail:
  980. for ( n = 0; n < count; n++ )
  981. Free_SubRule( &sr[n] );
  982. FREE( sr );
  983. return error;
  984. }
  985. static void Free_SubRuleSet( TTO_SubRuleSet* srs )
  986. {
  987. UShort n, count;
  988. TTO_SubRule* sr;
  989. if ( srs->SubRule )
  990. {
  991. count = srs->SubRuleCount;
  992. sr = srs->SubRule;
  993. for ( n = 0; n < count; n++ )
  994. Free_SubRule( &sr[n] );
  995. FREE( sr );
  996. }
  997. }
  998. /* ContextSubstFormat1 */
  999. static TT_Error Load_ContextSubst1( TTO_ContextSubstFormat1* csf1,
  1000. PFace input )
  1001. {
  1002. DEFINE_LOAD_LOCALS( input->stream );
  1003. UShort n, count;
  1004. ULong cur_offset, new_offset, base_offset;
  1005. TTO_SubRuleSet* srs;
  1006. base_offset = FILE_Pos() - 2L;
  1007. if ( ACCESS_Frame( 2L ) )
  1008. return error;
  1009. new_offset = GET_UShort() + base_offset;
  1010. FORGET_Frame();
  1011. cur_offset = FILE_Pos();
  1012. if ( FILE_Seek( new_offset ) ||
  1013. ( error = Load_Coverage( &csf1->Coverage, input ) ) != TT_Err_Ok )
  1014. return error;
  1015. (void)FILE_Seek( cur_offset );
  1016. if ( ACCESS_Frame( 2L ) )
  1017. goto Fail2;
  1018. count = csf1->SubRuleSetCount = GET_UShort();
  1019. FORGET_Frame();
  1020. csf1->SubRuleSet = NULL;
  1021. if ( ALLOC_ARRAY( csf1->SubRuleSet, count, TTO_SubRuleSet ) )
  1022. goto Fail2;
  1023. srs = csf1->SubRuleSet;
  1024. for ( n = 0; n < count; n++ )
  1025. {
  1026. if ( ACCESS_Frame( 2L ) )
  1027. goto Fail1;
  1028. new_offset = GET_UShort() + base_offset;
  1029. FORGET_Frame();
  1030. cur_offset = FILE_Pos();
  1031. if ( FILE_Seek( new_offset ) ||
  1032. ( error = Load_SubRuleSet( &srs[n], input ) ) != TT_Err_Ok )
  1033. goto Fail1;
  1034. (void)FILE_Seek( cur_offset );
  1035. }
  1036. return TT_Err_Ok;
  1037. Fail1:
  1038. for ( n = 0; n < count; n++ )
  1039. Free_SubRuleSet( &srs[n] );
  1040. FREE( srs );
  1041. Fail2:
  1042. Free_Coverage( &csf1->Coverage );
  1043. return error;
  1044. }
  1045. static void Free_Context1( TTO_ContextSubstFormat1* csf1 )
  1046. {
  1047. UShort n, count;
  1048. TTO_SubRuleSet* srs;
  1049. if ( csf1->SubRuleSet )
  1050. {
  1051. count = csf1->SubRuleSetCount;
  1052. srs = csf1->SubRuleSet;
  1053. for ( n = 0; n < count; n++ )
  1054. Free_SubRuleSet( &srs[n] );
  1055. FREE( srs );
  1056. }
  1057. Free_Coverage( &csf1->Coverage );
  1058. }
  1059. /* SubClassRule */
  1060. static TT_Error Load_SubClassRule( TTO_ContextSubstFormat2* csf2,
  1061. TTO_SubClassRule* scr,
  1062. PFace input )
  1063. {
  1064. DEFINE_LOAD_LOCALS( input->stream );
  1065. UShort n, count;
  1066. UShort* c;
  1067. TTO_SubstLookupRecord* slr;
  1068. Bool* d;
  1069. if ( ACCESS_Frame( 4L ) )
  1070. return error;
  1071. scr->GlyphCount = GET_UShort();
  1072. scr->SubstCount = GET_UShort();
  1073. if ( scr->GlyphCount > csf2->MaxContextLength )
  1074. csf2->MaxContextLength = scr->GlyphCount;
  1075. FORGET_Frame();
  1076. scr->Class = NULL;
  1077. count = scr->GlyphCount - 1; /* only GlyphCount - 1 elements */
  1078. if ( ALLOC_ARRAY( scr->Class, count, UShort ) )
  1079. return error;
  1080. c = scr->Class;
  1081. d = csf2->ClassDef.Defined;
  1082. if ( ACCESS_Frame( count * 2L ) )
  1083. goto Fail2;
  1084. for ( n = 0; n < count; n++ )
  1085. {
  1086. c[n] = GET_UShort();
  1087. /* We check whether the specific class is used at all. If not,
  1088. class 0 is used instead. */
  1089. if ( !d[c[n]] )
  1090. c[n] = 0;
  1091. }
  1092. FORGET_Frame();
  1093. scr->SubstLookupRecord = NULL;
  1094. count = scr->SubstCount;
  1095. if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, TTO_SubstLookupRecord ) )
  1096. goto Fail2;
  1097. slr = scr->SubstLookupRecord;
  1098. if ( ACCESS_Frame( count * 4L ) )
  1099. goto Fail1;
  1100. for ( n = 0; n < count; n++ )
  1101. {
  1102. slr[n].SequenceIndex = GET_UShort();
  1103. slr[n].LookupListIndex = GET_UShort();
  1104. }
  1105. FORGET_Frame();
  1106. return TT_Err_Ok;
  1107. Fail1:
  1108. FREE( slr );
  1109. Fail2:
  1110. FREE( c );
  1111. return error;
  1112. }
  1113. static void Free_SubClassRule( TTO_SubClassRule* scr )
  1114. {
  1115. FREE( scr->SubstLookupRecord );
  1116. FREE( scr->Class );
  1117. }
  1118. /* SubClassSet */
  1119. static TT_Error Load_SubClassSet( TTO_ContextSubstFormat2* csf2,
  1120. TTO_SubClassSet* scs,
  1121. PFace input )
  1122. {
  1123. DEFINE_LOAD_LOCALS( input->stream );
  1124. UShort n, count;
  1125. ULong cur_offset, new_offset, base_offset;
  1126. TTO_SubClassRule* scr;
  1127. base_offset = FILE_Pos();
  1128. if ( ACCESS_Frame( 2L ) )
  1129. return error;
  1130. count = scs->SubClassRuleCount = GET_UShort();
  1131. FORGET_Frame();
  1132. scs->SubClassRule = NULL;
  1133. if ( ALLOC_ARRAY( scs->SubClassRule, count, TTO_SubClassRule ) )
  1134. return error;
  1135. scr = scs->SubClassRule;
  1136. for ( n = 0; n < count; n++ )
  1137. {
  1138. if ( ACCESS_Frame( 2L ) )
  1139. goto Fail;
  1140. new_offset = GET_UShort() + base_offset;
  1141. FORGET_Frame();
  1142. cur_offset = FILE_Pos();
  1143. if ( FILE_Seek( new_offset ) ||
  1144. ( error = Load_SubClassRule( csf2, &scr[n],
  1145. input ) ) != TT_Err_Ok )
  1146. goto Fail;
  1147. (void)FILE_Seek( cur_offset );
  1148. }
  1149. return TT_Err_Ok;
  1150. Fail:
  1151. for ( n = 0; n < count; n++ )
  1152. Free_SubClassRule( &scr[n] );
  1153. FREE( scr );
  1154. return error;
  1155. }
  1156. static void Free_SubClassSet( TTO_SubClassSet* scs )
  1157. {
  1158. UShort n, count;
  1159. TTO_SubClassRule* scr;
  1160. if ( scs->SubClassRule )
  1161. {
  1162. count = scs->SubClassRuleCount;
  1163. scr = scs->SubClassRule;
  1164. for ( n = 0; n < count; n++ )
  1165. Free_SubClassRule( &scr[n] );
  1166. FREE( scr );
  1167. }
  1168. }
  1169. /* ContextSubstFormat2 */
  1170. static TT_Error Load_ContextSubst2( TTO_ContextSubstFormat2* csf2,
  1171. PFace input )
  1172. {
  1173. DEFINE_LOAD_LOCALS( input->stream );
  1174. UShort n, count;
  1175. ULong cur_offset, new_offset, base_offset;
  1176. TTO_SubClassSet* scs;
  1177. base_offset = FILE_Pos() - 2;
  1178. if ( ACCESS_Frame( 2L ) )
  1179. return error;
  1180. new_offset = GET_UShort() + base_offset;
  1181. FORGET_Frame();
  1182. cur_offset = FILE_Pos();
  1183. if ( FILE_Seek( new_offset ) ||
  1184. ( error = Load_Coverage( &csf2->Coverage, input ) ) != TT_Err_Ok )
  1185. return error;
  1186. (void)FILE_Seek( cur_offset );
  1187. if ( ACCESS_Frame( 4L ) )
  1188. goto Fail3;
  1189. new_offset = GET_UShort() + base_offset;
  1190. /* `SubClassSetCount' is the upper limit for class values, thus we
  1191. read it now to make an additional safety check. */
  1192. count = csf2->SubClassSetCount = GET_UShort();
  1193. FORGET_Frame();
  1194. cur_offset = FILE_Pos();
  1195. if ( FILE_Seek( new_offset ) ||
  1196. ( error = Load_ClassDefinition( &csf2->ClassDef, count,
  1197. input ) ) != TT_Err_Ok )
  1198. goto Fail3;
  1199. (void)FILE_Seek( cur_offset );
  1200. csf2->SubClassSet = NULL;
  1201. csf2->MaxContextLength = 0;
  1202. if ( ALLOC_ARRAY( csf2->SubClassSet, count, TTO_SubClassSet ) )
  1203. goto Fail2;
  1204. scs = csf2->SubClassSet;
  1205. for ( n = 0; n < count; n++ )
  1206. {
  1207. if ( ACCESS_Frame( 2L ) )
  1208. goto Fail1;
  1209. new_offset = GET_UShort() + base_offset;
  1210. FORGET_Frame();
  1211. if ( new_offset != base_offset ) /* not a NULL offset */
  1212. {
  1213. cur_offset = FILE_Pos();
  1214. if ( FILE_Seek( new_offset ) ||
  1215. ( error = Load_SubClassSet( csf2, &scs[n],
  1216. input ) ) != TT_Err_Ok )
  1217. goto Fail1;
  1218. (void)FILE_Seek( cur_offset );
  1219. }
  1220. else
  1221. {
  1222. /* we create a SubClassSet table with no entries */
  1223. csf2->SubClassSet[n].SubClassRuleCount = 0;
  1224. csf2->SubClassSet[n].SubClassRule = NULL;
  1225. }
  1226. }
  1227. return TT_Err_Ok;
  1228. Fail1:
  1229. for ( n = 0; n < count; n++ )
  1230. Free_SubClassSet( &scs[n] );
  1231. FREE( scs );
  1232. Fail2:
  1233. Free_ClassDefinition( &csf2->ClassDef );
  1234. Fail3:
  1235. Free_Coverage( &csf2->Coverage );
  1236. return error;
  1237. }
  1238. static void Free_Context2( TTO_ContextSubstFormat2* csf2 )
  1239. {
  1240. UShort n, count;
  1241. TTO_SubClassSet* scs;
  1242. if ( csf2->SubClassSet )
  1243. {
  1244. count = csf2->SubClassSetCount;
  1245. scs = csf2->SubClassSet;
  1246. for ( n = 0; n < count; n++ )
  1247. Free_SubClassSet( &scs[n] );
  1248. FREE( scs );
  1249. }
  1250. Free_ClassDefinition( &csf2->ClassDef );
  1251. Free_Coverage( &csf2->Coverage );
  1252. }
  1253. /* ContextSubstFormat3 */
  1254. static TT_Error Load_ContextSubst3( TTO_ContextSubstFormat3* csf3,
  1255. PFace input )
  1256. {
  1257. DEFINE_LOAD_LOCALS( input->stream );
  1258. UShort n, count;
  1259. ULong cur_offset, new_offset, base_offset;
  1260. TTO_Coverage* c;
  1261. TTO_SubstLookupRecord* slr;
  1262. base_offset = FILE_Pos() - 2L;
  1263. if ( ACCESS_Frame( 4L ) )
  1264. return error;
  1265. csf3->GlyphCount = GET_UShort();
  1266. csf3->SubstCount = GET_UShort();
  1267. FORGET_Frame();
  1268. csf3->Coverage = NULL;
  1269. count = csf3->GlyphCount;
  1270. if ( ALLOC_ARRAY( csf3->Coverage, count, TTO_Coverage ) )
  1271. return error;
  1272. c = csf3->Coverage;
  1273. for ( n = 0; n < count; n++ )
  1274. {
  1275. if ( ACCESS_Frame( 2L ) )
  1276. goto Fail2;
  1277. new_offset = GET_UShort() + base_offset;
  1278. FORGET_Frame();
  1279. cur_offset = FILE_Pos();
  1280. if ( FILE_Seek( new_offset ) ||
  1281. ( error = Load_Coverage( &c[n], input ) ) != TT_Err_Ok )
  1282. goto Fail2;
  1283. (void)FILE_Seek( cur_offset );
  1284. }
  1285. csf3->SubstLookupRecord = NULL;
  1286. count = csf3->SubstCount;
  1287. if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count,
  1288. TTO_SubstLookupRecord ) )
  1289. goto Fail2;
  1290. slr = csf3->SubstLookupRecord;
  1291. if ( ACCESS_Frame( count * 4L ) )
  1292. goto Fail1;
  1293. for ( n = 0; n < count; n++ )
  1294. {
  1295. slr[n].SequenceIndex = GET_UShort();
  1296. slr[n].LookupListIndex = GET_UShort();
  1297. }
  1298. FORGET_Frame();
  1299. return TT_Err_Ok;
  1300. Fail1:
  1301. FREE( slr );
  1302. Fail2:
  1303. for ( n = 0; n < count; n++ )
  1304. Free_Coverage( &c[n] );
  1305. FREE( c );
  1306. return error;
  1307. }
  1308. static void Free_Context3( TTO_ContextSubstFormat3* csf3 )
  1309. {
  1310. UShort n, count;
  1311. TTO_Coverage* c;
  1312. FREE( csf3->SubstLookupRecord );
  1313. if ( csf3->Coverage )
  1314. {
  1315. count = csf3->GlyphCount;
  1316. c = csf3->Coverage;
  1317. for ( n = 0; n < count; n++ )
  1318. Free_Coverage( &c[n] );
  1319. FREE( c );
  1320. }
  1321. }
  1322. /* ContextSubst */
  1323. TT_Error Load_ContextSubst( TTO_ContextSubst* cs,
  1324. PFace input )
  1325. {
  1326. DEFINE_LOAD_LOCALS( input->stream );
  1327. if ( ACCESS_Frame( 2L ) )
  1328. return error;
  1329. cs->SubstFormat = GET_UShort();
  1330. FORGET_Frame();
  1331. switch ( cs->SubstFormat )
  1332. {
  1333. case 1:
  1334. return Load_ContextSubst1( &cs->csf.csf1, input );
  1335. case 2:
  1336. return Load_ContextSubst2( &cs->csf.csf2, input );
  1337. case 3:
  1338. return Load_ContextSubst3( &cs->csf.csf3, input );
  1339. default:
  1340. return TTO_Err_Invalid_GSUB_SubTable_Format;
  1341. }
  1342. return TT_Err_Ok; /* never reached */
  1343. }
  1344. void Free_ContextSubst( TTO_ContextSubst* cs )
  1345. {
  1346. switch ( cs->SubstFormat )
  1347. {
  1348. case 1:
  1349. Free_Context1( &cs->csf.csf1 );
  1350. break;
  1351. case 2:
  1352. Free_Context2( &cs->csf.csf2 );
  1353. break;
  1354. case 3:
  1355. Free_Context3( &cs->csf.csf3 );
  1356. break;
  1357. }
  1358. }
  1359. static TT_Error Lookup_ContextSubst1(
  1360. TTO_GSUBHeader* gsub,
  1361. TTO_ContextSubstFormat1* csf1,
  1362. TTO_GSUB_String* in,
  1363. TTO_GSUB_String* out,
  1364. UShort flags,
  1365. UShort context_length,
  1366. int nesting_level )
  1367. {
  1368. UShort index, property;
  1369. UShort i, j, k, numsr;
  1370. TT_Error error;
  1371. UShort* s_in;
  1372. TTO_SubRule* sr;
  1373. TTO_GDEFHeader* gdef;
  1374. gdef = gsub->gdef;
  1375. if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
  1376. return error;
  1377. error = Coverage_Index( &csf1->Coverage, in->string[in->pos], &index );
  1378. if ( error )
  1379. return error;
  1380. sr = csf1->SubRuleSet[index].SubRule;
  1381. numsr = csf1->SubRuleSet[index].SubRuleCount;
  1382. for ( k = 0; k < numsr; k++ )
  1383. {
  1384. if ( context_length != 0xFFFF && context_length < sr[k].GlyphCount )
  1385. continue;
  1386. if ( in->pos + sr[k].GlyphCount > in->length )
  1387. continue; /* context is too long */
  1388. s_in = &in->string[in->pos];
  1389. for ( i = 1, j = 1; i < sr[k].GlyphCount; i++, j++ )
  1390. {
  1391. while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
  1392. {
  1393. if ( error && error != TTO_Err_Not_Covered )
  1394. return error;
  1395. if ( in->pos + j < in->length )
  1396. j++;
  1397. else
  1398. break;
  1399. }
  1400. if ( s_in[j] != sr[k].Input[i - 1] )
  1401. break;
  1402. }
  1403. if ( i == sr[k].GlyphCount )
  1404. return Do_ContextSubst( gsub, sr[k].GlyphCount,
  1405. sr[k].SubstCount, sr[k].SubstLookupRecord,
  1406. in, out,
  1407. nesting_level );
  1408. }
  1409. return TTO_Err_Not_Covered;
  1410. }
  1411. static TT_Error Lookup_ContextSubst2(
  1412. TTO_GSUBHeader* gsub,
  1413. TTO_ContextSubstFormat2* csf2,
  1414. TTO_GSUB_String* in,
  1415. TTO_GSUB_String* out,
  1416. UShort flags,
  1417. UShort context_length,
  1418. int nesting_level )
  1419. {
  1420. UShort index, property;
  1421. TT_Error error;
  1422. UShort i, j, k, known_classes;
  1423. UShort* classes;
  1424. UShort* s_in;
  1425. UShort* cl;
  1426. TTO_SubClassSet* scs;
  1427. TTO_SubClassRule* sr;
  1428. TTO_GDEFHeader* gdef;
  1429. gdef = gsub->gdef;
  1430. if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, UShort ) )
  1431. return error;
  1432. if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
  1433. return error;
  1434. /* Note: The coverage table in format 2 doesn't give an index into
  1435. anything. It just lets us know whether or not we need to
  1436. do any lookup at all. */
  1437. error = Coverage_Index( &csf2->Coverage, in->string[in->pos], &index );
  1438. if ( error )
  1439. goto End;
  1440. error = Get_Class( &csf2->ClassDef, in->string[in->pos],
  1441. &classes[0], NULL );
  1442. if ( error )
  1443. goto End;
  1444. known_classes = 0;
  1445. scs = &csf2->SubClassSet[classes[0]];
  1446. if ( !scs )
  1447. {
  1448. error = TTO_Err_Invalid_GSUB_SubTable;
  1449. goto End;
  1450. }
  1451. for ( k = 0; k < scs->SubClassRuleCount; k++ )
  1452. {
  1453. sr = &scs->SubClassRule[k];
  1454. if ( context_length != 0xFFFF && context_length < sr->GlyphCount )
  1455. continue;
  1456. if ( in->pos + sr->GlyphCount > in->length )
  1457. continue; /* context is too long */
  1458. s_in = &in->string[in->pos];
  1459. cl = sr->Class;
  1460. /* Start at 1 because [0] is implied */
  1461. for ( i = 1, j = 1; i < sr->GlyphCount; i++, j++ )
  1462. {
  1463. while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
  1464. {
  1465. if ( error && error != TTO_Err_Not_Covered )
  1466. return error;
  1467. if ( in->pos + j < in->length )
  1468. j++;
  1469. else
  1470. break;
  1471. }
  1472. if ( i > known_classes )
  1473. {
  1474. /* Keeps us from having to do this for each rule */
  1475. error = Get_Class( &csf2->ClassDef, s_in[j], &classes[i], NULL );
  1476. if ( error && error != TTO_Err_Not_Covered )
  1477. return error;
  1478. known_classes = i;
  1479. }
  1480. if ( cl[i - 1] != classes[i] )
  1481. break;
  1482. }
  1483. if ( i == sr->GlyphCount )
  1484. {
  1485. error = Do_ContextSubst( gsub, sr->GlyphCount,
  1486. sr->SubstCount, sr->SubstLookupRecord,
  1487. in, out,
  1488. nesting_level );
  1489. goto End;
  1490. }
  1491. }
  1492. error = TTO_Err_Not_Covered;
  1493. End:
  1494. FREE( classes );
  1495. return error;
  1496. }
  1497. static TT_Error Lookup_ContextSubst3(
  1498. TTO_GSUBHeader* gsub,
  1499. TTO_ContextSubstFormat3* csf3,
  1500. TTO_GSUB_String* in,
  1501. TTO_GSUB_String* out,
  1502. UShort flags,
  1503. UShort context_length,
  1504. int nesting_level )
  1505. {
  1506. TT_Error error;
  1507. UShort index, i, j, property;
  1508. UShort* s_in;
  1509. TTO_Coverage* c;
  1510. TTO_GDEFHeader* gdef;
  1511. gdef = gsub->gdef;
  1512. if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
  1513. return error;
  1514. if ( context_length != 0xFFFF && context_length < csf3->GlyphCount )
  1515. return TTO_Err_Not_Covered;
  1516. if ( in->pos + csf3->GlyphCount > in->length )
  1517. return TTO_Err_Not_Covered; /* context is too long */
  1518. s_in = &in->string[in->pos];
  1519. c = csf3->Coverage;
  1520. for ( i = 1, j = 1; i < csf3->GlyphCount; i++, j++ )
  1521. {
  1522. while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
  1523. {
  1524. if ( error && error != TTO_Err_Not_Covered )
  1525. return error;
  1526. if ( in->pos + j < in->length )
  1527. j++;
  1528. else
  1529. return TTO_Err_Not_Covered;
  1530. }
  1531. error = Coverage_Index( &c[i], s_in[j], &index );
  1532. if ( error )
  1533. return error;
  1534. }
  1535. return Do_ContextSubst( gsub, csf3->GlyphCount,
  1536. csf3->SubstCount, csf3->SubstLookupRecord,
  1537. in, out,
  1538. nesting_level );
  1539. }
  1540. static TT_Error Lookup_ContextSubst( TTO_GSUBHeader* gsub,
  1541. TTO_ContextSubst* cs,
  1542. TTO_GSUB_String* in,
  1543. TTO_GSUB_String* out,
  1544. UShort flags,
  1545. UShort context_length,
  1546. int nesting_level )
  1547. {
  1548. switch ( cs->SubstFormat )
  1549. {
  1550. case 1:
  1551. return Lookup_ContextSubst1( gsub, &cs->csf.csf1, in, out,
  1552. flags, context_length, nesting_level );
  1553. case 2:
  1554. return Lookup_ContextSubst2( gsub, &cs->csf.csf2, in, out,
  1555. flags, context_length, nesting_level );
  1556. case 3:
  1557. return Lookup_ContextSubst3( gsub, &cs->csf.csf3, in, out,
  1558. flags, context_length, nesting_level );
  1559. default:
  1560. return TTO_Err_Invalid_GSUB_SubTable_Format;
  1561. }
  1562. return TT_Err_Ok; /* never reached */
  1563. }
  1564. /* LookupType 6 */
  1565. /* ChainSubRule */
  1566. static TT_Error Load_ChainSubRule( TTO_ChainSubRule* csr,
  1567. PFace input )
  1568. {
  1569. DEFINE_LOAD_LOCALS( input->stream );
  1570. UShort n, count;
  1571. UShort* b;
  1572. UShort* i;
  1573. UShort* l;
  1574. TTO_SubstLookupRecord* slr;
  1575. if ( ACCESS_Frame( 2L ) )
  1576. return error;
  1577. csr->BacktrackGlyphCount = GET_UShort();
  1578. FORGET_Frame();
  1579. csr->Backtrack = NULL;
  1580. count = csr->BacktrackGlyphCount;
  1581. if ( ALLOC_ARRAY( csr->Backtrack, count, UShort ) )
  1582. return error;
  1583. b = csr->Backtrack;
  1584. if ( ACCESS_Frame( count * 2L ) )
  1585. goto Fail4;
  1586. for ( n = 0; n < count; n++ )
  1587. b[n] = GET_UShort();
  1588. FORGET_Frame();
  1589. if ( ACCESS_Frame( 2L ) )
  1590. goto Fail4;
  1591. csr->InputGlyphCount = GET_UShort();
  1592. FORGET_Frame();
  1593. csr->Input = NULL;
  1594. count = csr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
  1595. if ( ALLOC_ARRAY( csr->Input, count, UShort ) )
  1596. goto Fail4;
  1597. i = csr->Input;
  1598. if ( ACCESS_Frame( count * 2L ) )
  1599. goto Fail3;
  1600. for ( n = 0; n < count; n++ )
  1601. i[n] = GET_UShort();
  1602. FORGET_Frame();
  1603. if ( ACCESS_Frame( 2L ) )
  1604. goto Fail3;
  1605. csr->LookaheadGlyphCount = GET_UShort();
  1606. FORGET_Frame();
  1607. csr->Lookahead = NULL;
  1608. count = csr->LookaheadGlyphCount;
  1609. if ( ALLOC_ARRAY( csr->Lookahead, count, UShort ) )
  1610. goto Fail3;
  1611. l = csr->Lookahead;
  1612. if ( ACCESS_Frame( count * 2L ) )
  1613. goto Fail2;
  1614. for ( n = 0; n < count; n++ )
  1615. l[n] = GET_UShort();
  1616. FORGET_Frame();
  1617. if ( ACCESS_Frame( 2L ) )
  1618. goto Fail2;
  1619. csr->SubstCount = GET_UShort();
  1620. FORGET_Frame();
  1621. csr->SubstLookupRecord = NULL;
  1622. count = csr->SubstCount;
  1623. if ( ALLOC_ARRAY( csr->SubstLookupRecord, count, TTO_SubstLookupRecord ) )
  1624. goto Fail2;
  1625. slr = csr->SubstLookupRecord;
  1626. if ( ACCESS_Frame( count * 4L ) )
  1627. goto Fail1;
  1628. for ( n = 0; n < count; n++ )
  1629. {
  1630. slr[n].SequenceIndex = GET_UShort();
  1631. slr[n].LookupListIndex = GET_UShort();
  1632. }
  1633. FORGET_Frame();
  1634. return TT_Err_Ok;
  1635. Fail1:
  1636. FREE( slr );
  1637. Fail2:
  1638. FREE( l );
  1639. Fail3:
  1640. FREE( i );
  1641. Fail4:
  1642. FREE( b );
  1643. return error;
  1644. }
  1645. static void Free_ChainSubRule( TTO_ChainSubRule* csr )
  1646. {
  1647. FREE( csr->SubstLookupRecord );
  1648. FREE( csr->Lookahead );
  1649. FREE( csr->Input );
  1650. FREE( csr->Backtrack );
  1651. }
  1652. /* ChainSubRuleSet */
  1653. static TT_Error Load_ChainSubRuleSet( TTO_ChainSubRuleSet* csrs,
  1654. PFace input )
  1655. {
  1656. DEFINE_LOAD_LOCALS( input->stream );
  1657. UShort n, count;
  1658. ULong cur_offset, new_offset, base_offset;
  1659. TTO_ChainSubRule* csr;
  1660. base_offset = FILE_Pos();
  1661. if ( ACCESS_Frame( 2L ) )
  1662. return error;
  1663. count = csrs->ChainSubRuleCount = GET_UShort();
  1664. FORGET_Frame();
  1665. csrs->ChainSubRule = NULL;
  1666. if ( ALLOC_ARRAY( csrs->ChainSubRule, count, TTO_ChainSubRule ) )
  1667. return error;
  1668. csr = csrs->ChainSubRule;
  1669. for ( n = 0; n < count; n++ )
  1670. {
  1671. if ( ACCESS_Frame( 2L ) )
  1672. goto Fail;
  1673. new_offset = GET_UShort() + base_offset;
  1674. FORGET_Frame();
  1675. cur_offset = FILE_Pos();
  1676. if ( FILE_Seek( new_offset ) ||
  1677. ( error = Load_ChainSubRule( &csr[n], input ) ) != TT_Err_Ok )
  1678. goto Fail;
  1679. (void)FILE_Seek( cur_offset );
  1680. }
  1681. return TT_Err_Ok;
  1682. Fail:
  1683. for ( n = 0; n < count; n++ )
  1684. Free_ChainSubRule( &csr[n] );
  1685. FREE( csr );
  1686. return error;
  1687. }
  1688. static void Free_ChainSubRuleSet( TTO_ChainSubRuleSet* csrs )
  1689. {
  1690. UShort n, count;
  1691. TTO_ChainSubRule* csr;
  1692. if ( csrs->ChainSubRule )
  1693. {
  1694. count = csrs->ChainSubRuleCount;
  1695. csr = csrs->ChainSubRule;
  1696. for ( n = 0; n < count; n++ )
  1697. Free_ChainSubRule( &csr[n] );
  1698. FREE( csr );
  1699. }
  1700. }
  1701. /* ChainContextSubstFormat1 */
  1702. static TT_Error Load_ChainContextSubst1(
  1703. TTO_ChainContextSubstFormat1* ccsf1,
  1704. PFace input )
  1705. {
  1706. DEFINE_LOAD_LOCALS( input->stream );
  1707. UShort n, count;
  1708. ULong cur_offset, new_offset, base_offset;
  1709. TTO_ChainSubRuleSet* csrs;
  1710. base_offset = FILE_Pos() - 2L;
  1711. if ( ACCESS_Frame( 2L ) )
  1712. return error;
  1713. new_offset = GET_UShort() + base_offset;
  1714. FORGET_Frame();
  1715. cur_offset = FILE_Pos();
  1716. if ( FILE_Seek( new_offset ) ||
  1717. ( error = Load_Coverage( &ccsf1->Coverage, input ) ) != TT_Err_Ok )
  1718. return error;
  1719. (void)FILE_Seek( cur_offset );
  1720. if ( ACCESS_Frame( 2L ) )
  1721. goto Fail2;
  1722. count = ccsf1->ChainSubRuleSetCount = GET_UShort();
  1723. FORGET_Frame();
  1724. ccsf1->ChainSubRuleSet = NULL;
  1725. if ( ALLOC_ARRAY( ccsf1->ChainSubRuleSet, count, TTO_ChainSubRuleSet ) )
  1726. goto Fail2;
  1727. csrs = ccsf1->ChainSubRuleSet;
  1728. for ( n = 0; n < count; n++ )
  1729. {
  1730. if ( ACCESS_Frame( 2L ) )
  1731. goto Fail1;
  1732. new_offset = GET_UShort() + base_offset;
  1733. FORGET_Frame();
  1734. cur_offset = FILE_Pos();
  1735. if ( FILE_Seek( new_offset ) ||
  1736. ( error = Load_ChainSubRuleSet( &csrs[n], input ) ) != TT_Err_Ok )
  1737. goto Fail1;
  1738. (void)FILE_Seek( cur_offset );
  1739. }
  1740. return TT_Err_Ok;
  1741. Fail1:
  1742. for ( n = 0; n < count; n++ )
  1743. Free_ChainSubRuleSet( &csrs[n] );
  1744. FREE( csrs );
  1745. Fail2:
  1746. Free_Coverage( &ccsf1->Coverage );
  1747. return error;
  1748. }
  1749. static void Free_ChainContext1( TTO_ChainContextSubstFormat1* ccsf1 )
  1750. {
  1751. UShort n, count;
  1752. TTO_ChainSubRuleSet* csrs;
  1753. if ( ccsf1->ChainSubRuleSet )
  1754. {
  1755. count = ccsf1->ChainSubRuleSetCount;
  1756. csrs = ccsf1->ChainSubRuleSet;
  1757. for ( n = 0; n < count; n++ )
  1758. Free_ChainSubRuleSet( &csrs[n] );
  1759. FREE( csrs );
  1760. }
  1761. Free_Coverage( &ccsf1->Coverage );
  1762. }
  1763. /* ChainSubClassRule */
  1764. static TT_Error Load_ChainSubClassRule(
  1765. TTO_ChainContextSubstFormat2* ccsf2,
  1766. TTO_ChainSubClassRule* cscr,
  1767. PFace input )
  1768. {
  1769. DEFINE_LOAD_LOCALS( input->stream );
  1770. UShort n, count;
  1771. UShort* b;
  1772. UShort* i;
  1773. UShort* l;
  1774. TTO_SubstLookupRecord* slr;
  1775. Bool* d;
  1776. if ( ACCESS_Frame( 2L ) )
  1777. return error;
  1778. cscr->BacktrackGlyphCount = GET_UShort();
  1779. FORGET_Frame();
  1780. if ( cscr->BacktrackGlyphCount > ccsf2->MaxBacktrackLength )
  1781. ccsf2->MaxBacktrackLength = cscr->BacktrackGlyphCount;
  1782. cscr->Backtrack = NULL;
  1783. count = cscr->BacktrackGlyphCount;
  1784. if ( ALLOC_ARRAY( cscr->Backtrack, count, UShort ) )
  1785. return error;
  1786. b = cscr->Backtrack;
  1787. d = ccsf2->BacktrackClassDef.Defined;
  1788. if ( ACCESS_Frame( count * 2L ) )
  1789. goto Fail4;
  1790. for ( n = 0; n < count; n++ )
  1791. {
  1792. b[n] = GET_UShort();
  1793. /* We check whether the specific class is used at all. If not,
  1794. class 0 is used instead. */
  1795. if ( !d[b[n]] )
  1796. b[n] = 0;
  1797. }
  1798. FORGET_Frame();
  1799. if ( ACCESS_Frame( 2L ) )
  1800. goto Fail4;
  1801. cscr->InputGlyphCount = GET_UShort();
  1802. FORGET_Frame();
  1803. if ( cscr->InputGlyphCount > ccsf2->MaxInputLength )
  1804. ccsf2->MaxInputLength = cscr->InputGlyphCount;
  1805. cscr->Input = NULL;
  1806. count = cscr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
  1807. if ( ALLOC_ARRAY( cscr->Input, count, UShort ) )
  1808. goto Fail4;
  1809. i = cscr->Input;
  1810. d = ccsf2->InputClassDef.Defined;
  1811. if ( ACCESS_Frame( count * 2L ) )
  1812. goto Fail3;
  1813. for ( n = 0; n < count; n++ )
  1814. {
  1815. i[n] = GET_UShort();
  1816. if ( !d[i[n]] )
  1817. i[n] = 0;
  1818. }
  1819. FORGET_Frame();
  1820. if ( ACCESS_Frame( 2L ) )
  1821. goto Fail3;
  1822. cscr->LookaheadGlyphCount = GET_UShort();
  1823. FORGET_Frame();
  1824. if ( cscr->LookaheadGlyphCount > ccsf2->MaxLookaheadLength )
  1825. ccsf2->MaxLookaheadLength = cscr->LookaheadGlyphCount;
  1826. cscr->Lookahead = NULL;
  1827. count = cscr->LookaheadGlyphCount;
  1828. if ( ALLOC_ARRAY( cscr->Lookahead, count, UShort ) )
  1829. goto Fail3;
  1830. l = cscr->Lookahead;
  1831. d = ccsf2->LookaheadClassDef.Defined;
  1832. if ( ACCESS_Frame( count * 2L ) )
  1833. goto Fail2;
  1834. for ( n = 0; n < count; n++ )
  1835. {
  1836. l[n] = GET_UShort();
  1837. if ( !d[l[n]] )
  1838. l[n] = 0;
  1839. }
  1840. FORGET_Frame();
  1841. if ( ACCESS_Frame( 2L ) )
  1842. goto Fail2;
  1843. cscr->SubstCount = GET_UShort();
  1844. FORGET_Frame();
  1845. cscr->SubstLookupRecord = NULL;
  1846. count = cscr->SubstCount;
  1847. if ( ALLOC_ARRAY( cscr->SubstLookupRecord, count,
  1848. TTO_SubstLookupRecord ) )
  1849. goto Fail2;
  1850. slr = cscr->SubstLookupRecord;
  1851. if ( ACCESS_Frame( count * 4L ) )
  1852. goto Fail1;
  1853. for ( n = 0; n < count; n++ )
  1854. {
  1855. slr[n].SequenceIndex = GET_UShort();
  1856. slr[n].LookupListIndex = GET_UShort();
  1857. }
  1858. FORGET_Frame();
  1859. return TT_Err_Ok;
  1860. Fail1:
  1861. FREE( slr );
  1862. Fail2:
  1863. FREE( l );
  1864. Fail3:
  1865. FREE( i );
  1866. Fail4:
  1867. FREE( b );
  1868. return error;
  1869. }
  1870. static void Free_ChainSubClassRule( TTO_ChainSubClassRule* cscr )
  1871. {
  1872. FREE( cscr->SubstLookupRecord );
  1873. FREE( cscr->Lookahead );
  1874. FREE( cscr->Input );
  1875. FREE( cscr->Backtrack );
  1876. }
  1877. /* SubClassSet */
  1878. static TT_Error Load_ChainSubClassSet(
  1879. TTO_ChainContextSubstFormat2* ccsf2,
  1880. TTO_ChainSubClassSet* cscs,
  1881. PFace input )
  1882. {
  1883. DEFINE_LOAD_LOCALS( input->stream );
  1884. UShort n, count;
  1885. ULong cur_offset, new_offset, base_offset;
  1886. TTO_ChainSubClassRule* cscr;
  1887. base_offset = FILE_Pos();
  1888. if ( ACCESS_Frame( 2L ) )
  1889. return error;
  1890. count = cscs->ChainSubClassRuleCount = GET_UShort();
  1891. FORGET_Frame();
  1892. cscs->ChainSubClassRule = NULL;
  1893. if ( ALLOC_ARRAY( cscs->ChainSubClassRule, count,
  1894. TTO_ChainSubClassRule ) )
  1895. return error;
  1896. cscr = cscs->ChainSubClassRule;
  1897. for ( n = 0; n < count; n++ )
  1898. {
  1899. if ( ACCESS_Frame( 2L ) )
  1900. goto Fail;
  1901. new_offset = GET_UShort() + base_offset;
  1902. FORGET_Frame();
  1903. cur_offset = FILE_Pos();
  1904. if ( FILE_Seek( new_offset ) ||
  1905. ( error = Load_ChainSubClassRule( ccsf2, &cscr[n],
  1906. input ) ) != TT_Err_Ok )
  1907. goto Fail;
  1908. (void)FILE_Seek( cur_offset );
  1909. }
  1910. return TT_Err_Ok;
  1911. Fail:
  1912. for ( n = 0; n < count; n++ )
  1913. Free_ChainSubClassRule( &cscr[n] );
  1914. FREE( cscr );
  1915. return error;
  1916. }
  1917. static void Free_ChainSubClassSet( TTO_ChainSubClassSet* cscs )
  1918. {
  1919. UShort n, count;
  1920. TTO_ChainSubClassRule* cscr;
  1921. if ( cscs->ChainSubClassRule )
  1922. {
  1923. count = cscs->ChainSubClassRuleCount;
  1924. cscr = cscs->ChainSubClassRule;
  1925. for ( n = 0; n < count; n++ )
  1926. Free_ChainSubClassRule( &cscr[n] );
  1927. FREE( cscr );
  1928. }
  1929. }
  1930. /* ChainContextSubstFormat2 */
  1931. static TT_Error Load_ChainContextSubst2(
  1932. TTO_ChainContextSubstFormat2* ccsf2,
  1933. PFace input )
  1934. {
  1935. DEFINE_LOAD_LOCALS( input->stream );
  1936. UShort n, count;
  1937. ULong cur_offset, new_offset, base_offset;
  1938. ULong backtrack_offset, input_offset, lookahead_offset;
  1939. TTO_ChainSubClassSet* cscs;
  1940. base_offset = FILE_Pos() - 2;
  1941. if ( ACCESS_Frame( 2L ) )
  1942. return error;
  1943. new_offset = GET_UShort() + base_offset;
  1944. FORGET_Frame();
  1945. cur_offset = FILE_Pos();
  1946. if ( FILE_Seek( new_offset ) ||
  1947. ( error = Load_Coverage( &ccsf2->Coverage, input ) ) != TT_Err_Ok )
  1948. return error;
  1949. (void)FILE_Seek( cur_offset );
  1950. if ( ACCESS_Frame( 8L ) )
  1951. goto Fail5;
  1952. backtrack_offset = GET_UShort() + base_offset;
  1953. input_offset = GET_UShort() + base_offset;
  1954. lookahead_offset = GET_UShort() + base_offset;
  1955. /* `ChainSubClassSetCount' is the upper limit for input class values,
  1956. thus we read it now to make an additional safety check. */
  1957. count = ccsf2->ChainSubClassSetCount = GET_UShort();
  1958. FORGET_Frame();
  1959. cur_offset = FILE_Pos();
  1960. if ( FILE_Seek( backtrack_offset ) ||
  1961. ( error = Load_ClassDefinition( &ccsf2->BacktrackClassDef, count,
  1962. input ) ) != TT_Err_Ok )
  1963. goto Fail5;
  1964. if ( FILE_Seek( input_offset ) ||
  1965. ( error = Load_ClassDefinition( &ccsf2->InputClassDef, count,
  1966. input ) ) != TT_Err_Ok )
  1967. goto Fail4;
  1968. if ( FILE_Seek( lookahead_offset ) ||
  1969. ( error = Load_ClassDefinition( &ccsf2->LookaheadClassDef, count,
  1970. input ) ) != TT_Err_Ok )
  1971. goto Fail3;
  1972. (void)FILE_Seek( cur_offset );
  1973. ccsf2->ChainSubClassSet = NULL;
  1974. ccsf2->MaxBacktrackLength = 0;
  1975. ccsf2->MaxInputLength = 0;
  1976. ccsf2->MaxLookaheadLength = 0;
  1977. if ( ALLOC_ARRAY( ccsf2->ChainSubClassSet, count, TTO_ChainSubClassSet ) )
  1978. goto Fail2;
  1979. cscs = ccsf2->ChainSubClassSet;
  1980. for ( n = 0; n < count; n++ )
  1981. {
  1982. if ( ACCESS_Frame( 2L ) )
  1983. goto Fail1;
  1984. new_offset = GET_UShort() + base_offset;
  1985. FORGET_Frame();
  1986. if ( new_offset != base_offset ) /* not a NULL offset */
  1987. {
  1988. cur_offset = FILE_Pos();
  1989. if ( FILE_Seek( new_offset ) ||
  1990. ( error = Load_ChainSubClassSet( ccsf2, &cscs[n],
  1991. input ) ) != TT_Err_Ok )
  1992. goto Fail1;
  1993. (void)FILE_Seek( cur_offset );
  1994. }
  1995. else
  1996. {
  1997. /* we create a ChainSubClassSet table with no entries */
  1998. ccsf2->ChainSubClassSet[n].ChainSubClassRuleCount = 0;
  1999. ccsf2->ChainSubClassSet[n].ChainSubClassRule = NULL;
  2000. }
  2001. }
  2002. return TT_Err_Ok;
  2003. Fail1:
  2004. for ( n = 0; n < count; n++ )
  2005. Free_ChainSubClassSet( &cscs[n] );
  2006. FREE( cscs );
  2007. Fail2:
  2008. Free_ClassDefinition( &ccsf2->LookaheadClassDef );
  2009. Fail3:
  2010. Free_ClassDefinition( &ccsf2->InputClassDef );
  2011. Fail4:
  2012. Free_ClassDefinition( &ccsf2->BacktrackClassDef );
  2013. Fail5:
  2014. Free_Coverage( &ccsf2->Coverage );
  2015. return error;
  2016. }
  2017. static void Free_ChainContext2( TTO_ChainContextSubstFormat2* ccsf2 )
  2018. {
  2019. UShort n, count;
  2020. TTO_ChainSubClassSet* cscs;
  2021. if ( ccsf2->ChainSubClassSet )
  2022. {
  2023. count = ccsf2->ChainSubClassSetCount;
  2024. cscs = ccsf2->ChainSubClassSet;
  2025. for ( n = 0; n < count; n++ )
  2026. Free_ChainSubClassSet( &cscs[n] );
  2027. FREE( cscs );
  2028. }
  2029. Free_ClassDefinition( &ccsf2->LookaheadClassDef );
  2030. Free_ClassDefinition( &ccsf2->InputClassDef );
  2031. Free_ClassDefinition( &ccsf2->BacktrackClassDef );
  2032. Free_Coverage( &ccsf2->Coverage );
  2033. }
  2034. /* ChainContextSubstFormat3 */
  2035. static TT_Error Load_ChainContextSubst3(
  2036. TTO_ChainContextSubstFormat3* ccsf3,
  2037. PFace input )
  2038. {
  2039. DEFINE_LOAD_LOCALS( input->stream );
  2040. UShort n, count;
  2041. UShort backtrack_count, input_count, lookahead_count;
  2042. ULong cur_offset, new_offset, base_offset;
  2043. TTO_Coverage* b;
  2044. TTO_Coverage* i;
  2045. TTO_Coverage* l;
  2046. TTO_SubstLookupRecord* slr;
  2047. base_offset = FILE_Pos() - 2L;
  2048. if ( ACCESS_Frame( 2L ) )
  2049. return error;
  2050. ccsf3->BacktrackGlyphCount = GET_UShort();
  2051. FORGET_Frame();
  2052. ccsf3->BacktrackCoverage = NULL;
  2053. backtrack_count = ccsf3->BacktrackGlyphCount;
  2054. if ( ALLOC_ARRAY( ccsf3->BacktrackCoverage, backtrack_count,
  2055. TTO_Coverage ) )
  2056. return error;
  2057. b = ccsf3->BacktrackCoverage;
  2058. for ( n = 0; n < backtrack_count; n++ )
  2059. {
  2060. if ( ACCESS_Frame( 2L ) )
  2061. goto Fail4;
  2062. new_offset = GET_UShort() + base_offset;
  2063. FORGET_Frame();
  2064. cur_offset = FILE_Pos();
  2065. if ( FILE_Seek( new_offset ) ||
  2066. ( error = Load_Coverage( &b[n], input ) ) != TT_Err_Ok )
  2067. goto Fail4;
  2068. (void)FILE_Seek( cur_offset );
  2069. }
  2070. if ( ACCESS_Frame( 2L ) )
  2071. goto Fail4;
  2072. ccsf3->InputGlyphCount = GET_UShort();
  2073. FORGET_Frame();
  2074. ccsf3->InputCoverage = NULL;
  2075. input_count = ccsf3->InputGlyphCount;
  2076. if ( ALLOC_ARRAY( ccsf3->InputCoverage, input_count, TTO_Coverage ) )
  2077. goto Fail4;
  2078. i = ccsf3->InputCoverage;
  2079. for ( n = 0; n < input_count; n++ )
  2080. {
  2081. if ( ACCESS_Frame( 2L ) )
  2082. goto Fail3;
  2083. new_offset = GET_UShort() + base_offset;
  2084. FORGET_Frame();
  2085. cur_offset = FILE_Pos();
  2086. if ( FILE_Seek( new_offset ) ||
  2087. ( error = Load_Coverage( &i[n], input ) ) != TT_Err_Ok )
  2088. goto Fail3;
  2089. (void)FILE_Seek( cur_offset );
  2090. }
  2091. if ( ACCESS_Frame( 2L ) )
  2092. goto Fail3;
  2093. ccsf3->LookaheadGlyphCount = GET_UShort();
  2094. FORGET_Frame();
  2095. ccsf3->LookaheadCoverage = NULL;
  2096. lookahead_count = ccsf3->LookaheadGlyphCount;
  2097. if ( ALLOC_ARRAY( ccsf3->LookaheadCoverage, lookahead_count,
  2098. TTO_Coverage ) )
  2099. goto Fail3;
  2100. l = ccsf3->LookaheadCoverage;
  2101. for ( n = 0; n < lookahead_count; n++ )
  2102. {
  2103. if ( ACCESS_Frame( 2L ) )
  2104. goto Fail2;
  2105. new_offset = GET_UShort() + base_offset;
  2106. FORGET_Frame();
  2107. cur_offset = FILE_Pos();
  2108. if ( FILE_Seek( new_offset ) ||
  2109. ( error = Load_Coverage( &l[n], input ) ) != TT_Err_Ok )
  2110. goto Fail2;
  2111. (void)FILE_Seek( cur_offset );
  2112. }
  2113. if ( ACCESS_Frame( 2L ) )
  2114. goto Fail2;
  2115. ccsf3->SubstCount = GET_UShort();
  2116. FORGET_Frame();
  2117. ccsf3->SubstLookupRecord = NULL;
  2118. count = ccsf3->SubstCount;
  2119. if ( ALLOC_ARRAY( ccsf3->SubstLookupRecord, count,
  2120. TTO_SubstLookupRecord ) )
  2121. goto Fail2;
  2122. slr = ccsf3->SubstLookupRecord;
  2123. if ( ACCESS_Frame( count * 4L ) )
  2124. goto Fail1;
  2125. for ( n = 0; n < count; n++ )
  2126. {
  2127. slr[n].SequenceIndex = GET_UShort();
  2128. slr[n].LookupListIndex = GET_UShort();
  2129. }
  2130. FORGET_Frame();
  2131. return TT_Err_Ok;
  2132. Fail1:
  2133. FREE( slr );
  2134. Fail2:
  2135. for ( n = 0; n < lookahead_count; n++ )
  2136. Free_Coverage( &l[n] );
  2137. FREE( l );
  2138. Fail3:
  2139. for ( n = 0; n < input_count; n++ )
  2140. Free_Coverage( &i[n] );
  2141. FREE( i );
  2142. Fail4:
  2143. for ( n = 0; n < backtrack_count; n++ )
  2144. Free_Coverage( &b[n] );
  2145. FREE( b );
  2146. return error;
  2147. }
  2148. static void Free_ChainContext3( TTO_ChainContextSubstFormat3* ccsf3 )
  2149. {
  2150. UShort n, count;
  2151. TTO_Coverage* c;
  2152. FREE( ccsf3->SubstLookupRecord );
  2153. if ( ccsf3->LookaheadCoverage )
  2154. {
  2155. count = ccsf3->LookaheadGlyphCount;
  2156. c = ccsf3->LookaheadCoverage;
  2157. for ( n = 0; n < count; n++ )
  2158. Free_Coverage( &c[n] );
  2159. FREE( c );
  2160. }
  2161. if ( ccsf3->InputCoverage )
  2162. {
  2163. count = ccsf3->InputGlyphCount;
  2164. c = ccsf3->InputCoverage;
  2165. for ( n = 0; n < count; n++ )
  2166. Free_Coverage( &c[n] );
  2167. FREE( c );
  2168. }
  2169. if ( ccsf3->BacktrackCoverage )
  2170. {
  2171. count = ccsf3->BacktrackGlyphCount;
  2172. c = ccsf3->BacktrackCoverage;
  2173. for ( n = 0; n < count; n++ )
  2174. Free_Coverage( &c[n] );
  2175. FREE( c );
  2176. }
  2177. }
  2178. /* ChainContextSubst */
  2179. TT_Error Load_ChainContextSubst( TTO_ChainContextSubst* ccs,
  2180. PFace input )
  2181. {
  2182. DEFINE_LOAD_LOCALS( input->stream );
  2183. if ( ACCESS_Frame( 2L ) )
  2184. return error;
  2185. ccs->SubstFormat = GET_UShort();
  2186. FORGET_Frame();
  2187. switch ( ccs->SubstFormat )
  2188. {
  2189. case 1:
  2190. return Load_ChainContextSubst1( &ccs->ccsf.ccsf1, input );
  2191. case 2:
  2192. return Load_ChainContextSubst2( &ccs->ccsf.ccsf2, input );
  2193. case 3:
  2194. return Load_ChainContextSubst3( &ccs->ccsf.ccsf3, input );
  2195. default:
  2196. return TTO_Err_Invalid_GSUB_SubTable_Format;
  2197. }
  2198. return TT_Err_Ok; /* never reached */
  2199. }
  2200. void Free_ChainContextSubst( TTO_ChainContextSubst* ccs )
  2201. {
  2202. switch ( ccs->SubstFormat )
  2203. {
  2204. case 1:
  2205. Free_ChainContext1( &ccs->ccsf.ccsf1 );
  2206. break;
  2207. case 2:
  2208. Free_ChainContext2( &ccs->ccsf.ccsf2 );
  2209. break;
  2210. case 3:
  2211. Free_ChainContext3( &ccs->ccsf.ccsf3 );
  2212. break;
  2213. }
  2214. }
  2215. static TT_Error Lookup_ChainContextSubst1(
  2216. TTO_GSUBHeader* gsub,
  2217. TTO_ChainContextSubstFormat1* ccsf1,
  2218. TTO_GSUB_String* in,
  2219. TTO_GSUB_String* out,
  2220. UShort flags,
  2221. UShort context_length,
  2222. int nesting_level )
  2223. {
  2224. UShort index, property;
  2225. UShort i, j, k, num_csr, curr_pos;
  2226. UShort bgc, igc, lgc;
  2227. TT_Error error;
  2228. UShort* s_in;
  2229. TTO_ChainSubRule* csr;
  2230. TTO_ChainSubRule curr_csr;
  2231. TTO_GDEFHeader* gdef;
  2232. gdef = gsub->gdef;
  2233. if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
  2234. return error;
  2235. error = Coverage_Index( &ccsf1->Coverage, in->string[in->pos], &index );
  2236. if ( error )
  2237. return error;
  2238. csr = ccsf1->ChainSubRuleSet[index].ChainSubRule;
  2239. num_csr = ccsf1->ChainSubRuleSet[index].ChainSubRuleCount;
  2240. for ( k = 0; k < num_csr; k++ )
  2241. {
  2242. curr_csr = csr[k];
  2243. bgc = curr_csr.BacktrackGlyphCount;
  2244. igc = curr_csr.InputGlyphCount;
  2245. lgc = curr_csr.LookaheadGlyphCount;
  2246. if ( context_length != 0xFFFF && context_length < igc )
  2247. continue;
  2248. /* check whether context is too long; it is a first guess only */
  2249. if ( bgc > in->pos || in->pos + igc + lgc > in->length )
  2250. continue;
  2251. if ( bgc )
  2252. {
  2253. /* Since we don't know in advance the number of glyphs to inspect,
  2254. we search backwards for matches in the backtrack glyph array */
  2255. curr_pos = 0;
  2256. s_in = &in->string[curr_pos];
  2257. for ( i = bgc, j = in->pos - 1; i > 0; i--, j-- )
  2258. {
  2259. while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
  2260. {
  2261. if ( error && error != TTO_Err_Not_Covered )
  2262. return error;
  2263. if ( j > curr_pos )
  2264. j--;
  2265. else
  2266. break;
  2267. }
  2268. if ( s_in[j] != curr_csr.Backtrack[i - 1] )
  2269. break;
  2270. }
  2271. if ( i != 0 )
  2272. continue;
  2273. }
  2274. curr_pos = in->pos;
  2275. s_in = &in->string[curr_pos];
  2276. /* Start at 1 because [0] is implied */
  2277. for ( i = 1, j = 1; i < igc; i++, j++ )
  2278. {
  2279. while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
  2280. {
  2281. if ( error && error != TTO_Err_Not_Covered )
  2282. return error;
  2283. if ( curr_pos + j < in->length )
  2284. j++;
  2285. else
  2286. break;
  2287. }
  2288. if ( s_in[j] != curr_csr.Input[i - 1] )
  2289. break;
  2290. }
  2291. if ( i != igc )
  2292. continue;
  2293. /* we are starting to check for lookahead glyphs right after the
  2294. last context glyph */
  2295. curr_pos = j;
  2296. s_in = &in->string[curr_pos];
  2297. for ( i = 0, j = 0; i < lgc; i++, j++ )
  2298. {
  2299. while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
  2300. {
  2301. if ( error && error != TTO_Err_Not_Covered )
  2302. return error;
  2303. if ( curr_pos + j < in->length )
  2304. j++;
  2305. else
  2306. break;
  2307. }
  2308. if ( s_in[j] != curr_csr.Lookahead[i] )
  2309. break;
  2310. }
  2311. if ( i == lgc )
  2312. return Do_ContextSubst( gsub, igc,
  2313. curr_csr.SubstCount,
  2314. curr_csr.SubstLookupRecord,
  2315. in, out,
  2316. nesting_level );
  2317. }
  2318. return TTO_Err_Not_Covered;
  2319. }
  2320. static TT_Error Lookup_ChainContextSubst2(
  2321. TTO_GSUBHeader* gsub,
  2322. TTO_ChainContextSubstFormat2* ccsf2,
  2323. TTO_GSUB_String* in,
  2324. TTO_GSUB_String* out,
  2325. UShort flags,
  2326. UShort context_length,
  2327. int nesting_level )
  2328. {
  2329. UShort index, property;
  2330. TT_Error error;
  2331. UShort i, j, k, curr_pos;
  2332. UShort bgc, igc, lgc;
  2333. UShort known_backtrack_classes,
  2334. known_input_classes,
  2335. known_lookahead_classes;
  2336. UShort* backtrack_classes;
  2337. UShort* input_classes;
  2338. UShort* lookahead_classes;
  2339. UShort* s_in;
  2340. UShort* bc;
  2341. UShort* ic;
  2342. UShort* lc;
  2343. TTO_ChainSubClassSet* cscs;
  2344. TTO_ChainSubClassRule ccsr;
  2345. TTO_GDEFHeader* gdef;
  2346. gdef = gsub->gdef;
  2347. if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
  2348. return error;
  2349. /* Note: The coverage table in format 2 doesn't give an index into
  2350. anything. It just lets us know whether or not we need to
  2351. do any lookup at all. */
  2352. error = Coverage_Index( &ccsf2->Coverage, in->string[in->pos], &index );
  2353. if ( error )
  2354. return error;
  2355. if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, UShort ) )
  2356. return error;
  2357. known_backtrack_classes = 0;
  2358. if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, UShort ) )
  2359. goto End3;
  2360. known_input_classes = 1;
  2361. if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, UShort ) )
  2362. goto End2;
  2363. known_lookahead_classes = 0;
  2364. error = Get_Class( &ccsf2->InputClassDef, in->string[in->pos],
  2365. &input_classes[0], NULL );
  2366. if ( error )
  2367. goto End1;
  2368. cscs = &ccsf2->ChainSubClassSet[input_classes[0]];
  2369. if ( !cscs )
  2370. {
  2371. error = TTO_Err_Invalid_GSUB_SubTable;
  2372. goto End1;
  2373. }
  2374. for ( k = 0; k < cscs->ChainSubClassRuleCount; k++ )
  2375. {
  2376. ccsr = cscs->ChainSubClassRule[k];
  2377. bgc = ccsr.BacktrackGlyphCount;
  2378. igc = ccsr.InputGlyphCount;
  2379. lgc = ccsr.LookaheadGlyphCount;
  2380. if ( context_length != 0xFFFF && context_length < igc )
  2381. continue;
  2382. /* check whether context is too long; it is a first guess only */
  2383. if ( bgc > in->pos || in->pos + igc + lgc > in->length )
  2384. continue;
  2385. if ( bgc )
  2386. {
  2387. /* Since we don't know in advance the number of glyphs to inspect,
  2388. we search backwards for matches in the backtrack glyph array.
  2389. Note that `known_backtrack_classes' starts at index 0. */
  2390. curr_pos = 0;
  2391. s_in = &in->string[curr_pos];
  2392. bc = ccsr.Backtrack;
  2393. for ( i = 0, j = in->pos - 1; i < bgc; i++, j-- )
  2394. {
  2395. while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
  2396. {
  2397. if ( error && error != TTO_Err_Not_Covered )
  2398. return error;
  2399. if ( j > curr_pos )
  2400. j--;
  2401. else
  2402. break;
  2403. }
  2404. if ( i >= known_backtrack_classes )
  2405. {
  2406. /* Keeps us from having to do this for each rule */
  2407. error = Get_Class( &ccsf2->BacktrackClassDef, s_in[j],
  2408. &backtrack_classes[i], NULL );
  2409. if ( error && error != TTO_Err_Not_Covered )
  2410. goto End1;
  2411. known_backtrack_classes = i;
  2412. }
  2413. if ( bc[bgc - 1 - i] != backtrack_classes[i] )
  2414. break;
  2415. }
  2416. if ( i != bgc )
  2417. continue;
  2418. }
  2419. curr_pos = in->pos;
  2420. s_in = &in->string[curr_pos];
  2421. ic = ccsr.Input;
  2422. /* Start at 1 because [0] is implied */
  2423. for ( i = 1, j = 1; i < igc; i++, j++ )
  2424. {
  2425. while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
  2426. {
  2427. if ( error && error != TTO_Err_Not_Covered )
  2428. goto End1;
  2429. if ( curr_pos + j < in->length )
  2430. j++;
  2431. else
  2432. break;
  2433. }
  2434. if ( i >= known_input_classes )
  2435. {
  2436. error = Get_Class( &ccsf2->InputClassDef, s_in[j],
  2437. &input_classes[i], NULL );
  2438. if ( error && error != TTO_Err_Not_Covered )
  2439. goto End1;
  2440. known_input_classes = i;
  2441. }
  2442. if ( ic[i - 1] != input_classes[i] )
  2443. break;
  2444. }
  2445. if ( i != igc )
  2446. continue;
  2447. /* we are starting to check for lookahead glyphs right after the
  2448. last context glyph */
  2449. curr_pos = j;
  2450. s_in = &in->string[curr_pos];
  2451. lc = ccsr.Lookahead;
  2452. for ( i = 0, j = 0; i < lgc; i++, j++ )
  2453. {
  2454. while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
  2455. {
  2456. if ( error && error != TTO_Err_Not_Covered )
  2457. return error;
  2458. if ( curr_pos + j < in->length )
  2459. j++;
  2460. else
  2461. break;
  2462. }
  2463. if ( i >= known_lookahead_classes )
  2464. {
  2465. error = Get_Class( &ccsf2->LookaheadClassDef, s_in[j],
  2466. &lookahead_classes[i], NULL );
  2467. if ( error && error != TTO_Err_Not_Covered )
  2468. goto End1;
  2469. known_lookahead_classes = i;
  2470. }
  2471. if ( lc[i] != lookahead_classes[i] )
  2472. break;
  2473. }
  2474. if ( i == lgc )
  2475. {
  2476. error = Do_ContextSubst( gsub, igc,
  2477. ccsr.SubstCount,
  2478. ccsr.SubstLookupRecord,
  2479. in, out,
  2480. nesting_level );
  2481. goto End1;
  2482. }
  2483. }
  2484. error = TTO_Err_Not_Covered;
  2485. End1:
  2486. FREE( lookahead_classes );
  2487. End2:
  2488. FREE( input_classes );
  2489. End3:
  2490. FREE( backtrack_classes );
  2491. return error;
  2492. }
  2493. static TT_Error Lookup_ChainContextSubst3(
  2494. TTO_GSUBHeader* gsub,
  2495. TTO_ChainContextSubstFormat3* ccsf3,
  2496. TTO_GSUB_String* in,
  2497. TTO_GSUB_String* out,
  2498. UShort flags,
  2499. UShort context_length,
  2500. int nesting_level )
  2501. {
  2502. UShort index, i, j, curr_pos, property;
  2503. UShort bgc, igc, lgc;
  2504. TT_Error error;
  2505. UShort* s_in;
  2506. TTO_Coverage* bc;
  2507. TTO_Coverage* ic;
  2508. TTO_Coverage* lc;
  2509. TTO_GDEFHeader* gdef;
  2510. gdef = gsub->gdef;
  2511. if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) )
  2512. return error;
  2513. bgc = ccsf3->BacktrackGlyphCount;
  2514. igc = ccsf3->InputGlyphCount;
  2515. lgc = ccsf3->LookaheadGlyphCount;
  2516. if ( context_length != 0xFFFF && context_length < igc )
  2517. return TTO_Err_Not_Covered;
  2518. /* check whether context is too long; it is a first guess only */
  2519. if ( bgc > in->pos || in->pos + igc + lgc > in->length )
  2520. return TTO_Err_Not_Covered;
  2521. if ( bgc )
  2522. {
  2523. /* Since we don't know in advance the number of glyphs to inspect,
  2524. we search backwards for matches in the backtrack glyph array */
  2525. curr_pos = 0;
  2526. s_in = &in->string[curr_pos];
  2527. bc = ccsf3->BacktrackCoverage;
  2528. for ( i = bgc, j = in->pos - 1; i > 0; i--, j-- )
  2529. {
  2530. while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
  2531. {
  2532. if ( error && error != TTO_Err_Not_Covered )
  2533. return error;
  2534. if ( j > curr_pos )
  2535. j--;
  2536. else
  2537. return TTO_Err_Not_Covered;
  2538. }
  2539. error = Coverage_Index( &bc[i - 1], s_in[j], &index );
  2540. if ( error )
  2541. return error;
  2542. }
  2543. }
  2544. curr_pos = in->pos;
  2545. s_in = &in->string[curr_pos];
  2546. ic = ccsf3->InputCoverage;
  2547. /* Start at 1 because [0] is implied */
  2548. for ( i = 1, j = 1; i < igc; i++, j++ )
  2549. {
  2550. while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
  2551. {
  2552. if ( error && error != TTO_Err_Not_Covered )
  2553. return error;
  2554. if ( curr_pos + j < in->length )
  2555. j++;
  2556. else
  2557. return TTO_Err_Not_Covered;
  2558. }
  2559. error = Coverage_Index( &ic[i], s_in[j], &index );
  2560. if ( error )
  2561. return error;
  2562. }
  2563. /* we are starting for lookahead glyphs right after the last context
  2564. glyph */
  2565. curr_pos = j;
  2566. s_in = &in->string[curr_pos];
  2567. lc = ccsf3->LookaheadCoverage;
  2568. for ( i = 0, j = 0; i < lgc; i++, j++ )
  2569. {
  2570. while ( CHECK_Property( gdef, s_in[j], flags, &property ) )
  2571. {
  2572. if ( error && error != TTO_Err_Not_Covered )
  2573. return error;
  2574. if ( curr_pos + j < in->length )
  2575. j++;
  2576. else
  2577. return TTO_Err_Not_Covered;
  2578. }
  2579. error = Coverage_Index( &lc[i], s_in[j], &index );
  2580. if ( error )
  2581. return error;
  2582. }
  2583. return Do_ContextSubst( gsub, igc,
  2584. ccsf3->SubstCount,
  2585. ccsf3->SubstLookupRecord,
  2586. in, out,
  2587. nesting_level );
  2588. }
  2589. static TT_Error Lookup_ChainContextSubst(
  2590. TTO_GSUBHeader* gsub,
  2591. TTO_ChainContextSubst* ccs,
  2592. TTO_GSUB_String* in,
  2593. TTO_GSUB_String* out,
  2594. UShort flags,
  2595. UShort context_length,
  2596. int nesting_level )
  2597. {
  2598. switch ( ccs->SubstFormat )
  2599. {
  2600. case 1:
  2601. return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, in, out,
  2602. flags, context_length,
  2603. nesting_level );
  2604. case 2:
  2605. return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, in, out,
  2606. flags, context_length,
  2607. nesting_level );
  2608. case 3:
  2609. return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, in, out,
  2610. flags, context_length,
  2611. nesting_level );
  2612. default:
  2613. return TTO_Err_Invalid_GSUB_SubTable_Format;
  2614. }
  2615. return TT_Err_Ok; /* never reached */
  2616. }
  2617. /***********
  2618. * GSUB API
  2619. ***********/
  2620. EXPORT_FUNC
  2621. TT_Error TT_GSUB_Select_Script( TTO_GSUBHeader* gsub,
  2622. TT_ULong script_tag,
  2623. TT_UShort* script_index )
  2624. {
  2625. UShort n;
  2626. TTO_ScriptList* sl;
  2627. TTO_ScriptRecord* sr;
  2628. if ( !gsub || !script_index )
  2629. return TT_Err_Invalid_Argument;
  2630. sl = &gsub->ScriptList;
  2631. sr = sl->ScriptRecord;
  2632. for ( n = 0; n < sl->ScriptCount; n++ )
  2633. if ( script_tag == sr[n].ScriptTag )
  2634. {
  2635. *script_index = n;
  2636. return TT_Err_Ok;
  2637. }
  2638. return TTO_Err_Not_Covered;
  2639. }
  2640. EXPORT_FUNC
  2641. TT_Error TT_GSUB_Select_Language( TTO_GSUBHeader* gsub,
  2642. TT_ULong language_tag,
  2643. TT_UShort script_index,
  2644. TT_UShort* language_index,
  2645. TT_UShort* req_feature_index )
  2646. {
  2647. UShort n;
  2648. TTO_ScriptList* sl;
  2649. TTO_ScriptRecord* sr;
  2650. TTO_Script* s;
  2651. TTO_LangSysRecord* lsr;
  2652. if ( !gsub || !language_index || !req_feature_index )
  2653. return TT_Err_Invalid_Argument;
  2654. sl = &gsub->ScriptList;
  2655. sr = sl->ScriptRecord;
  2656. if ( script_index >= sl->ScriptCount )
  2657. return TT_Err_Invalid_Argument;
  2658. s = &sr[script_index].Script;
  2659. lsr = s->LangSysRecord;
  2660. for ( n = 0; n < s->LangSysCount; n++ )
  2661. if ( language_tag == lsr[n].LangSysTag )
  2662. {
  2663. *language_index = n;
  2664. *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
  2665. return TT_Err_Ok;
  2666. }
  2667. return TTO_Err_Not_Covered;
  2668. }
  2669. /* selecting 0xFFFF for language_index asks for the values of the
  2670. default language (DefaultLangSys) */
  2671. EXPORT_FUNC
  2672. TT_Error TT_GSUB_Select_Feature( TTO_GSUBHeader* gsub,
  2673. TT_ULong feature_tag,
  2674. TT_UShort script_index,
  2675. TT_UShort language_index,
  2676. TT_UShort* feature_index )
  2677. {
  2678. UShort n;
  2679. TTO_ScriptList* sl;
  2680. TTO_ScriptRecord* sr;
  2681. TTO_Script* s;
  2682. TTO_LangSysRecord* lsr;
  2683. TTO_LangSys* ls;
  2684. UShort* fi;
  2685. TTO_FeatureList* fl;
  2686. TTO_FeatureRecord* fr;
  2687. if ( !gsub || !feature_index )
  2688. return TT_Err_Invalid_Argument;
  2689. sl = &gsub->ScriptList;
  2690. sr = sl->ScriptRecord;
  2691. fl = &gsub->FeatureList;
  2692. fr = fl->FeatureRecord;
  2693. if ( script_index >= sl->ScriptCount )
  2694. return TT_Err_Invalid_Argument;
  2695. s = &sr[script_index].Script;
  2696. lsr = s->LangSysRecord;
  2697. if ( language_index == 0xFFFF )
  2698. ls = &s->DefaultLangSys;
  2699. else
  2700. {
  2701. if ( language_index >= s->LangSysCount )
  2702. return TT_Err_Invalid_Argument;
  2703. ls = &lsr[language_index].LangSys;
  2704. }
  2705. fi = ls->FeatureIndex;
  2706. for ( n = 0; n < ls->FeatureCount; n++ )
  2707. {
  2708. if ( fi[n] >= fl->FeatureCount )
  2709. return TTO_Err_Invalid_GSUB_SubTable_Format;
  2710. if ( feature_tag == fr[fi[n]].FeatureTag )
  2711. {
  2712. *feature_index = fi[n];
  2713. return TT_Err_Ok;
  2714. }
  2715. }
  2716. return TTO_Err_Not_Covered;
  2717. }
  2718. /* The next three functions return a null-terminated list */
  2719. EXPORT_FUNC
  2720. TT_Error TT_GSUB_Query_Scripts( TTO_GSUBHeader* gsub,
  2721. TT_ULong** script_tag_list )
  2722. {
  2723. UShort n;
  2724. TT_Error error;
  2725. ULong* stl;
  2726. TTO_ScriptList* sl;
  2727. TTO_ScriptRecord* sr;
  2728. if ( !gsub || !script_tag_list )
  2729. return TT_Err_Invalid_Argument;
  2730. sl = &gsub->ScriptList;
  2731. sr = sl->ScriptRecord;
  2732. if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, ULong ) )
  2733. return error;
  2734. for ( n = 0; n < sl->ScriptCount; n++ )
  2735. stl[n] = sr[n].ScriptTag;
  2736. stl[n] = 0;
  2737. *script_tag_list = stl;
  2738. return TT_Err_Ok;
  2739. }
  2740. EXPORT_FUNC
  2741. TT_Error TT_GSUB_Query_Languages( TTO_GSUBHeader* gsub,
  2742. TT_UShort script_index,
  2743. TT_ULong** language_tag_list )
  2744. {
  2745. UShort n;
  2746. TT_Error error;
  2747. ULong* ltl;
  2748. TTO_ScriptList* sl;
  2749. TTO_ScriptRecord* sr;
  2750. TTO_Script* s;
  2751. TTO_LangSysRecord* lsr;
  2752. if ( !gsub || !language_tag_list )
  2753. return TT_Err_Invalid_Argument;
  2754. sl = &gsub->ScriptList;
  2755. sr = sl->ScriptRecord;
  2756. if ( script_index >= sl->ScriptCount )
  2757. return TT_Err_Invalid_Argument;
  2758. s = &sr[script_index].Script;
  2759. lsr = s->LangSysRecord;
  2760. if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, ULong ) )
  2761. return error;
  2762. for ( n = 0; n < s->LangSysCount; n++ )
  2763. ltl[n] = lsr[n].LangSysTag;
  2764. ltl[n] = 0;
  2765. *language_tag_list = ltl;
  2766. return TT_Err_Ok;
  2767. }
  2768. /* selecting 0xFFFF for language_index asks for the values of the
  2769. default language (DefaultLangSys) */
  2770. EXPORT_FUNC
  2771. TT_Error TT_GSUB_Query_Features( TTO_GSUBHeader* gsub,
  2772. TT_UShort script_index,
  2773. TT_UShort language_index,
  2774. TT_ULong** feature_tag_list )
  2775. {
  2776. UShort n;
  2777. TT_Error error;
  2778. ULong* ftl;
  2779. TTO_ScriptList* sl;
  2780. TTO_ScriptRecord* sr;
  2781. TTO_Script* s;
  2782. TTO_LangSysRecord* lsr;
  2783. TTO_LangSys* ls;
  2784. UShort* fi;
  2785. TTO_FeatureList* fl;
  2786. TTO_FeatureRecord* fr;
  2787. if ( !gsub || !feature_tag_list )
  2788. return TT_Err_Invalid_Argument;
  2789. sl = &gsub->ScriptList;
  2790. sr = sl->ScriptRecord;
  2791. fl = &gsub->FeatureList;
  2792. fr = fl->FeatureRecord;
  2793. if ( script_index >= sl->ScriptCount )
  2794. return TT_Err_Invalid_Argument;
  2795. s = &sr[script_index].Script;
  2796. lsr = s->LangSysRecord;
  2797. if ( language_index == 0xFFFF )
  2798. ls = &s->DefaultLangSys;
  2799. else
  2800. {
  2801. if ( language_index >= s->LangSysCount )
  2802. return TT_Err_Invalid_Argument;
  2803. ls = &lsr[language_index].LangSys;
  2804. }
  2805. fi = ls->FeatureIndex;
  2806. if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, ULong ) )
  2807. return error;
  2808. for ( n = 0; n < ls->FeatureCount; n++ )
  2809. {
  2810. if ( fi[n] >= fl->FeatureCount )
  2811. {
  2812. FREE( ftl );
  2813. return TTO_Err_Invalid_GSUB_SubTable_Format;
  2814. }
  2815. ftl[n] = fr[fi[n]].FeatureTag;
  2816. }
  2817. ftl[n] = 0;
  2818. *feature_tag_list = ftl;
  2819. return TT_Err_Ok;
  2820. }
  2821. /* Do an individual subtable lookup. Returns TT_Err_Ok if substitution
  2822. has been done, or TTO_Err_Not_Covered if not. */
  2823. static TT_Error Do_Glyph_Lookup( TTO_GSUBHeader* gsub,
  2824. UShort lookup_index,
  2825. TTO_GSUB_String* in,
  2826. TTO_GSUB_String* out,
  2827. UShort context_length,
  2828. int nesting_level )
  2829. {
  2830. TT_Error error = TT_Err_Ok;
  2831. UShort i, flags;
  2832. TTO_Lookup* lo;
  2833. nesting_level++;
  2834. if ( nesting_level > TTO_MAX_NESTING_LEVEL )
  2835. return TTO_Err_Too_Many_Nested_Contexts;
  2836. lo = &gsub->LookupList.Lookup[lookup_index];
  2837. flags = lo->LookupFlag;
  2838. for ( i = 0; i < lo->SubTableCount; i++ )
  2839. {
  2840. switch ( lo->LookupType )
  2841. {
  2842. case GSUB_LOOKUP_SINGLE:
  2843. error = Lookup_SingleSubst( &lo->SubTable[i].st.gsub.single,
  2844. in, out,
  2845. flags, context_length, gsub->gdef );
  2846. break;
  2847. case GSUB_LOOKUP_MULTIPLE:
  2848. error = Lookup_MultipleSubst( &lo->SubTable[i].st.gsub.multiple,
  2849. in, out,
  2850. flags, context_length, gsub->gdef );
  2851. break;
  2852. case GSUB_LOOKUP_ALTERNATE:
  2853. error = Lookup_AlternateSubst( gsub,
  2854. &lo->SubTable[i].st.gsub.alternate,
  2855. in, out,
  2856. flags, context_length, gsub->gdef );
  2857. break;
  2858. case GSUB_LOOKUP_LIGATURE:
  2859. error = Lookup_LigatureSubst( &lo->SubTable[i].st.gsub.ligature,
  2860. in, out,
  2861. flags, context_length, gsub->gdef );
  2862. break;
  2863. case GSUB_LOOKUP_CONTEXT:
  2864. error = Lookup_ContextSubst( gsub, &lo->SubTable[i].st.gsub.context,
  2865. in, out,
  2866. flags, context_length, nesting_level );
  2867. break;
  2868. case GSUB_LOOKUP_CHAIN:
  2869. error = Lookup_ChainContextSubst( gsub,
  2870. &lo->SubTable[i].st.gsub.chain,
  2871. in, out,
  2872. flags, context_length,
  2873. nesting_level );
  2874. break;
  2875. }
  2876. /* Check whether we have a successful substitution or an error other
  2877. than TTO_Err_Not_Covered */
  2878. if ( error != TTO_Err_Not_Covered )
  2879. return error;
  2880. }
  2881. return TTO_Err_Not_Covered;
  2882. }
  2883. /* apply one lookup to the input string object */
  2884. static TT_Error Do_String_Lookup( TTO_GSUBHeader* gsub,
  2885. UShort lookup_index,
  2886. TTO_GSUB_String* in,
  2887. TTO_GSUB_String* out )
  2888. {
  2889. TT_Error error = TTO_Err_Not_Covered;
  2890. UShort* properties = gsub->LookupList.Properties;
  2891. UShort* p_in = in->properties;
  2892. UShort* s_in = in->string;
  2893. int nesting_level = 0;
  2894. while ( in->pos < in->length )
  2895. {
  2896. if ( ~p_in[in->pos] & properties[lookup_index] )
  2897. {
  2898. /* 0xFFFF indicates that we don't have a context length yet */
  2899. error = Do_Glyph_Lookup( gsub, lookup_index, in, out,
  2900. 0xFFFF, nesting_level );
  2901. if ( error && error != TTO_Err_Not_Covered )
  2902. return error;
  2903. }
  2904. else
  2905. error = TTO_Err_Not_Covered;
  2906. if ( error == TTO_Err_Not_Covered )
  2907. if ( ADD_String( in, 1, out, 1, &s_in[in->pos] ) )
  2908. return error;
  2909. }
  2910. return error;
  2911. }
  2912. EXPORT_FUNC
  2913. TT_Error TT_GSUB_Add_Feature( TTO_GSUBHeader* gsub,
  2914. TT_UShort feature_index,
  2915. TT_UShort property )
  2916. {
  2917. UShort i;
  2918. TTO_Feature feature;
  2919. UShort* properties;
  2920. UShort* index;
  2921. if ( !gsub ||
  2922. feature_index >= gsub->FeatureList.FeatureCount )
  2923. return TT_Err_Invalid_Argument;
  2924. properties = gsub->LookupList.Properties;
  2925. feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
  2926. index = feature.LookupListIndex;
  2927. for ( i = 0; i < feature.LookupListCount; i++ )
  2928. properties[index[i]] |= property;
  2929. return TT_Err_Ok;
  2930. }
  2931. EXPORT_FUNC
  2932. TT_Error TT_GSUB_Clear_Features( TTO_GSUBHeader* gsub )
  2933. {
  2934. UShort i;
  2935. UShort* properties;
  2936. if ( !gsub )
  2937. return TT_Err_Invalid_Argument;
  2938. properties = gsub->LookupList.Properties;
  2939. for ( i = 0; i < gsub->LookupList.LookupCount; i++ )
  2940. properties[i] = 0;
  2941. return TT_Err_Ok;
  2942. }
  2943. EXPORT_FUNC
  2944. TT_Error TT_GSUB_Register_Alternate_Function( TTO_GSUBHeader* gsub,
  2945. TTO_AltFunction alt,
  2946. void* data )
  2947. {
  2948. if ( !gsub )
  2949. return TT_Err_Invalid_Argument;
  2950. gsub->alt = alt;
  2951. gsub->data = data;
  2952. return TT_Err_Ok;
  2953. }
  2954. EXPORT_FUNC
  2955. TT_Error TT_GSUB_Apply_String( TTO_GSUBHeader* gsub,
  2956. TTO_GSUB_String* in,
  2957. TTO_GSUB_String* out )
  2958. {
  2959. TT_Error error = TTO_Err_Not_Covered;
  2960. UShort j;
  2961. TTO_GSUB_String tmp1;
  2962. TTO_GSUB_String* ptmp1;
  2963. TTO_GSUB_String tmp2;
  2964. TTO_GSUB_String* ptmp2;
  2965. TTO_GSUB_String* t;
  2966. UShort* properties;
  2967. if ( !gsub ||
  2968. !in || !out || in->length == 0 || in->pos >= in->length )
  2969. return TT_Err_Invalid_Argument;
  2970. properties = gsub->LookupList.Properties;
  2971. tmp1.length = in->length;
  2972. tmp1.allocated = in->length;
  2973. tmp1.pos = in->pos;
  2974. if ( ALLOC_ARRAY( tmp1.string, tmp1.length, UShort ) )
  2975. return error;
  2976. MEM_Copy( tmp1.string, in->string, in->length * sizeof ( UShort ) );
  2977. /* make sure that we always have a `properties' array in the string
  2978. object */
  2979. if ( ALLOC_ARRAY( tmp1.properties, tmp1.length, UShort ) )
  2980. return error;
  2981. if ( in->properties )
  2982. MEM_Copy( tmp1.properties, in->properties,
  2983. in->length * sizeof( UShort ) );
  2984. tmp2.allocated = 0;
  2985. tmp2.pos = 0;
  2986. tmp2.string = NULL;
  2987. tmp2.properties = NULL;
  2988. ptmp1 = &tmp1;
  2989. ptmp2 = &tmp2;
  2990. for ( j = 0; j < gsub->LookupList.LookupCount; j++ )
  2991. if ( properties[j] )
  2992. {
  2993. error = Do_String_Lookup( gsub, j, ptmp1, ptmp2 );
  2994. if ( error && error != TTO_Err_Not_Covered )
  2995. return error;
  2996. /* flipping `in' and `out', preparing for the next loop */
  2997. ptmp1->pos = in->pos;
  2998. ptmp2->length = ptmp2->pos;
  2999. ptmp2->pos = in->pos;
  3000. t = ptmp2;
  3001. ptmp2 = ptmp1;
  3002. ptmp1 = t;
  3003. }
  3004. out->length = ptmp1->length;
  3005. out->pos = 0;
  3006. out->allocated = ptmp1->allocated;
  3007. out->string = ptmp1->string;
  3008. if ( in->properties )
  3009. out->properties = ptmp1->properties;
  3010. else
  3011. {
  3012. free( ptmp1->properties );
  3013. out->properties = NULL;
  3014. }
  3015. free( ptmp2->string );
  3016. free( ptmp2->properties );
  3017. return error;
  3018. }
  3019. /* END */