| 1 | /***************************************************************************/ | 
|---|
| 2 | /*                                                                         */ | 
|---|
| 3 | /*  ttgxvar.c                                                              */ | 
|---|
| 4 | /*                                                                         */ | 
|---|
| 5 | /*    TrueType GX Font Variation loader                                    */ | 
|---|
| 6 | /*                                                                         */ | 
|---|
| 7 | /*  Copyright 2004-2018 by                                                 */ | 
|---|
| 8 | /*  David Turner, Robert Wilhelm, Werner Lemberg, and George Williams.     */ | 
|---|
| 9 | /*                                                                         */ | 
|---|
| 10 | /*  This file is part of the FreeType project, and may only be used,       */ | 
|---|
| 11 | /*  modified, and distributed under the terms of the FreeType project      */ | 
|---|
| 12 | /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */ | 
|---|
| 13 | /*  this file you indicate that you have read the license and              */ | 
|---|
| 14 | /*  understand and accept it fully.                                        */ | 
|---|
| 15 | /*                                                                         */ | 
|---|
| 16 | /***************************************************************************/ | 
|---|
| 17 |  | 
|---|
| 18 |  | 
|---|
| 19 | /*************************************************************************/ | 
|---|
| 20 | /*                                                                       */ | 
|---|
| 21 | /* Apple documents the `fvar', `gvar', `cvar', and `avar' tables at      */ | 
|---|
| 22 | /*                                                                       */ | 
|---|
| 23 | /*   https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6[fgca]var.html */ | 
|---|
| 24 | /*                                                                       */ | 
|---|
| 25 | /* The documentation for `gvar' is not intelligible; `cvar' refers you   */ | 
|---|
| 26 | /* to `gvar' and is thus also incomprehensible.                          */ | 
|---|
| 27 | /*                                                                       */ | 
|---|
| 28 | /* The documentation for `avar' appears correct, but Apple has no fonts  */ | 
|---|
| 29 | /* with an `avar' table, so it is hard to test.                          */ | 
|---|
| 30 | /*                                                                       */ | 
|---|
| 31 | /* Many thanks to John Jenkins (at Apple) in figuring this out.          */ | 
|---|
| 32 | /*                                                                       */ | 
|---|
| 33 | /*                                                                       */ | 
|---|
| 34 | /* Apple's `kern' table has some references to tuple indices, but as     */ | 
|---|
| 35 | /* there is no indication where these indices are defined, nor how to    */ | 
|---|
| 36 | /* interpolate the kerning values (different tuples have different       */ | 
|---|
| 37 | /* classes) this issue is ignored.                                       */ | 
|---|
| 38 | /*                                                                       */ | 
|---|
| 39 | /*************************************************************************/ | 
|---|
| 40 |  | 
|---|
| 41 |  | 
|---|
| 42 | #include <ft2build.h> | 
|---|
| 43 | #include FT_INTERNAL_DEBUG_H | 
|---|
| 44 | #include FT_CONFIG_CONFIG_H | 
|---|
| 45 | #include FT_INTERNAL_STREAM_H | 
|---|
| 46 | #include FT_INTERNAL_SFNT_H | 
|---|
| 47 | #include FT_TRUETYPE_TAGS_H | 
|---|
| 48 | #include FT_TRUETYPE_IDS_H | 
|---|
| 49 | #include FT_MULTIPLE_MASTERS_H | 
|---|
| 50 | #include FT_LIST_H | 
|---|
| 51 |  | 
|---|
| 52 | #include "ttpload.h" | 
|---|
| 53 | #include "ttgxvar.h" | 
|---|
| 54 |  | 
|---|
| 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 | /*************************************************************************/ | 
|---|
| 71 | /*                                                                       */ | 
|---|
| 72 | /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */ | 
|---|
| 73 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */ | 
|---|
| 74 | /* messages during execution.                                            */ | 
|---|
| 75 | /*                                                                       */ | 
|---|
| 76 | #undef  FT_COMPONENT | 
|---|
| 77 | #define FT_COMPONENT  trace_ttgxvar | 
|---|
| 78 |  | 
|---|
| 79 |  | 
|---|
| 80 | /*************************************************************************/ | 
|---|
| 81 | /*************************************************************************/ | 
|---|
| 82 | /*****                                                               *****/ | 
|---|
| 83 | /*****                       Internal Routines                       *****/ | 
|---|
| 84 | /*****                                                               *****/ | 
|---|
| 85 | /*************************************************************************/ | 
|---|
| 86 | /*************************************************************************/ | 
|---|
| 87 |  | 
|---|
| 88 |  | 
|---|
| 89 | /*************************************************************************/ | 
|---|
| 90 | /*                                                                       */ | 
|---|
| 91 | /* The macro ALL_POINTS is used in `ft_var_readpackedpoints'.  It        */ | 
|---|
| 92 | /* indicates that there is a delta for every point without needing to    */ | 
|---|
| 93 | /* enumerate all of them.                                                */ | 
|---|
| 94 | /*                                                                       */ | 
|---|
| 95 |  | 
|---|
| 96 | /* ensure that value `0' has the same width as a pointer */ | 
|---|
| 97 | #define ALL_POINTS  (FT_UShort*)~(FT_PtrDist)0 | 
|---|
| 98 |  | 
|---|
| 99 |  | 
|---|
| 100 | #define GX_PT_POINTS_ARE_WORDS      0x80U | 
|---|
| 101 | #define GX_PT_POINT_RUN_COUNT_MASK  0x7FU | 
|---|
| 102 |  | 
|---|
| 103 |  | 
|---|
| 104 | /*************************************************************************/ | 
|---|
| 105 | /*                                                                       */ | 
|---|
| 106 | /* <Function>                                                            */ | 
|---|
| 107 | /*    ft_var_readpackedpoints                                            */ | 
|---|
| 108 | /*                                                                       */ | 
|---|
| 109 | /* <Description>                                                         */ | 
|---|
| 110 | /*    Read a set of points to which the following deltas will apply.     */ | 
|---|
| 111 | /*    Points are packed with a run length encoding.                      */ | 
|---|
| 112 | /*                                                                       */ | 
|---|
| 113 | /* <Input>                                                               */ | 
|---|
| 114 | /*    stream    :: The data stream.                                      */ | 
|---|
| 115 | /*                                                                       */ | 
|---|
| 116 | /*    size      :: The size of the table holding the data.               */ | 
|---|
| 117 | /*                                                                       */ | 
|---|
| 118 | /* <Output>                                                              */ | 
|---|
| 119 | /*    point_cnt :: The number of points read.  A zero value means that   */ | 
|---|
| 120 | /*                 all points in the glyph will be affected, without     */ | 
|---|
| 121 | /*                 enumerating them individually.                        */ | 
|---|
| 122 | /*                                                                       */ | 
|---|
| 123 | /* <Return>                                                              */ | 
|---|
| 124 | /*    An array of FT_UShort containing the affected points or the        */ | 
|---|
| 125 | /*    special value ALL_POINTS.                                          */ | 
|---|
| 126 | /*                                                                       */ | 
|---|
| 127 | static FT_UShort* | 
|---|
| 128 | ft_var_readpackedpoints( FT_Stream  stream, | 
|---|
| 129 | FT_ULong   size, | 
|---|
| 130 | FT_UInt   *point_cnt ) | 
|---|
| 131 | { | 
|---|
| 132 | FT_UShort *points = NULL; | 
|---|
| 133 | FT_UInt    n; | 
|---|
| 134 | FT_UInt    runcnt; | 
|---|
| 135 | FT_UInt    i, j; | 
|---|
| 136 | FT_UShort  first; | 
|---|
| 137 | FT_Memory  memory = stream->memory; | 
|---|
| 138 | FT_Error   error  = FT_Err_Ok; | 
|---|
| 139 |  | 
|---|
| 140 | FT_UNUSED( error ); | 
|---|
| 141 |  | 
|---|
| 142 |  | 
|---|
| 143 | *point_cnt = 0; | 
|---|
| 144 |  | 
|---|
| 145 | n = FT_GET_BYTE(); | 
|---|
| 146 | if ( n == 0 ) | 
|---|
| 147 | return ALL_POINTS; | 
|---|
| 148 |  | 
|---|
| 149 | if ( n & GX_PT_POINTS_ARE_WORDS ) | 
|---|
| 150 | { | 
|---|
| 151 | n  &= GX_PT_POINT_RUN_COUNT_MASK; | 
|---|
| 152 | n <<= 8; | 
|---|
| 153 | n  |= FT_GET_BYTE(); | 
|---|
| 154 | } | 
|---|
| 155 |  | 
|---|
| 156 | if ( n > size ) | 
|---|
| 157 | { | 
|---|
| 158 | FT_TRACE1(( "ft_var_readpackedpoints: number of points too large\n")); | 
|---|
| 159 | return NULL; | 
|---|
| 160 | } | 
|---|
| 161 |  | 
|---|
| 162 | /* in the nested loops below we increase `i' twice; */ | 
|---|
| 163 | /* it is faster to simply allocate one more slot    */ | 
|---|
| 164 | /* than to add another test within the loop         */ | 
|---|
| 165 | if ( FT_NEW_ARRAY( points, n + 1 ) ) | 
|---|
| 166 | return NULL; | 
|---|
| 167 |  | 
|---|
| 168 | *point_cnt = n; | 
|---|
| 169 |  | 
|---|
| 170 | first = 0; | 
|---|
| 171 | i     = 0; | 
|---|
| 172 | while ( i < n ) | 
|---|
| 173 | { | 
|---|
| 174 | runcnt = FT_GET_BYTE(); | 
|---|
| 175 | if ( runcnt & GX_PT_POINTS_ARE_WORDS ) | 
|---|
| 176 | { | 
|---|
| 177 | runcnt     &= GX_PT_POINT_RUN_COUNT_MASK; | 
|---|
| 178 | first      += FT_GET_USHORT(); | 
|---|
| 179 | points[i++] = first; | 
|---|
| 180 |  | 
|---|
| 181 | /* first point not included in run count */ | 
|---|
| 182 | for ( j = 0; j < runcnt; j++ ) | 
|---|
| 183 | { | 
|---|
| 184 | first      += FT_GET_USHORT(); | 
|---|
| 185 | points[i++] = first; | 
|---|
| 186 | if ( i >= n ) | 
|---|
| 187 | break; | 
|---|
| 188 | } | 
|---|
| 189 | } | 
|---|
| 190 | else | 
|---|
| 191 | { | 
|---|
| 192 | first      += FT_GET_BYTE(); | 
|---|
| 193 | points[i++] = first; | 
|---|
| 194 |  | 
|---|
| 195 | for ( j = 0; j < runcnt; j++ ) | 
|---|
| 196 | { | 
|---|
| 197 | first      += FT_GET_BYTE(); | 
|---|
| 198 | points[i++] = first; | 
|---|
| 199 | if ( i >= n ) | 
|---|
| 200 | break; | 
|---|
| 201 | } | 
|---|
| 202 | } | 
|---|
| 203 | } | 
|---|
| 204 |  | 
|---|
| 205 | return points; | 
|---|
| 206 | } | 
|---|
| 207 |  | 
|---|
| 208 |  | 
|---|
| 209 | #define GX_DT_DELTAS_ARE_ZERO       0x80U | 
|---|
| 210 | #define GX_DT_DELTAS_ARE_WORDS      0x40U | 
|---|
| 211 | #define GX_DT_DELTA_RUN_COUNT_MASK  0x3FU | 
|---|
| 212 |  | 
|---|
| 213 |  | 
|---|
| 214 | /*************************************************************************/ | 
|---|
| 215 | /*                                                                       */ | 
|---|
| 216 | /* <Function>                                                            */ | 
|---|
| 217 | /*    ft_var_readpackeddeltas                                            */ | 
|---|
| 218 | /*                                                                       */ | 
|---|
| 219 | /* <Description>                                                         */ | 
|---|
| 220 | /*    Read a set of deltas.  These are packed slightly differently than  */ | 
|---|
| 221 | /*    points.  In particular there is no overall count.                  */ | 
|---|
| 222 | /*                                                                       */ | 
|---|
| 223 | /* <Input>                                                               */ | 
|---|
| 224 | /*    stream    :: The data stream.                                      */ | 
|---|
| 225 | /*                                                                       */ | 
|---|
| 226 | /*    size      :: The size of the table holding the data.               */ | 
|---|
| 227 | /*                                                                       */ | 
|---|
| 228 | /*    delta_cnt :: The number of deltas to be read.                      */ | 
|---|
| 229 | /*                                                                       */ | 
|---|
| 230 | /* <Return>                                                              */ | 
|---|
| 231 | /*    An array of FT_Short containing the deltas for the affected        */ | 
|---|
| 232 | /*    points.  (This only gets the deltas for one dimension.  It will    */ | 
|---|
| 233 | /*    generally be called twice, once for x, once for y.  When used in   */ | 
|---|
| 234 | /*    cvt table, it will only be called once.)                           */ | 
|---|
| 235 | /*                                                                       */ | 
|---|
| 236 | static FT_Short* | 
|---|
| 237 | ft_var_readpackeddeltas( FT_Stream  stream, | 
|---|
| 238 | FT_ULong   size, | 
|---|
| 239 | FT_UInt    delta_cnt ) | 
|---|
| 240 | { | 
|---|
| 241 | FT_Short  *deltas = NULL; | 
|---|
| 242 | FT_UInt    runcnt, cnt; | 
|---|
| 243 | FT_UInt    i, j; | 
|---|
| 244 | FT_Memory  memory = stream->memory; | 
|---|
| 245 | FT_Error   error  = FT_Err_Ok; | 
|---|
| 246 |  | 
|---|
| 247 | FT_UNUSED( error ); | 
|---|
| 248 |  | 
|---|
| 249 |  | 
|---|
| 250 | if ( delta_cnt > size ) | 
|---|
| 251 | { | 
|---|
| 252 | FT_TRACE1(( "ft_var_readpackeddeltas: number of points too large\n")); | 
|---|
| 253 | return NULL; | 
|---|
| 254 | } | 
|---|
| 255 |  | 
|---|
| 256 | if ( FT_NEW_ARRAY( deltas, delta_cnt ) ) | 
|---|
| 257 | return NULL; | 
|---|
| 258 |  | 
|---|
| 259 | i = 0; | 
|---|
| 260 | while ( i < delta_cnt ) | 
|---|
| 261 | { | 
|---|
| 262 | runcnt = FT_GET_BYTE(); | 
|---|
| 263 | cnt    = runcnt & GX_DT_DELTA_RUN_COUNT_MASK; | 
|---|
| 264 |  | 
|---|
| 265 | if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) | 
|---|
| 266 | { | 
|---|
| 267 | /* `runcnt' zeroes get added */ | 
|---|
| 268 | for ( j = 0; j <= cnt && i < delta_cnt; j++ ) | 
|---|
| 269 | deltas[i++] = 0; | 
|---|
| 270 | } | 
|---|
| 271 | else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) | 
|---|
| 272 | { | 
|---|
| 273 | /* `runcnt' shorts from the stack */ | 
|---|
| 274 | for ( j = 0; j <= cnt && i < delta_cnt; j++ ) | 
|---|
| 275 | deltas[i++] = FT_GET_SHORT(); | 
|---|
| 276 | } | 
|---|
| 277 | else | 
|---|
| 278 | { | 
|---|
| 279 | /* `runcnt' signed bytes from the stack */ | 
|---|
| 280 | for ( j = 0; j <= cnt && i < delta_cnt; j++ ) | 
|---|
| 281 | deltas[i++] = FT_GET_CHAR(); | 
|---|
| 282 | } | 
|---|
| 283 |  | 
|---|
| 284 | if ( j <= cnt ) | 
|---|
| 285 | { | 
|---|
| 286 | /* bad format */ | 
|---|
| 287 | FT_FREE( deltas ); | 
|---|
| 288 | return NULL; | 
|---|
| 289 | } | 
|---|
| 290 | } | 
|---|
| 291 |  | 
|---|
| 292 | return deltas; | 
|---|
| 293 | } | 
|---|
| 294 |  | 
|---|
| 295 |  | 
|---|
| 296 | /*************************************************************************/ | 
|---|
| 297 | /*                                                                       */ | 
|---|
| 298 | /* <Function>                                                            */ | 
|---|
| 299 | /*    ft_var_load_avar                                                   */ | 
|---|
| 300 | /*                                                                       */ | 
|---|
| 301 | /* <Description>                                                         */ | 
|---|
| 302 | /*    Parse the `avar' table if present.  It need not be, so we return   */ | 
|---|
| 303 | /*    nothing.                                                           */ | 
|---|
| 304 | /*                                                                       */ | 
|---|
| 305 | /* <InOut>                                                               */ | 
|---|
| 306 | /*    face :: The font face.                                             */ | 
|---|
| 307 | /*                                                                       */ | 
|---|
| 308 | static void | 
|---|
| 309 | ft_var_load_avar( TT_Face  face ) | 
|---|
| 310 | { | 
|---|
| 311 | FT_Stream       stream = FT_FACE_STREAM( face ); | 
|---|
| 312 | FT_Memory       memory = stream->memory; | 
|---|
| 313 | GX_Blend        blend  = face->blend; | 
|---|
| 314 | GX_AVarSegment  segment; | 
|---|
| 315 | FT_Error        error = FT_Err_Ok; | 
|---|
| 316 | FT_Long         version; | 
|---|
| 317 | FT_Long         axisCount; | 
|---|
| 318 | FT_Int          i, j; | 
|---|
| 319 | FT_ULong        table_len; | 
|---|
| 320 |  | 
|---|
| 321 | FT_UNUSED( error ); | 
|---|
| 322 |  | 
|---|
| 323 |  | 
|---|
| 324 | FT_TRACE2(( "AVAR ")); | 
|---|
| 325 |  | 
|---|
| 326 | blend->avar_loaded = TRUE; | 
|---|
| 327 | error = face->goto_table( face, TTAG_avar, stream, &table_len ); | 
|---|
| 328 | if ( error ) | 
|---|
| 329 | { | 
|---|
| 330 | FT_TRACE2(( "is missing\n")); | 
|---|
| 331 | return; | 
|---|
| 332 | } | 
|---|
| 333 |  | 
|---|
| 334 | if ( FT_FRAME_ENTER( table_len ) ) | 
|---|
| 335 | return; | 
|---|
| 336 |  | 
|---|
| 337 | version   = FT_GET_LONG(); | 
|---|
| 338 | axisCount = FT_GET_LONG(); | 
|---|
| 339 |  | 
|---|
| 340 | if ( version != 0x00010000L ) | 
|---|
| 341 | { | 
|---|
| 342 | FT_TRACE2(( "bad table version\n")); | 
|---|
| 343 | goto Exit; | 
|---|
| 344 | } | 
|---|
| 345 |  | 
|---|
| 346 | FT_TRACE2(( "loaded\n")); | 
|---|
| 347 |  | 
|---|
| 348 | if ( axisCount != (FT_Long)blend->mmvar->num_axis ) | 
|---|
| 349 | { | 
|---|
| 350 | FT_TRACE2(( "ft_var_load_avar: number of axes in `avar' and `fvar'\n" | 
|---|
| 351 | "                  table are different\n")); | 
|---|
| 352 | goto Exit; | 
|---|
| 353 | } | 
|---|
| 354 |  | 
|---|
| 355 | if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) ) | 
|---|
| 356 | goto Exit; | 
|---|
| 357 |  | 
|---|
| 358 | segment = &blend->avar_segment[0]; | 
|---|
| 359 | for ( i = 0; i < axisCount; i++, segment++ ) | 
|---|
| 360 | { | 
|---|
| 361 | FT_TRACE5(( "  axis %d:\n", i )); | 
|---|
| 362 |  | 
|---|
| 363 | segment->pairCount = FT_GET_USHORT(); | 
|---|
| 364 | if ( (FT_ULong)segment->pairCount * 4 > table_len                || | 
|---|
| 365 | FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) ) | 
|---|
| 366 | { | 
|---|
| 367 | /* Failure.  Free everything we have done so far.  We must do */ | 
|---|
| 368 | /* it right now since loading the `avar' table is optional.   */ | 
|---|
| 369 |  | 
|---|
| 370 | for ( j = i - 1; j >= 0; j-- ) | 
|---|
| 371 | FT_FREE( blend->avar_segment[j].correspondence ); | 
|---|
| 372 |  | 
|---|
| 373 | FT_FREE( blend->avar_segment ); | 
|---|
| 374 | blend->avar_segment = NULL; | 
|---|
| 375 | goto Exit; | 
|---|
| 376 | } | 
|---|
| 377 |  | 
|---|
| 378 | for ( j = 0; j < segment->pairCount; j++ ) | 
|---|
| 379 | { | 
|---|
| 380 | /* convert to Fixed */ | 
|---|
| 381 | segment->correspondence[j].fromCoord = FT_GET_SHORT() * 4; | 
|---|
| 382 | segment->correspondence[j].toCoord   = FT_GET_SHORT() * 4; | 
|---|
| 383 |  | 
|---|
| 384 | FT_TRACE5(( "    mapping %.5f to %.5f\n", | 
|---|
| 385 | segment->correspondence[j].fromCoord / 65536.0, | 
|---|
| 386 | segment->correspondence[j].toCoord / 65536.0 )); | 
|---|
| 387 | } | 
|---|
| 388 |  | 
|---|
| 389 | FT_TRACE5(( "\n")); | 
|---|
| 390 | } | 
|---|
| 391 |  | 
|---|
| 392 | Exit: | 
|---|
| 393 | FT_FRAME_EXIT(); | 
|---|
| 394 | } | 
|---|
| 395 |  | 
|---|
| 396 |  | 
|---|
| 397 | /* some macros we need */ | 
|---|
| 398 | #define FT_FIXED_ONE  ( (FT_Fixed)0x10000 ) | 
|---|
| 399 |  | 
|---|
| 400 | #define FT_fdot14ToFixed( x )                \ | 
|---|
| 401 | ( (FT_Fixed)( (FT_ULong)(x) << 2 ) ) | 
|---|
| 402 | #define FT_intToFixed( i )                    \ | 
|---|
| 403 | ( (FT_Fixed)( (FT_ULong)(i) << 16 ) ) | 
|---|
| 404 | #define FT_fixedToInt( x )                                   \ | 
|---|
| 405 | ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) ) | 
|---|
| 406 |  | 
|---|
| 407 |  | 
|---|
| 408 | static FT_Error | 
|---|
| 409 | ft_var_load_item_variation_store( TT_Face          face, | 
|---|
| 410 | FT_ULong         offset, | 
|---|
| 411 | GX_ItemVarStore  itemStore ) | 
|---|
| 412 | { | 
|---|
| 413 | FT_Stream  stream = FT_FACE_STREAM( face ); | 
|---|
| 414 | FT_Memory  memory = stream->memory; | 
|---|
| 415 |  | 
|---|
| 416 | FT_Error   error; | 
|---|
| 417 | FT_UShort  format; | 
|---|
| 418 | FT_ULong   region_offset; | 
|---|
| 419 | FT_UInt    i, j, k; | 
|---|
| 420 | FT_UInt    shortDeltaCount; | 
|---|
| 421 |  | 
|---|
| 422 | GX_Blend        blend = face->blend; | 
|---|
| 423 | GX_ItemVarData  varData; | 
|---|
| 424 |  | 
|---|
| 425 | FT_ULong*  dataOffsetArray = NULL; | 
|---|
| 426 |  | 
|---|
| 427 |  | 
|---|
| 428 | if ( FT_STREAM_SEEK( offset ) || | 
|---|
| 429 | FT_READ_USHORT( format ) ) | 
|---|
| 430 | goto Exit; | 
|---|
| 431 |  | 
|---|
| 432 | if ( format != 1 ) | 
|---|
| 433 | { | 
|---|
| 434 | FT_TRACE2(( "ft_var_load_item_variation_store: bad store format %d\n", | 
|---|
| 435 | format )); | 
|---|
| 436 | error = FT_THROW( Invalid_Table ); | 
|---|
| 437 | goto Exit; | 
|---|
| 438 | } | 
|---|
| 439 |  | 
|---|
| 440 | /* read top level fields */ | 
|---|
| 441 | if ( FT_READ_ULONG( region_offset )         || | 
|---|
| 442 | FT_READ_USHORT( itemStore->dataCount ) ) | 
|---|
| 443 | goto Exit; | 
|---|
| 444 |  | 
|---|
| 445 | /* we need at least one entry in `itemStore->varData' */ | 
|---|
| 446 | if ( !itemStore->dataCount ) | 
|---|
| 447 | { | 
|---|
| 448 | FT_TRACE2(( "ft_var_load_item_variation_store: missing varData\n")); | 
|---|
| 449 | error = FT_THROW( Invalid_Table ); | 
|---|
| 450 | goto Exit; | 
|---|
| 451 | } | 
|---|
| 452 |  | 
|---|
| 453 | /* make temporary copy of item variation data offsets; */ | 
|---|
| 454 | /* we will parse region list first, then come back     */ | 
|---|
| 455 | if ( FT_NEW_ARRAY( dataOffsetArray, itemStore->dataCount ) ) | 
|---|
| 456 | goto Exit; | 
|---|
| 457 |  | 
|---|
| 458 | for ( i = 0; i < itemStore->dataCount; i++ ) | 
|---|
| 459 | { | 
|---|
| 460 | if ( FT_READ_ULONG( dataOffsetArray[i] ) ) | 
|---|
| 461 | goto Exit; | 
|---|
| 462 | } | 
|---|
| 463 |  | 
|---|
| 464 | /* parse array of region records (region list) */ | 
|---|
| 465 | if ( FT_STREAM_SEEK( offset + region_offset ) ) | 
|---|
| 466 | goto Exit; | 
|---|
| 467 |  | 
|---|
| 468 | if ( FT_READ_USHORT( itemStore->axisCount )   || | 
|---|
| 469 | FT_READ_USHORT( itemStore->regionCount ) ) | 
|---|
| 470 | goto Exit; | 
|---|
| 471 |  | 
|---|
| 472 | if ( itemStore->axisCount != (FT_Long)blend->mmvar->num_axis ) | 
|---|
| 473 | { | 
|---|
| 474 | FT_TRACE2(( "ft_var_load_item_variation_store:" | 
|---|
| 475 | " number of axes in item variation store\n" | 
|---|
| 476 | "                                 " | 
|---|
| 477 | " and `fvar' table are different\n")); | 
|---|
| 478 | error = FT_THROW( Invalid_Table ); | 
|---|
| 479 | goto Exit; | 
|---|
| 480 | } | 
|---|
| 481 |  | 
|---|
| 482 | if ( FT_NEW_ARRAY( itemStore->varRegionList, itemStore->regionCount ) ) | 
|---|
| 483 | goto Exit; | 
|---|
| 484 |  | 
|---|
| 485 | for ( i = 0; i < itemStore->regionCount; i++ ) | 
|---|
| 486 | { | 
|---|
| 487 | GX_AxisCoords  axisCoords; | 
|---|
| 488 |  | 
|---|
| 489 |  | 
|---|
| 490 | if ( FT_NEW_ARRAY( itemStore->varRegionList[i].axisList, | 
|---|
| 491 | itemStore->axisCount ) ) | 
|---|
| 492 | goto Exit; | 
|---|
| 493 |  | 
|---|
| 494 | axisCoords = itemStore->varRegionList[i].axisList; | 
|---|
| 495 |  | 
|---|
| 496 | for ( j = 0; j < itemStore->axisCount; j++ ) | 
|---|
| 497 | { | 
|---|
| 498 | FT_Short  start, peak, end; | 
|---|
| 499 |  | 
|---|
| 500 |  | 
|---|
| 501 | if ( FT_READ_SHORT( start ) || | 
|---|
| 502 | FT_READ_SHORT( peak )  || | 
|---|
| 503 | FT_READ_SHORT( end )   ) | 
|---|
| 504 | goto Exit; | 
|---|
| 505 |  | 
|---|
| 506 | axisCoords[j].startCoord = FT_fdot14ToFixed( start ); | 
|---|
| 507 | axisCoords[j].peakCoord  = FT_fdot14ToFixed( peak ); | 
|---|
| 508 | axisCoords[j].endCoord   = FT_fdot14ToFixed( end ); | 
|---|
| 509 | } | 
|---|
| 510 | } | 
|---|
| 511 |  | 
|---|
| 512 | /* end of region list parse */ | 
|---|
| 513 |  | 
|---|
| 514 | /* use dataOffsetArray now to parse varData items */ | 
|---|
| 515 | if ( FT_NEW_ARRAY( itemStore->varData, itemStore->dataCount ) ) | 
|---|
| 516 | goto Exit; | 
|---|
| 517 |  | 
|---|
| 518 | for ( i = 0; i < itemStore->dataCount; i++ ) | 
|---|
| 519 | { | 
|---|
| 520 | varData = &itemStore->varData[i]; | 
|---|
| 521 |  | 
|---|
| 522 | if ( FT_STREAM_SEEK( offset + dataOffsetArray[i] ) ) | 
|---|
| 523 | goto Exit; | 
|---|
| 524 |  | 
|---|
| 525 | if ( FT_READ_USHORT( varData->itemCount )      || | 
|---|
| 526 | FT_READ_USHORT( shortDeltaCount )         || | 
|---|
| 527 | FT_READ_USHORT( varData->regionIdxCount ) ) | 
|---|
| 528 | goto Exit; | 
|---|
| 529 |  | 
|---|
| 530 | /* check some data consistency */ | 
|---|
| 531 | if ( shortDeltaCount > varData->regionIdxCount ) | 
|---|
| 532 | { | 
|---|
| 533 | FT_TRACE2(( "bad short count %d or region count %d\n", | 
|---|
| 534 | shortDeltaCount, | 
|---|
| 535 | varData->regionIdxCount )); | 
|---|
| 536 | error = FT_THROW( Invalid_Table ); | 
|---|
| 537 | goto Exit; | 
|---|
| 538 | } | 
|---|
| 539 |  | 
|---|
| 540 | if ( varData->regionIdxCount > itemStore->regionCount ) | 
|---|
| 541 | { | 
|---|
| 542 | FT_TRACE2(( "inconsistent regionCount %d in varData[%d]\n", | 
|---|
| 543 | varData->regionIdxCount, | 
|---|
| 544 | i )); | 
|---|
| 545 | error = FT_THROW( Invalid_Table ); | 
|---|
| 546 | goto Exit; | 
|---|
| 547 | } | 
|---|
| 548 |  | 
|---|
| 549 | /* parse region indices */ | 
|---|
| 550 | if ( FT_NEW_ARRAY( varData->regionIndices, | 
|---|
| 551 | varData->regionIdxCount ) ) | 
|---|
| 552 | goto Exit; | 
|---|
| 553 |  | 
|---|
| 554 | for ( j = 0; j < varData->regionIdxCount; j++ ) | 
|---|
| 555 | { | 
|---|
| 556 | if ( FT_READ_USHORT( varData->regionIndices[j] ) ) | 
|---|
| 557 | goto Exit; | 
|---|
| 558 |  | 
|---|
| 559 | if ( varData->regionIndices[j] >= itemStore->regionCount ) | 
|---|
| 560 | { | 
|---|
| 561 | FT_TRACE2(( "bad region index %d\n", | 
|---|
| 562 | varData->regionIndices[j] )); | 
|---|
| 563 | error = FT_THROW( Invalid_Table ); | 
|---|
| 564 | goto Exit; | 
|---|
| 565 | } | 
|---|
| 566 | } | 
|---|
| 567 |  | 
|---|
| 568 | /* Parse delta set.                                                */ | 
|---|
| 569 | /*                                                                 */ | 
|---|
| 570 | /* On input, deltas are (shortDeltaCount + regionIdxCount) bytes   */ | 
|---|
| 571 | /* each; on output, deltas are expanded to `regionIdxCount' shorts */ | 
|---|
| 572 | /* each.                                                           */ | 
|---|
| 573 | if ( FT_NEW_ARRAY( varData->deltaSet, | 
|---|
| 574 | varData->regionIdxCount * varData->itemCount ) ) | 
|---|
| 575 | goto Exit; | 
|---|
| 576 |  | 
|---|
| 577 | /* the delta set is stored as a 2-dimensional array of shorts; */ | 
|---|
| 578 | /* sign-extend signed bytes to signed shorts                   */ | 
|---|
| 579 | for ( j = 0; j < varData->itemCount * varData->regionIdxCount; ) | 
|---|
| 580 | { | 
|---|
| 581 | for ( k = 0; k < shortDeltaCount; k++, j++ ) | 
|---|
| 582 | { | 
|---|
| 583 | /* read the short deltas */ | 
|---|
| 584 | FT_Short  delta; | 
|---|
| 585 |  | 
|---|
| 586 |  | 
|---|
| 587 | if ( FT_READ_SHORT( delta ) ) | 
|---|
| 588 | goto Exit; | 
|---|
| 589 |  | 
|---|
| 590 | varData->deltaSet[j] = delta; | 
|---|
| 591 | } | 
|---|
| 592 |  | 
|---|
| 593 | for ( ; k < varData->regionIdxCount; k++, j++ ) | 
|---|
| 594 | { | 
|---|
| 595 | /* read the (signed) byte deltas */ | 
|---|
| 596 | FT_Char  delta; | 
|---|
| 597 |  | 
|---|
| 598 |  | 
|---|
| 599 | if ( FT_READ_CHAR( delta ) ) | 
|---|
| 600 | goto Exit; | 
|---|
| 601 |  | 
|---|
| 602 | varData->deltaSet[j] = delta; | 
|---|
| 603 | } | 
|---|
| 604 | } | 
|---|
| 605 | } | 
|---|
| 606 |  | 
|---|
| 607 | Exit: | 
|---|
| 608 | FT_FREE( dataOffsetArray ); | 
|---|
| 609 |  | 
|---|
| 610 | return error; | 
|---|
| 611 | } | 
|---|
| 612 |  | 
|---|
| 613 |  | 
|---|
| 614 | static FT_Error | 
|---|
| 615 | ft_var_load_delta_set_index_mapping( TT_Face            face, | 
|---|
| 616 | FT_ULong           offset, | 
|---|
| 617 | GX_DeltaSetIdxMap  map, | 
|---|
| 618 | GX_ItemVarStore    itemStore ) | 
|---|
| 619 | { | 
|---|
| 620 | FT_Stream  stream = FT_FACE_STREAM( face ); | 
|---|
| 621 | FT_Memory  memory = stream->memory; | 
|---|
| 622 |  | 
|---|
| 623 | FT_Error   error; | 
|---|
| 624 |  | 
|---|
| 625 | FT_UShort  format; | 
|---|
| 626 | FT_UInt    entrySize; | 
|---|
| 627 | FT_UInt    innerBitCount; | 
|---|
| 628 | FT_UInt    innerIndexMask; | 
|---|
| 629 | FT_UInt    i, j; | 
|---|
| 630 |  | 
|---|
| 631 |  | 
|---|
| 632 | if ( FT_STREAM_SEEK( offset )        || | 
|---|
| 633 | FT_READ_USHORT( format )        || | 
|---|
| 634 | FT_READ_USHORT( map->mapCount ) ) | 
|---|
| 635 | goto Exit; | 
|---|
| 636 |  | 
|---|
| 637 | if ( format & 0xFFC0 ) | 
|---|
| 638 | { | 
|---|
| 639 | FT_TRACE2(( "bad map format %d\n", format )); | 
|---|
| 640 | error = FT_THROW( Invalid_Table ); | 
|---|
| 641 | goto Exit; | 
|---|
| 642 | } | 
|---|
| 643 |  | 
|---|
| 644 | /* bytes per entry: 1, 2, 3, or 4 */ | 
|---|
| 645 | entrySize      = ( ( format & 0x0030 ) >> 4 ) + 1; | 
|---|
| 646 | innerBitCount  = ( format & 0x000F ) + 1; | 
|---|
| 647 | innerIndexMask = ( 1 << innerBitCount ) - 1; | 
|---|
| 648 |  | 
|---|
| 649 | if ( FT_NEW_ARRAY( map->innerIndex, map->mapCount ) ) | 
|---|
| 650 | goto Exit; | 
|---|
| 651 |  | 
|---|
| 652 | if ( FT_NEW_ARRAY( map->outerIndex, map->mapCount ) ) | 
|---|
| 653 | goto Exit; | 
|---|
| 654 |  | 
|---|
| 655 | for ( i = 0; i < map->mapCount; i++ ) | 
|---|
| 656 | { | 
|---|
| 657 | FT_UInt  mapData = 0; | 
|---|
| 658 | FT_UInt  outerIndex, innerIndex; | 
|---|
| 659 |  | 
|---|
| 660 |  | 
|---|
| 661 | /* read map data one unsigned byte at a time, big endian */ | 
|---|
| 662 | for ( j = 0; j < entrySize; j++ ) | 
|---|
| 663 | { | 
|---|
| 664 | FT_Byte  data; | 
|---|
| 665 |  | 
|---|
| 666 |  | 
|---|
| 667 | if ( FT_READ_BYTE( data ) ) | 
|---|
| 668 | goto Exit; | 
|---|
| 669 |  | 
|---|
| 670 | mapData = ( mapData << 8 ) | data; | 
|---|
| 671 | } | 
|---|
| 672 |  | 
|---|
| 673 | outerIndex = mapData >> innerBitCount; | 
|---|
| 674 |  | 
|---|
| 675 | if ( outerIndex >= itemStore->dataCount ) | 
|---|
| 676 | { | 
|---|
| 677 | FT_TRACE2(( "outerIndex[%d] == %d out of range\n", | 
|---|
| 678 | i, | 
|---|
| 679 | outerIndex )); | 
|---|
| 680 | error = FT_THROW( Invalid_Table ); | 
|---|
| 681 | goto Exit; | 
|---|
| 682 | } | 
|---|
| 683 |  | 
|---|
| 684 | map->outerIndex[i] = outerIndex; | 
|---|
| 685 |  | 
|---|
| 686 | innerIndex = mapData & innerIndexMask; | 
|---|
| 687 |  | 
|---|
| 688 | if ( innerIndex >= itemStore->varData[outerIndex].itemCount ) | 
|---|
| 689 | { | 
|---|
| 690 | FT_TRACE2(( "innerIndex[%d] == %d out of range\n", | 
|---|
| 691 | i, | 
|---|
| 692 | innerIndex )); | 
|---|
| 693 | error = FT_THROW( Invalid_Table ); | 
|---|
| 694 | goto Exit; | 
|---|
| 695 | } | 
|---|
| 696 |  | 
|---|
| 697 | map->innerIndex[i] = innerIndex; | 
|---|
| 698 | } | 
|---|
| 699 |  | 
|---|
| 700 | Exit: | 
|---|
| 701 | return error; | 
|---|
| 702 | } | 
|---|
| 703 |  | 
|---|
| 704 |  | 
|---|
| 705 | /*************************************************************************/ | 
|---|
| 706 | /*                                                                       */ | 
|---|
| 707 | /* <Function>                                                            */ | 
|---|
| 708 | /*    ft_var_load_hvvar                                                  */ | 
|---|
| 709 | /*                                                                       */ | 
|---|
| 710 | /* <Description>                                                         */ | 
|---|
| 711 | /*    If `vertical' is zero, parse the `HVAR' table and set              */ | 
|---|
| 712 | /*    `blend->hvar_loaded' to TRUE.  On success, `blend->hvar_checked'   */ | 
|---|
| 713 | /*    is set to TRUE.                                                    */ | 
|---|
| 714 | /*                                                                       */ | 
|---|
| 715 | /*    If `vertical' is not zero, parse the `VVAR' table and set          */ | 
|---|
| 716 | /*    `blend->vvar_loaded' to TRUE.  On success, `blend->vvar_checked'   */ | 
|---|
| 717 | /*    is set to TRUE.                                                    */ | 
|---|
| 718 | /*                                                                       */ | 
|---|
| 719 | /*    Some memory may remain allocated on error; it is always freed in   */ | 
|---|
| 720 | /*    `tt_done_blend', however.                                          */ | 
|---|
| 721 | /*                                                                       */ | 
|---|
| 722 | /* <InOut>                                                               */ | 
|---|
| 723 | /*    face :: The font face.                                             */ | 
|---|
| 724 | /*                                                                       */ | 
|---|
| 725 | /* <Return>                                                              */ | 
|---|
| 726 | /*    FreeType error code.  0 means success.                             */ | 
|---|
| 727 | /*                                                                       */ | 
|---|
| 728 | static FT_Error | 
|---|
| 729 | ft_var_load_hvvar( TT_Face  face, | 
|---|
| 730 | FT_Bool  vertical ) | 
|---|
| 731 | { | 
|---|
| 732 | FT_Stream  stream = FT_FACE_STREAM( face ); | 
|---|
| 733 | FT_Memory  memory = stream->memory; | 
|---|
| 734 |  | 
|---|
| 735 | GX_Blend  blend = face->blend; | 
|---|
| 736 |  | 
|---|
| 737 | GX_HVVarTable  table; | 
|---|
| 738 |  | 
|---|
| 739 | FT_Error   error; | 
|---|
| 740 | FT_UShort  majorVersion; | 
|---|
| 741 | FT_ULong   table_len; | 
|---|
| 742 | FT_ULong   table_offset; | 
|---|
| 743 | FT_ULong   store_offset; | 
|---|
| 744 | FT_ULong   widthMap_offset; | 
|---|
| 745 |  | 
|---|
| 746 |  | 
|---|
| 747 | if ( vertical ) | 
|---|
| 748 | { | 
|---|
| 749 | blend->vvar_loaded = TRUE; | 
|---|
| 750 |  | 
|---|
| 751 | FT_TRACE2(( "VVAR ")); | 
|---|
| 752 |  | 
|---|
| 753 | error = face->goto_table( face, TTAG_VVAR, stream, &table_len ); | 
|---|
| 754 | } | 
|---|
| 755 | else | 
|---|
| 756 | { | 
|---|
| 757 | blend->hvar_loaded = TRUE; | 
|---|
| 758 |  | 
|---|
| 759 | FT_TRACE2(( "HVAR ")); | 
|---|
| 760 |  | 
|---|
| 761 | error = face->goto_table( face, TTAG_HVAR, stream, &table_len ); | 
|---|
| 762 | } | 
|---|
| 763 |  | 
|---|
| 764 | if ( error ) | 
|---|
| 765 | { | 
|---|
| 766 | FT_TRACE2(( "is missing\n")); | 
|---|
| 767 | goto Exit; | 
|---|
| 768 | } | 
|---|
| 769 |  | 
|---|
| 770 | table_offset = FT_STREAM_POS(); | 
|---|
| 771 |  | 
|---|
| 772 | /* skip minor version */ | 
|---|
| 773 | if ( FT_READ_USHORT( majorVersion ) || | 
|---|
| 774 | FT_STREAM_SKIP( 2 )            ) | 
|---|
| 775 | goto Exit; | 
|---|
| 776 |  | 
|---|
| 777 | if ( majorVersion != 1 ) | 
|---|
| 778 | { | 
|---|
| 779 | FT_TRACE2(( "bad table version %d\n", majorVersion )); | 
|---|
| 780 | error = FT_THROW( Invalid_Table ); | 
|---|
| 781 | goto Exit; | 
|---|
| 782 | } | 
|---|
| 783 |  | 
|---|
| 784 | if ( FT_READ_ULONG( store_offset )    || | 
|---|
| 785 | FT_READ_ULONG( widthMap_offset ) ) | 
|---|
| 786 | goto Exit; | 
|---|
| 787 |  | 
|---|
| 788 | if ( vertical ) | 
|---|
| 789 | { | 
|---|
| 790 | if ( FT_NEW( blend->vvar_table ) ) | 
|---|
| 791 | goto Exit; | 
|---|
| 792 | table = blend->vvar_table; | 
|---|
| 793 | } | 
|---|
| 794 | else | 
|---|
| 795 | { | 
|---|
| 796 | if ( FT_NEW( blend->hvar_table ) ) | 
|---|
| 797 | goto Exit; | 
|---|
| 798 | table = blend->hvar_table; | 
|---|
| 799 | } | 
|---|
| 800 |  | 
|---|
| 801 | error = ft_var_load_item_variation_store( | 
|---|
| 802 | face, | 
|---|
| 803 | table_offset + store_offset, | 
|---|
| 804 | &table->itemStore ); | 
|---|
| 805 | if ( error ) | 
|---|
| 806 | goto Exit; | 
|---|
| 807 |  | 
|---|
| 808 | if ( widthMap_offset ) | 
|---|
| 809 | { | 
|---|
| 810 | error = ft_var_load_delta_set_index_mapping( | 
|---|
| 811 | face, | 
|---|
| 812 | table_offset + widthMap_offset, | 
|---|
| 813 | &table->widthMap, | 
|---|
| 814 | &table->itemStore ); | 
|---|
| 815 | if ( error ) | 
|---|
| 816 | goto Exit; | 
|---|
| 817 | } | 
|---|
| 818 |  | 
|---|
| 819 | FT_TRACE2(( "loaded\n")); | 
|---|
| 820 | error = FT_Err_Ok; | 
|---|
| 821 |  | 
|---|
| 822 | Exit: | 
|---|
| 823 | if ( !error ) | 
|---|
| 824 | { | 
|---|
| 825 | if ( vertical ) | 
|---|
| 826 | { | 
|---|
| 827 | blend->vvar_checked = TRUE; | 
|---|
| 828 |  | 
|---|
| 829 | /* FreeType doesn't provide functions to quickly retrieve    */ | 
|---|
| 830 | /* TSB, BSB, or VORG values; we thus don't have to implement */ | 
|---|
| 831 | /* support for those three item variation stores.            */ | 
|---|
| 832 |  | 
|---|
| 833 | face->variation_support |= TT_FACE_FLAG_VAR_VADVANCE; | 
|---|
| 834 | } | 
|---|
| 835 | else | 
|---|
| 836 | { | 
|---|
| 837 | blend->hvar_checked = TRUE; | 
|---|
| 838 |  | 
|---|
| 839 | /* FreeType doesn't provide functions to quickly retrieve */ | 
|---|
| 840 | /* LSB or RSB values; we thus don't have to implement     */ | 
|---|
| 841 | /* support for those two item variation stores.           */ | 
|---|
| 842 |  | 
|---|
| 843 | face->variation_support |= TT_FACE_FLAG_VAR_HADVANCE; | 
|---|
| 844 | } | 
|---|
| 845 | } | 
|---|
| 846 |  | 
|---|
| 847 | return error; | 
|---|
| 848 | } | 
|---|
| 849 |  | 
|---|
| 850 |  | 
|---|
| 851 | static FT_Int | 
|---|
| 852 | ft_var_get_item_delta( TT_Face          face, | 
|---|
| 853 | GX_ItemVarStore  itemStore, | 
|---|
| 854 | FT_UInt          outerIndex, | 
|---|
| 855 | FT_UInt          innerIndex ) | 
|---|
| 856 | { | 
|---|
| 857 | GX_ItemVarData  varData; | 
|---|
| 858 | FT_Short*       deltaSet; | 
|---|
| 859 |  | 
|---|
| 860 | FT_UInt   master, j; | 
|---|
| 861 | FT_Fixed  netAdjustment = 0;     /* accumulated adjustment */ | 
|---|
| 862 | FT_Fixed  scaledDelta; | 
|---|
| 863 | FT_Fixed  delta; | 
|---|
| 864 |  | 
|---|
| 865 |  | 
|---|
| 866 | /* See pseudo code from `Font Variations Overview' */ | 
|---|
| 867 | /* in the OpenType specification.                  */ | 
|---|
| 868 |  | 
|---|
| 869 | varData  = &itemStore->varData[outerIndex]; | 
|---|
| 870 | deltaSet = &varData->deltaSet[varData->regionIdxCount * innerIndex]; | 
|---|
| 871 |  | 
|---|
| 872 | /* outer loop steps through master designs to be blended */ | 
|---|
| 873 | for ( master = 0; master < varData->regionIdxCount; master++ ) | 
|---|
| 874 | { | 
|---|
| 875 | FT_Fixed  scalar      = FT_FIXED_ONE; | 
|---|
| 876 | FT_UInt   regionIndex = varData->regionIndices[master]; | 
|---|
| 877 |  | 
|---|
| 878 | GX_AxisCoords  axis = itemStore->varRegionList[regionIndex].axisList; | 
|---|
| 879 |  | 
|---|
| 880 |  | 
|---|
| 881 | /* inner loop steps through axes in this region */ | 
|---|
| 882 | for ( j = 0; j < itemStore->axisCount; j++, axis++ ) | 
|---|
| 883 | { | 
|---|
| 884 | FT_Fixed  axisScalar; | 
|---|
| 885 |  | 
|---|
| 886 |  | 
|---|
| 887 | /* compute the scalar contribution of this axis; */ | 
|---|
| 888 | /* ignore invalid ranges                         */ | 
|---|
| 889 | if ( axis->startCoord > axis->peakCoord || | 
|---|
| 890 | axis->peakCoord > axis->endCoord   ) | 
|---|
| 891 | axisScalar = FT_FIXED_ONE; | 
|---|
| 892 |  | 
|---|
| 893 | else if ( axis->startCoord < 0 && | 
|---|
| 894 | axis->endCoord > 0   && | 
|---|
| 895 | axis->peakCoord != 0 ) | 
|---|
| 896 | axisScalar = FT_FIXED_ONE; | 
|---|
| 897 |  | 
|---|
| 898 | /* peak of 0 means ignore this axis */ | 
|---|
| 899 | else if ( axis->peakCoord == 0 ) | 
|---|
| 900 | axisScalar = FT_FIXED_ONE; | 
|---|
| 901 |  | 
|---|
| 902 | /* ignore this region if coords are out of range */ | 
|---|
| 903 | else if ( face->blend->normalizedcoords[j] < axis->startCoord || | 
|---|
| 904 | face->blend->normalizedcoords[j] > axis->endCoord   ) | 
|---|
| 905 | axisScalar = 0; | 
|---|
| 906 |  | 
|---|
| 907 | /* calculate a proportional factor */ | 
|---|
| 908 | else | 
|---|
| 909 | { | 
|---|
| 910 | if ( face->blend->normalizedcoords[j] == axis->peakCoord ) | 
|---|
| 911 | axisScalar = FT_FIXED_ONE; | 
|---|
| 912 | else if ( face->blend->normalizedcoords[j] < axis->peakCoord ) | 
|---|
| 913 | axisScalar = | 
|---|
| 914 | FT_DivFix( face->blend->normalizedcoords[j] - axis->startCoord, | 
|---|
| 915 | axis->peakCoord - axis->startCoord ); | 
|---|
| 916 | else | 
|---|
| 917 | axisScalar = | 
|---|
| 918 | FT_DivFix( axis->endCoord - face->blend->normalizedcoords[j], | 
|---|
| 919 | axis->endCoord - axis->peakCoord ); | 
|---|
| 920 | } | 
|---|
| 921 |  | 
|---|
| 922 | /* take product of all the axis scalars */ | 
|---|
| 923 | scalar = FT_MulFix( scalar, axisScalar ); | 
|---|
| 924 |  | 
|---|
| 925 | } /* per-axis loop */ | 
|---|
| 926 |  | 
|---|
| 927 | /* get the scaled delta for this region */ | 
|---|
| 928 | delta       = FT_intToFixed( deltaSet[master] ); | 
|---|
| 929 | scaledDelta = FT_MulFix( scalar, delta ); | 
|---|
| 930 |  | 
|---|
| 931 | /* accumulate the adjustments from each region */ | 
|---|
| 932 | netAdjustment = netAdjustment + scaledDelta; | 
|---|
| 933 |  | 
|---|
| 934 | } /* per-region loop */ | 
|---|
| 935 |  | 
|---|
| 936 | return FT_fixedToInt( netAdjustment ); | 
|---|
| 937 | } | 
|---|
| 938 |  | 
|---|
| 939 |  | 
|---|
| 940 | /*************************************************************************/ | 
|---|
| 941 | /*                                                                       */ | 
|---|
| 942 | /* <Function>                                                            */ | 
|---|
| 943 | /*    tt_hvadvance_adjust                                                */ | 
|---|
| 944 | /*                                                                       */ | 
|---|
| 945 | /* <Description>                                                         */ | 
|---|
| 946 | /*    Apply `HVAR' advance width or `VVAR' advance height adjustment of  */ | 
|---|
| 947 | /*    a given glyph.                                                     */ | 
|---|
| 948 | /*                                                                       */ | 
|---|
| 949 | /* <Input>                                                               */ | 
|---|
| 950 | /*    gindex   :: The glyph index.                                       */ | 
|---|
| 951 | /*                                                                       */ | 
|---|
| 952 | /*    vertical :: If set, handle `VVAR' table.                           */ | 
|---|
| 953 | /*                                                                       */ | 
|---|
| 954 | /* <InOut>                                                               */ | 
|---|
| 955 | /*    face     :: The font face.                                         */ | 
|---|
| 956 | /*                                                                       */ | 
|---|
| 957 | /*    adelta   :: Points to width or height value that gets modified.    */ | 
|---|
| 958 | /*                                                                       */ | 
|---|
| 959 | static FT_Error | 
|---|
| 960 | tt_hvadvance_adjust( TT_Face  face, | 
|---|
| 961 | FT_UInt  gindex, | 
|---|
| 962 | FT_Int  *avalue, | 
|---|
| 963 | FT_Bool  vertical ) | 
|---|
| 964 | { | 
|---|
| 965 | FT_Error  error = FT_Err_Ok; | 
|---|
| 966 | FT_UInt   innerIndex, outerIndex; | 
|---|
| 967 | FT_Int    delta; | 
|---|
| 968 |  | 
|---|
| 969 | GX_HVVarTable  table; | 
|---|
| 970 |  | 
|---|
| 971 |  | 
|---|
| 972 | if ( !face->doblend || !face->blend ) | 
|---|
| 973 | goto Exit; | 
|---|
| 974 |  | 
|---|
| 975 | if ( vertical ) | 
|---|
| 976 | { | 
|---|
| 977 | if ( !face->blend->vvar_loaded ) | 
|---|
| 978 | { | 
|---|
| 979 | /* initialize vvar table */ | 
|---|
| 980 | face->blend->vvar_error = ft_var_load_hvvar( face, 1 ); | 
|---|
| 981 | } | 
|---|
| 982 |  | 
|---|
| 983 | if ( !face->blend->vvar_checked ) | 
|---|
| 984 | { | 
|---|
| 985 | error = face->blend->vvar_error; | 
|---|
| 986 | goto Exit; | 
|---|
| 987 | } | 
|---|
| 988 |  | 
|---|
| 989 | table = face->blend->vvar_table; | 
|---|
| 990 | } | 
|---|
| 991 | else | 
|---|
| 992 | { | 
|---|
| 993 | if ( !face->blend->hvar_loaded ) | 
|---|
| 994 | { | 
|---|
| 995 | /* initialize hvar table */ | 
|---|
| 996 | face->blend->hvar_error = ft_var_load_hvvar( face, 0 ); | 
|---|
| 997 | } | 
|---|
| 998 |  | 
|---|
| 999 | if ( !face->blend->hvar_checked ) | 
|---|
| 1000 | { | 
|---|
| 1001 | error = face->blend->hvar_error; | 
|---|
| 1002 | goto Exit; | 
|---|
| 1003 | } | 
|---|
| 1004 |  | 
|---|
| 1005 | table = face->blend->hvar_table; | 
|---|
| 1006 | } | 
|---|
| 1007 |  | 
|---|
| 1008 | /* advance width or height adjustments are always present in an */ | 
|---|
| 1009 | /* `HVAR' or `VVAR' table; no need to test for this capability  */ | 
|---|
| 1010 |  | 
|---|
| 1011 | if ( table->widthMap.innerIndex ) | 
|---|
| 1012 | { | 
|---|
| 1013 | FT_UInt  idx = gindex; | 
|---|
| 1014 |  | 
|---|
| 1015 |  | 
|---|
| 1016 | if ( idx >= table->widthMap.mapCount ) | 
|---|
| 1017 | idx = table->widthMap.mapCount - 1; | 
|---|
| 1018 |  | 
|---|
| 1019 | /* trust that HVAR parser has checked indices */ | 
|---|
| 1020 | outerIndex = table->widthMap.outerIndex[idx]; | 
|---|
| 1021 | innerIndex = table->widthMap.innerIndex[idx]; | 
|---|
| 1022 | } | 
|---|
| 1023 | else | 
|---|
| 1024 | { | 
|---|
| 1025 | GX_ItemVarData  varData; | 
|---|
| 1026 |  | 
|---|
| 1027 |  | 
|---|
| 1028 | /* no widthMap data */ | 
|---|
| 1029 | outerIndex = 0; | 
|---|
| 1030 | innerIndex = gindex; | 
|---|
| 1031 |  | 
|---|
| 1032 | varData = &table->itemStore.varData[outerIndex]; | 
|---|
| 1033 | if ( gindex >= varData->itemCount ) | 
|---|
| 1034 | { | 
|---|
| 1035 | FT_TRACE2(( "gindex %d out of range\n", gindex )); | 
|---|
| 1036 | error = FT_THROW( Invalid_Argument ); | 
|---|
| 1037 | goto Exit; | 
|---|
| 1038 | } | 
|---|
| 1039 | } | 
|---|
| 1040 |  | 
|---|
| 1041 | delta = ft_var_get_item_delta( face, | 
|---|
| 1042 | &table->itemStore, | 
|---|
| 1043 | outerIndex, | 
|---|
| 1044 | innerIndex ); | 
|---|
| 1045 |  | 
|---|
| 1046 | FT_TRACE5(( "%s value %d adjusted by %d unit%s (%s)\n", | 
|---|
| 1047 | vertical ? "vertical height": "horizontal width", | 
|---|
| 1048 | *avalue, | 
|---|
| 1049 | delta, | 
|---|
| 1050 | delta == 1 ? "": "s", | 
|---|
| 1051 | vertical ? "VVAR": "HVAR")); | 
|---|
| 1052 |  | 
|---|
| 1053 | *avalue += delta; | 
|---|
| 1054 |  | 
|---|
| 1055 | Exit: | 
|---|
| 1056 | return error; | 
|---|
| 1057 | } | 
|---|
| 1058 |  | 
|---|
| 1059 |  | 
|---|
| 1060 | FT_LOCAL_DEF( FT_Error ) | 
|---|
| 1061 | tt_hadvance_adjust( TT_Face  face, | 
|---|
| 1062 | FT_UInt  gindex, | 
|---|
| 1063 | FT_Int  *avalue ) | 
|---|
| 1064 | { | 
|---|
| 1065 | return tt_hvadvance_adjust( face, gindex, avalue, 0 ); | 
|---|
| 1066 | } | 
|---|
| 1067 |  | 
|---|
| 1068 |  | 
|---|
| 1069 | FT_LOCAL_DEF( FT_Error ) | 
|---|
| 1070 | tt_vadvance_adjust( TT_Face  face, | 
|---|
| 1071 | FT_UInt  gindex, | 
|---|
| 1072 | FT_Int  *avalue ) | 
|---|
| 1073 | { | 
|---|
| 1074 | return tt_hvadvance_adjust( face, gindex, avalue, 1 ); | 
|---|
| 1075 | } | 
|---|
| 1076 |  | 
|---|
| 1077 |  | 
|---|
| 1078 | #define GX_VALUE_SIZE  8 | 
|---|
| 1079 |  | 
|---|
| 1080 | /* all values are FT_Short or FT_UShort entities; */ | 
|---|
| 1081 | /* we treat them consistently as FT_Short         */ | 
|---|
| 1082 | #define GX_VALUE_CASE( tag, dflt )      \ | 
|---|
| 1083 | case MVAR_TAG_ ## tag :       \ | 
|---|
| 1084 | p = (FT_Short*)&face->dflt; \ | 
|---|
| 1085 | break | 
|---|
| 1086 |  | 
|---|
| 1087 | #define GX_GASP_CASE( idx )                                       \ | 
|---|
| 1088 | case MVAR_TAG_GASP_ ## idx :                            \ | 
|---|
| 1089 | if ( idx < face->gasp.numRanges - 1 )                 \ | 
|---|
| 1090 | p = (FT_Short*)&face->gasp.gaspRanges[idx].maxPPEM; \ | 
|---|
| 1091 | else                                                  \ | 
|---|
| 1092 | p = NULL;                                           \ | 
|---|
| 1093 | break | 
|---|
| 1094 |  | 
|---|
| 1095 |  | 
|---|
| 1096 | static FT_Short* | 
|---|
| 1097 | ft_var_get_value_pointer( TT_Face   face, | 
|---|
| 1098 | FT_ULong  mvar_tag ) | 
|---|
| 1099 | { | 
|---|
| 1100 | FT_Short*  p; | 
|---|
| 1101 |  | 
|---|
| 1102 |  | 
|---|
| 1103 | switch ( mvar_tag ) | 
|---|
| 1104 | { | 
|---|
| 1105 | GX_GASP_CASE( 0 ); | 
|---|
| 1106 | GX_GASP_CASE( 1 ); | 
|---|
| 1107 | GX_GASP_CASE( 2 ); | 
|---|
| 1108 | GX_GASP_CASE( 3 ); | 
|---|
| 1109 | GX_GASP_CASE( 4 ); | 
|---|
| 1110 | GX_GASP_CASE( 5 ); | 
|---|
| 1111 | GX_GASP_CASE( 6 ); | 
|---|
| 1112 | GX_GASP_CASE( 7 ); | 
|---|
| 1113 | GX_GASP_CASE( 8 ); | 
|---|
| 1114 | GX_GASP_CASE( 9 ); | 
|---|
| 1115 |  | 
|---|
| 1116 | GX_VALUE_CASE( CPHT, os2.sCapHeight ); | 
|---|
| 1117 | GX_VALUE_CASE( HASC, os2.sTypoAscender ); | 
|---|
| 1118 | GX_VALUE_CASE( HCLA, os2.usWinAscent ); | 
|---|
| 1119 | GX_VALUE_CASE( HCLD, os2.usWinDescent ); | 
|---|
| 1120 | GX_VALUE_CASE( HCOF, horizontal.caret_Offset ); | 
|---|
| 1121 | GX_VALUE_CASE( HCRN, horizontal.caret_Slope_Run ); | 
|---|
| 1122 | GX_VALUE_CASE( HCRS, horizontal.caret_Slope_Rise ); | 
|---|
| 1123 | GX_VALUE_CASE( HDSC, os2.sTypoDescender ); | 
|---|
| 1124 | GX_VALUE_CASE( HLGP, os2.sTypoLineGap ); | 
|---|
| 1125 | GX_VALUE_CASE( SBXO, os2.ySubscriptXOffset); | 
|---|
| 1126 | GX_VALUE_CASE( SBXS, os2.ySubscriptXSize ); | 
|---|
| 1127 | GX_VALUE_CASE( SBYO, os2.ySubscriptYOffset ); | 
|---|
| 1128 | GX_VALUE_CASE( SBYS, os2.ySubscriptYSize ); | 
|---|
| 1129 | GX_VALUE_CASE( SPXO, os2.ySuperscriptXOffset ); | 
|---|
| 1130 | GX_VALUE_CASE( SPXS, os2.ySuperscriptXSize ); | 
|---|
| 1131 | GX_VALUE_CASE( SPYO, os2.ySuperscriptYOffset ); | 
|---|
| 1132 | GX_VALUE_CASE( SPYS, os2.ySuperscriptYSize ); | 
|---|
| 1133 | GX_VALUE_CASE( STRO, os2.yStrikeoutPosition ); | 
|---|
| 1134 | GX_VALUE_CASE( STRS, os2.yStrikeoutSize ); | 
|---|
| 1135 | GX_VALUE_CASE( UNDO, postscript.underlinePosition ); | 
|---|
| 1136 | GX_VALUE_CASE( UNDS, postscript.underlineThickness ); | 
|---|
| 1137 | GX_VALUE_CASE( VASC, vertical.Ascender ); | 
|---|
| 1138 | GX_VALUE_CASE( VCOF, vertical.caret_Offset ); | 
|---|
| 1139 | GX_VALUE_CASE( VCRN, vertical.caret_Slope_Run ); | 
|---|
| 1140 | GX_VALUE_CASE( VCRS, vertical.caret_Slope_Rise ); | 
|---|
| 1141 | GX_VALUE_CASE( VDSC, vertical.Descender ); | 
|---|
| 1142 | GX_VALUE_CASE( VLGP, vertical.Line_Gap ); | 
|---|
| 1143 | GX_VALUE_CASE( XHGT, os2.sxHeight ); | 
|---|
| 1144 |  | 
|---|
| 1145 | default: | 
|---|
| 1146 | /* ignore unknown tag */ | 
|---|
| 1147 | p = NULL; | 
|---|
| 1148 | } | 
|---|
| 1149 |  | 
|---|
| 1150 | return p; | 
|---|
| 1151 | } | 
|---|
| 1152 |  | 
|---|
| 1153 |  | 
|---|
| 1154 | /*************************************************************************/ | 
|---|
| 1155 | /*                                                                       */ | 
|---|
| 1156 | /* <Function>                                                            */ | 
|---|
| 1157 | /*    ft_var_load_mvar                                                   */ | 
|---|
| 1158 | /*                                                                       */ | 
|---|
| 1159 | /* <Description>                                                         */ | 
|---|
| 1160 | /*    Parse the `MVAR' table.                                            */ | 
|---|
| 1161 | /*                                                                       */ | 
|---|
| 1162 | /*    Some memory may remain allocated on error; it is always freed in   */ | 
|---|
| 1163 | /*    `tt_done_blend', however.                                          */ | 
|---|
| 1164 | /*                                                                       */ | 
|---|
| 1165 | /* <InOut>                                                               */ | 
|---|
| 1166 | /*    face :: The font face.                                             */ | 
|---|
| 1167 | /*                                                                       */ | 
|---|
| 1168 | static void | 
|---|
| 1169 | ft_var_load_mvar( TT_Face  face ) | 
|---|
| 1170 | { | 
|---|
| 1171 | FT_Stream  stream = FT_FACE_STREAM( face ); | 
|---|
| 1172 | FT_Memory  memory = stream->memory; | 
|---|
| 1173 |  | 
|---|
| 1174 | GX_Blend         blend = face->blend; | 
|---|
| 1175 | GX_ItemVarStore  itemStore; | 
|---|
| 1176 | GX_Value         value, limit; | 
|---|
| 1177 |  | 
|---|
| 1178 | FT_Error   error; | 
|---|
| 1179 | FT_UShort  majorVersion; | 
|---|
| 1180 | FT_ULong   table_len; | 
|---|
| 1181 | FT_ULong   table_offset; | 
|---|
| 1182 | FT_UShort  store_offset; | 
|---|
| 1183 | FT_ULong   records_offset; | 
|---|
| 1184 |  | 
|---|
| 1185 |  | 
|---|
| 1186 | FT_TRACE2(( "MVAR ")); | 
|---|
| 1187 |  | 
|---|
| 1188 | error = face->goto_table( face, TTAG_MVAR, stream, &table_len ); | 
|---|
| 1189 | if ( error ) | 
|---|
| 1190 | { | 
|---|
| 1191 | FT_TRACE2(( "is missing\n")); | 
|---|
| 1192 | return; | 
|---|
| 1193 | } | 
|---|
| 1194 |  | 
|---|
| 1195 | table_offset = FT_STREAM_POS(); | 
|---|
| 1196 |  | 
|---|
| 1197 | /* skip minor version */ | 
|---|
| 1198 | if ( FT_READ_USHORT( majorVersion ) || | 
|---|
| 1199 | FT_STREAM_SKIP( 2 )            ) | 
|---|
| 1200 | return; | 
|---|
| 1201 |  | 
|---|
| 1202 | if ( majorVersion != 1 ) | 
|---|
| 1203 | { | 
|---|
| 1204 | FT_TRACE2(( "bad table version %d\n", majorVersion )); | 
|---|
| 1205 | return; | 
|---|
| 1206 | } | 
|---|
| 1207 |  | 
|---|
| 1208 | if ( FT_NEW( blend->mvar_table ) ) | 
|---|
| 1209 | return; | 
|---|
| 1210 |  | 
|---|
| 1211 | /* skip reserved entry and value record size */ | 
|---|
| 1212 | if ( FT_STREAM_SKIP( 4 )                             || | 
|---|
| 1213 | FT_READ_USHORT( blend->mvar_table->valueCount ) || | 
|---|
| 1214 | FT_READ_USHORT( store_offset )                  ) | 
|---|
| 1215 | return; | 
|---|
| 1216 |  | 
|---|
| 1217 | records_offset = FT_STREAM_POS(); | 
|---|
| 1218 |  | 
|---|
| 1219 | error = ft_var_load_item_variation_store( | 
|---|
| 1220 | face, | 
|---|
| 1221 | table_offset + store_offset, | 
|---|
| 1222 | &blend->mvar_table->itemStore ); | 
|---|
| 1223 | if ( error ) | 
|---|
| 1224 | return; | 
|---|
| 1225 |  | 
|---|
| 1226 | if ( FT_NEW_ARRAY( blend->mvar_table->values, | 
|---|
| 1227 | blend->mvar_table->valueCount ) ) | 
|---|
| 1228 | return; | 
|---|
| 1229 |  | 
|---|
| 1230 | if ( FT_STREAM_SEEK( records_offset )                                || | 
|---|
| 1231 | FT_FRAME_ENTER( blend->mvar_table->valueCount * GX_VALUE_SIZE ) ) | 
|---|
| 1232 | return; | 
|---|
| 1233 |  | 
|---|
| 1234 | value     = blend->mvar_table->values; | 
|---|
| 1235 | limit     = value + blend->mvar_table->valueCount; | 
|---|
| 1236 | itemStore = &blend->mvar_table->itemStore; | 
|---|
| 1237 |  | 
|---|
| 1238 | for ( ; value < limit; value++ ) | 
|---|
| 1239 | { | 
|---|
| 1240 | value->tag        = FT_GET_ULONG(); | 
|---|
| 1241 | value->outerIndex = FT_GET_USHORT(); | 
|---|
| 1242 | value->innerIndex = FT_GET_USHORT(); | 
|---|
| 1243 |  | 
|---|
| 1244 | if ( value->outerIndex >= itemStore->dataCount                  || | 
|---|
| 1245 | value->innerIndex >= itemStore->varData[value->outerIndex] | 
|---|
| 1246 | .itemCount          ) | 
|---|
| 1247 | { | 
|---|
| 1248 | error = FT_THROW( Invalid_Table ); | 
|---|
| 1249 | break; | 
|---|
| 1250 | } | 
|---|
| 1251 | } | 
|---|
| 1252 |  | 
|---|
| 1253 | FT_FRAME_EXIT(); | 
|---|
| 1254 |  | 
|---|
| 1255 | if ( error ) | 
|---|
| 1256 | return; | 
|---|
| 1257 |  | 
|---|
| 1258 | FT_TRACE2(( "loaded\n")); | 
|---|
| 1259 |  | 
|---|
| 1260 | value = blend->mvar_table->values; | 
|---|
| 1261 | limit = value + blend->mvar_table->valueCount; | 
|---|
| 1262 |  | 
|---|
| 1263 | /* save original values of the data MVAR is going to modify */ | 
|---|
| 1264 | for ( ; value < limit; value++ ) | 
|---|
| 1265 | { | 
|---|
| 1266 | FT_Short*  p = ft_var_get_value_pointer( face, value->tag ); | 
|---|
| 1267 |  | 
|---|
| 1268 |  | 
|---|
| 1269 | if ( p ) | 
|---|
| 1270 | value->unmodified = *p; | 
|---|
| 1271 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 1272 | else | 
|---|
| 1273 | FT_TRACE1(( "ft_var_load_mvar: Ignoring unknown tag `%c%c%c%c'\n", | 
|---|
| 1274 | (FT_Char)( value->tag >> 24 ), | 
|---|
| 1275 | (FT_Char)( value->tag >> 16 ), | 
|---|
| 1276 | (FT_Char)( value->tag >> 8 ), | 
|---|
| 1277 | (FT_Char)( value->tag ) )); | 
|---|
| 1278 | #endif | 
|---|
| 1279 | } | 
|---|
| 1280 |  | 
|---|
| 1281 | face->variation_support |= TT_FACE_FLAG_VAR_MVAR; | 
|---|
| 1282 | } | 
|---|
| 1283 |  | 
|---|
| 1284 |  | 
|---|
| 1285 | static FT_Error | 
|---|
| 1286 | tt_size_reset_iterator( FT_ListNode  node, | 
|---|
| 1287 | void*        user ) | 
|---|
| 1288 | { | 
|---|
| 1289 | TT_Size  size = (TT_Size)node->data; | 
|---|
| 1290 |  | 
|---|
| 1291 | FT_UNUSED( user ); | 
|---|
| 1292 |  | 
|---|
| 1293 |  | 
|---|
| 1294 | tt_size_reset( size, 1 ); | 
|---|
| 1295 |  | 
|---|
| 1296 | return FT_Err_Ok; | 
|---|
| 1297 | } | 
|---|
| 1298 |  | 
|---|
| 1299 |  | 
|---|
| 1300 | /*************************************************************************/ | 
|---|
| 1301 | /*                                                                       */ | 
|---|
| 1302 | /* <Function>                                                            */ | 
|---|
| 1303 | /*    tt_apply_mvar                                                      */ | 
|---|
| 1304 | /*                                                                       */ | 
|---|
| 1305 | /* <Description>                                                         */ | 
|---|
| 1306 | /*    Apply `MVAR' table adjustments.                                    */ | 
|---|
| 1307 | /*                                                                       */ | 
|---|
| 1308 | /* <InOut>                                                               */ | 
|---|
| 1309 | /*    face :: The font face.                                             */ | 
|---|
| 1310 | /*                                                                       */ | 
|---|
| 1311 | FT_LOCAL_DEF( void ) | 
|---|
| 1312 | tt_apply_mvar( TT_Face  face ) | 
|---|
| 1313 | { | 
|---|
| 1314 | GX_Blend  blend = face->blend; | 
|---|
| 1315 | GX_Value  value, limit; | 
|---|
| 1316 |  | 
|---|
| 1317 |  | 
|---|
| 1318 | if ( !( face->variation_support & TT_FACE_FLAG_VAR_MVAR ) ) | 
|---|
| 1319 | return; | 
|---|
| 1320 |  | 
|---|
| 1321 | value = blend->mvar_table->values; | 
|---|
| 1322 | limit = value + blend->mvar_table->valueCount; | 
|---|
| 1323 |  | 
|---|
| 1324 | for ( ; value < limit; value++ ) | 
|---|
| 1325 | { | 
|---|
| 1326 | FT_Short*  p = ft_var_get_value_pointer( face, value->tag ); | 
|---|
| 1327 | FT_Int     delta; | 
|---|
| 1328 |  | 
|---|
| 1329 |  | 
|---|
| 1330 | delta = ft_var_get_item_delta( face, | 
|---|
| 1331 | &blend->mvar_table->itemStore, | 
|---|
| 1332 | value->outerIndex, | 
|---|
| 1333 | value->innerIndex ); | 
|---|
| 1334 |  | 
|---|
| 1335 | if ( p ) | 
|---|
| 1336 | { | 
|---|
| 1337 | FT_TRACE5(( "value %c%c%c%c (%d unit%s) adjusted by %d unit%s (MVAR)\n", | 
|---|
| 1338 | (FT_Char)( value->tag >> 24 ), | 
|---|
| 1339 | (FT_Char)( value->tag >> 16 ), | 
|---|
| 1340 | (FT_Char)( value->tag >> 8 ), | 
|---|
| 1341 | (FT_Char)( value->tag ), | 
|---|
| 1342 | value->unmodified, | 
|---|
| 1343 | value->unmodified == 1 ? "": "s", | 
|---|
| 1344 | delta, | 
|---|
| 1345 | delta == 1 ? "": "s")); | 
|---|
| 1346 |  | 
|---|
| 1347 | /* since we handle both signed and unsigned values as FT_Short, */ | 
|---|
| 1348 | /* ensure proper overflow arithmetic                            */ | 
|---|
| 1349 | *p = (FT_Short)( value->unmodified + (FT_Short)delta ); | 
|---|
| 1350 | } | 
|---|
| 1351 | } | 
|---|
| 1352 |  | 
|---|
| 1353 | /* adjust all derived values */ | 
|---|
| 1354 | { | 
|---|
| 1355 | FT_Face  root = &face->root; | 
|---|
| 1356 |  | 
|---|
| 1357 |  | 
|---|
| 1358 | if ( face->os2.version != 0xFFFFU ) | 
|---|
| 1359 | { | 
|---|
| 1360 | if ( face->os2.sTypoAscender || face->os2.sTypoDescender ) | 
|---|
| 1361 | { | 
|---|
| 1362 | root->ascender  = face->os2.sTypoAscender; | 
|---|
| 1363 | root->descender = face->os2.sTypoDescender; | 
|---|
| 1364 |  | 
|---|
| 1365 | root->height = root->ascender - root->descender + | 
|---|
| 1366 | face->os2.sTypoLineGap; | 
|---|
| 1367 | } | 
|---|
| 1368 | else | 
|---|
| 1369 | { | 
|---|
| 1370 | root->ascender  =  (FT_Short)face->os2.usWinAscent; | 
|---|
| 1371 | root->descender = -(FT_Short)face->os2.usWinDescent; | 
|---|
| 1372 |  | 
|---|
| 1373 | root->height = root->ascender - root->descender; | 
|---|
| 1374 | } | 
|---|
| 1375 | } | 
|---|
| 1376 |  | 
|---|
| 1377 | root->underline_position  = face->postscript.underlinePosition - | 
|---|
| 1378 | face->postscript.underlineThickness / 2; | 
|---|
| 1379 | root->underline_thickness = face->postscript.underlineThickness; | 
|---|
| 1380 |  | 
|---|
| 1381 | /* iterate over all FT_Size objects and call `tt_size_reset' */ | 
|---|
| 1382 | /* to propagate the metrics changes                          */ | 
|---|
| 1383 | FT_List_Iterate( &root->sizes_list, | 
|---|
| 1384 | tt_size_reset_iterator, | 
|---|
| 1385 | NULL ); | 
|---|
| 1386 | } | 
|---|
| 1387 | } | 
|---|
| 1388 |  | 
|---|
| 1389 |  | 
|---|
| 1390 | typedef struct  GX_GVar_Head_ | 
|---|
| 1391 | { | 
|---|
| 1392 | FT_Long    version; | 
|---|
| 1393 | FT_UShort  axisCount; | 
|---|
| 1394 | FT_UShort  globalCoordCount; | 
|---|
| 1395 | FT_ULong   offsetToCoord; | 
|---|
| 1396 | FT_UShort  glyphCount; | 
|---|
| 1397 | FT_UShort  flags; | 
|---|
| 1398 | FT_ULong   offsetToData; | 
|---|
| 1399 |  | 
|---|
| 1400 | } GX_GVar_Head; | 
|---|
| 1401 |  | 
|---|
| 1402 |  | 
|---|
| 1403 | /*************************************************************************/ | 
|---|
| 1404 | /*                                                                       */ | 
|---|
| 1405 | /* <Function>                                                            */ | 
|---|
| 1406 | /*    ft_var_load_gvar                                                   */ | 
|---|
| 1407 | /*                                                                       */ | 
|---|
| 1408 | /* <Description>                                                         */ | 
|---|
| 1409 | /*    Parse the `gvar' table if present.  If `fvar' is there, `gvar' had */ | 
|---|
| 1410 | /*    better be there too.                                               */ | 
|---|
| 1411 | /*                                                                       */ | 
|---|
| 1412 | /* <InOut>                                                               */ | 
|---|
| 1413 | /*    face :: The font face.                                             */ | 
|---|
| 1414 | /*                                                                       */ | 
|---|
| 1415 | /* <Return>                                                              */ | 
|---|
| 1416 | /*    FreeType error code.  0 means success.                             */ | 
|---|
| 1417 | /*                                                                       */ | 
|---|
| 1418 | static FT_Error | 
|---|
| 1419 | ft_var_load_gvar( TT_Face  face ) | 
|---|
| 1420 | { | 
|---|
| 1421 | FT_Stream     stream = FT_FACE_STREAM( face ); | 
|---|
| 1422 | FT_Memory     memory = stream->memory; | 
|---|
| 1423 | GX_Blend      blend  = face->blend; | 
|---|
| 1424 | FT_Error      error; | 
|---|
| 1425 | FT_UInt       i, j; | 
|---|
| 1426 | FT_ULong      table_len; | 
|---|
| 1427 | FT_ULong      gvar_start; | 
|---|
| 1428 | FT_ULong      offsetToData; | 
|---|
| 1429 | GX_GVar_Head  gvar_head; | 
|---|
| 1430 |  | 
|---|
| 1431 | static const FT_Frame_Field  gvar_fields[] = | 
|---|
| 1432 | { | 
|---|
| 1433 |  | 
|---|
| 1434 | #undef  FT_STRUCTURE | 
|---|
| 1435 | #define FT_STRUCTURE  GX_GVar_Head | 
|---|
| 1436 |  | 
|---|
| 1437 | FT_FRAME_START( 20 ), | 
|---|
| 1438 | FT_FRAME_LONG  ( version ), | 
|---|
| 1439 | FT_FRAME_USHORT( axisCount ), | 
|---|
| 1440 | FT_FRAME_USHORT( globalCoordCount ), | 
|---|
| 1441 | FT_FRAME_ULONG ( offsetToCoord ), | 
|---|
| 1442 | FT_FRAME_USHORT( glyphCount ), | 
|---|
| 1443 | FT_FRAME_USHORT( flags ), | 
|---|
| 1444 | FT_FRAME_ULONG ( offsetToData ), | 
|---|
| 1445 | FT_FRAME_END | 
|---|
| 1446 | }; | 
|---|
| 1447 |  | 
|---|
| 1448 |  | 
|---|
| 1449 | FT_TRACE2(( "GVAR ")); | 
|---|
| 1450 |  | 
|---|
| 1451 | if ( FT_SET_ERROR( face->goto_table( face, | 
|---|
| 1452 | TTAG_gvar, | 
|---|
| 1453 | stream, | 
|---|
| 1454 | &table_len ) ) ) | 
|---|
| 1455 | { | 
|---|
| 1456 | FT_TRACE2(( "is missing\n")); | 
|---|
| 1457 | goto Exit; | 
|---|
| 1458 | } | 
|---|
| 1459 |  | 
|---|
| 1460 | gvar_start = FT_STREAM_POS( ); | 
|---|
| 1461 | if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) ) | 
|---|
| 1462 | goto Exit; | 
|---|
| 1463 |  | 
|---|
| 1464 | if ( gvar_head.version != 0x00010000L ) | 
|---|
| 1465 | { | 
|---|
| 1466 | FT_TRACE1(( "bad table version\n")); | 
|---|
| 1467 | error = FT_THROW( Invalid_Table ); | 
|---|
| 1468 | goto Exit; | 
|---|
| 1469 | } | 
|---|
| 1470 |  | 
|---|
| 1471 | if ( gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) | 
|---|
| 1472 | { | 
|---|
| 1473 | FT_TRACE1(( "ft_var_load_gvar: number of axes in `gvar' and `cvar'\n" | 
|---|
| 1474 | "                  table are different\n")); | 
|---|
| 1475 | error = FT_THROW( Invalid_Table ); | 
|---|
| 1476 | goto Exit; | 
|---|
| 1477 | } | 
|---|
| 1478 |  | 
|---|
| 1479 | /* rough sanity check, ignoring offsets */ | 
|---|
| 1480 | if ( (FT_ULong)gvar_head.globalCoordCount * gvar_head.axisCount > | 
|---|
| 1481 | table_len / 2 ) | 
|---|
| 1482 | { | 
|---|
| 1483 | FT_TRACE1(( "ft_var_load_gvar:" | 
|---|
| 1484 | " invalid number of global coordinates\n")); | 
|---|
| 1485 | error = FT_THROW( Invalid_Table ); | 
|---|
| 1486 | goto Exit; | 
|---|
| 1487 | } | 
|---|
| 1488 |  | 
|---|
| 1489 | /* rough sanity check: offsets can be either 2 or 4 bytes */ | 
|---|
| 1490 | if ( (FT_ULong)gvar_head.glyphCount * | 
|---|
| 1491 | ( ( gvar_head.flags & 1 ) ? 4 : 2 ) > table_len ) | 
|---|
| 1492 | { | 
|---|
| 1493 | FT_TRACE1(( "ft_var_load_gvar: invalid number of glyphs\n")); | 
|---|
| 1494 | error = FT_THROW( Invalid_Table ); | 
|---|
| 1495 | goto Exit; | 
|---|
| 1496 | } | 
|---|
| 1497 |  | 
|---|
| 1498 | FT_TRACE2(( "loaded\n")); | 
|---|
| 1499 |  | 
|---|
| 1500 | blend->gvar_size   = table_len; | 
|---|
| 1501 | blend->tuplecount  = gvar_head.globalCoordCount; | 
|---|
| 1502 | blend->gv_glyphcnt = gvar_head.glyphCount; | 
|---|
| 1503 | offsetToData       = gvar_start + gvar_head.offsetToData; | 
|---|
| 1504 |  | 
|---|
| 1505 | FT_TRACE5(( "gvar: there %s %d shared coordinate%s:\n", | 
|---|
| 1506 | blend->tuplecount == 1 ? "is": "are", | 
|---|
| 1507 | blend->tuplecount, | 
|---|
| 1508 | blend->tuplecount == 1 ? "": "s")); | 
|---|
| 1509 |  | 
|---|
| 1510 | if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) ) | 
|---|
| 1511 | goto Exit; | 
|---|
| 1512 |  | 
|---|
| 1513 | if ( gvar_head.flags & 1 ) | 
|---|
| 1514 | { | 
|---|
| 1515 | /* long offsets (one more offset than glyphs, to mark size of last) */ | 
|---|
| 1516 | if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) ) | 
|---|
| 1517 | goto Exit; | 
|---|
| 1518 |  | 
|---|
| 1519 | for ( i = 0; i <= blend->gv_glyphcnt; i++ ) | 
|---|
| 1520 | blend->glyphoffsets[i] = offsetToData + FT_GET_ULONG(); | 
|---|
| 1521 |  | 
|---|
| 1522 | FT_FRAME_EXIT(); | 
|---|
| 1523 | } | 
|---|
| 1524 | else | 
|---|
| 1525 | { | 
|---|
| 1526 | /* short offsets (one more offset than glyphs, to mark size of last) */ | 
|---|
| 1527 | if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) ) | 
|---|
| 1528 | goto Exit; | 
|---|
| 1529 |  | 
|---|
| 1530 | for ( i = 0; i <= blend->gv_glyphcnt; i++ ) | 
|---|
| 1531 | blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2; | 
|---|
| 1532 | /* XXX: Undocumented: `*2'! */ | 
|---|
| 1533 |  | 
|---|
| 1534 | FT_FRAME_EXIT(); | 
|---|
| 1535 | } | 
|---|
| 1536 |  | 
|---|
| 1537 | if ( blend->tuplecount != 0 ) | 
|---|
| 1538 | { | 
|---|
| 1539 | if ( FT_NEW_ARRAY( blend->tuplecoords, | 
|---|
| 1540 | gvar_head.axisCount * blend->tuplecount ) ) | 
|---|
| 1541 | goto Exit; | 
|---|
| 1542 |  | 
|---|
| 1543 | if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord )         || | 
|---|
| 1544 | FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) ) | 
|---|
| 1545 | goto Exit; | 
|---|
| 1546 |  | 
|---|
| 1547 | for ( i = 0; i < blend->tuplecount; i++ ) | 
|---|
| 1548 | { | 
|---|
| 1549 | FT_TRACE5(( "  [ ")); | 
|---|
| 1550 | for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ ) | 
|---|
| 1551 | { | 
|---|
| 1552 | blend->tuplecoords[i * gvar_head.axisCount + j] = | 
|---|
| 1553 | FT_GET_SHORT() * 4;                 /* convert to FT_Fixed */ | 
|---|
| 1554 | FT_TRACE5(( "%.5f ", | 
|---|
| 1555 | blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 )); | 
|---|
| 1556 | } | 
|---|
| 1557 | FT_TRACE5(( "]\n")); | 
|---|
| 1558 | } | 
|---|
| 1559 |  | 
|---|
| 1560 | FT_TRACE5(( "\n")); | 
|---|
| 1561 |  | 
|---|
| 1562 | FT_FRAME_EXIT(); | 
|---|
| 1563 | } | 
|---|
| 1564 |  | 
|---|
| 1565 | Exit: | 
|---|
| 1566 | return error; | 
|---|
| 1567 | } | 
|---|
| 1568 |  | 
|---|
| 1569 |  | 
|---|
| 1570 | /*************************************************************************/ | 
|---|
| 1571 | /*                                                                       */ | 
|---|
| 1572 | /* <Function>                                                            */ | 
|---|
| 1573 | /*    ft_var_apply_tuple                                                 */ | 
|---|
| 1574 | /*                                                                       */ | 
|---|
| 1575 | /* <Description>                                                         */ | 
|---|
| 1576 | /*    Figure out whether a given tuple (design) applies to the current   */ | 
|---|
| 1577 | /*    blend, and if so, what is the scaling factor.                      */ | 
|---|
| 1578 | /*                                                                       */ | 
|---|
| 1579 | /* <Input>                                                               */ | 
|---|
| 1580 | /*    blend           :: The current blend of the font.                  */ | 
|---|
| 1581 | /*                                                                       */ | 
|---|
| 1582 | /*    tupleIndex      :: A flag saying whether this is an intermediate   */ | 
|---|
| 1583 | /*                       tuple or not.                                   */ | 
|---|
| 1584 | /*                                                                       */ | 
|---|
| 1585 | /*    tuple_coords    :: The coordinates of the tuple in normalized axis */ | 
|---|
| 1586 | /*                       units.                                          */ | 
|---|
| 1587 | /*                                                                       */ | 
|---|
| 1588 | /*    im_start_coords :: The initial coordinates where this tuple starts */ | 
|---|
| 1589 | /*                       to apply (for intermediate coordinates).        */ | 
|---|
| 1590 | /*                                                                       */ | 
|---|
| 1591 | /*    im_end_coords   :: The final coordinates after which this tuple no */ | 
|---|
| 1592 | /*                       longer applies (for intermediate coordinates).  */ | 
|---|
| 1593 | /*                                                                       */ | 
|---|
| 1594 | /* <Return>                                                              */ | 
|---|
| 1595 | /*    An FT_Fixed value containing the scaling factor.                   */ | 
|---|
| 1596 | /*                                                                       */ | 
|---|
| 1597 | static FT_Fixed | 
|---|
| 1598 | ft_var_apply_tuple( GX_Blend   blend, | 
|---|
| 1599 | FT_UShort  tupleIndex, | 
|---|
| 1600 | FT_Fixed*  tuple_coords, | 
|---|
| 1601 | FT_Fixed*  im_start_coords, | 
|---|
| 1602 | FT_Fixed*  im_end_coords ) | 
|---|
| 1603 | { | 
|---|
| 1604 | FT_UInt   i; | 
|---|
| 1605 | FT_Fixed  apply = 0x10000L; | 
|---|
| 1606 |  | 
|---|
| 1607 |  | 
|---|
| 1608 | for ( i = 0; i < blend->num_axis; i++ ) | 
|---|
| 1609 | { | 
|---|
| 1610 | FT_TRACE6(( "    axis coordinate %d (%.5f):\n", | 
|---|
| 1611 | i, blend->normalizedcoords[i] / 65536.0 )); | 
|---|
| 1612 | if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) | 
|---|
| 1613 | FT_TRACE6(( "      intermediate coordinates %d (%.5f, %.5f):\n", | 
|---|
| 1614 | i, | 
|---|
| 1615 | im_start_coords[i] / 65536.0, | 
|---|
| 1616 | im_end_coords[i] / 65536.0 )); | 
|---|
| 1617 |  | 
|---|
| 1618 | /* It's not clear why (for intermediate tuples) we don't need     */ | 
|---|
| 1619 | /* to check against start/end -- the documentation says we don't. */ | 
|---|
| 1620 | /* Similarly, it's unclear why we don't need to scale along the   */ | 
|---|
| 1621 | /* axis.                                                          */ | 
|---|
| 1622 |  | 
|---|
| 1623 | if ( tuple_coords[i] == 0 ) | 
|---|
| 1624 | { | 
|---|
| 1625 | FT_TRACE6(( "      tuple coordinate is zero, ignored\n", i )); | 
|---|
| 1626 | continue; | 
|---|
| 1627 | } | 
|---|
| 1628 |  | 
|---|
| 1629 | if ( blend->normalizedcoords[i] == 0 ) | 
|---|
| 1630 | { | 
|---|
| 1631 | FT_TRACE6(( "      axis coordinate is zero, stop\n")); | 
|---|
| 1632 | apply = 0; | 
|---|
| 1633 | break; | 
|---|
| 1634 | } | 
|---|
| 1635 |  | 
|---|
| 1636 | if ( blend->normalizedcoords[i] == tuple_coords[i] ) | 
|---|
| 1637 | { | 
|---|
| 1638 | FT_TRACE6(( "      tuple coordinate value %.5f fits perfectly\n", | 
|---|
| 1639 | tuple_coords[i] / 65536.0 )); | 
|---|
| 1640 | /* `apply' does not change */ | 
|---|
| 1641 | continue; | 
|---|
| 1642 | } | 
|---|
| 1643 |  | 
|---|
| 1644 | if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) | 
|---|
| 1645 | { | 
|---|
| 1646 | /* not an intermediate tuple */ | 
|---|
| 1647 |  | 
|---|
| 1648 | if ( blend->normalizedcoords[i] < FT_MIN( 0, tuple_coords[i] ) || | 
|---|
| 1649 | blend->normalizedcoords[i] > FT_MAX( 0, tuple_coords[i] ) ) | 
|---|
| 1650 | { | 
|---|
| 1651 | FT_TRACE6(( "      tuple coordinate value %.5f is exceeded, stop\n", | 
|---|
| 1652 | tuple_coords[i] / 65536.0 )); | 
|---|
| 1653 | apply = 0; | 
|---|
| 1654 | break; | 
|---|
| 1655 | } | 
|---|
| 1656 |  | 
|---|
| 1657 | FT_TRACE6(( "      tuple coordinate value %.5f fits\n", | 
|---|
| 1658 | tuple_coords[i] / 65536.0 )); | 
|---|
| 1659 | apply = FT_MulDiv( apply, | 
|---|
| 1660 | blend->normalizedcoords[i], | 
|---|
| 1661 | tuple_coords[i] ); | 
|---|
| 1662 | } | 
|---|
| 1663 | else | 
|---|
| 1664 | { | 
|---|
| 1665 | /* intermediate tuple */ | 
|---|
| 1666 |  | 
|---|
| 1667 | if ( blend->normalizedcoords[i] < im_start_coords[i] || | 
|---|
| 1668 | blend->normalizedcoords[i] > im_end_coords[i]   ) | 
|---|
| 1669 | { | 
|---|
| 1670 | FT_TRACE6(( "      intermediate tuple range [%.5f;%.5f] is exceeded," | 
|---|
| 1671 | " stop\n", | 
|---|
| 1672 | im_start_coords[i] / 65536.0, | 
|---|
| 1673 | im_end_coords[i] / 65536.0 )); | 
|---|
| 1674 | apply = 0; | 
|---|
| 1675 | break; | 
|---|
| 1676 | } | 
|---|
| 1677 |  | 
|---|
| 1678 | else if ( blend->normalizedcoords[i] < tuple_coords[i] ) | 
|---|
| 1679 | { | 
|---|
| 1680 | FT_TRACE6(( "      intermediate tuple range [%.5f;%.5f] fits\n", | 
|---|
| 1681 | im_start_coords[i] / 65536.0, | 
|---|
| 1682 | im_end_coords[i] / 65536.0 )); | 
|---|
| 1683 | apply = FT_MulDiv( apply, | 
|---|
| 1684 | blend->normalizedcoords[i] - im_start_coords[i], | 
|---|
| 1685 | tuple_coords[i] - im_start_coords[i] ); | 
|---|
| 1686 | } | 
|---|
| 1687 |  | 
|---|
| 1688 | else | 
|---|
| 1689 | { | 
|---|
| 1690 | FT_TRACE6(( "      intermediate tuple range [%.5f;%.5f] fits\n", | 
|---|
| 1691 | im_start_coords[i] / 65536.0, | 
|---|
| 1692 | im_end_coords[i] / 65536.0 )); | 
|---|
| 1693 | apply = FT_MulDiv( apply, | 
|---|
| 1694 | im_end_coords[i] - blend->normalizedcoords[i], | 
|---|
| 1695 | im_end_coords[i] - tuple_coords[i] ); | 
|---|
| 1696 | } | 
|---|
| 1697 | } | 
|---|
| 1698 | } | 
|---|
| 1699 |  | 
|---|
| 1700 | FT_TRACE6(( "    apply factor is %.5f\n", apply / 65536.0 )); | 
|---|
| 1701 |  | 
|---|
| 1702 | return apply; | 
|---|
| 1703 | } | 
|---|
| 1704 |  | 
|---|
| 1705 |  | 
|---|
| 1706 | /* convert from design coordinates to normalized coordinates */ | 
|---|
| 1707 |  | 
|---|
| 1708 | static void | 
|---|
| 1709 | ft_var_to_normalized( TT_Face    face, | 
|---|
| 1710 | FT_UInt    num_coords, | 
|---|
| 1711 | FT_Fixed*  coords, | 
|---|
| 1712 | FT_Fixed*  normalized ) | 
|---|
| 1713 | { | 
|---|
| 1714 | GX_Blend        blend; | 
|---|
| 1715 | FT_MM_Var*      mmvar; | 
|---|
| 1716 | FT_UInt         i, j; | 
|---|
| 1717 | FT_Var_Axis*    a; | 
|---|
| 1718 | GX_AVarSegment  av; | 
|---|
| 1719 |  | 
|---|
| 1720 |  | 
|---|
| 1721 | blend = face->blend; | 
|---|
| 1722 | mmvar = blend->mmvar; | 
|---|
| 1723 |  | 
|---|
| 1724 | if ( num_coords > mmvar->num_axis ) | 
|---|
| 1725 | { | 
|---|
| 1726 | FT_TRACE2(( "ft_var_to_normalized:" | 
|---|
| 1727 | " only using first %d of %d coordinates\n", | 
|---|
| 1728 | mmvar->num_axis, num_coords )); | 
|---|
| 1729 | num_coords = mmvar->num_axis; | 
|---|
| 1730 | } | 
|---|
| 1731 |  | 
|---|
| 1732 | /* Axis normalization is a two-stage process.  First we normalize */ | 
|---|
| 1733 | /* based on the [min,def,max] values for the axis to be [-1,0,1]. */ | 
|---|
| 1734 | /* Then, if there's an `avar' table, we renormalize this range.   */ | 
|---|
| 1735 |  | 
|---|
| 1736 | a = mmvar->axis; | 
|---|
| 1737 | for ( i = 0; i < num_coords; i++, a++ ) | 
|---|
| 1738 | { | 
|---|
| 1739 | FT_Fixed  coord = coords[i]; | 
|---|
| 1740 |  | 
|---|
| 1741 |  | 
|---|
| 1742 | FT_TRACE5(( "    %d: %.5f\n", i, coord / 65536.0 )); | 
|---|
| 1743 | if ( coord > a->maximum || coord < a->minimum ) | 
|---|
| 1744 | { | 
|---|
| 1745 | FT_TRACE1(( | 
|---|
| 1746 | "ft_var_to_normalized: design coordinate %.5f\n" | 
|---|
| 1747 | "                      is out of range [%.5f;%.5f]; clamping\n", | 
|---|
| 1748 | coord / 65536.0, | 
|---|
| 1749 | a->minimum / 65536.0, | 
|---|
| 1750 | a->maximum / 65536.0 )); | 
|---|
| 1751 |  | 
|---|
| 1752 | if ( coord > a->maximum ) | 
|---|
| 1753 | coord = a->maximum; | 
|---|
| 1754 | else | 
|---|
| 1755 | coord = a->minimum; | 
|---|
| 1756 | } | 
|---|
| 1757 |  | 
|---|
| 1758 | if ( coord < a->def ) | 
|---|
| 1759 | normalized[i] = -FT_DivFix( coord - a->def, | 
|---|
| 1760 | a->minimum - a->def ); | 
|---|
| 1761 | else if ( coord > a->def ) | 
|---|
| 1762 | normalized[i] = FT_DivFix( coord - a->def, | 
|---|
| 1763 | a->maximum - a->def ); | 
|---|
| 1764 | else | 
|---|
| 1765 | normalized[i] = 0; | 
|---|
| 1766 | } | 
|---|
| 1767 |  | 
|---|
| 1768 | FT_TRACE5(( "\n")); | 
|---|
| 1769 |  | 
|---|
| 1770 | for ( ; i < mmvar->num_axis; i++ ) | 
|---|
| 1771 | normalized[i] = 0; | 
|---|
| 1772 |  | 
|---|
| 1773 | if ( blend->avar_segment ) | 
|---|
| 1774 | { | 
|---|
| 1775 | FT_TRACE5(( "normalized design coordinates" | 
|---|
| 1776 | " before applying `avar' data:\n")); | 
|---|
| 1777 |  | 
|---|
| 1778 | av = blend->avar_segment; | 
|---|
| 1779 | for ( i = 0; i < mmvar->num_axis; i++, av++ ) | 
|---|
| 1780 | { | 
|---|
| 1781 | for ( j = 1; j < (FT_UInt)av->pairCount; j++ ) | 
|---|
| 1782 | { | 
|---|
| 1783 | if ( normalized[i] < av->correspondence[j].fromCoord ) | 
|---|
| 1784 | { | 
|---|
| 1785 | FT_TRACE5(( "  %.5f\n", normalized[i] / 65536.0 )); | 
|---|
| 1786 |  | 
|---|
| 1787 | normalized[i] = | 
|---|
| 1788 | FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord, | 
|---|
| 1789 | av->correspondence[j].toCoord - | 
|---|
| 1790 | av->correspondence[j - 1].toCoord, | 
|---|
| 1791 | av->correspondence[j].fromCoord - | 
|---|
| 1792 | av->correspondence[j - 1].fromCoord ) + | 
|---|
| 1793 | av->correspondence[j - 1].toCoord; | 
|---|
| 1794 | break; | 
|---|
| 1795 | } | 
|---|
| 1796 | } | 
|---|
| 1797 | } | 
|---|
| 1798 | } | 
|---|
| 1799 | } | 
|---|
| 1800 |  | 
|---|
| 1801 |  | 
|---|
| 1802 | /* convert from normalized coordinates to design coordinates */ | 
|---|
| 1803 |  | 
|---|
| 1804 | static void | 
|---|
| 1805 | ft_var_to_design( TT_Face    face, | 
|---|
| 1806 | FT_UInt    num_coords, | 
|---|
| 1807 | FT_Fixed*  coords, | 
|---|
| 1808 | FT_Fixed*  design ) | 
|---|
| 1809 | { | 
|---|
| 1810 | GX_Blend      blend; | 
|---|
| 1811 | FT_MM_Var*    mmvar; | 
|---|
| 1812 | FT_Var_Axis*  a; | 
|---|
| 1813 |  | 
|---|
| 1814 | FT_UInt  i, j, nc; | 
|---|
| 1815 |  | 
|---|
| 1816 |  | 
|---|
| 1817 | blend = face->blend; | 
|---|
| 1818 |  | 
|---|
| 1819 | nc = num_coords; | 
|---|
| 1820 | if ( num_coords > blend->num_axis ) | 
|---|
| 1821 | { | 
|---|
| 1822 | FT_TRACE2(( "ft_var_to_design:" | 
|---|
| 1823 | " only using first %d of %d coordinates\n", | 
|---|
| 1824 | blend->num_axis, num_coords )); | 
|---|
| 1825 | nc = blend->num_axis; | 
|---|
| 1826 | } | 
|---|
| 1827 |  | 
|---|
| 1828 | for ( i = 0; i < nc; i++ ) | 
|---|
| 1829 | design[i] = coords[i]; | 
|---|
| 1830 |  | 
|---|
| 1831 | for ( ; i < num_coords; i++ ) | 
|---|
| 1832 | design[i] = 0; | 
|---|
| 1833 |  | 
|---|
| 1834 | if ( blend->avar_segment ) | 
|---|
| 1835 | { | 
|---|
| 1836 | GX_AVarSegment  av = blend->avar_segment; | 
|---|
| 1837 |  | 
|---|
| 1838 |  | 
|---|
| 1839 | FT_TRACE5(( "design coordinates" | 
|---|
| 1840 | " after removing `avar' distortion:\n")); | 
|---|
| 1841 |  | 
|---|
| 1842 | for ( i = 0; i < nc; i++, av++ ) | 
|---|
| 1843 | { | 
|---|
| 1844 | for ( j = 1; j < (FT_UInt)av->pairCount; j++ ) | 
|---|
| 1845 | { | 
|---|
| 1846 | if ( design[i] < av->correspondence[j].toCoord ) | 
|---|
| 1847 | { | 
|---|
| 1848 | design[i] = | 
|---|
| 1849 | FT_MulDiv( design[i] - av->correspondence[j - 1].toCoord, | 
|---|
| 1850 | av->correspondence[j].fromCoord - | 
|---|
| 1851 | av->correspondence[j - 1].fromCoord, | 
|---|
| 1852 | av->correspondence[j].toCoord - | 
|---|
| 1853 | av->correspondence[j - 1].toCoord ) + | 
|---|
| 1854 | av->correspondence[j - 1].fromCoord; | 
|---|
| 1855 |  | 
|---|
| 1856 | FT_TRACE5(( "  %.5f\n", design[i] / 65536.0 )); | 
|---|
| 1857 | break; | 
|---|
| 1858 | } | 
|---|
| 1859 | } | 
|---|
| 1860 | } | 
|---|
| 1861 | } | 
|---|
| 1862 |  | 
|---|
| 1863 | mmvar = blend->mmvar; | 
|---|
| 1864 | a     = mmvar->axis; | 
|---|
| 1865 |  | 
|---|
| 1866 | for ( i = 0; i < nc; i++, a++ ) | 
|---|
| 1867 | { | 
|---|
| 1868 | if ( design[i] < 0 ) | 
|---|
| 1869 | design[i] = a->def + FT_MulFix( design[i], | 
|---|
| 1870 | a->def - a->minimum ); | 
|---|
| 1871 | else if ( design[i] > 0 ) | 
|---|
| 1872 | design[i] = a->def + FT_MulFix( design[i], | 
|---|
| 1873 | a->maximum - a->def ); | 
|---|
| 1874 | else | 
|---|
| 1875 | design[i] = a->def; | 
|---|
| 1876 | } | 
|---|
| 1877 | } | 
|---|
| 1878 |  | 
|---|
| 1879 |  | 
|---|
| 1880 | /*************************************************************************/ | 
|---|
| 1881 | /*************************************************************************/ | 
|---|
| 1882 | /*****                                                               *****/ | 
|---|
| 1883 | /*****               MULTIPLE MASTERS SERVICE FUNCTIONS              *****/ | 
|---|
| 1884 | /*****                                                               *****/ | 
|---|
| 1885 | /*************************************************************************/ | 
|---|
| 1886 | /*************************************************************************/ | 
|---|
| 1887 |  | 
|---|
| 1888 |  | 
|---|
| 1889 | typedef struct  GX_FVar_Head_ | 
|---|
| 1890 | { | 
|---|
| 1891 | FT_Long    version; | 
|---|
| 1892 | FT_UShort  offsetToData; | 
|---|
| 1893 | FT_UShort  axisCount; | 
|---|
| 1894 | FT_UShort  axisSize; | 
|---|
| 1895 | FT_UShort  instanceCount; | 
|---|
| 1896 | FT_UShort  instanceSize; | 
|---|
| 1897 |  | 
|---|
| 1898 | } GX_FVar_Head; | 
|---|
| 1899 |  | 
|---|
| 1900 |  | 
|---|
| 1901 | typedef struct  fvar_axis_ | 
|---|
| 1902 | { | 
|---|
| 1903 | FT_ULong   axisTag; | 
|---|
| 1904 | FT_Fixed   minValue; | 
|---|
| 1905 | FT_Fixed   defaultValue; | 
|---|
| 1906 | FT_Fixed   maxValue; | 
|---|
| 1907 | FT_UShort  flags; | 
|---|
| 1908 | FT_UShort  nameID; | 
|---|
| 1909 |  | 
|---|
| 1910 | } GX_FVar_Axis; | 
|---|
| 1911 |  | 
|---|
| 1912 |  | 
|---|
| 1913 | /*************************************************************************/ | 
|---|
| 1914 | /*                                                                       */ | 
|---|
| 1915 | /* <Function>                                                            */ | 
|---|
| 1916 | /*    TT_Get_MM_Var                                                      */ | 
|---|
| 1917 | /*                                                                       */ | 
|---|
| 1918 | /* <Description>                                                         */ | 
|---|
| 1919 | /*    Check that the font's `fvar' table is valid, parse it, and return  */ | 
|---|
| 1920 | /*    those data.  It also loads (and parses) the `MVAR' table, if       */ | 
|---|
| 1921 | /*    possible.                                                          */ | 
|---|
| 1922 | /*                                                                       */ | 
|---|
| 1923 | /* <InOut>                                                               */ | 
|---|
| 1924 | /*    face   :: The font face.                                           */ | 
|---|
| 1925 | /*              TT_Get_MM_Var initializes the blend structure.           */ | 
|---|
| 1926 | /*                                                                       */ | 
|---|
| 1927 | /* <Output>                                                              */ | 
|---|
| 1928 | /*    master :: The `fvar' data (must be freed by caller).  Can be NULL, */ | 
|---|
| 1929 | /*              which makes this function simply load MM support.        */ | 
|---|
| 1930 | /*                                                                       */ | 
|---|
| 1931 | /* <Return>                                                              */ | 
|---|
| 1932 | /*    FreeType error code.  0 means success.                             */ | 
|---|
| 1933 | /*                                                                       */ | 
|---|
| 1934 | FT_LOCAL_DEF( FT_Error ) | 
|---|
| 1935 | TT_Get_MM_Var( TT_Face      face, | 
|---|
| 1936 | FT_MM_Var*  *master ) | 
|---|
| 1937 | { | 
|---|
| 1938 | FT_Stream            stream     = face->root.stream; | 
|---|
| 1939 | FT_Memory            memory     = face->root.memory; | 
|---|
| 1940 | FT_ULong             table_len; | 
|---|
| 1941 | FT_Error             error      = FT_Err_Ok; | 
|---|
| 1942 | FT_ULong             fvar_start = 0; | 
|---|
| 1943 | FT_UInt              i, j; | 
|---|
| 1944 | FT_MM_Var*           mmvar = NULL; | 
|---|
| 1945 | FT_Fixed*            next_coords; | 
|---|
| 1946 | FT_Fixed*            nsc; | 
|---|
| 1947 | FT_String*           next_name; | 
|---|
| 1948 | FT_Var_Axis*         a; | 
|---|
| 1949 | FT_Fixed*            c; | 
|---|
| 1950 | FT_Var_Named_Style*  ns; | 
|---|
| 1951 | GX_FVar_Head         fvar_head; | 
|---|
| 1952 | FT_Bool              usePsName  = 0; | 
|---|
| 1953 | FT_UInt              num_instances; | 
|---|
| 1954 | FT_UInt              num_axes; | 
|---|
| 1955 | FT_UShort*           axis_flags; | 
|---|
| 1956 |  | 
|---|
| 1957 | FT_Offset  mmvar_size; | 
|---|
| 1958 | FT_Offset  axis_flags_size; | 
|---|
| 1959 | FT_Offset  axis_size; | 
|---|
| 1960 | FT_Offset  namedstyle_size; | 
|---|
| 1961 | FT_Offset  next_coords_size; | 
|---|
| 1962 | FT_Offset  next_name_size; | 
|---|
| 1963 |  | 
|---|
| 1964 | FT_Bool  need_init; | 
|---|
| 1965 |  | 
|---|
| 1966 | static const FT_Frame_Field  fvar_fields[] = | 
|---|
| 1967 | { | 
|---|
| 1968 |  | 
|---|
| 1969 | #undef  FT_STRUCTURE | 
|---|
| 1970 | #define FT_STRUCTURE  GX_FVar_Head | 
|---|
| 1971 |  | 
|---|
| 1972 | FT_FRAME_START( 16 ), | 
|---|
| 1973 | FT_FRAME_LONG      ( version ), | 
|---|
| 1974 | FT_FRAME_USHORT    ( offsetToData ), | 
|---|
| 1975 | FT_FRAME_SKIP_SHORT, | 
|---|
| 1976 | FT_FRAME_USHORT    ( axisCount ), | 
|---|
| 1977 | FT_FRAME_USHORT    ( axisSize ), | 
|---|
| 1978 | FT_FRAME_USHORT    ( instanceCount ), | 
|---|
| 1979 | FT_FRAME_USHORT    ( instanceSize ), | 
|---|
| 1980 | FT_FRAME_END | 
|---|
| 1981 | }; | 
|---|
| 1982 |  | 
|---|
| 1983 | static const FT_Frame_Field  fvaraxis_fields[] = | 
|---|
| 1984 | { | 
|---|
| 1985 |  | 
|---|
| 1986 | #undef  FT_STRUCTURE | 
|---|
| 1987 | #define FT_STRUCTURE  GX_FVar_Axis | 
|---|
| 1988 |  | 
|---|
| 1989 | FT_FRAME_START( 20 ), | 
|---|
| 1990 | FT_FRAME_ULONG ( axisTag ), | 
|---|
| 1991 | FT_FRAME_LONG  ( minValue ), | 
|---|
| 1992 | FT_FRAME_LONG  ( defaultValue ), | 
|---|
| 1993 | FT_FRAME_LONG  ( maxValue ), | 
|---|
| 1994 | FT_FRAME_USHORT( flags ), | 
|---|
| 1995 | FT_FRAME_USHORT( nameID ), | 
|---|
| 1996 | FT_FRAME_END | 
|---|
| 1997 | }; | 
|---|
| 1998 |  | 
|---|
| 1999 |  | 
|---|
| 2000 | /* read the font data and set up the internal representation */ | 
|---|
| 2001 | /* if not already done                                       */ | 
|---|
| 2002 |  | 
|---|
| 2003 | need_init = !face->blend; | 
|---|
| 2004 |  | 
|---|
| 2005 | if ( need_init ) | 
|---|
| 2006 | { | 
|---|
| 2007 | FT_TRACE2(( "FVAR ")); | 
|---|
| 2008 |  | 
|---|
| 2009 | /* both `fvar' and `gvar' must be present */ | 
|---|
| 2010 | if ( FT_SET_ERROR( face->goto_table( face, TTAG_gvar, | 
|---|
| 2011 | stream, &table_len ) ) ) | 
|---|
| 2012 | { | 
|---|
| 2013 | /* CFF2 is an alternate to gvar here */ | 
|---|
| 2014 | if ( FT_SET_ERROR( face->goto_table( face, TTAG_CFF2, | 
|---|
| 2015 | stream, &table_len ) ) ) | 
|---|
| 2016 | { | 
|---|
| 2017 | FT_TRACE1(( "\n" | 
|---|
| 2018 | "TT_Get_MM_Var: `gvar' or `CFF2' table is missing\n")); | 
|---|
| 2019 | goto Exit; | 
|---|
| 2020 | } | 
|---|
| 2021 | } | 
|---|
| 2022 |  | 
|---|
| 2023 | if ( FT_SET_ERROR( face->goto_table( face, TTAG_fvar, | 
|---|
| 2024 | stream, &table_len ) ) ) | 
|---|
| 2025 | { | 
|---|
| 2026 | FT_TRACE1(( "is missing\n")); | 
|---|
| 2027 | goto Exit; | 
|---|
| 2028 | } | 
|---|
| 2029 |  | 
|---|
| 2030 | fvar_start = FT_STREAM_POS( ); | 
|---|
| 2031 |  | 
|---|
| 2032 | /* the validity of the `fvar' header data was already checked */ | 
|---|
| 2033 | /* in function `sfnt_init_face'                               */ | 
|---|
| 2034 | if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) ) | 
|---|
| 2035 | goto Exit; | 
|---|
| 2036 |  | 
|---|
| 2037 | usePsName = FT_BOOL( fvar_head.instanceSize == | 
|---|
| 2038 | 6 + 4 * fvar_head.axisCount ); | 
|---|
| 2039 |  | 
|---|
| 2040 | FT_TRACE2(( "loaded\n")); | 
|---|
| 2041 |  | 
|---|
| 2042 | FT_TRACE5(( "%d variation ax%s\n", | 
|---|
| 2043 | fvar_head.axisCount, | 
|---|
| 2044 | fvar_head.axisCount == 1 ? "is": "es")); | 
|---|
| 2045 |  | 
|---|
| 2046 | if ( FT_NEW( face->blend ) ) | 
|---|
| 2047 | goto Exit; | 
|---|
| 2048 |  | 
|---|
| 2049 | num_axes              = fvar_head.axisCount; | 
|---|
| 2050 | face->blend->num_axis = num_axes; | 
|---|
| 2051 | } | 
|---|
| 2052 | else | 
|---|
| 2053 | num_axes = face->blend->num_axis; | 
|---|
| 2054 |  | 
|---|
| 2055 | /* `num_instances' holds the number of all named instances, */ | 
|---|
| 2056 | /* including the default instance which might be missing    */ | 
|---|
| 2057 | /* in fvar's table of named instances                       */ | 
|---|
| 2058 | num_instances = (FT_UInt)face->root.style_flags >> 16; | 
|---|
| 2059 |  | 
|---|
| 2060 | /* prepare storage area for MM data; this cannot overflow   */ | 
|---|
| 2061 | /* 32-bit arithmetic because of the size limits used in the */ | 
|---|
| 2062 | /* `fvar' table validity check in `sfnt_init_face'          */ | 
|---|
| 2063 |  | 
|---|
| 2064 | /* the various `*_size' variables, which we also use as     */ | 
|---|
| 2065 | /* offsets into the `mmlen' array, must be multiples of the */ | 
|---|
| 2066 | /* pointer size (except the last one); without such an      */ | 
|---|
| 2067 | /* alignment there might be runtime errors due to           */ | 
|---|
| 2068 | /* misaligned addresses                                     */ | 
|---|
| 2069 | #undef  ALIGN_SIZE | 
|---|
| 2070 | #define ALIGN_SIZE( n ) \ | 
|---|
| 2071 | ( ( (n) + sizeof (void*) - 1 ) & ~( sizeof (void*) - 1 ) ) | 
|---|
| 2072 |  | 
|---|
| 2073 | mmvar_size       = ALIGN_SIZE( sizeof ( FT_MM_Var ) ); | 
|---|
| 2074 | axis_flags_size  = ALIGN_SIZE( num_axes * | 
|---|
| 2075 | sizeof ( FT_UShort ) ); | 
|---|
| 2076 | axis_size        = ALIGN_SIZE( num_axes * | 
|---|
| 2077 | sizeof ( FT_Var_Axis ) ); | 
|---|
| 2078 | namedstyle_size  = ALIGN_SIZE( num_instances * | 
|---|
| 2079 | sizeof ( FT_Var_Named_Style ) ); | 
|---|
| 2080 | next_coords_size = ALIGN_SIZE( num_instances * | 
|---|
| 2081 | num_axes * | 
|---|
| 2082 | sizeof ( FT_Fixed ) ); | 
|---|
| 2083 | next_name_size   = num_axes * 5; | 
|---|
| 2084 |  | 
|---|
| 2085 | if ( need_init ) | 
|---|
| 2086 | { | 
|---|
| 2087 | face->blend->mmvar_len = mmvar_size       + | 
|---|
| 2088 | axis_flags_size  + | 
|---|
| 2089 | axis_size        + | 
|---|
| 2090 | namedstyle_size  + | 
|---|
| 2091 | next_coords_size + | 
|---|
| 2092 | next_name_size; | 
|---|
| 2093 |  | 
|---|
| 2094 | if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) | 
|---|
| 2095 | goto Exit; | 
|---|
| 2096 | face->blend->mmvar = mmvar; | 
|---|
| 2097 |  | 
|---|
| 2098 | /* set up pointers and offsets into the `mmvar' array; */ | 
|---|
| 2099 | /* the data gets filled in later on                    */ | 
|---|
| 2100 |  | 
|---|
| 2101 | mmvar->num_axis = | 
|---|
| 2102 | num_axes; | 
|---|
| 2103 | mmvar->num_designs = | 
|---|
| 2104 | ~0U;                   /* meaningless in this context; each glyph */ | 
|---|
| 2105 | /* may have a different number of designs  */ | 
|---|
| 2106 | /* (or tuples, as called by Apple)         */ | 
|---|
| 2107 | mmvar->num_namedstyles = | 
|---|
| 2108 | num_instances; | 
|---|
| 2109 |  | 
|---|
| 2110 | /* alas, no public field in `FT_Var_Axis' for axis flags */ | 
|---|
| 2111 | axis_flags = | 
|---|
| 2112 | (FT_UShort*)( (char*)mmvar + mmvar_size ); | 
|---|
| 2113 | mmvar->axis = | 
|---|
| 2114 | (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size ); | 
|---|
| 2115 | mmvar->namedstyle = | 
|---|
| 2116 | (FT_Var_Named_Style*)( (char*)mmvar->axis + axis_size ); | 
|---|
| 2117 |  | 
|---|
| 2118 | next_coords = (FT_Fixed*)( (char*)mmvar->namedstyle + | 
|---|
| 2119 | namedstyle_size ); | 
|---|
| 2120 | for ( i = 0; i < num_instances; i++ ) | 
|---|
| 2121 | { | 
|---|
| 2122 | mmvar->namedstyle[i].coords  = next_coords; | 
|---|
| 2123 | next_coords                 += num_axes; | 
|---|
| 2124 | } | 
|---|
| 2125 |  | 
|---|
| 2126 | next_name = (FT_String*)( (char*)mmvar->namedstyle + | 
|---|
| 2127 | namedstyle_size + next_coords_size ); | 
|---|
| 2128 | for ( i = 0; i < num_axes; i++ ) | 
|---|
| 2129 | { | 
|---|
| 2130 | mmvar->axis[i].name  = next_name; | 
|---|
| 2131 | next_name           += 5; | 
|---|
| 2132 | } | 
|---|
| 2133 |  | 
|---|
| 2134 | /* now fill in the data */ | 
|---|
| 2135 |  | 
|---|
| 2136 | if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) ) | 
|---|
| 2137 | goto Exit; | 
|---|
| 2138 |  | 
|---|
| 2139 | a = mmvar->axis; | 
|---|
| 2140 | for ( i = 0; i < num_axes; i++ ) | 
|---|
| 2141 | { | 
|---|
| 2142 | GX_FVar_Axis  axis_rec; | 
|---|
| 2143 |  | 
|---|
| 2144 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 2145 | int  invalid = 0; | 
|---|
| 2146 | #endif | 
|---|
| 2147 |  | 
|---|
| 2148 |  | 
|---|
| 2149 | if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) ) | 
|---|
| 2150 | goto Exit; | 
|---|
| 2151 | a->tag     = axis_rec.axisTag; | 
|---|
| 2152 | a->minimum = axis_rec.minValue; | 
|---|
| 2153 | a->def     = axis_rec.defaultValue; | 
|---|
| 2154 | a->maximum = axis_rec.maxValue; | 
|---|
| 2155 | a->strid   = axis_rec.nameID; | 
|---|
| 2156 |  | 
|---|
| 2157 | a->name[0] = (FT_String)(   a->tag >> 24 ); | 
|---|
| 2158 | a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF ); | 
|---|
| 2159 | a->name[2] = (FT_String)( ( a->tag >>  8 ) & 0xFF ); | 
|---|
| 2160 | a->name[3] = (FT_String)( ( a->tag       ) & 0xFF ); | 
|---|
| 2161 | a->name[4] = '\0'; | 
|---|
| 2162 |  | 
|---|
| 2163 | *axis_flags = axis_rec.flags; | 
|---|
| 2164 |  | 
|---|
| 2165 | if ( a->minimum > a->def || | 
|---|
| 2166 | a->def > a->maximum ) | 
|---|
| 2167 | { | 
|---|
| 2168 | a->minimum = a->def; | 
|---|
| 2169 | a->maximum = a->def; | 
|---|
| 2170 |  | 
|---|
| 2171 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 2172 | invalid = 1; | 
|---|
| 2173 | #endif | 
|---|
| 2174 | } | 
|---|
| 2175 |  | 
|---|
| 2176 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 2177 | if ( i == 0 ) | 
|---|
| 2178 | FT_TRACE5(( "  idx   tag  " | 
|---|
| 2179 | /* "  XXX  `XXXX'" */ | 
|---|
| 2180 | "    minimum     default     maximum   flags\n")); | 
|---|
| 2181 | /* "  XXXX.XXXXX  XXXX.XXXXX  XXXX.XXXXX  0xXXXX" */ | 
|---|
| 2182 |  | 
|---|
| 2183 | FT_TRACE5(( "  %3d  `%s'" | 
|---|
| 2184 | "  %10.5f  %10.5f  %10.5f  0x%04X%s\n", | 
|---|
| 2185 | i, | 
|---|
| 2186 | a->name, | 
|---|
| 2187 | a->minimum / 65536.0, | 
|---|
| 2188 | a->def / 65536.0, | 
|---|
| 2189 | a->maximum / 65536.0, | 
|---|
| 2190 | *axis_flags, | 
|---|
| 2191 | invalid ? " (invalid, disabled)": "")); | 
|---|
| 2192 | #endif | 
|---|
| 2193 |  | 
|---|
| 2194 | a++; | 
|---|
| 2195 | axis_flags++; | 
|---|
| 2196 | } | 
|---|
| 2197 |  | 
|---|
| 2198 | FT_TRACE5(( "\n")); | 
|---|
| 2199 |  | 
|---|
| 2200 | /* named instance coordinates are stored as design coordinates; */ | 
|---|
| 2201 | /* we have to convert them to normalized coordinates also       */ | 
|---|
| 2202 | if ( FT_NEW_ARRAY( face->blend->normalized_stylecoords, | 
|---|
| 2203 | num_axes * num_instances ) ) | 
|---|
| 2204 | goto Exit; | 
|---|
| 2205 |  | 
|---|
| 2206 | if ( fvar_head.instanceCount && !face->blend->avar_loaded ) | 
|---|
| 2207 | { | 
|---|
| 2208 | FT_ULong  offset = FT_STREAM_POS(); | 
|---|
| 2209 |  | 
|---|
| 2210 |  | 
|---|
| 2211 | ft_var_load_avar( face ); | 
|---|
| 2212 |  | 
|---|
| 2213 | if ( FT_STREAM_SEEK( offset ) ) | 
|---|
| 2214 | goto Exit; | 
|---|
| 2215 | } | 
|---|
| 2216 |  | 
|---|
| 2217 | FT_TRACE5(( "%d instance%s\n", | 
|---|
| 2218 | fvar_head.instanceCount, | 
|---|
| 2219 | fvar_head.instanceCount == 1 ? "": "s")); | 
|---|
| 2220 |  | 
|---|
| 2221 | ns  = mmvar->namedstyle; | 
|---|
| 2222 | nsc = face->blend->normalized_stylecoords; | 
|---|
| 2223 | for ( i = 0; i < fvar_head.instanceCount; i++, ns++ ) | 
|---|
| 2224 | { | 
|---|
| 2225 | /* PostScript names add 2 bytes to the instance record size */ | 
|---|
| 2226 | if ( FT_FRAME_ENTER( ( usePsName ? 6L : 4L ) + | 
|---|
| 2227 | 4L * num_axes ) ) | 
|---|
| 2228 | goto Exit; | 
|---|
| 2229 |  | 
|---|
| 2230 | ns->strid       =    FT_GET_USHORT(); | 
|---|
| 2231 | (void) /* flags = */ FT_GET_USHORT(); | 
|---|
| 2232 |  | 
|---|
| 2233 | c = ns->coords; | 
|---|
| 2234 | for ( j = 0; j < num_axes; j++, c++ ) | 
|---|
| 2235 | *c = FT_GET_LONG(); | 
|---|
| 2236 |  | 
|---|
| 2237 | /* valid psid values are 6, [256;32767], and 0xFFFF */ | 
|---|
| 2238 | if ( usePsName ) | 
|---|
| 2239 | ns->psid = FT_GET_USHORT(); | 
|---|
| 2240 | else | 
|---|
| 2241 | ns->psid = 0xFFFF; | 
|---|
| 2242 |  | 
|---|
| 2243 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 2244 | { | 
|---|
| 2245 | SFNT_Service  sfnt = (SFNT_Service)face->sfnt; | 
|---|
| 2246 |  | 
|---|
| 2247 | FT_String*  strname = NULL; | 
|---|
| 2248 | FT_String*  psname  = NULL; | 
|---|
| 2249 |  | 
|---|
| 2250 | FT_ULong  pos; | 
|---|
| 2251 |  | 
|---|
| 2252 |  | 
|---|
| 2253 | pos = FT_STREAM_POS(); | 
|---|
| 2254 |  | 
|---|
| 2255 | if ( ns->strid != 0xFFFF ) | 
|---|
| 2256 | { | 
|---|
| 2257 | (void)sfnt->get_name( face, | 
|---|
| 2258 | (FT_UShort)ns->strid, | 
|---|
| 2259 | &strname ); | 
|---|
| 2260 | if ( strname && !ft_strcmp( strname, ".notdef") ) | 
|---|
| 2261 | strname = NULL; | 
|---|
| 2262 | } | 
|---|
| 2263 |  | 
|---|
| 2264 | if ( ns->psid != 0xFFFF ) | 
|---|
| 2265 | { | 
|---|
| 2266 | (void)sfnt->get_name( face, | 
|---|
| 2267 | (FT_UShort)ns->psid, | 
|---|
| 2268 | &psname ); | 
|---|
| 2269 | if ( psname && !ft_strcmp( psname, ".notdef") ) | 
|---|
| 2270 | psname = NULL; | 
|---|
| 2271 | } | 
|---|
| 2272 |  | 
|---|
| 2273 | (void)FT_STREAM_SEEK( pos ); | 
|---|
| 2274 |  | 
|---|
| 2275 | FT_TRACE5(( "  instance %d (%s%s%s, %s%s%s)\n", | 
|---|
| 2276 | i, | 
|---|
| 2277 | strname ? "name: `": "", | 
|---|
| 2278 | strname ? strname : "unnamed", | 
|---|
| 2279 | strname ? "'": "", | 
|---|
| 2280 | psname ? "PS name: `": "", | 
|---|
| 2281 | psname ? psname : "no PS name", | 
|---|
| 2282 | psname ? "'": "")); | 
|---|
| 2283 |  | 
|---|
| 2284 | FT_FREE( strname ); | 
|---|
| 2285 | FT_FREE( psname ); | 
|---|
| 2286 | } | 
|---|
| 2287 | #endif /* FT_DEBUG_LEVEL_TRACE */ | 
|---|
| 2288 |  | 
|---|
| 2289 | ft_var_to_normalized( face, num_axes, ns->coords, nsc ); | 
|---|
| 2290 | nsc += num_axes; | 
|---|
| 2291 |  | 
|---|
| 2292 | FT_FRAME_EXIT(); | 
|---|
| 2293 | } | 
|---|
| 2294 |  | 
|---|
| 2295 | if ( num_instances != fvar_head.instanceCount ) | 
|---|
| 2296 | { | 
|---|
| 2297 | SFNT_Service  sfnt = (SFNT_Service)face->sfnt; | 
|---|
| 2298 |  | 
|---|
| 2299 | FT_Int   found, dummy1, dummy2; | 
|---|
| 2300 | FT_UInt  strid = ~0U; | 
|---|
| 2301 |  | 
|---|
| 2302 |  | 
|---|
| 2303 | /* the default instance is missing in array the   */ | 
|---|
| 2304 | /* of named instances; try to synthesize an entry */ | 
|---|
| 2305 | found = sfnt->get_name_id( face, | 
|---|
| 2306 | TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY, | 
|---|
| 2307 | &dummy1, | 
|---|
| 2308 | &dummy2 ); | 
|---|
| 2309 | if ( found ) | 
|---|
| 2310 | strid = TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY; | 
|---|
| 2311 | else | 
|---|
| 2312 | { | 
|---|
| 2313 | found = sfnt->get_name_id( face, | 
|---|
| 2314 | TT_NAME_ID_FONT_SUBFAMILY, | 
|---|
| 2315 | &dummy1, | 
|---|
| 2316 | &dummy2 ); | 
|---|
| 2317 | if ( found ) | 
|---|
| 2318 | strid = TT_NAME_ID_FONT_SUBFAMILY; | 
|---|
| 2319 | } | 
|---|
| 2320 |  | 
|---|
| 2321 | if ( found ) | 
|---|
| 2322 | { | 
|---|
| 2323 | found = sfnt->get_name_id( face, | 
|---|
| 2324 | TT_NAME_ID_PS_NAME, | 
|---|
| 2325 | &dummy1, | 
|---|
| 2326 | &dummy2 ); | 
|---|
| 2327 | if ( found ) | 
|---|
| 2328 | { | 
|---|
| 2329 | FT_TRACE5(( "TT_Get_MM_Var:" | 
|---|
| 2330 | " Adding default instance to named instances\n")); | 
|---|
| 2331 |  | 
|---|
| 2332 | ns = &mmvar->namedstyle[fvar_head.instanceCount]; | 
|---|
| 2333 |  | 
|---|
| 2334 | ns->strid = strid; | 
|---|
| 2335 | ns->psid  = TT_NAME_ID_PS_NAME; | 
|---|
| 2336 |  | 
|---|
| 2337 | a = mmvar->axis; | 
|---|
| 2338 | c = ns->coords; | 
|---|
| 2339 | for ( j = 0; j < num_axes; j++, a++, c++ ) | 
|---|
| 2340 | *c = a->def; | 
|---|
| 2341 | } | 
|---|
| 2342 | } | 
|---|
| 2343 | } | 
|---|
| 2344 |  | 
|---|
| 2345 | ft_var_load_mvar( face ); | 
|---|
| 2346 | } | 
|---|
| 2347 |  | 
|---|
| 2348 | /* fill the output array if requested */ | 
|---|
| 2349 |  | 
|---|
| 2350 | if ( master ) | 
|---|
| 2351 | { | 
|---|
| 2352 | FT_UInt  n; | 
|---|
| 2353 |  | 
|---|
| 2354 |  | 
|---|
| 2355 | if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) | 
|---|
| 2356 | goto Exit; | 
|---|
| 2357 | FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len ); | 
|---|
| 2358 |  | 
|---|
| 2359 | axis_flags = | 
|---|
| 2360 | (FT_UShort*)( (char*)mmvar + mmvar_size ); | 
|---|
| 2361 | mmvar->axis = | 
|---|
| 2362 | (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size ); | 
|---|
| 2363 | mmvar->namedstyle = | 
|---|
| 2364 | (FT_Var_Named_Style*)( (char*)mmvar->axis+ axis_size ); | 
|---|
| 2365 |  | 
|---|
| 2366 | next_coords = (FT_Fixed*)( (char*)mmvar->namedstyle + | 
|---|
| 2367 | namedstyle_size ); | 
|---|
| 2368 | for ( n = 0; n < mmvar->num_namedstyles; n++ ) | 
|---|
| 2369 | { | 
|---|
| 2370 | mmvar->namedstyle[n].coords  = next_coords; | 
|---|
| 2371 | next_coords                 += num_axes; | 
|---|
| 2372 | } | 
|---|
| 2373 |  | 
|---|
| 2374 | a         = mmvar->axis; | 
|---|
| 2375 | next_name = (FT_String*)( (char*)mmvar->namedstyle + | 
|---|
| 2376 | namedstyle_size + next_coords_size ); | 
|---|
| 2377 | for ( n = 0; n < num_axes; n++ ) | 
|---|
| 2378 | { | 
|---|
| 2379 | a->name = next_name; | 
|---|
| 2380 |  | 
|---|
| 2381 | /* standard PostScript names for some standard apple tags */ | 
|---|
| 2382 | if ( a->tag == TTAG_wght ) | 
|---|
| 2383 | a->name = (char*) "Weight"; | 
|---|
| 2384 | else if ( a->tag == TTAG_wdth ) | 
|---|
| 2385 | a->name = (char*) "Width"; | 
|---|
| 2386 | else if ( a->tag == TTAG_opsz ) | 
|---|
| 2387 | a->name = (char*) "OpticalSize"; | 
|---|
| 2388 | else if ( a->tag == TTAG_slnt ) | 
|---|
| 2389 | a->name = (char*) "Slant"; | 
|---|
| 2390 |  | 
|---|
| 2391 | next_name += 5; | 
|---|
| 2392 | a++; | 
|---|
| 2393 | } | 
|---|
| 2394 |  | 
|---|
| 2395 | *master = mmvar; | 
|---|
| 2396 | } | 
|---|
| 2397 |  | 
|---|
| 2398 | Exit: | 
|---|
| 2399 | return error; | 
|---|
| 2400 | } | 
|---|
| 2401 |  | 
|---|
| 2402 |  | 
|---|
| 2403 | static FT_Error | 
|---|
| 2404 | tt_set_mm_blend( TT_Face    face, | 
|---|
| 2405 | FT_UInt    num_coords, | 
|---|
| 2406 | FT_Fixed*  coords, | 
|---|
| 2407 | FT_Bool    set_design_coords ) | 
|---|
| 2408 | { | 
|---|
| 2409 | FT_Error    error = FT_Err_Ok; | 
|---|
| 2410 | GX_Blend    blend; | 
|---|
| 2411 | FT_MM_Var*  mmvar; | 
|---|
| 2412 | FT_UInt     i; | 
|---|
| 2413 |  | 
|---|
| 2414 | FT_Bool     all_design_coords = FALSE; | 
|---|
| 2415 |  | 
|---|
| 2416 | FT_Memory   memory = face->root.memory; | 
|---|
| 2417 |  | 
|---|
| 2418 | enum | 
|---|
| 2419 | { | 
|---|
| 2420 | mcvt_retain, | 
|---|
| 2421 | mcvt_modify, | 
|---|
| 2422 | mcvt_load | 
|---|
| 2423 |  | 
|---|
| 2424 | } manageCvt; | 
|---|
| 2425 |  | 
|---|
| 2426 |  | 
|---|
| 2427 | face->doblend = FALSE; | 
|---|
| 2428 |  | 
|---|
| 2429 | if ( !face->blend ) | 
|---|
| 2430 | { | 
|---|
| 2431 | if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) | 
|---|
| 2432 | goto Exit; | 
|---|
| 2433 | } | 
|---|
| 2434 |  | 
|---|
| 2435 | blend = face->blend; | 
|---|
| 2436 | mmvar = blend->mmvar; | 
|---|
| 2437 |  | 
|---|
| 2438 | if ( num_coords > mmvar->num_axis ) | 
|---|
| 2439 | { | 
|---|
| 2440 | FT_TRACE2(( "TT_Set_MM_Blend:" | 
|---|
| 2441 | " only using first %d of %d coordinates\n", | 
|---|
| 2442 | mmvar->num_axis, num_coords )); | 
|---|
| 2443 | num_coords = mmvar->num_axis; | 
|---|
| 2444 | } | 
|---|
| 2445 |  | 
|---|
| 2446 | FT_TRACE5(( "TT_Set_MM_Blend:\n" | 
|---|
| 2447 | "  normalized design coordinates:\n")); | 
|---|
| 2448 |  | 
|---|
| 2449 | for ( i = 0; i < num_coords; i++ ) | 
|---|
| 2450 | { | 
|---|
| 2451 | FT_TRACE5(( "    %.5f\n", coords[i] / 65536.0 )); | 
|---|
| 2452 | if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L ) | 
|---|
| 2453 | { | 
|---|
| 2454 | FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.5f\n" | 
|---|
| 2455 | "                 is out of range [-1;1]\n", | 
|---|
| 2456 | coords[i] / 65536.0 )); | 
|---|
| 2457 | error = FT_THROW( Invalid_Argument ); | 
|---|
| 2458 | goto Exit; | 
|---|
| 2459 | } | 
|---|
| 2460 | } | 
|---|
| 2461 |  | 
|---|
| 2462 | FT_TRACE5(( "\n")); | 
|---|
| 2463 |  | 
|---|
| 2464 | if ( !face->is_cff2 && !blend->glyphoffsets ) | 
|---|
| 2465 | if ( FT_SET_ERROR( ft_var_load_gvar( face ) ) ) | 
|---|
| 2466 | goto Exit; | 
|---|
| 2467 |  | 
|---|
| 2468 | if ( !blend->coords ) | 
|---|
| 2469 | { | 
|---|
| 2470 | if ( FT_NEW_ARRAY( blend->coords, mmvar->num_axis ) ) | 
|---|
| 2471 | goto Exit; | 
|---|
| 2472 |  | 
|---|
| 2473 | /* the first time we have to compute all design coordinates */ | 
|---|
| 2474 | all_design_coords = TRUE; | 
|---|
| 2475 | } | 
|---|
| 2476 |  | 
|---|
| 2477 | if ( !blend->normalizedcoords ) | 
|---|
| 2478 | { | 
|---|
| 2479 | if ( FT_NEW_ARRAY( blend->normalizedcoords, mmvar->num_axis ) ) | 
|---|
| 2480 | goto Exit; | 
|---|
| 2481 |  | 
|---|
| 2482 | manageCvt = mcvt_modify; | 
|---|
| 2483 |  | 
|---|
| 2484 | /* If we have not set the blend coordinates before this, then the  */ | 
|---|
| 2485 | /* cvt table will still be what we read from the `cvt ' table and  */ | 
|---|
| 2486 | /* we don't need to reload it.  We may need to change it though... */ | 
|---|
| 2487 | } | 
|---|
| 2488 | else | 
|---|
| 2489 | { | 
|---|
| 2490 | FT_Bool    have_diff = 0; | 
|---|
| 2491 | FT_UInt    j; | 
|---|
| 2492 | FT_Fixed*  c; | 
|---|
| 2493 | FT_Fixed*  n; | 
|---|
| 2494 |  | 
|---|
| 2495 |  | 
|---|
| 2496 | manageCvt = mcvt_retain; | 
|---|
| 2497 |  | 
|---|
| 2498 | for ( i = 0; i < num_coords; i++ ) | 
|---|
| 2499 | { | 
|---|
| 2500 | if ( blend->normalizedcoords[i] != coords[i] ) | 
|---|
| 2501 | { | 
|---|
| 2502 | manageCvt = mcvt_load; | 
|---|
| 2503 | have_diff = 1; | 
|---|
| 2504 | break; | 
|---|
| 2505 | } | 
|---|
| 2506 | } | 
|---|
| 2507 |  | 
|---|
| 2508 | if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ) | 
|---|
| 2509 | { | 
|---|
| 2510 | FT_UInt  idx = (FT_UInt)face->root.face_index >> 16; | 
|---|
| 2511 |  | 
|---|
| 2512 |  | 
|---|
| 2513 | c = blend->normalizedcoords + i; | 
|---|
| 2514 | n = blend->normalized_stylecoords + idx * mmvar->num_axis + i; | 
|---|
| 2515 | for ( j = i; j < mmvar->num_axis; j++, n++, c++ ) | 
|---|
| 2516 | if ( *c != *n ) | 
|---|
| 2517 | have_diff = 1; | 
|---|
| 2518 | } | 
|---|
| 2519 | else | 
|---|
| 2520 | { | 
|---|
| 2521 | c = blend->normalizedcoords + i; | 
|---|
| 2522 | for ( j = i; j < mmvar->num_axis; j++, c++ ) | 
|---|
| 2523 | if ( *c != 0 ) | 
|---|
| 2524 | have_diff = 1; | 
|---|
| 2525 | } | 
|---|
| 2526 |  | 
|---|
| 2527 | /* return value -1 indicates `no change' */ | 
|---|
| 2528 | if ( !have_diff ) | 
|---|
| 2529 | return -1; | 
|---|
| 2530 |  | 
|---|
| 2531 | for ( ; i < mmvar->num_axis; i++ ) | 
|---|
| 2532 | { | 
|---|
| 2533 | if ( blend->normalizedcoords[i] != 0 ) | 
|---|
| 2534 | { | 
|---|
| 2535 | manageCvt = mcvt_load; | 
|---|
| 2536 | break; | 
|---|
| 2537 | } | 
|---|
| 2538 | } | 
|---|
| 2539 |  | 
|---|
| 2540 | /* If we don't change the blend coords then we don't need to do  */ | 
|---|
| 2541 | /* anything to the cvt table.  It will be correct.  Otherwise we */ | 
|---|
| 2542 | /* no longer have the original cvt (it was modified when we set  */ | 
|---|
| 2543 | /* the blend last time), so we must reload and then modify it.   */ | 
|---|
| 2544 | } | 
|---|
| 2545 |  | 
|---|
| 2546 | blend->num_axis = mmvar->num_axis; | 
|---|
| 2547 | FT_MEM_COPY( blend->normalizedcoords, | 
|---|
| 2548 | coords, | 
|---|
| 2549 | num_coords * sizeof ( FT_Fixed ) ); | 
|---|
| 2550 |  | 
|---|
| 2551 | if ( set_design_coords ) | 
|---|
| 2552 | ft_var_to_design( face, | 
|---|
| 2553 | all_design_coords ? blend->num_axis : num_coords, | 
|---|
| 2554 | blend->normalizedcoords, | 
|---|
| 2555 | blend->coords ); | 
|---|
| 2556 |  | 
|---|
| 2557 | face->doblend = TRUE; | 
|---|
| 2558 |  | 
|---|
| 2559 | if ( face->cvt ) | 
|---|
| 2560 | { | 
|---|
| 2561 | switch ( manageCvt ) | 
|---|
| 2562 | { | 
|---|
| 2563 | case mcvt_load: | 
|---|
| 2564 | /* The cvt table has been loaded already; every time we change the */ | 
|---|
| 2565 | /* blend we may need to reload and remodify the cvt table.         */ | 
|---|
| 2566 | FT_FREE( face->cvt ); | 
|---|
| 2567 | face->cvt = NULL; | 
|---|
| 2568 |  | 
|---|
| 2569 | error = tt_face_load_cvt( face, face->root.stream ); | 
|---|
| 2570 | break; | 
|---|
| 2571 |  | 
|---|
| 2572 | case mcvt_modify: | 
|---|
| 2573 | /* The original cvt table is in memory.  All we need to do is */ | 
|---|
| 2574 | /* apply the `cvar' table (if any).                           */ | 
|---|
| 2575 | error = tt_face_vary_cvt( face, face->root.stream ); | 
|---|
| 2576 | break; | 
|---|
| 2577 |  | 
|---|
| 2578 | case mcvt_retain: | 
|---|
| 2579 | /* The cvt table is correct for this set of coordinates. */ | 
|---|
| 2580 | break; | 
|---|
| 2581 | } | 
|---|
| 2582 | } | 
|---|
| 2583 |  | 
|---|
| 2584 | /* enforce recomputation of the PostScript name; */ | 
|---|
| 2585 | FT_FREE( face->postscript_name ); | 
|---|
| 2586 | face->postscript_name = NULL; | 
|---|
| 2587 |  | 
|---|
| 2588 | Exit: | 
|---|
| 2589 | return error; | 
|---|
| 2590 | } | 
|---|
| 2591 |  | 
|---|
| 2592 |  | 
|---|
| 2593 | /*************************************************************************/ | 
|---|
| 2594 | /*                                                                       */ | 
|---|
| 2595 | /* <Function>                                                            */ | 
|---|
| 2596 | /*    TT_Set_MM_Blend                                                    */ | 
|---|
| 2597 | /*                                                                       */ | 
|---|
| 2598 | /* <Description>                                                         */ | 
|---|
| 2599 | /*    Set the blend (normalized) coordinates for this instance of the    */ | 
|---|
| 2600 | /*    font.  Check that the `gvar' table is reasonable and does some     */ | 
|---|
| 2601 | /*    initial preparation.                                               */ | 
|---|
| 2602 | /*                                                                       */ | 
|---|
| 2603 | /* <InOut>                                                               */ | 
|---|
| 2604 | /*    face       :: The font.                                            */ | 
|---|
| 2605 | /*                  Initialize the blend structure with `gvar' data.     */ | 
|---|
| 2606 | /*                                                                       */ | 
|---|
| 2607 | /* <Input>                                                               */ | 
|---|
| 2608 | /*    num_coords :: The number of available coordinates.  If it is       */ | 
|---|
| 2609 | /*                  larger than the number of axes, ignore the excess    */ | 
|---|
| 2610 | /*                  values.  If it is smaller than the number of axes,   */ | 
|---|
| 2611 | /*                  use the default value (0) for the remaining axes.    */ | 
|---|
| 2612 | /*                                                                       */ | 
|---|
| 2613 | /*    coords     :: An array of `num_coords', each between [-1,1].       */ | 
|---|
| 2614 | /*                                                                       */ | 
|---|
| 2615 | /* <Return>                                                              */ | 
|---|
| 2616 | /*    FreeType error code.  0 means success.                             */ | 
|---|
| 2617 | /*                                                                       */ | 
|---|
| 2618 | FT_LOCAL_DEF( FT_Error ) | 
|---|
| 2619 | TT_Set_MM_Blend( TT_Face    face, | 
|---|
| 2620 | FT_UInt    num_coords, | 
|---|
| 2621 | FT_Fixed*  coords ) | 
|---|
| 2622 | { | 
|---|
| 2623 | FT_Error  error; | 
|---|
| 2624 |  | 
|---|
| 2625 |  | 
|---|
| 2626 | error = tt_set_mm_blend( face, num_coords, coords, 1 ); | 
|---|
| 2627 | if ( error ) | 
|---|
| 2628 | return error; | 
|---|
| 2629 |  | 
|---|
| 2630 | if ( num_coords ) | 
|---|
| 2631 | face->root.face_flags |= FT_FACE_FLAG_VARIATION; | 
|---|
| 2632 | else | 
|---|
| 2633 | face->root.face_flags &= ~FT_FACE_FLAG_VARIATION; | 
|---|
| 2634 |  | 
|---|
| 2635 | return FT_Err_Ok; | 
|---|
| 2636 | } | 
|---|
| 2637 |  | 
|---|
| 2638 |  | 
|---|
| 2639 | /*************************************************************************/ | 
|---|
| 2640 | /*                                                                       */ | 
|---|
| 2641 | /* <Function>                                                            */ | 
|---|
| 2642 | /*    TT_Get_MM_Blend                                                    */ | 
|---|
| 2643 | /*                                                                       */ | 
|---|
| 2644 | /* <Description>                                                         */ | 
|---|
| 2645 | /*    Get the blend (normalized) coordinates for this instance of the    */ | 
|---|
| 2646 | /*    font.                                                              */ | 
|---|
| 2647 | /*                                                                       */ | 
|---|
| 2648 | /* <InOut>                                                               */ | 
|---|
| 2649 | /*    face       :: The font.                                            */ | 
|---|
| 2650 | /*                  Initialize the blend structure with `gvar' data.     */ | 
|---|
| 2651 | /*                                                                       */ | 
|---|
| 2652 | /* <Input>                                                               */ | 
|---|
| 2653 | /*    num_coords :: The number of available coordinates.  If it is       */ | 
|---|
| 2654 | /*                  larger than the number of axes, set the excess       */ | 
|---|
| 2655 | /*                  values to 0.                                         */ | 
|---|
| 2656 | /*                                                                       */ | 
|---|
| 2657 | /*    coords     :: An array of `num_coords', each between [-1,1].       */ | 
|---|
| 2658 | /*                                                                       */ | 
|---|
| 2659 | /* <Return>                                                              */ | 
|---|
| 2660 | /*    FreeType error code.  0 means success.                             */ | 
|---|
| 2661 | /*                                                                       */ | 
|---|
| 2662 | FT_LOCAL_DEF( FT_Error ) | 
|---|
| 2663 | TT_Get_MM_Blend( TT_Face    face, | 
|---|
| 2664 | FT_UInt    num_coords, | 
|---|
| 2665 | FT_Fixed*  coords ) | 
|---|
| 2666 | { | 
|---|
| 2667 | FT_Error  error = FT_Err_Ok; | 
|---|
| 2668 | GX_Blend  blend; | 
|---|
| 2669 | FT_UInt   i, nc; | 
|---|
| 2670 |  | 
|---|
| 2671 |  | 
|---|
| 2672 | if ( !face->blend ) | 
|---|
| 2673 | { | 
|---|
| 2674 | if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) | 
|---|
| 2675 | return error; | 
|---|
| 2676 | } | 
|---|
| 2677 |  | 
|---|
| 2678 | blend = face->blend; | 
|---|
| 2679 |  | 
|---|
| 2680 | if ( !blend->coords ) | 
|---|
| 2681 | { | 
|---|
| 2682 | /* select default instance coordinates */ | 
|---|
| 2683 | /* if no instance is selected yet      */ | 
|---|
| 2684 | if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) ) | 
|---|
| 2685 | return error; | 
|---|
| 2686 | } | 
|---|
| 2687 |  | 
|---|
| 2688 | nc = num_coords; | 
|---|
| 2689 | if ( num_coords > blend->num_axis ) | 
|---|
| 2690 | { | 
|---|
| 2691 | FT_TRACE2(( "TT_Get_MM_Blend:" | 
|---|
| 2692 | " only using first %d of %d coordinates\n", | 
|---|
| 2693 | blend->num_axis, num_coords )); | 
|---|
| 2694 | nc = blend->num_axis; | 
|---|
| 2695 | } | 
|---|
| 2696 |  | 
|---|
| 2697 | if ( face->doblend ) | 
|---|
| 2698 | { | 
|---|
| 2699 | for ( i = 0; i < nc; i++ ) | 
|---|
| 2700 | coords[i] = blend->normalizedcoords[i]; | 
|---|
| 2701 | } | 
|---|
| 2702 | else | 
|---|
| 2703 | { | 
|---|
| 2704 | for ( i = 0; i < nc; i++ ) | 
|---|
| 2705 | coords[i] = 0; | 
|---|
| 2706 | } | 
|---|
| 2707 |  | 
|---|
| 2708 | for ( ; i < num_coords; i++ ) | 
|---|
| 2709 | coords[i] = 0; | 
|---|
| 2710 |  | 
|---|
| 2711 | return FT_Err_Ok; | 
|---|
| 2712 | } | 
|---|
| 2713 |  | 
|---|
| 2714 |  | 
|---|
| 2715 | /*************************************************************************/ | 
|---|
| 2716 | /*                                                                       */ | 
|---|
| 2717 | /* <Function>                                                            */ | 
|---|
| 2718 | /*    TT_Set_Var_Design                                                  */ | 
|---|
| 2719 | /*                                                                       */ | 
|---|
| 2720 | /* <Description>                                                         */ | 
|---|
| 2721 | /*    Set the coordinates for the instance, measured in the user         */ | 
|---|
| 2722 | /*    coordinate system.  Parse the `avar' table (if present) to convert */ | 
|---|
| 2723 | /*    from user to normalized coordinates.                               */ | 
|---|
| 2724 | /*                                                                       */ | 
|---|
| 2725 | /* <InOut>                                                               */ | 
|---|
| 2726 | /*    face       :: The font face.                                       */ | 
|---|
| 2727 | /*                  Initialize the blend struct with `gvar' data.        */ | 
|---|
| 2728 | /*                                                                       */ | 
|---|
| 2729 | /* <Input>                                                               */ | 
|---|
| 2730 | /*    num_coords :: The number of available coordinates.  If it is       */ | 
|---|
| 2731 | /*                  larger than the number of axes, ignore the excess    */ | 
|---|
| 2732 | /*                  values.  If it is smaller than the number of axes,   */ | 
|---|
| 2733 | /*                  use the default values for the remaining axes.       */ | 
|---|
| 2734 | /*                                                                       */ | 
|---|
| 2735 | /*    coords     :: A coordinate array with `num_coords' elements.       */ | 
|---|
| 2736 | /*                                                                       */ | 
|---|
| 2737 | /* <Return>                                                              */ | 
|---|
| 2738 | /*    FreeType error code.  0 means success.                             */ | 
|---|
| 2739 | /*                                                                       */ | 
|---|
| 2740 | FT_LOCAL_DEF( FT_Error ) | 
|---|
| 2741 | TT_Set_Var_Design( TT_Face    face, | 
|---|
| 2742 | FT_UInt    num_coords, | 
|---|
| 2743 | FT_Fixed*  coords ) | 
|---|
| 2744 | { | 
|---|
| 2745 | FT_Error    error  = FT_Err_Ok; | 
|---|
| 2746 | GX_Blend    blend; | 
|---|
| 2747 | FT_MM_Var*  mmvar; | 
|---|
| 2748 | FT_UInt     i; | 
|---|
| 2749 | FT_Memory   memory = face->root.memory; | 
|---|
| 2750 |  | 
|---|
| 2751 | FT_Fixed*  c; | 
|---|
| 2752 | FT_Fixed*  n; | 
|---|
| 2753 | FT_Fixed*  normalized = NULL; | 
|---|
| 2754 |  | 
|---|
| 2755 | FT_Bool  have_diff = 0; | 
|---|
| 2756 |  | 
|---|
| 2757 |  | 
|---|
| 2758 | if ( !face->blend ) | 
|---|
| 2759 | { | 
|---|
| 2760 | if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) | 
|---|
| 2761 | goto Exit; | 
|---|
| 2762 | } | 
|---|
| 2763 |  | 
|---|
| 2764 | blend = face->blend; | 
|---|
| 2765 | mmvar = blend->mmvar; | 
|---|
| 2766 |  | 
|---|
| 2767 | if ( num_coords > mmvar->num_axis ) | 
|---|
| 2768 | { | 
|---|
| 2769 | FT_TRACE2(( "TT_Set_Var_Design:" | 
|---|
| 2770 | " only using first %d of %d coordinates\n", | 
|---|
| 2771 | mmvar->num_axis, num_coords )); | 
|---|
| 2772 | num_coords = mmvar->num_axis; | 
|---|
| 2773 | } | 
|---|
| 2774 |  | 
|---|
| 2775 | if ( !blend->coords ) | 
|---|
| 2776 | { | 
|---|
| 2777 | if ( FT_NEW_ARRAY( blend->coords, mmvar->num_axis ) ) | 
|---|
| 2778 | goto Exit; | 
|---|
| 2779 | } | 
|---|
| 2780 |  | 
|---|
| 2781 | c = blend->coords; | 
|---|
| 2782 | n = coords; | 
|---|
| 2783 | for ( i = 0; i < num_coords; i++, n++, c++ ) | 
|---|
| 2784 | { | 
|---|
| 2785 | if ( *c != *n ) | 
|---|
| 2786 | { | 
|---|
| 2787 | *c        = *n; | 
|---|
| 2788 | have_diff = 1; | 
|---|
| 2789 | } | 
|---|
| 2790 | } | 
|---|
| 2791 |  | 
|---|
| 2792 | if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ) | 
|---|
| 2793 | { | 
|---|
| 2794 | FT_UInt              instance_index; | 
|---|
| 2795 | FT_Var_Named_Style*  named_style; | 
|---|
| 2796 |  | 
|---|
| 2797 |  | 
|---|
| 2798 | instance_index = (FT_UInt)face->root.face_index >> 16; | 
|---|
| 2799 | named_style    = mmvar->namedstyle + instance_index - 1; | 
|---|
| 2800 |  | 
|---|
| 2801 | n = named_style->coords + num_coords; | 
|---|
| 2802 | for ( ; i < mmvar->num_axis; i++, n++, c++ ) | 
|---|
| 2803 | { | 
|---|
| 2804 | if ( *c != *n ) | 
|---|
| 2805 | { | 
|---|
| 2806 | *c        = *n; | 
|---|
| 2807 | have_diff = 1; | 
|---|
| 2808 | } | 
|---|
| 2809 | } | 
|---|
| 2810 | } | 
|---|
| 2811 | else | 
|---|
| 2812 | { | 
|---|
| 2813 | FT_Var_Axis*  a; | 
|---|
| 2814 |  | 
|---|
| 2815 |  | 
|---|
| 2816 | a = mmvar->axis + num_coords; | 
|---|
| 2817 | for ( ; i < mmvar->num_axis; i++, a++, c++ ) | 
|---|
| 2818 | { | 
|---|
| 2819 | if ( *c != a->def ) | 
|---|
| 2820 | { | 
|---|
| 2821 | *c        = a->def; | 
|---|
| 2822 | have_diff = 1; | 
|---|
| 2823 | } | 
|---|
| 2824 | } | 
|---|
| 2825 | } | 
|---|
| 2826 |  | 
|---|
| 2827 | /* return value -1 indicates `no change';                      */ | 
|---|
| 2828 | /* we can exit early if `normalizedcoords' is already computed */ | 
|---|
| 2829 | if ( blend->normalizedcoords && !have_diff ) | 
|---|
| 2830 | return -1; | 
|---|
| 2831 |  | 
|---|
| 2832 | if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) ) | 
|---|
| 2833 | goto Exit; | 
|---|
| 2834 |  | 
|---|
| 2835 | if ( !face->blend->avar_loaded ) | 
|---|
| 2836 | ft_var_load_avar( face ); | 
|---|
| 2837 |  | 
|---|
| 2838 | FT_TRACE5(( "TT_Set_Var_Design:\n" | 
|---|
| 2839 | "  normalized design coordinates:\n")); | 
|---|
| 2840 | ft_var_to_normalized( face, num_coords, blend->coords, normalized ); | 
|---|
| 2841 |  | 
|---|
| 2842 | error = tt_set_mm_blend( face, mmvar->num_axis, normalized, 0 ); | 
|---|
| 2843 | if ( error ) | 
|---|
| 2844 | goto Exit; | 
|---|
| 2845 |  | 
|---|
| 2846 | if ( num_coords ) | 
|---|
| 2847 | face->root.face_flags |= FT_FACE_FLAG_VARIATION; | 
|---|
| 2848 | else | 
|---|
| 2849 | face->root.face_flags &= ~FT_FACE_FLAG_VARIATION; | 
|---|
| 2850 |  | 
|---|
| 2851 | Exit: | 
|---|
| 2852 | FT_FREE( normalized ); | 
|---|
| 2853 | return error; | 
|---|
| 2854 | } | 
|---|
| 2855 |  | 
|---|
| 2856 |  | 
|---|
| 2857 | /*************************************************************************/ | 
|---|
| 2858 | /*                                                                       */ | 
|---|
| 2859 | /* <Function>                                                            */ | 
|---|
| 2860 | /*    TT_Get_Var_Design                                                  */ | 
|---|
| 2861 | /*                                                                       */ | 
|---|
| 2862 | /* <Description>                                                         */ | 
|---|
| 2863 | /*    Get the design coordinates of the currently selected interpolated  */ | 
|---|
| 2864 | /*    font.                                                              */ | 
|---|
| 2865 | /*                                                                       */ | 
|---|
| 2866 | /* <Input>                                                               */ | 
|---|
| 2867 | /*    face       :: A handle to the source face.                         */ | 
|---|
| 2868 | /*                                                                       */ | 
|---|
| 2869 | /*    num_coords :: The number of design coordinates to retrieve.  If it */ | 
|---|
| 2870 | /*                  is larger than the number of axes, set the excess    */ | 
|---|
| 2871 | /*                  values to~0.                                         */ | 
|---|
| 2872 | /*                                                                       */ | 
|---|
| 2873 | /* <Output>                                                              */ | 
|---|
| 2874 | /*    coords     :: The design coordinates array.                        */ | 
|---|
| 2875 | /*                                                                       */ | 
|---|
| 2876 | /* <Return>                                                              */ | 
|---|
| 2877 | /*    FreeType error code.  0~means success.                             */ | 
|---|
| 2878 | /*                                                                       */ | 
|---|
| 2879 | FT_LOCAL_DEF( FT_Error ) | 
|---|
| 2880 | TT_Get_Var_Design( TT_Face    face, | 
|---|
| 2881 | FT_UInt    num_coords, | 
|---|
| 2882 | FT_Fixed*  coords ) | 
|---|
| 2883 | { | 
|---|
| 2884 | FT_Error  error = FT_Err_Ok; | 
|---|
| 2885 | GX_Blend  blend; | 
|---|
| 2886 | FT_UInt   i, nc; | 
|---|
| 2887 |  | 
|---|
| 2888 |  | 
|---|
| 2889 | if ( !face->blend ) | 
|---|
| 2890 | { | 
|---|
| 2891 | if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) | 
|---|
| 2892 | return error; | 
|---|
| 2893 | } | 
|---|
| 2894 |  | 
|---|
| 2895 | blend = face->blend; | 
|---|
| 2896 |  | 
|---|
| 2897 | if ( !blend->coords ) | 
|---|
| 2898 | { | 
|---|
| 2899 | /* select default instance coordinates */ | 
|---|
| 2900 | /* if no instance is selected yet      */ | 
|---|
| 2901 | if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) ) | 
|---|
| 2902 | return error; | 
|---|
| 2903 | } | 
|---|
| 2904 |  | 
|---|
| 2905 | nc = num_coords; | 
|---|
| 2906 | if ( num_coords > blend->num_axis ) | 
|---|
| 2907 | { | 
|---|
| 2908 | FT_TRACE2(( "TT_Get_Var_Design:" | 
|---|
| 2909 | " only using first %d of %d coordinates\n", | 
|---|
| 2910 | blend->num_axis, num_coords )); | 
|---|
| 2911 | nc = blend->num_axis; | 
|---|
| 2912 | } | 
|---|
| 2913 |  | 
|---|
| 2914 | if ( face->doblend ) | 
|---|
| 2915 | { | 
|---|
| 2916 | for ( i = 0; i < nc; i++ ) | 
|---|
| 2917 | coords[i] = blend->coords[i]; | 
|---|
| 2918 | } | 
|---|
| 2919 | else | 
|---|
| 2920 | { | 
|---|
| 2921 | for ( i = 0; i < nc; i++ ) | 
|---|
| 2922 | coords[i] = 0; | 
|---|
| 2923 | } | 
|---|
| 2924 |  | 
|---|
| 2925 | for ( ; i < num_coords; i++ ) | 
|---|
| 2926 | coords[i] = 0; | 
|---|
| 2927 |  | 
|---|
| 2928 | return FT_Err_Ok; | 
|---|
| 2929 | } | 
|---|
| 2930 |  | 
|---|
| 2931 |  | 
|---|
| 2932 | /*************************************************************************/ | 
|---|
| 2933 | /*                                                                       */ | 
|---|
| 2934 | /* <Function>                                                            */ | 
|---|
| 2935 | /*    TT_Set_Named_Instance                                              */ | 
|---|
| 2936 | /*                                                                       */ | 
|---|
| 2937 | /* <Description>                                                         */ | 
|---|
| 2938 | /*    Set the given named instance, also resetting any further           */ | 
|---|
| 2939 | /*    variation.                                                         */ | 
|---|
| 2940 | /*                                                                       */ | 
|---|
| 2941 | /* <Input>                                                               */ | 
|---|
| 2942 | /*    face           :: A handle to the source face.                     */ | 
|---|
| 2943 | /*                                                                       */ | 
|---|
| 2944 | /*    instance_index :: The instance index, starting with value 1.       */ | 
|---|
| 2945 | /*                      Value 0 indicates to not use an instance.        */ | 
|---|
| 2946 | /*                                                                       */ | 
|---|
| 2947 | /* <Return>                                                              */ | 
|---|
| 2948 | /*    FreeType error code.  0~means success.                             */ | 
|---|
| 2949 | /*                                                                       */ | 
|---|
| 2950 | FT_LOCAL_DEF( FT_Error ) | 
|---|
| 2951 | TT_Set_Named_Instance( TT_Face  face, | 
|---|
| 2952 | FT_UInt  instance_index ) | 
|---|
| 2953 | { | 
|---|
| 2954 | FT_Error    error = FT_ERR( Invalid_Argument ); | 
|---|
| 2955 | GX_Blend    blend; | 
|---|
| 2956 | FT_MM_Var*  mmvar; | 
|---|
| 2957 |  | 
|---|
| 2958 | FT_UInt  num_instances; | 
|---|
| 2959 |  | 
|---|
| 2960 |  | 
|---|
| 2961 | if ( !face->blend ) | 
|---|
| 2962 | { | 
|---|
| 2963 | if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) | 
|---|
| 2964 | goto Exit; | 
|---|
| 2965 | } | 
|---|
| 2966 |  | 
|---|
| 2967 | blend = face->blend; | 
|---|
| 2968 | mmvar = blend->mmvar; | 
|---|
| 2969 |  | 
|---|
| 2970 | num_instances = (FT_UInt)face->root.style_flags >> 16; | 
|---|
| 2971 |  | 
|---|
| 2972 | /* `instance_index' starts with value 1, thus `>' */ | 
|---|
| 2973 | if ( instance_index > num_instances ) | 
|---|
| 2974 | goto Exit; | 
|---|
| 2975 |  | 
|---|
| 2976 | if ( instance_index > 0 && mmvar->namedstyle ) | 
|---|
| 2977 | { | 
|---|
| 2978 | FT_Memory     memory = face->root.memory; | 
|---|
| 2979 | SFNT_Service  sfnt   = (SFNT_Service)face->sfnt; | 
|---|
| 2980 |  | 
|---|
| 2981 | FT_Var_Named_Style*  named_style; | 
|---|
| 2982 | FT_String*           style_name; | 
|---|
| 2983 |  | 
|---|
| 2984 |  | 
|---|
| 2985 | named_style = mmvar->namedstyle + instance_index - 1; | 
|---|
| 2986 |  | 
|---|
| 2987 | error = sfnt->get_name( face, | 
|---|
| 2988 | (FT_UShort)named_style->strid, | 
|---|
| 2989 | &style_name ); | 
|---|
| 2990 | if ( error ) | 
|---|
| 2991 | goto Exit; | 
|---|
| 2992 |  | 
|---|
| 2993 | /* set (or replace) style name */ | 
|---|
| 2994 | FT_FREE( face->root.style_name ); | 
|---|
| 2995 | face->root.style_name = style_name; | 
|---|
| 2996 |  | 
|---|
| 2997 | /* finally, select the named instance */ | 
|---|
| 2998 | error = TT_Set_Var_Design( face, | 
|---|
| 2999 | mmvar->num_axis, | 
|---|
| 3000 | named_style->coords ); | 
|---|
| 3001 | if ( error ) | 
|---|
| 3002 | goto Exit; | 
|---|
| 3003 | } | 
|---|
| 3004 | else | 
|---|
| 3005 | error = TT_Set_Var_Design( face, 0, NULL ); | 
|---|
| 3006 |  | 
|---|
| 3007 | face->root.face_index  = ( instance_index << 16 )             | | 
|---|
| 3008 | ( face->root.face_index & 0xFFFFL ); | 
|---|
| 3009 | face->root.face_flags &= ~FT_FACE_FLAG_VARIATION; | 
|---|
| 3010 |  | 
|---|
| 3011 | Exit: | 
|---|
| 3012 | return error; | 
|---|
| 3013 | } | 
|---|
| 3014 |  | 
|---|
| 3015 |  | 
|---|
| 3016 | /*************************************************************************/ | 
|---|
| 3017 | /*************************************************************************/ | 
|---|
| 3018 | /*****                                                               *****/ | 
|---|
| 3019 | /*****                     GX VAR PARSING ROUTINES                   *****/ | 
|---|
| 3020 | /*****                                                               *****/ | 
|---|
| 3021 | /*************************************************************************/ | 
|---|
| 3022 | /*************************************************************************/ | 
|---|
| 3023 |  | 
|---|
| 3024 |  | 
|---|
| 3025 | /*************************************************************************/ | 
|---|
| 3026 | /*                                                                       */ | 
|---|
| 3027 | /* <Function>                                                            */ | 
|---|
| 3028 | /*    tt_face_vary_cvt                                                   */ | 
|---|
| 3029 | /*                                                                       */ | 
|---|
| 3030 | /* <Description>                                                         */ | 
|---|
| 3031 | /*    Modify the loaded cvt table according to the `cvar' table and the  */ | 
|---|
| 3032 | /*    font's blend.                                                      */ | 
|---|
| 3033 | /*                                                                       */ | 
|---|
| 3034 | /* <InOut>                                                               */ | 
|---|
| 3035 | /*    face   :: A handle to the target face object.                      */ | 
|---|
| 3036 | /*                                                                       */ | 
|---|
| 3037 | /* <Input>                                                               */ | 
|---|
| 3038 | /*    stream :: A handle to the input stream.                            */ | 
|---|
| 3039 | /*                                                                       */ | 
|---|
| 3040 | /* <Return>                                                              */ | 
|---|
| 3041 | /*    FreeType error code.  0 means success.                             */ | 
|---|
| 3042 | /*                                                                       */ | 
|---|
| 3043 | /*    Most errors are ignored.  It is perfectly valid not to have a      */ | 
|---|
| 3044 | /*    `cvar' table even if there is a `gvar' and `fvar' table.           */ | 
|---|
| 3045 | /*                                                                       */ | 
|---|
| 3046 | FT_LOCAL_DEF( FT_Error ) | 
|---|
| 3047 | tt_face_vary_cvt( TT_Face    face, | 
|---|
| 3048 | FT_Stream  stream ) | 
|---|
| 3049 | { | 
|---|
| 3050 | FT_Error    error; | 
|---|
| 3051 | FT_Memory   memory = stream->memory; | 
|---|
| 3052 | FT_ULong    table_start; | 
|---|
| 3053 | FT_ULong    table_len; | 
|---|
| 3054 | FT_UInt     tupleCount; | 
|---|
| 3055 | FT_ULong    offsetToData; | 
|---|
| 3056 | FT_ULong    here; | 
|---|
| 3057 | FT_UInt     i, j; | 
|---|
| 3058 | FT_Fixed*   tuple_coords    = NULL; | 
|---|
| 3059 | FT_Fixed*   im_start_coords = NULL; | 
|---|
| 3060 | FT_Fixed*   im_end_coords   = NULL; | 
|---|
| 3061 | GX_Blend    blend           = face->blend; | 
|---|
| 3062 | FT_UInt     point_count, spoint_count = 0; | 
|---|
| 3063 | FT_UShort*  sharedpoints = NULL; | 
|---|
| 3064 | FT_UShort*  localpoints  = NULL; | 
|---|
| 3065 | FT_UShort*  points; | 
|---|
| 3066 | FT_Short*   deltas; | 
|---|
| 3067 |  | 
|---|
| 3068 |  | 
|---|
| 3069 | FT_TRACE2(( "CVAR ")); | 
|---|
| 3070 |  | 
|---|
| 3071 | if ( !blend ) | 
|---|
| 3072 | { | 
|---|
| 3073 | FT_TRACE2(( "\n" | 
|---|
| 3074 | "tt_face_vary_cvt: no blend specified\n")); | 
|---|
| 3075 | error = FT_Err_Ok; | 
|---|
| 3076 | goto Exit; | 
|---|
| 3077 | } | 
|---|
| 3078 |  | 
|---|
| 3079 | if ( !face->cvt ) | 
|---|
| 3080 | { | 
|---|
| 3081 | FT_TRACE2(( "\n" | 
|---|
| 3082 | "tt_face_vary_cvt: no `cvt ' table\n")); | 
|---|
| 3083 | error = FT_Err_Ok; | 
|---|
| 3084 | goto Exit; | 
|---|
| 3085 | } | 
|---|
| 3086 |  | 
|---|
| 3087 | error = face->goto_table( face, TTAG_cvar, stream, &table_len ); | 
|---|
| 3088 | if ( error ) | 
|---|
| 3089 | { | 
|---|
| 3090 | FT_TRACE2(( "is missing\n")); | 
|---|
| 3091 |  | 
|---|
| 3092 | error = FT_Err_Ok; | 
|---|
| 3093 | goto Exit; | 
|---|
| 3094 | } | 
|---|
| 3095 |  | 
|---|
| 3096 | if ( FT_FRAME_ENTER( table_len ) ) | 
|---|
| 3097 | { | 
|---|
| 3098 | error = FT_Err_Ok; | 
|---|
| 3099 | goto Exit; | 
|---|
| 3100 | } | 
|---|
| 3101 |  | 
|---|
| 3102 | table_start = FT_Stream_FTell( stream ); | 
|---|
| 3103 | if ( FT_GET_LONG() != 0x00010000L ) | 
|---|
| 3104 | { | 
|---|
| 3105 | FT_TRACE2(( "bad table version\n")); | 
|---|
| 3106 |  | 
|---|
| 3107 | error = FT_Err_Ok; | 
|---|
| 3108 | goto FExit; | 
|---|
| 3109 | } | 
|---|
| 3110 |  | 
|---|
| 3111 | FT_TRACE2(( "loaded\n")); | 
|---|
| 3112 |  | 
|---|
| 3113 | if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis )    || | 
|---|
| 3114 | FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || | 
|---|
| 3115 | FT_NEW_ARRAY( im_end_coords, blend->num_axis )   ) | 
|---|
| 3116 | goto FExit; | 
|---|
| 3117 |  | 
|---|
| 3118 | tupleCount   = FT_GET_USHORT(); | 
|---|
| 3119 | offsetToData = FT_GET_USHORT(); | 
|---|
| 3120 |  | 
|---|
| 3121 | /* rough sanity test */ | 
|---|
| 3122 | if ( offsetToData + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 > | 
|---|
| 3123 | table_len ) | 
|---|
| 3124 | { | 
|---|
| 3125 | FT_TRACE2(( "tt_face_vary_cvt:" | 
|---|
| 3126 | " invalid CVT variation array header\n")); | 
|---|
| 3127 |  | 
|---|
| 3128 | error = FT_THROW( Invalid_Table ); | 
|---|
| 3129 | goto FExit; | 
|---|
| 3130 | } | 
|---|
| 3131 |  | 
|---|
| 3132 | offsetToData += table_start; | 
|---|
| 3133 |  | 
|---|
| 3134 | if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) | 
|---|
| 3135 | { | 
|---|
| 3136 | here = FT_Stream_FTell( stream ); | 
|---|
| 3137 |  | 
|---|
| 3138 | FT_Stream_SeekSet( stream, offsetToData ); | 
|---|
| 3139 |  | 
|---|
| 3140 | sharedpoints = ft_var_readpackedpoints( stream, | 
|---|
| 3141 | table_len, | 
|---|
| 3142 | &spoint_count ); | 
|---|
| 3143 | offsetToData = FT_Stream_FTell( stream ); | 
|---|
| 3144 |  | 
|---|
| 3145 | FT_Stream_SeekSet( stream, here ); | 
|---|
| 3146 | } | 
|---|
| 3147 |  | 
|---|
| 3148 | FT_TRACE5(( "cvar: there %s %d tuple%s:\n", | 
|---|
| 3149 | ( tupleCount & 0xFFF ) == 1 ? "is": "are", | 
|---|
| 3150 | tupleCount & 0xFFF, | 
|---|
| 3151 | ( tupleCount & 0xFFF ) == 1 ? "": "s")); | 
|---|
| 3152 |  | 
|---|
| 3153 | for ( i = 0; i < ( tupleCount & 0xFFF ); i++ ) | 
|---|
| 3154 | { | 
|---|
| 3155 | FT_UInt   tupleDataSize; | 
|---|
| 3156 | FT_UInt   tupleIndex; | 
|---|
| 3157 | FT_Fixed  apply; | 
|---|
| 3158 |  | 
|---|
| 3159 |  | 
|---|
| 3160 | FT_TRACE6(( "  tuple %d:\n", i )); | 
|---|
| 3161 |  | 
|---|
| 3162 | tupleDataSize = FT_GET_USHORT(); | 
|---|
| 3163 | tupleIndex    = FT_GET_USHORT(); | 
|---|
| 3164 |  | 
|---|
| 3165 | if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) | 
|---|
| 3166 | { | 
|---|
| 3167 | for ( j = 0; j < blend->num_axis; j++ ) | 
|---|
| 3168 | tuple_coords[j] = FT_GET_SHORT() * 4;  /* convert from        */ | 
|---|
| 3169 | /* short frac to fixed */ | 
|---|
| 3170 | } | 
|---|
| 3171 | else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) | 
|---|
| 3172 | { | 
|---|
| 3173 | FT_TRACE2(( "tt_face_vary_cvt:" | 
|---|
| 3174 | " invalid tuple index\n")); | 
|---|
| 3175 |  | 
|---|
| 3176 | error = FT_THROW( Invalid_Table ); | 
|---|
| 3177 | goto Exit; | 
|---|
| 3178 | } | 
|---|
| 3179 | else | 
|---|
| 3180 | FT_MEM_COPY( | 
|---|
| 3181 | tuple_coords, | 
|---|
| 3182 | &blend->tuplecoords[( tupleIndex & 0xFFF ) * blend->num_axis], | 
|---|
| 3183 | blend->num_axis * sizeof ( FT_Fixed ) ); | 
|---|
| 3184 |  | 
|---|
| 3185 | if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) | 
|---|
| 3186 | { | 
|---|
| 3187 | for ( j = 0; j < blend->num_axis; j++ ) | 
|---|
| 3188 | im_start_coords[j] = FT_GET_SHORT() * 4; | 
|---|
| 3189 | for ( j = 0; j < blend->num_axis; j++ ) | 
|---|
| 3190 | im_end_coords[j] = FT_GET_SHORT() * 4; | 
|---|
| 3191 | } | 
|---|
| 3192 |  | 
|---|
| 3193 | apply = ft_var_apply_tuple( blend, | 
|---|
| 3194 | (FT_UShort)tupleIndex, | 
|---|
| 3195 | tuple_coords, | 
|---|
| 3196 | im_start_coords, | 
|---|
| 3197 | im_end_coords ); | 
|---|
| 3198 |  | 
|---|
| 3199 | if ( apply == 0 )              /* tuple isn't active for our blend */ | 
|---|
| 3200 | { | 
|---|
| 3201 | offsetToData += tupleDataSize; | 
|---|
| 3202 | continue; | 
|---|
| 3203 | } | 
|---|
| 3204 |  | 
|---|
| 3205 | here = FT_Stream_FTell( stream ); | 
|---|
| 3206 |  | 
|---|
| 3207 | FT_Stream_SeekSet( stream, offsetToData ); | 
|---|
| 3208 |  | 
|---|
| 3209 | if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) | 
|---|
| 3210 | { | 
|---|
| 3211 | localpoints = ft_var_readpackedpoints( stream, | 
|---|
| 3212 | table_len, | 
|---|
| 3213 | &point_count ); | 
|---|
| 3214 | points      = localpoints; | 
|---|
| 3215 | } | 
|---|
| 3216 | else | 
|---|
| 3217 | { | 
|---|
| 3218 | points      = sharedpoints; | 
|---|
| 3219 | point_count = spoint_count; | 
|---|
| 3220 | } | 
|---|
| 3221 |  | 
|---|
| 3222 | deltas = ft_var_readpackeddeltas( stream, | 
|---|
| 3223 | table_len, | 
|---|
| 3224 | point_count == 0 ? face->cvt_size | 
|---|
| 3225 | : point_count ); | 
|---|
| 3226 |  | 
|---|
| 3227 | if ( !points                                                        || | 
|---|
| 3228 | !deltas                                                        || | 
|---|
| 3229 | ( localpoints == ALL_POINTS && point_count != face->cvt_size ) ) | 
|---|
| 3230 | ; /* failure, ignore it */ | 
|---|
| 3231 |  | 
|---|
| 3232 | else if ( localpoints == ALL_POINTS ) | 
|---|
| 3233 | { | 
|---|
| 3234 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 3235 | int  count = 0; | 
|---|
| 3236 | #endif | 
|---|
| 3237 |  | 
|---|
| 3238 |  | 
|---|
| 3239 | FT_TRACE7(( "    CVT deltas:\n")); | 
|---|
| 3240 |  | 
|---|
| 3241 | /* this means that there are deltas for every entry in cvt */ | 
|---|
| 3242 | for ( j = 0; j < face->cvt_size; j++ ) | 
|---|
| 3243 | { | 
|---|
| 3244 | FT_Long  orig_cvt = face->cvt[j]; | 
|---|
| 3245 |  | 
|---|
| 3246 |  | 
|---|
| 3247 | face->cvt[j] = (FT_Short)( orig_cvt + | 
|---|
| 3248 | FT_MulFix( deltas[j], apply ) ); | 
|---|
| 3249 |  | 
|---|
| 3250 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 3251 | if ( orig_cvt != face->cvt[j] ) | 
|---|
| 3252 | { | 
|---|
| 3253 | FT_TRACE7(( "      %d: %d -> %d\n", | 
|---|
| 3254 | j, orig_cvt, face->cvt[j] )); | 
|---|
| 3255 | count++; | 
|---|
| 3256 | } | 
|---|
| 3257 | #endif | 
|---|
| 3258 | } | 
|---|
| 3259 |  | 
|---|
| 3260 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 3261 | if ( !count ) | 
|---|
| 3262 | FT_TRACE7(( "      none\n")); | 
|---|
| 3263 | #endif | 
|---|
| 3264 | } | 
|---|
| 3265 |  | 
|---|
| 3266 | else | 
|---|
| 3267 | { | 
|---|
| 3268 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 3269 | int  count = 0; | 
|---|
| 3270 | #endif | 
|---|
| 3271 |  | 
|---|
| 3272 |  | 
|---|
| 3273 | FT_TRACE7(( "    CVT deltas:\n")); | 
|---|
| 3274 |  | 
|---|
| 3275 | for ( j = 0; j < point_count; j++ ) | 
|---|
| 3276 | { | 
|---|
| 3277 | int      pindex; | 
|---|
| 3278 | FT_Long  orig_cvt; | 
|---|
| 3279 |  | 
|---|
| 3280 |  | 
|---|
| 3281 | pindex = points[j]; | 
|---|
| 3282 | if ( (FT_ULong)pindex >= face->cvt_size ) | 
|---|
| 3283 | continue; | 
|---|
| 3284 |  | 
|---|
| 3285 | orig_cvt          = face->cvt[pindex]; | 
|---|
| 3286 | face->cvt[pindex] = (FT_Short)( orig_cvt + | 
|---|
| 3287 | FT_MulFix( deltas[j], apply ) ); | 
|---|
| 3288 |  | 
|---|
| 3289 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 3290 | if ( orig_cvt != face->cvt[pindex] ) | 
|---|
| 3291 | { | 
|---|
| 3292 | FT_TRACE7(( "      %d: %d -> %d\n", | 
|---|
| 3293 | pindex, orig_cvt, face->cvt[pindex] )); | 
|---|
| 3294 | count++; | 
|---|
| 3295 | } | 
|---|
| 3296 | #endif | 
|---|
| 3297 | } | 
|---|
| 3298 |  | 
|---|
| 3299 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 3300 | if ( !count ) | 
|---|
| 3301 | FT_TRACE7(( "      none\n")); | 
|---|
| 3302 | #endif | 
|---|
| 3303 | } | 
|---|
| 3304 |  | 
|---|
| 3305 | if ( localpoints != ALL_POINTS ) | 
|---|
| 3306 | FT_FREE( localpoints ); | 
|---|
| 3307 | FT_FREE( deltas ); | 
|---|
| 3308 |  | 
|---|
| 3309 | offsetToData += tupleDataSize; | 
|---|
| 3310 |  | 
|---|
| 3311 | FT_Stream_SeekSet( stream, here ); | 
|---|
| 3312 | } | 
|---|
| 3313 |  | 
|---|
| 3314 | FT_TRACE5(( "\n")); | 
|---|
| 3315 |  | 
|---|
| 3316 | FExit: | 
|---|
| 3317 | FT_FRAME_EXIT(); | 
|---|
| 3318 |  | 
|---|
| 3319 | Exit: | 
|---|
| 3320 | if ( sharedpoints != ALL_POINTS ) | 
|---|
| 3321 | FT_FREE( sharedpoints ); | 
|---|
| 3322 | FT_FREE( tuple_coords ); | 
|---|
| 3323 | FT_FREE( im_start_coords ); | 
|---|
| 3324 | FT_FREE( im_end_coords ); | 
|---|
| 3325 |  | 
|---|
| 3326 | return error; | 
|---|
| 3327 | } | 
|---|
| 3328 |  | 
|---|
| 3329 |  | 
|---|
| 3330 | /* Shift the original coordinates of all points between indices `p1' */ | 
|---|
| 3331 | /* and `p2', using the same difference as given by index `ref'.      */ | 
|---|
| 3332 |  | 
|---|
| 3333 | /* modeled after `af_iup_shift' */ | 
|---|
| 3334 |  | 
|---|
| 3335 | static void | 
|---|
| 3336 | tt_delta_shift( int         p1, | 
|---|
| 3337 | int         p2, | 
|---|
| 3338 | int         ref, | 
|---|
| 3339 | FT_Vector*  in_points, | 
|---|
| 3340 | FT_Vector*  out_points ) | 
|---|
| 3341 | { | 
|---|
| 3342 | int        p; | 
|---|
| 3343 | FT_Vector  delta; | 
|---|
| 3344 |  | 
|---|
| 3345 |  | 
|---|
| 3346 | delta.x = out_points[ref].x - in_points[ref].x; | 
|---|
| 3347 | delta.y = out_points[ref].y - in_points[ref].y; | 
|---|
| 3348 |  | 
|---|
| 3349 | if ( delta.x == 0 && delta.y == 0 ) | 
|---|
| 3350 | return; | 
|---|
| 3351 |  | 
|---|
| 3352 | for ( p = p1; p < ref; p++ ) | 
|---|
| 3353 | { | 
|---|
| 3354 | out_points[p].x += delta.x; | 
|---|
| 3355 | out_points[p].y += delta.y; | 
|---|
| 3356 | } | 
|---|
| 3357 |  | 
|---|
| 3358 | for ( p = ref + 1; p <= p2; p++ ) | 
|---|
| 3359 | { | 
|---|
| 3360 | out_points[p].x += delta.x; | 
|---|
| 3361 | out_points[p].y += delta.y; | 
|---|
| 3362 | } | 
|---|
| 3363 | } | 
|---|
| 3364 |  | 
|---|
| 3365 |  | 
|---|
| 3366 | /* Interpolate the original coordinates of all points with indices */ | 
|---|
| 3367 | /* between `p1' and `p2', using `ref1' and `ref2' as the reference */ | 
|---|
| 3368 | /* point indices.                                                  */ | 
|---|
| 3369 |  | 
|---|
| 3370 | /* modeled after `af_iup_interp', `_iup_worker_interpolate', and */ | 
|---|
| 3371 | /* `Ins_IUP'                                                     */ | 
|---|
| 3372 |  | 
|---|
| 3373 | static void | 
|---|
| 3374 | tt_delta_interpolate( int         p1, | 
|---|
| 3375 | int         p2, | 
|---|
| 3376 | int         ref1, | 
|---|
| 3377 | int         ref2, | 
|---|
| 3378 | FT_Vector*  in_points, | 
|---|
| 3379 | FT_Vector*  out_points ) | 
|---|
| 3380 | { | 
|---|
| 3381 | int  p, i; | 
|---|
| 3382 |  | 
|---|
| 3383 | FT_Pos  out, in1, in2, out1, out2, d1, d2; | 
|---|
| 3384 |  | 
|---|
| 3385 |  | 
|---|
| 3386 | if ( p1 > p2 ) | 
|---|
| 3387 | return; | 
|---|
| 3388 |  | 
|---|
| 3389 | /* handle both horizontal and vertical coordinates */ | 
|---|
| 3390 | for ( i = 0; i <= 1; i++ ) | 
|---|
| 3391 | { | 
|---|
| 3392 | /* shift array pointers so that we can access `foo.y' as `foo.x' */ | 
|---|
| 3393 | in_points  = (FT_Vector*)( (FT_Pos*)in_points + i ); | 
|---|
| 3394 | out_points = (FT_Vector*)( (FT_Pos*)out_points + i ); | 
|---|
| 3395 |  | 
|---|
| 3396 | if ( in_points[ref1].x > in_points[ref2].x ) | 
|---|
| 3397 | { | 
|---|
| 3398 | p    = ref1; | 
|---|
| 3399 | ref1 = ref2; | 
|---|
| 3400 | ref2 = p; | 
|---|
| 3401 | } | 
|---|
| 3402 |  | 
|---|
| 3403 | in1  = in_points[ref1].x; | 
|---|
| 3404 | in2  = in_points[ref2].x; | 
|---|
| 3405 | out1 = out_points[ref1].x; | 
|---|
| 3406 | out2 = out_points[ref2].x; | 
|---|
| 3407 | d1   = out1 - in1; | 
|---|
| 3408 | d2   = out2 - in2; | 
|---|
| 3409 |  | 
|---|
| 3410 | /* If the reference points have the same coordinate but different */ | 
|---|
| 3411 | /* delta, inferred delta is zero.  Otherwise interpolate.         */ | 
|---|
| 3412 | if ( in1 != in2 || out1 == out2 ) | 
|---|
| 3413 | { | 
|---|
| 3414 | FT_Fixed  scale = in1 != in2 ? FT_DivFix( out2 - out1, in2 - in1 ) | 
|---|
| 3415 | : 0; | 
|---|
| 3416 |  | 
|---|
| 3417 |  | 
|---|
| 3418 | for ( p = p1; p <= p2; p++ ) | 
|---|
| 3419 | { | 
|---|
| 3420 | out = in_points[p].x; | 
|---|
| 3421 |  | 
|---|
| 3422 | if ( out <= in1 ) | 
|---|
| 3423 | out += d1; | 
|---|
| 3424 | else if ( out >= in2 ) | 
|---|
| 3425 | out += d2; | 
|---|
| 3426 | else | 
|---|
| 3427 | out = out1 + FT_MulFix( out - in1, scale ); | 
|---|
| 3428 |  | 
|---|
| 3429 | out_points[p].x = out; | 
|---|
| 3430 | } | 
|---|
| 3431 | } | 
|---|
| 3432 | } | 
|---|
| 3433 | } | 
|---|
| 3434 |  | 
|---|
| 3435 |  | 
|---|
| 3436 | /* Interpolate points without delta values, similar to */ | 
|---|
| 3437 | /* the `IUP' hinting instruction.                      */ | 
|---|
| 3438 |  | 
|---|
| 3439 | /* modeled after `Ins_IUP */ | 
|---|
| 3440 |  | 
|---|
| 3441 | static void | 
|---|
| 3442 | tt_interpolate_deltas( FT_Outline*  outline, | 
|---|
| 3443 | FT_Vector*   out_points, | 
|---|
| 3444 | FT_Vector*   in_points, | 
|---|
| 3445 | FT_Bool*     has_delta ) | 
|---|
| 3446 | { | 
|---|
| 3447 | FT_Int  first_point; | 
|---|
| 3448 | FT_Int  end_point; | 
|---|
| 3449 |  | 
|---|
| 3450 | FT_Int  first_delta; | 
|---|
| 3451 | FT_Int  cur_delta; | 
|---|
| 3452 |  | 
|---|
| 3453 | FT_Int    point; | 
|---|
| 3454 | FT_Short  contour; | 
|---|
| 3455 |  | 
|---|
| 3456 |  | 
|---|
| 3457 | /* ignore empty outlines */ | 
|---|
| 3458 | if ( !outline->n_contours ) | 
|---|
| 3459 | return; | 
|---|
| 3460 |  | 
|---|
| 3461 | contour = 0; | 
|---|
| 3462 | point   = 0; | 
|---|
| 3463 |  | 
|---|
| 3464 | do | 
|---|
| 3465 | { | 
|---|
| 3466 | end_point   = outline->contours[contour]; | 
|---|
| 3467 | first_point = point; | 
|---|
| 3468 |  | 
|---|
| 3469 | /* search first point that has a delta */ | 
|---|
| 3470 | while ( point <= end_point && !has_delta[point] ) | 
|---|
| 3471 | point++; | 
|---|
| 3472 |  | 
|---|
| 3473 | if ( point <= end_point ) | 
|---|
| 3474 | { | 
|---|
| 3475 | first_delta = point; | 
|---|
| 3476 | cur_delta   = point; | 
|---|
| 3477 |  | 
|---|
| 3478 | point++; | 
|---|
| 3479 |  | 
|---|
| 3480 | while ( point <= end_point ) | 
|---|
| 3481 | { | 
|---|
| 3482 | /* search next point that has a delta  */ | 
|---|
| 3483 | /* and interpolate intermediate points */ | 
|---|
| 3484 | if ( has_delta[point] ) | 
|---|
| 3485 | { | 
|---|
| 3486 | tt_delta_interpolate( cur_delta + 1, | 
|---|
| 3487 | point - 1, | 
|---|
| 3488 | cur_delta, | 
|---|
| 3489 | point, | 
|---|
| 3490 | in_points, | 
|---|
| 3491 | out_points ); | 
|---|
| 3492 | cur_delta = point; | 
|---|
| 3493 | } | 
|---|
| 3494 |  | 
|---|
| 3495 | point++; | 
|---|
| 3496 | } | 
|---|
| 3497 |  | 
|---|
| 3498 | /* shift contour if we only have a single delta */ | 
|---|
| 3499 | if ( cur_delta == first_delta ) | 
|---|
| 3500 | tt_delta_shift( first_point, | 
|---|
| 3501 | end_point, | 
|---|
| 3502 | cur_delta, | 
|---|
| 3503 | in_points, | 
|---|
| 3504 | out_points ); | 
|---|
| 3505 | else | 
|---|
| 3506 | { | 
|---|
| 3507 | /* otherwise handle remaining points       */ | 
|---|
| 3508 | /* at the end and beginning of the contour */ | 
|---|
| 3509 | tt_delta_interpolate( cur_delta + 1, | 
|---|
| 3510 | end_point, | 
|---|
| 3511 | cur_delta, | 
|---|
| 3512 | first_delta, | 
|---|
| 3513 | in_points, | 
|---|
| 3514 | out_points ); | 
|---|
| 3515 |  | 
|---|
| 3516 | if ( first_delta > 0 ) | 
|---|
| 3517 | tt_delta_interpolate( first_point, | 
|---|
| 3518 | first_delta - 1, | 
|---|
| 3519 | cur_delta, | 
|---|
| 3520 | first_delta, | 
|---|
| 3521 | in_points, | 
|---|
| 3522 | out_points ); | 
|---|
| 3523 | } | 
|---|
| 3524 | } | 
|---|
| 3525 | contour++; | 
|---|
| 3526 |  | 
|---|
| 3527 | } while ( contour < outline->n_contours ); | 
|---|
| 3528 | } | 
|---|
| 3529 |  | 
|---|
| 3530 |  | 
|---|
| 3531 | /*************************************************************************/ | 
|---|
| 3532 | /*                                                                       */ | 
|---|
| 3533 | /* <Function>                                                            */ | 
|---|
| 3534 | /*    TT_Vary_Apply_Glyph_Deltas                                         */ | 
|---|
| 3535 | /*                                                                       */ | 
|---|
| 3536 | /* <Description>                                                         */ | 
|---|
| 3537 | /*    Apply the appropriate deltas to the current glyph.                 */ | 
|---|
| 3538 | /*                                                                       */ | 
|---|
| 3539 | /* <Input>                                                               */ | 
|---|
| 3540 | /*    face        :: A handle to the target face object.                 */ | 
|---|
| 3541 | /*                                                                       */ | 
|---|
| 3542 | /*    glyph_index :: The index of the glyph being modified.              */ | 
|---|
| 3543 | /*                                                                       */ | 
|---|
| 3544 | /*    n_points    :: The number of the points in the glyph, including    */ | 
|---|
| 3545 | /*                   phantom points.                                     */ | 
|---|
| 3546 | /*                                                                       */ | 
|---|
| 3547 | /* <InOut>                                                               */ | 
|---|
| 3548 | /*    outline     :: The outline to change.                              */ | 
|---|
| 3549 | /*                                                                       */ | 
|---|
| 3550 | /* <Return>                                                              */ | 
|---|
| 3551 | /*    FreeType error code.  0 means success.                             */ | 
|---|
| 3552 | /*                                                                       */ | 
|---|
| 3553 | FT_LOCAL_DEF( FT_Error ) | 
|---|
| 3554 | TT_Vary_Apply_Glyph_Deltas( TT_Face      face, | 
|---|
| 3555 | FT_UInt      glyph_index, | 
|---|
| 3556 | FT_Outline*  outline, | 
|---|
| 3557 | FT_UInt      n_points ) | 
|---|
| 3558 | { | 
|---|
| 3559 | FT_Stream   stream = face->root.stream; | 
|---|
| 3560 | FT_Memory   memory = stream->memory; | 
|---|
| 3561 | GX_Blend    blend  = face->blend; | 
|---|
| 3562 |  | 
|---|
| 3563 | FT_Vector*  points_org = NULL; | 
|---|
| 3564 | FT_Vector*  points_out = NULL; | 
|---|
| 3565 | FT_Bool*    has_delta  = NULL; | 
|---|
| 3566 |  | 
|---|
| 3567 | FT_Error    error; | 
|---|
| 3568 | FT_ULong    glyph_start; | 
|---|
| 3569 | FT_UInt     tupleCount; | 
|---|
| 3570 | FT_ULong    offsetToData; | 
|---|
| 3571 | FT_ULong    here; | 
|---|
| 3572 | FT_UInt     i, j; | 
|---|
| 3573 | FT_Fixed*   tuple_coords    = NULL; | 
|---|
| 3574 | FT_Fixed*   im_start_coords = NULL; | 
|---|
| 3575 | FT_Fixed*   im_end_coords   = NULL; | 
|---|
| 3576 | FT_UInt     point_count, spoint_count = 0; | 
|---|
| 3577 | FT_UShort*  sharedpoints = NULL; | 
|---|
| 3578 | FT_UShort*  localpoints  = NULL; | 
|---|
| 3579 | FT_UShort*  points; | 
|---|
| 3580 | FT_Short    *deltas_x, *deltas_y; | 
|---|
| 3581 |  | 
|---|
| 3582 |  | 
|---|
| 3583 | if ( !face->doblend || !blend ) | 
|---|
| 3584 | return FT_THROW( Invalid_Argument ); | 
|---|
| 3585 |  | 
|---|
| 3586 | if ( glyph_index >= blend->gv_glyphcnt      || | 
|---|
| 3587 | blend->glyphoffsets[glyph_index] == | 
|---|
| 3588 | blend->glyphoffsets[glyph_index + 1] ) | 
|---|
| 3589 | { | 
|---|
| 3590 | FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" | 
|---|
| 3591 | " no variation data for this glyph\n")); | 
|---|
| 3592 | return FT_Err_Ok; | 
|---|
| 3593 | } | 
|---|
| 3594 |  | 
|---|
| 3595 | if ( FT_NEW_ARRAY( points_org, n_points ) || | 
|---|
| 3596 | FT_NEW_ARRAY( points_out, n_points ) || | 
|---|
| 3597 | FT_NEW_ARRAY( has_delta, n_points )  ) | 
|---|
| 3598 | goto Fail1; | 
|---|
| 3599 |  | 
|---|
| 3600 | if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] )   || | 
|---|
| 3601 | FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] - | 
|---|
| 3602 | blend->glyphoffsets[glyph_index] ) ) | 
|---|
| 3603 | goto Fail1; | 
|---|
| 3604 |  | 
|---|
| 3605 | glyph_start = FT_Stream_FTell( stream ); | 
|---|
| 3606 |  | 
|---|
| 3607 | /* each set of glyph variation data is formatted similarly to `cvar' */ | 
|---|
| 3608 |  | 
|---|
| 3609 | if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis )    || | 
|---|
| 3610 | FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || | 
|---|
| 3611 | FT_NEW_ARRAY( im_end_coords, blend->num_axis )   ) | 
|---|
| 3612 | goto Fail2; | 
|---|
| 3613 |  | 
|---|
| 3614 | tupleCount   = FT_GET_USHORT(); | 
|---|
| 3615 | offsetToData = FT_GET_USHORT(); | 
|---|
| 3616 |  | 
|---|
| 3617 | /* rough sanity test */ | 
|---|
| 3618 | if ( offsetToData + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 > | 
|---|
| 3619 | blend->gvar_size ) | 
|---|
| 3620 | { | 
|---|
| 3621 | FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" | 
|---|
| 3622 | " invalid glyph variation array header\n")); | 
|---|
| 3623 |  | 
|---|
| 3624 | error = FT_THROW( Invalid_Table ); | 
|---|
| 3625 | goto Fail2; | 
|---|
| 3626 | } | 
|---|
| 3627 |  | 
|---|
| 3628 | offsetToData += glyph_start; | 
|---|
| 3629 |  | 
|---|
| 3630 | if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) | 
|---|
| 3631 | { | 
|---|
| 3632 | here = FT_Stream_FTell( stream ); | 
|---|
| 3633 |  | 
|---|
| 3634 | FT_Stream_SeekSet( stream, offsetToData ); | 
|---|
| 3635 |  | 
|---|
| 3636 | sharedpoints = ft_var_readpackedpoints( stream, | 
|---|
| 3637 | blend->gvar_size, | 
|---|
| 3638 | &spoint_count ); | 
|---|
| 3639 | offsetToData = FT_Stream_FTell( stream ); | 
|---|
| 3640 |  | 
|---|
| 3641 | FT_Stream_SeekSet( stream, here ); | 
|---|
| 3642 | } | 
|---|
| 3643 |  | 
|---|
| 3644 | FT_TRACE5(( "gvar: there %s %d tuple%s:\n", | 
|---|
| 3645 | ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is": "are", | 
|---|
| 3646 | tupleCount & GX_TC_TUPLE_COUNT_MASK, | 
|---|
| 3647 | ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "": "s")); | 
|---|
| 3648 |  | 
|---|
| 3649 | for ( j = 0; j < n_points; j++ ) | 
|---|
| 3650 | points_org[j] = outline->points[j]; | 
|---|
| 3651 |  | 
|---|
| 3652 | for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) | 
|---|
| 3653 | { | 
|---|
| 3654 | FT_UInt   tupleDataSize; | 
|---|
| 3655 | FT_UInt   tupleIndex; | 
|---|
| 3656 | FT_Fixed  apply; | 
|---|
| 3657 |  | 
|---|
| 3658 |  | 
|---|
| 3659 | FT_TRACE6(( "  tuple %d:\n", i )); | 
|---|
| 3660 |  | 
|---|
| 3661 | tupleDataSize = FT_GET_USHORT(); | 
|---|
| 3662 | tupleIndex    = FT_GET_USHORT(); | 
|---|
| 3663 |  | 
|---|
| 3664 | if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) | 
|---|
| 3665 | { | 
|---|
| 3666 | for ( j = 0; j < blend->num_axis; j++ ) | 
|---|
| 3667 | tuple_coords[j] = FT_GET_SHORT() * 4;   /* convert from        */ | 
|---|
| 3668 | /* short frac to fixed */ | 
|---|
| 3669 | } | 
|---|
| 3670 | else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) | 
|---|
| 3671 | { | 
|---|
| 3672 | FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" | 
|---|
| 3673 | " invalid tuple index\n")); | 
|---|
| 3674 |  | 
|---|
| 3675 | error = FT_THROW( Invalid_Table ); | 
|---|
| 3676 | goto Fail2; | 
|---|
| 3677 | } | 
|---|
| 3678 | else | 
|---|
| 3679 | FT_MEM_COPY( | 
|---|
| 3680 | tuple_coords, | 
|---|
| 3681 | &blend->tuplecoords[( tupleIndex & 0xFFF ) * blend->num_axis], | 
|---|
| 3682 | blend->num_axis * sizeof ( FT_Fixed ) ); | 
|---|
| 3683 |  | 
|---|
| 3684 | if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) | 
|---|
| 3685 | { | 
|---|
| 3686 | for ( j = 0; j < blend->num_axis; j++ ) | 
|---|
| 3687 | im_start_coords[j] = FT_GET_SHORT() * 4; | 
|---|
| 3688 | for ( j = 0; j < blend->num_axis; j++ ) | 
|---|
| 3689 | im_end_coords[j] = FT_GET_SHORT() * 4; | 
|---|
| 3690 | } | 
|---|
| 3691 |  | 
|---|
| 3692 | apply = ft_var_apply_tuple( blend, | 
|---|
| 3693 | (FT_UShort)tupleIndex, | 
|---|
| 3694 | tuple_coords, | 
|---|
| 3695 | im_start_coords, | 
|---|
| 3696 | im_end_coords ); | 
|---|
| 3697 |  | 
|---|
| 3698 | if ( apply == 0 )              /* tuple isn't active for our blend */ | 
|---|
| 3699 | { | 
|---|
| 3700 | offsetToData += tupleDataSize; | 
|---|
| 3701 | continue; | 
|---|
| 3702 | } | 
|---|
| 3703 |  | 
|---|
| 3704 | here = FT_Stream_FTell( stream ); | 
|---|
| 3705 |  | 
|---|
| 3706 | FT_Stream_SeekSet( stream, offsetToData ); | 
|---|
| 3707 |  | 
|---|
| 3708 | if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) | 
|---|
| 3709 | { | 
|---|
| 3710 | localpoints = ft_var_readpackedpoints( stream, | 
|---|
| 3711 | blend->gvar_size, | 
|---|
| 3712 | &point_count ); | 
|---|
| 3713 | points      = localpoints; | 
|---|
| 3714 | } | 
|---|
| 3715 | else | 
|---|
| 3716 | { | 
|---|
| 3717 | points      = sharedpoints; | 
|---|
| 3718 | point_count = spoint_count; | 
|---|
| 3719 | } | 
|---|
| 3720 |  | 
|---|
| 3721 | deltas_x = ft_var_readpackeddeltas( stream, | 
|---|
| 3722 | blend->gvar_size, | 
|---|
| 3723 | point_count == 0 ? n_points | 
|---|
| 3724 | : point_count ); | 
|---|
| 3725 | deltas_y = ft_var_readpackeddeltas( stream, | 
|---|
| 3726 | blend->gvar_size, | 
|---|
| 3727 | point_count == 0 ? n_points | 
|---|
| 3728 | : point_count ); | 
|---|
| 3729 |  | 
|---|
| 3730 | if ( !points || !deltas_y || !deltas_x ) | 
|---|
| 3731 | ; /* failure, ignore it */ | 
|---|
| 3732 |  | 
|---|
| 3733 | else if ( points == ALL_POINTS ) | 
|---|
| 3734 | { | 
|---|
| 3735 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 3736 | int  count = 0; | 
|---|
| 3737 | #endif | 
|---|
| 3738 |  | 
|---|
| 3739 |  | 
|---|
| 3740 | FT_TRACE7(( "    point deltas:\n")); | 
|---|
| 3741 |  | 
|---|
| 3742 | /* this means that there are deltas for every point in the glyph */ | 
|---|
| 3743 | for ( j = 0; j < n_points; j++ ) | 
|---|
| 3744 | { | 
|---|
| 3745 | FT_Pos  delta_x = FT_MulFix( deltas_x[j], apply ); | 
|---|
| 3746 | FT_Pos  delta_y = FT_MulFix( deltas_y[j], apply ); | 
|---|
| 3747 |  | 
|---|
| 3748 |  | 
|---|
| 3749 | if ( j < n_points - 4 ) | 
|---|
| 3750 | { | 
|---|
| 3751 | outline->points[j].x += delta_x; | 
|---|
| 3752 | outline->points[j].y += delta_y; | 
|---|
| 3753 | } | 
|---|
| 3754 | else | 
|---|
| 3755 | { | 
|---|
| 3756 | /* To avoid double adjustment of advance width or height, */ | 
|---|
| 3757 | /* adjust phantom points only if there is no HVAR or VVAR */ | 
|---|
| 3758 | /* support, respectively.                                 */ | 
|---|
| 3759 | if ( j == ( n_points - 4 )        && | 
|---|
| 3760 | !( face->variation_support & | 
|---|
| 3761 | TT_FACE_FLAG_VAR_LSB    ) ) | 
|---|
| 3762 | outline->points[j].x += delta_x; | 
|---|
| 3763 |  | 
|---|
| 3764 | else if ( j == ( n_points - 3 )          && | 
|---|
| 3765 | !( face->variation_support   & | 
|---|
| 3766 | TT_FACE_FLAG_VAR_HADVANCE ) ) | 
|---|
| 3767 | outline->points[j].x += delta_x; | 
|---|
| 3768 |  | 
|---|
| 3769 | else if ( j == ( n_points - 2 )        && | 
|---|
| 3770 | !( face->variation_support & | 
|---|
| 3771 | TT_FACE_FLAG_VAR_TSB    ) ) | 
|---|
| 3772 | outline->points[j].y += delta_y; | 
|---|
| 3773 |  | 
|---|
| 3774 | else if ( j == ( n_points - 1 )          && | 
|---|
| 3775 | !( face->variation_support   & | 
|---|
| 3776 | TT_FACE_FLAG_VAR_VADVANCE ) ) | 
|---|
| 3777 | outline->points[j].y += delta_y; | 
|---|
| 3778 | } | 
|---|
| 3779 |  | 
|---|
| 3780 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 3781 | if ( delta_x || delta_y ) | 
|---|
| 3782 | { | 
|---|
| 3783 | FT_TRACE7(( "      %d: (%d, %d) -> (%d, %d)\n", | 
|---|
| 3784 | j, | 
|---|
| 3785 | outline->points[j].x - delta_x, | 
|---|
| 3786 | outline->points[j].y - delta_y, | 
|---|
| 3787 | outline->points[j].x, | 
|---|
| 3788 | outline->points[j].y )); | 
|---|
| 3789 | count++; | 
|---|
| 3790 | } | 
|---|
| 3791 | #endif | 
|---|
| 3792 | } | 
|---|
| 3793 |  | 
|---|
| 3794 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 3795 | if ( !count ) | 
|---|
| 3796 | FT_TRACE7(( "      none\n")); | 
|---|
| 3797 | #endif | 
|---|
| 3798 | } | 
|---|
| 3799 |  | 
|---|
| 3800 | else | 
|---|
| 3801 | { | 
|---|
| 3802 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 3803 | int  count = 0; | 
|---|
| 3804 | #endif | 
|---|
| 3805 |  | 
|---|
| 3806 |  | 
|---|
| 3807 | /* we have to interpolate the missing deltas similar to the */ | 
|---|
| 3808 | /* IUP bytecode instruction                                 */ | 
|---|
| 3809 | for ( j = 0; j < n_points; j++ ) | 
|---|
| 3810 | { | 
|---|
| 3811 | has_delta[j]  = FALSE; | 
|---|
| 3812 | points_out[j] = points_org[j]; | 
|---|
| 3813 | } | 
|---|
| 3814 |  | 
|---|
| 3815 | for ( j = 0; j < point_count; j++ ) | 
|---|
| 3816 | { | 
|---|
| 3817 | FT_UShort  idx = points[j]; | 
|---|
| 3818 |  | 
|---|
| 3819 |  | 
|---|
| 3820 | if ( idx >= n_points ) | 
|---|
| 3821 | continue; | 
|---|
| 3822 |  | 
|---|
| 3823 | has_delta[idx] = TRUE; | 
|---|
| 3824 |  | 
|---|
| 3825 | points_out[idx].x += FT_MulFix( deltas_x[j], apply ); | 
|---|
| 3826 | points_out[idx].y += FT_MulFix( deltas_y[j], apply ); | 
|---|
| 3827 | } | 
|---|
| 3828 |  | 
|---|
| 3829 | /* no need to handle phantom points here,      */ | 
|---|
| 3830 | /* since solitary points can't be interpolated */ | 
|---|
| 3831 | tt_interpolate_deltas( outline, | 
|---|
| 3832 | points_out, | 
|---|
| 3833 | points_org, | 
|---|
| 3834 | has_delta ); | 
|---|
| 3835 |  | 
|---|
| 3836 | FT_TRACE7(( "    point deltas:\n")); | 
|---|
| 3837 |  | 
|---|
| 3838 | for ( j = 0; j < n_points; j++ ) | 
|---|
| 3839 | { | 
|---|
| 3840 | FT_Pos  delta_x = points_out[j].x - points_org[j].x; | 
|---|
| 3841 | FT_Pos  delta_y = points_out[j].y - points_org[j].y; | 
|---|
| 3842 |  | 
|---|
| 3843 |  | 
|---|
| 3844 | if ( j < n_points - 4 ) | 
|---|
| 3845 | { | 
|---|
| 3846 | outline->points[j].x += delta_x; | 
|---|
| 3847 | outline->points[j].y += delta_y; | 
|---|
| 3848 | } | 
|---|
| 3849 | else | 
|---|
| 3850 | { | 
|---|
| 3851 | /* To avoid double adjustment of advance width or height, */ | 
|---|
| 3852 | /* adjust phantom points only if there is no HVAR or VVAR */ | 
|---|
| 3853 | /* support, respectively.                                 */ | 
|---|
| 3854 | if ( j == ( n_points - 4 )        && | 
|---|
| 3855 | !( face->variation_support & | 
|---|
| 3856 | TT_FACE_FLAG_VAR_LSB    ) ) | 
|---|
| 3857 | outline->points[j].x += delta_x; | 
|---|
| 3858 |  | 
|---|
| 3859 | else if ( j == ( n_points - 3 )          && | 
|---|
| 3860 | !( face->variation_support   & | 
|---|
| 3861 | TT_FACE_FLAG_VAR_HADVANCE ) ) | 
|---|
| 3862 | outline->points[j].x += delta_x; | 
|---|
| 3863 |  | 
|---|
| 3864 | else if ( j == ( n_points - 2 )        && | 
|---|
| 3865 | !( face->variation_support & | 
|---|
| 3866 | TT_FACE_FLAG_VAR_TSB    ) ) | 
|---|
| 3867 | outline->points[j].y += delta_y; | 
|---|
| 3868 |  | 
|---|
| 3869 | else if ( j == ( n_points - 1 )          && | 
|---|
| 3870 | !( face->variation_support   & | 
|---|
| 3871 | TT_FACE_FLAG_VAR_VADVANCE ) ) | 
|---|
| 3872 | outline->points[j].y += delta_y; | 
|---|
| 3873 | } | 
|---|
| 3874 |  | 
|---|
| 3875 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 3876 | if ( delta_x || delta_y ) | 
|---|
| 3877 | { | 
|---|
| 3878 | FT_TRACE7(( "      %d: (%d, %d) -> (%d, %d)\n", | 
|---|
| 3879 | j, | 
|---|
| 3880 | outline->points[j].x - delta_x, | 
|---|
| 3881 | outline->points[j].y - delta_y, | 
|---|
| 3882 | outline->points[j].x, | 
|---|
| 3883 | outline->points[j].y )); | 
|---|
| 3884 | count++; | 
|---|
| 3885 | } | 
|---|
| 3886 | #endif | 
|---|
| 3887 | } | 
|---|
| 3888 |  | 
|---|
| 3889 | #ifdef FT_DEBUG_LEVEL_TRACE | 
|---|
| 3890 | if ( !count ) | 
|---|
| 3891 | FT_TRACE7(( "      none\n")); | 
|---|
| 3892 | #endif | 
|---|
| 3893 | } | 
|---|
| 3894 |  | 
|---|
| 3895 | if ( localpoints != ALL_POINTS ) | 
|---|
| 3896 | FT_FREE( localpoints ); | 
|---|
| 3897 | FT_FREE( deltas_x ); | 
|---|
| 3898 | FT_FREE( deltas_y ); | 
|---|
| 3899 |  | 
|---|
| 3900 | offsetToData += tupleDataSize; | 
|---|
| 3901 |  | 
|---|
| 3902 | FT_Stream_SeekSet( stream, here ); | 
|---|
| 3903 | } | 
|---|
| 3904 |  | 
|---|
| 3905 | FT_TRACE5(( "\n")); | 
|---|
| 3906 |  | 
|---|
| 3907 | Fail2: | 
|---|
| 3908 | if ( sharedpoints != ALL_POINTS ) | 
|---|
| 3909 | FT_FREE( sharedpoints ); | 
|---|
| 3910 | FT_FREE( tuple_coords ); | 
|---|
| 3911 | FT_FREE( im_start_coords ); | 
|---|
| 3912 | FT_FREE( im_end_coords ); | 
|---|
| 3913 |  | 
|---|
| 3914 | FT_FRAME_EXIT(); | 
|---|
| 3915 |  | 
|---|
| 3916 | Fail1: | 
|---|
| 3917 | FT_FREE( points_org ); | 
|---|
| 3918 | FT_FREE( points_out ); | 
|---|
| 3919 | FT_FREE( has_delta ); | 
|---|
| 3920 |  | 
|---|
| 3921 | return error; | 
|---|
| 3922 | } | 
|---|
| 3923 |  | 
|---|
| 3924 |  | 
|---|
| 3925 | /*************************************************************************/ | 
|---|
| 3926 | /*                                                                       */ | 
|---|
| 3927 | /* <Function>                                                            */ | 
|---|
| 3928 | /*    tt_get_var_blend                                                   */ | 
|---|
| 3929 | /*                                                                       */ | 
|---|
| 3930 | /* <Description>                                                         */ | 
|---|
| 3931 | /*    An extended internal version of `TT_Get_MM_Blend' that returns     */ | 
|---|
| 3932 | /*    pointers instead of copying data, without any initialization of    */ | 
|---|
| 3933 | /*    the MM machinery in case it isn't loaded yet.                      */ | 
|---|
| 3934 | /*                                                                       */ | 
|---|
| 3935 | FT_LOCAL_DEF( FT_Error ) | 
|---|
| 3936 | tt_get_var_blend( TT_Face      face, | 
|---|
| 3937 | FT_UInt     *num_coords, | 
|---|
| 3938 | FT_Fixed*   *coords, | 
|---|
| 3939 | FT_Fixed*   *normalizedcoords, | 
|---|
| 3940 | FT_MM_Var*  *mm_var ) | 
|---|
| 3941 | { | 
|---|
| 3942 | if ( face->blend ) | 
|---|
| 3943 | { | 
|---|
| 3944 | if ( num_coords ) | 
|---|
| 3945 | *num_coords       = face->blend->num_axis; | 
|---|
| 3946 | if ( coords ) | 
|---|
| 3947 | *coords           = face->blend->coords; | 
|---|
| 3948 | if ( normalizedcoords ) | 
|---|
| 3949 | *normalizedcoords = face->blend->normalizedcoords; | 
|---|
| 3950 | if ( mm_var ) | 
|---|
| 3951 | *mm_var           = face->blend->mmvar; | 
|---|
| 3952 | } | 
|---|
| 3953 | else | 
|---|
| 3954 | { | 
|---|
| 3955 | if ( num_coords ) | 
|---|
| 3956 | *num_coords = 0; | 
|---|
| 3957 | if ( coords ) | 
|---|
| 3958 | *coords     = NULL; | 
|---|
| 3959 | if ( mm_var ) | 
|---|
| 3960 | *mm_var     = NULL; | 
|---|
| 3961 | } | 
|---|
| 3962 |  | 
|---|
| 3963 | return FT_Err_Ok; | 
|---|
| 3964 | } | 
|---|
| 3965 |  | 
|---|
| 3966 |  | 
|---|
| 3967 | static void | 
|---|
| 3968 | ft_var_done_item_variation_store( TT_Face          face, | 
|---|
| 3969 | GX_ItemVarStore  itemStore ) | 
|---|
| 3970 | { | 
|---|
| 3971 | FT_Memory  memory = FT_FACE_MEMORY( face ); | 
|---|
| 3972 | FT_UInt    i; | 
|---|
| 3973 |  | 
|---|
| 3974 |  | 
|---|
| 3975 | if ( itemStore->varData ) | 
|---|
| 3976 | { | 
|---|
| 3977 | for ( i = 0; i < itemStore->dataCount; i++ ) | 
|---|
| 3978 | { | 
|---|
| 3979 | FT_FREE( itemStore->varData[i].regionIndices ); | 
|---|
| 3980 | FT_FREE( itemStore->varData[i].deltaSet ); | 
|---|
| 3981 | } | 
|---|
| 3982 |  | 
|---|
| 3983 | FT_FREE( itemStore->varData ); | 
|---|
| 3984 | } | 
|---|
| 3985 |  | 
|---|
| 3986 | if ( itemStore->varRegionList ) | 
|---|
| 3987 | { | 
|---|
| 3988 | for ( i = 0; i < itemStore->regionCount; i++ ) | 
|---|
| 3989 | FT_FREE( itemStore->varRegionList[i].axisList ); | 
|---|
| 3990 |  | 
|---|
| 3991 | FT_FREE( itemStore->varRegionList ); | 
|---|
| 3992 | } | 
|---|
| 3993 | } | 
|---|
| 3994 |  | 
|---|
| 3995 |  | 
|---|
| 3996 | /*************************************************************************/ | 
|---|
| 3997 | /*                                                                       */ | 
|---|
| 3998 | /* <Function>                                                            */ | 
|---|
| 3999 | /*    tt_done_blend                                                      */ | 
|---|
| 4000 | /*                                                                       */ | 
|---|
| 4001 | /* <Description>                                                         */ | 
|---|
| 4002 | /*    Free the blend internal data structure.                            */ | 
|---|
| 4003 | /*                                                                       */ | 
|---|
| 4004 | FT_LOCAL_DEF( void ) | 
|---|
| 4005 | tt_done_blend( TT_Face  face ) | 
|---|
| 4006 | { | 
|---|
| 4007 | FT_Memory  memory = FT_FACE_MEMORY( face ); | 
|---|
| 4008 | GX_Blend   blend  = face->blend; | 
|---|
| 4009 |  | 
|---|
| 4010 |  | 
|---|
| 4011 | if ( blend ) | 
|---|
| 4012 | { | 
|---|
| 4013 | FT_UInt  i, num_axes; | 
|---|
| 4014 |  | 
|---|
| 4015 |  | 
|---|
| 4016 | /* blend->num_axis might not be set up yet */ | 
|---|
| 4017 | num_axes = blend->mmvar->num_axis; | 
|---|
| 4018 |  | 
|---|
| 4019 | FT_FREE( blend->coords ); | 
|---|
| 4020 | FT_FREE( blend->normalizedcoords ); | 
|---|
| 4021 | FT_FREE( blend->normalized_stylecoords ); | 
|---|
| 4022 | FT_FREE( blend->mmvar ); | 
|---|
| 4023 |  | 
|---|
| 4024 | if ( blend->avar_segment ) | 
|---|
| 4025 | { | 
|---|
| 4026 | for ( i = 0; i < num_axes; i++ ) | 
|---|
| 4027 | FT_FREE( blend->avar_segment[i].correspondence ); | 
|---|
| 4028 | FT_FREE( blend->avar_segment ); | 
|---|
| 4029 | } | 
|---|
| 4030 |  | 
|---|
| 4031 | if ( blend->hvar_table ) | 
|---|
| 4032 | { | 
|---|
| 4033 | ft_var_done_item_variation_store( face, | 
|---|
| 4034 | &blend->hvar_table->itemStore ); | 
|---|
| 4035 |  | 
|---|
| 4036 | FT_FREE( blend->hvar_table->widthMap.innerIndex ); | 
|---|
| 4037 | FT_FREE( blend->hvar_table->widthMap.outerIndex ); | 
|---|
| 4038 | FT_FREE( blend->hvar_table ); | 
|---|
| 4039 | } | 
|---|
| 4040 |  | 
|---|
| 4041 | if ( blend->vvar_table ) | 
|---|
| 4042 | { | 
|---|
| 4043 | ft_var_done_item_variation_store( face, | 
|---|
| 4044 | &blend->vvar_table->itemStore ); | 
|---|
| 4045 |  | 
|---|
| 4046 | FT_FREE( blend->vvar_table->widthMap.innerIndex ); | 
|---|
| 4047 | FT_FREE( blend->vvar_table->widthMap.outerIndex ); | 
|---|
| 4048 | FT_FREE( blend->vvar_table ); | 
|---|
| 4049 | } | 
|---|
| 4050 |  | 
|---|
| 4051 | if ( blend->mvar_table ) | 
|---|
| 4052 | { | 
|---|
| 4053 | ft_var_done_item_variation_store( face, | 
|---|
| 4054 | &blend->mvar_table->itemStore ); | 
|---|
| 4055 |  | 
|---|
| 4056 | FT_FREE( blend->mvar_table->values ); | 
|---|
| 4057 | FT_FREE( blend->mvar_table ); | 
|---|
| 4058 | } | 
|---|
| 4059 |  | 
|---|
| 4060 | FT_FREE( blend->tuplecoords ); | 
|---|
| 4061 | FT_FREE( blend->glyphoffsets ); | 
|---|
| 4062 | FT_FREE( blend ); | 
|---|
| 4063 | } | 
|---|
| 4064 | } | 
|---|
| 4065 |  | 
|---|
| 4066 | #else /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */ | 
|---|
| 4067 |  | 
|---|
| 4068 | /* ANSI C doesn't like empty source files */ | 
|---|
| 4069 | typedef int  _tt_gxvar_dummy; | 
|---|
| 4070 |  | 
|---|
| 4071 | #endif /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */ | 
|---|
| 4072 |  | 
|---|
| 4073 |  | 
|---|
| 4074 | /* END */ | 
|---|
| 4075 |  | 
|---|