pfrgload.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. /***************************************************************************/
  2. /* */
  3. /* pfrgload.c */
  4. /* */
  5. /* FreeType PFR glyph loader (body). */
  6. /* */
  7. /* Copyright 2002 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. #include "pfrgload.h"
  18. #include "pfrsbit.h"
  19. #include "pfrload.h" /* for macro definitions */
  20. #include FT_INTERNAL_DEBUG_H
  21. #include "pfrerror.h"
  22. #undef FT_COMPONENT
  23. #define FT_COMPONENT trace_pfr
  24. /*************************************************************************/
  25. /*************************************************************************/
  26. /***** *****/
  27. /***** PFR GLYPH BUILDER *****/
  28. /***** *****/
  29. /*************************************************************************/
  30. /*************************************************************************/
  31. FT_LOCAL_DEF( void )
  32. pfr_glyph_init( PFR_Glyph glyph,
  33. FT_GlyphLoader loader )
  34. {
  35. FT_ZERO( glyph );
  36. glyph->loader = loader;
  37. glyph->path_begun = 0;
  38. FT_GlyphLoader_Rewind( loader );
  39. }
  40. FT_LOCAL_DEF( void )
  41. pfr_glyph_done( PFR_Glyph glyph )
  42. {
  43. FT_Memory memory = glyph->loader->memory;
  44. FT_FREE( glyph->x_control );
  45. glyph->y_control = NULL;
  46. glyph->max_xy_control = 0;
  47. glyph->num_x_control = 0;
  48. glyph->num_y_control = 0;
  49. FT_FREE( glyph->subs );
  50. glyph->max_subs = 0;
  51. glyph->num_subs = 0;
  52. glyph->loader = NULL;
  53. glyph->path_begun = 0;
  54. }
  55. /* close current contour, if any */
  56. static void
  57. pfr_glyph_close_contour( PFR_Glyph glyph )
  58. {
  59. FT_GlyphLoader loader = glyph->loader;
  60. FT_Outline* outline = &loader->current.outline;
  61. FT_Int last, first;
  62. if ( !glyph->path_begun )
  63. return;
  64. /* compute first and last point indices in current glyph outline */
  65. last = outline->n_points - 1;
  66. first = 0;
  67. if ( outline->n_contours > 0 )
  68. first = outline->contours[outline->n_contours - 1];
  69. /* if the last point falls on the same location than the first one */
  70. /* we need to delete it */
  71. if ( last > first )
  72. {
  73. FT_Vector* p1 = outline->points + first;
  74. FT_Vector* p2 = outline->points + last;
  75. if ( p1->x == p2->x && p1->y == p2->y )
  76. {
  77. outline->n_points--;
  78. last--;
  79. }
  80. }
  81. /* don't add empty contours */
  82. if ( last >= first )
  83. outline->contours[outline->n_contours++] = (short)last;
  84. glyph->path_begun = 0;
  85. }
  86. /* reset glyph to start the loading of a new glyph */
  87. static void
  88. pfr_glyph_start( PFR_Glyph glyph )
  89. {
  90. glyph->path_begun = 0;
  91. }
  92. static FT_Error
  93. pfr_glyph_line_to( PFR_Glyph glyph,
  94. FT_Vector* to )
  95. {
  96. FT_GlyphLoader loader = glyph->loader;
  97. FT_Outline* outline = &loader->current.outline;
  98. FT_Error error;
  99. /* check that we have begun a new path */
  100. FT_ASSERT( glyph->path_begun != 0 );
  101. error = FT_GlyphLoader_CheckPoints( loader, 1, 0 );
  102. if ( !error )
  103. {
  104. FT_UInt n = outline->n_points;
  105. outline->points[n] = *to;
  106. outline->tags [n] = FT_CURVE_TAG_ON;
  107. outline->n_points++;
  108. }
  109. return error;
  110. }
  111. static FT_Error
  112. pfr_glyph_curve_to( PFR_Glyph glyph,
  113. FT_Vector* control1,
  114. FT_Vector* control2,
  115. FT_Vector* to )
  116. {
  117. FT_GlyphLoader loader = glyph->loader;
  118. FT_Outline* outline = &loader->current.outline;
  119. FT_Error error;
  120. /* check that we have begun a new path */
  121. FT_ASSERT( glyph->path_begun != 0 );
  122. error = FT_GlyphLoader_CheckPoints( loader, 3, 0 );
  123. if ( !error )
  124. {
  125. FT_Vector* vec = outline->points + outline->n_points;
  126. FT_Byte* tag = (FT_Byte*)outline->tags + outline->n_points;
  127. vec[0] = *control1;
  128. vec[1] = *control2;
  129. vec[2] = *to;
  130. tag[0] = FT_CURVE_TAG_CUBIC;
  131. tag[1] = FT_CURVE_TAG_CUBIC;
  132. tag[2] = FT_CURVE_TAG_ON;
  133. outline->n_points = (FT_Short)( outline->n_points + 3 );
  134. }
  135. return error;
  136. }
  137. static FT_Error
  138. pfr_glyph_move_to( PFR_Glyph glyph,
  139. FT_Vector* to )
  140. {
  141. FT_GlyphLoader loader = glyph->loader;
  142. FT_Error error;
  143. /* close current contour if any */
  144. pfr_glyph_close_contour( glyph );
  145. /* indicate that a new contour has started */
  146. glyph->path_begun = 1;
  147. /* check that there is room for a new contour and a new point */
  148. error = FT_GlyphLoader_CheckPoints( loader, 1, 1 );
  149. if ( !error )
  150. /* add new start point */
  151. error = pfr_glyph_line_to( glyph, to );
  152. return error;
  153. }
  154. static void
  155. pfr_glyph_end( PFR_Glyph glyph )
  156. {
  157. /* close current contour if any */
  158. pfr_glyph_close_contour( glyph );
  159. /* merge the current glyph into the stack */
  160. FT_GlyphLoader_Add( glyph->loader );
  161. }
  162. /*************************************************************************/
  163. /*************************************************************************/
  164. /***** *****/
  165. /***** PFR GLYPH LOADER *****/
  166. /***** *****/
  167. /*************************************************************************/
  168. /*************************************************************************/
  169. /* load a simple glyph */
  170. static FT_Error
  171. pfr_glyph_load_simple( PFR_Glyph glyph,
  172. FT_Byte* p,
  173. FT_Byte* limit )
  174. {
  175. FT_Error error = 0;
  176. FT_Memory memory = glyph->loader->memory;
  177. FT_UInt flags, x_count, y_count, i, count, mask;
  178. FT_Int x;
  179. PFR_CHECK( 1 );
  180. flags = PFR_NEXT_BYTE( p );
  181. /* test for composite glyphs */
  182. FT_ASSERT( ( flags & PFR_GLYPH_IS_COMPOUND ) == 0 );
  183. x_count = 0;
  184. y_count = 0;
  185. if ( flags & PFR_GLYPH_1BYTE_XYCOUNT )
  186. {
  187. PFR_CHECK( 1 );
  188. count = PFR_NEXT_BYTE( p );
  189. x_count = ( count & 15 );
  190. y_count = ( count >> 4 );
  191. }
  192. else
  193. {
  194. if ( flags & PFR_GLYPH_XCOUNT )
  195. {
  196. PFR_CHECK( 1 );
  197. x_count = PFR_NEXT_BYTE( p );
  198. }
  199. if ( flags & PFR_GLYPH_YCOUNT )
  200. {
  201. PFR_CHECK( 1 );
  202. y_count = PFR_NEXT_BYTE( p );
  203. }
  204. }
  205. count = x_count + y_count;
  206. /* re-allocate array when necessary */
  207. if ( count > glyph->max_xy_control )
  208. {
  209. FT_UInt new_max = ( count + 7 ) & -8;
  210. if ( FT_RENEW_ARRAY( glyph->x_control,
  211. glyph->max_xy_control,
  212. new_max ) )
  213. goto Exit;
  214. glyph->max_xy_control = new_max;
  215. }
  216. glyph->y_control = glyph->x_control + x_count;
  217. mask = 0;
  218. x = 0;
  219. for ( i = 0; i < count; i++ )
  220. {
  221. if ( ( i & 7 ) == 0 )
  222. {
  223. PFR_CHECK( 1 );
  224. mask = PFR_NEXT_BYTE( p );
  225. }
  226. if ( mask & 1 )
  227. {
  228. PFR_CHECK( 2 );
  229. x = PFR_NEXT_SHORT( p );
  230. }
  231. else
  232. {
  233. PFR_CHECK( 1 );
  234. x += PFR_NEXT_BYTE( p );
  235. }
  236. glyph->x_control[i] = x;
  237. mask >>= 1;
  238. }
  239. /* XXX: for now we ignore the secondary stroke and edge definitions */
  240. /* since we don't want to support native PFR hinting */
  241. /* */
  242. if ( flags & PFR_GLYPH_EXTRA_ITEMS )
  243. {
  244. error = pfr_extra_items_skip( &p, limit );
  245. if ( error )
  246. goto Exit;
  247. }
  248. pfr_glyph_start( glyph );
  249. /* now load a simple glyph */
  250. {
  251. FT_Vector pos[4];
  252. FT_Vector* cur;
  253. pos[0].x = pos[0].y = 0;
  254. pos[3] = pos[0];
  255. for (;;)
  256. {
  257. FT_Int format, args_format = 0, args_count, n;
  258. /***************************************************************/
  259. /* read instruction */
  260. /* */
  261. PFR_CHECK( 1 );
  262. format = PFR_NEXT_BYTE( p );
  263. switch ( format >> 4 )
  264. {
  265. case 0: /* end glyph */
  266. FT_TRACE6(( "- end glyph" ));
  267. args_count = 0;
  268. break;
  269. case 1: /* general line operation */
  270. FT_TRACE6(( "- general line" ));
  271. goto Line1;
  272. case 4: /* move to inside contour */
  273. FT_TRACE6(( "- move to inside" ));
  274. goto Line1;
  275. case 5: /* move to outside contour */
  276. FT_TRACE6(( "- move to outside" ));
  277. Line1:
  278. args_format = format & 15;
  279. args_count = 1;
  280. break;
  281. case 2: /* horizontal line to */
  282. FT_TRACE6(( "- horizontal line to cx.%d", format & 15 ));
  283. pos[0].y = pos[3].y;
  284. pos[0].x = glyph->x_control[format & 15];
  285. pos[3] = pos[0];
  286. args_count = 0;
  287. break;
  288. case 3: /* vertical line to */
  289. FT_TRACE6(( "- vertical line to cy.%d", format & 15 ));
  290. pos[0].x = pos[3].x;
  291. pos[0].y = glyph->y_control[format & 15];
  292. pos[3] = pos[0];
  293. args_count = 0;
  294. break;
  295. case 6: /* horizontal to vertical curve */
  296. FT_TRACE6(( "- hv curve " ));
  297. args_format = 0xB8E;
  298. args_count = 3;
  299. break;
  300. case 7: /* vertical to horizontal curve */
  301. FT_TRACE6(( "- vh curve" ));
  302. args_format = 0xE2B;
  303. args_count = 3;
  304. break;
  305. default: /* general curve to */
  306. FT_TRACE6(( "- general curve" ));
  307. args_count = 4;
  308. args_format = format & 15;
  309. }
  310. /***********************************************************/
  311. /* now read arguments */
  312. /* */
  313. cur = pos;
  314. for ( n = 0; n < args_count; n++ )
  315. {
  316. FT_Int idx, delta;
  317. /* read the X argument */
  318. switch ( args_format & 3 )
  319. {
  320. case 0: /* 8-bit index */
  321. PFR_CHECK( 1 );
  322. idx = PFR_NEXT_BYTE( p );
  323. cur->x = glyph->x_control[idx];
  324. FT_TRACE7(( " cx#%d", idx ));
  325. break;
  326. case 1: /* 16-bit value */
  327. PFR_CHECK( 2 );
  328. cur->x = PFR_NEXT_SHORT( p );
  329. FT_TRACE7(( " x.%d", cur->x ));
  330. break;
  331. case 2: /* 8-bit delta */
  332. PFR_CHECK( 1 );
  333. delta = PFR_NEXT_INT8( p );
  334. cur->x = pos[3].x + delta;
  335. FT_TRACE7(( " dx.%d", delta ));
  336. break;
  337. default:
  338. FT_TRACE7(( " |" ));
  339. cur->x = pos[3].x;
  340. }
  341. /* read the Y argument */
  342. switch ( ( args_format >> 2 ) & 3 )
  343. {
  344. case 0: /* 8-bit index */
  345. PFR_CHECK( 1 );
  346. idx = PFR_NEXT_BYTE( p );
  347. cur->y = glyph->y_control[idx];
  348. FT_TRACE7(( " cy#%d", idx ));
  349. break;
  350. case 1: /* 16-bit absolute value */
  351. PFR_CHECK( 2 );
  352. cur->y = PFR_NEXT_SHORT( p );
  353. FT_TRACE7(( " y.%d", cur->y ));
  354. break;
  355. case 2: /* 8-bit delta */
  356. PFR_CHECK( 1 );
  357. delta = PFR_NEXT_INT8( p );
  358. cur->y = pos[3].y + delta;
  359. FT_TRACE7(( " dy.%d", delta ));
  360. break;
  361. default:
  362. FT_TRACE7(( " -" ));
  363. cur->y = pos[3].y;
  364. }
  365. /* read the additional format flag for the general curve */
  366. if ( n == 0 && args_count == 4 )
  367. {
  368. PFR_CHECK( 1 );
  369. args_format = PFR_NEXT_BYTE( p );
  370. args_count--;
  371. }
  372. else
  373. args_format >>= 4;
  374. /* save the previous point */
  375. pos[3] = cur[0];
  376. cur++;
  377. }
  378. FT_TRACE7(( "\n" ));
  379. /***********************************************************/
  380. /* finally, execute instruction */
  381. /* */
  382. switch ( format >> 4 )
  383. {
  384. case 0: /* end glyph => EXIT */
  385. pfr_glyph_end( glyph );
  386. goto Exit;
  387. case 1: /* line operations */
  388. case 2:
  389. case 3:
  390. error = pfr_glyph_line_to( glyph, pos );
  391. goto Test_Error;
  392. case 4: /* move to inside contour */
  393. case 5: /* move to outside contour */
  394. error = pfr_glyph_move_to( glyph, pos );
  395. goto Test_Error;
  396. default: /* curve operations */
  397. error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 );
  398. Test_Error: /* test error condition */
  399. if ( error )
  400. goto Exit;
  401. }
  402. } /* for (;;) */
  403. }
  404. Exit:
  405. return error;
  406. Too_Short:
  407. error = PFR_Err_Invalid_Table;
  408. FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" ));
  409. goto Exit;
  410. }
  411. /* load a composite/compound glyph */
  412. static FT_Error
  413. pfr_glyph_load_compound( PFR_Glyph glyph,
  414. FT_Byte* p,
  415. FT_Byte* limit )
  416. {
  417. FT_Error error = 0;
  418. FT_GlyphLoader loader = glyph->loader;
  419. FT_Memory memory = loader->memory;
  420. PFR_SubGlyph subglyph;
  421. FT_UInt flags, i, count, org_count;
  422. FT_Int x_pos, y_pos;
  423. PFR_CHECK( 1 );
  424. flags = PFR_NEXT_BYTE( p );
  425. /* test for composite glyphs */
  426. FT_ASSERT( ( flags & PFR_GLYPH_IS_COMPOUND ) != 0 );
  427. count = flags & 0x3F;
  428. /* ignore extra items when present */
  429. /* */
  430. if ( flags & PFR_GLYPH_EXTRA_ITEMS )
  431. {
  432. error = pfr_extra_items_skip( &p, limit );
  433. if (error) goto Exit;
  434. }
  435. /* we can't rely on the FT_GlyphLoader to load sub-glyphs, because */
  436. /* the PFR format is dumb, using direct file offsets to point to the */
  437. /* sub-glyphs (instead of glyph indices). Sigh. */
  438. /* */
  439. /* For now, we load the list of sub-glyphs into a different array */
  440. /* but this will prevent us from using the auto-hinter at its best */
  441. /* quality. */
  442. /* */
  443. org_count = glyph->num_subs;
  444. if ( org_count + count > glyph->max_subs )
  445. {
  446. FT_UInt new_max = ( org_count + count + 3 ) & -4;
  447. if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) )
  448. goto Exit;
  449. glyph->max_subs = new_max;
  450. }
  451. subglyph = glyph->subs + org_count;
  452. for ( i = 0; i < count; i++, subglyph++ )
  453. {
  454. FT_UInt format;
  455. x_pos = 0;
  456. y_pos = 0;
  457. PFR_CHECK( 1 );
  458. format = PFR_NEXT_BYTE( p );
  459. /* read scale when available */
  460. subglyph->x_scale = 0x10000L;
  461. if ( format & PFR_SUBGLYPH_XSCALE )
  462. {
  463. PFR_CHECK( 2 );
  464. subglyph->x_scale = PFR_NEXT_SHORT( p ) << 4;
  465. }
  466. subglyph->y_scale = 0x10000L;
  467. if ( format & PFR_SUBGLYPH_YSCALE )
  468. {
  469. PFR_CHECK( 2 );
  470. subglyph->y_scale = PFR_NEXT_SHORT( p ) << 4;
  471. }
  472. /* read offset */
  473. switch ( format & 3 )
  474. {
  475. case 1:
  476. PFR_CHECK( 2 );
  477. x_pos = PFR_NEXT_SHORT( p );
  478. break;
  479. case 2:
  480. PFR_CHECK( 1 );
  481. x_pos += PFR_NEXT_INT8( p );
  482. break;
  483. default:
  484. ;
  485. }
  486. switch ( ( format >> 2 ) & 3 )
  487. {
  488. case 1:
  489. PFR_CHECK( 2 );
  490. y_pos = PFR_NEXT_SHORT( p );
  491. break;
  492. case 2:
  493. PFR_CHECK( 1 );
  494. y_pos += PFR_NEXT_INT8( p );
  495. break;
  496. default:
  497. ;
  498. }
  499. subglyph->x_delta = x_pos;
  500. subglyph->y_delta = y_pos;
  501. /* read glyph position and size now */
  502. if ( format & PFR_SUBGLYPH_2BYTE_SIZE )
  503. {
  504. PFR_CHECK( 2 );
  505. subglyph->gps_size = PFR_NEXT_USHORT( p );
  506. }
  507. else
  508. {
  509. PFR_CHECK( 1 );
  510. subglyph->gps_size = PFR_NEXT_BYTE( p );
  511. }
  512. if ( format & PFR_SUBGLYPH_3BYTE_OFFSET )
  513. {
  514. PFR_CHECK( 3 );
  515. subglyph->gps_offset = PFR_NEXT_LONG( p );
  516. }
  517. else
  518. {
  519. PFR_CHECK( 2 );
  520. subglyph->gps_offset = PFR_NEXT_USHORT( p );
  521. }
  522. glyph->num_subs++;
  523. }
  524. Exit:
  525. return error;
  526. Too_Short:
  527. error = PFR_Err_Invalid_Table;
  528. FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" ));
  529. goto Exit;
  530. }
  531. static FT_Error
  532. pfr_glyph_load_rec( PFR_Glyph glyph,
  533. FT_Stream stream,
  534. FT_ULong gps_offset,
  535. FT_ULong offset,
  536. FT_ULong size )
  537. {
  538. FT_Error error;
  539. FT_Byte* p;
  540. FT_Byte* limit;
  541. if ( FT_STREAM_SEEK( gps_offset + offset ) ||
  542. FT_FRAME_ENTER( size ) )
  543. goto Exit;
  544. p = (FT_Byte*)stream->cursor;
  545. limit = p + size;
  546. if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND )
  547. {
  548. FT_Int n, old_count, count;
  549. FT_GlyphLoader loader = glyph->loader;
  550. FT_Outline* base = &loader->base.outline;
  551. old_count = glyph->num_subs;
  552. /* this is a compound glyph - load it */
  553. error = pfr_glyph_load_compound( glyph, p, limit );
  554. FT_FRAME_EXIT();
  555. if ( error )
  556. goto Exit;
  557. count = glyph->num_subs - old_count;
  558. /* now, load each individual glyph */
  559. for ( n = 0; n < count; n++ )
  560. {
  561. FT_Int i, old_points, num_points;
  562. PFR_SubGlyph subglyph;
  563. subglyph = glyph->subs + old_count + n;
  564. old_points = base->n_points;
  565. error = pfr_glyph_load_rec( glyph, stream, gps_offset,
  566. subglyph->gps_offset,
  567. subglyph->gps_size );
  568. if ( error )
  569. goto Exit;
  570. /* note that `glyph->subs' might have been re-allocated */
  571. subglyph = glyph->subs + old_count + n;
  572. num_points = base->n_points - old_points;
  573. /* translate and eventually scale the new glyph points */
  574. if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L )
  575. {
  576. FT_Vector* vec = base->points + old_points;
  577. for ( i = 0; i < num_points; i++, vec++ )
  578. {
  579. vec->x = FT_MulFix( vec->x, subglyph->x_scale ) +
  580. subglyph->x_delta;
  581. vec->y = FT_MulFix( vec->y, subglyph->y_scale ) +
  582. subglyph->y_delta;
  583. }
  584. }
  585. else
  586. {
  587. FT_Vector* vec = loader->base.outline.points + old_points;
  588. for ( i = 0; i < num_points; i++, vec++ )
  589. {
  590. vec->x += subglyph->x_delta;
  591. vec->y += subglyph->y_delta;
  592. }
  593. }
  594. /* proceed to next sub-glyph */
  595. }
  596. }
  597. else
  598. {
  599. /* load a simple glyph */
  600. error = pfr_glyph_load_simple( glyph, p, limit );
  601. FT_FRAME_EXIT();
  602. }
  603. Exit:
  604. return error;
  605. }
  606. FT_LOCAL_DEF( FT_Error )
  607. pfr_glyph_load( PFR_Glyph glyph,
  608. FT_Stream stream,
  609. FT_ULong gps_offset,
  610. FT_ULong offset,
  611. FT_ULong size )
  612. {
  613. /* initialize glyph loader */
  614. FT_GlyphLoader_Rewind( glyph->loader );
  615. /* load the glyph, recursively when needed */
  616. return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size );
  617. }
  618. /* END */