PageRenderTime 32ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/src/freetype/src/truetype/ttgxvar.c

https://bitbucket.org/cabalistic/ogredeps/
C | 1551 lines | 957 code | 258 blank | 336 comment | 219 complexity | 2f115255783908edda59cff6048fa5bd 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. /* ttgxvar.c */
  4. /* */
  5. /* TrueType GX Font Variation loader */
  6. /* */
  7. /* Copyright 2004-2011 by */
  8. /* David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. */
  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. /* Apple documents the `fvar', `gvar', `cvar', and `avar' tables at */
  20. /* */
  21. /* http://developer.apple.com/fonts/TTRefMan/RM06/Chap6[fgca]var.html */
  22. /* */
  23. /* The documentation for `fvar' is inconsistent. At one point it says */
  24. /* that `countSizePairs' should be 3, at another point 2. It should */
  25. /* be 2. */
  26. /* */
  27. /* The documentation for `gvar' is not intelligible; `cvar' refers you */
  28. /* to `gvar' and is thus also incomprehensible. */
  29. /* */
  30. /* The documentation for `avar' appears correct, but Apple has no fonts */
  31. /* with an `avar' table, so it is hard to test. */
  32. /* */
  33. /* Many thanks to John Jenkins (at Apple) in figuring this out. */
  34. /* */
  35. /* */
  36. /* Apple's `kern' table has some references to tuple indices, but as */
  37. /* there is no indication where these indices are defined, nor how to */
  38. /* interpolate the kerning values (different tuples have different */
  39. /* classes) this issue is ignored. */
  40. /* */
  41. /*************************************************************************/
  42. #include <ft2build.h>
  43. #include FT_INTERNAL_DEBUG_H
  44. #include FT_CONFIG_CONFIG_H
  45. #include FT_INTERNAL_STREAM_H
  46. #include FT_INTERNAL_SFNT_H
  47. #include FT_TRUETYPE_TAGS_H
  48. #include FT_MULTIPLE_MASTERS_H
  49. #include "ttpload.h"
  50. #include "ttgxvar.h"
  51. #include "tterrors.h"
  52. #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
  53. #define FT_Stream_FTell( stream ) \
  54. ( (stream)->cursor - (stream)->base )
  55. #define FT_Stream_SeekSet( stream, off ) \
  56. ( (stream)->cursor = (stream)->base+(off) )
  57. /*************************************************************************/
  58. /* */
  59. /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
  60. /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
  61. /* messages during execution. */
  62. /* */
  63. #undef FT_COMPONENT
  64. #define FT_COMPONENT trace_ttgxvar
  65. /*************************************************************************/
  66. /*************************************************************************/
  67. /***** *****/
  68. /***** Internal Routines *****/
  69. /***** *****/
  70. /*************************************************************************/
  71. /*************************************************************************/
  72. /*************************************************************************/
  73. /* */
  74. /* The macro ALL_POINTS is used in `ft_var_readpackedpoints'. It */
  75. /* indicates that there is a delta for every point without needing to */
  76. /* enumerate all of them. */
  77. /* */
  78. #define ALL_POINTS (FT_UShort*)( -1 )
  79. #define GX_PT_POINTS_ARE_WORDS 0x80
  80. #define GX_PT_POINT_RUN_COUNT_MASK 0x7F
  81. /*************************************************************************/
  82. /* */
  83. /* <Function> */
  84. /* ft_var_readpackedpoints */
  85. /* */
  86. /* <Description> */
  87. /* Read a set of points to which the following deltas will apply. */
  88. /* Points are packed with a run length encoding. */
  89. /* */
  90. /* <Input> */
  91. /* stream :: The data stream. */
  92. /* */
  93. /* <Output> */
  94. /* point_cnt :: The number of points read. A zero value means that */
  95. /* all points in the glyph will be affected, without */
  96. /* enumerating them individually. */
  97. /* */
  98. /* <Return> */
  99. /* An array of FT_UShort containing the affected points or the */
  100. /* special value ALL_POINTS. */
  101. /* */
  102. static FT_UShort*
  103. ft_var_readpackedpoints( FT_Stream stream,
  104. FT_UInt *point_cnt )
  105. {
  106. FT_UShort *points = NULL;
  107. FT_Int n;
  108. FT_Int runcnt;
  109. FT_Int i;
  110. FT_Int j;
  111. FT_Int first;
  112. FT_Memory memory = stream->memory;
  113. FT_Error error = TT_Err_Ok;
  114. FT_UNUSED( error );
  115. *point_cnt = n = FT_GET_BYTE();
  116. if ( n == 0 )
  117. return ALL_POINTS;
  118. if ( n & GX_PT_POINTS_ARE_WORDS )
  119. n = FT_GET_BYTE() | ( ( n & GX_PT_POINT_RUN_COUNT_MASK ) << 8 );
  120. if ( FT_NEW_ARRAY( points, n ) )
  121. return NULL;
  122. i = 0;
  123. while ( i < n )
  124. {
  125. runcnt = FT_GET_BYTE();
  126. if ( runcnt & GX_PT_POINTS_ARE_WORDS )
  127. {
  128. runcnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK;
  129. first = points[i++] = FT_GET_USHORT();
  130. if ( runcnt < 1 || i + runcnt >= n )
  131. goto Exit;
  132. /* first point not included in runcount */
  133. for ( j = 0; j < runcnt; ++j )
  134. points[i++] = (FT_UShort)( first += FT_GET_USHORT() );
  135. }
  136. else
  137. {
  138. first = points[i++] = FT_GET_BYTE();
  139. if ( runcnt < 1 || i + runcnt >= n )
  140. goto Exit;
  141. for ( j = 0; j < runcnt; ++j )
  142. points[i++] = (FT_UShort)( first += FT_GET_BYTE() );
  143. }
  144. }
  145. Exit:
  146. return points;
  147. }
  148. enum
  149. {
  150. GX_DT_DELTAS_ARE_ZERO = 0x80,
  151. GX_DT_DELTAS_ARE_WORDS = 0x40,
  152. GX_DT_DELTA_RUN_COUNT_MASK = 0x3F
  153. };
  154. /*************************************************************************/
  155. /* */
  156. /* <Function> */
  157. /* ft_var_readpackeddeltas */
  158. /* */
  159. /* <Description> */
  160. /* Read a set of deltas. These are packed slightly differently than */
  161. /* points. In particular there is no overall count. */
  162. /* */
  163. /* <Input> */
  164. /* stream :: The data stream. */
  165. /* */
  166. /* delta_cnt :: The number of to be read. */
  167. /* */
  168. /* <Return> */
  169. /* An array of FT_Short containing the deltas for the affected */
  170. /* points. (This only gets the deltas for one dimension. It will */
  171. /* generally be called twice, once for x, once for y. When used in */
  172. /* cvt table, it will only be called once.) */
  173. /* */
  174. static FT_Short*
  175. ft_var_readpackeddeltas( FT_Stream stream,
  176. FT_Offset delta_cnt )
  177. {
  178. FT_Short *deltas = NULL;
  179. FT_UInt runcnt;
  180. FT_Offset i;
  181. FT_UInt j;
  182. FT_Memory memory = stream->memory;
  183. FT_Error error = TT_Err_Ok;
  184. FT_UNUSED( error );
  185. if ( FT_NEW_ARRAY( deltas, delta_cnt ) )
  186. return NULL;
  187. i = 0;
  188. while ( i < delta_cnt )
  189. {
  190. runcnt = FT_GET_BYTE();
  191. if ( runcnt & GX_DT_DELTAS_ARE_ZERO )
  192. {
  193. /* runcnt zeroes get added */
  194. for ( j = 0;
  195. j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt;
  196. ++j )
  197. deltas[i++] = 0;
  198. }
  199. else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
  200. {
  201. /* runcnt shorts from the stack */
  202. for ( j = 0;
  203. j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt;
  204. ++j )
  205. deltas[i++] = FT_GET_SHORT();
  206. }
  207. else
  208. {
  209. /* runcnt signed bytes from the stack */
  210. for ( j = 0;
  211. j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt;
  212. ++j )
  213. deltas[i++] = FT_GET_CHAR();
  214. }
  215. if ( j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) )
  216. {
  217. /* Bad format */
  218. FT_FREE( deltas );
  219. return NULL;
  220. }
  221. }
  222. return deltas;
  223. }
  224. /*************************************************************************/
  225. /* */
  226. /* <Function> */
  227. /* ft_var_load_avar */
  228. /* */
  229. /* <Description> */
  230. /* Parse the `avar' table if present. It need not be, so we return */
  231. /* nothing. */
  232. /* */
  233. /* <InOut> */
  234. /* face :: The font face. */
  235. /* */
  236. static void
  237. ft_var_load_avar( TT_Face face )
  238. {
  239. FT_Stream stream = FT_FACE_STREAM(face);
  240. FT_Memory memory = stream->memory;
  241. GX_Blend blend = face->blend;
  242. GX_AVarSegment segment;
  243. FT_Error error = TT_Err_Ok;
  244. FT_ULong version;
  245. FT_Long axisCount;
  246. FT_Int i, j;
  247. FT_ULong table_len;
  248. FT_UNUSED( error );
  249. blend->avar_checked = TRUE;
  250. if ( (error = face->goto_table( face, TTAG_avar, stream, &table_len )) != 0 )
  251. return;
  252. if ( FT_FRAME_ENTER( table_len ) )
  253. return;
  254. version = FT_GET_LONG();
  255. axisCount = FT_GET_LONG();
  256. if ( version != 0x00010000L ||
  257. axisCount != (FT_Long)blend->mmvar->num_axis )
  258. goto Exit;
  259. if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) )
  260. goto Exit;
  261. segment = &blend->avar_segment[0];
  262. for ( i = 0; i < axisCount; ++i, ++segment )
  263. {
  264. segment->pairCount = FT_GET_USHORT();
  265. if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) )
  266. {
  267. /* Failure. Free everything we have done so far. We must do */
  268. /* it right now since loading the `avar' table is optional. */
  269. for ( j = i - 1; j >= 0; --j )
  270. FT_FREE( blend->avar_segment[j].correspondence );
  271. FT_FREE( blend->avar_segment );
  272. blend->avar_segment = NULL;
  273. goto Exit;
  274. }
  275. for ( j = 0; j < segment->pairCount; ++j )
  276. {
  277. segment->correspondence[j].fromCoord =
  278. FT_GET_SHORT() << 2; /* convert to Fixed */
  279. segment->correspondence[j].toCoord =
  280. FT_GET_SHORT()<<2; /* convert to Fixed */
  281. }
  282. }
  283. Exit:
  284. FT_FRAME_EXIT();
  285. }
  286. typedef struct GX_GVar_Head_
  287. {
  288. FT_Long version;
  289. FT_UShort axisCount;
  290. FT_UShort globalCoordCount;
  291. FT_ULong offsetToCoord;
  292. FT_UShort glyphCount;
  293. FT_UShort flags;
  294. FT_ULong offsetToData;
  295. } GX_GVar_Head;
  296. /*************************************************************************/
  297. /* */
  298. /* <Function> */
  299. /* ft_var_load_gvar */
  300. /* */
  301. /* <Description> */
  302. /* Parses the `gvar' table if present. If `fvar' is there, `gvar' */
  303. /* had better be there too. */
  304. /* */
  305. /* <InOut> */
  306. /* face :: The font face. */
  307. /* */
  308. /* <Return> */
  309. /* FreeType error code. 0 means success. */
  310. /* */
  311. static FT_Error
  312. ft_var_load_gvar( TT_Face face )
  313. {
  314. FT_Stream stream = FT_FACE_STREAM(face);
  315. FT_Memory memory = stream->memory;
  316. GX_Blend blend = face->blend;
  317. FT_Error error;
  318. FT_UInt i, j;
  319. FT_ULong table_len;
  320. FT_ULong gvar_start;
  321. FT_ULong offsetToData;
  322. GX_GVar_Head gvar_head;
  323. static const FT_Frame_Field gvar_fields[] =
  324. {
  325. #undef FT_STRUCTURE
  326. #define FT_STRUCTURE GX_GVar_Head
  327. FT_FRAME_START( 20 ),
  328. FT_FRAME_LONG ( version ),
  329. FT_FRAME_USHORT( axisCount ),
  330. FT_FRAME_USHORT( globalCoordCount ),
  331. FT_FRAME_ULONG ( offsetToCoord ),
  332. FT_FRAME_USHORT( glyphCount ),
  333. FT_FRAME_USHORT( flags ),
  334. FT_FRAME_ULONG ( offsetToData ),
  335. FT_FRAME_END
  336. };
  337. if ( (error = face->goto_table( face, TTAG_gvar, stream, &table_len )) != 0 )
  338. goto Exit;
  339. gvar_start = FT_STREAM_POS( );
  340. if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) )
  341. goto Exit;
  342. blend->tuplecount = gvar_head.globalCoordCount;
  343. blend->gv_glyphcnt = gvar_head.glyphCount;
  344. offsetToData = gvar_start + gvar_head.offsetToData;
  345. if ( gvar_head.version != (FT_Long)0x00010000L ||
  346. gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis )
  347. {
  348. error = TT_Err_Invalid_Table;
  349. goto Exit;
  350. }
  351. if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) )
  352. goto Exit;
  353. if ( gvar_head.flags & 1 )
  354. {
  355. /* long offsets (one more offset than glyphs, to mark size of last) */
  356. if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) )
  357. goto Exit;
  358. for ( i = 0; i <= blend->gv_glyphcnt; ++i )
  359. blend->glyphoffsets[i] = offsetToData + FT_GET_LONG();
  360. FT_FRAME_EXIT();
  361. }
  362. else
  363. {
  364. /* short offsets (one more offset than glyphs, to mark size of last) */
  365. if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) )
  366. goto Exit;
  367. for ( i = 0; i <= blend->gv_glyphcnt; ++i )
  368. blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2;
  369. /* XXX: Undocumented: `*2'! */
  370. FT_FRAME_EXIT();
  371. }
  372. if ( blend->tuplecount != 0 )
  373. {
  374. if ( FT_NEW_ARRAY( blend->tuplecoords,
  375. gvar_head.axisCount * blend->tuplecount ) )
  376. goto Exit;
  377. if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) ||
  378. FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) )
  379. goto Exit;
  380. for ( i = 0; i < blend->tuplecount; ++i )
  381. for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; ++j )
  382. blend->tuplecoords[i * gvar_head.axisCount + j] =
  383. FT_GET_SHORT() << 2; /* convert to FT_Fixed */
  384. FT_FRAME_EXIT();
  385. }
  386. Exit:
  387. return error;
  388. }
  389. /*************************************************************************/
  390. /* */
  391. /* <Function> */
  392. /* ft_var_apply_tuple */
  393. /* */
  394. /* <Description> */
  395. /* Figure out whether a given tuple (design) applies to the current */
  396. /* blend, and if so, what is the scaling factor. */
  397. /* */
  398. /* <Input> */
  399. /* blend :: The current blend of the font. */
  400. /* */
  401. /* tupleIndex :: A flag saying whether this is an intermediate */
  402. /* tuple or not. */
  403. /* */
  404. /* tuple_coords :: The coordinates of the tuple in normalized axis */
  405. /* units. */
  406. /* */
  407. /* im_start_coords :: The initial coordinates where this tuple starts */
  408. /* to apply (for intermediate coordinates). */
  409. /* */
  410. /* im_end_coords :: The final coordinates after which this tuple no */
  411. /* longer applies (for intermediate coordinates). */
  412. /* */
  413. /* <Return> */
  414. /* An FT_Fixed value containing the scaling factor. */
  415. /* */
  416. static FT_Fixed
  417. ft_var_apply_tuple( GX_Blend blend,
  418. FT_UShort tupleIndex,
  419. FT_Fixed* tuple_coords,
  420. FT_Fixed* im_start_coords,
  421. FT_Fixed* im_end_coords )
  422. {
  423. FT_UInt i;
  424. FT_Fixed apply;
  425. FT_Fixed temp;
  426. apply = 0x10000L;
  427. for ( i = 0; i < blend->num_axis; ++i )
  428. {
  429. if ( tuple_coords[i] == 0 )
  430. /* It's not clear why (for intermediate tuples) we don't need */
  431. /* to check against start/end -- the documentation says we don't. */
  432. /* Similarly, it's unclear why we don't need to scale along the */
  433. /* axis. */
  434. continue;
  435. else if ( blend->normalizedcoords[i] == 0 ||
  436. ( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) ||
  437. ( blend->normalizedcoords[i] > 0 && tuple_coords[i] < 0 ) )
  438. {
  439. apply = 0;
  440. break;
  441. }
  442. else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) )
  443. /* not an intermediate tuple */
  444. apply = FT_MulDiv( apply,
  445. blend->normalizedcoords[i] > 0
  446. ? blend->normalizedcoords[i]
  447. : -blend->normalizedcoords[i],
  448. 0x10000L );
  449. else if ( blend->normalizedcoords[i] <= im_start_coords[i] ||
  450. blend->normalizedcoords[i] >= im_end_coords[i] )
  451. {
  452. apply = 0;
  453. break;
  454. }
  455. else if ( blend->normalizedcoords[i] < tuple_coords[i] )
  456. {
  457. temp = FT_MulDiv( blend->normalizedcoords[i] - im_start_coords[i],
  458. 0x10000L,
  459. tuple_coords[i] - im_start_coords[i]);
  460. apply = FT_MulDiv( apply, temp, 0x10000L );
  461. }
  462. else
  463. {
  464. temp = FT_MulDiv( im_end_coords[i] - blend->normalizedcoords[i],
  465. 0x10000L,
  466. im_end_coords[i] - tuple_coords[i] );
  467. apply = FT_MulDiv( apply, temp, 0x10000L );
  468. }
  469. }
  470. return apply;
  471. }
  472. /*************************************************************************/
  473. /*************************************************************************/
  474. /***** *****/
  475. /***** MULTIPLE MASTERS SERVICE FUNCTIONS *****/
  476. /***** *****/
  477. /*************************************************************************/
  478. /*************************************************************************/
  479. typedef struct GX_FVar_Head_
  480. {
  481. FT_Long version;
  482. FT_UShort offsetToData;
  483. FT_UShort countSizePairs;
  484. FT_UShort axisCount;
  485. FT_UShort axisSize;
  486. FT_UShort instanceCount;
  487. FT_UShort instanceSize;
  488. } GX_FVar_Head;
  489. typedef struct fvar_axis_
  490. {
  491. FT_ULong axisTag;
  492. FT_ULong minValue;
  493. FT_ULong defaultValue;
  494. FT_ULong maxValue;
  495. FT_UShort flags;
  496. FT_UShort nameID;
  497. } GX_FVar_Axis;
  498. /*************************************************************************/
  499. /* */
  500. /* <Function> */
  501. /* TT_Get_MM_Var */
  502. /* */
  503. /* <Description> */
  504. /* Check that the font's `fvar' table is valid, parse it, and return */
  505. /* those data. */
  506. /* */
  507. /* <InOut> */
  508. /* face :: The font face. */
  509. /* TT_Get_MM_Var initializes the blend structure. */
  510. /* */
  511. /* <Output> */
  512. /* master :: The `fvar' data (must be freed by caller). */
  513. /* */
  514. /* <Return> */
  515. /* FreeType error code. 0 means success. */
  516. /* */
  517. FT_LOCAL_DEF( FT_Error )
  518. TT_Get_MM_Var( TT_Face face,
  519. FT_MM_Var* *master )
  520. {
  521. FT_Stream stream = face->root.stream;
  522. FT_Memory memory = face->root.memory;
  523. FT_ULong table_len;
  524. FT_Error error = TT_Err_Ok;
  525. FT_ULong fvar_start;
  526. FT_Int i, j;
  527. FT_MM_Var* mmvar = NULL;
  528. FT_Fixed* next_coords;
  529. FT_String* next_name;
  530. FT_Var_Axis* a;
  531. FT_Var_Named_Style* ns;
  532. GX_FVar_Head fvar_head;
  533. static const FT_Frame_Field fvar_fields[] =
  534. {
  535. #undef FT_STRUCTURE
  536. #define FT_STRUCTURE GX_FVar_Head
  537. FT_FRAME_START( 16 ),
  538. FT_FRAME_LONG ( version ),
  539. FT_FRAME_USHORT( offsetToData ),
  540. FT_FRAME_USHORT( countSizePairs ),
  541. FT_FRAME_USHORT( axisCount ),
  542. FT_FRAME_USHORT( axisSize ),
  543. FT_FRAME_USHORT( instanceCount ),
  544. FT_FRAME_USHORT( instanceSize ),
  545. FT_FRAME_END
  546. };
  547. static const FT_Frame_Field fvaraxis_fields[] =
  548. {
  549. #undef FT_STRUCTURE
  550. #define FT_STRUCTURE GX_FVar_Axis
  551. FT_FRAME_START( 20 ),
  552. FT_FRAME_ULONG ( axisTag ),
  553. FT_FRAME_ULONG ( minValue ),
  554. FT_FRAME_ULONG ( defaultValue ),
  555. FT_FRAME_ULONG ( maxValue ),
  556. FT_FRAME_USHORT( flags ),
  557. FT_FRAME_USHORT( nameID ),
  558. FT_FRAME_END
  559. };
  560. if ( face->blend == NULL )
  561. {
  562. /* both `fvar' and `gvar' must be present */
  563. if ( (error = face->goto_table( face, TTAG_gvar,
  564. stream, &table_len )) != 0 )
  565. goto Exit;
  566. if ( (error = face->goto_table( face, TTAG_fvar,
  567. stream, &table_len )) != 0 )
  568. goto Exit;
  569. fvar_start = FT_STREAM_POS( );
  570. if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) )
  571. goto Exit;
  572. if ( fvar_head.version != (FT_Long)0x00010000L ||
  573. fvar_head.countSizePairs != 2 ||
  574. fvar_head.axisSize != 20 ||
  575. /* axisCount limit implied by 16-bit instanceSize */
  576. fvar_head.axisCount > 0x3FFE ||
  577. fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount ||
  578. /* instanceCount limit implied by limited range of name IDs */
  579. fvar_head.instanceCount > 0x7EFF ||
  580. fvar_head.offsetToData + fvar_head.axisCount * 20U +
  581. fvar_head.instanceCount * fvar_head.instanceSize > table_len )
  582. {
  583. error = TT_Err_Invalid_Table;
  584. goto Exit;
  585. }
  586. if ( FT_NEW( face->blend ) )
  587. goto Exit;
  588. /* cannot overflow 32-bit arithmetic because of limits above */
  589. face->blend->mmvar_len =
  590. sizeof ( FT_MM_Var ) +
  591. fvar_head.axisCount * sizeof ( FT_Var_Axis ) +
  592. fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) +
  593. fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) +
  594. 5 * fvar_head.axisCount;
  595. if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
  596. goto Exit;
  597. face->blend->mmvar = mmvar;
  598. mmvar->num_axis =
  599. fvar_head.axisCount;
  600. mmvar->num_designs =
  601. (FT_UInt)-1; /* meaningless in this context; each glyph */
  602. /* may have a different number of designs */
  603. /* (or tuples, as called by Apple) */
  604. mmvar->num_namedstyles =
  605. fvar_head.instanceCount;
  606. mmvar->axis =
  607. (FT_Var_Axis*)&(mmvar[1]);
  608. mmvar->namedstyle =
  609. (FT_Var_Named_Style*)&(mmvar->axis[fvar_head.axisCount]);
  610. next_coords =
  611. (FT_Fixed*)&(mmvar->namedstyle[fvar_head.instanceCount]);
  612. for ( i = 0; i < fvar_head.instanceCount; ++i )
  613. {
  614. mmvar->namedstyle[i].coords = next_coords;
  615. next_coords += fvar_head.axisCount;
  616. }
  617. next_name = (FT_String*)next_coords;
  618. for ( i = 0; i < fvar_head.axisCount; ++i )
  619. {
  620. mmvar->axis[i].name = next_name;
  621. next_name += 5;
  622. }
  623. if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) )
  624. goto Exit;
  625. a = mmvar->axis;
  626. for ( i = 0; i < fvar_head.axisCount; ++i )
  627. {
  628. GX_FVar_Axis axis_rec;
  629. if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) )
  630. goto Exit;
  631. a->tag = axis_rec.axisTag;
  632. a->minimum = axis_rec.minValue; /* A Fixed */
  633. a->def = axis_rec.defaultValue; /* A Fixed */
  634. a->maximum = axis_rec.maxValue; /* A Fixed */
  635. a->strid = axis_rec.nameID;
  636. a->name[0] = (FT_String)( a->tag >> 24 );
  637. a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF );
  638. a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF );
  639. a->name[3] = (FT_String)( ( a->tag ) & 0xFF );
  640. a->name[4] = 0;
  641. ++a;
  642. }
  643. ns = mmvar->namedstyle;
  644. for ( i = 0; i < fvar_head.instanceCount; ++i, ++ns )
  645. {
  646. if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) )
  647. goto Exit;
  648. ns->strid = FT_GET_USHORT();
  649. (void) /* flags = */ FT_GET_USHORT();
  650. for ( j = 0; j < fvar_head.axisCount; ++j )
  651. ns->coords[j] = FT_GET_ULONG(); /* A Fixed */
  652. FT_FRAME_EXIT();
  653. }
  654. }
  655. if ( master != NULL )
  656. {
  657. FT_UInt n;
  658. if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
  659. goto Exit;
  660. FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len );
  661. mmvar->axis =
  662. (FT_Var_Axis*)&(mmvar[1]);
  663. mmvar->namedstyle =
  664. (FT_Var_Named_Style*)&(mmvar->axis[mmvar->num_axis]);
  665. next_coords =
  666. (FT_Fixed*)&(mmvar->namedstyle[mmvar->num_namedstyles]);
  667. for ( n = 0; n < mmvar->num_namedstyles; ++n )
  668. {
  669. mmvar->namedstyle[n].coords = next_coords;
  670. next_coords += mmvar->num_axis;
  671. }
  672. a = mmvar->axis;
  673. next_name = (FT_String*)next_coords;
  674. for ( n = 0; n < mmvar->num_axis; ++n )
  675. {
  676. a->name = next_name;
  677. /* standard PostScript names for some standard apple tags */
  678. if ( a->tag == TTAG_wght )
  679. a->name = (char *)"Weight";
  680. else if ( a->tag == TTAG_wdth )
  681. a->name = (char *)"Width";
  682. else if ( a->tag == TTAG_opsz )
  683. a->name = (char *)"OpticalSize";
  684. else if ( a->tag == TTAG_slnt )
  685. a->name = (char *)"Slant";
  686. next_name += 5;
  687. ++a;
  688. }
  689. *master = mmvar;
  690. }
  691. Exit:
  692. return error;
  693. }
  694. /*************************************************************************/
  695. /* */
  696. /* <Function> */
  697. /* TT_Set_MM_Blend */
  698. /* */
  699. /* <Description> */
  700. /* Set the blend (normalized) coordinates for this instance of the */
  701. /* font. Check that the `gvar' table is reasonable and does some */
  702. /* initial preparation. */
  703. /* */
  704. /* <InOut> */
  705. /* face :: The font. */
  706. /* Initialize the blend structure with `gvar' data. */
  707. /* */
  708. /* <Input> */
  709. /* num_coords :: Must be the axis count of the font. */
  710. /* */
  711. /* coords :: An array of num_coords, each between [-1,1]. */
  712. /* */
  713. /* <Return> */
  714. /* FreeType error code. 0 means success. */
  715. /* */
  716. FT_LOCAL_DEF( FT_Error )
  717. TT_Set_MM_Blend( TT_Face face,
  718. FT_UInt num_coords,
  719. FT_Fixed* coords )
  720. {
  721. FT_Error error = TT_Err_Ok;
  722. GX_Blend blend;
  723. FT_MM_Var* mmvar;
  724. FT_UInt i;
  725. FT_Memory memory = face->root.memory;
  726. enum
  727. {
  728. mcvt_retain,
  729. mcvt_modify,
  730. mcvt_load
  731. } manageCvt;
  732. face->doblend = FALSE;
  733. if ( face->blend == NULL )
  734. {
  735. if ( (error = TT_Get_MM_Var( face, NULL)) != 0 )
  736. goto Exit;
  737. }
  738. blend = face->blend;
  739. mmvar = blend->mmvar;
  740. if ( num_coords != mmvar->num_axis )
  741. {
  742. error = TT_Err_Invalid_Argument;
  743. goto Exit;
  744. }
  745. for ( i = 0; i < num_coords; ++i )
  746. if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L )
  747. {
  748. error = TT_Err_Invalid_Argument;
  749. goto Exit;
  750. }
  751. if ( blend->glyphoffsets == NULL )
  752. if ( (error = ft_var_load_gvar( face )) != 0 )
  753. goto Exit;
  754. if ( blend->normalizedcoords == NULL )
  755. {
  756. if ( FT_NEW_ARRAY( blend->normalizedcoords, num_coords ) )
  757. goto Exit;
  758. manageCvt = mcvt_modify;
  759. /* If we have not set the blend coordinates before this, then the */
  760. /* cvt table will still be what we read from the `cvt ' table and */
  761. /* we don't need to reload it. We may need to change it though... */
  762. }
  763. else
  764. {
  765. manageCvt = mcvt_retain;
  766. for ( i = 0; i < num_coords; ++i )
  767. {
  768. if ( blend->normalizedcoords[i] != coords[i] )
  769. {
  770. manageCvt = mcvt_load;
  771. break;
  772. }
  773. }
  774. /* If we don't change the blend coords then we don't need to do */
  775. /* anything to the cvt table. It will be correct. Otherwise we */
  776. /* no longer have the original cvt (it was modified when we set */
  777. /* the blend last time), so we must reload and then modify it. */
  778. }
  779. blend->num_axis = num_coords;
  780. FT_MEM_COPY( blend->normalizedcoords,
  781. coords,
  782. num_coords * sizeof ( FT_Fixed ) );
  783. face->doblend = TRUE;
  784. if ( face->cvt != NULL )
  785. {
  786. switch ( manageCvt )
  787. {
  788. case mcvt_load:
  789. /* The cvt table has been loaded already; every time we change the */
  790. /* blend we may need to reload and remodify the cvt table. */
  791. FT_FREE( face->cvt );
  792. face->cvt = NULL;
  793. tt_face_load_cvt( face, face->root.stream );
  794. break;
  795. case mcvt_modify:
  796. /* The original cvt table is in memory. All we need to do is */
  797. /* apply the `cvar' table (if any). */
  798. tt_face_vary_cvt( face, face->root.stream );
  799. break;
  800. case mcvt_retain:
  801. /* The cvt table is correct for this set of coordinates. */
  802. break;
  803. }
  804. }
  805. Exit:
  806. return error;
  807. }
  808. /*************************************************************************/
  809. /* */
  810. /* <Function> */
  811. /* TT_Set_Var_Design */
  812. /* */
  813. /* <Description> */
  814. /* Set the coordinates for the instance, measured in the user */
  815. /* coordinate system. Parse the `avar' table (if present) to convert */
  816. /* from user to normalized coordinates. */
  817. /* */
  818. /* <InOut> */
  819. /* face :: The font face. */
  820. /* Initialize the blend struct with `gvar' data. */
  821. /* */
  822. /* <Input> */
  823. /* num_coords :: This must be the axis count of the font. */
  824. /* */
  825. /* coords :: A coordinate array with `num_coords' elements. */
  826. /* */
  827. /* <Return> */
  828. /* FreeType error code. 0 means success. */
  829. /* */
  830. FT_LOCAL_DEF( FT_Error )
  831. TT_Set_Var_Design( TT_Face face,
  832. FT_UInt num_coords,
  833. FT_Fixed* coords )
  834. {
  835. FT_Error error = TT_Err_Ok;
  836. FT_Fixed* normalized = NULL;
  837. GX_Blend blend;
  838. FT_MM_Var* mmvar;
  839. FT_UInt i, j;
  840. FT_Var_Axis* a;
  841. GX_AVarSegment av;
  842. FT_Memory memory = face->root.memory;
  843. if ( face->blend == NULL )
  844. {
  845. if ( (error = TT_Get_MM_Var( face, NULL )) != 0 )
  846. goto Exit;
  847. }
  848. blend = face->blend;
  849. mmvar = blend->mmvar;
  850. if ( num_coords != mmvar->num_axis )
  851. {
  852. error = TT_Err_Invalid_Argument;
  853. goto Exit;
  854. }
  855. /* Axis normalization is a two stage process. First we normalize */
  856. /* based on the [min,def,max] values for the axis to be [-1,0,1]. */
  857. /* Then, if there's an `avar' table, we renormalize this range. */
  858. if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) )
  859. goto Exit;
  860. a = mmvar->axis;
  861. for ( i = 0; i < mmvar->num_axis; ++i, ++a )
  862. {
  863. if ( coords[i] > a->maximum || coords[i] < a->minimum )
  864. {
  865. error = TT_Err_Invalid_Argument;
  866. goto Exit;
  867. }
  868. if ( coords[i] < a->def )
  869. {
  870. normalized[i] = -FT_MulDiv( coords[i] - a->def,
  871. 0x10000L,
  872. a->minimum - a->def );
  873. }
  874. else if ( a->maximum == a->def )
  875. normalized[i] = 0;
  876. else
  877. {
  878. normalized[i] = FT_MulDiv( coords[i] - a->def,
  879. 0x10000L,
  880. a->maximum - a->def );
  881. }
  882. }
  883. if ( !blend->avar_checked )
  884. ft_var_load_avar( face );
  885. if ( blend->avar_segment != NULL )
  886. {
  887. av = blend->avar_segment;
  888. for ( i = 0; i < mmvar->num_axis; ++i, ++av )
  889. {
  890. for ( j = 1; j < (FT_UInt)av->pairCount; ++j )
  891. if ( normalized[i] < av->correspondence[j].fromCoord )
  892. {
  893. normalized[i] =
  894. FT_MulDiv(
  895. FT_MulDiv(
  896. normalized[i] - av->correspondence[j - 1].fromCoord,
  897. 0x10000L,
  898. av->correspondence[j].fromCoord -
  899. av->correspondence[j - 1].fromCoord ),
  900. av->correspondence[j].toCoord -
  901. av->correspondence[j - 1].toCoord,
  902. 0x10000L ) +
  903. av->correspondence[j - 1].toCoord;
  904. break;
  905. }
  906. }
  907. }
  908. error = TT_Set_MM_Blend( face, num_coords, normalized );
  909. Exit:
  910. FT_FREE( normalized );
  911. return error;
  912. }
  913. /*************************************************************************/
  914. /*************************************************************************/
  915. /***** *****/
  916. /***** GX VAR PARSING ROUTINES *****/
  917. /***** *****/
  918. /*************************************************************************/
  919. /*************************************************************************/
  920. /*************************************************************************/
  921. /* */
  922. /* <Function> */
  923. /* tt_face_vary_cvt */
  924. /* */
  925. /* <Description> */
  926. /* Modify the loaded cvt table according to the `cvar' table and the */
  927. /* font's blend. */
  928. /* */
  929. /* <InOut> */
  930. /* face :: A handle to the target face object. */
  931. /* */
  932. /* <Input> */
  933. /* stream :: A handle to the input stream. */
  934. /* */
  935. /* <Return> */
  936. /* FreeType error code. 0 means success. */
  937. /* */
  938. /* Most errors are ignored. It is perfectly valid not to have a */
  939. /* `cvar' table even if there is a `gvar' and `fvar' table. */
  940. /* */
  941. FT_LOCAL_DEF( FT_Error )
  942. tt_face_vary_cvt( TT_Face face,
  943. FT_Stream stream )
  944. {
  945. FT_Error error;
  946. FT_Memory memory = stream->memory;
  947. FT_ULong table_start;
  948. FT_ULong table_len;
  949. FT_UInt tupleCount;
  950. FT_ULong offsetToData;
  951. FT_ULong here;
  952. FT_UInt i, j;
  953. FT_Fixed* tuple_coords = NULL;
  954. FT_Fixed* im_start_coords = NULL;
  955. FT_Fixed* im_end_coords = NULL;
  956. GX_Blend blend = face->blend;
  957. FT_UInt point_count;
  958. FT_UShort* localpoints;
  959. FT_Short* deltas;
  960. FT_TRACE2(( "CVAR " ));
  961. if ( blend == NULL )
  962. {
  963. FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" ));
  964. error = TT_Err_Ok;
  965. goto Exit;
  966. }
  967. if ( face->cvt == NULL )
  968. {
  969. FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" ));
  970. error = TT_Err_Ok;
  971. goto Exit;
  972. }
  973. error = face->goto_table( face, TTAG_cvar, stream, &table_len );
  974. if ( error )
  975. {
  976. FT_TRACE2(( "is missing\n" ));
  977. error = TT_Err_Ok;
  978. goto Exit;
  979. }
  980. if ( FT_FRAME_ENTER( table_len ) )
  981. {
  982. error = TT_Err_Ok;
  983. goto Exit;
  984. }
  985. table_start = FT_Stream_FTell( stream );
  986. if ( FT_GET_LONG() != 0x00010000L )
  987. {
  988. FT_TRACE2(( "bad table version\n" ));
  989. error = TT_Err_Ok;
  990. goto FExit;
  991. }
  992. if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) ||
  993. FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
  994. FT_NEW_ARRAY( im_end_coords, blend->num_axis ) )
  995. goto FExit;
  996. tupleCount = FT_GET_USHORT();
  997. offsetToData = table_start + FT_GET_USHORT();
  998. /* The documentation implies there are flags packed into the */
  999. /* tuplecount, but John Jenkins says that shared points don't apply */
  1000. /* to `cvar', and no other flags are defined. */
  1001. for ( i = 0; i < ( tupleCount & 0xFFF ); ++i )
  1002. {
  1003. FT_UInt tupleDataSize;
  1004. FT_UInt tupleIndex;
  1005. FT_Fixed apply;
  1006. tupleDataSize = FT_GET_USHORT();
  1007. tupleIndex = FT_GET_USHORT();
  1008. /* There is no provision here for a global tuple coordinate section, */
  1009. /* so John says. There are no tuple indices, just embedded tuples. */
  1010. if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
  1011. {
  1012. for ( j = 0; j < blend->num_axis; ++j )
  1013. tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */
  1014. /* short frac to fixed */
  1015. }
  1016. else
  1017. {
  1018. /* skip this tuple; it makes no sense */
  1019. if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
  1020. for ( j = 0; j < 2 * blend->num_axis; ++j )
  1021. (void)FT_GET_SHORT();
  1022. offsetToData += tupleDataSize;
  1023. continue;
  1024. }
  1025. if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
  1026. {
  1027. for ( j = 0; j < blend->num_axis; ++j )
  1028. im_start_coords[j] = FT_GET_SHORT() << 2;
  1029. for ( j = 0; j < blend->num_axis; ++j )
  1030. im_end_coords[j] = FT_GET_SHORT() << 2;
  1031. }
  1032. apply = ft_var_apply_tuple( blend,
  1033. (FT_UShort)tupleIndex,
  1034. tuple_coords,
  1035. im_start_coords,
  1036. im_end_coords );
  1037. if ( /* tuple isn't active for our blend */
  1038. apply == 0 ||
  1039. /* global points not allowed, */
  1040. /* if they aren't local, makes no sense */
  1041. !( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) )
  1042. {
  1043. offsetToData += tupleDataSize;
  1044. continue;
  1045. }
  1046. here = FT_Stream_FTell( stream );
  1047. FT_Stream_SeekSet( stream, offsetToData );
  1048. localpoints = ft_var_readpackedpoints( stream, &point_count );
  1049. deltas = ft_var_readpackeddeltas( stream,
  1050. point_count == 0 ? face->cvt_size
  1051. : point_count );
  1052. if ( localpoints == NULL || deltas == NULL )
  1053. /* failure, ignore it */;
  1054. else if ( localpoints == ALL_POINTS )
  1055. {
  1056. /* this means that there are deltas for every entry in cvt */
  1057. for ( j = 0; j < face->cvt_size; ++j )
  1058. face->cvt[j] = (FT_Short)( face->cvt[j] +
  1059. FT_MulFix( deltas[j], apply ) );
  1060. }
  1061. else
  1062. {
  1063. for ( j = 0; j < point_count; ++j )
  1064. {
  1065. int pindex = localpoints[j];
  1066. face->cvt[pindex] = (FT_Short)( face->cvt[pindex] +
  1067. FT_MulFix( deltas[j], apply ) );
  1068. }
  1069. }
  1070. if ( localpoints != ALL_POINTS )
  1071. FT_FREE( localpoints );
  1072. FT_FREE( deltas );
  1073. offsetToData += tupleDataSize;
  1074. FT_Stream_SeekSet( stream, here );
  1075. }
  1076. FExit:
  1077. FT_FRAME_EXIT();
  1078. Exit:
  1079. FT_FREE( tuple_coords );
  1080. FT_FREE( im_start_coords );
  1081. FT_FREE( im_end_coords );
  1082. return error;
  1083. }
  1084. /*************************************************************************/
  1085. /* */
  1086. /* <Function> */
  1087. /* TT_Vary_Get_Glyph_Deltas */
  1088. /* */
  1089. /* <Description> */
  1090. /* Load the appropriate deltas for the current glyph. */
  1091. /* */
  1092. /* <Input> */
  1093. /* face :: A handle to the target face object. */
  1094. /* */
  1095. /* glyph_index :: The index of the glyph being modified. */
  1096. /* */
  1097. /* n_points :: The number of the points in the glyph, including */
  1098. /* phantom points. */
  1099. /* */
  1100. /* <Output> */
  1101. /* deltas :: The array of points to change. */
  1102. /* */
  1103. /* <Return> */
  1104. /* FreeType error code. 0 means success. */
  1105. /* */
  1106. FT_LOCAL_DEF( FT_Error )
  1107. TT_Vary_Get_Glyph_Deltas( TT_Face face,
  1108. FT_UInt glyph_index,
  1109. FT_Vector* *deltas,
  1110. FT_UInt n_points )
  1111. {
  1112. FT_Stream stream = face->root.stream;
  1113. FT_Memory memory = stream->memory;
  1114. GX_Blend blend = face->blend;
  1115. FT_Vector* delta_xy = NULL;
  1116. FT_Error error;
  1117. FT_ULong glyph_start;
  1118. FT_UInt tupleCount;
  1119. FT_ULong offsetToData;
  1120. FT_ULong here;
  1121. FT_UInt i, j;
  1122. FT_Fixed* tuple_coords = NULL;
  1123. FT_Fixed* im_start_coords = NULL;
  1124. FT_Fixed* im_end_coords = NULL;
  1125. FT_UInt point_count, spoint_count = 0;
  1126. FT_UShort* sharedpoints = NULL;
  1127. FT_UShort* localpoints = NULL;
  1128. FT_UShort* points;
  1129. FT_Short *deltas_x, *deltas_y;
  1130. if ( !face->doblend || blend == NULL )
  1131. return TT_Err_Invalid_Argument;
  1132. /* to be freed by the caller */
  1133. if ( FT_NEW_ARRAY( delta_xy, n_points ) )
  1134. goto Exit;
  1135. *deltas = delta_xy;
  1136. if ( glyph_index >= blend->gv_glyphcnt ||
  1137. blend->glyphoffsets[glyph_index] ==
  1138. blend->glyphoffsets[glyph_index + 1] )
  1139. return TT_Err_Ok; /* no variation data for this glyph */
  1140. if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) ||
  1141. FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] -
  1142. blend->glyphoffsets[glyph_index] ) )
  1143. goto Fail1;
  1144. glyph_start = FT_Stream_FTell( stream );
  1145. /* each set of glyph variation data is formatted similarly to `cvar' */
  1146. /* (except we get shared points and global tuples) */
  1147. if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) ||
  1148. FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
  1149. FT_NEW_ARRAY( im_end_coords, blend->num_axis ) )
  1150. goto Fail2;
  1151. tupleCount = FT_GET_USHORT();
  1152. offsetToData = glyph_start + FT_GET_USHORT();
  1153. if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
  1154. {
  1155. here = FT_Stream_FTell( stream );
  1156. FT_Stream_SeekSet( stream, offsetToData );
  1157. sharedpoints = ft_var_readpackedpoints( stream, &spoint_count );
  1158. offsetToData = FT_Stream_FTell( stream );
  1159. FT_Stream_SeekSet( stream, here );
  1160. }
  1161. for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); ++i )
  1162. {
  1163. FT_UInt tupleDataSize;
  1164. FT_UInt tupleIndex;
  1165. FT_Fixed apply;
  1166. tupleDataSize = FT_GET_USHORT();
  1167. tupleIndex = FT_GET_USHORT();
  1168. if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
  1169. {
  1170. for ( j = 0; j < blend->num_axis; ++j )
  1171. tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */
  1172. /* short frac to fixed */
  1173. }
  1174. else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
  1175. {
  1176. error = TT_Err_Invalid_Table;
  1177. goto Fail3;
  1178. }
  1179. else
  1180. {
  1181. FT_MEM_COPY(
  1182. tuple_coords,
  1183. &blend->tuplecoords[(tupleIndex & 0xFFF) * blend->num_axis],
  1184. blend->num_axis * sizeof ( FT_Fixed ) );
  1185. }
  1186. if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
  1187. {
  1188. for ( j = 0; j < blend->num_axis; ++j )
  1189. im_start_coords[j] = FT_GET_SHORT() << 2;
  1190. for ( j = 0; j < blend->num_axis; ++j )
  1191. im_end_coords[j] = FT_GET_SHORT() << 2;
  1192. }
  1193. apply = ft_var_apply_tuple( blend,
  1194. (FT_UShort)tupleIndex,
  1195. tuple_coords,
  1196. im_start_coords,
  1197. im_end_coords );
  1198. if ( apply == 0 ) /* tuple isn't active for our blend */
  1199. {
  1200. offsetToData += tupleDataSize;
  1201. continue;
  1202. }
  1203. here = FT_Stream_FTell( stream );
  1204. if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
  1205. {
  1206. FT_Stream_SeekSet( stream, offsetToData );
  1207. localpoints = ft_var_readpackedpoints( stream, &point_count );
  1208. points = localpoints;
  1209. }
  1210. else
  1211. {
  1212. points = sharedpoints;
  1213. point_count = spoint_count;
  1214. }
  1215. deltas_x = ft_var_readpackeddeltas( stream,
  1216. point_count == 0 ? n_points
  1217. : point_count );
  1218. deltas_y = ft_var_readpackeddeltas( stream,
  1219. point_count == 0 ? n_points
  1220. : point_count );
  1221. if ( points == NULL || deltas_y == NULL || deltas_x == NULL )
  1222. ; /* failure, ignore it */
  1223. else if ( points == ALL_POINTS )
  1224. {
  1225. /* this means that there are deltas for every point in the glyph */
  1226. for ( j = 0; j < n_points; ++j )
  1227. {
  1228. delta_xy[j].x += FT_MulFix( deltas_x[j], apply );
  1229. delta_xy[j].y += FT_MulFix( deltas_y[j], apply );
  1230. }
  1231. }
  1232. else
  1233. {
  1234. for ( j = 0; j < point_count; ++j )
  1235. {
  1236. if ( localpoints[j] >= n_points )
  1237. continue;
  1238. delta_xy[localpoints[j]].x += FT_MulFix( deltas_x[j], apply );
  1239. delta_xy[localpoints[j]].y += FT_MulFix( deltas_y[j], apply );
  1240. }
  1241. }
  1242. if ( localpoints != ALL_POINTS )
  1243. FT_FREE( localpoints );
  1244. FT_FREE( deltas_x );
  1245. FT_FREE( deltas_y );
  1246. offsetToData += tupleDataSize;
  1247. FT_Stream_SeekSet( stream, here );
  1248. }
  1249. Fail3:
  1250. FT_FREE( tuple_coords );
  1251. FT_FREE( im_start_coords );
  1252. FT_FREE( im_end_coords );
  1253. Fail2:
  1254. FT_FRAME_EXIT();
  1255. Fail1:
  1256. if ( error )
  1257. {
  1258. FT_FREE( delta_xy );
  1259. *deltas = NULL;
  1260. }
  1261. Exit:
  1262. return error;
  1263. }
  1264. /*************************************************************************/
  1265. /* */
  1266. /* <Function> */
  1267. /* tt_done_blend */
  1268. /* */
  1269. /* <Description> */
  1270. /* Frees the blend internal data structure. */
  1271. /* */
  1272. FT_LOCAL_DEF( void )
  1273. tt_done_blend( FT_Memory memory,
  1274. GX_Blend blend )
  1275. {
  1276. if ( blend != NULL )
  1277. {
  1278. FT_UInt i;
  1279. FT_FREE( blend->normalizedcoords );
  1280. FT_FREE( blend->mmvar );
  1281. if ( blend->avar_segment != NULL )
  1282. {
  1283. for ( i = 0; i < blend->num_axis; ++i )
  1284. FT_FREE( blend->avar_segment[i].correspondence );
  1285. FT_FREE( blend->avar_segment );
  1286. }
  1287. FT_FREE( blend->tuplecoords );
  1288. FT_FREE( blend->glyphoffsets );
  1289. FT_FREE( blend );
  1290. }
  1291. }
  1292. #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
  1293. /* END */