55 #include "tterrors.h"
56
57
58 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
59
60
61 #define FT_Stream_FTell( stream ) \
62 (FT_ULong)( (stream)->cursor - (stream)->base )
63 #define FT_Stream_SeekSet( stream, off ) \
64 (stream)->cursor = \
65 ( (off) < (FT_ULong)( (stream)->limit - (stream)->base ) ) \
66 ? (stream)->base + (off) \
67 : (stream)->limit
68
69
70 /* some macros we need */
71 #define FT_fdot14ToFixed( x ) \
72 ( (FT_Fixed)( (FT_ULong)(x) << 2 ) )
73 #define FT_intToFixed( i ) \
74 ( (FT_Fixed)( (FT_ULong)(i) << 16 ) )
75 #define FT_fixedToInt( x ) \
76 ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
77
78
79 /**************************************************************************
80 *
81 * The macro FT_COMPONENT is used in trace mode. It is an implicit
82 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
83 * messages during execution.
84 */
85 #undef FT_COMPONENT
86 #define FT_COMPONENT ttgxvar
87
88
89 /*************************************************************************/
90 /*************************************************************************/
91 /***** *****/
92 /***** Internal Routines *****/
93 /***** *****/
94 /*************************************************************************/
95 /*************************************************************************/
96
380 {
381 FT_TRACE5(( " axis %d:\n", i ));
382
383 segment->pairCount = FT_GET_USHORT();
384 if ( (FT_ULong)segment->pairCount * 4 > table_len ||
385 FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) )
386 {
387 /* Failure. Free everything we have done so far. We must do */
388 /* it right now since loading the `avar' table is optional. */
389
390 for ( j = i - 1; j >= 0; j-- )
391 FT_FREE( blend->avar_segment[j].correspondence );
392
393 FT_FREE( blend->avar_segment );
394 blend->avar_segment = NULL;
395 goto Exit;
396 }
397
398 for ( j = 0; j < segment->pairCount; j++ )
399 {
400 /* convert to Fixed */
401 segment->correspondence[j].fromCoord = FT_GET_SHORT() * 4;
402 segment->correspondence[j].toCoord = FT_GET_SHORT() * 4;
403
404 FT_TRACE5(( " mapping %.5f to %.5f\n",
405 segment->correspondence[j].fromCoord / 65536.0,
406 segment->correspondence[j].toCoord / 65536.0 ));
407 }
408
409 FT_TRACE5(( "\n" ));
410 }
411
412 Exit:
413 FT_FRAME_EXIT();
414 }
415
416
417 static FT_Error
418 ft_var_load_item_variation_store( TT_Face face,
419 FT_ULong offset,
420 GX_ItemVarStore itemStore )
421 {
422 FT_Stream stream = FT_FACE_STREAM( face );
1599 FT_FRAME_EXIT();
1600 if ( error )
1601 goto Exit;
1602
1603 if ( blend->tuplecount != 0 )
1604 {
1605 if ( FT_NEW_ARRAY( blend->tuplecoords,
1606 gvar_head.axisCount * blend->tuplecount ) )
1607 goto Exit;
1608
1609 if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) ||
1610 FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) )
1611 goto Exit;
1612
1613 for ( i = 0; i < blend->tuplecount; i++ )
1614 {
1615 FT_TRACE5(( " [ " ));
1616 for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ )
1617 {
1618 blend->tuplecoords[i * gvar_head.axisCount + j] =
1619 FT_GET_SHORT() * 4; /* convert to FT_Fixed */
1620 FT_TRACE5(( "%.5f ",
1621 blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 ));
1622 }
1623 FT_TRACE5(( "]\n" ));
1624 }
1625
1626 FT_TRACE5(( "\n" ));
1627
1628 FT_FRAME_EXIT();
1629 }
1630
1631 Exit:
1632 return error;
1633 }
1634
1635
1636 /**************************************************************************
1637 *
1638 * @Function:
1639 * ft_var_apply_tuple
3037 FT_MM_Var* mmvar;
3038
3039 FT_UInt num_instances;
3040
3041
3042 if ( !face->blend )
3043 {
3044 if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
3045 goto Exit;
3046 }
3047
3048 blend = face->blend;
3049 mmvar = blend->mmvar;
3050
3051 num_instances = (FT_UInt)face->root.style_flags >> 16;
3052
3053 /* `instance_index' starts with value 1, thus `>' */
3054 if ( instance_index > num_instances )
3055 goto Exit;
3056
3057 if ( instance_index > 0 && mmvar->namedstyle )
3058 {
3059 FT_Memory memory = face->root.memory;
3060 SFNT_Service sfnt = (SFNT_Service)face->sfnt;
3061
3062 FT_Var_Named_Style* named_style;
3063 FT_String* style_name;
3064
3065
3066 named_style = mmvar->namedstyle + instance_index - 1;
3067
3068 error = sfnt->get_name( face,
3069 (FT_UShort)named_style->strid,
3070 &style_name );
3071 if ( error )
3072 goto Exit;
3073
3074 /* set (or replace) style name */
3075 FT_FREE( face->root.style_name );
3076 face->root.style_name = style_name;
3077
3078 /* finally, select the named instance */
3079 error = TT_Set_Var_Design( face,
3080 mmvar->num_axis,
3081 named_style->coords );
3082 if ( error )
3083 goto Exit;
3084 }
3085 else
3086 error = TT_Set_Var_Design( face, 0, NULL );
3087
3088 face->root.face_index = ( instance_index << 16 ) |
3089 ( face->root.face_index & 0xFFFFL );
3090 face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
3091
3092 Exit:
3093 return error;
3094 }
3095
3096
3097 /*************************************************************************/
3098 /*************************************************************************/
3099 /***** *****/
3100 /***** GX VAR PARSING ROUTINES *****/
3101 /***** *****/
3102 /*************************************************************************/
3103 /*************************************************************************/
3104
3105
3106 /**************************************************************************
3107 *
3108 * @Function:
3109 * tt_face_vary_cvt
3110 *
3111 * @Description:
3112 * Modify the loaded cvt table according to the `cvar' table and the
3113 * font's blend.
3114 *
3115 * @InOut:
3116 * face ::
3117 * A handle to the target face object.
3118 *
3119 * @Input:
3120 * stream ::
3121 * A handle to the input stream.
3122 *
3123 * @Return:
3124 * FreeType error code. 0 means success.
3125 *
3126 * Most errors are ignored. It is perfectly valid not to have a
3127 * `cvar' table even if there is a `gvar' and `fvar' table.
3128 */
3129 FT_LOCAL_DEF( FT_Error )
3130 tt_face_vary_cvt( TT_Face face,
3131 FT_Stream stream )
3132 {
3133 FT_Error error;
3134 FT_Memory memory = stream->memory;
3135
3136 FT_ULong table_start;
3137 FT_ULong table_len;
3138
3139 FT_UInt tupleCount;
3140 FT_ULong offsetToData;
3141
3142 FT_ULong here;
3143 FT_UInt i, j;
3144
3145 FT_Fixed* tuple_coords = NULL;
3146 FT_Fixed* im_start_coords = NULL;
3147 FT_Fixed* im_end_coords = NULL;
3148
3149 GX_Blend blend = face->blend;
3150
3151 FT_UInt point_count;
3152 FT_UInt spoint_count = 0;
3153
3154 FT_UShort* sharedpoints = NULL;
3155 FT_UShort* localpoints = NULL;
3244 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" ));
3245
3246 if ( FT_NEW_ARRAY( cvt_deltas, face->cvt_size ) )
3247 goto FExit;
3248
3249 for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
3250 {
3251 FT_UInt tupleDataSize;
3252 FT_UInt tupleIndex;
3253 FT_Fixed apply;
3254
3255
3256 FT_TRACE6(( " tuple %d:\n", i ));
3257
3258 tupleDataSize = FT_GET_USHORT();
3259 tupleIndex = FT_GET_USHORT();
3260
3261 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
3262 {
3263 for ( j = 0; j < blend->num_axis; j++ )
3264 tuple_coords[j] = FT_GET_SHORT() * 4; /* convert from */
3265 /* short frac to fixed */
3266 }
3267 else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
3268 {
3269 FT_TRACE2(( "tt_face_vary_cvt:"
3270 " invalid tuple index\n" ));
3271
3272 error = FT_THROW( Invalid_Table );
3273 goto FExit;
3274 }
3275 else
3276 {
3277 if ( !blend->tuplecoords )
3278 {
3279 FT_TRACE2(( "tt_face_vary_cvt:"
3280 " no valid tuple coordinates available\n" ));
3281
3282 error = FT_THROW( Invalid_Table );
3283 goto FExit;
3284 }
3285
3286 FT_MEM_COPY(
3287 tuple_coords,
3288 blend->tuplecoords +
3289 ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis,
3290 blend->num_axis * sizeof ( FT_Fixed ) );
3291 }
3292
3293 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
3294 {
3295 for ( j = 0; j < blend->num_axis; j++ )
3296 im_start_coords[j] = FT_GET_SHORT() * 4;
3297 for ( j = 0; j < blend->num_axis; j++ )
3298 im_end_coords[j] = FT_GET_SHORT() * 4;
3299 }
3300
3301 apply = ft_var_apply_tuple( blend,
3302 (FT_UShort)tupleIndex,
3303 tuple_coords,
3304 im_start_coords,
3305 im_end_coords );
3306
3307 if ( apply == 0 ) /* tuple isn't active for our blend */
3308 {
3309 offsetToData += tupleDataSize;
3310 continue;
3311 }
3312
3313 here = FT_Stream_FTell( stream );
3314
3315 FT_Stream_SeekSet( stream, offsetToData );
3316
3317 if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
3318 {
3343 int count = 0;
3344 #endif
3345
3346
3347 FT_TRACE7(( " CVT deltas:\n" ));
3348
3349 /* this means that there are deltas for every entry in cvt */
3350 for ( j = 0; j < face->cvt_size; j++ )
3351 {
3352 FT_Fixed old_cvt_delta;
3353
3354
3355 old_cvt_delta = cvt_deltas[j];
3356 cvt_deltas[j] = old_cvt_delta + FT_MulFix( deltas[j], apply );
3357
3358 #ifdef FT_DEBUG_LEVEL_TRACE
3359 if ( old_cvt_delta != cvt_deltas[j] )
3360 {
3361 FT_TRACE7(( " %d: %f -> %f\n",
3362 j,
3363 ( FT_intToFixed( face->cvt[j] ) +
3364 old_cvt_delta ) / 65536.0,
3365 ( FT_intToFixed( face->cvt[j] ) +
3366 cvt_deltas[j] ) / 65536.0 ));
3367 count++;
3368 }
3369 #endif
3370 }
3371
3372 #ifdef FT_DEBUG_LEVEL_TRACE
3373 if ( !count )
3374 FT_TRACE7(( " none\n" ));
3375 #endif
3376 }
3377
3378 else
3379 {
3380 #ifdef FT_DEBUG_LEVEL_TRACE
3381 int count = 0;
3382 #endif
3383
3384
3385 FT_TRACE7(( " CVT deltas:\n" ));
3386
3387 for ( j = 0; j < point_count; j++ )
3388 {
3389 int pindex;
3390 FT_Fixed old_cvt_delta;
3391
3392
3393 pindex = points[j];
3394 if ( (FT_ULong)pindex >= face->cvt_size )
3395 continue;
3396
3397 old_cvt_delta = cvt_deltas[pindex];
3398 cvt_deltas[pindex] = old_cvt_delta + FT_MulFix( deltas[j], apply );
3399
3400 #ifdef FT_DEBUG_LEVEL_TRACE
3401 if ( old_cvt_delta != cvt_deltas[pindex] )
3402 {
3403 FT_TRACE7(( " %d: %f -> %f\n",
3404 pindex,
3405 ( FT_intToFixed( face->cvt[pindex] ) +
3406 old_cvt_delta ) / 65536.0,
3407 ( FT_intToFixed( face->cvt[pindex] ) +
3408 cvt_deltas[pindex] ) / 65536.0 ));
3409 count++;
3410 }
3411 #endif
3412 }
3413
3414 #ifdef FT_DEBUG_LEVEL_TRACE
3415 if ( !count )
3416 FT_TRACE7(( " none\n" ));
3417 #endif
3418 }
3419
3420 if ( localpoints != ALL_POINTS )
3421 FT_FREE( localpoints );
3422 FT_FREE( deltas );
3423
3424 offsetToData += tupleDataSize;
3425
3426 FT_Stream_SeekSet( stream, here );
3427 }
3428
3429 FT_TRACE5(( "\n" ));
3430
3431 for ( i = 0; i < face->cvt_size; i++ )
3432 face->cvt[i] += FT_fixedToInt( cvt_deltas[i] );
3433
3434 FExit:
3435 FT_FRAME_EXIT();
3436
3437 Exit:
3438 if ( sharedpoints != ALL_POINTS )
3439 FT_FREE( sharedpoints );
3440 FT_FREE( tuple_coords );
3441 FT_FREE( im_start_coords );
3442 FT_FREE( im_end_coords );
3443 FT_FREE( cvt_deltas );
3444
3445 return error;
3446 }
3447
3448
3449 /* Shift the original coordinates of all points between indices `p1' */
3450 /* and `p2', using the same difference as given by index `ref'. */
3451
3452 /* modeled after `af_iup_shift' */
3453
3454 static void
3455 tt_delta_shift( int p1,
3456 int p2,
3457 int ref,
3458 FT_Vector* in_points,
3459 FT_Vector* out_points )
3460 {
3461 int p;
3462 FT_Vector delta;
3463
3464
3652 * TT_Vary_Apply_Glyph_Deltas
3653 *
3654 * @Description:
3655 * Apply the appropriate deltas to the current glyph.
3656 *
3657 * @Input:
3658 * face ::
3659 * A handle to the target face object.
3660 *
3661 * glyph_index ::
3662 * The index of the glyph being modified.
3663 *
3664 * n_points ::
3665 * The number of the points in the glyph, including
3666 * phantom points.
3667 *
3668 * @InOut:
3669 * outline ::
3670 * The outline to change.
3671 *
3672 * @Return:
3673 * FreeType error code. 0 means success.
3674 */
3675 FT_LOCAL_DEF( FT_Error )
3676 TT_Vary_Apply_Glyph_Deltas( TT_Face face,
3677 FT_UInt glyph_index,
3678 FT_Outline* outline,
3679 FT_UInt n_points )
3680 {
3681 FT_Error error;
3682 FT_Stream stream = face->root.stream;
3683 FT_Memory memory = stream->memory;
3684
3685 FT_Vector* points_org = NULL; /* coordinates in 16.16 format */
3686 FT_Vector* points_out = NULL; /* coordinates in 16.16 format */
3687 FT_Bool* has_delta = NULL;
3688
3689 FT_ULong glyph_start;
3690
3691 FT_UInt tupleCount;
3692 FT_ULong offsetToData;
3693 FT_ULong dataSize;
3694
3695 FT_ULong here;
3696 FT_UInt i, j;
3697
3698 FT_Fixed* tuple_coords = NULL;
3700 FT_Fixed* im_end_coords = NULL;
3701
3702 GX_Blend blend = face->blend;
3703
3704 FT_UInt point_count;
3705 FT_UInt spoint_count = 0;
3706
3707 FT_UShort* sharedpoints = NULL;
3708 FT_UShort* localpoints = NULL;
3709 FT_UShort* points;
3710
3711 FT_Fixed* deltas_x = NULL;
3712 FT_Fixed* deltas_y = NULL;
3713 FT_Fixed* point_deltas_x = NULL;
3714 FT_Fixed* point_deltas_y = NULL;
3715
3716
3717 if ( !face->doblend || !blend )
3718 return FT_THROW( Invalid_Argument );
3719
3720 if ( glyph_index >= blend->gv_glyphcnt ||
3721 blend->glyphoffsets[glyph_index] ==
3722 blend->glyphoffsets[glyph_index + 1] )
3723 {
3724 FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
3725 " no variation data for this glyph\n" ));
3726 return FT_Err_Ok;
3727 }
3728
3729 if ( FT_NEW_ARRAY( points_org, n_points ) ||
3730 FT_NEW_ARRAY( points_out, n_points ) ||
3731 FT_NEW_ARRAY( has_delta, n_points ) )
3732 goto Fail1;
3733
3734 dataSize = blend->glyphoffsets[glyph_index + 1] -
3735 blend->glyphoffsets[glyph_index];
3736
3737 if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) ||
3738 FT_FRAME_ENTER( dataSize ) )
3739 goto Fail1;
3790 {
3791 points_org[j].x = FT_intToFixed( outline->points[j].x );
3792 points_org[j].y = FT_intToFixed( outline->points[j].y );
3793 }
3794
3795 for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
3796 {
3797 FT_UInt tupleDataSize;
3798 FT_UInt tupleIndex;
3799 FT_Fixed apply;
3800
3801
3802 FT_TRACE6(( " tuple %d:\n", i ));
3803
3804 tupleDataSize = FT_GET_USHORT();
3805 tupleIndex = FT_GET_USHORT();
3806
3807 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
3808 {
3809 for ( j = 0; j < blend->num_axis; j++ )
3810 tuple_coords[j] = FT_GET_SHORT() * 4; /* convert from */
3811 /* short frac to fixed */
3812 }
3813 else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
3814 {
3815 FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
3816 " invalid tuple index\n" ));
3817
3818 error = FT_THROW( Invalid_Table );
3819 goto Fail3;
3820 }
3821 else
3822 FT_MEM_COPY(
3823 tuple_coords,
3824 blend->tuplecoords +
3825 ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis,
3826 blend->num_axis * sizeof ( FT_Fixed ) );
3827
3828 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
3829 {
3830 for ( j = 0; j < blend->num_axis; j++ )
3831 im_start_coords[j] = FT_GET_SHORT() * 4;
3832 for ( j = 0; j < blend->num_axis; j++ )
3833 im_end_coords[j] = FT_GET_SHORT() * 4;
3834 }
3835
3836 apply = ft_var_apply_tuple( blend,
3837 (FT_UShort)tupleIndex,
3838 tuple_coords,
3839 im_start_coords,
3840 im_end_coords );
3841
3842 if ( apply == 0 ) /* tuple isn't active for our blend */
3843 {
3844 offsetToData += tupleDataSize;
3845 continue;
3846 }
3847
3848 here = FT_Stream_FTell( stream );
3849
3850 FT_Stream_SeekSet( stream, offsetToData );
3851
3852 if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
3853 {
4047 #ifdef FT_DEBUG_LEVEL_TRACE
4048 if ( !count )
4049 FT_TRACE7(( " none\n" ));
4050 #endif
4051 }
4052
4053 if ( localpoints != ALL_POINTS )
4054 FT_FREE( localpoints );
4055 FT_FREE( deltas_x );
4056 FT_FREE( deltas_y );
4057
4058 offsetToData += tupleDataSize;
4059
4060 FT_Stream_SeekSet( stream, here );
4061 }
4062
4063 FT_TRACE5(( "\n" ));
4064
4065 for ( i = 0; i < n_points; i++ )
4066 {
4067 outline->points[i].x += FT_fixedToInt( point_deltas_x[i] );
4068 outline->points[i].y += FT_fixedToInt( point_deltas_y[i] );
4069 }
4070
4071 Fail3:
4072 FT_FREE( point_deltas_x );
4073 FT_FREE( point_deltas_y );
4074
4075 Fail2:
4076 if ( sharedpoints != ALL_POINTS )
4077 FT_FREE( sharedpoints );
4078 FT_FREE( tuple_coords );
4079 FT_FREE( im_start_coords );
4080 FT_FREE( im_end_coords );
4081
4082 FT_FRAME_EXIT();
4083
4084 Fail1:
4085 FT_FREE( points_org );
4086 FT_FREE( points_out );
|
55 #include "tterrors.h"
56
57
58 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
59
60
61 #define FT_Stream_FTell( stream ) \
62 (FT_ULong)( (stream)->cursor - (stream)->base )
63 #define FT_Stream_SeekSet( stream, off ) \
64 (stream)->cursor = \
65 ( (off) < (FT_ULong)( (stream)->limit - (stream)->base ) ) \
66 ? (stream)->base + (off) \
67 : (stream)->limit
68
69
70 /* some macros we need */
71 #define FT_fdot14ToFixed( x ) \
72 ( (FT_Fixed)( (FT_ULong)(x) << 2 ) )
73 #define FT_intToFixed( i ) \
74 ( (FT_Fixed)( (FT_ULong)(i) << 16 ) )
75 #define FT_fdot6ToFixed( i ) \
76 ( (FT_Fixed)( (FT_ULong)(i) << 10 ) )
77 #define FT_fixedToInt( x ) \
78 ( (FT_Short)( ( (x) + 0x8000U ) >> 16 ) )
79 #define FT_fixedToFdot6( x ) \
80 ( (FT_Pos)( ( (x) + 0x200 ) >> 10 ) )
81
82
83 /**************************************************************************
84 *
85 * The macro FT_COMPONENT is used in trace mode. It is an implicit
86 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
87 * messages during execution.
88 */
89 #undef FT_COMPONENT
90 #define FT_COMPONENT ttgxvar
91
92
93 /*************************************************************************/
94 /*************************************************************************/
95 /***** *****/
96 /***** Internal Routines *****/
97 /***** *****/
98 /*************************************************************************/
99 /*************************************************************************/
100
384 {
385 FT_TRACE5(( " axis %d:\n", i ));
386
387 segment->pairCount = FT_GET_USHORT();
388 if ( (FT_ULong)segment->pairCount * 4 > table_len ||
389 FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) )
390 {
391 /* Failure. Free everything we have done so far. We must do */
392 /* it right now since loading the `avar' table is optional. */
393
394 for ( j = i - 1; j >= 0; j-- )
395 FT_FREE( blend->avar_segment[j].correspondence );
396
397 FT_FREE( blend->avar_segment );
398 blend->avar_segment = NULL;
399 goto Exit;
400 }
401
402 for ( j = 0; j < segment->pairCount; j++ )
403 {
404 segment->correspondence[j].fromCoord =
405 FT_fdot14ToFixed( FT_GET_SHORT() );
406 segment->correspondence[j].toCoord =
407 FT_fdot14ToFixed( FT_GET_SHORT() );
408
409 FT_TRACE5(( " mapping %.5f to %.5f\n",
410 segment->correspondence[j].fromCoord / 65536.0,
411 segment->correspondence[j].toCoord / 65536.0 ));
412 }
413
414 FT_TRACE5(( "\n" ));
415 }
416
417 Exit:
418 FT_FRAME_EXIT();
419 }
420
421
422 static FT_Error
423 ft_var_load_item_variation_store( TT_Face face,
424 FT_ULong offset,
425 GX_ItemVarStore itemStore )
426 {
427 FT_Stream stream = FT_FACE_STREAM( face );
1604 FT_FRAME_EXIT();
1605 if ( error )
1606 goto Exit;
1607
1608 if ( blend->tuplecount != 0 )
1609 {
1610 if ( FT_NEW_ARRAY( blend->tuplecoords,
1611 gvar_head.axisCount * blend->tuplecount ) )
1612 goto Exit;
1613
1614 if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) ||
1615 FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) )
1616 goto Exit;
1617
1618 for ( i = 0; i < blend->tuplecount; i++ )
1619 {
1620 FT_TRACE5(( " [ " ));
1621 for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ )
1622 {
1623 blend->tuplecoords[i * gvar_head.axisCount + j] =
1624 FT_fdot14ToFixed( FT_GET_SHORT() );
1625 FT_TRACE5(( "%.5f ",
1626 blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 ));
1627 }
1628 FT_TRACE5(( "]\n" ));
1629 }
1630
1631 FT_TRACE5(( "\n" ));
1632
1633 FT_FRAME_EXIT();
1634 }
1635
1636 Exit:
1637 return error;
1638 }
1639
1640
1641 /**************************************************************************
1642 *
1643 * @Function:
1644 * ft_var_apply_tuple
3042 FT_MM_Var* mmvar;
3043
3044 FT_UInt num_instances;
3045
3046
3047 if ( !face->blend )
3048 {
3049 if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
3050 goto Exit;
3051 }
3052
3053 blend = face->blend;
3054 mmvar = blend->mmvar;
3055
3056 num_instances = (FT_UInt)face->root.style_flags >> 16;
3057
3058 /* `instance_index' starts with value 1, thus `>' */
3059 if ( instance_index > num_instances )
3060 goto Exit;
3061
3062 if ( instance_index > 0 )
3063 {
3064 FT_Memory memory = face->root.memory;
3065 SFNT_Service sfnt = (SFNT_Service)face->sfnt;
3066
3067 FT_Var_Named_Style* named_style;
3068 FT_String* style_name;
3069
3070
3071 named_style = mmvar->namedstyle + instance_index - 1;
3072
3073 error = sfnt->get_name( face,
3074 (FT_UShort)named_style->strid,
3075 &style_name );
3076 if ( error )
3077 goto Exit;
3078
3079 /* set (or replace) style name */
3080 FT_FREE( face->root.style_name );
3081 face->root.style_name = style_name;
3082
3083 /* finally, select the named instance */
3084 error = TT_Set_Var_Design( face,
3085 mmvar->num_axis,
3086 named_style->coords );
3087 if ( error )
3088 {
3089 /* internal error code -1 means `no change' */
3090 if ( error == -1 )
3091 error = FT_Err_Ok;
3092 goto Exit;
3093 }
3094 }
3095 else
3096 error = TT_Set_Var_Design( face, 0, NULL );
3097
3098 face->root.face_index = ( instance_index << 16 ) |
3099 ( face->root.face_index & 0xFFFFL );
3100 face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
3101
3102 Exit:
3103 return error;
3104 }
3105
3106
3107 /*************************************************************************/
3108 /*************************************************************************/
3109 /***** *****/
3110 /***** GX VAR PARSING ROUTINES *****/
3111 /***** *****/
3112 /*************************************************************************/
3113 /*************************************************************************/
3114
3115
3116 static FT_Error
3117 tt_cvt_ready_iterator( FT_ListNode node,
3118 void* user )
3119 {
3120 TT_Size size = (TT_Size)node->data;
3121
3122 FT_UNUSED( user );
3123
3124
3125 size->cvt_ready = -1;
3126
3127 return FT_Err_Ok;
3128 }
3129
3130
3131 /**************************************************************************
3132 *
3133 * @Function:
3134 * tt_face_vary_cvt
3135 *
3136 * @Description:
3137 * Modify the loaded cvt table according to the `cvar' table and the
3138 * font's blend.
3139 *
3140 * @InOut:
3141 * face ::
3142 * A handle to the target face object.
3143 *
3144 * @Input:
3145 * stream ::
3146 * A handle to the input stream.
3147 *
3148 * @Return:
3149 * FreeType error code. 0 means success.
3150 *
3151 * Most errors are ignored. It is perfectly valid not to have a
3152 * `cvar' table even if there is a `gvar' and `fvar' table.
3153 */
3154 FT_LOCAL_DEF( FT_Error )
3155 tt_face_vary_cvt( TT_Face face,
3156 FT_Stream stream )
3157 {
3158 FT_Error error;
3159 FT_Memory memory = stream->memory;
3160
3161 FT_Face root = &face->root;
3162
3163 FT_ULong table_start;
3164 FT_ULong table_len;
3165
3166 FT_UInt tupleCount;
3167 FT_ULong offsetToData;
3168
3169 FT_ULong here;
3170 FT_UInt i, j;
3171
3172 FT_Fixed* tuple_coords = NULL;
3173 FT_Fixed* im_start_coords = NULL;
3174 FT_Fixed* im_end_coords = NULL;
3175
3176 GX_Blend blend = face->blend;
3177
3178 FT_UInt point_count;
3179 FT_UInt spoint_count = 0;
3180
3181 FT_UShort* sharedpoints = NULL;
3182 FT_UShort* localpoints = NULL;
3271 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" ));
3272
3273 if ( FT_NEW_ARRAY( cvt_deltas, face->cvt_size ) )
3274 goto FExit;
3275
3276 for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
3277 {
3278 FT_UInt tupleDataSize;
3279 FT_UInt tupleIndex;
3280 FT_Fixed apply;
3281
3282
3283 FT_TRACE6(( " tuple %d:\n", i ));
3284
3285 tupleDataSize = FT_GET_USHORT();
3286 tupleIndex = FT_GET_USHORT();
3287
3288 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
3289 {
3290 for ( j = 0; j < blend->num_axis; j++ )
3291 tuple_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() );
3292 }
3293 else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
3294 {
3295 FT_TRACE2(( "tt_face_vary_cvt:"
3296 " invalid tuple index\n" ));
3297
3298 error = FT_THROW( Invalid_Table );
3299 goto FExit;
3300 }
3301 else
3302 {
3303 if ( !blend->tuplecoords )
3304 {
3305 FT_TRACE2(( "tt_face_vary_cvt:"
3306 " no valid tuple coordinates available\n" ));
3307
3308 error = FT_THROW( Invalid_Table );
3309 goto FExit;
3310 }
3311
3312 FT_MEM_COPY(
3313 tuple_coords,
3314 blend->tuplecoords +
3315 ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis,
3316 blend->num_axis * sizeof ( FT_Fixed ) );
3317 }
3318
3319 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
3320 {
3321 for ( j = 0; j < blend->num_axis; j++ )
3322 im_start_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() );
3323 for ( j = 0; j < blend->num_axis; j++ )
3324 im_end_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() );
3325 }
3326
3327 apply = ft_var_apply_tuple( blend,
3328 (FT_UShort)tupleIndex,
3329 tuple_coords,
3330 im_start_coords,
3331 im_end_coords );
3332
3333 if ( apply == 0 ) /* tuple isn't active for our blend */
3334 {
3335 offsetToData += tupleDataSize;
3336 continue;
3337 }
3338
3339 here = FT_Stream_FTell( stream );
3340
3341 FT_Stream_SeekSet( stream, offsetToData );
3342
3343 if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
3344 {
3369 int count = 0;
3370 #endif
3371
3372
3373 FT_TRACE7(( " CVT deltas:\n" ));
3374
3375 /* this means that there are deltas for every entry in cvt */
3376 for ( j = 0; j < face->cvt_size; j++ )
3377 {
3378 FT_Fixed old_cvt_delta;
3379
3380
3381 old_cvt_delta = cvt_deltas[j];
3382 cvt_deltas[j] = old_cvt_delta + FT_MulFix( deltas[j], apply );
3383
3384 #ifdef FT_DEBUG_LEVEL_TRACE
3385 if ( old_cvt_delta != cvt_deltas[j] )
3386 {
3387 FT_TRACE7(( " %d: %f -> %f\n",
3388 j,
3389 ( FT_fdot6ToFixed( face->cvt[j] ) +
3390 old_cvt_delta ) / 65536.0,
3391 ( FT_fdot6ToFixed( face->cvt[j] ) +
3392 cvt_deltas[j] ) / 65536.0 ));
3393 count++;
3394 }
3395 #endif
3396 }
3397
3398 #ifdef FT_DEBUG_LEVEL_TRACE
3399 if ( !count )
3400 FT_TRACE7(( " none\n" ));
3401 #endif
3402 }
3403
3404 else
3405 {
3406 #ifdef FT_DEBUG_LEVEL_TRACE
3407 int count = 0;
3408 #endif
3409
3410
3411 FT_TRACE7(( " CVT deltas:\n" ));
3412
3413 for ( j = 0; j < point_count; j++ )
3414 {
3415 int pindex;
3416 FT_Fixed old_cvt_delta;
3417
3418
3419 pindex = points[j];
3420 if ( (FT_ULong)pindex >= face->cvt_size )
3421 continue;
3422
3423 old_cvt_delta = cvt_deltas[pindex];
3424 cvt_deltas[pindex] = old_cvt_delta + FT_MulFix( deltas[j], apply );
3425
3426 #ifdef FT_DEBUG_LEVEL_TRACE
3427 if ( old_cvt_delta != cvt_deltas[pindex] )
3428 {
3429 FT_TRACE7(( " %d: %f -> %f\n",
3430 pindex,
3431 ( FT_fdot6ToFixed( face->cvt[pindex] ) +
3432 old_cvt_delta ) / 65536.0,
3433 ( FT_fdot6ToFixed( face->cvt[pindex] ) +
3434 cvt_deltas[pindex] ) / 65536.0 ));
3435 count++;
3436 }
3437 #endif
3438 }
3439
3440 #ifdef FT_DEBUG_LEVEL_TRACE
3441 if ( !count )
3442 FT_TRACE7(( " none\n" ));
3443 #endif
3444 }
3445
3446 if ( localpoints != ALL_POINTS )
3447 FT_FREE( localpoints );
3448 FT_FREE( deltas );
3449
3450 offsetToData += tupleDataSize;
3451
3452 FT_Stream_SeekSet( stream, here );
3453 }
3454
3455 FT_TRACE5(( "\n" ));
3456
3457 for ( i = 0; i < face->cvt_size; i++ )
3458 face->cvt[i] += FT_fixedToFdot6( cvt_deltas[i] );
3459
3460 FExit:
3461 FT_FRAME_EXIT();
3462
3463 Exit:
3464 if ( sharedpoints != ALL_POINTS )
3465 FT_FREE( sharedpoints );
3466 FT_FREE( tuple_coords );
3467 FT_FREE( im_start_coords );
3468 FT_FREE( im_end_coords );
3469 FT_FREE( cvt_deltas );
3470
3471 /* iterate over all FT_Size objects and set `cvt_ready' to -1 */
3472 /* to trigger rescaling of all CVT values */
3473 FT_List_Iterate( &root->sizes_list,
3474 tt_cvt_ready_iterator,
3475 NULL );
3476
3477 return error;
3478 }
3479
3480
3481 /* Shift the original coordinates of all points between indices `p1' */
3482 /* and `p2', using the same difference as given by index `ref'. */
3483
3484 /* modeled after `af_iup_shift' */
3485
3486 static void
3487 tt_delta_shift( int p1,
3488 int p2,
3489 int ref,
3490 FT_Vector* in_points,
3491 FT_Vector* out_points )
3492 {
3493 int p;
3494 FT_Vector delta;
3495
3496
3684 * TT_Vary_Apply_Glyph_Deltas
3685 *
3686 * @Description:
3687 * Apply the appropriate deltas to the current glyph.
3688 *
3689 * @Input:
3690 * face ::
3691 * A handle to the target face object.
3692 *
3693 * glyph_index ::
3694 * The index of the glyph being modified.
3695 *
3696 * n_points ::
3697 * The number of the points in the glyph, including
3698 * phantom points.
3699 *
3700 * @InOut:
3701 * outline ::
3702 * The outline to change.
3703 *
3704 * @Output:
3705 * unrounded ::
3706 * An array with `n_points' elements that is filled with unrounded
3707 * point coordinates (in 26.6 format).
3708 *
3709 * @Return:
3710 * FreeType error code. 0 means success.
3711 */
3712 FT_LOCAL_DEF( FT_Error )
3713 TT_Vary_Apply_Glyph_Deltas( TT_Face face,
3714 FT_UInt glyph_index,
3715 FT_Outline* outline,
3716 FT_Vector* unrounded,
3717 FT_UInt n_points )
3718 {
3719 FT_Error error;
3720 FT_Stream stream = face->root.stream;
3721 FT_Memory memory = stream->memory;
3722
3723 FT_Vector* points_org = NULL; /* coordinates in 16.16 format */
3724 FT_Vector* points_out = NULL; /* coordinates in 16.16 format */
3725 FT_Bool* has_delta = NULL;
3726
3727 FT_ULong glyph_start;
3728
3729 FT_UInt tupleCount;
3730 FT_ULong offsetToData;
3731 FT_ULong dataSize;
3732
3733 FT_ULong here;
3734 FT_UInt i, j;
3735
3736 FT_Fixed* tuple_coords = NULL;
3738 FT_Fixed* im_end_coords = NULL;
3739
3740 GX_Blend blend = face->blend;
3741
3742 FT_UInt point_count;
3743 FT_UInt spoint_count = 0;
3744
3745 FT_UShort* sharedpoints = NULL;
3746 FT_UShort* localpoints = NULL;
3747 FT_UShort* points;
3748
3749 FT_Fixed* deltas_x = NULL;
3750 FT_Fixed* deltas_y = NULL;
3751 FT_Fixed* point_deltas_x = NULL;
3752 FT_Fixed* point_deltas_y = NULL;
3753
3754
3755 if ( !face->doblend || !blend )
3756 return FT_THROW( Invalid_Argument );
3757
3758 for ( i = 0; i < n_points; i++ )
3759 {
3760 unrounded[i].x = INT_TO_F26DOT6( outline->points[i].x );
3761 unrounded[i].y = INT_TO_F26DOT6( outline->points[i].y );
3762 }
3763
3764 if ( glyph_index >= blend->gv_glyphcnt ||
3765 blend->glyphoffsets[glyph_index] ==
3766 blend->glyphoffsets[glyph_index + 1] )
3767 {
3768 FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
3769 " no variation data for this glyph\n" ));
3770 return FT_Err_Ok;
3771 }
3772
3773 if ( FT_NEW_ARRAY( points_org, n_points ) ||
3774 FT_NEW_ARRAY( points_out, n_points ) ||
3775 FT_NEW_ARRAY( has_delta, n_points ) )
3776 goto Fail1;
3777
3778 dataSize = blend->glyphoffsets[glyph_index + 1] -
3779 blend->glyphoffsets[glyph_index];
3780
3781 if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) ||
3782 FT_FRAME_ENTER( dataSize ) )
3783 goto Fail1;
3834 {
3835 points_org[j].x = FT_intToFixed( outline->points[j].x );
3836 points_org[j].y = FT_intToFixed( outline->points[j].y );
3837 }
3838
3839 for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
3840 {
3841 FT_UInt tupleDataSize;
3842 FT_UInt tupleIndex;
3843 FT_Fixed apply;
3844
3845
3846 FT_TRACE6(( " tuple %d:\n", i ));
3847
3848 tupleDataSize = FT_GET_USHORT();
3849 tupleIndex = FT_GET_USHORT();
3850
3851 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
3852 {
3853 for ( j = 0; j < blend->num_axis; j++ )
3854 tuple_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() );
3855 }
3856 else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
3857 {
3858 FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
3859 " invalid tuple index\n" ));
3860
3861 error = FT_THROW( Invalid_Table );
3862 goto Fail3;
3863 }
3864 else
3865 FT_MEM_COPY(
3866 tuple_coords,
3867 blend->tuplecoords +
3868 ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis,
3869 blend->num_axis * sizeof ( FT_Fixed ) );
3870
3871 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
3872 {
3873 for ( j = 0; j < blend->num_axis; j++ )
3874 im_start_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() );
3875 for ( j = 0; j < blend->num_axis; j++ )
3876 im_end_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() );
3877 }
3878
3879 apply = ft_var_apply_tuple( blend,
3880 (FT_UShort)tupleIndex,
3881 tuple_coords,
3882 im_start_coords,
3883 im_end_coords );
3884
3885 if ( apply == 0 ) /* tuple isn't active for our blend */
3886 {
3887 offsetToData += tupleDataSize;
3888 continue;
3889 }
3890
3891 here = FT_Stream_FTell( stream );
3892
3893 FT_Stream_SeekSet( stream, offsetToData );
3894
3895 if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
3896 {
4090 #ifdef FT_DEBUG_LEVEL_TRACE
4091 if ( !count )
4092 FT_TRACE7(( " none\n" ));
4093 #endif
4094 }
4095
4096 if ( localpoints != ALL_POINTS )
4097 FT_FREE( localpoints );
4098 FT_FREE( deltas_x );
4099 FT_FREE( deltas_y );
4100
4101 offsetToData += tupleDataSize;
4102
4103 FT_Stream_SeekSet( stream, here );
4104 }
4105
4106 FT_TRACE5(( "\n" ));
4107
4108 for ( i = 0; i < n_points; i++ )
4109 {
4110 unrounded[i].x += FT_fixedToFdot6( point_deltas_x[i] );
4111 unrounded[i].y += FT_fixedToFdot6( point_deltas_y[i] );
4112
4113 outline->points[i].x += FT_fixedToInt( point_deltas_x[i] );
4114 outline->points[i].y += FT_fixedToInt( point_deltas_y[i] );
4115 }
4116
4117 Fail3:
4118 FT_FREE( point_deltas_x );
4119 FT_FREE( point_deltas_y );
4120
4121 Fail2:
4122 if ( sharedpoints != ALL_POINTS )
4123 FT_FREE( sharedpoints );
4124 FT_FREE( tuple_coords );
4125 FT_FREE( im_start_coords );
4126 FT_FREE( im_end_coords );
4127
4128 FT_FRAME_EXIT();
4129
4130 Fail1:
4131 FT_FREE( points_org );
4132 FT_FREE( points_out );
|