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

/src/freetype/src/type1/t1load.c

https://bitbucket.org/cabalistic/ogredeps/
C | 2243 lines | 1489 code | 446 blank | 308 comment | 327 complexity | 75aa6f88e381913fe040e39a0a1d182e MD5 | raw file
Possible License(s): LGPL-3.0, BSD-3-Clause, CPL-1.0, Unlicense, GPL-2.0, GPL-3.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, BSD-2-Clause, LGPL-2.1
  1. /***************************************************************************/
  2. /* */
  3. /* t1load.c */
  4. /* */
  5. /* Type 1 font loader (body). */
  6. /* */
  7. /* Copyright 1996-2012 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. /*************************************************************************/
  18. /* */
  19. /* This is the new and improved Type 1 data loader for FreeType 2. The */
  20. /* old loader has several problems: it is slow, complex, difficult to */
  21. /* maintain, and contains incredible hacks to make it accept some */
  22. /* ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of */
  23. /* the Type 1 fonts on my machine still aren't loaded correctly by it. */
  24. /* */
  25. /* This version is much simpler, much faster and also easier to read and */
  26. /* maintain by a great order of magnitude. The idea behind it is to */
  27. /* _not_ try to read the Type 1 token stream with a state machine (i.e. */
  28. /* a Postscript-like interpreter) but rather to perform simple pattern */
  29. /* matching. */
  30. /* */
  31. /* Indeed, nearly all data definitions follow a simple pattern like */
  32. /* */
  33. /* ... /Field <data> ... */
  34. /* */
  35. /* where <data> can be a number, a boolean, a string, or an array of */
  36. /* numbers. There are a few exceptions, namely the encoding, font name, */
  37. /* charstrings, and subrs; they are handled with a special pattern */
  38. /* matching routine. */
  39. /* */
  40. /* All other common cases are handled very simply. The matching rules */
  41. /* are defined in the file `t1tokens.h' through the use of several */
  42. /* macros calls PARSE_XXX. This file is included twice here; the first */
  43. /* time to generate parsing callback functions, the second time to */
  44. /* generate a table of keywords (with pointers to the associated */
  45. /* callback functions). */
  46. /* */
  47. /* The function `parse_dict' simply scans *linearly* a given dictionary */
  48. /* (either the top-level or private one) and calls the appropriate */
  49. /* callback when it encounters an immediate keyword. */
  50. /* */
  51. /* This is by far the fastest way one can find to parse and read all */
  52. /* data. */
  53. /* */
  54. /* This led to tremendous code size reduction. Note that later, the */
  55. /* glyph loader will also be _greatly_ simplified, and the automatic */
  56. /* hinter will replace the clumsy `t1hinter'. */
  57. /* */
  58. /*************************************************************************/
  59. #include <ft2build.h>
  60. #include FT_INTERNAL_DEBUG_H
  61. #include FT_CONFIG_CONFIG_H
  62. #include FT_MULTIPLE_MASTERS_H
  63. #include FT_INTERNAL_TYPE1_TYPES_H
  64. #include FT_INTERNAL_CALC_H
  65. #include "t1load.h"
  66. #include "t1errors.h"
  67. /*************************************************************************/
  68. /* */
  69. /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
  70. /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
  71. /* messages during execution. */
  72. /* */
  73. #undef FT_COMPONENT
  74. #define FT_COMPONENT trace_t1load
  75. #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
  76. /*************************************************************************/
  77. /*************************************************************************/
  78. /***** *****/
  79. /***** MULTIPLE MASTERS SUPPORT *****/
  80. /***** *****/
  81. /*************************************************************************/
  82. /*************************************************************************/
  83. static FT_Error
  84. t1_allocate_blend( T1_Face face,
  85. FT_UInt num_designs,
  86. FT_UInt num_axis )
  87. {
  88. PS_Blend blend;
  89. FT_Memory memory = face->root.memory;
  90. FT_Error error = T1_Err_Ok;
  91. blend = face->blend;
  92. if ( !blend )
  93. {
  94. if ( FT_NEW( blend ) )
  95. goto Exit;
  96. blend->num_default_design_vector = 0;
  97. face->blend = blend;
  98. }
  99. /* allocate design data if needed */
  100. if ( num_designs > 0 )
  101. {
  102. if ( blend->num_designs == 0 )
  103. {
  104. FT_UInt nn;
  105. /* allocate the blend `private' and `font_info' dictionaries */
  106. if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) ||
  107. FT_NEW_ARRAY( blend->privates[1], num_designs ) ||
  108. FT_NEW_ARRAY( blend->bboxes[1], num_designs ) ||
  109. FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) )
  110. goto Exit;
  111. blend->default_weight_vector = blend->weight_vector + num_designs;
  112. blend->font_infos[0] = &face->type1.font_info;
  113. blend->privates [0] = &face->type1.private_dict;
  114. blend->bboxes [0] = &face->type1.font_bbox;
  115. for ( nn = 2; nn <= num_designs; nn++ )
  116. {
  117. blend->privates[nn] = blend->privates [nn - 1] + 1;
  118. blend->font_infos[nn] = blend->font_infos[nn - 1] + 1;
  119. blend->bboxes[nn] = blend->bboxes [nn - 1] + 1;
  120. }
  121. blend->num_designs = num_designs;
  122. }
  123. else if ( blend->num_designs != num_designs )
  124. goto Fail;
  125. }
  126. /* allocate axis data if needed */
  127. if ( num_axis > 0 )
  128. {
  129. if ( blend->num_axis != 0 && blend->num_axis != num_axis )
  130. goto Fail;
  131. blend->num_axis = num_axis;
  132. }
  133. /* allocate the blend design pos table if needed */
  134. num_designs = blend->num_designs;
  135. num_axis = blend->num_axis;
  136. if ( num_designs && num_axis && blend->design_pos[0] == 0 )
  137. {
  138. FT_UInt n;
  139. if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) )
  140. goto Exit;
  141. for ( n = 1; n < num_designs; n++ )
  142. blend->design_pos[n] = blend->design_pos[0] + num_axis * n;
  143. }
  144. Exit:
  145. return error;
  146. Fail:
  147. error = T1_Err_Invalid_File_Format;
  148. goto Exit;
  149. }
  150. FT_LOCAL_DEF( FT_Error )
  151. T1_Get_Multi_Master( T1_Face face,
  152. FT_Multi_Master* master )
  153. {
  154. PS_Blend blend = face->blend;
  155. FT_UInt n;
  156. FT_Error error;
  157. error = T1_Err_Invalid_Argument;
  158. if ( blend )
  159. {
  160. master->num_axis = blend->num_axis;
  161. master->num_designs = blend->num_designs;
  162. for ( n = 0; n < blend->num_axis; n++ )
  163. {
  164. FT_MM_Axis* axis = master->axis + n;
  165. PS_DesignMap map = blend->design_map + n;
  166. axis->name = blend->axis_names[n];
  167. axis->minimum = map->design_points[0];
  168. axis->maximum = map->design_points[map->num_points - 1];
  169. }
  170. error = T1_Err_Ok;
  171. }
  172. return error;
  173. }
  174. /*************************************************************************/
  175. /* */
  176. /* Given a normalized (blend) coordinate, figure out the design */
  177. /* coordinate appropriate for that value. */
  178. /* */
  179. FT_LOCAL_DEF( FT_Fixed )
  180. mm_axis_unmap( PS_DesignMap axismap,
  181. FT_Fixed ncv )
  182. {
  183. int j;
  184. if ( ncv <= axismap->blend_points[0] )
  185. return INT_TO_FIXED( axismap->design_points[0] );
  186. for ( j = 1; j < axismap->num_points; ++j )
  187. {
  188. if ( ncv <= axismap->blend_points[j] )
  189. {
  190. FT_Fixed t = FT_MulDiv( ncv - axismap->blend_points[j - 1],
  191. 0x10000L,
  192. axismap->blend_points[j] -
  193. axismap->blend_points[j - 1] );
  194. return INT_TO_FIXED( axismap->design_points[j - 1] ) +
  195. FT_MulDiv( t,
  196. axismap->design_points[j] -
  197. axismap->design_points[j - 1],
  198. 1L );
  199. }
  200. }
  201. return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] );
  202. }
  203. /*************************************************************************/
  204. /* */
  205. /* Given a vector of weights, one for each design, figure out the */
  206. /* normalized axis coordinates which gave rise to those weights. */
  207. /* */
  208. FT_LOCAL_DEF( void )
  209. mm_weights_unmap( FT_Fixed* weights,
  210. FT_Fixed* axiscoords,
  211. FT_UInt axis_count )
  212. {
  213. FT_ASSERT( axis_count <= T1_MAX_MM_AXIS );
  214. if ( axis_count == 1 )
  215. axiscoords[0] = weights[1];
  216. else if ( axis_count == 2 )
  217. {
  218. axiscoords[0] = weights[3] + weights[1];
  219. axiscoords[1] = weights[3] + weights[2];
  220. }
  221. else if ( axis_count == 3 )
  222. {
  223. axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1];
  224. axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2];
  225. axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4];
  226. }
  227. else
  228. {
  229. axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] +
  230. weights[7] + weights[5] + weights[3] + weights[1];
  231. axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] +
  232. weights[7] + weights[6] + weights[3] + weights[2];
  233. axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] +
  234. weights[7] + weights[6] + weights[5] + weights[4];
  235. axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] +
  236. weights[11] + weights[10] + weights[9] + weights[8];
  237. }
  238. }
  239. /*************************************************************************/
  240. /* */
  241. /* Just a wrapper around T1_Get_Multi_Master to support the different */
  242. /* arguments needed by the GX var distortable fonts. */
  243. /* */
  244. FT_LOCAL_DEF( FT_Error )
  245. T1_Get_MM_Var( T1_Face face,
  246. FT_MM_Var* *master )
  247. {
  248. FT_Memory memory = face->root.memory;
  249. FT_MM_Var *mmvar = NULL;
  250. FT_Multi_Master mmaster;
  251. FT_Error error;
  252. FT_UInt i;
  253. FT_Fixed axiscoords[T1_MAX_MM_AXIS];
  254. PS_Blend blend = face->blend;
  255. error = T1_Get_Multi_Master( face, &mmaster );
  256. if ( error )
  257. goto Exit;
  258. if ( FT_ALLOC( mmvar,
  259. sizeof ( FT_MM_Var ) +
  260. mmaster.num_axis * sizeof ( FT_Var_Axis ) ) )
  261. goto Exit;
  262. mmvar->num_axis = mmaster.num_axis;
  263. mmvar->num_designs = mmaster.num_designs;
  264. mmvar->num_namedstyles = (FT_UInt)-1; /* Does not apply */
  265. mmvar->axis = (FT_Var_Axis*)&mmvar[1];
  266. /* Point to axes after MM_Var struct */
  267. mmvar->namedstyle = NULL;
  268. for ( i = 0 ; i < mmaster.num_axis; ++i )
  269. {
  270. mmvar->axis[i].name = mmaster.axis[i].name;
  271. mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum);
  272. mmvar->axis[i].maximum = INT_TO_FIXED( mmaster.axis[i].maximum);
  273. mmvar->axis[i].def = ( mmvar->axis[i].minimum +
  274. mmvar->axis[i].maximum ) / 2;
  275. /* Does not apply. But this value is in range */
  276. mmvar->axis[i].strid = (FT_UInt)-1; /* Does not apply */
  277. mmvar->axis[i].tag = (FT_ULong)-1; /* Does not apply */
  278. if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 )
  279. mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' );
  280. else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 )
  281. mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' );
  282. else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 )
  283. mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' );
  284. }
  285. if ( blend->num_designs == ( 1U << blend->num_axis ) )
  286. {
  287. mm_weights_unmap( blend->default_weight_vector,
  288. axiscoords,
  289. blend->num_axis );
  290. for ( i = 0; i < mmaster.num_axis; ++i )
  291. mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i],
  292. axiscoords[i] );
  293. }
  294. *master = mmvar;
  295. Exit:
  296. return error;
  297. }
  298. FT_LOCAL_DEF( FT_Error )
  299. T1_Set_MM_Blend( T1_Face face,
  300. FT_UInt num_coords,
  301. FT_Fixed* coords )
  302. {
  303. PS_Blend blend = face->blend;
  304. FT_Error error;
  305. FT_UInt n, m;
  306. error = T1_Err_Invalid_Argument;
  307. if ( blend && blend->num_axis == num_coords )
  308. {
  309. /* recompute the weight vector from the blend coordinates */
  310. error = T1_Err_Ok;
  311. for ( n = 0; n < blend->num_designs; n++ )
  312. {
  313. FT_Fixed result = 0x10000L; /* 1.0 fixed */
  314. for ( m = 0; m < blend->num_axis; m++ )
  315. {
  316. FT_Fixed factor;
  317. /* get current blend axis position */
  318. factor = coords[m];
  319. if ( factor < 0 ) factor = 0;
  320. if ( factor > 0x10000L ) factor = 0x10000L;
  321. if ( ( n & ( 1 << m ) ) == 0 )
  322. factor = 0x10000L - factor;
  323. result = FT_MulFix( result, factor );
  324. }
  325. blend->weight_vector[n] = result;
  326. }
  327. error = T1_Err_Ok;
  328. }
  329. return error;
  330. }
  331. FT_LOCAL_DEF( FT_Error )
  332. T1_Set_MM_Design( T1_Face face,
  333. FT_UInt num_coords,
  334. FT_Long* coords )
  335. {
  336. PS_Blend blend = face->blend;
  337. FT_Error error;
  338. FT_UInt n, p;
  339. error = T1_Err_Invalid_Argument;
  340. if ( blend && blend->num_axis == num_coords )
  341. {
  342. /* compute the blend coordinates through the blend design map */
  343. FT_Fixed final_blends[T1_MAX_MM_DESIGNS];
  344. for ( n = 0; n < blend->num_axis; n++ )
  345. {
  346. FT_Long design = coords[n];
  347. FT_Fixed the_blend;
  348. PS_DesignMap map = blend->design_map + n;
  349. FT_Long* designs = map->design_points;
  350. FT_Fixed* blends = map->blend_points;
  351. FT_Int before = -1, after = -1;
  352. for ( p = 0; p < (FT_UInt)map->num_points; p++ )
  353. {
  354. FT_Long p_design = designs[p];
  355. /* exact match? */
  356. if ( design == p_design )
  357. {
  358. the_blend = blends[p];
  359. goto Found;
  360. }
  361. if ( design < p_design )
  362. {
  363. after = p;
  364. break;
  365. }
  366. before = p;
  367. }
  368. /* now interpolate if necessary */
  369. if ( before < 0 )
  370. the_blend = blends[0];
  371. else if ( after < 0 )
  372. the_blend = blends[map->num_points - 1];
  373. else
  374. the_blend = FT_MulDiv( design - designs[before],
  375. blends [after] - blends [before],
  376. designs[after] - designs[before] );
  377. Found:
  378. final_blends[n] = the_blend;
  379. }
  380. error = T1_Set_MM_Blend( face, num_coords, final_blends );
  381. }
  382. return error;
  383. }
  384. /*************************************************************************/
  385. /* */
  386. /* Just a wrapper around T1_Set_MM_Design to support the different */
  387. /* arguments needed by the GX var distortable fonts. */
  388. /* */
  389. FT_LOCAL_DEF( FT_Error )
  390. T1_Set_Var_Design( T1_Face face,
  391. FT_UInt num_coords,
  392. FT_Fixed* coords )
  393. {
  394. FT_Long lcoords[4]; /* maximum axis count is 4 */
  395. FT_UInt i;
  396. FT_Error error;
  397. error = T1_Err_Invalid_Argument;
  398. if ( num_coords <= 4 && num_coords > 0 )
  399. {
  400. for ( i = 0; i < num_coords; ++i )
  401. lcoords[i] = FIXED_TO_INT( coords[i] );
  402. error = T1_Set_MM_Design( face, num_coords, lcoords );
  403. }
  404. return error;
  405. }
  406. FT_LOCAL_DEF( void )
  407. T1_Done_Blend( T1_Face face )
  408. {
  409. FT_Memory memory = face->root.memory;
  410. PS_Blend blend = face->blend;
  411. if ( blend )
  412. {
  413. FT_UInt num_designs = blend->num_designs;
  414. FT_UInt num_axis = blend->num_axis;
  415. FT_UInt n;
  416. /* release design pos table */
  417. FT_FREE( blend->design_pos[0] );
  418. for ( n = 1; n < num_designs; n++ )
  419. blend->design_pos[n] = 0;
  420. /* release blend `private' and `font info' dictionaries */
  421. FT_FREE( blend->privates[1] );
  422. FT_FREE( blend->font_infos[1] );
  423. FT_FREE( blend->bboxes[1] );
  424. for ( n = 0; n < num_designs; n++ )
  425. {
  426. blend->privates [n] = 0;
  427. blend->font_infos[n] = 0;
  428. blend->bboxes [n] = 0;
  429. }
  430. /* release weight vectors */
  431. FT_FREE( blend->weight_vector );
  432. blend->default_weight_vector = 0;
  433. /* release axis names */
  434. for ( n = 0; n < num_axis; n++ )
  435. FT_FREE( blend->axis_names[n] );
  436. /* release design map */
  437. for ( n = 0; n < num_axis; n++ )
  438. {
  439. PS_DesignMap dmap = blend->design_map + n;
  440. FT_FREE( dmap->design_points );
  441. dmap->num_points = 0;
  442. }
  443. FT_FREE( face->blend );
  444. }
  445. }
  446. static void
  447. parse_blend_axis_types( T1_Face face,
  448. T1_Loader loader )
  449. {
  450. T1_TokenRec axis_tokens[T1_MAX_MM_AXIS];
  451. FT_Int n, num_axis;
  452. FT_Error error = T1_Err_Ok;
  453. PS_Blend blend;
  454. FT_Memory memory;
  455. /* take an array of objects */
  456. T1_ToTokenArray( &loader->parser, axis_tokens,
  457. T1_MAX_MM_AXIS, &num_axis );
  458. if ( num_axis < 0 )
  459. {
  460. error = T1_Err_Ignore;
  461. goto Exit;
  462. }
  463. if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS )
  464. {
  465. FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n",
  466. num_axis ));
  467. error = T1_Err_Invalid_File_Format;
  468. goto Exit;
  469. }
  470. /* allocate blend if necessary */
  471. error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
  472. if ( error )
  473. goto Exit;
  474. blend = face->blend;
  475. memory = face->root.memory;
  476. /* each token is an immediate containing the name of the axis */
  477. for ( n = 0; n < num_axis; n++ )
  478. {
  479. T1_Token token = axis_tokens + n;
  480. FT_Byte* name;
  481. FT_PtrDist len;
  482. /* skip first slash, if any */
  483. if ( token->start[0] == '/' )
  484. token->start++;
  485. len = token->limit - token->start;
  486. if ( len == 0 )
  487. {
  488. error = T1_Err_Invalid_File_Format;
  489. goto Exit;
  490. }
  491. if ( FT_ALLOC( blend->axis_names[n], len + 1 ) )
  492. goto Exit;
  493. name = (FT_Byte*)blend->axis_names[n];
  494. FT_MEM_COPY( name, token->start, len );
  495. name[len] = 0;
  496. }
  497. Exit:
  498. loader->parser.root.error = error;
  499. }
  500. static void
  501. parse_blend_design_positions( T1_Face face,
  502. T1_Loader loader )
  503. {
  504. T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS];
  505. FT_Int num_designs;
  506. FT_Int num_axis;
  507. T1_Parser parser = &loader->parser;
  508. FT_Error error = T1_Err_Ok;
  509. PS_Blend blend;
  510. /* get the array of design tokens -- compute number of designs */
  511. T1_ToTokenArray( parser, design_tokens,
  512. T1_MAX_MM_DESIGNS, &num_designs );
  513. if ( num_designs < 0 )
  514. {
  515. error = T1_Err_Ignore;
  516. goto Exit;
  517. }
  518. if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS )
  519. {
  520. FT_ERROR(( "parse_blend_design_positions:"
  521. " incorrect number of designs: %d\n",
  522. num_designs ));
  523. error = T1_Err_Invalid_File_Format;
  524. goto Exit;
  525. }
  526. {
  527. FT_Byte* old_cursor = parser->root.cursor;
  528. FT_Byte* old_limit = parser->root.limit;
  529. FT_Int n;
  530. blend = face->blend;
  531. num_axis = 0; /* make compiler happy */
  532. for ( n = 0; n < num_designs; n++ )
  533. {
  534. T1_TokenRec axis_tokens[T1_MAX_MM_AXIS];
  535. T1_Token token;
  536. FT_Int axis, n_axis;
  537. /* read axis/coordinates tokens */
  538. token = design_tokens + n;
  539. parser->root.cursor = token->start;
  540. parser->root.limit = token->limit;
  541. T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
  542. if ( n == 0 )
  543. {
  544. if ( n_axis <= 0 || n_axis > T1_MAX_MM_AXIS )
  545. {
  546. FT_ERROR(( "parse_blend_design_positions:"
  547. " invalid number of axes: %d\n",
  548. n_axis ));
  549. error = T1_Err_Invalid_File_Format;
  550. goto Exit;
  551. }
  552. num_axis = n_axis;
  553. error = t1_allocate_blend( face, num_designs, num_axis );
  554. if ( error )
  555. goto Exit;
  556. blend = face->blend;
  557. }
  558. else if ( n_axis != num_axis )
  559. {
  560. FT_ERROR(( "parse_blend_design_positions: incorrect table\n" ));
  561. error = T1_Err_Invalid_File_Format;
  562. goto Exit;
  563. }
  564. /* now read each axis token into the design position */
  565. for ( axis = 0; axis < n_axis; axis++ )
  566. {
  567. T1_Token token2 = axis_tokens + axis;
  568. parser->root.cursor = token2->start;
  569. parser->root.limit = token2->limit;
  570. blend->design_pos[n][axis] = T1_ToFixed( parser, 0 );
  571. }
  572. }
  573. loader->parser.root.cursor = old_cursor;
  574. loader->parser.root.limit = old_limit;
  575. }
  576. Exit:
  577. loader->parser.root.error = error;
  578. }
  579. static void
  580. parse_blend_design_map( T1_Face face,
  581. T1_Loader loader )
  582. {
  583. FT_Error error = T1_Err_Ok;
  584. T1_Parser parser = &loader->parser;
  585. PS_Blend blend;
  586. T1_TokenRec axis_tokens[T1_MAX_MM_AXIS];
  587. FT_Int n, num_axis;
  588. FT_Byte* old_cursor;
  589. FT_Byte* old_limit;
  590. FT_Memory memory = face->root.memory;
  591. T1_ToTokenArray( parser, axis_tokens,
  592. T1_MAX_MM_AXIS, &num_axis );
  593. if ( num_axis < 0 )
  594. {
  595. error = T1_Err_Ignore;
  596. goto Exit;
  597. }
  598. if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS )
  599. {
  600. FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n",
  601. num_axis ));
  602. error = T1_Err_Invalid_File_Format;
  603. goto Exit;
  604. }
  605. old_cursor = parser->root.cursor;
  606. old_limit = parser->root.limit;
  607. error = t1_allocate_blend( face, 0, num_axis );
  608. if ( error )
  609. goto Exit;
  610. blend = face->blend;
  611. /* now read each axis design map */
  612. for ( n = 0; n < num_axis; n++ )
  613. {
  614. PS_DesignMap map = blend->design_map + n;
  615. T1_Token axis_token;
  616. T1_TokenRec point_tokens[T1_MAX_MM_MAP_POINTS];
  617. FT_Int p, num_points;
  618. axis_token = axis_tokens + n;
  619. parser->root.cursor = axis_token->start;
  620. parser->root.limit = axis_token->limit;
  621. T1_ToTokenArray( parser, point_tokens,
  622. T1_MAX_MM_MAP_POINTS, &num_points );
  623. if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
  624. {
  625. FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
  626. error = T1_Err_Invalid_File_Format;
  627. goto Exit;
  628. }
  629. /* allocate design map data */
  630. if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) )
  631. goto Exit;
  632. map->blend_points = map->design_points + num_points;
  633. map->num_points = (FT_Byte)num_points;
  634. for ( p = 0; p < num_points; p++ )
  635. {
  636. T1_Token point_token;
  637. point_token = point_tokens + p;
  638. /* don't include delimiting brackets */
  639. parser->root.cursor = point_token->start + 1;
  640. parser->root.limit = point_token->limit - 1;
  641. map->design_points[p] = T1_ToInt( parser );
  642. map->blend_points [p] = T1_ToFixed( parser, 0 );
  643. }
  644. }
  645. parser->root.cursor = old_cursor;
  646. parser->root.limit = old_limit;
  647. Exit:
  648. parser->root.error = error;
  649. }
  650. static void
  651. parse_weight_vector( T1_Face face,
  652. T1_Loader loader )
  653. {
  654. T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS];
  655. FT_Int num_designs;
  656. FT_Error error = T1_Err_Ok;
  657. T1_Parser parser = &loader->parser;
  658. PS_Blend blend = face->blend;
  659. T1_Token token;
  660. FT_Int n;
  661. FT_Byte* old_cursor;
  662. FT_Byte* old_limit;
  663. T1_ToTokenArray( parser, design_tokens,
  664. T1_MAX_MM_DESIGNS, &num_designs );
  665. if ( num_designs < 0 )
  666. {
  667. error = T1_Err_Ignore;
  668. goto Exit;
  669. }
  670. if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS )
  671. {
  672. FT_ERROR(( "parse_weight_vector:"
  673. " incorrect number of designs: %d\n",
  674. num_designs ));
  675. error = T1_Err_Invalid_File_Format;
  676. goto Exit;
  677. }
  678. if ( !blend || !blend->num_designs )
  679. {
  680. error = t1_allocate_blend( face, num_designs, 0 );
  681. if ( error )
  682. goto Exit;
  683. blend = face->blend;
  684. }
  685. else if ( blend->num_designs != (FT_UInt)num_designs )
  686. {
  687. FT_ERROR(( "parse_weight_vector:"
  688. " /BlendDesignPosition and /WeightVector have\n"
  689. " "
  690. " different number of elements\n" ));
  691. error = T1_Err_Invalid_File_Format;
  692. goto Exit;
  693. }
  694. old_cursor = parser->root.cursor;
  695. old_limit = parser->root.limit;
  696. for ( n = 0; n < num_designs; n++ )
  697. {
  698. token = design_tokens + n;
  699. parser->root.cursor = token->start;
  700. parser->root.limit = token->limit;
  701. blend->default_weight_vector[n] =
  702. blend->weight_vector[n] = T1_ToFixed( parser, 0 );
  703. }
  704. parser->root.cursor = old_cursor;
  705. parser->root.limit = old_limit;
  706. Exit:
  707. parser->root.error = error;
  708. }
  709. /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def */
  710. /* we're only interested in the number of array elements */
  711. static void
  712. parse_buildchar( T1_Face face,
  713. T1_Loader loader )
  714. {
  715. face->len_buildchar = T1_ToFixedArray( &loader->parser, 0, NULL, 0 );
  716. return;
  717. }
  718. #endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */
  719. /*************************************************************************/
  720. /*************************************************************************/
  721. /***** *****/
  722. /***** TYPE 1 SYMBOL PARSING *****/
  723. /***** *****/
  724. /*************************************************************************/
  725. /*************************************************************************/
  726. static FT_Error
  727. t1_load_keyword( T1_Face face,
  728. T1_Loader loader,
  729. const T1_Field field )
  730. {
  731. FT_Error error;
  732. void* dummy_object;
  733. void** objects;
  734. FT_UInt max_objects;
  735. PS_Blend blend = face->blend;
  736. if ( blend && blend->num_designs == 0 )
  737. blend = NULL;
  738. /* if the keyword has a dedicated callback, call it */
  739. if ( field->type == T1_FIELD_TYPE_CALLBACK )
  740. {
  741. field->reader( (FT_Face)face, loader );
  742. error = loader->parser.root.error;
  743. goto Exit;
  744. }
  745. /* now, the keyword is either a simple field, or a table of fields; */
  746. /* we are now going to take care of it */
  747. switch ( field->location )
  748. {
  749. case T1_FIELD_LOCATION_FONT_INFO:
  750. dummy_object = &face->type1.font_info;
  751. objects = &dummy_object;
  752. max_objects = 0;
  753. if ( blend )
  754. {
  755. objects = (void**)blend->font_infos;
  756. max_objects = blend->num_designs;
  757. }
  758. break;
  759. case T1_FIELD_LOCATION_FONT_EXTRA:
  760. dummy_object = &face->type1.font_extra;
  761. objects = &dummy_object;
  762. max_objects = 0;
  763. break;
  764. case T1_FIELD_LOCATION_PRIVATE:
  765. dummy_object = &face->type1.private_dict;
  766. objects = &dummy_object;
  767. max_objects = 0;
  768. if ( blend )
  769. {
  770. objects = (void**)blend->privates;
  771. max_objects = blend->num_designs;
  772. }
  773. break;
  774. case T1_FIELD_LOCATION_BBOX:
  775. dummy_object = &face->type1.font_bbox;
  776. objects = &dummy_object;
  777. max_objects = 0;
  778. if ( blend )
  779. {
  780. objects = (void**)blend->bboxes;
  781. max_objects = blend->num_designs;
  782. }
  783. break;
  784. case T1_FIELD_LOCATION_LOADER:
  785. dummy_object = loader;
  786. objects = &dummy_object;
  787. max_objects = 0;
  788. break;
  789. case T1_FIELD_LOCATION_FACE:
  790. dummy_object = face;
  791. objects = &dummy_object;
  792. max_objects = 0;
  793. break;
  794. #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
  795. case T1_FIELD_LOCATION_BLEND:
  796. dummy_object = face->blend;
  797. objects = &dummy_object;
  798. max_objects = 0;
  799. break;
  800. #endif
  801. default:
  802. dummy_object = &face->type1;
  803. objects = &dummy_object;
  804. max_objects = 0;
  805. }
  806. if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
  807. field->type == T1_FIELD_TYPE_FIXED_ARRAY )
  808. error = T1_Load_Field_Table( &loader->parser, field,
  809. objects, max_objects, 0 );
  810. else
  811. error = T1_Load_Field( &loader->parser, field,
  812. objects, max_objects, 0 );
  813. Exit:
  814. return error;
  815. }
  816. static void
  817. parse_private( T1_Face face,
  818. T1_Loader loader )
  819. {
  820. FT_UNUSED( face );
  821. loader->keywords_encountered |= T1_PRIVATE;
  822. }
  823. static int
  824. read_binary_data( T1_Parser parser,
  825. FT_Long* size,
  826. FT_Byte** base )
  827. {
  828. FT_Byte* cur;
  829. FT_Byte* limit = parser->root.limit;
  830. /* the binary data has one of the following formats */
  831. /* */
  832. /* `size' [white*] RD white ....... ND */
  833. /* `size' [white*] -| white ....... |- */
  834. /* */
  835. T1_Skip_Spaces( parser );
  836. cur = parser->root.cursor;
  837. if ( cur < limit && ft_isdigit( *cur ) )
  838. {
  839. FT_Long s = T1_ToInt( parser );
  840. T1_Skip_PS_Token( parser ); /* `RD' or `-|' or something else */
  841. /* there is only one whitespace char after the */
  842. /* `RD' or `-|' token */
  843. *base = parser->root.cursor + 1;
  844. if ( s >= 0 && s < limit - *base )
  845. {
  846. parser->root.cursor += s + 1;
  847. *size = s;
  848. return !parser->root.error;
  849. }
  850. }
  851. FT_ERROR(( "read_binary_data: invalid size field\n" ));
  852. parser->root.error = T1_Err_Invalid_File_Format;
  853. return 0;
  854. }
  855. /* We now define the routines to handle the `/Encoding', `/Subrs', */
  856. /* and `/CharStrings' dictionaries. */
  857. static void
  858. t1_parse_font_matrix( T1_Face face,
  859. T1_Loader loader )
  860. {
  861. T1_Parser parser = &loader->parser;
  862. FT_Matrix* matrix = &face->type1.font_matrix;
  863. FT_Vector* offset = &face->type1.font_offset;
  864. FT_Face root = (FT_Face)&face->root;
  865. FT_Fixed temp[6];
  866. FT_Fixed temp_scale;
  867. FT_Int result;
  868. result = T1_ToFixedArray( parser, 6, temp, 3 );
  869. if ( result < 0 )
  870. {
  871. parser->root.error = T1_Err_Invalid_File_Format;
  872. return;
  873. }
  874. temp_scale = FT_ABS( temp[3] );
  875. if ( temp_scale == 0 )
  876. {
  877. FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" ));
  878. parser->root.error = T1_Err_Invalid_File_Format;
  879. return;
  880. }
  881. /* Set Units per EM based on FontMatrix values. We set the value to */
  882. /* 1000 / temp_scale, because temp_scale was already multiplied by */
  883. /* 1000 (in t1_tofixed, from psobjs.c). */
  884. root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
  885. temp_scale ) >> 16 );
  886. /* we need to scale the values by 1.0/temp_scale */
  887. if ( temp_scale != 0x10000L )
  888. {
  889. temp[0] = FT_DivFix( temp[0], temp_scale );
  890. temp[1] = FT_DivFix( temp[1], temp_scale );
  891. temp[2] = FT_DivFix( temp[2], temp_scale );
  892. temp[4] = FT_DivFix( temp[4], temp_scale );
  893. temp[5] = FT_DivFix( temp[5], temp_scale );
  894. temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L;
  895. }
  896. matrix->xx = temp[0];
  897. matrix->yx = temp[1];
  898. matrix->xy = temp[2];
  899. matrix->yy = temp[3];
  900. /* note that the offsets must be expressed in integer font units */
  901. offset->x = temp[4] >> 16;
  902. offset->y = temp[5] >> 16;
  903. }
  904. static void
  905. parse_encoding( T1_Face face,
  906. T1_Loader loader )
  907. {
  908. T1_Parser parser = &loader->parser;
  909. FT_Byte* cur;
  910. FT_Byte* limit = parser->root.limit;
  911. PSAux_Service psaux = (PSAux_Service)face->psaux;
  912. T1_Skip_Spaces( parser );
  913. cur = parser->root.cursor;
  914. if ( cur >= limit )
  915. {
  916. FT_ERROR(( "parse_encoding: out of bounds\n" ));
  917. parser->root.error = T1_Err_Invalid_File_Format;
  918. return;
  919. }
  920. /* if we have a number or `[', the encoding is an array, */
  921. /* and we must load it now */
  922. if ( ft_isdigit( *cur ) || *cur == '[' )
  923. {
  924. T1_Encoding encode = &face->type1.encoding;
  925. FT_Int count, n;
  926. PS_Table char_table = &loader->encoding_table;
  927. FT_Memory memory = parser->root.memory;
  928. FT_Error error;
  929. FT_Bool only_immediates = 0;
  930. /* read the number of entries in the encoding; should be 256 */
  931. if ( *cur == '[' )
  932. {
  933. count = 256;
  934. only_immediates = 1;
  935. parser->root.cursor++;
  936. }
  937. else
  938. count = (FT_Int)T1_ToInt( parser );
  939. T1_Skip_Spaces( parser );
  940. if ( parser->root.cursor >= limit )
  941. return;
  942. /* we use a T1_Table to store our charnames */
  943. loader->num_chars = encode->num_chars = count;
  944. if ( FT_NEW_ARRAY( encode->char_index, count ) ||
  945. FT_NEW_ARRAY( encode->char_name, count ) ||
  946. FT_SET_ERROR( psaux->ps_table_funcs->init(
  947. char_table, count, memory ) ) )
  948. {
  949. parser->root.error = error;
  950. return;
  951. }
  952. /* We need to `zero' out encoding_table.elements */
  953. for ( n = 0; n < count; n++ )
  954. {
  955. char* notdef = (char *)".notdef";
  956. T1_Add_Table( char_table, n, notdef, 8 );
  957. }
  958. /* Now we need to read records of the form */
  959. /* */
  960. /* ... charcode /charname ... */
  961. /* */
  962. /* for each entry in our table. */
  963. /* */
  964. /* We simply look for a number followed by an immediate */
  965. /* name. Note that this ignores correctly the sequence */
  966. /* that is often seen in type1 fonts: */
  967. /* */
  968. /* 0 1 255 { 1 index exch /.notdef put } for dup */
  969. /* */
  970. /* used to clean the encoding array before anything else. */
  971. /* */
  972. /* Alternatively, if the array is directly given as */
  973. /* */
  974. /* /Encoding [ ... ] */
  975. /* */
  976. /* we only read immediates. */
  977. n = 0;
  978. T1_Skip_Spaces( parser );
  979. while ( parser->root.cursor < limit )
  980. {
  981. cur = parser->root.cursor;
  982. /* we stop when we encounter a `def' or `]' */
  983. if ( *cur == 'd' && cur + 3 < limit )
  984. {
  985. if ( cur[1] == 'e' &&
  986. cur[2] == 'f' &&
  987. IS_PS_DELIM( cur[3] ) )
  988. {
  989. FT_TRACE6(( "encoding end\n" ));
  990. cur += 3;
  991. break;
  992. }
  993. }
  994. if ( *cur == ']' )
  995. {
  996. FT_TRACE6(( "encoding end\n" ));
  997. cur++;
  998. break;
  999. }
  1000. /* check whether we've found an entry */
  1001. if ( ft_isdigit( *cur ) || only_immediates )
  1002. {
  1003. FT_Int charcode;
  1004. if ( only_immediates )
  1005. charcode = n;
  1006. else
  1007. {
  1008. charcode = (FT_Int)T1_ToInt( parser );
  1009. T1_Skip_Spaces( parser );
  1010. }
  1011. cur = parser->root.cursor;
  1012. if ( *cur == '/' && cur + 2 < limit && n < count )
  1013. {
  1014. FT_PtrDist len;
  1015. cur++;
  1016. parser->root.cursor = cur;
  1017. T1_Skip_PS_Token( parser );
  1018. if ( parser->root.error )
  1019. return;
  1020. len = parser->root.cursor - cur;
  1021. parser->root.error = T1_Add_Table( char_table, charcode,
  1022. cur, len + 1 );
  1023. if ( parser->root.error )
  1024. return;
  1025. char_table->elements[charcode][len] = '\0';
  1026. n++;
  1027. }
  1028. else if ( only_immediates )
  1029. {
  1030. /* Since the current position is not updated for */
  1031. /* immediates-only mode we would get an infinite loop if */
  1032. /* we don't do anything here. */
  1033. /* */
  1034. /* This encoding array is not valid according to the type1 */
  1035. /* specification (it might be an encoding for a CID type1 */
  1036. /* font, however), so we conclude that this font is NOT a */
  1037. /* type1 font. */
  1038. parser->root.error = FT_Err_Unknown_File_Format;
  1039. return;
  1040. }
  1041. }
  1042. else
  1043. {
  1044. T1_Skip_PS_Token( parser );
  1045. if ( parser->root.error )
  1046. return;
  1047. }
  1048. T1_Skip_Spaces( parser );
  1049. }
  1050. face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
  1051. parser->root.cursor = cur;
  1052. }
  1053. /* Otherwise, we should have either `StandardEncoding', */
  1054. /* `ExpertEncoding', or `ISOLatin1Encoding' */
  1055. else
  1056. {
  1057. if ( cur + 17 < limit &&
  1058. ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
  1059. face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
  1060. else if ( cur + 15 < limit &&
  1061. ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
  1062. face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
  1063. else if ( cur + 18 < limit &&
  1064. ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
  1065. face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
  1066. else
  1067. parser->root.error = T1_Err_Ignore;
  1068. }
  1069. }
  1070. static void
  1071. parse_subrs( T1_Face face,
  1072. T1_Loader loader )
  1073. {
  1074. T1_Parser parser = &loader->parser;
  1075. PS_Table table = &loader->subrs;
  1076. FT_Memory memory = parser->root.memory;
  1077. FT_Error error;
  1078. FT_Int num_subrs;
  1079. PSAux_Service psaux = (PSAux_Service)face->psaux;
  1080. T1_Skip_Spaces( parser );
  1081. /* test for empty array */
  1082. if ( parser->root.cursor < parser->root.limit &&
  1083. *parser->root.cursor == '[' )
  1084. {
  1085. T1_Skip_PS_Token( parser );
  1086. T1_Skip_Spaces ( parser );
  1087. if ( parser->root.cursor >= parser->root.limit ||
  1088. *parser->root.cursor != ']' )
  1089. parser->root.error = T1_Err_Invalid_File_Format;
  1090. return;
  1091. }
  1092. num_subrs = (FT_Int)T1_ToInt( parser );
  1093. /* position the parser right before the `dup' of the first subr */
  1094. T1_Skip_PS_Token( parser ); /* `array' */
  1095. if ( parser->root.error )
  1096. return;
  1097. T1_Skip_Spaces( parser );
  1098. /* initialize subrs array -- with synthetic fonts it is possible */
  1099. /* we get here twice */
  1100. if ( !loader->num_subrs )
  1101. {
  1102. error = psaux->ps_table_funcs->init( table, num_subrs, memory );
  1103. if ( error )
  1104. goto Fail;
  1105. }
  1106. /* the format is simple: */
  1107. /* */
  1108. /* `index' + binary data */
  1109. /* */
  1110. for (;;)
  1111. {
  1112. FT_Long idx, size;
  1113. FT_Byte* base;
  1114. /* If the next token isn't `dup' we are done. */
  1115. if ( parser->root.cursor + 4 < parser->root.limit &&
  1116. ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
  1117. break;
  1118. T1_Skip_PS_Token( parser ); /* `dup' */
  1119. idx = T1_ToInt( parser );
  1120. if ( !read_binary_data( parser, &size, &base ) )
  1121. return;
  1122. /* The binary string is followed by one token, e.g. `NP' */
  1123. /* (bound to `noaccess put') or by two separate tokens: */
  1124. /* `noaccess' & `put'. We position the parser right */
  1125. /* before the next `dup', if any. */
  1126. T1_Skip_PS_Token( parser ); /* `NP' or `|' or `noaccess' */
  1127. if ( parser->root.error )
  1128. return;
  1129. T1_Skip_Spaces ( parser );
  1130. if ( parser->root.cursor + 4 < parser->root.limit &&
  1131. ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 )
  1132. {
  1133. T1_Skip_PS_Token( parser ); /* skip `put' */
  1134. T1_Skip_Spaces ( parser );
  1135. }
  1136. /* with synthetic fonts it is possible we get here twice */
  1137. if ( loader->num_subrs )
  1138. continue;
  1139. /* some fonts use a value of -1 for lenIV to indicate that */
  1140. /* the charstrings are unencoded */
  1141. /* */
  1142. /* thanks to Tom Kacvinsky for pointing this out */
  1143. /* */
  1144. if ( face->type1.private_dict.lenIV >= 0 )
  1145. {
  1146. FT_Byte* temp;
  1147. /* some fonts define empty subr records -- this is not totally */
  1148. /* compliant to the specification (which says they should at */
  1149. /* least contain a `return'), but we support them anyway */
  1150. if ( size < face->type1.private_dict.lenIV )
  1151. {
  1152. error = T1_Err_Invalid_File_Format;
  1153. goto Fail;
  1154. }
  1155. /* t1_decrypt() shouldn't write to base -- make temporary copy */
  1156. if ( FT_ALLOC( temp, size ) )
  1157. goto Fail;
  1158. FT_MEM_COPY( temp, base, size );
  1159. psaux->t1_decrypt( temp, size, 4330 );
  1160. size -= face->type1.private_dict.lenIV;
  1161. error = T1_Add_Table( table, (FT_Int)idx,
  1162. temp + face->type1.private_dict.lenIV, size );
  1163. FT_FREE( temp );
  1164. }
  1165. else
  1166. error = T1_Add_Table( table, (FT_Int)idx, base, size );
  1167. if ( error )
  1168. goto Fail;
  1169. }
  1170. if ( !loader->num_subrs )
  1171. loader->num_subrs = num_subrs;
  1172. return;
  1173. Fail:
  1174. parser->root.error = error;
  1175. }
  1176. #define TABLE_EXTEND 5
  1177. static void
  1178. parse_charstrings( T1_Face face,
  1179. T1_Loader loader )
  1180. {
  1181. T1_Parser parser = &loader->parser;
  1182. PS_Table code_table = &loader->charstrings;
  1183. PS_Table name_table = &loader->glyph_names;
  1184. PS_Table swap_table = &loader->swap_table;
  1185. FT_Memory memory = parser->root.memory;
  1186. FT_Error error;
  1187. PSAux_Service psaux = (PSAux_Service)face->psaux;
  1188. FT_Byte* cur;
  1189. FT_Byte* limit = parser->root.limit;
  1190. FT_Int n, num_glyphs;
  1191. FT_UInt notdef_index = 0;
  1192. FT_Byte notdef_found = 0;
  1193. num_glyphs = (FT_Int)T1_ToInt( parser );
  1194. /* some fonts like Optima-Oblique not only define the /CharStrings */
  1195. /* array but access it also */
  1196. if ( num_glyphs == 0 || parser->root.error )
  1197. return;
  1198. /* initialize tables, leaving space for addition of .notdef, */
  1199. /* if necessary, and a few other glyphs to handle buggy */
  1200. /* fonts which have more glyphs than specified. */
  1201. /* for some non-standard fonts like `Optima' which provides */
  1202. /* different outlines depending on the resolution it is */
  1203. /* possible to get here twice */
  1204. if ( !loader->num_glyphs )
  1205. {
  1206. error = psaux->ps_table_funcs->init(
  1207. code_table, num_glyphs + 1 + TABLE_EXTEND, memory );
  1208. if ( error )
  1209. goto Fail;
  1210. error = psaux->ps_table_funcs->init(
  1211. name_table, num_glyphs + 1 + TABLE_EXTEND, memory );
  1212. if ( error )
  1213. goto Fail;
  1214. /* Initialize table for swapping index notdef_index and */
  1215. /* index 0 names and codes (if necessary). */
  1216. error = psaux->ps_table_funcs->init( swap_table, 4, memory );
  1217. if ( error )
  1218. goto Fail;
  1219. }
  1220. n = 0;
  1221. for (;;)
  1222. {
  1223. FT_Long size;
  1224. FT_Byte* base;
  1225. /* the format is simple: */
  1226. /* `/glyphname' + binary data */
  1227. T1_Skip_Spaces( parser );
  1228. cur = parser->root.cursor;
  1229. if ( cur >= limit )
  1230. break;
  1231. /* we stop when we find a `def' or `end' keyword */
  1232. if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) )
  1233. {
  1234. if ( cur[0] == 'd' &&
  1235. cur[1] == 'e' &&
  1236. cur[2] == 'f' )
  1237. {
  1238. /* There are fonts which have this: */
  1239. /* */
  1240. /* /CharStrings 118 dict def */
  1241. /* Private begin */
  1242. /* CharStrings begin */
  1243. /* ... */
  1244. /* */
  1245. /* To catch this we ignore `def' if */
  1246. /* no charstring has actually been */
  1247. /* seen. */
  1248. if ( n )
  1249. break;
  1250. }
  1251. if ( cur[0] == 'e' &&
  1252. cur[1] == 'n' &&
  1253. cur[2] == 'd' )
  1254. break;
  1255. }
  1256. T1_Skip_PS_Token( parser );
  1257. if ( parser->root.error )
  1258. return;
  1259. if ( *cur == '/' )
  1260. {
  1261. FT_PtrDist len;
  1262. if ( cur + 1 >= limit )
  1263. {
  1264. error = T1_Err_Invalid_File_Format;
  1265. goto Fail;
  1266. }
  1267. cur++; /* skip `/' */
  1268. len = parser->root.cursor - cur;
  1269. if ( !read_binary_data( parser, &size, &base ) )
  1270. return;
  1271. /* for some non-standard fonts like `Optima' which provides */
  1272. /* different outlines depending on the resolution it is */
  1273. /* possible to get here twice */
  1274. if ( loader->num_glyphs )
  1275. continue;
  1276. error = T1_Add_Table( name_table, n, cur, len + 1 );
  1277. if ( error )
  1278. goto Fail;
  1279. /* add a trailing zero to the name table */
  1280. name_table->elements[n][len] = '\0';
  1281. /* record index of /.notdef */
  1282. if ( *cur == '.' &&
  1283. ft_strcmp( ".notdef",
  1284. (const char*)(name_table->elements[n]) ) == 0 )
  1285. {
  1286. notdef_index = n;
  1287. notdef_found = 1;
  1288. }
  1289. if ( face->type1.private_dict.lenIV >= 0 &&
  1290. n < num_glyphs + TABLE_EXTEND )
  1291. {
  1292. FT_Byte* temp;
  1293. if ( size <= face->type1.private_dict.lenIV )
  1294. {
  1295. error = T1_Err_Invalid_File_Format;
  1296. goto Fail;
  1297. }
  1298. /* t1_decrypt() shouldn't write to base -- make temporary copy */
  1299. if ( FT_ALLOC( temp, size ) )
  1300. goto Fail;
  1301. FT_MEM_COPY( temp, base, size );
  1302. psaux->t1_decrypt( temp, size, 4330 );
  1303. size -= face->type1.private_dict.lenIV;
  1304. error = T1_Add_Table( code_table, n,
  1305. temp + face->type1.private_dict.lenIV, size );
  1306. FT_FREE( temp );
  1307. }
  1308. else
  1309. error = T1_Add_Table( code_table, n, base, size );
  1310. if ( error )
  1311. goto Fail;
  1312. n++;
  1313. }
  1314. }
  1315. loader->num_glyphs = n;
  1316. /* if /.notdef is found but does not occupy index 0, do our magic. */
  1317. if ( notdef_found &&
  1318. ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) )
  1319. {
  1320. /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */
  1321. /* name and code entries to swap_table. Then place notdef_index */
  1322. /* name and code entries into swap_table. Then swap name and code */
  1323. /* entries at indices notdef_index and 0 using values stored in */
  1324. /* swap_table. */
  1325. /* Index 0 name */
  1326. error = T1_Add_Table( swap_table, 0,
  1327. name_table->elements[0],
  1328. name_table->lengths [0] );
  1329. if ( error )
  1330. goto Fail;
  1331. /* Index 0 code */
  1332. error = T1_Add_Table( swap_table, 1,
  1333. code_table->elements[0],
  1334. code_table->lengths [0] );
  1335. if ( error )
  1336. goto Fail;
  1337. /* Index notdef_index name */
  1338. error = T1_Add_Table( swap_table, 2,
  1339. name_table->elements[notdef_index],
  1340. name_table->lengths [notdef_index] );
  1341. if ( error )
  1342. goto Fail;
  1343. /* Index notdef_index code */
  1344. error = T1_Add_Table( swap_table, 3,
  1345. code_table->elements[notdef_index],
  1346. code_table->lengths [notdef_index] );
  1347. if ( error )
  1348. goto Fail;
  1349. error = T1_Add_Table( name_table, notdef_index,
  1350. swap_table->elements[0],
  1351. swap_table->lengths [0] );
  1352. if ( error )
  1353. goto Fail;
  1354. error = T1_Add_Table( code_table, notdef_index,
  1355. swap_table->elements[1],
  1356. swap_table->lengths [1] );
  1357. if ( error )
  1358. goto Fail;
  1359. error = T1_Add_Table( name_table, 0,
  1360. swap_table->elements[2],
  1361. swap_table->lengths [2] );
  1362. if ( error )
  1363. goto Fail;
  1364. error = T1_Add_Table( code_table, 0,
  1365. swap_table->elements[3],
  1366. swap_table->lengths [3] );
  1367. if ( error )
  1368. goto Fail;
  1369. }
  1370. else if ( !notdef_found )
  1371. {
  1372. /* notdef_index is already 0, or /.notdef is undefined in */
  1373. /* charstrings dictionary. Worry about /.notdef undefined. */
  1374. /* We take index 0 and add it to the end of the table(s) */
  1375. /* and add our own /.notdef glyph to index 0. */
  1376. /* 0 333 hsbw endchar */
  1377. FT_Byte notdef_glyph[] = { 0x8B, 0xF7, 0xE1, 0x0D, 0x0E };
  1378. char* notdef_name = (char *)".notdef";
  1379. error = T1_Add_Table( swap_table, 0,
  1380. name_table->elements[0],
  1381. name_table->lengths [0] );
  1382. if ( error )
  1383. goto Fail;
  1384. error = T1_Add_Table( swap_table, 1,
  1385. code_table->elements[0],
  1386. code_table->lengths [0] );
  1387. if ( error )
  1388. goto Fail;
  1389. error = T1_Add_Table( name_table, 0, notdef_name, 8 );
  1390. if ( error )
  1391. goto Fail;
  1392. error = T1_Add_Table( code_table, 0, notdef_glyph, 5 );
  1393. if ( error )
  1394. goto Fail;
  1395. error = T1_Add_Table( name_table, n,
  1396. swap_table->elements[0],
  1397. swap_table->lengths [0] );
  1398. if ( error )
  1399. goto Fail;
  1400. error = T1_Add_Table( code_table, n,
  1401. swap_table->elements[1],
  1402. swap_table->lengths [1] );
  1403. if ( error )
  1404. goto Fail;
  1405. /* we added a glyph. */
  1406. loader->num_glyphs += 1;
  1407. }
  1408. return;
  1409. Fail:
  1410. parser->root.error = error;
  1411. }
  1412. /*************************************************************************/
  1413. /* */
  1414. /* Define the token field static variables. This is a set of */
  1415. /* T1_FieldRec variables. */
  1416. /* */
  1417. /*************************************************************************/
  1418. static
  1419. const T1_FieldRec t1_keywords[] =
  1420. {
  1421. #include "t1tokens.h"
  1422. /* now add the special functions... */
  1423. T1_FIELD_CALLBACK( "FontMatrix", t1_parse_font_matrix,
  1424. T1_FIELD_DICT_FONTDICT )
  1425. T1_FIELD_CALLBACK( "Encoding", parse_encoding,
  1426. T1_FIELD_DICT_FONTDICT )
  1427. T1_FIELD_CALLBACK( "Subrs", parse_subrs,
  1428. T1_FIELD_DICT_PRIVATE )
  1429. T1_FIELD_CALLBACK( "CharStrings", parse_charstrings,
  1430. T1_FIELD_DICT_PRIVATE )
  1431. T1_FIELD_CALLBACK( "Private", parse_private,
  1432. T1_FIELD_DICT_FONTDICT )
  1433. #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
  1434. T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions,
  1435. T1_FIELD_DICT_FONTDICT )
  1436. T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map,
  1437. T1_FIELD_DICT_FONTDICT )
  1438. T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types,
  1439. T1_FIELD_DICT_FONTDICT )
  1440. T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector,
  1441. T1_FIELD_DICT_FONTDICT )
  1442. T1_FIELD_CALLBACK( "BuildCharArray", parse_buildchar,
  1443. T1_FIELD_DICT_PRIVATE )
  1444. #endif
  1445. { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 }
  1446. };
  1447. #define T1_FIELD_COUNT \
  1448. ( sizeof ( t1_keywords ) / sizeof ( t1_keywords[0] ) )
  1449. static FT_Error
  1450. parse_dict( T1_Face face,
  1451. T1_Loader loader,
  1452. FT_Byte* base,
  1453. FT_Long size )
  1454. {
  1455. T1_Parser parser = &loader->parser;
  1456. FT_Byte *limit, *start_binary = NULL;
  1457. FT_Bool have_integer = 0;
  1458. parser->root.cursor = base;
  1459. parser->root.limit = base + size;
  1460. parser->root.error = T1_Err_Ok;
  1461. limit = parser->root.limit;
  1462. T1_Skip_Spaces( parser );
  1463. while ( parser->root.cursor < limit )
  1464. {
  1465. FT_Byte* cur;
  1466. cur = parser->root.cursor;
  1467. /* look for `eexec' */
  1468. if ( IS_PS_TOKEN( cur, limit, "eexec" ) )
  1469. break;
  1470. /* look for `closefile' which ends the eexec section */
  1471. else if ( IS_PS_TOKEN( cur, limit, "closefile" ) )
  1472. break;
  1473. /* in a synthetic font the base font starts after a */
  1474. /* `FontDictionary' token that is placed after a Private dict */
  1475. else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) )
  1476. {
  1477. if ( loader->keywords_encountered & T1_PRIVATE )
  1478. loader->keywords_encountered |=
  1479. T1_FONTDIR_AFTER_PRIVATE;
  1480. parser->root.cursor += 13;
  1481. }
  1482. /* check whether we have an integer */
  1483. else if ( ft_isdigit( *cur ) )
  1484. {
  1485. start_binary = cur;
  1486. T1_Skip_PS_Token( parser );
  1487. if ( parser->root.error )
  1488. goto Exit;
  1489. have_integer = 1;
  1490. }
  1491. /* in valid Type 1 fonts we don't see `RD' or `-|' directly */
  1492. /* since those tokens are handled by parse_subrs and */
  1493. /* parse_charstrings */
  1494. else if ( *cur == 'R' && cur + 6 < limit && *(cur + 1) == 'D' &&
  1495. have_integer )
  1496. {
  1497. FT_Long s;
  1498. FT_Byte* b;
  1499. parser->root.cursor = start_binary;
  1500. if ( !read_binary_data( parser, &s, &b ) )
  1501. return T1_Err_Invalid_File_Format;
  1502. have_integer = 0;
  1503. }
  1504. else if ( *cur == '-' && cur + 6 < limit && *(cur + 1) == '|' &&
  1505. have_integer )
  1506. {
  1507. FT_Long s;
  1508. FT_Byte* b;
  1509. parser->root.cursor = start_binary;
  1510. if ( !read_binary_data( parser, &s, &b ) )
  1511. return T1_Err_Invalid_File_Format;
  1512. have_integer = 0;
  1513. }
  1514. /* look for immediates */
  1515. else if ( *cur == '/' && cur + 2 < limit )
  1516. {
  1517. FT_PtrDist len;
  1518. cur++;
  1519. parser->root.cursor = cur;
  1520. T1_Skip_PS_Token( parser );
  1521. if ( parser->root.error )
  1522. goto Exit;
  1523. len = parser->root.cursor - cur;
  1524. if ( len > 0 && len < 22 && parser->root.cursor < limit )
  1525. {
  1526. /* now compare the immediate name to the keyword table */
  1527. T1_Field keyword = (T1_Field)t1_keywords;
  1528. for (;;)
  1529. {
  1530. FT_Byte* name;
  1531. name = (FT_Byte*)keyword->ident;
  1532. if ( !name )
  1533. break;
  1534. if ( cur[0] == name[0] &&
  1535. len == (FT_PtrDist)ft_strlen( (const char *)name ) &&
  1536. ft_memcmp( cur, name, len ) == 0 )
  1537. {
  1538. /* We found it -- run the parsing callback! */
  1539. /* We record every instance of every field */
  1540. /* (until we reach the base font of a */
  1541. /* synthetic font) to deal adequately with */
  1542. /* multiple master fonts; this is also */
  1543. /* necessary because later PostScript */
  1544. /* definitions override earlier ones. */
  1545. /* Once we encounter `FontDirectory' after */
  1546. /* `/Private', we know that this is a synthetic */
  1547. /* font; except for `/CharStrings' we are not */
  1548. /* interested in anything that follows this */
  1549. /* `FontDirectory'. */
  1550. /* MM fonts have more than one /Private token at */
  1551. /* the top level; let's hope that all the junk */
  1552. /* that follows the first /Private token is not */
  1553. /* interesting to us. */
  1554. /* According to Adobe Tech Note #5175 (CID-Keyed */
  1555. /* Font Installation for ATM Software) a `begin' */
  1556. /* must be followed by exactly one `end', and */
  1557. /* `begin' -- `end' pairs must be accurately */
  1558. /* paired. We could use this to distinguish */
  1559. /* between the global Private and the Private */
  1560. /* dict that is a member of the Blend dict. */
  1561. const FT_UInt dict =
  1562. ( loader->keywords_encountered & T1_PRIVATE )
  1563. ? T1_FIELD_DICT_PRIVATE
  1564. : T1_FIELD_DICT_FONTDICT;
  1565. if ( !( dict & keyword->dict ) )
  1566. {
  1567. FT_TRACE1(( "parse_dict: found %s but ignoring it "
  1568. "since it is in the wrong dictionary\n",
  1569. keyword->ident ));
  1570. break;
  1571. }
  1572. if ( !( loader->keywords_encountered &
  1573. T1_FONTDIR_AFTER_PRIVATE ) ||
  1574. ft_strcmp( (const char*)name, "CharStrings" ) == 0 )
  1575. {
  1576. parser->root.error = t1_load_keyword( face,
  1577. loader,
  1578. keyword );
  1579. if ( parser->root.error != T1_Err_Ok )
  1580. {
  1581. if ( FT_ERROR_BASE( parser->root.error ) == FT_Err_Ignore )
  1582. parser->root.error = T1_Err_Ok;
  1583. else
  1584. return parser->root.error;
  1585. }
  1586. }
  1587. break;
  1588. }
  1589. keyword++;
  1590. }
  1591. }
  1592. have_integer = 0;
  1593. }
  1594. else
  1595. {
  1596. T1_Skip_PS_Token( parser );
  1597. if ( parser->root.error )
  1598. goto Exit;
  1599. have_integer = 0;
  1600. }
  1601. T1_Skip_Spaces( parser );
  1602. }
  1603. Exit:
  1604. return parser->root.error;
  1605. }
  1606. static void
  1607. t1_init_loader( T1_Loader loader,
  1608. T1_Face face )
  1609. {
  1610. FT_UNUSED( face );
  1611. FT_MEM_ZERO( loader, sizeof ( *loader ) );
  1612. loader->num_glyphs = 0;
  1613. loader->num_chars = 0;
  1614. /* initialize the tables -- simply set their `init' field to 0 */
  1615. loader->encoding_table.init = 0;
  1616. loader->charstrings.init = 0;
  1617. loader->glyph_names.init = 0;
  1618. loader->subrs.init = 0;
  1619. loader->swap_table.init = 0;
  1620. loader->fontdata = 0;
  1621. loader->keywords_encountered = 0;
  1622. }
  1623. static void
  1624. t1_done_loader( T1_Loader loader )
  1625. {
  1626. T1_Parser parser = &loader->parser;
  1627. /* finalize tables */
  1628. T1_Release_Table( &loader->encoding_table );
  1629. T1_Release_Table( &loader->charstrings );
  1630. T1_Release_Table( &loader->glyph_names );
  1631. T1_Release_Table( &loader->swap_table );
  1632. T1_Release_Table( &loader->subrs );
  1633. /* finalize parser */
  1634. T1_Finalize_Parser( parser );
  1635. }
  1636. FT_LOCAL_DEF( FT_Error )
  1637. T1_Open_Face( T1_Face face )
  1638. {
  1639. T1_LoaderRec loader;
  1640. T1_Parser parser;
  1641. T1_Font type1 = &face->type1;
  1642. PS_Private priv = &type1->private_dict;
  1643. FT_Error error;
  1644. PSAux_Service psaux = (PSAux_Service)face->psaux;
  1645. t1_init_loader( &loader, face );
  1646. /* default values */
  1647. face->ndv_idx = -1;
  1648. face->cdv_idx = -1;
  1649. face->len_buildchar = 0;
  1650. priv->blue_shift = 7;
  1651. priv->blue_fuzz = 1;
  1652. priv->lenIV = 4;
  1653. priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
  1654. priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 );
  1655. parser = &loader.parser;
  1656. error = T1_New_Parser( parser,
  1657. face->root.stream,
  1658. face->root.memory,
  1659. psaux );
  1660. if ( error )
  1661. goto Exit;
  1662. error = parse_dict( face, &loader,
  1663. parser->base_dict, parser->base_len );
  1664. if ( error )
  1665. goto Exit;
  1666. error = T1_Get_Private_Dict( parser, psaux );
  1667. if ( error )
  1668. goto Exit;
  1669. error = parse_dict( face, &loader,
  1670. parser->private_dict, parser->private_len );
  1671. if ( error )
  1672. goto Exit;
  1673. /* ensure even-ness of `num_blue_values' */
  1674. priv->num_blue_values &= ~1;
  1675. #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
  1676. if ( face->blend &&
  1677. face->blend->num_default_design_vector != 0 &&
  1678. face->blend->num_default_design_vector != face->blend->num_axis )
  1679. {
  1680. /* we don't use it currently so just warn, reset, and ignore */
  1681. FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries "
  1682. "while there are %u axes.\n",
  1683. face->blend->num_default_design_vector,
  1684. face->blend->num_axis ));
  1685. face->blend->num_default_design_vector = 0;
  1686. }
  1687. /* the following can happen for MM instances; we then treat the */
  1688. /* font as a normal PS font */
  1689. if ( face->blend &&
  1690. ( !face->blend->num_designs || !face->blend->num_axis ) )
  1691. T1_Done_Blend( face );
  1692. /* another safety check */
  1693. if ( face->blend )
  1694. {
  1695. FT_UInt i;
  1696. for ( i = 0; i < face->blend->num_axis; i++ )
  1697. if ( !face->blend->design_map[i].num_points )
  1698. {
  1699. T1_Done_Blend( face );
  1700. break;
  1701. }
  1702. }
  1703. if ( face->blend )
  1704. {
  1705. if ( face->len_buildchar > 0 )
  1706. {
  1707. FT_Memory memory = face->root.memory;
  1708. if ( FT_NEW_ARRAY( face->buildchar, face->len_buildchar ) )
  1709. {
  1710. FT_ERROR(( "T1_Open_Face: cannot allocate BuildCharArray\n" ));
  1711. face->len_buildchar = 0;
  1712. goto Exit;
  1713. }
  1714. }
  1715. }
  1716. else
  1717. face->len_buildchar = 0;
  1718. #endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */
  1719. /* now, propagate the subrs, charstrings, and glyphnames tables */
  1720. /* to the Type1 data */
  1721. type1->num_glyphs = loader.num_glyphs;
  1722. if ( loader.subrs.init )
  1723. {
  1724. loader.subrs.init = 0;
  1725. type1->num_subrs = loader.num_subrs;
  1726. type1->subrs_block = loader.subrs.block;
  1727. type1->subrs = loader.subrs.elements;
  1728. type1->subrs_len = loader.subrs.lengths;
  1729. }
  1730. #ifdef FT_CONFIG_OPTION_INCREMENTAL
  1731. if ( !face->root.internal->incremental_interface )
  1732. #endif
  1733. if ( !loader.charstrings.init )
  1734. {
  1735. FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face\n" ));
  1736. error = T1_Err_Invalid_File_Format;
  1737. }
  1738. loader.charstrings.init = 0;
  1739. type1->charstrings_block = loader.charstrings.block;
  1740. type1->charstrings = loader.charstrings.elements;
  1741. type1->charstrings_len = loader.charstrings.lengths;
  1742. /* we copy the glyph names `block' and `elements' fields; */
  1743. /* the `lengths' field must be released later */
  1744. type1->glyph_names_block = loader.glyph_names.block;
  1745. type1->glyph_names = (FT_String**)loader.glyph_names.elements;
  1746. loader.glyph_names.block = 0;
  1747. loader.glyph_names.elements = 0;
  1748. /* we must now build type1.encoding when we have a custom array */
  1749. if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY )
  1750. {
  1751. FT_Int charcode, idx, min_char, max_char;
  1752. FT_Byte* char_name;
  1753. FT_Byte* glyph_name;
  1754. /* OK, we do the following: for each element in the encoding */
  1755. /* table, look up the index of the glyph having the same name */
  1756. /* the index is then stored in type1.encoding.char_index, and */
  1757. /* the name to type1.encoding.char_name */
  1758. min_char = 0;
  1759. max_char = 0;
  1760. charcode = 0;
  1761. for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
  1762. {
  1763. type1->encoding.char_index[charcode] = 0;
  1764. type1->encoding.char_name [charcode] = (char *)".notdef";
  1765. char_name = loader.encoding_table.elements[charcode];
  1766. if ( char_name )
  1767. for ( idx = 0; idx < type1->num_glyphs; idx++ )
  1768. {
  1769. glyph_name = (FT_Byte*)type1->glyph_names[idx];
  1770. if ( ft_strcmp( (const char*)char_name,
  1771. (const char*)glyph_name ) == 0 )
  1772. {
  1773. type1->encoding.char_index[charcode] = (FT_UShort)idx;
  1774. type1->encoding.char_name [charcode] = (char*)glyph_name;
  1775. /* Change min/max encoded char only if glyph name is */
  1776. /* not /.notdef */
  1777. if ( ft_strcmp( (const char*)".notdef",
  1778. (const char*)glyph_name ) != 0 )
  1779. {
  1780. if ( charcode < min_char )
  1781. min_char = charcode;
  1782. if ( charcode >= max_char )
  1783. max_char = charcode + 1;
  1784. }
  1785. break;
  1786. }
  1787. }
  1788. }
  1789. type1->encoding.code_first = min_char;
  1790. type1->encoding.code_last = max_char;
  1791. type1->encoding.num_chars = loader.num_chars;
  1792. }
  1793. Exit:
  1794. t1_done_loader( &loader );
  1795. return error;
  1796. }
  1797. /* END */