1 /***************************************************************************/
   2 /*                                                                         */
   3 /*  ftmm.c                                                                 */
   4 /*                                                                         */
   5 /*    Multiple Master font support (body).                                 */
   6 /*                                                                         */
   7 /*  Copyright 1996-2018 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 <ft2build.h>
  20 #include FT_INTERNAL_DEBUG_H
  21 
  22 #include FT_MULTIPLE_MASTERS_H
  23 #include FT_INTERNAL_OBJECTS_H
  24 #include FT_SERVICE_MULTIPLE_MASTERS_H
  25 #include FT_SERVICE_METRICS_VARIATIONS_H
  26 
  27 
  28   /*************************************************************************/
  29   /*                                                                       */
  30   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  31   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  32   /* messages during execution.                                            */
  33   /*                                                                       */
  34 #undef  FT_COMPONENT
  35 #define FT_COMPONENT  trace_mm
  36 
  37 
  38   static FT_Error
  39   ft_face_get_mm_service( FT_Face                   face,
  40                           FT_Service_MultiMasters  *aservice )
  41   {
  42     FT_Error  error;
  43 
  44 
  45     *aservice = NULL;
  46 
  47     if ( !face )
  48       return FT_THROW( Invalid_Face_Handle );
  49 
  50     error = FT_ERR( Invalid_Argument );
  51 
  52     if ( FT_HAS_MULTIPLE_MASTERS( face ) )
  53     {
  54       FT_FACE_LOOKUP_SERVICE( face,
  55                               *aservice,
  56                               MULTI_MASTERS );
  57 
  58       if ( *aservice )
  59         error = FT_Err_Ok;
  60     }
  61 
  62     return error;
  63   }
  64 
  65 
  66   static FT_Error
  67   ft_face_get_mvar_service( FT_Face                        face,
  68                             FT_Service_MetricsVariations  *aservice )
  69   {
  70     FT_Error  error;
  71 
  72 
  73     *aservice = NULL;
  74 
  75     if ( !face )
  76       return FT_THROW( Invalid_Face_Handle );
  77 
  78     error = FT_ERR( Invalid_Argument );
  79 
  80     if ( FT_HAS_MULTIPLE_MASTERS( face ) )
  81     {
  82       FT_FACE_LOOKUP_SERVICE( face,
  83                               *aservice,
  84                               METRICS_VARIATIONS );
  85 
  86       if ( *aservice )
  87         error = FT_Err_Ok;
  88     }
  89 
  90     return error;
  91   }
  92 
  93 
  94   /* documentation is in ftmm.h */
  95 
  96   FT_EXPORT_DEF( FT_Error )
  97   FT_Get_Multi_Master( FT_Face           face,
  98                        FT_Multi_Master  *amaster )
  99   {
 100     FT_Error                 error;
 101     FT_Service_MultiMasters  service;
 102 
 103 
 104     /* check of `face' delayed to `ft_face_get_mm_service' */
 105 
 106     if ( !amaster )
 107       return FT_THROW( Invalid_Argument );
 108 
 109     error = ft_face_get_mm_service( face, &service );
 110     if ( !error )
 111     {
 112       error = FT_ERR( Invalid_Argument );
 113       if ( service->get_mm )
 114         error = service->get_mm( face, amaster );
 115     }
 116 
 117     return error;
 118   }
 119 
 120 
 121   /* documentation is in ftmm.h */
 122 
 123   FT_EXPORT_DEF( FT_Error )
 124   FT_Get_MM_Var( FT_Face      face,
 125                  FT_MM_Var*  *amaster )
 126   {
 127     FT_Error                 error;
 128     FT_Service_MultiMasters  service;
 129 
 130 
 131     /* check of `face' delayed to `ft_face_get_mm_service' */
 132 
 133     if ( !amaster )
 134       return FT_THROW( Invalid_Argument );
 135 
 136     error = ft_face_get_mm_service( face, &service );
 137     if ( !error )
 138     {
 139       error = FT_ERR( Invalid_Argument );
 140       if ( service->get_mm_var )
 141         error = service->get_mm_var( face, amaster );
 142     }
 143 
 144     return error;
 145   }
 146 
 147 
 148   /* documentation is in ftmm.h */
 149 
 150   FT_EXPORT_DEF( FT_Error )
 151   FT_Done_MM_Var( FT_Library  library,
 152                   FT_MM_Var*  amaster )
 153   {
 154     FT_Memory  memory;
 155 
 156 
 157     if ( !library )
 158       return FT_THROW( Invalid_Library_Handle );
 159 
 160     memory = library->memory;
 161     FT_FREE( amaster );
 162 
 163     return FT_Err_Ok;
 164   }
 165 
 166 
 167   /* documentation is in ftmm.h */
 168 
 169   FT_EXPORT_DEF( FT_Error )
 170   FT_Set_MM_Design_Coordinates( FT_Face   face,
 171                                 FT_UInt   num_coords,
 172                                 FT_Long*  coords )
 173   {
 174     FT_Error                 error;
 175     FT_Service_MultiMasters  service;
 176 
 177 
 178     /* check of `face' delayed to `ft_face_get_mm_service' */
 179 
 180     if ( num_coords && !coords )
 181       return FT_THROW( Invalid_Argument );
 182 
 183     error = ft_face_get_mm_service( face, &service );
 184     if ( !error )
 185     {
 186       error = FT_ERR( Invalid_Argument );
 187       if ( service->set_mm_design )
 188         error = service->set_mm_design( face, num_coords, coords );
 189     }
 190 
 191     /* enforce recomputation of auto-hinting data */
 192     if ( !error && face->autohint.finalizer )
 193     {
 194       face->autohint.finalizer( face->autohint.data );
 195       face->autohint.data = NULL;
 196     }
 197 
 198     return error;
 199   }
 200 
 201 
 202   /* documentation is in ftmm.h */
 203 
 204   FT_EXPORT_DEF( FT_Error )
 205   FT_Set_Var_Design_Coordinates( FT_Face    face,
 206                                  FT_UInt    num_coords,
 207                                  FT_Fixed*  coords )
 208   {
 209     FT_Error                      error;
 210     FT_Service_MultiMasters       service_mm   = NULL;
 211     FT_Service_MetricsVariations  service_mvar = NULL;
 212 
 213 
 214     /* check of `face' delayed to `ft_face_get_mm_service' */
 215 
 216     if ( num_coords && !coords )
 217       return FT_THROW( Invalid_Argument );
 218 
 219     error = ft_face_get_mm_service( face, &service_mm );
 220     if ( !error )
 221     {
 222       error = FT_ERR( Invalid_Argument );
 223       if ( service_mm->set_var_design )
 224         error = service_mm->set_var_design( face, num_coords, coords );
 225 
 226       /* internal error code -1 means `no change'; we can exit immediately */
 227       if ( error == -1 )
 228         return FT_Err_Ok;
 229     }
 230 
 231     if ( !error )
 232     {
 233       (void)ft_face_get_mvar_service( face, &service_mvar );
 234 
 235       if ( service_mvar && service_mvar->metrics_adjust )
 236         service_mvar->metrics_adjust( face );
 237     }
 238 
 239     /* enforce recomputation of auto-hinting data */
 240     if ( !error && face->autohint.finalizer )
 241     {
 242       face->autohint.finalizer( face->autohint.data );
 243       face->autohint.data = NULL;
 244     }
 245 
 246     return error;
 247   }
 248 
 249 
 250   /* documentation is in ftmm.h */
 251 
 252   FT_EXPORT_DEF( FT_Error )
 253   FT_Get_Var_Design_Coordinates( FT_Face    face,
 254                                  FT_UInt    num_coords,
 255                                  FT_Fixed*  coords )
 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 ( !coords )
 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_var_design )
 271         error = service->get_var_design( face, num_coords, coords );
 272     }
 273 
 274     return error;
 275   }
 276 
 277 
 278   /* documentation is in ftmm.h */
 279 
 280   FT_EXPORT_DEF( FT_Error )
 281   FT_Set_MM_Blend_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_mm_blend )
 300         error = service_mm->set_mm_blend( face, num_coords, coords );
 301 
 302       /* internal error code -1 means `no change'; we can exit immediately */
 303       if ( error == -1 )
 304         return FT_Err_Ok;
 305     }
 306 
 307     if ( !error )
 308     {
 309       (void)ft_face_get_mvar_service( face, &service_mvar );
 310 
 311       if ( service_mvar && service_mvar->metrics_adjust )
 312         service_mvar->metrics_adjust( face );
 313     }
 314 
 315     /* enforce recomputation of auto-hinting data */
 316     if ( !error && face->autohint.finalizer )
 317     {
 318       face->autohint.finalizer( face->autohint.data );
 319       face->autohint.data = NULL;
 320     }
 321 
 322     return error;
 323   }
 324 
 325 
 326   /* documentation is in ftmm.h */
 327 
 328   /* This is exactly the same as the previous function.  It exists for */
 329   /* orthogonality.                                                    */
 330 
 331   FT_EXPORT_DEF( FT_Error )
 332   FT_Set_Var_Blend_Coordinates( FT_Face    face,
 333                                 FT_UInt    num_coords,
 334                                 FT_Fixed*  coords )
 335   {
 336     FT_Error                      error;
 337     FT_Service_MultiMasters       service_mm   = NULL;
 338     FT_Service_MetricsVariations  service_mvar = NULL;
 339 
 340 
 341     /* check of `face' delayed to `ft_face_get_mm_service' */
 342 
 343     if ( num_coords && !coords )
 344       return FT_THROW( Invalid_Argument );
 345 
 346     error = ft_face_get_mm_service( face, &service_mm );
 347     if ( !error )
 348     {
 349       error = FT_ERR( Invalid_Argument );
 350       if ( service_mm->set_mm_blend )
 351         error = service_mm->set_mm_blend( face, num_coords, coords );
 352 
 353       /* internal error code -1 means `no change'; we can exit immediately */
 354       if ( error == -1 )
 355         return FT_Err_Ok;
 356     }
 357 
 358     if ( !error )
 359     {
 360       (void)ft_face_get_mvar_service( face, &service_mvar );
 361 
 362       if ( service_mvar && service_mvar->metrics_adjust )
 363         service_mvar->metrics_adjust( face );
 364     }
 365 
 366     /* enforce recomputation of auto-hinting data */
 367     if ( !error && face->autohint.finalizer )
 368     {
 369       face->autohint.finalizer( face->autohint.data );
 370       face->autohint.data = NULL;
 371     }
 372 
 373     return error;
 374   }
 375 
 376 
 377   /* documentation is in ftmm.h */
 378 
 379   FT_EXPORT_DEF( FT_Error )
 380   FT_Get_MM_Blend_Coordinates( FT_Face    face,
 381                                FT_UInt    num_coords,
 382                                FT_Fixed*  coords )
 383   {
 384     FT_Error                 error;
 385     FT_Service_MultiMasters  service;
 386 
 387 
 388     /* check of `face' delayed to `ft_face_get_mm_service' */
 389 
 390     if ( !coords )
 391       return FT_THROW( Invalid_Argument );
 392 
 393     error = ft_face_get_mm_service( face, &service );
 394     if ( !error )
 395     {
 396       error = FT_ERR( Invalid_Argument );
 397       if ( service->get_mm_blend )
 398         error = service->get_mm_blend( face, num_coords, coords );
 399     }
 400 
 401     return error;
 402   }
 403 
 404 
 405   /* documentation is in ftmm.h */
 406 
 407   /* This is exactly the same as the previous function.  It exists for */
 408   /* orthogonality.                                                    */
 409 
 410   FT_EXPORT_DEF( FT_Error )
 411   FT_Get_Var_Blend_Coordinates( FT_Face    face,
 412                                 FT_UInt    num_coords,
 413                                 FT_Fixed*  coords )
 414   {
 415     FT_Error                 error;
 416     FT_Service_MultiMasters  service;
 417 
 418 
 419     /* check of `face' delayed to `ft_face_get_mm_service' */
 420 
 421     if ( !coords )
 422       return FT_THROW( Invalid_Argument );
 423 
 424     error = ft_face_get_mm_service( face, &service );
 425     if ( !error )
 426     {
 427       error = FT_ERR( Invalid_Argument );
 428       if ( service->get_mm_blend )
 429         error = service->get_mm_blend( face, num_coords, coords );
 430     }
 431 
 432     return error;
 433   }
 434 
 435 
 436   /* documentation is in ftmm.h */
 437 
 438   FT_EXPORT_DEF( FT_Error )
 439   FT_Get_Var_Axis_Flags( FT_MM_Var*  master,
 440                          FT_UInt     axis_index,
 441                          FT_UInt*    flags )
 442   {
 443     FT_UShort*  axis_flags;
 444 
 445 
 446     if ( !master || !flags )
 447       return FT_THROW( Invalid_Argument );
 448 
 449     if ( axis_index >= master->num_axis )
 450       return FT_THROW( Invalid_Argument );
 451 
 452     /* the axis flags array immediately follows the data of `master' */
 453     axis_flags = (FT_UShort*)&( master[1] );
 454     *flags     = axis_flags[axis_index];
 455 
 456     return FT_Err_Ok;
 457   }
 458 
 459 
 460   /* documentation is in ftmm.h */
 461 
 462   FT_EXPORT_DEF( FT_Error )
 463   FT_Set_Named_Instance( FT_Face  face,
 464                          FT_UInt  instance_index )
 465   {
 466     FT_Error  error;
 467 
 468     FT_Service_MultiMasters       service_mm   = NULL;
 469     FT_Service_MetricsVariations  service_mvar = NULL;
 470 
 471 
 472     /* check of `face' delayed to `ft_face_get_mm_service' */
 473 
 474     error = ft_face_get_mm_service( face, &service_mm );
 475     if ( !error )
 476     {
 477       error = FT_ERR( Invalid_Argument );
 478       if ( service_mm->set_instance )
 479         error = service_mm->set_instance( face, instance_index );
 480     }
 481 
 482     if ( !error )
 483     {
 484       (void)ft_face_get_mvar_service( face, &service_mvar );
 485 
 486       if ( service_mvar && service_mvar->metrics_adjust )
 487         service_mvar->metrics_adjust( face );
 488     }
 489 
 490     /* enforce recomputation of auto-hinting data */
 491     if ( !error && face->autohint.finalizer )
 492     {
 493       face->autohint.finalizer( face->autohint.data );
 494       face->autohint.data = NULL;
 495     }
 496 
 497     if ( !error )
 498     {
 499       face->face_index  = ( instance_index << 16 )        |
 500                           ( face->face_index & 0xFFFFL );
 501       face->face_flags &= ~FT_FACE_FLAG_VARIATION;
 502     }
 503 
 504     return error;
 505   }
 506 
 507 
 508 /* END */