Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenttgxvar.c
Go to the documentation of this file.
00001 /***************************************************************************/ 00002 /* */ 00003 /* ttgxvar.c */ 00004 /* */ 00005 /* TrueType GX Font Variation loader */ 00006 /* */ 00007 /* Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010 by */ 00008 /* David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. */ 00009 /* */ 00010 /* This file is part of the FreeType project, and may only be used, */ 00011 /* modified, and distributed under the terms of the FreeType project */ 00012 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 00013 /* this file you indicate that you have read the license and */ 00014 /* understand and accept it fully. */ 00015 /* */ 00016 /***************************************************************************/ 00017 00018 00019 /*************************************************************************/ 00020 /* */ 00021 /* Apple documents the `fvar', `gvar', `cvar', and `avar' tables at */ 00022 /* */ 00023 /* http://developer.apple.com/fonts/TTRefMan/RM06/Chap6[fgca]var.html */ 00024 /* */ 00025 /* The documentation for `fvar' is inconsistent. At one point it says */ 00026 /* that `countSizePairs' should be 3, at another point 2. It should */ 00027 /* be 2. */ 00028 /* */ 00029 /* The documentation for `gvar' is not intelligible; `cvar' refers you */ 00030 /* to `gvar' and is thus also incomprehensible. */ 00031 /* */ 00032 /* The documentation for `avar' appears correct, but Apple has no fonts */ 00033 /* with an `avar' table, so it is hard to test. */ 00034 /* */ 00035 /* Many thanks to John Jenkins (at Apple) in figuring this out. */ 00036 /* */ 00037 /* */ 00038 /* Apple's `kern' table has some references to tuple indices, but as */ 00039 /* there is no indication where these indices are defined, nor how to */ 00040 /* interpolate the kerning values (different tuples have different */ 00041 /* classes) this issue is ignored. */ 00042 /* */ 00043 /*************************************************************************/ 00044 00045 00046 #include <ft2build.h> 00047 #include FT_INTERNAL_DEBUG_H 00048 #include FT_CONFIG_CONFIG_H 00049 #include FT_INTERNAL_STREAM_H 00050 #include FT_INTERNAL_SFNT_H 00051 #include FT_TRUETYPE_TAGS_H 00052 #include FT_MULTIPLE_MASTERS_H 00053 00054 #include "ttpload.h" 00055 #include "ttgxvar.h" 00056 00057 #include "tterrors.h" 00058 00059 00060 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT 00061 00062 00063 #define FT_Stream_FTell( stream ) \ 00064 ( (stream)->cursor - (stream)->base ) 00065 #define FT_Stream_SeekSet( stream, off ) \ 00066 ( (stream)->cursor = (stream)->base+(off) ) 00067 00068 00069 /*************************************************************************/ 00070 /* */ 00071 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 00072 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 00073 /* messages during execution. */ 00074 /* */ 00075 #undef FT_COMPONENT 00076 #define FT_COMPONENT trace_ttgxvar 00077 00078 00079 /*************************************************************************/ 00080 /*************************************************************************/ 00081 /***** *****/ 00082 /***** Internal Routines *****/ 00083 /***** *****/ 00084 /*************************************************************************/ 00085 /*************************************************************************/ 00086 00087 00088 /*************************************************************************/ 00089 /* */ 00090 /* The macro ALL_POINTS is used in `ft_var_readpackedpoints'. It */ 00091 /* indicates that there is a delta for every point without needing to */ 00092 /* enumerate all of them. */ 00093 /* */ 00094 #define ALL_POINTS (FT_UShort*)( -1 ) 00095 00096 00097 #define GX_PT_POINTS_ARE_WORDS 0x80 00098 #define GX_PT_POINT_RUN_COUNT_MASK 0x7F 00099 00100 00101 /*************************************************************************/ 00102 /* */ 00103 /* <Function> */ 00104 /* ft_var_readpackedpoints */ 00105 /* */ 00106 /* <Description> */ 00107 /* Read a set of points to which the following deltas will apply. */ 00108 /* Points are packed with a run length encoding. */ 00109 /* */ 00110 /* <Input> */ 00111 /* stream :: The data stream. */ 00112 /* */ 00113 /* <Output> */ 00114 /* point_cnt :: The number of points read. A zero value means that */ 00115 /* all points in the glyph will be affected, without */ 00116 /* enumerating them individually. */ 00117 /* */ 00118 /* <Return> */ 00119 /* An array of FT_UShort containing the affected points or the */ 00120 /* special value ALL_POINTS. */ 00121 /* */ 00122 static FT_UShort* 00123 ft_var_readpackedpoints( FT_Stream stream, 00124 FT_UInt *point_cnt ) 00125 { 00126 FT_UShort *points; 00127 FT_Int n; 00128 FT_Int runcnt; 00129 FT_Int i; 00130 FT_Int j; 00131 FT_Int first; 00132 FT_Memory memory = stream->memory; 00133 FT_Error error = TT_Err_Ok; 00134 00135 FT_UNUSED( error ); 00136 00137 00138 *point_cnt = n = FT_GET_BYTE(); 00139 if ( n == 0 ) 00140 return ALL_POINTS; 00141 00142 if ( n & GX_PT_POINTS_ARE_WORDS ) 00143 n = FT_GET_BYTE() | ( ( n & GX_PT_POINT_RUN_COUNT_MASK ) << 8 ); 00144 00145 if ( FT_NEW_ARRAY( points, n ) ) 00146 return NULL; 00147 00148 i = 0; 00149 while ( i < n ) 00150 { 00151 runcnt = FT_GET_BYTE(); 00152 if ( runcnt & GX_PT_POINTS_ARE_WORDS ) 00153 { 00154 runcnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK; 00155 first = points[i++] = FT_GET_USHORT(); 00156 00157 if ( runcnt < 1 || i + runcnt >= n ) 00158 goto Exit; 00159 00160 /* first point not included in runcount */ 00161 for ( j = 0; j < runcnt; ++j ) 00162 points[i++] = (FT_UShort)( first += FT_GET_USHORT() ); 00163 } 00164 else 00165 { 00166 first = points[i++] = FT_GET_BYTE(); 00167 00168 if ( runcnt < 1 || i + runcnt >= n ) 00169 goto Exit; 00170 00171 for ( j = 0; j < runcnt; ++j ) 00172 points[i++] = (FT_UShort)( first += FT_GET_BYTE() ); 00173 } 00174 } 00175 00176 Exit: 00177 return points; 00178 } 00179 00180 00181 enum 00182 { 00183 GX_DT_DELTAS_ARE_ZERO = 0x80, 00184 GX_DT_DELTAS_ARE_WORDS = 0x40, 00185 GX_DT_DELTA_RUN_COUNT_MASK = 0x3F 00186 }; 00187 00188 00189 /*************************************************************************/ 00190 /* */ 00191 /* <Function> */ 00192 /* ft_var_readpackeddeltas */ 00193 /* */ 00194 /* <Description> */ 00195 /* Read a set of deltas. These are packed slightly differently than */ 00196 /* points. In particular there is no overall count. */ 00197 /* */ 00198 /* <Input> */ 00199 /* stream :: The data stream. */ 00200 /* */ 00201 /* delta_cnt :: The number of to be read. */ 00202 /* */ 00203 /* <Return> */ 00204 /* An array of FT_Short containing the deltas for the affected */ 00205 /* points. (This only gets the deltas for one dimension. It will */ 00206 /* generally be called twice, once for x, once for y. When used in */ 00207 /* cvt table, it will only be called once.) */ 00208 /* */ 00209 static FT_Short* 00210 ft_var_readpackeddeltas( FT_Stream stream, 00211 FT_Offset delta_cnt ) 00212 { 00213 FT_Short *deltas = NULL; 00214 FT_UInt runcnt; 00215 FT_Offset i; 00216 FT_UInt j; 00217 FT_Memory memory = stream->memory; 00218 FT_Error error = TT_Err_Ok; 00219 00220 FT_UNUSED( error ); 00221 00222 00223 if ( FT_NEW_ARRAY( deltas, delta_cnt ) ) 00224 return NULL; 00225 00226 i = 0; 00227 while ( i < delta_cnt ) 00228 { 00229 runcnt = FT_GET_BYTE(); 00230 if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) 00231 { 00232 /* runcnt zeroes get added */ 00233 for ( j = 0; 00234 j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; 00235 ++j ) 00236 deltas[i++] = 0; 00237 } 00238 else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) 00239 { 00240 /* runcnt shorts from the stack */ 00241 for ( j = 0; 00242 j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; 00243 ++j ) 00244 deltas[i++] = FT_GET_SHORT(); 00245 } 00246 else 00247 { 00248 /* runcnt signed bytes from the stack */ 00249 for ( j = 0; 00250 j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; 00251 ++j ) 00252 deltas[i++] = FT_GET_CHAR(); 00253 } 00254 00255 if ( j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) ) 00256 { 00257 /* Bad format */ 00258 FT_FREE( deltas ); 00259 return NULL; 00260 } 00261 } 00262 00263 return deltas; 00264 } 00265 00266 00267 /*************************************************************************/ 00268 /* */ 00269 /* <Function> */ 00270 /* ft_var_load_avar */ 00271 /* */ 00272 /* <Description> */ 00273 /* Parse the `avar' table if present. It need not be, so we return */ 00274 /* nothing. */ 00275 /* */ 00276 /* <InOut> */ 00277 /* face :: The font face. */ 00278 /* */ 00279 static void 00280 ft_var_load_avar( TT_Face face ) 00281 { 00282 FT_Stream stream = FT_FACE_STREAM(face); 00283 FT_Memory memory = stream->memory; 00284 GX_Blend blend = face->blend; 00285 GX_AVarSegment segment; 00286 FT_Error error = TT_Err_Ok; 00287 FT_ULong version; 00288 FT_Long axisCount; 00289 FT_Int i, j; 00290 FT_ULong table_len; 00291 00292 FT_UNUSED( error ); 00293 00294 00295 blend->avar_checked = TRUE; 00296 if ( (error = face->goto_table( face, TTAG_avar, stream, &table_len )) != 0 ) 00297 return; 00298 00299 if ( FT_FRAME_ENTER( table_len ) ) 00300 return; 00301 00302 version = FT_GET_LONG(); 00303 axisCount = FT_GET_LONG(); 00304 00305 if ( version != 0x00010000L || 00306 axisCount != (FT_Long)blend->mmvar->num_axis ) 00307 goto Exit; 00308 00309 if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) ) 00310 goto Exit; 00311 00312 segment = &blend->avar_segment[0]; 00313 for ( i = 0; i < axisCount; ++i, ++segment ) 00314 { 00315 segment->pairCount = FT_GET_USHORT(); 00316 if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) ) 00317 { 00318 /* Failure. Free everything we have done so far. We must do */ 00319 /* it right now since loading the `avar' table is optional. */ 00320 00321 for ( j = i - 1; j >= 0; --j ) 00322 FT_FREE( blend->avar_segment[j].correspondence ); 00323 00324 FT_FREE( blend->avar_segment ); 00325 blend->avar_segment = NULL; 00326 goto Exit; 00327 } 00328 00329 for ( j = 0; j < segment->pairCount; ++j ) 00330 { 00331 segment->correspondence[j].fromCoord = 00332 FT_GET_SHORT() << 2; /* convert to Fixed */ 00333 segment->correspondence[j].toCoord = 00334 FT_GET_SHORT()<<2; /* convert to Fixed */ 00335 } 00336 } 00337 00338 Exit: 00339 FT_FRAME_EXIT(); 00340 } 00341 00342 00343 typedef struct GX_GVar_Head_ 00344 { 00345 FT_Long version; 00346 FT_UShort axisCount; 00347 FT_UShort globalCoordCount; 00348 FT_ULong offsetToCoord; 00349 FT_UShort glyphCount; 00350 FT_UShort flags; 00351 FT_ULong offsetToData; 00352 00353 } GX_GVar_Head; 00354 00355 00356 /*************************************************************************/ 00357 /* */ 00358 /* <Function> */ 00359 /* ft_var_load_gvar */ 00360 /* */ 00361 /* <Description> */ 00362 /* Parses the `gvar' table if present. If `fvar' is there, `gvar' */ 00363 /* had better be there too. */ 00364 /* */ 00365 /* <InOut> */ 00366 /* face :: The font face. */ 00367 /* */ 00368 /* <Return> */ 00369 /* FreeType error code. 0 means success. */ 00370 /* */ 00371 static FT_Error 00372 ft_var_load_gvar( TT_Face face ) 00373 { 00374 FT_Stream stream = FT_FACE_STREAM(face); 00375 FT_Memory memory = stream->memory; 00376 GX_Blend blend = face->blend; 00377 FT_Error error; 00378 FT_UInt i, j; 00379 FT_ULong table_len; 00380 FT_ULong gvar_start; 00381 FT_ULong offsetToData; 00382 GX_GVar_Head gvar_head; 00383 00384 static const FT_Frame_Field gvar_fields[] = 00385 { 00386 00387 #undef FT_STRUCTURE 00388 #define FT_STRUCTURE GX_GVar_Head 00389 00390 FT_FRAME_START( 20 ), 00391 FT_FRAME_LONG ( version ), 00392 FT_FRAME_USHORT( axisCount ), 00393 FT_FRAME_USHORT( globalCoordCount ), 00394 FT_FRAME_ULONG ( offsetToCoord ), 00395 FT_FRAME_USHORT( glyphCount ), 00396 FT_FRAME_USHORT( flags ), 00397 FT_FRAME_ULONG ( offsetToData ), 00398 FT_FRAME_END 00399 }; 00400 00401 if ( (error = face->goto_table( face, TTAG_gvar, stream, &table_len )) != 0 ) 00402 goto Exit; 00403 00404 gvar_start = FT_STREAM_POS( ); 00405 if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) ) 00406 goto Exit; 00407 00408 blend->tuplecount = gvar_head.globalCoordCount; 00409 blend->gv_glyphcnt = gvar_head.glyphCount; 00410 offsetToData = gvar_start + gvar_head.offsetToData; 00411 00412 if ( gvar_head.version != (FT_Long)0x00010000L || 00413 gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) 00414 { 00415 error = TT_Err_Invalid_Table; 00416 goto Exit; 00417 } 00418 00419 if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) ) 00420 goto Exit; 00421 00422 if ( gvar_head.flags & 1 ) 00423 { 00424 /* long offsets (one more offset than glyphs, to mark size of last) */ 00425 if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) ) 00426 goto Exit; 00427 00428 for ( i = 0; i <= blend->gv_glyphcnt; ++i ) 00429 blend->glyphoffsets[i] = offsetToData + FT_GET_LONG(); 00430 00431 FT_FRAME_EXIT(); 00432 } 00433 else 00434 { 00435 /* short offsets (one more offset than glyphs, to mark size of last) */ 00436 if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) ) 00437 goto Exit; 00438 00439 for ( i = 0; i <= blend->gv_glyphcnt; ++i ) 00440 blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2; 00441 /* XXX: Undocumented: `*2'! */ 00442 00443 FT_FRAME_EXIT(); 00444 } 00445 00446 if ( blend->tuplecount != 0 ) 00447 { 00448 if ( FT_NEW_ARRAY( blend->tuplecoords, 00449 gvar_head.axisCount * blend->tuplecount ) ) 00450 goto Exit; 00451 00452 if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) || 00453 FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) ) 00454 goto Exit; 00455 00456 for ( i = 0; i < blend->tuplecount; ++i ) 00457 for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; ++j ) 00458 blend->tuplecoords[i * gvar_head.axisCount + j] = 00459 FT_GET_SHORT() << 2; /* convert to FT_Fixed */ 00460 00461 FT_FRAME_EXIT(); 00462 } 00463 00464 Exit: 00465 return error; 00466 } 00467 00468 00469 /*************************************************************************/ 00470 /* */ 00471 /* <Function> */ 00472 /* ft_var_apply_tuple */ 00473 /* */ 00474 /* <Description> */ 00475 /* Figure out whether a given tuple (design) applies to the current */ 00476 /* blend, and if so, what is the scaling factor. */ 00477 /* */ 00478 /* <Input> */ 00479 /* blend :: The current blend of the font. */ 00480 /* */ 00481 /* tupleIndex :: A flag saying whether this is an intermediate */ 00482 /* tuple or not. */ 00483 /* */ 00484 /* tuple_coords :: The coordinates of the tuple in normalized axis */ 00485 /* units. */ 00486 /* */ 00487 /* im_start_coords :: The initial coordinates where this tuple starts */ 00488 /* to apply (for intermediate coordinates). */ 00489 /* */ 00490 /* im_end_coords :: The final coordinates after which this tuple no */ 00491 /* longer applies (for intermediate coordinates). */ 00492 /* */ 00493 /* <Return> */ 00494 /* An FT_Fixed value containing the scaling factor. */ 00495 /* */ 00496 static FT_Fixed 00497 ft_var_apply_tuple( GX_Blend blend, 00498 FT_UShort tupleIndex, 00499 FT_Fixed* tuple_coords, 00500 FT_Fixed* im_start_coords, 00501 FT_Fixed* im_end_coords ) 00502 { 00503 FT_UInt i; 00504 FT_Fixed apply; 00505 FT_Fixed temp; 00506 00507 00508 apply = 0x10000L; 00509 for ( i = 0; i < blend->num_axis; ++i ) 00510 { 00511 if ( tuple_coords[i] == 0 ) 00512 /* It's not clear why (for intermediate tuples) we don't need */ 00513 /* to check against start/end -- the documentation says we don't. */ 00514 /* Similarly, it's unclear why we don't need to scale along the */ 00515 /* axis. */ 00516 continue; 00517 00518 else if ( blend->normalizedcoords[i] == 0 || 00519 ( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) || 00520 ( blend->normalizedcoords[i] > 0 && tuple_coords[i] < 0 ) ) 00521 { 00522 apply = 0; 00523 break; 00524 } 00525 00526 else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) 00527 /* not an intermediate tuple */ 00528 apply = FT_MulDiv( apply, 00529 blend->normalizedcoords[i] > 0 00530 ? blend->normalizedcoords[i] 00531 : -blend->normalizedcoords[i], 00532 0x10000L ); 00533 00534 else if ( blend->normalizedcoords[i] <= im_start_coords[i] || 00535 blend->normalizedcoords[i] >= im_end_coords[i] ) 00536 { 00537 apply = 0; 00538 break; 00539 } 00540 00541 else if ( blend->normalizedcoords[i] < tuple_coords[i] ) 00542 { 00543 temp = FT_MulDiv( blend->normalizedcoords[i] - im_start_coords[i], 00544 0x10000L, 00545 tuple_coords[i] - im_start_coords[i]); 00546 apply = FT_MulDiv( apply, temp, 0x10000L ); 00547 } 00548 00549 else 00550 { 00551 temp = FT_MulDiv( im_end_coords[i] - blend->normalizedcoords[i], 00552 0x10000L, 00553 im_end_coords[i] - tuple_coords[i] ); 00554 apply = FT_MulDiv( apply, temp, 0x10000L ); 00555 } 00556 } 00557 00558 return apply; 00559 } 00560 00561 00562 /*************************************************************************/ 00563 /*************************************************************************/ 00564 /***** *****/ 00565 /***** MULTIPLE MASTERS SERVICE FUNCTIONS *****/ 00566 /***** *****/ 00567 /*************************************************************************/ 00568 /*************************************************************************/ 00569 00570 00571 typedef struct GX_FVar_Head_ 00572 { 00573 FT_Long version; 00574 FT_UShort offsetToData; 00575 FT_UShort countSizePairs; 00576 FT_UShort axisCount; 00577 FT_UShort axisSize; 00578 FT_UShort instanceCount; 00579 FT_UShort instanceSize; 00580 00581 } GX_FVar_Head; 00582 00583 00584 typedef struct fvar_axis_ 00585 { 00586 FT_ULong axisTag; 00587 FT_ULong minValue; 00588 FT_ULong defaultValue; 00589 FT_ULong maxValue; 00590 FT_UShort flags; 00591 FT_UShort nameID; 00592 00593 } GX_FVar_Axis; 00594 00595 00596 /*************************************************************************/ 00597 /* */ 00598 /* <Function> */ 00599 /* TT_Get_MM_Var */ 00600 /* */ 00601 /* <Description> */ 00602 /* Check that the font's `fvar' table is valid, parse it, and return */ 00603 /* those data. */ 00604 /* */ 00605 /* <InOut> */ 00606 /* face :: The font face. */ 00607 /* TT_Get_MM_Var initializes the blend structure. */ 00608 /* */ 00609 /* <Output> */ 00610 /* master :: The `fvar' data (must be freed by caller). */ 00611 /* */ 00612 /* <Return> */ 00613 /* FreeType error code. 0 means success. */ 00614 /* */ 00615 FT_LOCAL_DEF( FT_Error ) 00616 TT_Get_MM_Var( TT_Face face, 00617 FT_MM_Var* *master ) 00618 { 00619 FT_Stream stream = face->root.stream; 00620 FT_Memory memory = face->root.memory; 00621 FT_ULong table_len; 00622 FT_Error error = TT_Err_Ok; 00623 FT_ULong fvar_start; 00624 FT_Int i, j; 00625 FT_MM_Var* mmvar; 00626 FT_Fixed* next_coords; 00627 FT_String* next_name; 00628 FT_Var_Axis* a; 00629 FT_Var_Named_Style* ns; 00630 GX_FVar_Head fvar_head; 00631 00632 static const FT_Frame_Field fvar_fields[] = 00633 { 00634 00635 #undef FT_STRUCTURE 00636 #define FT_STRUCTURE GX_FVar_Head 00637 00638 FT_FRAME_START( 16 ), 00639 FT_FRAME_LONG ( version ), 00640 FT_FRAME_USHORT( offsetToData ), 00641 FT_FRAME_USHORT( countSizePairs ), 00642 FT_FRAME_USHORT( axisCount ), 00643 FT_FRAME_USHORT( axisSize ), 00644 FT_FRAME_USHORT( instanceCount ), 00645 FT_FRAME_USHORT( instanceSize ), 00646 FT_FRAME_END 00647 }; 00648 00649 static const FT_Frame_Field fvaraxis_fields[] = 00650 { 00651 00652 #undef FT_STRUCTURE 00653 #define FT_STRUCTURE GX_FVar_Axis 00654 00655 FT_FRAME_START( 20 ), 00656 FT_FRAME_ULONG ( axisTag ), 00657 FT_FRAME_ULONG ( minValue ), 00658 FT_FRAME_ULONG ( defaultValue ), 00659 FT_FRAME_ULONG ( maxValue ), 00660 FT_FRAME_USHORT( flags ), 00661 FT_FRAME_USHORT( nameID ), 00662 FT_FRAME_END 00663 }; 00664 00665 00666 if ( face->blend == NULL ) 00667 { 00668 /* both `fvar' and `gvar' must be present */ 00669 if ( (error = face->goto_table( face, TTAG_gvar, 00670 stream, &table_len )) != 0 ) 00671 goto Exit; 00672 00673 if ( (error = face->goto_table( face, TTAG_fvar, 00674 stream, &table_len )) != 0 ) 00675 goto Exit; 00676 00677 fvar_start = FT_STREAM_POS( ); 00678 00679 if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) ) 00680 goto Exit; 00681 00682 if ( fvar_head.version != (FT_Long)0x00010000L || 00683 fvar_head.countSizePairs != 2 || 00684 fvar_head.axisSize != 20 || 00685 /* axisCount limit implied by 16-bit instanceSize */ 00686 fvar_head.axisCount > 0x3FFE || 00687 fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount || 00688 /* instanceCount limit implied by limited range of name IDs */ 00689 fvar_head.instanceCount > 0x7EFF || 00690 fvar_head.offsetToData + fvar_head.axisCount * 20U + 00691 fvar_head.instanceCount * fvar_head.instanceSize > table_len ) 00692 { 00693 error = TT_Err_Invalid_Table; 00694 goto Exit; 00695 } 00696 00697 if ( FT_NEW( face->blend ) ) 00698 goto Exit; 00699 00700 /* cannot overflow 32-bit arithmetic because of limits above */ 00701 face->blend->mmvar_len = 00702 sizeof ( FT_MM_Var ) + 00703 fvar_head.axisCount * sizeof ( FT_Var_Axis ) + 00704 fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) + 00705 fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) + 00706 5 * fvar_head.axisCount; 00707 00708 if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) 00709 goto Exit; 00710 face->blend->mmvar = mmvar; 00711 00712 mmvar->num_axis = 00713 fvar_head.axisCount; 00714 mmvar->num_designs = 00715 (FT_UInt)-1; /* meaningless in this context; each glyph */ 00716 /* may have a different number of designs */ 00717 /* (or tuples, as called by Apple) */ 00718 mmvar->num_namedstyles = 00719 fvar_head.instanceCount; 00720 mmvar->axis = 00721 (FT_Var_Axis*)&(mmvar[1]); 00722 mmvar->namedstyle = 00723 (FT_Var_Named_Style*)&(mmvar->axis[fvar_head.axisCount]); 00724 00725 next_coords = 00726 (FT_Fixed*)&(mmvar->namedstyle[fvar_head.instanceCount]); 00727 for ( i = 0; i < fvar_head.instanceCount; ++i ) 00728 { 00729 mmvar->namedstyle[i].coords = next_coords; 00730 next_coords += fvar_head.axisCount; 00731 } 00732 00733 next_name = (FT_String*)next_coords; 00734 for ( i = 0; i < fvar_head.axisCount; ++i ) 00735 { 00736 mmvar->axis[i].name = next_name; 00737 next_name += 5; 00738 } 00739 00740 if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) ) 00741 goto Exit; 00742 00743 a = mmvar->axis; 00744 for ( i = 0; i < fvar_head.axisCount; ++i ) 00745 { 00746 GX_FVar_Axis axis_rec; 00747 00748 00749 if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) ) 00750 goto Exit; 00751 a->tag = axis_rec.axisTag; 00752 a->minimum = axis_rec.minValue; /* A Fixed */ 00753 a->def = axis_rec.defaultValue; /* A Fixed */ 00754 a->maximum = axis_rec.maxValue; /* A Fixed */ 00755 a->strid = axis_rec.nameID; 00756 00757 a->name[0] = (FT_String)( a->tag >> 24 ); 00758 a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF ); 00759 a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF ); 00760 a->name[3] = (FT_String)( ( a->tag ) & 0xFF ); 00761 a->name[4] = 0; 00762 00763 ++a; 00764 } 00765 00766 ns = mmvar->namedstyle; 00767 for ( i = 0; i < fvar_head.instanceCount; ++i, ++ns ) 00768 { 00769 if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) ) 00770 goto Exit; 00771 00772 ns->strid = FT_GET_USHORT(); 00773 (void) /* flags = */ FT_GET_USHORT(); 00774 00775 for ( j = 0; j < fvar_head.axisCount; ++j ) 00776 ns->coords[j] = FT_GET_ULONG(); /* A Fixed */ 00777 00778 FT_FRAME_EXIT(); 00779 } 00780 } 00781 00782 if ( master != NULL ) 00783 { 00784 FT_UInt n; 00785 00786 00787 if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) 00788 goto Exit; 00789 FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len ); 00790 00791 mmvar->axis = 00792 (FT_Var_Axis*)&(mmvar[1]); 00793 mmvar->namedstyle = 00794 (FT_Var_Named_Style*)&(mmvar->axis[mmvar->num_axis]); 00795 next_coords = 00796 (FT_Fixed*)&(mmvar->namedstyle[mmvar->num_namedstyles]); 00797 00798 for ( n = 0; n < mmvar->num_namedstyles; ++n ) 00799 { 00800 mmvar->namedstyle[n].coords = next_coords; 00801 next_coords += mmvar->num_axis; 00802 } 00803 00804 a = mmvar->axis; 00805 next_name = (FT_String*)next_coords; 00806 for ( n = 0; n < mmvar->num_axis; ++n ) 00807 { 00808 a->name = next_name; 00809 00810 /* standard PostScript names for some standard apple tags */ 00811 if ( a->tag == TTAG_wght ) 00812 a->name = (char *)"Weight"; 00813 else if ( a->tag == TTAG_wdth ) 00814 a->name = (char *)"Width"; 00815 else if ( a->tag == TTAG_opsz ) 00816 a->name = (char *)"OpticalSize"; 00817 else if ( a->tag == TTAG_slnt ) 00818 a->name = (char *)"Slant"; 00819 00820 next_name += 5; 00821 ++a; 00822 } 00823 00824 *master = mmvar; 00825 } 00826 00827 Exit: 00828 return error; 00829 } 00830 00831 00832 /*************************************************************************/ 00833 /* */ 00834 /* <Function> */ 00835 /* TT_Set_MM_Blend */ 00836 /* */ 00837 /* <Description> */ 00838 /* Set the blend (normalized) coordinates for this instance of the */ 00839 /* font. Check that the `gvar' table is reasonable and does some */ 00840 /* initial preparation. */ 00841 /* */ 00842 /* <InOut> */ 00843 /* face :: The font. */ 00844 /* Initialize the blend structure with `gvar' data. */ 00845 /* */ 00846 /* <Input> */ 00847 /* num_coords :: Must be the axis count of the font. */ 00848 /* */ 00849 /* coords :: An array of num_coords, each between [-1,1]. */ 00850 /* */ 00851 /* <Return> */ 00852 /* FreeType error code. 0 means success. */ 00853 /* */ 00854 FT_LOCAL_DEF( FT_Error ) 00855 TT_Set_MM_Blend( TT_Face face, 00856 FT_UInt num_coords, 00857 FT_Fixed* coords ) 00858 { 00859 FT_Error error = TT_Err_Ok; 00860 GX_Blend blend; 00861 FT_MM_Var* mmvar; 00862 FT_UInt i; 00863 FT_Memory memory = face->root.memory; 00864 00865 enum 00866 { 00867 mcvt_retain, 00868 mcvt_modify, 00869 mcvt_load 00870 00871 } manageCvt; 00872 00873 00874 face->doblend = FALSE; 00875 00876 if ( face->blend == NULL ) 00877 { 00878 if ( (error = TT_Get_MM_Var( face, NULL)) != 0 ) 00879 goto Exit; 00880 } 00881 00882 blend = face->blend; 00883 mmvar = blend->mmvar; 00884 00885 if ( num_coords != mmvar->num_axis ) 00886 { 00887 error = TT_Err_Invalid_Argument; 00888 goto Exit; 00889 } 00890 00891 for ( i = 0; i < num_coords; ++i ) 00892 if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L ) 00893 { 00894 error = TT_Err_Invalid_Argument; 00895 goto Exit; 00896 } 00897 00898 if ( blend->glyphoffsets == NULL ) 00899 if ( (error = ft_var_load_gvar( face )) != 0 ) 00900 goto Exit; 00901 00902 if ( blend->normalizedcoords == NULL ) 00903 { 00904 if ( FT_NEW_ARRAY( blend->normalizedcoords, num_coords ) ) 00905 goto Exit; 00906 00907 manageCvt = mcvt_modify; 00908 00909 /* If we have not set the blend coordinates before this, then the */ 00910 /* cvt table will still be what we read from the `cvt ' table and */ 00911 /* we don't need to reload it. We may need to change it though... */ 00912 } 00913 else 00914 { 00915 manageCvt = mcvt_retain; 00916 for ( i = 0; i < num_coords; ++i ) 00917 { 00918 if ( blend->normalizedcoords[i] != coords[i] ) 00919 { 00920 manageCvt = mcvt_load; 00921 break; 00922 } 00923 } 00924 00925 /* If we don't change the blend coords then we don't need to do */ 00926 /* anything to the cvt table. It will be correct. Otherwise we */ 00927 /* no longer have the original cvt (it was modified when we set */ 00928 /* the blend last time), so we must reload and then modify it. */ 00929 } 00930 00931 blend->num_axis = num_coords; 00932 FT_MEM_COPY( blend->normalizedcoords, 00933 coords, 00934 num_coords * sizeof ( FT_Fixed ) ); 00935 00936 face->doblend = TRUE; 00937 00938 if ( face->cvt != NULL ) 00939 { 00940 switch ( manageCvt ) 00941 { 00942 case mcvt_load: 00943 /* The cvt table has been loaded already; every time we change the */ 00944 /* blend we may need to reload and remodify the cvt table. */ 00945 FT_FREE( face->cvt ); 00946 face->cvt = NULL; 00947 00948 tt_face_load_cvt( face, face->root.stream ); 00949 break; 00950 00951 case mcvt_modify: 00952 /* The original cvt table is in memory. All we need to do is */ 00953 /* apply the `cvar' table (if any). */ 00954 tt_face_vary_cvt( face, face->root.stream ); 00955 break; 00956 00957 case mcvt_retain: 00958 /* The cvt table is correct for this set of coordinates. */ 00959 break; 00960 } 00961 } 00962 00963 Exit: 00964 return error; 00965 } 00966 00967 00968 /*************************************************************************/ 00969 /* */ 00970 /* <Function> */ 00971 /* TT_Set_Var_Design */ 00972 /* */ 00973 /* <Description> */ 00974 /* Set the coordinates for the instance, measured in the user */ 00975 /* coordinate system. Parse the `avar' table (if present) to convert */ 00976 /* from user to normalized coordinates. */ 00977 /* */ 00978 /* <InOut> */ 00979 /* face :: The font face. */ 00980 /* Initialize the blend struct with `gvar' data. */ 00981 /* */ 00982 /* <Input> */ 00983 /* num_coords :: This must be the axis count of the font. */ 00984 /* */ 00985 /* coords :: A coordinate array with `num_coords' elements. */ 00986 /* */ 00987 /* <Return> */ 00988 /* FreeType error code. 0 means success. */ 00989 /* */ 00990 FT_LOCAL_DEF( FT_Error ) 00991 TT_Set_Var_Design( TT_Face face, 00992 FT_UInt num_coords, 00993 FT_Fixed* coords ) 00994 { 00995 FT_Error error = TT_Err_Ok; 00996 FT_Fixed* normalized = NULL; 00997 GX_Blend blend; 00998 FT_MM_Var* mmvar; 00999 FT_UInt i, j; 01000 FT_Var_Axis* a; 01001 GX_AVarSegment av; 01002 FT_Memory memory = face->root.memory; 01003 01004 01005 if ( face->blend == NULL ) 01006 { 01007 if ( (error = TT_Get_MM_Var( face, NULL )) != 0 ) 01008 goto Exit; 01009 } 01010 01011 blend = face->blend; 01012 mmvar = blend->mmvar; 01013 01014 if ( num_coords != mmvar->num_axis ) 01015 { 01016 error = TT_Err_Invalid_Argument; 01017 goto Exit; 01018 } 01019 01020 /* Axis normalization is a two stage process. First we normalize */ 01021 /* based on the [min,def,max] values for the axis to be [-1,0,1]. */ 01022 /* Then, if there's an `avar' table, we renormalize this range. */ 01023 01024 if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) ) 01025 goto Exit; 01026 01027 a = mmvar->axis; 01028 for ( i = 0; i < mmvar->num_axis; ++i, ++a ) 01029 { 01030 if ( coords[i] > a->maximum || coords[i] < a->minimum ) 01031 { 01032 error = TT_Err_Invalid_Argument; 01033 goto Exit; 01034 } 01035 01036 if ( coords[i] < a->def ) 01037 { 01038 normalized[i] = -FT_MulDiv( coords[i] - a->def, 01039 0x10000L, 01040 a->minimum - a->def ); 01041 } 01042 else if ( a->maximum == a->def ) 01043 normalized[i] = 0; 01044 else 01045 { 01046 normalized[i] = FT_MulDiv( coords[i] - a->def, 01047 0x10000L, 01048 a->maximum - a->def ); 01049 } 01050 } 01051 01052 if ( !blend->avar_checked ) 01053 ft_var_load_avar( face ); 01054 01055 if ( blend->avar_segment != NULL ) 01056 { 01057 av = blend->avar_segment; 01058 for ( i = 0; i < mmvar->num_axis; ++i, ++av ) 01059 { 01060 for ( j = 1; j < (FT_UInt)av->pairCount; ++j ) 01061 if ( normalized[i] < av->correspondence[j].fromCoord ) 01062 { 01063 normalized[i] = 01064 FT_MulDiv( 01065 FT_MulDiv( 01066 normalized[i] - av->correspondence[j - 1].fromCoord, 01067 0x10000L, 01068 av->correspondence[j].fromCoord - 01069 av->correspondence[j - 1].fromCoord ), 01070 av->correspondence[j].toCoord - 01071 av->correspondence[j - 1].toCoord, 01072 0x10000L ) + 01073 av->correspondence[j - 1].toCoord; 01074 break; 01075 } 01076 } 01077 } 01078 01079 error = TT_Set_MM_Blend( face, num_coords, normalized ); 01080 01081 Exit: 01082 FT_FREE( normalized ); 01083 return error; 01084 } 01085 01086 01087 /*************************************************************************/ 01088 /*************************************************************************/ 01089 /***** *****/ 01090 /***** GX VAR PARSING ROUTINES *****/ 01091 /***** *****/ 01092 /*************************************************************************/ 01093 /*************************************************************************/ 01094 01095 01096 /*************************************************************************/ 01097 /* */ 01098 /* <Function> */ 01099 /* tt_face_vary_cvt */ 01100 /* */ 01101 /* <Description> */ 01102 /* Modify the loaded cvt table according to the `cvar' table and the */ 01103 /* font's blend. */ 01104 /* */ 01105 /* <InOut> */ 01106 /* face :: A handle to the target face object. */ 01107 /* */ 01108 /* <Input> */ 01109 /* stream :: A handle to the input stream. */ 01110 /* */ 01111 /* <Return> */ 01112 /* FreeType error code. 0 means success. */ 01113 /* */ 01114 /* Most errors are ignored. It is perfectly valid not to have a */ 01115 /* `cvar' table even if there is a `gvar' and `fvar' table. */ 01116 /* */ 01117 FT_LOCAL_DEF( FT_Error ) 01118 tt_face_vary_cvt( TT_Face face, 01119 FT_Stream stream ) 01120 { 01121 FT_Error error; 01122 FT_Memory memory = stream->memory; 01123 FT_ULong table_start; 01124 FT_ULong table_len; 01125 FT_UInt tupleCount; 01126 FT_ULong offsetToData; 01127 FT_ULong here; 01128 FT_UInt i, j; 01129 FT_Fixed* tuple_coords = NULL; 01130 FT_Fixed* im_start_coords = NULL; 01131 FT_Fixed* im_end_coords = NULL; 01132 GX_Blend blend = face->blend; 01133 FT_UInt point_count; 01134 FT_UShort* localpoints; 01135 FT_Short* deltas; 01136 01137 01138 FT_TRACE2(( "CVAR " )); 01139 01140 if ( blend == NULL ) 01141 { 01142 FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" )); 01143 01144 error = TT_Err_Ok; 01145 goto Exit; 01146 } 01147 01148 if ( face->cvt == NULL ) 01149 { 01150 FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" )); 01151 01152 error = TT_Err_Ok; 01153 goto Exit; 01154 } 01155 01156 error = face->goto_table( face, TTAG_cvar, stream, &table_len ); 01157 if ( error ) 01158 { 01159 FT_TRACE2(( "is missing\n" )); 01160 01161 error = TT_Err_Ok; 01162 goto Exit; 01163 } 01164 01165 if ( FT_FRAME_ENTER( table_len ) ) 01166 { 01167 error = TT_Err_Ok; 01168 goto Exit; 01169 } 01170 01171 table_start = FT_Stream_FTell( stream ); 01172 if ( FT_GET_LONG() != 0x00010000L ) 01173 { 01174 FT_TRACE2(( "bad table version\n" )); 01175 01176 error = TT_Err_Ok; 01177 goto FExit; 01178 } 01179 01180 if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || 01181 FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || 01182 FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) 01183 goto FExit; 01184 01185 tupleCount = FT_GET_USHORT(); 01186 offsetToData = table_start + FT_GET_USHORT(); 01187 01188 /* The documentation implies there are flags packed into the */ 01189 /* tuplecount, but John Jenkins says that shared points don't apply */ 01190 /* to `cvar', and no other flags are defined. */ 01191 01192 for ( i = 0; i < ( tupleCount & 0xFFF ); ++i ) 01193 { 01194 FT_UInt tupleDataSize; 01195 FT_UInt tupleIndex; 01196 FT_Fixed apply; 01197 01198 01199 tupleDataSize = FT_GET_USHORT(); 01200 tupleIndex = FT_GET_USHORT(); 01201 01202 /* There is no provision here for a global tuple coordinate section, */ 01203 /* so John says. There are no tuple indices, just embedded tuples. */ 01204 01205 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) 01206 { 01207 for ( j = 0; j < blend->num_axis; ++j ) 01208 tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */ 01209 /* short frac to fixed */ 01210 } 01211 else 01212 { 01213 /* skip this tuple; it makes no sense */ 01214 01215 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) 01216 for ( j = 0; j < 2 * blend->num_axis; ++j ) 01217 (void)FT_GET_SHORT(); 01218 01219 offsetToData += tupleDataSize; 01220 continue; 01221 } 01222 01223 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) 01224 { 01225 for ( j = 0; j < blend->num_axis; ++j ) 01226 im_start_coords[j] = FT_GET_SHORT() << 2; 01227 for ( j = 0; j < blend->num_axis; ++j ) 01228 im_end_coords[j] = FT_GET_SHORT() << 2; 01229 } 01230 01231 apply = ft_var_apply_tuple( blend, 01232 (FT_UShort)tupleIndex, 01233 tuple_coords, 01234 im_start_coords, 01235 im_end_coords ); 01236 if ( /* tuple isn't active for our blend */ 01237 apply == 0 || 01238 /* global points not allowed, */ 01239 /* if they aren't local, makes no sense */ 01240 !( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) ) 01241 { 01242 offsetToData += tupleDataSize; 01243 continue; 01244 } 01245 01246 here = FT_Stream_FTell( stream ); 01247 01248 FT_Stream_SeekSet( stream, offsetToData ); 01249 01250 localpoints = ft_var_readpackedpoints( stream, &point_count ); 01251 deltas = ft_var_readpackeddeltas( stream, 01252 point_count == 0 ? face->cvt_size 01253 : point_count ); 01254 if ( localpoints == NULL || deltas == NULL ) 01255 /* failure, ignore it */; 01256 01257 else if ( localpoints == ALL_POINTS ) 01258 { 01259 /* this means that there are deltas for every entry in cvt */ 01260 for ( j = 0; j < face->cvt_size; ++j ) 01261 face->cvt[j] = (FT_Short)( face->cvt[j] + 01262 FT_MulFix( deltas[j], apply ) ); 01263 } 01264 01265 else 01266 { 01267 for ( j = 0; j < point_count; ++j ) 01268 { 01269 int pindex = localpoints[j]; 01270 01271 face->cvt[pindex] = (FT_Short)( face->cvt[pindex] + 01272 FT_MulFix( deltas[j], apply ) ); 01273 } 01274 } 01275 01276 if ( localpoints != ALL_POINTS ) 01277 FT_FREE( localpoints ); 01278 FT_FREE( deltas ); 01279 01280 offsetToData += tupleDataSize; 01281 01282 FT_Stream_SeekSet( stream, here ); 01283 } 01284 01285 FExit: 01286 FT_FRAME_EXIT(); 01287 01288 Exit: 01289 FT_FREE( tuple_coords ); 01290 FT_FREE( im_start_coords ); 01291 FT_FREE( im_end_coords ); 01292 01293 return error; 01294 } 01295 01296 01297 /*************************************************************************/ 01298 /* */ 01299 /* <Function> */ 01300 /* TT_Vary_Get_Glyph_Deltas */ 01301 /* */ 01302 /* <Description> */ 01303 /* Load the appropriate deltas for the current glyph. */ 01304 /* */ 01305 /* <Input> */ 01306 /* face :: A handle to the target face object. */ 01307 /* */ 01308 /* glyph_index :: The index of the glyph being modified. */ 01309 /* */ 01310 /* n_points :: The number of the points in the glyph, including */ 01311 /* phantom points. */ 01312 /* */ 01313 /* <Output> */ 01314 /* deltas :: The array of points to change. */ 01315 /* */ 01316 /* <Return> */ 01317 /* FreeType error code. 0 means success. */ 01318 /* */ 01319 FT_LOCAL_DEF( FT_Error ) 01320 TT_Vary_Get_Glyph_Deltas( TT_Face face, 01321 FT_UInt glyph_index, 01322 FT_Vector* *deltas, 01323 FT_UInt n_points ) 01324 { 01325 FT_Stream stream = face->root.stream; 01326 FT_Memory memory = stream->memory; 01327 GX_Blend blend = face->blend; 01328 FT_Vector* delta_xy; 01329 01330 FT_Error error; 01331 FT_ULong glyph_start; 01332 FT_UInt tupleCount; 01333 FT_ULong offsetToData; 01334 FT_ULong here; 01335 FT_UInt i, j; 01336 FT_Fixed* tuple_coords = NULL; 01337 FT_Fixed* im_start_coords = NULL; 01338 FT_Fixed* im_end_coords = NULL; 01339 FT_UInt point_count, spoint_count = 0; 01340 FT_UShort* sharedpoints = NULL; 01341 FT_UShort* localpoints = NULL; 01342 FT_UShort* points; 01343 FT_Short *deltas_x, *deltas_y; 01344 01345 01346 if ( !face->doblend || blend == NULL ) 01347 return TT_Err_Invalid_Argument; 01348 01349 /* to be freed by the caller */ 01350 if ( FT_NEW_ARRAY( delta_xy, n_points ) ) 01351 goto Exit; 01352 *deltas = delta_xy; 01353 01354 if ( glyph_index >= blend->gv_glyphcnt || 01355 blend->glyphoffsets[glyph_index] == 01356 blend->glyphoffsets[glyph_index + 1] ) 01357 return TT_Err_Ok; /* no variation data for this glyph */ 01358 01359 if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) || 01360 FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] - 01361 blend->glyphoffsets[glyph_index] ) ) 01362 goto Fail1; 01363 01364 glyph_start = FT_Stream_FTell( stream ); 01365 01366 /* each set of glyph variation data is formatted similarly to `cvar' */ 01367 /* (except we get shared points and global tuples) */ 01368 01369 if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || 01370 FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || 01371 FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) 01372 goto Fail2; 01373 01374 tupleCount = FT_GET_USHORT(); 01375 offsetToData = glyph_start + FT_GET_USHORT(); 01376 01377 if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) 01378 { 01379 here = FT_Stream_FTell( stream ); 01380 01381 FT_Stream_SeekSet( stream, offsetToData ); 01382 01383 sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); 01384 offsetToData = FT_Stream_FTell( stream ); 01385 01386 FT_Stream_SeekSet( stream, here ); 01387 } 01388 01389 for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); ++i ) 01390 { 01391 FT_UInt tupleDataSize; 01392 FT_UInt tupleIndex; 01393 FT_Fixed apply; 01394 01395 01396 tupleDataSize = FT_GET_USHORT(); 01397 tupleIndex = FT_GET_USHORT(); 01398 01399 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) 01400 { 01401 for ( j = 0; j < blend->num_axis; ++j ) 01402 tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */ 01403 /* short frac to fixed */ 01404 } 01405 else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) 01406 { 01407 error = TT_Err_Invalid_Table; 01408 goto Fail3; 01409 } 01410 else 01411 { 01412 FT_MEM_COPY( 01413 tuple_coords, 01414 &blend->tuplecoords[(tupleIndex & 0xFFF) * blend->num_axis], 01415 blend->num_axis * sizeof ( FT_Fixed ) ); 01416 } 01417 01418 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) 01419 { 01420 for ( j = 0; j < blend->num_axis; ++j ) 01421 im_start_coords[j] = FT_GET_SHORT() << 2; 01422 for ( j = 0; j < blend->num_axis; ++j ) 01423 im_end_coords[j] = FT_GET_SHORT() << 2; 01424 } 01425 01426 apply = ft_var_apply_tuple( blend, 01427 (FT_UShort)tupleIndex, 01428 tuple_coords, 01429 im_start_coords, 01430 im_end_coords ); 01431 01432 if ( apply == 0 ) /* tuple isn't active for our blend */ 01433 { 01434 offsetToData += tupleDataSize; 01435 continue; 01436 } 01437 01438 here = FT_Stream_FTell( stream ); 01439 01440 if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) 01441 { 01442 FT_Stream_SeekSet( stream, offsetToData ); 01443 01444 localpoints = ft_var_readpackedpoints( stream, &point_count ); 01445 points = localpoints; 01446 } 01447 else 01448 { 01449 points = sharedpoints; 01450 point_count = spoint_count; 01451 } 01452 01453 deltas_x = ft_var_readpackeddeltas( stream, 01454 point_count == 0 ? n_points 01455 : point_count ); 01456 deltas_y = ft_var_readpackeddeltas( stream, 01457 point_count == 0 ? n_points 01458 : point_count ); 01459 01460 if ( points == NULL || deltas_y == NULL || deltas_x == NULL ) 01461 ; /* failure, ignore it */ 01462 01463 else if ( points == ALL_POINTS ) 01464 { 01465 /* this means that there are deltas for every point in the glyph */ 01466 for ( j = 0; j < n_points; ++j ) 01467 { 01468 delta_xy[j].x += FT_MulFix( deltas_x[j], apply ); 01469 delta_xy[j].y += FT_MulFix( deltas_y[j], apply ); 01470 } 01471 } 01472 01473 else 01474 { 01475 for ( j = 0; j < point_count; ++j ) 01476 { 01477 delta_xy[localpoints[j]].x += FT_MulFix( deltas_x[j], apply ); 01478 delta_xy[localpoints[j]].y += FT_MulFix( deltas_y[j], apply ); 01479 } 01480 } 01481 01482 if ( localpoints != ALL_POINTS ) 01483 FT_FREE( localpoints ); 01484 FT_FREE( deltas_x ); 01485 FT_FREE( deltas_y ); 01486 01487 offsetToData += tupleDataSize; 01488 01489 FT_Stream_SeekSet( stream, here ); 01490 } 01491 01492 Fail3: 01493 FT_FREE( tuple_coords ); 01494 FT_FREE( im_start_coords ); 01495 FT_FREE( im_end_coords ); 01496 01497 Fail2: 01498 FT_FRAME_EXIT(); 01499 01500 Fail1: 01501 if ( error ) 01502 { 01503 FT_FREE( delta_xy ); 01504 *deltas = NULL; 01505 } 01506 01507 Exit: 01508 return error; 01509 } 01510 01511 01512 /*************************************************************************/ 01513 /* */ 01514 /* <Function> */ 01515 /* tt_done_blend */ 01516 /* */ 01517 /* <Description> */ 01518 /* Frees the blend internal data structure. */ 01519 /* */ 01520 FT_LOCAL_DEF( void ) 01521 tt_done_blend( FT_Memory memory, 01522 GX_Blend blend ) 01523 { 01524 if ( blend != NULL ) 01525 { 01526 FT_UInt i; 01527 01528 01529 FT_FREE( blend->normalizedcoords ); 01530 FT_FREE( blend->mmvar ); 01531 01532 if ( blend->avar_segment != NULL ) 01533 { 01534 for ( i = 0; i < blend->num_axis; ++i ) 01535 FT_FREE( blend->avar_segment[i].correspondence ); 01536 FT_FREE( blend->avar_segment ); 01537 } 01538 01539 FT_FREE( blend->tuplecoords ); 01540 FT_FREE( blend->glyphoffsets ); 01541 FT_FREE( blend ); 01542 } 01543 } 01544 01545 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ 01546 01547 01548 /* END */ Generated on Sun May 27 2012 04:34:03 for ReactOS by
1.7.6.1
|