1 /**************************************************************************** 2 * 3 * ftmm.c 4 * 5 * Multiple Master font support (body). 6 * 7 * Copyright (C) 1996-2020 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 ft_face_get_mm_service(FT_Face face,FT_Service_MultiMasters * aservice)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 ft_face_get_mvar_service(FT_Face face,FT_Service_MetricsVariations * aservice)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 ) FT_Get_Multi_Master(FT_Face face,FT_Multi_Master * amaster)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 ) FT_Get_MM_Var(FT_Face face,FT_MM_Var ** amaster)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 ) FT_Done_MM_Var(FT_Library library,FT_MM_Var * amaster)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 ) FT_Set_MM_Design_Coordinates(FT_Face face,FT_UInt num_coords,FT_Long * coords)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 190 /* enforce recomputation of auto-hinting data */ 191 if ( !error && face->autohint.finalizer ) 192 { 193 face->autohint.finalizer( face->autohint.data ); 194 face->autohint.data = NULL; 195 } 196 197 return error; 198 } 199 200 201 /* documentation is in ftmm.h */ 202 203 FT_EXPORT_DEF( FT_Error ) FT_Set_MM_WeightVector(FT_Face face,FT_UInt len,FT_Fixed * weightvector)204 FT_Set_MM_WeightVector( FT_Face face, 205 FT_UInt len, 206 FT_Fixed* weightvector ) 207 { 208 FT_Error error; 209 FT_Service_MultiMasters service; 210 211 212 /* check of `face' delayed to `ft_face_get_mm_service' */ 213 214 if ( len && !weightvector ) 215 return FT_THROW( Invalid_Argument ); 216 217 error = ft_face_get_mm_service( face, &service ); 218 if ( !error ) 219 { 220 error = FT_ERR( Invalid_Argument ); 221 if ( service->set_mm_weightvector ) 222 error = service->set_mm_weightvector( face, len, weightvector ); 223 } 224 225 /* enforce recomputation of auto-hinting data */ 226 if ( !error && face->autohint.finalizer ) 227 { 228 face->autohint.finalizer( face->autohint.data ); 229 face->autohint.data = NULL; 230 } 231 232 return error; 233 } 234 235 236 FT_EXPORT_DEF( FT_Error ) FT_Get_MM_WeightVector(FT_Face face,FT_UInt * len,FT_Fixed * weightvector)237 FT_Get_MM_WeightVector( FT_Face face, 238 FT_UInt* len, 239 FT_Fixed* weightvector ) 240 { 241 FT_Error error; 242 FT_Service_MultiMasters service; 243 244 245 /* check of `face' delayed to `ft_face_get_mm_service' */ 246 247 if ( len && !weightvector ) 248 return FT_THROW( Invalid_Argument ); 249 250 error = ft_face_get_mm_service( face, &service ); 251 if ( !error ) 252 { 253 error = FT_ERR( Invalid_Argument ); 254 if ( service->get_mm_weightvector ) 255 error = service->get_mm_weightvector( face, len, weightvector ); 256 } 257 258 return error; 259 } 260 261 262 /* documentation is in ftmm.h */ 263 264 FT_EXPORT_DEF( FT_Error ) FT_Set_Var_Design_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)265 FT_Set_Var_Design_Coordinates( FT_Face face, 266 FT_UInt num_coords, 267 FT_Fixed* coords ) 268 { 269 FT_Error error; 270 FT_Service_MultiMasters service_mm = NULL; 271 FT_Service_MetricsVariations service_mvar = NULL; 272 273 274 /* check of `face' delayed to `ft_face_get_mm_service' */ 275 276 if ( num_coords && !coords ) 277 return FT_THROW( Invalid_Argument ); 278 279 error = ft_face_get_mm_service( face, &service_mm ); 280 if ( !error ) 281 { 282 error = FT_ERR( Invalid_Argument ); 283 if ( service_mm->set_var_design ) 284 error = service_mm->set_var_design( face, num_coords, coords ); 285 286 /* internal error code -1 means `no change'; we can exit immediately */ 287 if ( error == -1 ) 288 return FT_Err_Ok; 289 } 290 291 if ( !error ) 292 { 293 (void)ft_face_get_mvar_service( face, &service_mvar ); 294 295 if ( service_mvar && service_mvar->metrics_adjust ) 296 service_mvar->metrics_adjust( face ); 297 } 298 299 /* enforce recomputation of auto-hinting data */ 300 if ( !error && face->autohint.finalizer ) 301 { 302 face->autohint.finalizer( face->autohint.data ); 303 face->autohint.data = NULL; 304 } 305 306 return error; 307 } 308 309 310 /* documentation is in ftmm.h */ 311 312 FT_EXPORT_DEF( FT_Error ) FT_Get_Var_Design_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)313 FT_Get_Var_Design_Coordinates( FT_Face face, 314 FT_UInt num_coords, 315 FT_Fixed* coords ) 316 { 317 FT_Error error; 318 FT_Service_MultiMasters service; 319 320 321 /* check of `face' delayed to `ft_face_get_mm_service' */ 322 323 if ( !coords ) 324 return FT_THROW( Invalid_Argument ); 325 326 error = ft_face_get_mm_service( face, &service ); 327 if ( !error ) 328 { 329 error = FT_ERR( Invalid_Argument ); 330 if ( service->get_var_design ) 331 error = service->get_var_design( face, num_coords, coords ); 332 } 333 334 return error; 335 } 336 337 338 /* documentation is in ftmm.h */ 339 340 FT_EXPORT_DEF( FT_Error ) FT_Set_MM_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)341 FT_Set_MM_Blend_Coordinates( FT_Face face, 342 FT_UInt num_coords, 343 FT_Fixed* coords ) 344 { 345 FT_Error error; 346 FT_Service_MultiMasters service_mm = NULL; 347 FT_Service_MetricsVariations service_mvar = NULL; 348 349 350 /* check of `face' delayed to `ft_face_get_mm_service' */ 351 352 if ( num_coords && !coords ) 353 return FT_THROW( Invalid_Argument ); 354 355 error = ft_face_get_mm_service( face, &service_mm ); 356 if ( !error ) 357 { 358 error = FT_ERR( Invalid_Argument ); 359 if ( service_mm->set_mm_blend ) 360 error = service_mm->set_mm_blend( face, num_coords, coords ); 361 362 /* internal error code -1 means `no change'; we can exit immediately */ 363 if ( error == -1 ) 364 return FT_Err_Ok; 365 } 366 367 if ( !error ) 368 { 369 (void)ft_face_get_mvar_service( face, &service_mvar ); 370 371 if ( service_mvar && service_mvar->metrics_adjust ) 372 service_mvar->metrics_adjust( face ); 373 } 374 375 /* enforce recomputation of auto-hinting data */ 376 if ( !error && face->autohint.finalizer ) 377 { 378 face->autohint.finalizer( face->autohint.data ); 379 face->autohint.data = NULL; 380 } 381 382 return error; 383 } 384 385 386 /* documentation is in ftmm.h */ 387 388 /* This is exactly the same as the previous function. It exists for */ 389 /* orthogonality. */ 390 391 FT_EXPORT_DEF( FT_Error ) FT_Set_Var_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)392 FT_Set_Var_Blend_Coordinates( FT_Face face, 393 FT_UInt num_coords, 394 FT_Fixed* coords ) 395 { 396 FT_Error error; 397 FT_Service_MultiMasters service_mm = NULL; 398 FT_Service_MetricsVariations service_mvar = NULL; 399 400 401 /* check of `face' delayed to `ft_face_get_mm_service' */ 402 403 if ( num_coords && !coords ) 404 return FT_THROW( Invalid_Argument ); 405 406 error = ft_face_get_mm_service( face, &service_mm ); 407 if ( !error ) 408 { 409 error = FT_ERR( Invalid_Argument ); 410 if ( service_mm->set_mm_blend ) 411 error = service_mm->set_mm_blend( face, num_coords, coords ); 412 413 /* internal error code -1 means `no change'; we can exit immediately */ 414 if ( error == -1 ) 415 return FT_Err_Ok; 416 } 417 418 if ( !error ) 419 { 420 (void)ft_face_get_mvar_service( face, &service_mvar ); 421 422 if ( service_mvar && service_mvar->metrics_adjust ) 423 service_mvar->metrics_adjust( face ); 424 } 425 426 /* enforce recomputation of auto-hinting data */ 427 if ( !error && face->autohint.finalizer ) 428 { 429 face->autohint.finalizer( face->autohint.data ); 430 face->autohint.data = NULL; 431 } 432 433 return error; 434 } 435 436 437 /* documentation is in ftmm.h */ 438 439 FT_EXPORT_DEF( FT_Error ) FT_Get_MM_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)440 FT_Get_MM_Blend_Coordinates( FT_Face face, 441 FT_UInt num_coords, 442 FT_Fixed* coords ) 443 { 444 FT_Error error; 445 FT_Service_MultiMasters service; 446 447 448 /* check of `face' delayed to `ft_face_get_mm_service' */ 449 450 if ( !coords ) 451 return FT_THROW( Invalid_Argument ); 452 453 error = ft_face_get_mm_service( face, &service ); 454 if ( !error ) 455 { 456 error = FT_ERR( Invalid_Argument ); 457 if ( service->get_mm_blend ) 458 error = service->get_mm_blend( face, num_coords, coords ); 459 } 460 461 return error; 462 } 463 464 465 /* documentation is in ftmm.h */ 466 467 /* This is exactly the same as the previous function. It exists for */ 468 /* orthogonality. */ 469 470 FT_EXPORT_DEF( FT_Error ) FT_Get_Var_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)471 FT_Get_Var_Blend_Coordinates( FT_Face face, 472 FT_UInt num_coords, 473 FT_Fixed* coords ) 474 { 475 FT_Error error; 476 FT_Service_MultiMasters service; 477 478 479 /* check of `face' delayed to `ft_face_get_mm_service' */ 480 481 if ( !coords ) 482 return FT_THROW( Invalid_Argument ); 483 484 error = ft_face_get_mm_service( face, &service ); 485 if ( !error ) 486 { 487 error = FT_ERR( Invalid_Argument ); 488 if ( service->get_mm_blend ) 489 error = service->get_mm_blend( face, num_coords, coords ); 490 } 491 492 return error; 493 } 494 495 496 /* documentation is in ftmm.h */ 497 498 FT_EXPORT_DEF( FT_Error ) FT_Get_Var_Axis_Flags(FT_MM_Var * master,FT_UInt axis_index,FT_UInt * flags)499 FT_Get_Var_Axis_Flags( FT_MM_Var* master, 500 FT_UInt axis_index, 501 FT_UInt* flags ) 502 { 503 FT_UShort* axis_flags; 504 505 506 if ( !master || !flags ) 507 return FT_THROW( Invalid_Argument ); 508 509 if ( axis_index >= master->num_axis ) 510 return FT_THROW( Invalid_Argument ); 511 512 /* the axis flags array immediately follows the data of `master' */ 513 axis_flags = (FT_UShort*)&( master[1] ); 514 *flags = axis_flags[axis_index]; 515 516 return FT_Err_Ok; 517 } 518 519 520 /* documentation is in ftmm.h */ 521 522 FT_EXPORT_DEF( FT_Error ) FT_Set_Named_Instance(FT_Face face,FT_UInt instance_index)523 FT_Set_Named_Instance( FT_Face face, 524 FT_UInt instance_index ) 525 { 526 FT_Error error; 527 528 FT_Service_MultiMasters service_mm = NULL; 529 FT_Service_MetricsVariations service_mvar = NULL; 530 531 532 /* check of `face' delayed to `ft_face_get_mm_service' */ 533 534 error = ft_face_get_mm_service( face, &service_mm ); 535 if ( !error ) 536 { 537 error = FT_ERR( Invalid_Argument ); 538 if ( service_mm->set_instance ) 539 error = service_mm->set_instance( face, instance_index ); 540 } 541 542 if ( !error ) 543 { 544 (void)ft_face_get_mvar_service( face, &service_mvar ); 545 546 if ( service_mvar && service_mvar->metrics_adjust ) 547 service_mvar->metrics_adjust( face ); 548 } 549 550 /* enforce recomputation of auto-hinting data */ 551 if ( !error && face->autohint.finalizer ) 552 { 553 face->autohint.finalizer( face->autohint.data ); 554 face->autohint.data = NULL; 555 } 556 557 if ( !error ) 558 { 559 face->face_index = ( instance_index << 16 ) | 560 ( face->face_index & 0xFFFFL ); 561 face->face_flags &= ~FT_FACE_FLAG_VARIATION; 562 } 563 564 return error; 565 } 566 567 568 /* END */ 569