ftmm.c (18518B)
1 /**************************************************************************** 2 * 3 * ftmm.c 4 * 5 * Multiple Master font support (body). 6 * 7 * Copyright (C) 1996-2025 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 if ( !num_coords && !FT_IS_VARIATION( face ) ) 296 return FT_Err_Ok; /* nothing to be done */ 297 298 error = ft_face_get_mm_service( face, &service_mm ); 299 if ( !error ) 300 { 301 error = FT_ERR( Invalid_Argument ); 302 if ( service_mm->set_var_design ) 303 error = service_mm->set_var_design( face, num_coords, coords ); 304 305 if ( !error || error == -1 || error == -2 ) 306 { 307 FT_Bool is_variation_old = FT_IS_VARIATION( face ); 308 309 310 if ( error != -1 ) 311 { 312 if ( error == -2 ) /* -2 means is_variable. */ 313 { 314 face->face_flags |= FT_FACE_FLAG_VARIATION; 315 error = FT_Err_Ok; 316 } 317 else 318 face->face_flags &= ~FT_FACE_FLAG_VARIATION; 319 } 320 321 if ( service_mm->construct_ps_name ) 322 { 323 if ( error == -1 ) 324 { 325 /* The PS name of a named instance and a non-named instance */ 326 /* usually differs, even if the axis values are identical. */ 327 if ( is_variation_old != FT_IS_VARIATION( face ) ) 328 service_mm->construct_ps_name( face ); 329 } 330 else 331 service_mm->construct_ps_name( face ); 332 } 333 } 334 335 /* internal error code -1 means `no change'; we can exit immediately */ 336 if ( error == -1 ) 337 return FT_Err_Ok; 338 } 339 340 if ( !error ) 341 { 342 (void)ft_face_get_mvar_service( face, &service_mvar ); 343 344 if ( service_mvar && service_mvar->metrics_adjust ) 345 service_mvar->metrics_adjust( face ); 346 } 347 348 /* enforce recomputation of auto-hinting data */ 349 if ( !error && face->autohint.finalizer ) 350 { 351 face->autohint.finalizer( face->autohint.data ); 352 face->autohint.data = NULL; 353 } 354 355 return error; 356 } 357 358 359 /* documentation is in ftmm.h */ 360 361 FT_EXPORT_DEF( FT_Error ) 362 FT_Get_Var_Design_Coordinates( FT_Face face, 363 FT_UInt num_coords, 364 FT_Fixed* coords ) 365 { 366 FT_Error error; 367 FT_Service_MultiMasters service; 368 369 370 /* check of `face' delayed to `ft_face_get_mm_service' */ 371 372 if ( !coords ) 373 return FT_THROW( Invalid_Argument ); 374 375 error = ft_face_get_mm_service( face, &service ); 376 if ( !error ) 377 { 378 error = FT_ERR( Invalid_Argument ); 379 if ( service->get_var_design ) 380 error = service->get_var_design( face, num_coords, coords ); 381 } 382 383 return error; 384 } 385 386 387 /* documentation is in ftmm.h */ 388 389 FT_EXPORT_DEF( FT_Error ) 390 FT_Set_MM_Blend_Coordinates( FT_Face face, 391 FT_UInt num_coords, 392 FT_Fixed* coords ) 393 { 394 FT_Error error; 395 FT_Service_MultiMasters service_mm = NULL; 396 FT_Service_MetricsVariations service_mvar = NULL; 397 398 399 /* check of `face' delayed to `ft_face_get_mm_service' */ 400 401 if ( num_coords && !coords ) 402 return FT_THROW( Invalid_Argument ); 403 404 error = ft_face_get_mm_service( face, &service_mm ); 405 if ( !error ) 406 { 407 error = FT_ERR( Invalid_Argument ); 408 if ( service_mm->set_mm_blend ) 409 error = service_mm->set_mm_blend( face, num_coords, coords ); 410 411 if ( !error || error == -1 ) 412 { 413 FT_Bool is_variation_old = FT_IS_VARIATION( face ); 414 415 416 if ( num_coords ) 417 face->face_flags |= FT_FACE_FLAG_VARIATION; 418 else 419 face->face_flags &= ~FT_FACE_FLAG_VARIATION; 420 421 if ( service_mm->construct_ps_name ) 422 { 423 if ( error == -1 ) 424 { 425 /* The PS name of a named instance and a non-named instance */ 426 /* usually differs, even if the axis values are identical. */ 427 if ( is_variation_old != FT_IS_VARIATION( face ) ) 428 service_mm->construct_ps_name( face ); 429 } 430 else 431 service_mm->construct_ps_name( face ); 432 } 433 } 434 435 /* internal error code -1 means `no change'; we can exit immediately */ 436 if ( error == -1 ) 437 return FT_Err_Ok; 438 } 439 440 if ( !error ) 441 { 442 (void)ft_face_get_mvar_service( face, &service_mvar ); 443 444 if ( service_mvar && service_mvar->metrics_adjust ) 445 service_mvar->metrics_adjust( face ); 446 } 447 448 /* enforce recomputation of auto-hinting data */ 449 if ( !error && face->autohint.finalizer ) 450 { 451 face->autohint.finalizer( face->autohint.data ); 452 face->autohint.data = NULL; 453 } 454 455 return error; 456 } 457 458 459 /* documentation is in ftmm.h */ 460 461 /* This is exactly the same as the previous function. It exists for */ 462 /* orthogonality. */ 463 464 FT_EXPORT_DEF( FT_Error ) 465 FT_Set_Var_Blend_Coordinates( FT_Face face, 466 FT_UInt num_coords, 467 FT_Fixed* coords ) 468 { 469 FT_Error error; 470 FT_Service_MultiMasters service_mm = NULL; 471 FT_Service_MetricsVariations service_mvar = NULL; 472 473 474 /* check of `face' delayed to `ft_face_get_mm_service' */ 475 476 if ( num_coords && !coords ) 477 return FT_THROW( Invalid_Argument ); 478 479 error = ft_face_get_mm_service( face, &service_mm ); 480 if ( !error ) 481 { 482 error = FT_ERR( Invalid_Argument ); 483 if ( service_mm->set_mm_blend ) 484 error = service_mm->set_mm_blend( face, num_coords, coords ); 485 486 if ( !error || error == -1 || error == -2 ) 487 { 488 FT_Bool is_variation_old = FT_IS_VARIATION( face ); 489 490 491 if ( error != -1 ) 492 { 493 if ( error == -2 ) /* -2 means is_variable. */ 494 { 495 face->face_flags |= FT_FACE_FLAG_VARIATION; 496 error = FT_Err_Ok; 497 } 498 else 499 face->face_flags &= ~FT_FACE_FLAG_VARIATION; 500 } 501 502 if ( service_mm->construct_ps_name ) 503 { 504 if ( error == -1 ) 505 { 506 /* The PS name of a named instance and a non-named instance */ 507 /* usually differs, even if the axis values are identical. */ 508 if ( is_variation_old != FT_IS_VARIATION( face ) ) 509 service_mm->construct_ps_name( face ); 510 } 511 else 512 service_mm->construct_ps_name( face ); 513 } 514 } 515 516 /* internal error code -1 means `no change'; we can exit immediately */ 517 if ( error == -1 ) 518 return FT_Err_Ok; 519 } 520 521 if ( !error ) 522 { 523 (void)ft_face_get_mvar_service( face, &service_mvar ); 524 525 if ( service_mvar && service_mvar->metrics_adjust ) 526 service_mvar->metrics_adjust( face ); 527 } 528 529 /* enforce recomputation of auto-hinting data */ 530 if ( !error && face->autohint.finalizer ) 531 { 532 face->autohint.finalizer( face->autohint.data ); 533 face->autohint.data = NULL; 534 } 535 536 return error; 537 } 538 539 540 /* documentation is in ftmm.h */ 541 542 FT_EXPORT_DEF( FT_Error ) 543 FT_Get_MM_Blend_Coordinates( FT_Face face, 544 FT_UInt num_coords, 545 FT_Fixed* coords ) 546 { 547 FT_Error error; 548 FT_Service_MultiMasters service; 549 550 551 /* check of `face' delayed to `ft_face_get_mm_service' */ 552 553 if ( !coords ) 554 return FT_THROW( Invalid_Argument ); 555 556 error = ft_face_get_mm_service( face, &service ); 557 if ( !error ) 558 { 559 error = FT_ERR( Invalid_Argument ); 560 if ( service->get_mm_blend ) 561 error = service->get_mm_blend( face, num_coords, coords ); 562 } 563 564 return error; 565 } 566 567 568 /* documentation is in ftmm.h */ 569 570 /* This is exactly the same as the previous function. It exists for */ 571 /* orthogonality. */ 572 573 FT_EXPORT_DEF( FT_Error ) 574 FT_Get_Var_Blend_Coordinates( FT_Face face, 575 FT_UInt num_coords, 576 FT_Fixed* coords ) 577 { 578 FT_Error error; 579 FT_Service_MultiMasters service; 580 581 582 /* check of `face' delayed to `ft_face_get_mm_service' */ 583 584 if ( !coords ) 585 return FT_THROW( Invalid_Argument ); 586 587 error = ft_face_get_mm_service( face, &service ); 588 if ( !error ) 589 { 590 error = FT_ERR( Invalid_Argument ); 591 if ( service->get_mm_blend ) 592 error = service->get_mm_blend( face, num_coords, coords ); 593 } 594 595 return error; 596 } 597 598 599 /* documentation is in ftmm.h */ 600 601 FT_EXPORT_DEF( FT_Error ) 602 FT_Get_Var_Axis_Flags( FT_MM_Var* master, 603 FT_UInt axis_index, 604 FT_UInt* flags ) 605 { 606 FT_UShort* axis_flags; 607 608 609 if ( !master || !flags ) 610 return FT_THROW( Invalid_Argument ); 611 612 if ( axis_index >= master->num_axis ) 613 return FT_THROW( Invalid_Argument ); 614 615 /* the axis flags array immediately follows the data of `master' */ 616 axis_flags = (FT_UShort*)&( master[1] ); 617 *flags = axis_flags[axis_index]; 618 619 return FT_Err_Ok; 620 } 621 622 623 /* documentation is in ftmm.h */ 624 625 FT_EXPORT_DEF( FT_Error ) 626 FT_Set_Named_Instance( FT_Face face, 627 FT_UInt instance_index ) 628 { 629 FT_Error error; 630 631 FT_Service_MultiMasters service_mm = NULL; 632 FT_Service_MetricsVariations service_mvar = NULL; 633 634 635 /* check of `face' delayed to `ft_face_get_mm_service' */ 636 637 error = ft_face_get_mm_service( face, &service_mm ); 638 if ( !error ) 639 { 640 error = FT_ERR( Invalid_Argument ); 641 if ( service_mm->set_named_instance ) 642 error = service_mm->set_named_instance( face, instance_index ); 643 644 if ( !error || error == -1 ) 645 { 646 FT_Bool is_variation_old = FT_IS_VARIATION( face ); 647 648 649 face->face_flags &= ~FT_FACE_FLAG_VARIATION; 650 face->face_index = ( instance_index << 16 ) | 651 ( face->face_index & 0xFFFFL ); 652 653 if ( service_mm->construct_ps_name ) 654 { 655 if ( error == -1 ) 656 { 657 /* The PS name of a named instance and a non-named instance */ 658 /* usually differs, even if the axis values are identical. */ 659 if ( is_variation_old != FT_IS_VARIATION( face ) ) 660 service_mm->construct_ps_name( face ); 661 } 662 else 663 service_mm->construct_ps_name( face ); 664 } 665 } 666 667 /* internal error code -1 means `no change'; we can exit immediately */ 668 if ( error == -1 ) 669 return FT_Err_Ok; 670 } 671 672 if ( !error ) 673 { 674 (void)ft_face_get_mvar_service( face, &service_mvar ); 675 676 if ( service_mvar && service_mvar->metrics_adjust ) 677 service_mvar->metrics_adjust( face ); 678 } 679 680 /* enforce recomputation of auto-hinting data */ 681 if ( !error && face->autohint.finalizer ) 682 { 683 face->autohint.finalizer( face->autohint.data ); 684 face->autohint.data = NULL; 685 } 686 687 return error; 688 } 689 690 691 /* documentation is in ftmm.h */ 692 693 FT_EXPORT_DEF( FT_Error ) 694 FT_Get_Default_Named_Instance( FT_Face face, 695 FT_UInt *instance_index ) 696 { 697 FT_Error error; 698 699 FT_Service_MultiMasters service_mm = NULL; 700 701 702 /* check of `face' delayed to `ft_face_get_mm_service' */ 703 704 error = ft_face_get_mm_service( face, &service_mm ); 705 if ( !error ) 706 { 707 /* no error if `get_default_named_instance` is not available */ 708 if ( service_mm->get_default_named_instance ) 709 error = service_mm->get_default_named_instance( face, 710 instance_index ); 711 else 712 error = FT_Err_Ok; 713 } 714 715 return error; 716 } 717 718 719 /* END */