| 1 | /**************************************************************************** | 
| 2 |  * | 
| 3 |  * ftmm.c | 
| 4 |  * | 
| 5 |  *   Multiple Master font support (body). | 
| 6 |  * | 
| 7 |  * Copyright (C) 1996-2023 by | 
| 8 |  * David Turner, Robert Wilhelm, and Werner Lemberg. | 
| 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 | #include <freetype/internal/ftdebug.h> | 
| 20 |  | 
| 21 | #include <freetype/ftmm.h> | 
| 22 | #include <freetype/internal/ftobjs.h> | 
| 23 | #include <freetype/internal/services/svmm.h> | 
| 24 | #include <freetype/internal/services/svmetric.h> | 
| 25 |  | 
| 26 |  | 
| 27 |   /************************************************************************** | 
| 28 |    * | 
| 29 |    * The macro FT_COMPONENT is used in trace mode.  It is an implicit | 
| 30 |    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log | 
| 31 |    * messages during execution. | 
| 32 |    */ | 
| 33 | #undef  FT_COMPONENT | 
| 34 | #define FT_COMPONENT  mm | 
| 35 |  | 
| 36 |  | 
| 37 |   static FT_Error | 
| 38 |   ft_face_get_mm_service( FT_Face                   face, | 
| 39 |                           FT_Service_MultiMasters  *aservice ) | 
| 40 |   { | 
| 41 |     FT_Error  error; | 
| 42 |  | 
| 43 |  | 
| 44 |     *aservice = NULL; | 
| 45 |  | 
| 46 |     if ( !face ) | 
| 47 |       return FT_THROW( Invalid_Face_Handle ); | 
| 48 |  | 
| 49 |     error = FT_ERR( Invalid_Argument ); | 
| 50 |  | 
| 51 |     if ( FT_HAS_MULTIPLE_MASTERS( face ) ) | 
| 52 |     { | 
| 53 |       FT_FACE_LOOKUP_SERVICE( face, | 
| 54 |                               *aservice, | 
| 55 |                               MULTI_MASTERS ); | 
| 56 |  | 
| 57 |       if ( *aservice ) | 
| 58 |         error = FT_Err_Ok; | 
| 59 |     } | 
| 60 |  | 
| 61 |     return error; | 
| 62 |   } | 
| 63 |  | 
| 64 |  | 
| 65 |   static FT_Error | 
| 66 |   ft_face_get_mvar_service( FT_Face                        face, | 
| 67 |                             FT_Service_MetricsVariations  *aservice ) | 
| 68 |   { | 
| 69 |     FT_Error  error; | 
| 70 |  | 
| 71 |  | 
| 72 |     *aservice = NULL; | 
| 73 |  | 
| 74 |     if ( !face ) | 
| 75 |       return FT_THROW( Invalid_Face_Handle ); | 
| 76 |  | 
| 77 |     error = FT_ERR( Invalid_Argument ); | 
| 78 |  | 
| 79 |     if ( FT_HAS_MULTIPLE_MASTERS( face ) ) | 
| 80 |     { | 
| 81 |       FT_FACE_LOOKUP_SERVICE( face, | 
| 82 |                               *aservice, | 
| 83 |                               METRICS_VARIATIONS ); | 
| 84 |  | 
| 85 |       if ( *aservice ) | 
| 86 |         error = FT_Err_Ok; | 
| 87 |     } | 
| 88 |  | 
| 89 |     return error; | 
| 90 |   } | 
| 91 |  | 
| 92 |  | 
| 93 |   /* documentation is in ftmm.h */ | 
| 94 |  | 
| 95 |   FT_EXPORT_DEF( FT_Error ) | 
| 96 |   FT_Get_Multi_Master( FT_Face           face, | 
| 97 |                        FT_Multi_Master  *amaster ) | 
| 98 |   { | 
| 99 |     FT_Error                 error; | 
| 100 |     FT_Service_MultiMasters  service; | 
| 101 |  | 
| 102 |  | 
| 103 |     /* check of `face' delayed to `ft_face_get_mm_service' */ | 
| 104 |  | 
| 105 |     if ( !amaster ) | 
| 106 |       return FT_THROW( Invalid_Argument ); | 
| 107 |  | 
| 108 |     error = ft_face_get_mm_service( face, &service ); | 
| 109 |     if ( !error ) | 
| 110 |     { | 
| 111 |       error = FT_ERR( Invalid_Argument ); | 
| 112 |       if ( service->get_mm ) | 
| 113 |         error = service->get_mm( face, amaster ); | 
| 114 |     } | 
| 115 |  | 
| 116 |     return error; | 
| 117 |   } | 
| 118 |  | 
| 119 |  | 
| 120 |   /* documentation is in ftmm.h */ | 
| 121 |  | 
| 122 |   FT_EXPORT_DEF( FT_Error ) | 
| 123 |   FT_Get_MM_Var( FT_Face      face, | 
| 124 |                  FT_MM_Var*  *amaster ) | 
| 125 |   { | 
| 126 |     FT_Error                 error; | 
| 127 |     FT_Service_MultiMasters  service; | 
| 128 |  | 
| 129 |  | 
| 130 |     /* check of `face' delayed to `ft_face_get_mm_service' */ | 
| 131 |  | 
| 132 |     if ( !amaster ) | 
| 133 |       return FT_THROW( Invalid_Argument ); | 
| 134 |  | 
| 135 |     error = ft_face_get_mm_service( face, &service ); | 
| 136 |     if ( !error ) | 
| 137 |     { | 
| 138 |       error = FT_ERR( Invalid_Argument ); | 
| 139 |       if ( service->get_mm_var ) | 
| 140 |         error = service->get_mm_var( face, amaster ); | 
| 141 |     } | 
| 142 |  | 
| 143 |     return error; | 
| 144 |   } | 
| 145 |  | 
| 146 |  | 
| 147 |   /* documentation is in ftmm.h */ | 
| 148 |  | 
| 149 |   FT_EXPORT_DEF( FT_Error ) | 
| 150 |   FT_Done_MM_Var( FT_Library  library, | 
| 151 |                   FT_MM_Var*  amaster ) | 
| 152 |   { | 
| 153 |     FT_Memory  memory; | 
| 154 |  | 
| 155 |  | 
| 156 |     if ( !library ) | 
| 157 |       return FT_THROW( Invalid_Library_Handle ); | 
| 158 |  | 
| 159 |     memory = library->memory; | 
| 160 |     FT_FREE( amaster ); | 
| 161 |  | 
| 162 |     return FT_Err_Ok; | 
| 163 |   } | 
| 164 |  | 
| 165 |  | 
| 166 |   /* documentation is in ftmm.h */ | 
| 167 |  | 
| 168 |   FT_EXPORT_DEF( FT_Error ) | 
| 169 |   FT_Set_MM_Design_Coordinates( FT_Face   face, | 
| 170 |                                 FT_UInt   num_coords, | 
| 171 |                                 FT_Long*  coords ) | 
| 172 |   { | 
| 173 |     FT_Error                 error; | 
| 174 |     FT_Service_MultiMasters  service; | 
| 175 |  | 
| 176 |  | 
| 177 |     /* check of `face' delayed to `ft_face_get_mm_service' */ | 
| 178 |  | 
| 179 |     if ( num_coords && !coords ) | 
| 180 |       return FT_THROW( Invalid_Argument ); | 
| 181 |  | 
| 182 |     error = ft_face_get_mm_service( face, &service ); | 
| 183 |     if ( !error ) | 
| 184 |     { | 
| 185 |       error = FT_ERR( Invalid_Argument ); | 
| 186 |       if ( service->set_mm_design ) | 
| 187 |         error = service->set_mm_design( face, num_coords, coords ); | 
| 188 |  | 
| 189 |       if ( !error ) | 
| 190 |       { | 
| 191 |         if ( num_coords ) | 
| 192 |           face->face_flags |= FT_FACE_FLAG_VARIATION; | 
| 193 |         else | 
| 194 |           face->face_flags &= ~FT_FACE_FLAG_VARIATION; | 
| 195 |       } | 
| 196 |     } | 
| 197 |  | 
| 198 |     /* enforce recomputation of auto-hinting data */ | 
| 199 |     if ( !error && face->autohint.finalizer ) | 
| 200 |     { | 
| 201 |       face->autohint.finalizer( face->autohint.data ); | 
| 202 |       face->autohint.data = NULL; | 
| 203 |     } | 
| 204 |  | 
| 205 |     return error; | 
| 206 |   } | 
| 207 |  | 
| 208 |  | 
| 209 |   /* documentation is in ftmm.h */ | 
| 210 |  | 
| 211 |   FT_EXPORT_DEF( FT_Error ) | 
| 212 |   FT_Set_MM_WeightVector( FT_Face    face, | 
| 213 |                           FT_UInt    len, | 
| 214 |                           FT_Fixed*  weightvector ) | 
| 215 |   { | 
| 216 |     FT_Error                 error; | 
| 217 |     FT_Service_MultiMasters  service; | 
| 218 |  | 
| 219 |  | 
| 220 |     /* check of `face' delayed to `ft_face_get_mm_service' */ | 
| 221 |  | 
| 222 |     if ( len && !weightvector ) | 
| 223 |       return FT_THROW( Invalid_Argument ); | 
| 224 |  | 
| 225 |     error = ft_face_get_mm_service( face, &service ); | 
| 226 |     if ( !error ) | 
| 227 |     { | 
| 228 |       error = FT_ERR( Invalid_Argument ); | 
| 229 |       if ( service->set_mm_weightvector ) | 
| 230 |         error = service->set_mm_weightvector( face, len, weightvector ); | 
| 231 |  | 
| 232 |       if ( !error ) | 
| 233 |       { | 
| 234 |         if ( len ) | 
| 235 |           face->face_flags |= FT_FACE_FLAG_VARIATION; | 
| 236 |         else | 
| 237 |           face->face_flags &= ~FT_FACE_FLAG_VARIATION; | 
| 238 |       } | 
| 239 |     } | 
| 240 |  | 
| 241 |     /* enforce recomputation of auto-hinting data */ | 
| 242 |     if ( !error && face->autohint.finalizer ) | 
| 243 |     { | 
| 244 |       face->autohint.finalizer( face->autohint.data ); | 
| 245 |       face->autohint.data = NULL; | 
| 246 |     } | 
| 247 |  | 
| 248 |     return error; | 
| 249 |   } | 
| 250 |  | 
| 251 |  | 
| 252 |   FT_EXPORT_DEF( FT_Error ) | 
| 253 |   FT_Get_MM_WeightVector( FT_Face    face, | 
| 254 |                           FT_UInt*   len, | 
| 255 |                           FT_Fixed*  weightvector ) | 
| 256 |   { | 
| 257 |     FT_Error                 error; | 
| 258 |     FT_Service_MultiMasters  service; | 
| 259 |  | 
| 260 |  | 
| 261 |     /* check of `face' delayed to `ft_face_get_mm_service' */ | 
| 262 |  | 
| 263 |     if ( len && !weightvector ) | 
| 264 |       return FT_THROW( Invalid_Argument ); | 
| 265 |  | 
| 266 |     error = ft_face_get_mm_service( face, &service ); | 
| 267 |     if ( !error ) | 
| 268 |     { | 
| 269 |       error = FT_ERR( Invalid_Argument ); | 
| 270 |       if ( service->get_mm_weightvector ) | 
| 271 |         error = service->get_mm_weightvector( face, len, weightvector ); | 
| 272 |     } | 
| 273 |  | 
| 274 |     return error; | 
| 275 |   } | 
| 276 |  | 
| 277 |  | 
| 278 |   /* documentation is in ftmm.h */ | 
| 279 |  | 
| 280 |   FT_EXPORT_DEF( FT_Error ) | 
| 281 |   FT_Set_Var_Design_Coordinates( FT_Face    face, | 
| 282 |                                  FT_UInt    num_coords, | 
| 283 |                                  FT_Fixed*  coords ) | 
| 284 |   { | 
| 285 |     FT_Error                      error; | 
| 286 |     FT_Service_MultiMasters       service_mm   = NULL; | 
| 287 |     FT_Service_MetricsVariations  service_mvar = NULL; | 
| 288 |  | 
| 289 |  | 
| 290 |     /* check of `face' delayed to `ft_face_get_mm_service' */ | 
| 291 |  | 
| 292 |     if ( num_coords && !coords ) | 
| 293 |       return FT_THROW( Invalid_Argument ); | 
| 294 |  | 
| 295 |     error = ft_face_get_mm_service( face, &service_mm ); | 
| 296 |     if ( !error ) | 
| 297 |     { | 
| 298 |       error = FT_ERR( Invalid_Argument ); | 
| 299 |       if ( service_mm->set_var_design ) | 
| 300 |         error = service_mm->set_var_design( face, num_coords, coords ); | 
| 301 |  | 
| 302 |       if ( !error || error == -1 ) | 
| 303 |       { | 
| 304 |         FT_Bool  is_variation_old = FT_IS_VARIATION( face ); | 
| 305 |  | 
| 306 |  | 
| 307 |         if ( num_coords ) | 
| 308 |           face->face_flags |= FT_FACE_FLAG_VARIATION; | 
| 309 |         else | 
| 310 |           face->face_flags &= ~FT_FACE_FLAG_VARIATION; | 
| 311 |  | 
| 312 |         if ( service_mm->construct_ps_name ) | 
| 313 |         { | 
| 314 |           if ( error == -1 ) | 
| 315 |           { | 
| 316 |             /* The PS name of a named instance and a non-named instance */ | 
| 317 |             /* usually differs, even if the axis values are identical.  */ | 
| 318 |             if ( is_variation_old != FT_IS_VARIATION( face ) ) | 
| 319 |               service_mm->construct_ps_name( face ); | 
| 320 |           } | 
| 321 |           else | 
| 322 |             service_mm->construct_ps_name( face ); | 
| 323 |         } | 
| 324 |       } | 
| 325 |  | 
| 326 |       /* internal error code -1 means `no change'; we can exit immediately */ | 
| 327 |       if ( error == -1 ) | 
| 328 |         return FT_Err_Ok; | 
| 329 |     } | 
| 330 |  | 
| 331 |     if ( !error ) | 
| 332 |     { | 
| 333 |       (void)ft_face_get_mvar_service( face, &service_mvar ); | 
| 334 |  | 
| 335 |       if ( service_mvar && service_mvar->metrics_adjust ) | 
| 336 |         service_mvar->metrics_adjust( face ); | 
| 337 |     } | 
| 338 |  | 
| 339 |     /* enforce recomputation of auto-hinting data */ | 
| 340 |     if ( !error && face->autohint.finalizer ) | 
| 341 |     { | 
| 342 |       face->autohint.finalizer( face->autohint.data ); | 
| 343 |       face->autohint.data = NULL; | 
| 344 |     } | 
| 345 |  | 
| 346 |     return error; | 
| 347 |   } | 
| 348 |  | 
| 349 |  | 
| 350 |   /* documentation is in ftmm.h */ | 
| 351 |  | 
| 352 |   FT_EXPORT_DEF( FT_Error ) | 
| 353 |   FT_Get_Var_Design_Coordinates( FT_Face    face, | 
| 354 |                                  FT_UInt    num_coords, | 
| 355 |                                  FT_Fixed*  coords ) | 
| 356 |   { | 
| 357 |     FT_Error                 error; | 
| 358 |     FT_Service_MultiMasters  service; | 
| 359 |  | 
| 360 |  | 
| 361 |     /* check of `face' delayed to `ft_face_get_mm_service' */ | 
| 362 |  | 
| 363 |     if ( !coords ) | 
| 364 |       return FT_THROW( Invalid_Argument ); | 
| 365 |  | 
| 366 |     error = ft_face_get_mm_service( face, &service ); | 
| 367 |     if ( !error ) | 
| 368 |     { | 
| 369 |       error = FT_ERR( Invalid_Argument ); | 
| 370 |       if ( service->get_var_design ) | 
| 371 |         error = service->get_var_design( face, num_coords, coords ); | 
| 372 |     } | 
| 373 |  | 
| 374 |     return error; | 
| 375 |   } | 
| 376 |  | 
| 377 |  | 
| 378 |   /* documentation is in ftmm.h */ | 
| 379 |  | 
| 380 |   FT_EXPORT_DEF( FT_Error ) | 
| 381 |   FT_Set_MM_Blend_Coordinates( FT_Face    face, | 
| 382 |                                FT_UInt    num_coords, | 
| 383 |                                FT_Fixed*  coords ) | 
| 384 |   { | 
| 385 |     FT_Error                      error; | 
| 386 |     FT_Service_MultiMasters       service_mm   = NULL; | 
| 387 |     FT_Service_MetricsVariations  service_mvar = NULL; | 
| 388 |  | 
| 389 |  | 
| 390 |     /* check of `face' delayed to `ft_face_get_mm_service' */ | 
| 391 |  | 
| 392 |     if ( num_coords && !coords ) | 
| 393 |       return FT_THROW( Invalid_Argument ); | 
| 394 |  | 
| 395 |     error = ft_face_get_mm_service( face, &service_mm ); | 
| 396 |     if ( !error ) | 
| 397 |     { | 
| 398 |       error = FT_ERR( Invalid_Argument ); | 
| 399 |       if ( service_mm->set_mm_blend ) | 
| 400 |         error = service_mm->set_mm_blend( face, num_coords, coords ); | 
| 401 |  | 
| 402 |       if ( !error || error == -1 ) | 
| 403 |       { | 
| 404 |         FT_Bool  is_variation_old = FT_IS_VARIATION( face ); | 
| 405 |  | 
| 406 |  | 
| 407 |         if ( num_coords ) | 
| 408 |           face->face_flags |= FT_FACE_FLAG_VARIATION; | 
| 409 |         else | 
| 410 |           face->face_flags &= ~FT_FACE_FLAG_VARIATION; | 
| 411 |  | 
| 412 |         if ( service_mm->construct_ps_name ) | 
| 413 |         { | 
| 414 |           if ( error == -1 ) | 
| 415 |           { | 
| 416 |             /* The PS name of a named instance and a non-named instance */ | 
| 417 |             /* usually differs, even if the axis values are identical.  */ | 
| 418 |             if ( is_variation_old != FT_IS_VARIATION( face ) ) | 
| 419 |               service_mm->construct_ps_name( face ); | 
| 420 |           } | 
| 421 |           else | 
| 422 |             service_mm->construct_ps_name( face ); | 
| 423 |         } | 
| 424 |       } | 
| 425 |  | 
| 426 |       /* internal error code -1 means `no change'; we can exit immediately */ | 
| 427 |       if ( error == -1 ) | 
| 428 |         return FT_Err_Ok; | 
| 429 |     } | 
| 430 |  | 
| 431 |     if ( !error ) | 
| 432 |     { | 
| 433 |       (void)ft_face_get_mvar_service( face, &service_mvar ); | 
| 434 |  | 
| 435 |       if ( service_mvar && service_mvar->metrics_adjust ) | 
| 436 |         service_mvar->metrics_adjust( face ); | 
| 437 |     } | 
| 438 |  | 
| 439 |     /* enforce recomputation of auto-hinting data */ | 
| 440 |     if ( !error && face->autohint.finalizer ) | 
| 441 |     { | 
| 442 |       face->autohint.finalizer( face->autohint.data ); | 
| 443 |       face->autohint.data = NULL; | 
| 444 |     } | 
| 445 |  | 
| 446 |     return error; | 
| 447 |   } | 
| 448 |  | 
| 449 |  | 
| 450 |   /* documentation is in ftmm.h */ | 
| 451 |  | 
| 452 |   /* This is exactly the same as the previous function.  It exists for */ | 
| 453 |   /* orthogonality.                                                    */ | 
| 454 |  | 
| 455 |   FT_EXPORT_DEF( FT_Error ) | 
| 456 |   FT_Set_Var_Blend_Coordinates( FT_Face    face, | 
| 457 |                                 FT_UInt    num_coords, | 
| 458 |                                 FT_Fixed*  coords ) | 
| 459 |   { | 
| 460 |     FT_Error                      error; | 
| 461 |     FT_Service_MultiMasters       service_mm   = NULL; | 
| 462 |     FT_Service_MetricsVariations  service_mvar = NULL; | 
| 463 |  | 
| 464 |  | 
| 465 |     /* check of `face' delayed to `ft_face_get_mm_service' */ | 
| 466 |  | 
| 467 |     if ( num_coords && !coords ) | 
| 468 |       return FT_THROW( Invalid_Argument ); | 
| 469 |  | 
| 470 |     error = ft_face_get_mm_service( face, &service_mm ); | 
| 471 |     if ( !error ) | 
| 472 |     { | 
| 473 |       error = FT_ERR( Invalid_Argument ); | 
| 474 |       if ( service_mm->set_mm_blend ) | 
| 475 |         error = service_mm->set_mm_blend( face, num_coords, coords ); | 
| 476 |  | 
| 477 |       if ( !error || error == -1 ) | 
| 478 |       { | 
| 479 |         FT_Bool  is_variation_old = FT_IS_VARIATION( face ); | 
| 480 |  | 
| 481 |  | 
| 482 |         if ( num_coords ) | 
| 483 |           face->face_flags |= FT_FACE_FLAG_VARIATION; | 
| 484 |         else | 
| 485 |           face->face_flags &= ~FT_FACE_FLAG_VARIATION; | 
| 486 |  | 
| 487 |         if ( service_mm->construct_ps_name ) | 
| 488 |         { | 
| 489 |           if ( error == -1 ) | 
| 490 |           { | 
| 491 |             /* The PS name of a named instance and a non-named instance */ | 
| 492 |             /* usually differs, even if the axis values are identical.  */ | 
| 493 |             if ( is_variation_old != FT_IS_VARIATION( face ) ) | 
| 494 |               service_mm->construct_ps_name( face ); | 
| 495 |           } | 
| 496 |           else | 
| 497 |             service_mm->construct_ps_name( face ); | 
| 498 |         } | 
| 499 |       } | 
| 500 |  | 
| 501 |       /* internal error code -1 means `no change'; we can exit immediately */ | 
| 502 |       if ( error == -1 ) | 
| 503 |         return FT_Err_Ok; | 
| 504 |     } | 
| 505 |  | 
| 506 |     if ( !error ) | 
| 507 |     { | 
| 508 |       (void)ft_face_get_mvar_service( face, &service_mvar ); | 
| 509 |  | 
| 510 |       if ( service_mvar && service_mvar->metrics_adjust ) | 
| 511 |         service_mvar->metrics_adjust( face ); | 
| 512 |     } | 
| 513 |  | 
| 514 |     /* enforce recomputation of auto-hinting data */ | 
| 515 |     if ( !error && face->autohint.finalizer ) | 
| 516 |     { | 
| 517 |       face->autohint.finalizer( face->autohint.data ); | 
| 518 |       face->autohint.data = NULL; | 
| 519 |     } | 
| 520 |  | 
| 521 |     return error; | 
| 522 |   } | 
| 523 |  | 
| 524 |  | 
| 525 |   /* documentation is in ftmm.h */ | 
| 526 |  | 
| 527 |   FT_EXPORT_DEF( FT_Error ) | 
| 528 |   FT_Get_MM_Blend_Coordinates( FT_Face    face, | 
| 529 |                                FT_UInt    num_coords, | 
| 530 |                                FT_Fixed*  coords ) | 
| 531 |   { | 
| 532 |     FT_Error                 error; | 
| 533 |     FT_Service_MultiMasters  service; | 
| 534 |  | 
| 535 |  | 
| 536 |     /* check of `face' delayed to `ft_face_get_mm_service' */ | 
| 537 |  | 
| 538 |     if ( !coords ) | 
| 539 |       return FT_THROW( Invalid_Argument ); | 
| 540 |  | 
| 541 |     error = ft_face_get_mm_service( face, &service ); | 
| 542 |     if ( !error ) | 
| 543 |     { | 
| 544 |       error = FT_ERR( Invalid_Argument ); | 
| 545 |       if ( service->get_mm_blend ) | 
| 546 |         error = service->get_mm_blend( face, num_coords, coords ); | 
| 547 |     } | 
| 548 |  | 
| 549 |     return error; | 
| 550 |   } | 
| 551 |  | 
| 552 |  | 
| 553 |   /* documentation is in ftmm.h */ | 
| 554 |  | 
| 555 |   /* This is exactly the same as the previous function.  It exists for */ | 
| 556 |   /* orthogonality.                                                    */ | 
| 557 |  | 
| 558 |   FT_EXPORT_DEF( FT_Error ) | 
| 559 |   FT_Get_Var_Blend_Coordinates( FT_Face    face, | 
| 560 |                                 FT_UInt    num_coords, | 
| 561 |                                 FT_Fixed*  coords ) | 
| 562 |   { | 
| 563 |     FT_Error                 error; | 
| 564 |     FT_Service_MultiMasters  service; | 
| 565 |  | 
| 566 |  | 
| 567 |     /* check of `face' delayed to `ft_face_get_mm_service' */ | 
| 568 |  | 
| 569 |     if ( !coords ) | 
| 570 |       return FT_THROW( Invalid_Argument ); | 
| 571 |  | 
| 572 |     error = ft_face_get_mm_service( face, &service ); | 
| 573 |     if ( !error ) | 
| 574 |     { | 
| 575 |       error = FT_ERR( Invalid_Argument ); | 
| 576 |       if ( service->get_mm_blend ) | 
| 577 |         error = service->get_mm_blend( face, num_coords, coords ); | 
| 578 |     } | 
| 579 |  | 
| 580 |     return error; | 
| 581 |   } | 
| 582 |  | 
| 583 |  | 
| 584 |   /* documentation is in ftmm.h */ | 
| 585 |  | 
| 586 |   FT_EXPORT_DEF( FT_Error ) | 
| 587 |   FT_Get_Var_Axis_Flags( FT_MM_Var*  master, | 
| 588 |                          FT_UInt     axis_index, | 
| 589 |                          FT_UInt*    flags ) | 
| 590 |   { | 
| 591 |     FT_UShort*  axis_flags; | 
| 592 |  | 
| 593 |  | 
| 594 |     if ( !master || !flags ) | 
| 595 |       return FT_THROW( Invalid_Argument ); | 
| 596 |  | 
| 597 |     if ( axis_index >= master->num_axis ) | 
| 598 |       return FT_THROW( Invalid_Argument ); | 
| 599 |  | 
| 600 |     /* the axis flags array immediately follows the data of `master' */ | 
| 601 |     axis_flags = (FT_UShort*)&( master[1] ); | 
| 602 |     *flags     = axis_flags[axis_index]; | 
| 603 |  | 
| 604 |     return FT_Err_Ok; | 
| 605 |   } | 
| 606 |  | 
| 607 |  | 
| 608 |   /* documentation is in ftmm.h */ | 
| 609 |  | 
| 610 |   FT_EXPORT_DEF( FT_Error ) | 
| 611 |   FT_Set_Named_Instance( FT_Face  face, | 
| 612 |                          FT_UInt  instance_index ) | 
| 613 |   { | 
| 614 |     FT_Error  error; | 
| 615 |  | 
| 616 |     FT_Service_MultiMasters       service_mm   = NULL; | 
| 617 |     FT_Service_MetricsVariations  service_mvar = NULL; | 
| 618 |  | 
| 619 |  | 
| 620 |     /* check of `face' delayed to `ft_face_get_mm_service' */ | 
| 621 |  | 
| 622 |     error = ft_face_get_mm_service( face, &service_mm ); | 
| 623 |     if ( !error ) | 
| 624 |     { | 
| 625 |       error = FT_ERR( Invalid_Argument ); | 
| 626 |       if ( service_mm->set_named_instance ) | 
| 627 |         error = service_mm->set_named_instance( face, instance_index ); | 
| 628 |  | 
| 629 |       if ( !error || error == -1 ) | 
| 630 |       { | 
| 631 |         FT_Bool  is_variation_old = FT_IS_VARIATION( face ); | 
| 632 |  | 
| 633 |  | 
| 634 |         face->face_flags &= ~FT_FACE_FLAG_VARIATION; | 
| 635 |         face->face_index  = ( instance_index << 16 )        | | 
| 636 |                             ( face->face_index & 0xFFFFL ); | 
| 637 |  | 
| 638 |         if ( service_mm->construct_ps_name ) | 
| 639 |         { | 
| 640 |           if ( error == -1 ) | 
| 641 |           { | 
| 642 |             /* The PS name of a named instance and a non-named instance */ | 
| 643 |             /* usually differs, even if the axis values are identical.  */ | 
| 644 |             if ( is_variation_old != FT_IS_VARIATION( face ) ) | 
| 645 |               service_mm->construct_ps_name( face ); | 
| 646 |           } | 
| 647 |           else | 
| 648 |             service_mm->construct_ps_name( face ); | 
| 649 |         } | 
| 650 |       } | 
| 651 |  | 
| 652 |       /* internal error code -1 means `no change'; we can exit immediately */ | 
| 653 |       if ( error == -1 ) | 
| 654 |         return FT_Err_Ok; | 
| 655 |     } | 
| 656 |  | 
| 657 |     if ( !error ) | 
| 658 |     { | 
| 659 |       (void)ft_face_get_mvar_service( face, &service_mvar ); | 
| 660 |  | 
| 661 |       if ( service_mvar && service_mvar->metrics_adjust ) | 
| 662 |         service_mvar->metrics_adjust( face ); | 
| 663 |     } | 
| 664 |  | 
| 665 |     /* enforce recomputation of auto-hinting data */ | 
| 666 |     if ( !error && face->autohint.finalizer ) | 
| 667 |     { | 
| 668 |       face->autohint.finalizer( face->autohint.data ); | 
| 669 |       face->autohint.data = NULL; | 
| 670 |     } | 
| 671 |  | 
| 672 |     return error; | 
| 673 |   } | 
| 674 |  | 
| 675 |  | 
| 676 |   /* documentation is in ftmm.h */ | 
| 677 |  | 
| 678 |   FT_EXPORT_DEF( FT_Error ) | 
| 679 |   FT_Get_Default_Named_Instance( FT_Face   face, | 
| 680 |                                  FT_UInt  *instance_index ) | 
| 681 |   { | 
| 682 |     FT_Error  error; | 
| 683 |  | 
| 684 |     FT_Service_MultiMasters  service_mm = NULL; | 
| 685 |  | 
| 686 |  | 
| 687 |     /* check of `face' delayed to `ft_face_get_mm_service' */ | 
| 688 |  | 
| 689 |     error = ft_face_get_mm_service( face, &service_mm ); | 
| 690 |     if ( !error ) | 
| 691 |     { | 
| 692 |       /* no error if `get_default_named_instance` is not available */ | 
| 693 |       if ( service_mm->get_default_named_instance ) | 
| 694 |         error = service_mm->get_default_named_instance( face, | 
| 695 |                                                         instance_index ); | 
| 696 |       else | 
| 697 |         error = FT_Err_Ok; | 
| 698 |     } | 
| 699 |  | 
| 700 |     return error; | 
| 701 |   } | 
| 702 |  | 
| 703 |  | 
| 704 | /* END */ | 
| 705 |  |