Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygent1load.c
Go to the documentation of this file.
00001 /***************************************************************************/ 00002 /* */ 00003 /* t1load.c */ 00004 /* */ 00005 /* Type 1 font loader (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 /*************************************************************************/ 00021 /* */ 00022 /* This is the new and improved Type 1 data loader for FreeType 2. The */ 00023 /* old loader has several problems: it is slow, complex, difficult to */ 00024 /* maintain, and contains incredible hacks to make it accept some */ 00025 /* ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of */ 00026 /* the Type 1 fonts on my machine still aren't loaded correctly by it. */ 00027 /* */ 00028 /* This version is much simpler, much faster and also easier to read and */ 00029 /* maintain by a great order of magnitude. The idea behind it is to */ 00030 /* _not_ try to read the Type 1 token stream with a state machine (i.e. */ 00031 /* a Postscript-like interpreter) but rather to perform simple pattern */ 00032 /* matching. */ 00033 /* */ 00034 /* Indeed, nearly all data definitions follow a simple pattern like */ 00035 /* */ 00036 /* ... /Field <data> ... */ 00037 /* */ 00038 /* where <data> can be a number, a boolean, a string, or an array of */ 00039 /* numbers. There are a few exceptions, namely the encoding, font name, */ 00040 /* charstrings, and subrs; they are handled with a special pattern */ 00041 /* matching routine. */ 00042 /* */ 00043 /* All other common cases are handled very simply. The matching rules */ 00044 /* are defined in the file `t1tokens.h' through the use of several */ 00045 /* macros calls PARSE_XXX. This file is included twice here; the first */ 00046 /* time to generate parsing callback functions, the second time to */ 00047 /* generate a table of keywords (with pointers to the associated */ 00048 /* callback functions). */ 00049 /* */ 00050 /* The function `parse_dict' simply scans *linearly* a given dictionary */ 00051 /* (either the top-level or private one) and calls the appropriate */ 00052 /* callback when it encounters an immediate keyword. */ 00053 /* */ 00054 /* This is by far the fastest way one can find to parse and read all */ 00055 /* data. */ 00056 /* */ 00057 /* This led to tremendous code size reduction. Note that later, the */ 00058 /* glyph loader will also be _greatly_ simplified, and the automatic */ 00059 /* hinter will replace the clumsy `t1hinter'. */ 00060 /* */ 00061 /*************************************************************************/ 00062 00063 00064 #include <ft2build.h> 00065 #include FT_INTERNAL_DEBUG_H 00066 #include FT_CONFIG_CONFIG_H 00067 #include FT_MULTIPLE_MASTERS_H 00068 #include FT_INTERNAL_TYPE1_TYPES_H 00069 #include FT_INTERNAL_CALC_H 00070 00071 #include "t1load.h" 00072 #include "t1errors.h" 00073 00074 00075 /*************************************************************************/ 00076 /* */ 00077 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 00078 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 00079 /* messages during execution. */ 00080 /* */ 00081 #undef FT_COMPONENT 00082 #define FT_COMPONENT trace_t1load 00083 00084 00085 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT 00086 00087 00088 /*************************************************************************/ 00089 /*************************************************************************/ 00090 /***** *****/ 00091 /***** MULTIPLE MASTERS SUPPORT *****/ 00092 /***** *****/ 00093 /*************************************************************************/ 00094 /*************************************************************************/ 00095 00096 static FT_Error 00097 t1_allocate_blend( T1_Face face, 00098 FT_UInt num_designs, 00099 FT_UInt num_axis ) 00100 { 00101 PS_Blend blend; 00102 FT_Memory memory = face->root.memory; 00103 FT_Error error = T1_Err_Ok; 00104 00105 00106 blend = face->blend; 00107 if ( !blend ) 00108 { 00109 if ( FT_NEW( blend ) ) 00110 goto Exit; 00111 00112 blend->num_default_design_vector = 0; 00113 00114 face->blend = blend; 00115 } 00116 00117 /* allocate design data if needed */ 00118 if ( num_designs > 0 ) 00119 { 00120 if ( blend->num_designs == 0 ) 00121 { 00122 FT_UInt nn; 00123 00124 00125 /* allocate the blend `private' and `font_info' dictionaries */ 00126 if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) || 00127 FT_NEW_ARRAY( blend->privates[1], num_designs ) || 00128 FT_NEW_ARRAY( blend->bboxes[1], num_designs ) || 00129 FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) 00130 goto Exit; 00131 00132 blend->default_weight_vector = blend->weight_vector + num_designs; 00133 00134 blend->font_infos[0] = &face->type1.font_info; 00135 blend->privates [0] = &face->type1.private_dict; 00136 blend->bboxes [0] = &face->type1.font_bbox; 00137 00138 for ( nn = 2; nn <= num_designs; nn++ ) 00139 { 00140 blend->privates[nn] = blend->privates [nn - 1] + 1; 00141 blend->font_infos[nn] = blend->font_infos[nn - 1] + 1; 00142 blend->bboxes[nn] = blend->bboxes [nn - 1] + 1; 00143 } 00144 00145 blend->num_designs = num_designs; 00146 } 00147 else if ( blend->num_designs != num_designs ) 00148 goto Fail; 00149 } 00150 00151 /* allocate axis data if needed */ 00152 if ( num_axis > 0 ) 00153 { 00154 if ( blend->num_axis != 0 && blend->num_axis != num_axis ) 00155 goto Fail; 00156 00157 blend->num_axis = num_axis; 00158 } 00159 00160 /* allocate the blend design pos table if needed */ 00161 num_designs = blend->num_designs; 00162 num_axis = blend->num_axis; 00163 if ( num_designs && num_axis && blend->design_pos[0] == 0 ) 00164 { 00165 FT_UInt n; 00166 00167 00168 if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) ) 00169 goto Exit; 00170 00171 for ( n = 1; n < num_designs; n++ ) 00172 blend->design_pos[n] = blend->design_pos[0] + num_axis * n; 00173 } 00174 00175 Exit: 00176 return error; 00177 00178 Fail: 00179 error = T1_Err_Invalid_File_Format; 00180 goto Exit; 00181 } 00182 00183 00184 FT_LOCAL_DEF( FT_Error ) 00185 T1_Get_Multi_Master( T1_Face face, 00186 FT_Multi_Master* master ) 00187 { 00188 PS_Blend blend = face->blend; 00189 FT_UInt n; 00190 FT_Error error; 00191 00192 00193 error = T1_Err_Invalid_Argument; 00194 00195 if ( blend ) 00196 { 00197 master->num_axis = blend->num_axis; 00198 master->num_designs = blend->num_designs; 00199 00200 for ( n = 0; n < blend->num_axis; n++ ) 00201 { 00202 FT_MM_Axis* axis = master->axis + n; 00203 PS_DesignMap map = blend->design_map + n; 00204 00205 00206 axis->name = blend->axis_names[n]; 00207 axis->minimum = map->design_points[0]; 00208 axis->maximum = map->design_points[map->num_points - 1]; 00209 } 00210 00211 error = T1_Err_Ok; 00212 } 00213 00214 return error; 00215 } 00216 00217 00218 /*************************************************************************/ 00219 /* */ 00220 /* Given a normalized (blend) coordinate, figure out the design */ 00221 /* coordinate appropriate for that value. */ 00222 /* */ 00223 FT_LOCAL_DEF( FT_Fixed ) 00224 mm_axis_unmap( PS_DesignMap axismap, 00225 FT_Fixed ncv ) 00226 { 00227 int j; 00228 00229 00230 if ( ncv <= axismap->blend_points[0] ) 00231 return INT_TO_FIXED( axismap->design_points[0] ); 00232 00233 for ( j = 1; j < axismap->num_points; ++j ) 00234 { 00235 if ( ncv <= axismap->blend_points[j] ) 00236 { 00237 FT_Fixed t = FT_MulDiv( ncv - axismap->blend_points[j - 1], 00238 0x10000L, 00239 axismap->blend_points[j] - 00240 axismap->blend_points[j - 1] ); 00241 00242 return INT_TO_FIXED( axismap->design_points[j - 1] ) + 00243 FT_MulDiv( t, 00244 axismap->design_points[j] - 00245 axismap->design_points[j - 1], 00246 1L ); 00247 } 00248 } 00249 00250 return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] ); 00251 } 00252 00253 00254 /*************************************************************************/ 00255 /* */ 00256 /* Given a vector of weights, one for each design, figure out the */ 00257 /* normalized axis coordinates which gave rise to those weights. */ 00258 /* */ 00259 FT_LOCAL_DEF( void ) 00260 mm_weights_unmap( FT_Fixed* weights, 00261 FT_Fixed* axiscoords, 00262 FT_UInt axis_count ) 00263 { 00264 FT_ASSERT( axis_count <= T1_MAX_MM_AXIS ); 00265 00266 if ( axis_count == 1 ) 00267 axiscoords[0] = weights[1]; 00268 00269 else if ( axis_count == 2 ) 00270 { 00271 axiscoords[0] = weights[3] + weights[1]; 00272 axiscoords[1] = weights[3] + weights[2]; 00273 } 00274 00275 else if ( axis_count == 3 ) 00276 { 00277 axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1]; 00278 axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2]; 00279 axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4]; 00280 } 00281 00282 else 00283 { 00284 axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] + 00285 weights[7] + weights[5] + weights[3] + weights[1]; 00286 axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] + 00287 weights[7] + weights[6] + weights[3] + weights[2]; 00288 axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] + 00289 weights[7] + weights[6] + weights[5] + weights[4]; 00290 axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] + 00291 weights[11] + weights[10] + weights[9] + weights[8]; 00292 } 00293 } 00294 00295 00296 /*************************************************************************/ 00297 /* */ 00298 /* Just a wrapper around T1_Get_Multi_Master to support the different */ 00299 /* arguments needed by the GX var distortable fonts. */ 00300 /* */ 00301 FT_LOCAL_DEF( FT_Error ) 00302 T1_Get_MM_Var( T1_Face face, 00303 FT_MM_Var* *master ) 00304 { 00305 FT_Memory memory = face->root.memory; 00306 FT_MM_Var *mmvar; 00307 FT_Multi_Master mmaster; 00308 FT_Error error; 00309 FT_UInt i; 00310 FT_Fixed axiscoords[T1_MAX_MM_AXIS]; 00311 PS_Blend blend = face->blend; 00312 00313 00314 error = T1_Get_Multi_Master( face, &mmaster ); 00315 if ( error ) 00316 goto Exit; 00317 if ( FT_ALLOC( mmvar, 00318 sizeof ( FT_MM_Var ) + 00319 mmaster.num_axis * sizeof ( FT_Var_Axis ) ) ) 00320 goto Exit; 00321 00322 mmvar->num_axis = mmaster.num_axis; 00323 mmvar->num_designs = mmaster.num_designs; 00324 mmvar->num_namedstyles = (FT_UInt)-1; /* Does not apply */ 00325 mmvar->axis = (FT_Var_Axis*)&mmvar[1]; 00326 /* Point to axes after MM_Var struct */ 00327 mmvar->namedstyle = NULL; 00328 00329 for ( i = 0 ; i < mmaster.num_axis; ++i ) 00330 { 00331 mmvar->axis[i].name = mmaster.axis[i].name; 00332 mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum); 00333 mmvar->axis[i].maximum = INT_TO_FIXED( mmaster.axis[i].maximum); 00334 mmvar->axis[i].def = ( mmvar->axis[i].minimum + 00335 mmvar->axis[i].maximum ) / 2; 00336 /* Does not apply. But this value is in range */ 00337 mmvar->axis[i].strid = (FT_UInt)-1; /* Does not apply */ 00338 mmvar->axis[i].tag = (FT_ULong)-1; /* Does not apply */ 00339 00340 if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 ) 00341 mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' ); 00342 else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 ) 00343 mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' ); 00344 else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 ) 00345 mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' ); 00346 } 00347 00348 if ( blend->num_designs == ( 1U << blend->num_axis ) ) 00349 { 00350 mm_weights_unmap( blend->default_weight_vector, 00351 axiscoords, 00352 blend->num_axis ); 00353 00354 for ( i = 0; i < mmaster.num_axis; ++i ) 00355 mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i], 00356 axiscoords[i] ); 00357 } 00358 00359 *master = mmvar; 00360 00361 Exit: 00362 return error; 00363 } 00364 00365 00366 FT_LOCAL_DEF( FT_Error ) 00367 T1_Set_MM_Blend( T1_Face face, 00368 FT_UInt num_coords, 00369 FT_Fixed* coords ) 00370 { 00371 PS_Blend blend = face->blend; 00372 FT_Error error; 00373 FT_UInt n, m; 00374 00375 00376 error = T1_Err_Invalid_Argument; 00377 00378 if ( blend && blend->num_axis == num_coords ) 00379 { 00380 /* recompute the weight vector from the blend coordinates */ 00381 error = T1_Err_Ok; 00382 00383 for ( n = 0; n < blend->num_designs; n++ ) 00384 { 00385 FT_Fixed result = 0x10000L; /* 1.0 fixed */ 00386 00387 00388 for ( m = 0; m < blend->num_axis; m++ ) 00389 { 00390 FT_Fixed factor; 00391 00392 00393 /* get current blend axis position */ 00394 factor = coords[m]; 00395 if ( factor < 0 ) factor = 0; 00396 if ( factor > 0x10000L ) factor = 0x10000L; 00397 00398 if ( ( n & ( 1 << m ) ) == 0 ) 00399 factor = 0x10000L - factor; 00400 00401 result = FT_MulFix( result, factor ); 00402 } 00403 blend->weight_vector[n] = result; 00404 } 00405 00406 error = T1_Err_Ok; 00407 } 00408 00409 return error; 00410 } 00411 00412 00413 FT_LOCAL_DEF( FT_Error ) 00414 T1_Set_MM_Design( T1_Face face, 00415 FT_UInt num_coords, 00416 FT_Long* coords ) 00417 { 00418 PS_Blend blend = face->blend; 00419 FT_Error error; 00420 FT_UInt n, p; 00421 00422 00423 error = T1_Err_Invalid_Argument; 00424 if ( blend && blend->num_axis == num_coords ) 00425 { 00426 /* compute the blend coordinates through the blend design map */ 00427 FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; 00428 00429 00430 for ( n = 0; n < blend->num_axis; n++ ) 00431 { 00432 FT_Long design = coords[n]; 00433 FT_Fixed the_blend; 00434 PS_DesignMap map = blend->design_map + n; 00435 FT_Long* designs = map->design_points; 00436 FT_Fixed* blends = map->blend_points; 00437 FT_Int before = -1, after = -1; 00438 00439 00440 for ( p = 0; p < (FT_UInt)map->num_points; p++ ) 00441 { 00442 FT_Long p_design = designs[p]; 00443 00444 00445 /* exact match? */ 00446 if ( design == p_design ) 00447 { 00448 the_blend = blends[p]; 00449 goto Found; 00450 } 00451 00452 if ( design < p_design ) 00453 { 00454 after = p; 00455 break; 00456 } 00457 00458 before = p; 00459 } 00460 00461 /* now interpolate if necessary */ 00462 if ( before < 0 ) 00463 the_blend = blends[0]; 00464 00465 else if ( after < 0 ) 00466 the_blend = blends[map->num_points - 1]; 00467 00468 else 00469 the_blend = FT_MulDiv( design - designs[before], 00470 blends [after] - blends [before], 00471 designs[after] - designs[before] ); 00472 00473 Found: 00474 final_blends[n] = the_blend; 00475 } 00476 00477 error = T1_Set_MM_Blend( face, num_coords, final_blends ); 00478 } 00479 00480 return error; 00481 } 00482 00483 00484 /*************************************************************************/ 00485 /* */ 00486 /* Just a wrapper around T1_Set_MM_Design to support the different */ 00487 /* arguments needed by the GX var distortable fonts. */ 00488 /* */ 00489 FT_LOCAL_DEF( FT_Error ) 00490 T1_Set_Var_Design( T1_Face face, 00491 FT_UInt num_coords, 00492 FT_Fixed* coords ) 00493 { 00494 FT_Long lcoords[4]; /* maximum axis count is 4 */ 00495 FT_UInt i; 00496 FT_Error error; 00497 00498 00499 error = T1_Err_Invalid_Argument; 00500 if ( num_coords <= 4 && num_coords > 0 ) 00501 { 00502 for ( i = 0; i < num_coords; ++i ) 00503 lcoords[i] = FIXED_TO_INT( coords[i] ); 00504 error = T1_Set_MM_Design( face, num_coords, lcoords ); 00505 } 00506 00507 return error; 00508 } 00509 00510 00511 FT_LOCAL_DEF( void ) 00512 T1_Done_Blend( T1_Face face ) 00513 { 00514 FT_Memory memory = face->root.memory; 00515 PS_Blend blend = face->blend; 00516 00517 00518 if ( blend ) 00519 { 00520 FT_UInt num_designs = blend->num_designs; 00521 FT_UInt num_axis = blend->num_axis; 00522 FT_UInt n; 00523 00524 00525 /* release design pos table */ 00526 FT_FREE( blend->design_pos[0] ); 00527 for ( n = 1; n < num_designs; n++ ) 00528 blend->design_pos[n] = 0; 00529 00530 /* release blend `private' and `font info' dictionaries */ 00531 FT_FREE( blend->privates[1] ); 00532 FT_FREE( blend->font_infos[1] ); 00533 FT_FREE( blend->bboxes[1] ); 00534 00535 for ( n = 0; n < num_designs; n++ ) 00536 { 00537 blend->privates [n] = 0; 00538 blend->font_infos[n] = 0; 00539 blend->bboxes [n] = 0; 00540 } 00541 00542 /* release weight vectors */ 00543 FT_FREE( blend->weight_vector ); 00544 blend->default_weight_vector = 0; 00545 00546 /* release axis names */ 00547 for ( n = 0; n < num_axis; n++ ) 00548 FT_FREE( blend->axis_names[n] ); 00549 00550 /* release design map */ 00551 for ( n = 0; n < num_axis; n++ ) 00552 { 00553 PS_DesignMap dmap = blend->design_map + n; 00554 00555 00556 FT_FREE( dmap->design_points ); 00557 dmap->num_points = 0; 00558 } 00559 00560 FT_FREE( face->blend ); 00561 } 00562 } 00563 00564 00565 static void 00566 parse_blend_axis_types( T1_Face face, 00567 T1_Loader loader ) 00568 { 00569 T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; 00570 FT_Int n, num_axis; 00571 FT_Error error = T1_Err_Ok; 00572 PS_Blend blend; 00573 FT_Memory memory; 00574 00575 00576 /* take an array of objects */ 00577 T1_ToTokenArray( &loader->parser, axis_tokens, 00578 T1_MAX_MM_AXIS, &num_axis ); 00579 if ( num_axis < 0 ) 00580 { 00581 error = T1_Err_Ignore; 00582 goto Exit; 00583 } 00584 if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) 00585 { 00586 FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n", 00587 num_axis )); 00588 error = T1_Err_Invalid_File_Format; 00589 goto Exit; 00590 } 00591 00592 /* allocate blend if necessary */ 00593 error = t1_allocate_blend( face, 0, (FT_UInt)num_axis ); 00594 if ( error ) 00595 goto Exit; 00596 00597 blend = face->blend; 00598 memory = face->root.memory; 00599 00600 /* each token is an immediate containing the name of the axis */ 00601 for ( n = 0; n < num_axis; n++ ) 00602 { 00603 T1_Token token = axis_tokens + n; 00604 FT_Byte* name; 00605 FT_PtrDist len; 00606 00607 00608 /* skip first slash, if any */ 00609 if ( token->start[0] == '/' ) 00610 token->start++; 00611 00612 len = token->limit - token->start; 00613 if ( len == 0 ) 00614 { 00615 error = T1_Err_Invalid_File_Format; 00616 goto Exit; 00617 } 00618 00619 if ( FT_ALLOC( blend->axis_names[n], len + 1 ) ) 00620 goto Exit; 00621 00622 name = (FT_Byte*)blend->axis_names[n]; 00623 FT_MEM_COPY( name, token->start, len ); 00624 name[len] = 0; 00625 } 00626 00627 Exit: 00628 loader->parser.root.error = error; 00629 } 00630 00631 00632 static void 00633 parse_blend_design_positions( T1_Face face, 00634 T1_Loader loader ) 00635 { 00636 T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; 00637 FT_Int num_designs; 00638 FT_Int num_axis; 00639 T1_Parser parser = &loader->parser; 00640 00641 FT_Error error = T1_Err_Ok; 00642 PS_Blend blend; 00643 00644 00645 /* get the array of design tokens -- compute number of designs */ 00646 T1_ToTokenArray( parser, design_tokens, 00647 T1_MAX_MM_DESIGNS, &num_designs ); 00648 if ( num_designs < 0 ) 00649 { 00650 error = T1_Err_Ignore; 00651 goto Exit; 00652 } 00653 if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) 00654 { 00655 FT_ERROR(( "parse_blend_design_positions:" 00656 " incorrect number of designs: %d\n", 00657 num_designs )); 00658 error = T1_Err_Invalid_File_Format; 00659 goto Exit; 00660 } 00661 00662 { 00663 FT_Byte* old_cursor = parser->root.cursor; 00664 FT_Byte* old_limit = parser->root.limit; 00665 FT_Int n; 00666 00667 00668 blend = face->blend; 00669 num_axis = 0; /* make compiler happy */ 00670 00671 for ( n = 0; n < num_designs; n++ ) 00672 { 00673 T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; 00674 T1_Token token; 00675 FT_Int axis, n_axis; 00676 00677 00678 /* read axis/coordinates tokens */ 00679 token = design_tokens + n; 00680 parser->root.cursor = token->start; 00681 parser->root.limit = token->limit; 00682 T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis ); 00683 00684 if ( n == 0 ) 00685 { 00686 if ( n_axis <= 0 || n_axis > T1_MAX_MM_AXIS ) 00687 { 00688 FT_ERROR(( "parse_blend_design_positions:" 00689 " invalid number of axes: %d\n", 00690 n_axis )); 00691 error = T1_Err_Invalid_File_Format; 00692 goto Exit; 00693 } 00694 00695 num_axis = n_axis; 00696 error = t1_allocate_blend( face, num_designs, num_axis ); 00697 if ( error ) 00698 goto Exit; 00699 blend = face->blend; 00700 } 00701 else if ( n_axis != num_axis ) 00702 { 00703 FT_ERROR(( "parse_blend_design_positions: incorrect table\n" )); 00704 error = T1_Err_Invalid_File_Format; 00705 goto Exit; 00706 } 00707 00708 /* now read each axis token into the design position */ 00709 for ( axis = 0; axis < n_axis; axis++ ) 00710 { 00711 T1_Token token2 = axis_tokens + axis; 00712 00713 00714 parser->root.cursor = token2->start; 00715 parser->root.limit = token2->limit; 00716 blend->design_pos[n][axis] = T1_ToFixed( parser, 0 ); 00717 } 00718 } 00719 00720 loader->parser.root.cursor = old_cursor; 00721 loader->parser.root.limit = old_limit; 00722 } 00723 00724 Exit: 00725 loader->parser.root.error = error; 00726 } 00727 00728 00729 static void 00730 parse_blend_design_map( T1_Face face, 00731 T1_Loader loader ) 00732 { 00733 FT_Error error = T1_Err_Ok; 00734 T1_Parser parser = &loader->parser; 00735 PS_Blend blend; 00736 T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; 00737 FT_Int n, num_axis; 00738 FT_Byte* old_cursor; 00739 FT_Byte* old_limit; 00740 FT_Memory memory = face->root.memory; 00741 00742 00743 T1_ToTokenArray( parser, axis_tokens, 00744 T1_MAX_MM_AXIS, &num_axis ); 00745 if ( num_axis < 0 ) 00746 { 00747 error = T1_Err_Ignore; 00748 goto Exit; 00749 } 00750 if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) 00751 { 00752 FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n", 00753 num_axis )); 00754 error = T1_Err_Invalid_File_Format; 00755 goto Exit; 00756 } 00757 00758 old_cursor = parser->root.cursor; 00759 old_limit = parser->root.limit; 00760 00761 error = t1_allocate_blend( face, 0, num_axis ); 00762 if ( error ) 00763 goto Exit; 00764 blend = face->blend; 00765 00766 /* now read each axis design map */ 00767 for ( n = 0; n < num_axis; n++ ) 00768 { 00769 PS_DesignMap map = blend->design_map + n; 00770 T1_Token axis_token; 00771 T1_TokenRec point_tokens[T1_MAX_MM_MAP_POINTS]; 00772 FT_Int p, num_points; 00773 00774 00775 axis_token = axis_tokens + n; 00776 00777 parser->root.cursor = axis_token->start; 00778 parser->root.limit = axis_token->limit; 00779 T1_ToTokenArray( parser, point_tokens, 00780 T1_MAX_MM_MAP_POINTS, &num_points ); 00781 00782 if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS ) 00783 { 00784 FT_ERROR(( "parse_blend_design_map: incorrect table\n" )); 00785 error = T1_Err_Invalid_File_Format; 00786 goto Exit; 00787 } 00788 00789 /* allocate design map data */ 00790 if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) ) 00791 goto Exit; 00792 map->blend_points = map->design_points + num_points; 00793 map->num_points = (FT_Byte)num_points; 00794 00795 for ( p = 0; p < num_points; p++ ) 00796 { 00797 T1_Token point_token; 00798 00799 00800 point_token = point_tokens + p; 00801 00802 /* don't include delimiting brackets */ 00803 parser->root.cursor = point_token->start + 1; 00804 parser->root.limit = point_token->limit - 1; 00805 00806 map->design_points[p] = T1_ToInt( parser ); 00807 map->blend_points [p] = T1_ToFixed( parser, 0 ); 00808 } 00809 } 00810 00811 parser->root.cursor = old_cursor; 00812 parser->root.limit = old_limit; 00813 00814 Exit: 00815 parser->root.error = error; 00816 } 00817 00818 00819 static void 00820 parse_weight_vector( T1_Face face, 00821 T1_Loader loader ) 00822 { 00823 T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; 00824 FT_Int num_designs; 00825 FT_Error error = T1_Err_Ok; 00826 T1_Parser parser = &loader->parser; 00827 PS_Blend blend = face->blend; 00828 T1_Token token; 00829 FT_Int n; 00830 FT_Byte* old_cursor; 00831 FT_Byte* old_limit; 00832 00833 00834 T1_ToTokenArray( parser, design_tokens, 00835 T1_MAX_MM_DESIGNS, &num_designs ); 00836 if ( num_designs < 0 ) 00837 { 00838 error = T1_Err_Ignore; 00839 goto Exit; 00840 } 00841 if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) 00842 { 00843 FT_ERROR(( "parse_weight_vector:" 00844 " incorrect number of designs: %d\n", 00845 num_designs )); 00846 error = T1_Err_Invalid_File_Format; 00847 goto Exit; 00848 } 00849 00850 if ( !blend || !blend->num_designs ) 00851 { 00852 error = t1_allocate_blend( face, num_designs, 0 ); 00853 if ( error ) 00854 goto Exit; 00855 blend = face->blend; 00856 } 00857 else if ( blend->num_designs != (FT_UInt)num_designs ) 00858 { 00859 FT_ERROR(( "parse_weight_vector:" 00860 " /BlendDesignPosition and /WeightVector have\n" 00861 " " 00862 " different number of elements\n" )); 00863 error = T1_Err_Invalid_File_Format; 00864 goto Exit; 00865 } 00866 00867 old_cursor = parser->root.cursor; 00868 old_limit = parser->root.limit; 00869 00870 for ( n = 0; n < num_designs; n++ ) 00871 { 00872 token = design_tokens + n; 00873 parser->root.cursor = token->start; 00874 parser->root.limit = token->limit; 00875 00876 blend->default_weight_vector[n] = 00877 blend->weight_vector[n] = T1_ToFixed( parser, 0 ); 00878 } 00879 00880 parser->root.cursor = old_cursor; 00881 parser->root.limit = old_limit; 00882 00883 Exit: 00884 parser->root.error = error; 00885 } 00886 00887 00888 /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def */ 00889 /* we're only interested in the number of array elements */ 00890 static void 00891 parse_buildchar( T1_Face face, 00892 T1_Loader loader ) 00893 { 00894 face->len_buildchar = T1_ToFixedArray( &loader->parser, 0, NULL, 0 ); 00895 00896 return; 00897 } 00898 00899 00900 #endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */ 00901 00902 00903 00904 00905 /*************************************************************************/ 00906 /*************************************************************************/ 00907 /***** *****/ 00908 /***** TYPE 1 SYMBOL PARSING *****/ 00909 /***** *****/ 00910 /*************************************************************************/ 00911 /*************************************************************************/ 00912 00913 static FT_Error 00914 t1_load_keyword( T1_Face face, 00915 T1_Loader loader, 00916 const T1_Field field ) 00917 { 00918 FT_Error error; 00919 void* dummy_object; 00920 void** objects; 00921 FT_UInt max_objects; 00922 PS_Blend blend = face->blend; 00923 00924 00925 /* if the keyword has a dedicated callback, call it */ 00926 if ( field->type == T1_FIELD_TYPE_CALLBACK ) 00927 { 00928 field->reader( (FT_Face)face, loader ); 00929 error = loader->parser.root.error; 00930 goto Exit; 00931 } 00932 00933 /* now, the keyword is either a simple field, or a table of fields; */ 00934 /* we are now going to take care of it */ 00935 switch ( field->location ) 00936 { 00937 case T1_FIELD_LOCATION_FONT_INFO: 00938 dummy_object = &face->type1.font_info; 00939 objects = &dummy_object; 00940 max_objects = 0; 00941 00942 if ( blend ) 00943 { 00944 objects = (void**)blend->font_infos; 00945 max_objects = blend->num_designs; 00946 } 00947 break; 00948 00949 case T1_FIELD_LOCATION_FONT_EXTRA: 00950 dummy_object = &face->type1.font_extra; 00951 objects = &dummy_object; 00952 max_objects = 0; 00953 break; 00954 00955 case T1_FIELD_LOCATION_PRIVATE: 00956 dummy_object = &face->type1.private_dict; 00957 objects = &dummy_object; 00958 max_objects = 0; 00959 00960 if ( blend ) 00961 { 00962 objects = (void**)blend->privates; 00963 max_objects = blend->num_designs; 00964 } 00965 break; 00966 00967 case T1_FIELD_LOCATION_BBOX: 00968 dummy_object = &face->type1.font_bbox; 00969 objects = &dummy_object; 00970 max_objects = 0; 00971 00972 if ( blend ) 00973 { 00974 objects = (void**)blend->bboxes; 00975 max_objects = blend->num_designs; 00976 } 00977 break; 00978 00979 case T1_FIELD_LOCATION_LOADER: 00980 dummy_object = loader; 00981 objects = &dummy_object; 00982 max_objects = 0; 00983 break; 00984 00985 case T1_FIELD_LOCATION_FACE: 00986 dummy_object = face; 00987 objects = &dummy_object; 00988 max_objects = 0; 00989 break; 00990 00991 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT 00992 case T1_FIELD_LOCATION_BLEND: 00993 dummy_object = face->blend; 00994 objects = &dummy_object; 00995 max_objects = 0; 00996 break; 00997 #endif 00998 00999 default: 01000 dummy_object = &face->type1; 01001 objects = &dummy_object; 01002 max_objects = 0; 01003 } 01004 01005 if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || 01006 field->type == T1_FIELD_TYPE_FIXED_ARRAY ) 01007 error = T1_Load_Field_Table( &loader->parser, field, 01008 objects, max_objects, 0 ); 01009 else 01010 error = T1_Load_Field( &loader->parser, field, 01011 objects, max_objects, 0 ); 01012 01013 Exit: 01014 return error; 01015 } 01016 01017 01018 static void 01019 parse_private( T1_Face face, 01020 T1_Loader loader ) 01021 { 01022 FT_UNUSED( face ); 01023 01024 loader->keywords_encountered |= T1_PRIVATE; 01025 } 01026 01027 01028 static int 01029 read_binary_data( T1_Parser parser, 01030 FT_Long* size, 01031 FT_Byte** base ) 01032 { 01033 FT_Byte* cur; 01034 FT_Byte* limit = parser->root.limit; 01035 01036 01037 /* the binary data has one of the following formats */ 01038 /* */ 01039 /* `size' [white*] RD white ....... ND */ 01040 /* `size' [white*] -| white ....... |- */ 01041 /* */ 01042 01043 T1_Skip_Spaces( parser ); 01044 01045 cur = parser->root.cursor; 01046 01047 if ( cur < limit && ft_isdigit( *cur ) ) 01048 { 01049 FT_Long s = T1_ToInt( parser ); 01050 01051 01052 T1_Skip_PS_Token( parser ); /* `RD' or `-|' or something else */ 01053 01054 /* there is only one whitespace char after the */ 01055 /* `RD' or `-|' token */ 01056 *base = parser->root.cursor + 1; 01057 01058 if ( s >= 0 && s < limit - *base ) 01059 { 01060 parser->root.cursor += s + 1; 01061 *size = s; 01062 return !parser->root.error; 01063 } 01064 } 01065 01066 FT_ERROR(( "read_binary_data: invalid size field\n" )); 01067 parser->root.error = T1_Err_Invalid_File_Format; 01068 return 0; 01069 } 01070 01071 01072 /* We now define the routines to handle the `/Encoding', `/Subrs', */ 01073 /* and `/CharStrings' dictionaries. */ 01074 01075 static void 01076 parse_font_matrix( T1_Face face, 01077 T1_Loader loader ) 01078 { 01079 T1_Parser parser = &loader->parser; 01080 FT_Matrix* matrix = &face->type1.font_matrix; 01081 FT_Vector* offset = &face->type1.font_offset; 01082 FT_Face root = (FT_Face)&face->root; 01083 FT_Fixed temp[6]; 01084 FT_Fixed temp_scale; 01085 FT_Int result; 01086 01087 01088 result = T1_ToFixedArray( parser, 6, temp, 3 ); 01089 01090 if ( result < 0 ) 01091 { 01092 parser->root.error = T1_Err_Invalid_File_Format; 01093 return; 01094 } 01095 01096 temp_scale = FT_ABS( temp[3] ); 01097 01098 if ( temp_scale == 0 ) 01099 { 01100 FT_ERROR(( "parse_font_matrix: invalid font matrix\n" )); 01101 parser->root.error = T1_Err_Invalid_File_Format; 01102 return; 01103 } 01104 01105 /* Set Units per EM based on FontMatrix values. We set the value to */ 01106 /* 1000 / temp_scale, because temp_scale was already multiplied by */ 01107 /* 1000 (in t1_tofixed, from psobjs.c). */ 01108 01109 root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L, 01110 temp_scale ) >> 16 ); 01111 01112 /* we need to scale the values by 1.0/temp_scale */ 01113 if ( temp_scale != 0x10000L ) 01114 { 01115 temp[0] = FT_DivFix( temp[0], temp_scale ); 01116 temp[1] = FT_DivFix( temp[1], temp_scale ); 01117 temp[2] = FT_DivFix( temp[2], temp_scale ); 01118 temp[4] = FT_DivFix( temp[4], temp_scale ); 01119 temp[5] = FT_DivFix( temp[5], temp_scale ); 01120 temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; 01121 } 01122 01123 matrix->xx = temp[0]; 01124 matrix->yx = temp[1]; 01125 matrix->xy = temp[2]; 01126 matrix->yy = temp[3]; 01127 01128 /* note that the offsets must be expressed in integer font units */ 01129 offset->x = temp[4] >> 16; 01130 offset->y = temp[5] >> 16; 01131 } 01132 01133 01134 static void 01135 parse_encoding( T1_Face face, 01136 T1_Loader loader ) 01137 { 01138 T1_Parser parser = &loader->parser; 01139 FT_Byte* cur; 01140 FT_Byte* limit = parser->root.limit; 01141 01142 PSAux_Service psaux = (PSAux_Service)face->psaux; 01143 01144 01145 T1_Skip_Spaces( parser ); 01146 cur = parser->root.cursor; 01147 if ( cur >= limit ) 01148 { 01149 FT_ERROR(( "parse_encoding: out of bounds\n" )); 01150 parser->root.error = T1_Err_Invalid_File_Format; 01151 return; 01152 } 01153 01154 /* if we have a number or `[', the encoding is an array, */ 01155 /* and we must load it now */ 01156 if ( ft_isdigit( *cur ) || *cur == '[' ) 01157 { 01158 T1_Encoding encode = &face->type1.encoding; 01159 FT_Int count, n; 01160 PS_Table char_table = &loader->encoding_table; 01161 FT_Memory memory = parser->root.memory; 01162 FT_Error error; 01163 FT_Bool only_immediates = 0; 01164 01165 01166 /* read the number of entries in the encoding; should be 256 */ 01167 if ( *cur == '[' ) 01168 { 01169 count = 256; 01170 only_immediates = 1; 01171 parser->root.cursor++; 01172 } 01173 else 01174 count = (FT_Int)T1_ToInt( parser ); 01175 01176 T1_Skip_Spaces( parser ); 01177 if ( parser->root.cursor >= limit ) 01178 return; 01179 01180 /* we use a T1_Table to store our charnames */ 01181 loader->num_chars = encode->num_chars = count; 01182 if ( FT_NEW_ARRAY( encode->char_index, count ) || 01183 FT_NEW_ARRAY( encode->char_name, count ) || 01184 FT_SET_ERROR( psaux->ps_table_funcs->init( 01185 char_table, count, memory ) ) ) 01186 { 01187 parser->root.error = error; 01188 return; 01189 } 01190 01191 /* We need to `zero' out encoding_table.elements */ 01192 for ( n = 0; n < count; n++ ) 01193 { 01194 char* notdef = (char *)".notdef"; 01195 01196 01197 T1_Add_Table( char_table, n, notdef, 8 ); 01198 } 01199 01200 /* Now we need to read records of the form */ 01201 /* */ 01202 /* ... charcode /charname ... */ 01203 /* */ 01204 /* for each entry in our table. */ 01205 /* */ 01206 /* We simply look for a number followed by an immediate */ 01207 /* name. Note that this ignores correctly the sequence */ 01208 /* that is often seen in type1 fonts: */ 01209 /* */ 01210 /* 0 1 255 { 1 index exch /.notdef put } for dup */ 01211 /* */ 01212 /* used to clean the encoding array before anything else. */ 01213 /* */ 01214 /* Alternatively, if the array is directly given as */ 01215 /* */ 01216 /* /Encoding [ ... ] */ 01217 /* */ 01218 /* we only read immediates. */ 01219 01220 n = 0; 01221 T1_Skip_Spaces( parser ); 01222 01223 while ( parser->root.cursor < limit ) 01224 { 01225 cur = parser->root.cursor; 01226 01227 /* we stop when we encounter a `def' or `]' */ 01228 if ( *cur == 'd' && cur + 3 < limit ) 01229 { 01230 if ( cur[1] == 'e' && 01231 cur[2] == 'f' && 01232 IS_PS_DELIM( cur[3] ) ) 01233 { 01234 FT_TRACE6(( "encoding end\n" )); 01235 cur += 3; 01236 break; 01237 } 01238 } 01239 if ( *cur == ']' ) 01240 { 01241 FT_TRACE6(( "encoding end\n" )); 01242 cur++; 01243 break; 01244 } 01245 01246 /* check whether we've found an entry */ 01247 if ( ft_isdigit( *cur ) || only_immediates ) 01248 { 01249 FT_Int charcode; 01250 01251 01252 if ( only_immediates ) 01253 charcode = n; 01254 else 01255 { 01256 charcode = (FT_Int)T1_ToInt( parser ); 01257 T1_Skip_Spaces( parser ); 01258 } 01259 01260 cur = parser->root.cursor; 01261 01262 if ( *cur == '/' && cur + 2 < limit && n < count ) 01263 { 01264 FT_PtrDist len; 01265 01266 01267 cur++; 01268 01269 parser->root.cursor = cur; 01270 T1_Skip_PS_Token( parser ); 01271 if ( parser->root.error ) 01272 return; 01273 01274 len = parser->root.cursor - cur; 01275 01276 parser->root.error = T1_Add_Table( char_table, charcode, 01277 cur, len + 1 ); 01278 if ( parser->root.error ) 01279 return; 01280 char_table->elements[charcode][len] = '\0'; 01281 01282 n++; 01283 } 01284 else if ( only_immediates ) 01285 { 01286 /* Since the current position is not updated for */ 01287 /* immediates-only mode we would get an infinite loop if */ 01288 /* we don't do anything here. */ 01289 /* */ 01290 /* This encoding array is not valid according to the type1 */ 01291 /* specification (it might be an encoding for a CID type1 */ 01292 /* font, however), so we conclude that this font is NOT a */ 01293 /* type1 font. */ 01294 parser->root.error = FT_Err_Unknown_File_Format; 01295 return; 01296 } 01297 } 01298 else 01299 { 01300 T1_Skip_PS_Token( parser ); 01301 if ( parser->root.error ) 01302 return; 01303 } 01304 01305 T1_Skip_Spaces( parser ); 01306 } 01307 01308 face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; 01309 parser->root.cursor = cur; 01310 } 01311 01312 /* Otherwise, we should have either `StandardEncoding', */ 01313 /* `ExpertEncoding', or `ISOLatin1Encoding' */ 01314 else 01315 { 01316 if ( cur + 17 < limit && 01317 ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) 01318 face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; 01319 01320 else if ( cur + 15 < limit && 01321 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) 01322 face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; 01323 01324 else if ( cur + 18 < limit && 01325 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) 01326 face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; 01327 01328 else 01329 parser->root.error = T1_Err_Ignore; 01330 } 01331 } 01332 01333 01334 static void 01335 parse_subrs( T1_Face face, 01336 T1_Loader loader ) 01337 { 01338 T1_Parser parser = &loader->parser; 01339 PS_Table table = &loader->subrs; 01340 FT_Memory memory = parser->root.memory; 01341 FT_Error error; 01342 FT_Int num_subrs; 01343 01344 PSAux_Service psaux = (PSAux_Service)face->psaux; 01345 01346 01347 T1_Skip_Spaces( parser ); 01348 01349 /* test for empty array */ 01350 if ( parser->root.cursor < parser->root.limit && 01351 *parser->root.cursor == '[' ) 01352 { 01353 T1_Skip_PS_Token( parser ); 01354 T1_Skip_Spaces ( parser ); 01355 if ( parser->root.cursor >= parser->root.limit || 01356 *parser->root.cursor != ']' ) 01357 parser->root.error = T1_Err_Invalid_File_Format; 01358 return; 01359 } 01360 01361 num_subrs = (FT_Int)T1_ToInt( parser ); 01362 01363 /* position the parser right before the `dup' of the first subr */ 01364 T1_Skip_PS_Token( parser ); /* `array' */ 01365 if ( parser->root.error ) 01366 return; 01367 T1_Skip_Spaces( parser ); 01368 01369 /* initialize subrs array -- with synthetic fonts it is possible */ 01370 /* we get here twice */ 01371 if ( !loader->num_subrs ) 01372 { 01373 error = psaux->ps_table_funcs->init( table, num_subrs, memory ); 01374 if ( error ) 01375 goto Fail; 01376 } 01377 01378 /* the format is simple: */ 01379 /* */ 01380 /* `index' + binary data */ 01381 /* */ 01382 for (;;) 01383 { 01384 FT_Long idx, size; 01385 FT_Byte* base; 01386 01387 01388 /* If the next token isn't `dup' we are done. */ 01389 if ( ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 ) 01390 break; 01391 01392 T1_Skip_PS_Token( parser ); /* `dup' */ 01393 01394 idx = T1_ToInt( parser ); 01395 01396 if ( !read_binary_data( parser, &size, &base ) ) 01397 return; 01398 01399 /* The binary string is followed by one token, e.g. `NP' */ 01400 /* (bound to `noaccess put') or by two separate tokens: */ 01401 /* `noaccess' & `put'. We position the parser right */ 01402 /* before the next `dup', if any. */ 01403 T1_Skip_PS_Token( parser ); /* `NP' or `|' or `noaccess' */ 01404 if ( parser->root.error ) 01405 return; 01406 T1_Skip_Spaces ( parser ); 01407 01408 if ( ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 ) 01409 { 01410 T1_Skip_PS_Token( parser ); /* skip `put' */ 01411 T1_Skip_Spaces ( parser ); 01412 } 01413 01414 /* with synthetic fonts it is possible we get here twice */ 01415 if ( loader->num_subrs ) 01416 continue; 01417 01418 /* some fonts use a value of -1 for lenIV to indicate that */ 01419 /* the charstrings are unencoded */ 01420 /* */ 01421 /* thanks to Tom Kacvinsky for pointing this out */ 01422 /* */ 01423 if ( face->type1.private_dict.lenIV >= 0 ) 01424 { 01425 FT_Byte* temp; 01426 01427 01428 /* some fonts define empty subr records -- this is not totally */ 01429 /* compliant to the specification (which says they should at */ 01430 /* least contain a `return'), but we support them anyway */ 01431 if ( size < face->type1.private_dict.lenIV ) 01432 { 01433 error = T1_Err_Invalid_File_Format; 01434 goto Fail; 01435 } 01436 01437 /* t1_decrypt() shouldn't write to base -- make temporary copy */ 01438 if ( FT_ALLOC( temp, size ) ) 01439 goto Fail; 01440 FT_MEM_COPY( temp, base, size ); 01441 psaux->t1_decrypt( temp, size, 4330 ); 01442 size -= face->type1.private_dict.lenIV; 01443 error = T1_Add_Table( table, (FT_Int)idx, 01444 temp + face->type1.private_dict.lenIV, size ); 01445 FT_FREE( temp ); 01446 } 01447 else 01448 error = T1_Add_Table( table, (FT_Int)idx, base, size ); 01449 if ( error ) 01450 goto Fail; 01451 } 01452 01453 if ( !loader->num_subrs ) 01454 loader->num_subrs = num_subrs; 01455 01456 return; 01457 01458 Fail: 01459 parser->root.error = error; 01460 } 01461 01462 01463 #define TABLE_EXTEND 5 01464 01465 01466 static void 01467 parse_charstrings( T1_Face face, 01468 T1_Loader loader ) 01469 { 01470 T1_Parser parser = &loader->parser; 01471 PS_Table code_table = &loader->charstrings; 01472 PS_Table name_table = &loader->glyph_names; 01473 PS_Table swap_table = &loader->swap_table; 01474 FT_Memory memory = parser->root.memory; 01475 FT_Error error; 01476 01477 PSAux_Service psaux = (PSAux_Service)face->psaux; 01478 01479 FT_Byte* cur; 01480 FT_Byte* limit = parser->root.limit; 01481 FT_Int n, num_glyphs; 01482 FT_UInt notdef_index = 0; 01483 FT_Byte notdef_found = 0; 01484 01485 01486 num_glyphs = (FT_Int)T1_ToInt( parser ); 01487 /* some fonts like Optima-Oblique not only define the /CharStrings */ 01488 /* array but access it also */ 01489 if ( num_glyphs == 0 || parser->root.error ) 01490 return; 01491 01492 /* initialize tables, leaving space for addition of .notdef, */ 01493 /* if necessary, and a few other glyphs to handle buggy */ 01494 /* fonts which have more glyphs than specified. */ 01495 01496 /* for some non-standard fonts like `Optima' which provides */ 01497 /* different outlines depending on the resolution it is */ 01498 /* possible to get here twice */ 01499 if ( !loader->num_glyphs ) 01500 { 01501 error = psaux->ps_table_funcs->init( 01502 code_table, num_glyphs + 1 + TABLE_EXTEND, memory ); 01503 if ( error ) 01504 goto Fail; 01505 01506 error = psaux->ps_table_funcs->init( 01507 name_table, num_glyphs + 1 + TABLE_EXTEND, memory ); 01508 if ( error ) 01509 goto Fail; 01510 01511 /* Initialize table for swapping index notdef_index and */ 01512 /* index 0 names and codes (if necessary). */ 01513 01514 error = psaux->ps_table_funcs->init( swap_table, 4, memory ); 01515 if ( error ) 01516 goto Fail; 01517 } 01518 01519 n = 0; 01520 01521 for (;;) 01522 { 01523 FT_Long size; 01524 FT_Byte* base; 01525 01526 01527 /* the format is simple: */ 01528 /* `/glyphname' + binary data */ 01529 01530 T1_Skip_Spaces( parser ); 01531 01532 cur = parser->root.cursor; 01533 if ( cur >= limit ) 01534 break; 01535 01536 /* we stop when we find a `def' or `end' keyword */ 01537 if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) ) 01538 { 01539 if ( cur[0] == 'd' && 01540 cur[1] == 'e' && 01541 cur[2] == 'f' ) 01542 { 01543 /* There are fonts which have this: */ 01544 /* */ 01545 /* /CharStrings 118 dict def */ 01546 /* Private begin */ 01547 /* CharStrings begin */ 01548 /* ... */ 01549 /* */ 01550 /* To catch this we ignore `def' if */ 01551 /* no charstring has actually been */ 01552 /* seen. */ 01553 if ( n ) 01554 break; 01555 } 01556 01557 if ( cur[0] == 'e' && 01558 cur[1] == 'n' && 01559 cur[2] == 'd' ) 01560 break; 01561 } 01562 01563 T1_Skip_PS_Token( parser ); 01564 if ( parser->root.error ) 01565 return; 01566 01567 if ( *cur == '/' ) 01568 { 01569 FT_PtrDist len; 01570 01571 01572 if ( cur + 1 >= limit ) 01573 { 01574 error = T1_Err_Invalid_File_Format; 01575 goto Fail; 01576 } 01577 01578 cur++; /* skip `/' */ 01579 len = parser->root.cursor - cur; 01580 01581 if ( !read_binary_data( parser, &size, &base ) ) 01582 return; 01583 01584 /* for some non-standard fonts like `Optima' which provides */ 01585 /* different outlines depending on the resolution it is */ 01586 /* possible to get here twice */ 01587 if ( loader->num_glyphs ) 01588 continue; 01589 01590 error = T1_Add_Table( name_table, n, cur, len + 1 ); 01591 if ( error ) 01592 goto Fail; 01593 01594 /* add a trailing zero to the name table */ 01595 name_table->elements[n][len] = '\0'; 01596 01597 /* record index of /.notdef */ 01598 if ( *cur == '.' && 01599 ft_strcmp( ".notdef", 01600 (const char*)(name_table->elements[n]) ) == 0 ) 01601 { 01602 notdef_index = n; 01603 notdef_found = 1; 01604 } 01605 01606 if ( face->type1.private_dict.lenIV >= 0 && 01607 n < num_glyphs + TABLE_EXTEND ) 01608 { 01609 FT_Byte* temp; 01610 01611 01612 if ( size <= face->type1.private_dict.lenIV ) 01613 { 01614 error = T1_Err_Invalid_File_Format; 01615 goto Fail; 01616 } 01617 01618 /* t1_decrypt() shouldn't write to base -- make temporary copy */ 01619 if ( FT_ALLOC( temp, size ) ) 01620 goto Fail; 01621 FT_MEM_COPY( temp, base, size ); 01622 psaux->t1_decrypt( temp, size, 4330 ); 01623 size -= face->type1.private_dict.lenIV; 01624 error = T1_Add_Table( code_table, n, 01625 temp + face->type1.private_dict.lenIV, size ); 01626 FT_FREE( temp ); 01627 } 01628 else 01629 error = T1_Add_Table( code_table, n, base, size ); 01630 if ( error ) 01631 goto Fail; 01632 01633 n++; 01634 } 01635 } 01636 01637 loader->num_glyphs = n; 01638 01639 /* if /.notdef is found but does not occupy index 0, do our magic. */ 01640 if ( notdef_found && 01641 ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) ) 01642 { 01643 /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ 01644 /* name and code entries to swap_table. Then place notdef_index */ 01645 /* name and code entries into swap_table. Then swap name and code */ 01646 /* entries at indices notdef_index and 0 using values stored in */ 01647 /* swap_table. */ 01648 01649 /* Index 0 name */ 01650 error = T1_Add_Table( swap_table, 0, 01651 name_table->elements[0], 01652 name_table->lengths [0] ); 01653 if ( error ) 01654 goto Fail; 01655 01656 /* Index 0 code */ 01657 error = T1_Add_Table( swap_table, 1, 01658 code_table->elements[0], 01659 code_table->lengths [0] ); 01660 if ( error ) 01661 goto Fail; 01662 01663 /* Index notdef_index name */ 01664 error = T1_Add_Table( swap_table, 2, 01665 name_table->elements[notdef_index], 01666 name_table->lengths [notdef_index] ); 01667 if ( error ) 01668 goto Fail; 01669 01670 /* Index notdef_index code */ 01671 error = T1_Add_Table( swap_table, 3, 01672 code_table->elements[notdef_index], 01673 code_table->lengths [notdef_index] ); 01674 if ( error ) 01675 goto Fail; 01676 01677 error = T1_Add_Table( name_table, notdef_index, 01678 swap_table->elements[0], 01679 swap_table->lengths [0] ); 01680 if ( error ) 01681 goto Fail; 01682 01683 error = T1_Add_Table( code_table, notdef_index, 01684 swap_table->elements[1], 01685 swap_table->lengths [1] ); 01686 if ( error ) 01687 goto Fail; 01688 01689 error = T1_Add_Table( name_table, 0, 01690 swap_table->elements[2], 01691 swap_table->lengths [2] ); 01692 if ( error ) 01693 goto Fail; 01694 01695 error = T1_Add_Table( code_table, 0, 01696 swap_table->elements[3], 01697 swap_table->lengths [3] ); 01698 if ( error ) 01699 goto Fail; 01700 01701 } 01702 else if ( !notdef_found ) 01703 { 01704 /* notdef_index is already 0, or /.notdef is undefined in */ 01705 /* charstrings dictionary. Worry about /.notdef undefined. */ 01706 /* We take index 0 and add it to the end of the table(s) */ 01707 /* and add our own /.notdef glyph to index 0. */ 01708 01709 /* 0 333 hsbw endchar */ 01710 FT_Byte notdef_glyph[] = { 0x8B, 0xF7, 0xE1, 0x0D, 0x0E }; 01711 char* notdef_name = (char *)".notdef"; 01712 01713 01714 error = T1_Add_Table( swap_table, 0, 01715 name_table->elements[0], 01716 name_table->lengths [0] ); 01717 if ( error ) 01718 goto Fail; 01719 01720 error = T1_Add_Table( swap_table, 1, 01721 code_table->elements[0], 01722 code_table->lengths [0] ); 01723 if ( error ) 01724 goto Fail; 01725 01726 error = T1_Add_Table( name_table, 0, notdef_name, 8 ); 01727 if ( error ) 01728 goto Fail; 01729 01730 error = T1_Add_Table( code_table, 0, notdef_glyph, 5 ); 01731 01732 if ( error ) 01733 goto Fail; 01734 01735 error = T1_Add_Table( name_table, n, 01736 swap_table->elements[0], 01737 swap_table->lengths [0] ); 01738 if ( error ) 01739 goto Fail; 01740 01741 error = T1_Add_Table( code_table, n, 01742 swap_table->elements[1], 01743 swap_table->lengths [1] ); 01744 if ( error ) 01745 goto Fail; 01746 01747 /* we added a glyph. */ 01748 loader->num_glyphs += 1; 01749 } 01750 01751 return; 01752 01753 Fail: 01754 parser->root.error = error; 01755 } 01756 01757 01758 /*************************************************************************/ 01759 /* */ 01760 /* Define the token field static variables. This is a set of */ 01761 /* T1_FieldRec variables. */ 01762 /* */ 01763 /*************************************************************************/ 01764 01765 01766 static 01767 const T1_FieldRec t1_keywords[] = 01768 { 01769 01770 #include "t1tokens.h" 01771 01772 /* now add the special functions... */ 01773 T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix, 01774 T1_FIELD_DICT_FONTDICT ) 01775 T1_FIELD_CALLBACK( "Encoding", parse_encoding, 01776 T1_FIELD_DICT_FONTDICT ) 01777 T1_FIELD_CALLBACK( "Subrs", parse_subrs, 01778 T1_FIELD_DICT_PRIVATE ) 01779 T1_FIELD_CALLBACK( "CharStrings", parse_charstrings, 01780 T1_FIELD_DICT_PRIVATE ) 01781 T1_FIELD_CALLBACK( "Private", parse_private, 01782 T1_FIELD_DICT_FONTDICT ) 01783 01784 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT 01785 T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions, 01786 T1_FIELD_DICT_FONTDICT ) 01787 T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map, 01788 T1_FIELD_DICT_FONTDICT ) 01789 T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types, 01790 T1_FIELD_DICT_FONTDICT ) 01791 T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector, 01792 T1_FIELD_DICT_FONTDICT ) 01793 T1_FIELD_CALLBACK( "BuildCharArray", parse_buildchar, 01794 T1_FIELD_DICT_PRIVATE ) 01795 #endif 01796 01797 { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } 01798 }; 01799 01800 01801 #define T1_FIELD_COUNT \ 01802 ( sizeof ( t1_keywords ) / sizeof ( t1_keywords[0] ) ) 01803 01804 01805 static FT_Error 01806 parse_dict( T1_Face face, 01807 T1_Loader loader, 01808 FT_Byte* base, 01809 FT_Long size ) 01810 { 01811 T1_Parser parser = &loader->parser; 01812 FT_Byte *limit, *start_binary = NULL; 01813 FT_Bool have_integer = 0; 01814 01815 01816 parser->root.cursor = base; 01817 parser->root.limit = base + size; 01818 parser->root.error = T1_Err_Ok; 01819 01820 limit = parser->root.limit; 01821 01822 T1_Skip_Spaces( parser ); 01823 01824 while ( parser->root.cursor < limit ) 01825 { 01826 FT_Byte* cur; 01827 01828 01829 cur = parser->root.cursor; 01830 01831 /* look for `eexec' */ 01832 if ( IS_PS_TOKEN( cur, limit, "eexec" ) ) 01833 break; 01834 01835 /* look for `closefile' which ends the eexec section */ 01836 else if ( IS_PS_TOKEN( cur, limit, "closefile" ) ) 01837 break; 01838 01839 /* in a synthetic font the base font starts after a */ 01840 /* `FontDictionary' token that is placed after a Private dict */ 01841 else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) ) 01842 { 01843 if ( loader->keywords_encountered & T1_PRIVATE ) 01844 loader->keywords_encountered |= 01845 T1_FONTDIR_AFTER_PRIVATE; 01846 parser->root.cursor += 13; 01847 } 01848 01849 /* check whether we have an integer */ 01850 else if ( ft_isdigit( *cur ) ) 01851 { 01852 start_binary = cur; 01853 T1_Skip_PS_Token( parser ); 01854 if ( parser->root.error ) 01855 goto Exit; 01856 have_integer = 1; 01857 } 01858 01859 /* in valid Type 1 fonts we don't see `RD' or `-|' directly */ 01860 /* since those tokens are handled by parse_subrs and */ 01861 /* parse_charstrings */ 01862 else if ( *cur == 'R' && cur + 6 < limit && *(cur + 1) == 'D' && 01863 have_integer ) 01864 { 01865 FT_Long s; 01866 FT_Byte* b; 01867 01868 01869 parser->root.cursor = start_binary; 01870 if ( !read_binary_data( parser, &s, &b ) ) 01871 return T1_Err_Invalid_File_Format; 01872 have_integer = 0; 01873 } 01874 01875 else if ( *cur == '-' && cur + 6 < limit && *(cur + 1) == '|' && 01876 have_integer ) 01877 { 01878 FT_Long s; 01879 FT_Byte* b; 01880 01881 01882 parser->root.cursor = start_binary; 01883 if ( !read_binary_data( parser, &s, &b ) ) 01884 return T1_Err_Invalid_File_Format; 01885 have_integer = 0; 01886 } 01887 01888 /* look for immediates */ 01889 else if ( *cur == '/' && cur + 2 < limit ) 01890 { 01891 FT_PtrDist len; 01892 01893 01894 cur++; 01895 01896 parser->root.cursor = cur; 01897 T1_Skip_PS_Token( parser ); 01898 if ( parser->root.error ) 01899 goto Exit; 01900 01901 len = parser->root.cursor - cur; 01902 01903 if ( len > 0 && len < 22 && parser->root.cursor < limit ) 01904 { 01905 /* now compare the immediate name to the keyword table */ 01906 T1_Field keyword = (T1_Field)t1_keywords; 01907 01908 01909 for (;;) 01910 { 01911 FT_Byte* name; 01912 01913 01914 name = (FT_Byte*)keyword->ident; 01915 if ( !name ) 01916 break; 01917 01918 if ( cur[0] == name[0] && 01919 len == (FT_PtrDist)ft_strlen( (const char *)name ) && 01920 ft_memcmp( cur, name, len ) == 0 ) 01921 { 01922 /* We found it -- run the parsing callback! */ 01923 /* We record every instance of every field */ 01924 /* (until we reach the base font of a */ 01925 /* synthetic font) to deal adequately with */ 01926 /* multiple master fonts; this is also */ 01927 /* necessary because later PostScript */ 01928 /* definitions override earlier ones. */ 01929 01930 /* Once we encounter `FontDirectory' after */ 01931 /* `/Private', we know that this is a synthetic */ 01932 /* font; except for `/CharStrings' we are not */ 01933 /* interested in anything that follows this */ 01934 /* `FontDirectory'. */ 01935 01936 /* MM fonts have more than one /Private token at */ 01937 /* the top level; let's hope that all the junk */ 01938 /* that follows the first /Private token is not */ 01939 /* interesting to us. */ 01940 01941 /* According to Adobe Tech Note #5175 (CID-Keyed */ 01942 /* Font Installation for ATM Software) a `begin' */ 01943 /* must be followed by exactly one `end', and */ 01944 /* `begin' -- `end' pairs must be accurately */ 01945 /* paired. We could use this to distinguish */ 01946 /* between the global Private and the Private */ 01947 /* dict that is a member of the Blend dict. */ 01948 01949 const FT_UInt dict = 01950 ( loader->keywords_encountered & T1_PRIVATE ) 01951 ? T1_FIELD_DICT_PRIVATE 01952 : T1_FIELD_DICT_FONTDICT; 01953 01954 if ( !( dict & keyword->dict ) ) 01955 { 01956 FT_TRACE1(( "parse_dict: found %s but ignoring it " 01957 "since it is in the wrong dictionary\n", 01958 keyword->ident )); 01959 break; 01960 } 01961 01962 if ( !( loader->keywords_encountered & 01963 T1_FONTDIR_AFTER_PRIVATE ) || 01964 ft_strcmp( (const char*)name, "CharStrings" ) == 0 ) 01965 { 01966 parser->root.error = t1_load_keyword( face, 01967 loader, 01968 keyword ); 01969 if ( parser->root.error != T1_Err_Ok ) 01970 { 01971 if ( FT_ERROR_BASE( parser->root.error ) == FT_Err_Ignore ) 01972 parser->root.error = T1_Err_Ok; 01973 else 01974 return parser->root.error; 01975 } 01976 } 01977 break; 01978 } 01979 01980 keyword++; 01981 } 01982 } 01983 01984 have_integer = 0; 01985 } 01986 else 01987 { 01988 T1_Skip_PS_Token( parser ); 01989 if ( parser->root.error ) 01990 goto Exit; 01991 have_integer = 0; 01992 } 01993 01994 T1_Skip_Spaces( parser ); 01995 } 01996 01997 Exit: 01998 return parser->root.error; 01999 } 02000 02001 02002 static void 02003 t1_init_loader( T1_Loader loader, 02004 T1_Face face ) 02005 { 02006 FT_UNUSED( face ); 02007 02008 FT_MEM_ZERO( loader, sizeof ( *loader ) ); 02009 loader->num_glyphs = 0; 02010 loader->num_chars = 0; 02011 02012 /* initialize the tables -- simply set their `init' field to 0 */ 02013 loader->encoding_table.init = 0; 02014 loader->charstrings.init = 0; 02015 loader->glyph_names.init = 0; 02016 loader->subrs.init = 0; 02017 loader->swap_table.init = 0; 02018 loader->fontdata = 0; 02019 loader->keywords_encountered = 0; 02020 } 02021 02022 02023 static void 02024 t1_done_loader( T1_Loader loader ) 02025 { 02026 T1_Parser parser = &loader->parser; 02027 02028 02029 /* finalize tables */ 02030 T1_Release_Table( &loader->encoding_table ); 02031 T1_Release_Table( &loader->charstrings ); 02032 T1_Release_Table( &loader->glyph_names ); 02033 T1_Release_Table( &loader->swap_table ); 02034 T1_Release_Table( &loader->subrs ); 02035 02036 /* finalize parser */ 02037 T1_Finalize_Parser( parser ); 02038 } 02039 02040 02041 FT_LOCAL_DEF( FT_Error ) 02042 T1_Open_Face( T1_Face face ) 02043 { 02044 T1_LoaderRec loader; 02045 T1_Parser parser; 02046 T1_Font type1 = &face->type1; 02047 PS_Private priv = &type1->private_dict; 02048 FT_Error error; 02049 02050 PSAux_Service psaux = (PSAux_Service)face->psaux; 02051 02052 02053 t1_init_loader( &loader, face ); 02054 02055 /* default values */ 02056 face->ndv_idx = -1; 02057 face->cdv_idx = -1; 02058 face->len_buildchar = 0; 02059 02060 priv->blue_shift = 7; 02061 priv->blue_fuzz = 1; 02062 priv->lenIV = 4; 02063 priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); 02064 priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); 02065 02066 parser = &loader.parser; 02067 error = T1_New_Parser( parser, 02068 face->root.stream, 02069 face->root.memory, 02070 psaux ); 02071 if ( error ) 02072 goto Exit; 02073 02074 error = parse_dict( face, &loader, 02075 parser->base_dict, parser->base_len ); 02076 if ( error ) 02077 goto Exit; 02078 02079 error = T1_Get_Private_Dict( parser, psaux ); 02080 if ( error ) 02081 goto Exit; 02082 02083 error = parse_dict( face, &loader, 02084 parser->private_dict, parser->private_len ); 02085 if ( error ) 02086 goto Exit; 02087 02088 /* ensure even-ness of `num_blue_values' */ 02089 priv->num_blue_values &= ~1; 02090 02091 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT 02092 02093 if ( face->blend && 02094 face->blend->num_default_design_vector != 0 && 02095 face->blend->num_default_design_vector != face->blend->num_axis ) 02096 { 02097 /* we don't use it currently so just warn, reset, and ignore */ 02098 FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries " 02099 "while there are %u axes.\n", 02100 face->blend->num_default_design_vector, 02101 face->blend->num_axis )); 02102 02103 face->blend->num_default_design_vector = 0; 02104 } 02105 02106 /* the following can happen for MM instances; we then treat the */ 02107 /* font as a normal PS font */ 02108 if ( face->blend && 02109 ( !face->blend->num_designs || !face->blend->num_axis ) ) 02110 T1_Done_Blend( face ); 02111 02112 /* another safety check */ 02113 if ( face->blend ) 02114 { 02115 FT_UInt i; 02116 02117 02118 for ( i = 0; i < face->blend->num_axis; i++ ) 02119 if ( !face->blend->design_map[i].num_points ) 02120 { 02121 T1_Done_Blend( face ); 02122 break; 02123 } 02124 } 02125 02126 if ( face->blend ) 02127 { 02128 if ( face->len_buildchar > 0 ) 02129 { 02130 FT_Memory memory = face->root.memory; 02131 02132 02133 if ( FT_NEW_ARRAY( face->buildchar, face->len_buildchar ) ) 02134 { 02135 FT_ERROR(( "T1_Open_Face: cannot allocate BuildCharArray\n" )); 02136 face->len_buildchar = 0; 02137 goto Exit; 02138 } 02139 } 02140 } 02141 02142 #endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */ 02143 02144 /* now, propagate the subrs, charstrings, and glyphnames tables */ 02145 /* to the Type1 data */ 02146 type1->num_glyphs = loader.num_glyphs; 02147 02148 if ( loader.subrs.init ) 02149 { 02150 loader.subrs.init = 0; 02151 type1->num_subrs = loader.num_subrs; 02152 type1->subrs_block = loader.subrs.block; 02153 type1->subrs = loader.subrs.elements; 02154 type1->subrs_len = loader.subrs.lengths; 02155 } 02156 02157 #ifdef FT_CONFIG_OPTION_INCREMENTAL 02158 if ( !face->root.internal->incremental_interface ) 02159 #endif 02160 if ( !loader.charstrings.init ) 02161 { 02162 FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face\n" )); 02163 error = T1_Err_Invalid_File_Format; 02164 } 02165 02166 loader.charstrings.init = 0; 02167 type1->charstrings_block = loader.charstrings.block; 02168 type1->charstrings = loader.charstrings.elements; 02169 type1->charstrings_len = loader.charstrings.lengths; 02170 02171 /* we copy the glyph names `block' and `elements' fields; */ 02172 /* the `lengths' field must be released later */ 02173 type1->glyph_names_block = loader.glyph_names.block; 02174 type1->glyph_names = (FT_String**)loader.glyph_names.elements; 02175 loader.glyph_names.block = 0; 02176 loader.glyph_names.elements = 0; 02177 02178 /* we must now build type1.encoding when we have a custom array */ 02179 if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) 02180 { 02181 FT_Int charcode, idx, min_char, max_char; 02182 FT_Byte* char_name; 02183 FT_Byte* glyph_name; 02184 02185 02186 /* OK, we do the following: for each element in the encoding */ 02187 /* table, look up the index of the glyph having the same name */ 02188 /* the index is then stored in type1.encoding.char_index, and */ 02189 /* the name to type1.encoding.char_name */ 02190 02191 min_char = 0; 02192 max_char = 0; 02193 02194 charcode = 0; 02195 for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) 02196 { 02197 type1->encoding.char_index[charcode] = 0; 02198 type1->encoding.char_name [charcode] = (char *)".notdef"; 02199 02200 char_name = loader.encoding_table.elements[charcode]; 02201 if ( char_name ) 02202 for ( idx = 0; idx < type1->num_glyphs; idx++ ) 02203 { 02204 glyph_name = (FT_Byte*)type1->glyph_names[idx]; 02205 if ( ft_strcmp( (const char*)char_name, 02206 (const char*)glyph_name ) == 0 ) 02207 { 02208 type1->encoding.char_index[charcode] = (FT_UShort)idx; 02209 type1->encoding.char_name [charcode] = (char*)glyph_name; 02210 02211 /* Change min/max encoded char only if glyph name is */ 02212 /* not /.notdef */ 02213 if ( ft_strcmp( (const char*)".notdef", 02214 (const char*)glyph_name ) != 0 ) 02215 { 02216 if ( charcode < min_char ) 02217 min_char = charcode; 02218 if ( charcode >= max_char ) 02219 max_char = charcode + 1; 02220 } 02221 break; 02222 } 02223 } 02224 } 02225 02226 type1->encoding.code_first = min_char; 02227 type1->encoding.code_last = max_char; 02228 type1->encoding.num_chars = loader.num_chars; 02229 } 02230 02231 Exit: 02232 t1_done_loader( &loader ); 02233 return error; 02234 } 02235 02236 02237 /* END */ Generated on Sat May 26 2012 04:32:59 for ReactOS by
1.7.6.1
|