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