/modules/freetype2/src/type1/t1afm.c

http://github.com/zpao/v8monkey · C · 397 lines · 258 code · 85 blank · 54 comment · 52 complexity · 7b54f6e4bead7ded59951433c4709536 MD5 · raw file

  1. /***************************************************************************/
  2. /* */
  3. /* t1afm.c */
  4. /* */
  5. /* AFM support for Type 1 fonts (body). */
  6. /* */
  7. /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */
  8. /* 2010 by */
  9. /* David Turner, Robert Wilhelm, and Werner Lemberg. */
  10. /* */
  11. /* This file is part of the FreeType project, and may only be used, */
  12. /* modified, and distributed under the terms of the FreeType project */
  13. /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
  14. /* this file you indicate that you have read the license and */
  15. /* understand and accept it fully. */
  16. /* */
  17. /***************************************************************************/
  18. #include <ft2build.h>
  19. #include "t1afm.h"
  20. #include "t1errors.h"
  21. #include FT_INTERNAL_STREAM_H
  22. #include FT_INTERNAL_POSTSCRIPT_AUX_H
  23. /*************************************************************************/
  24. /* */
  25. /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
  26. /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
  27. /* messages during execution. */
  28. /* */
  29. #undef FT_COMPONENT
  30. #define FT_COMPONENT trace_t1afm
  31. FT_LOCAL_DEF( void )
  32. T1_Done_Metrics( FT_Memory memory,
  33. AFM_FontInfo fi )
  34. {
  35. FT_FREE( fi->KernPairs );
  36. fi->NumKernPair = 0;
  37. FT_FREE( fi->TrackKerns );
  38. fi->NumTrackKern = 0;
  39. FT_FREE( fi );
  40. }
  41. /* read a glyph name and return the equivalent glyph index */
  42. static FT_Int
  43. t1_get_index( const char* name,
  44. FT_Offset len,
  45. void* user_data )
  46. {
  47. T1_Font type1 = (T1_Font)user_data;
  48. FT_Int n;
  49. /* PS string/name length must be < 16-bit */
  50. if ( len > 0xFFFFU )
  51. return 0;
  52. for ( n = 0; n < type1->num_glyphs; n++ )
  53. {
  54. char* gname = (char*)type1->glyph_names[n];
  55. if ( gname && gname[0] == name[0] &&
  56. ft_strlen( gname ) == len &&
  57. ft_strncmp( gname, name, len ) == 0 )
  58. return n;
  59. }
  60. return 0;
  61. }
  62. #undef KERN_INDEX
  63. #define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) )
  64. /* compare two kerning pairs */
  65. FT_CALLBACK_DEF( int )
  66. compare_kern_pairs( const void* a,
  67. const void* b )
  68. {
  69. AFM_KernPair pair1 = (AFM_KernPair)a;
  70. AFM_KernPair pair2 = (AFM_KernPair)b;
  71. FT_ULong index1 = KERN_INDEX( pair1->index1, pair1->index2 );
  72. FT_ULong index2 = KERN_INDEX( pair2->index1, pair2->index2 );
  73. if ( index1 > index2 )
  74. return 1;
  75. else if ( index1 < index2 )
  76. return -1;
  77. else
  78. return 0;
  79. }
  80. /* parse a PFM file -- for now, only read the kerning pairs */
  81. static FT_Error
  82. T1_Read_PFM( FT_Face t1_face,
  83. FT_Stream stream,
  84. AFM_FontInfo fi )
  85. {
  86. FT_Error error = T1_Err_Ok;
  87. FT_Memory memory = stream->memory;
  88. FT_Byte* start;
  89. FT_Byte* limit;
  90. FT_Byte* p;
  91. AFM_KernPair kp;
  92. FT_Int width_table_length;
  93. FT_CharMap oldcharmap;
  94. FT_CharMap charmap;
  95. FT_Int n;
  96. start = (FT_Byte*)stream->cursor;
  97. limit = (FT_Byte*)stream->limit;
  98. p = start;
  99. /* Figure out how long the width table is. */
  100. /* This info is a little-endian short at offset 99. */
  101. p = start + 99;
  102. if ( p + 2 > limit )
  103. {
  104. error = T1_Err_Unknown_File_Format;
  105. goto Exit;
  106. }
  107. width_table_length = FT_PEEK_USHORT_LE( p );
  108. p += 18 + width_table_length;
  109. if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 )
  110. /* extension table is probably optional */
  111. goto Exit;
  112. /* Kerning offset is 14 bytes from start of extensions table. */
  113. p += 14;
  114. p = start + FT_PEEK_ULONG_LE( p );
  115. if ( p == start )
  116. /* zero offset means no table */
  117. goto Exit;
  118. if ( p + 2 > limit )
  119. {
  120. error = T1_Err_Unknown_File_Format;
  121. goto Exit;
  122. }
  123. fi->NumKernPair = FT_PEEK_USHORT_LE( p );
  124. p += 2;
  125. if ( p + 4 * fi->NumKernPair > limit )
  126. {
  127. error = T1_Err_Unknown_File_Format;
  128. goto Exit;
  129. }
  130. /* Actually, kerning pairs are simply optional! */
  131. if ( fi->NumKernPair == 0 )
  132. goto Exit;
  133. /* allocate the pairs */
  134. if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
  135. goto Exit;
  136. /* now, read each kern pair */
  137. kp = fi->KernPairs;
  138. limit = p + 4 * fi->NumKernPair;
  139. /* PFM kerning data are stored by encoding rather than glyph index, */
  140. /* so find the PostScript charmap of this font and install it */
  141. /* temporarily. If we find no PostScript charmap, then just use */
  142. /* the default and hope it is the right one. */
  143. oldcharmap = t1_face->charmap;
  144. charmap = NULL;
  145. for ( n = 0; n < t1_face->num_charmaps; n++ )
  146. {
  147. charmap = t1_face->charmaps[n];
  148. /* check against PostScript pseudo platform */
  149. if ( charmap->platform_id == 7 )
  150. {
  151. error = FT_Set_Charmap( t1_face, charmap );
  152. if ( error )
  153. goto Exit;
  154. break;
  155. }
  156. }
  157. /* Kerning info is stored as: */
  158. /* */
  159. /* encoding of first glyph (1 byte) */
  160. /* encoding of second glyph (1 byte) */
  161. /* offset (little-endian short) */
  162. for ( ; p < limit ; p += 4 )
  163. {
  164. kp->index1 = FT_Get_Char_Index( t1_face, p[0] );
  165. kp->index2 = FT_Get_Char_Index( t1_face, p[1] );
  166. kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2);
  167. kp->y = 0;
  168. kp++;
  169. }
  170. if ( oldcharmap != NULL )
  171. error = FT_Set_Charmap( t1_face, oldcharmap );
  172. if ( error )
  173. goto Exit;
  174. /* now, sort the kern pairs according to their glyph indices */
  175. ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ),
  176. compare_kern_pairs );
  177. Exit:
  178. if ( error )
  179. {
  180. FT_FREE( fi->KernPairs );
  181. fi->NumKernPair = 0;
  182. }
  183. return error;
  184. }
  185. /* parse a metrics file -- either AFM or PFM depending on what */
  186. /* it turns out to be */
  187. FT_LOCAL_DEF( FT_Error )
  188. T1_Read_Metrics( FT_Face t1_face,
  189. FT_Stream stream )
  190. {
  191. PSAux_Service psaux;
  192. FT_Memory memory = stream->memory;
  193. AFM_ParserRec parser;
  194. AFM_FontInfo fi = NULL;
  195. FT_Error error = T1_Err_Unknown_File_Format;
  196. T1_Font t1_font = &( (T1_Face)t1_face )->type1;
  197. if ( FT_NEW( fi ) ||
  198. FT_FRAME_ENTER( stream->size ) )
  199. goto Exit;
  200. fi->FontBBox = t1_font->font_bbox;
  201. fi->Ascender = t1_font->font_bbox.yMax;
  202. fi->Descender = t1_font->font_bbox.yMin;
  203. psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux;
  204. if ( psaux && psaux->afm_parser_funcs )
  205. {
  206. error = psaux->afm_parser_funcs->init( &parser,
  207. stream->memory,
  208. stream->cursor,
  209. stream->limit );
  210. if ( !error )
  211. {
  212. parser.FontInfo = fi;
  213. parser.get_index = t1_get_index;
  214. parser.user_data = t1_font;
  215. error = psaux->afm_parser_funcs->parse( &parser );
  216. psaux->afm_parser_funcs->done( &parser );
  217. }
  218. }
  219. if ( error == T1_Err_Unknown_File_Format )
  220. {
  221. FT_Byte* start = stream->cursor;
  222. /* MS Windows allows versions up to 0x3FF without complaining */
  223. if ( stream->size > 6 &&
  224. start[1] < 4 &&
  225. FT_PEEK_ULONG_LE( start + 2 ) == stream->size )
  226. error = T1_Read_PFM( t1_face, stream, fi );
  227. }
  228. if ( !error )
  229. {
  230. t1_font->font_bbox = fi->FontBBox;
  231. t1_face->bbox.xMin = fi->FontBBox.xMin >> 16;
  232. t1_face->bbox.yMin = fi->FontBBox.yMin >> 16;
  233. /* no `U' suffix here to 0xFFFF! */
  234. t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFF ) >> 16;
  235. t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFF ) >> 16;
  236. /* no `U' suffix here to 0x8000! */
  237. t1_face->ascender = (FT_Short)( ( fi->Ascender + 0x8000 ) >> 16 );
  238. t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 );
  239. if ( fi->NumKernPair )
  240. {
  241. t1_face->face_flags |= FT_FACE_FLAG_KERNING;
  242. ( (T1_Face)t1_face )->afm_data = fi;
  243. fi = NULL;
  244. }
  245. }
  246. FT_FRAME_EXIT();
  247. Exit:
  248. if ( fi != NULL )
  249. T1_Done_Metrics( memory, fi );
  250. return error;
  251. }
  252. /* find the kerning for a given glyph pair */
  253. FT_LOCAL_DEF( void )
  254. T1_Get_Kerning( AFM_FontInfo fi,
  255. FT_UInt glyph1,
  256. FT_UInt glyph2,
  257. FT_Vector* kerning )
  258. {
  259. AFM_KernPair min, mid, max;
  260. FT_ULong idx = KERN_INDEX( glyph1, glyph2 );
  261. /* simple binary search */
  262. min = fi->KernPairs;
  263. max = min + fi->NumKernPair - 1;
  264. while ( min <= max )
  265. {
  266. FT_ULong midi;
  267. mid = min + ( max - min ) / 2;
  268. midi = KERN_INDEX( mid->index1, mid->index2 );
  269. if ( midi == idx )
  270. {
  271. kerning->x = mid->x;
  272. kerning->y = mid->y;
  273. return;
  274. }
  275. if ( midi < idx )
  276. min = mid + 1;
  277. else
  278. max = mid - 1;
  279. }
  280. kerning->x = 0;
  281. kerning->y = 0;
  282. }
  283. FT_LOCAL_DEF( FT_Error )
  284. T1_Get_Track_Kerning( FT_Face face,
  285. FT_Fixed ptsize,
  286. FT_Int degree,
  287. FT_Fixed* kerning )
  288. {
  289. AFM_FontInfo fi = (AFM_FontInfo)( (T1_Face)face )->afm_data;
  290. FT_Int i;
  291. if ( !fi )
  292. return T1_Err_Invalid_Argument;
  293. for ( i = 0; i < fi->NumTrackKern; i++ )
  294. {
  295. AFM_TrackKern tk = fi->TrackKerns + i;
  296. if ( tk->degree != degree )
  297. continue;
  298. if ( ptsize < tk->min_ptsize )
  299. *kerning = tk->min_kern;
  300. else if ( ptsize > tk->max_ptsize )
  301. *kerning = tk->max_kern;
  302. else
  303. {
  304. *kerning = FT_MulDiv( ptsize - tk->min_ptsize,
  305. tk->max_kern - tk->min_kern,
  306. tk->max_ptsize - tk->min_ptsize ) +
  307. tk->min_kern;
  308. }
  309. }
  310. return T1_Err_Ok;
  311. }
  312. /* END */