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 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_Var_Design_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)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 ) FT_Get_Var_Design_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)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 ) FT_Set_MM_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)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 ) FT_Set_Var_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)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 ) FT_Get_MM_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)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 ) FT_Get_Var_Blend_Coordinates(FT_Face face,FT_UInt num_coords,FT_Fixed * coords)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 ) FT_Get_Var_Axis_Flags(FT_MM_Var * master,FT_UInt axis_index,FT_UInt * flags)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 ) FT_Set_Named_Instance(FT_Face face,FT_UInt instance_index)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 */ 509