Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygent1afm.c
Go to the documentation of this file.
00001 /***************************************************************************/ 00002 /* */ 00003 /* t1afm.c */ 00004 /* */ 00005 /* AFM support for Type 1 fonts (body). */ 00006 /* */ 00007 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ 00008 /* 2010 by */ 00009 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 00010 /* */ 00011 /* This file is part of the FreeType project, and may only be used, */ 00012 /* modified, and distributed under the terms of the FreeType project */ 00013 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 00014 /* this file you indicate that you have read the license and */ 00015 /* understand and accept it fully. */ 00016 /* */ 00017 /***************************************************************************/ 00018 00019 00020 #include <ft2build.h> 00021 #include "t1afm.h" 00022 #include "t1errors.h" 00023 #include FT_INTERNAL_STREAM_H 00024 #include FT_INTERNAL_POSTSCRIPT_AUX_H 00025 00026 00027 /*************************************************************************/ 00028 /* */ 00029 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 00030 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 00031 /* messages during execution. */ 00032 /* */ 00033 #undef FT_COMPONENT 00034 #define FT_COMPONENT trace_t1afm 00035 00036 00037 FT_LOCAL_DEF( void ) 00038 T1_Done_Metrics( FT_Memory memory, 00039 AFM_FontInfo fi ) 00040 { 00041 FT_FREE( fi->KernPairs ); 00042 fi->NumKernPair = 0; 00043 00044 FT_FREE( fi->TrackKerns ); 00045 fi->NumTrackKern = 0; 00046 00047 FT_FREE( fi ); 00048 } 00049 00050 00051 /* read a glyph name and return the equivalent glyph index */ 00052 static FT_Int 00053 t1_get_index( const char* name, 00054 FT_Offset len, 00055 void* user_data ) 00056 { 00057 T1_Font type1 = (T1_Font)user_data; 00058 FT_Int n; 00059 00060 00061 /* PS string/name length must be < 16-bit */ 00062 if ( len > 0xFFFFU ) 00063 return 0; 00064 00065 for ( n = 0; n < type1->num_glyphs; n++ ) 00066 { 00067 char* gname = (char*)type1->glyph_names[n]; 00068 00069 00070 if ( gname && gname[0] == name[0] && 00071 ft_strlen( gname ) == len && 00072 ft_strncmp( gname, name, len ) == 0 ) 00073 return n; 00074 } 00075 00076 return 0; 00077 } 00078 00079 00080 #undef KERN_INDEX 00081 #define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) 00082 00083 00084 /* compare two kerning pairs */ 00085 FT_CALLBACK_DEF( int ) 00086 compare_kern_pairs( const void* a, 00087 const void* b ) 00088 { 00089 AFM_KernPair pair1 = (AFM_KernPair)a; 00090 AFM_KernPair pair2 = (AFM_KernPair)b; 00091 00092 FT_ULong index1 = KERN_INDEX( pair1->index1, pair1->index2 ); 00093 FT_ULong index2 = KERN_INDEX( pair2->index1, pair2->index2 ); 00094 00095 00096 if ( index1 > index2 ) 00097 return 1; 00098 else if ( index1 < index2 ) 00099 return -1; 00100 else 00101 return 0; 00102 } 00103 00104 00105 /* parse a PFM file -- for now, only read the kerning pairs */ 00106 static FT_Error 00107 T1_Read_PFM( FT_Face t1_face, 00108 FT_Stream stream, 00109 AFM_FontInfo fi ) 00110 { 00111 FT_Error error = T1_Err_Ok; 00112 FT_Memory memory = stream->memory; 00113 FT_Byte* start; 00114 FT_Byte* limit; 00115 FT_Byte* p; 00116 AFM_KernPair kp; 00117 FT_Int width_table_length; 00118 FT_CharMap oldcharmap; 00119 FT_CharMap charmap; 00120 FT_Int n; 00121 00122 00123 start = (FT_Byte*)stream->cursor; 00124 limit = (FT_Byte*)stream->limit; 00125 p = start; 00126 00127 /* Figure out how long the width table is. */ 00128 /* This info is a little-endian short at offset 99. */ 00129 p = start + 99; 00130 if ( p + 2 > limit ) 00131 { 00132 error = T1_Err_Unknown_File_Format; 00133 goto Exit; 00134 } 00135 width_table_length = FT_PEEK_USHORT_LE( p ); 00136 00137 p += 18 + width_table_length; 00138 if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 ) 00139 /* extension table is probably optional */ 00140 goto Exit; 00141 00142 /* Kerning offset is 14 bytes from start of extensions table. */ 00143 p += 14; 00144 p = start + FT_PEEK_ULONG_LE( p ); 00145 00146 if ( p == start ) 00147 /* zero offset means no table */ 00148 goto Exit; 00149 00150 if ( p + 2 > limit ) 00151 { 00152 error = T1_Err_Unknown_File_Format; 00153 goto Exit; 00154 } 00155 00156 fi->NumKernPair = FT_PEEK_USHORT_LE( p ); 00157 p += 2; 00158 if ( p + 4 * fi->NumKernPair > limit ) 00159 { 00160 error = T1_Err_Unknown_File_Format; 00161 goto Exit; 00162 } 00163 00164 /* Actually, kerning pairs are simply optional! */ 00165 if ( fi->NumKernPair == 0 ) 00166 goto Exit; 00167 00168 /* allocate the pairs */ 00169 if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) ) 00170 goto Exit; 00171 00172 /* now, read each kern pair */ 00173 kp = fi->KernPairs; 00174 limit = p + 4 * fi->NumKernPair; 00175 00176 /* PFM kerning data are stored by encoding rather than glyph index, */ 00177 /* so find the PostScript charmap of this font and install it */ 00178 /* temporarily. If we find no PostScript charmap, then just use */ 00179 /* the default and hope it is the right one. */ 00180 oldcharmap = t1_face->charmap; 00181 charmap = NULL; 00182 00183 for ( n = 0; n < t1_face->num_charmaps; n++ ) 00184 { 00185 charmap = t1_face->charmaps[n]; 00186 /* check against PostScript pseudo platform */ 00187 if ( charmap->platform_id == 7 ) 00188 { 00189 error = FT_Set_Charmap( t1_face, charmap ); 00190 if ( error ) 00191 goto Exit; 00192 break; 00193 } 00194 } 00195 00196 /* Kerning info is stored as: */ 00197 /* */ 00198 /* encoding of first glyph (1 byte) */ 00199 /* encoding of second glyph (1 byte) */ 00200 /* offset (little-endian short) */ 00201 for ( ; p < limit ; p += 4 ) 00202 { 00203 kp->index1 = FT_Get_Char_Index( t1_face, p[0] ); 00204 kp->index2 = FT_Get_Char_Index( t1_face, p[1] ); 00205 00206 kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2); 00207 kp->y = 0; 00208 00209 kp++; 00210 } 00211 00212 if ( oldcharmap != NULL ) 00213 error = FT_Set_Charmap( t1_face, oldcharmap ); 00214 if ( error ) 00215 goto Exit; 00216 00217 /* now, sort the kern pairs according to their glyph indices */ 00218 ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ), 00219 compare_kern_pairs ); 00220 00221 Exit: 00222 if ( error ) 00223 { 00224 FT_FREE( fi->KernPairs ); 00225 fi->NumKernPair = 0; 00226 } 00227 00228 return error; 00229 } 00230 00231 00232 /* parse a metrics file -- either AFM or PFM depending on what */ 00233 /* it turns out to be */ 00234 FT_LOCAL_DEF( FT_Error ) 00235 T1_Read_Metrics( FT_Face t1_face, 00236 FT_Stream stream ) 00237 { 00238 PSAux_Service psaux; 00239 FT_Memory memory = stream->memory; 00240 AFM_ParserRec parser; 00241 AFM_FontInfo fi = NULL; 00242 FT_Error error = T1_Err_Unknown_File_Format; 00243 T1_Font t1_font = &( (T1_Face)t1_face )->type1; 00244 00245 00246 if ( FT_NEW( fi ) || 00247 FT_FRAME_ENTER( stream->size ) ) 00248 goto Exit; 00249 00250 fi->FontBBox = t1_font->font_bbox; 00251 fi->Ascender = t1_font->font_bbox.yMax; 00252 fi->Descender = t1_font->font_bbox.yMin; 00253 00254 psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux; 00255 if ( psaux && psaux->afm_parser_funcs ) 00256 { 00257 error = psaux->afm_parser_funcs->init( &parser, 00258 stream->memory, 00259 stream->cursor, 00260 stream->limit ); 00261 00262 if ( !error ) 00263 { 00264 parser.FontInfo = fi; 00265 parser.get_index = t1_get_index; 00266 parser.user_data = t1_font; 00267 00268 error = psaux->afm_parser_funcs->parse( &parser ); 00269 psaux->afm_parser_funcs->done( &parser ); 00270 } 00271 } 00272 00273 if ( error == T1_Err_Unknown_File_Format ) 00274 { 00275 FT_Byte* start = stream->cursor; 00276 00277 00278 /* MS Windows allows versions up to 0x3FF without complaining */ 00279 if ( stream->size > 6 && 00280 start[1] < 4 && 00281 FT_PEEK_ULONG_LE( start + 2 ) == stream->size ) 00282 error = T1_Read_PFM( t1_face, stream, fi ); 00283 } 00284 00285 if ( !error ) 00286 { 00287 t1_font->font_bbox = fi->FontBBox; 00288 00289 t1_face->bbox.xMin = fi->FontBBox.xMin >> 16; 00290 t1_face->bbox.yMin = fi->FontBBox.yMin >> 16; 00291 /* no `U' suffix here to 0xFFFF! */ 00292 t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFF ) >> 16; 00293 t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFF ) >> 16; 00294 00295 /* no `U' suffix here to 0x8000! */ 00296 t1_face->ascender = (FT_Short)( ( fi->Ascender + 0x8000 ) >> 16 ); 00297 t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 ); 00298 00299 if ( fi->NumKernPair ) 00300 { 00301 t1_face->face_flags |= FT_FACE_FLAG_KERNING; 00302 ( (T1_Face)t1_face )->afm_data = fi; 00303 fi = NULL; 00304 } 00305 } 00306 00307 FT_FRAME_EXIT(); 00308 00309 Exit: 00310 if ( fi != NULL ) 00311 T1_Done_Metrics( memory, fi ); 00312 00313 return error; 00314 } 00315 00316 00317 /* find the kerning for a given glyph pair */ 00318 FT_LOCAL_DEF( void ) 00319 T1_Get_Kerning( AFM_FontInfo fi, 00320 FT_UInt glyph1, 00321 FT_UInt glyph2, 00322 FT_Vector* kerning ) 00323 { 00324 AFM_KernPair min, mid, max; 00325 FT_ULong idx = KERN_INDEX( glyph1, glyph2 ); 00326 00327 00328 /* simple binary search */ 00329 min = fi->KernPairs; 00330 max = min + fi->NumKernPair - 1; 00331 00332 while ( min <= max ) 00333 { 00334 FT_ULong midi; 00335 00336 00337 mid = min + ( max - min ) / 2; 00338 midi = KERN_INDEX( mid->index1, mid->index2 ); 00339 00340 if ( midi == idx ) 00341 { 00342 kerning->x = mid->x; 00343 kerning->y = mid->y; 00344 00345 return; 00346 } 00347 00348 if ( midi < idx ) 00349 min = mid + 1; 00350 else 00351 max = mid - 1; 00352 } 00353 00354 kerning->x = 0; 00355 kerning->y = 0; 00356 } 00357 00358 00359 FT_LOCAL_DEF( FT_Error ) 00360 T1_Get_Track_Kerning( FT_Face face, 00361 FT_Fixed ptsize, 00362 FT_Int degree, 00363 FT_Fixed* kerning ) 00364 { 00365 AFM_FontInfo fi = (AFM_FontInfo)( (T1_Face)face )->afm_data; 00366 FT_Int i; 00367 00368 00369 if ( !fi ) 00370 return T1_Err_Invalid_Argument; 00371 00372 for ( i = 0; i < fi->NumTrackKern; i++ ) 00373 { 00374 AFM_TrackKern tk = fi->TrackKerns + i; 00375 00376 00377 if ( tk->degree != degree ) 00378 continue; 00379 00380 if ( ptsize < tk->min_ptsize ) 00381 *kerning = tk->min_kern; 00382 else if ( ptsize > tk->max_ptsize ) 00383 *kerning = tk->max_kern; 00384 else 00385 { 00386 *kerning = FT_MulDiv( ptsize - tk->min_ptsize, 00387 tk->max_kern - tk->min_kern, 00388 tk->max_ptsize - tk->min_ptsize ) + 00389 tk->min_kern; 00390 } 00391 } 00392 00393 return T1_Err_Ok; 00394 } 00395 00396 00397 /* END */ Generated on Fri May 25 2012 04:32:34 for ReactOS by
1.7.6.1
|