1 /***************************************************************************/ 2 /* */ 3 /* afmodule.c */ 4 /* */ 5 /* Auto-fitter module implementation (body). */ 6 /* */ 7 /* Copyright 2003-2017 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 "afglobal.h" 20 #include "afmodule.h" 21 #include "afloader.h" 22 #include "aferrors.h" 23 #include "afpic.h" 24 25 #ifdef FT_DEBUG_AUTOFIT 26 27 #ifndef FT_MAKE_OPTION_SINGLE_OBJECT 28 29 #ifdef __cplusplus 30 extern "C" { 31 #endif 32 extern void 33 af_glyph_hints_dump_segments( AF_GlyphHints hints, 34 FT_Bool to_stdout ); 35 extern void 36 af_glyph_hints_dump_points( AF_GlyphHints hints, 37 FT_Bool to_stdout ); 38 extern void 39 af_glyph_hints_dump_edges( AF_GlyphHints hints, 40 FT_Bool to_stdout ); 41 #ifdef __cplusplus 42 } 43 #endif 44 45 #endif 46 47 int _af_debug_disable_horz_hints; 48 int _af_debug_disable_vert_hints; 49 int _af_debug_disable_blue_hints; 50 51 /* we use a global object instead of a local one for debugging */ 52 AF_GlyphHintsRec _af_debug_hints_rec[1]; 53 54 void* _af_debug_hints = _af_debug_hints_rec; 55 #endif 56 57 #include FT_INTERNAL_OBJECTS_H 58 #include FT_INTERNAL_DEBUG_H 59 #include FT_AUTOHINTER_H 60 #include FT_SERVICE_PROPERTIES_H 61 62 63 /*************************************************************************/ 64 /* */ 65 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 66 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 67 /* messages during execution. */ 68 /* */ 69 #undef FT_COMPONENT 70 #define FT_COMPONENT trace_afmodule 71 72 73 static FT_Error af_property_get_face_globals(FT_Face face,AF_FaceGlobals * aglobals,AF_Module module)74 af_property_get_face_globals( FT_Face face, 75 AF_FaceGlobals* aglobals, 76 AF_Module module ) 77 { 78 FT_Error error = FT_Err_Ok; 79 AF_FaceGlobals globals; 80 81 82 if ( !face ) 83 return FT_THROW( Invalid_Face_Handle ); 84 85 globals = (AF_FaceGlobals)face->autohint.data; 86 if ( !globals ) 87 { 88 /* trigger computation of the global style data */ 89 /* in case it hasn't been done yet */ 90 error = af_face_globals_new( face, &globals, module ); 91 if ( !error ) 92 { 93 face->autohint.data = 94 (FT_Pointer)globals; 95 face->autohint.finalizer = 96 (FT_Generic_Finalizer)af_face_globals_free; 97 } 98 } 99 100 if ( !error ) 101 *aglobals = globals; 102 103 return error; 104 } 105 106 107 #ifdef FT_CONFIG_OPTION_PIC 108 109 #undef AF_SCRIPT_CLASSES_GET 110 #define AF_SCRIPT_CLASSES_GET \ 111 ( GET_PIC( ft_module->library )->af_script_classes ) 112 113 #undef AF_STYLE_CLASSES_GET 114 #define AF_STYLE_CLASSES_GET \ 115 ( GET_PIC( ft_module->library )->af_style_classes ) 116 117 #endif 118 119 120 static FT_Error af_property_set(FT_Module ft_module,const char * property_name,const void * value,FT_Bool value_is_string)121 af_property_set( FT_Module ft_module, 122 const char* property_name, 123 const void* value, 124 FT_Bool value_is_string ) 125 { 126 FT_Error error = FT_Err_Ok; 127 AF_Module module = (AF_Module)ft_module; 128 129 #ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES 130 FT_UNUSED( value_is_string ); 131 #endif 132 133 134 if ( !ft_strcmp( property_name, "fallback-script" ) ) 135 { 136 FT_UInt* fallback_script; 137 FT_UInt ss; 138 139 140 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES 141 if ( value_is_string ) 142 return FT_THROW( Invalid_Argument ); 143 #endif 144 145 fallback_script = (FT_UInt*)value; 146 147 /* We translate the fallback script to a fallback style that uses */ 148 /* `fallback-script' as its script and `AF_COVERAGE_NONE' as its */ 149 /* coverage value. */ 150 for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ ) 151 { 152 AF_StyleClass style_class = AF_STYLE_CLASSES_GET[ss]; 153 154 155 if ( (FT_UInt)style_class->script == *fallback_script && 156 style_class->coverage == AF_COVERAGE_DEFAULT ) 157 { 158 module->fallback_style = ss; 159 break; 160 } 161 } 162 163 if ( !AF_STYLE_CLASSES_GET[ss] ) 164 { 165 FT_TRACE0(( "af_property_set: Invalid value %d for property `%s'\n", 166 fallback_script, property_name )); 167 return FT_THROW( Invalid_Argument ); 168 } 169 170 return error; 171 } 172 else if ( !ft_strcmp( property_name, "default-script" ) ) 173 { 174 FT_UInt* default_script; 175 176 177 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES 178 if ( value_is_string ) 179 return FT_THROW( Invalid_Argument ); 180 #endif 181 182 default_script = (FT_UInt*)value; 183 184 module->default_script = *default_script; 185 186 return error; 187 } 188 else if ( !ft_strcmp( property_name, "increase-x-height" ) ) 189 { 190 FT_Prop_IncreaseXHeight* prop; 191 AF_FaceGlobals globals; 192 193 194 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES 195 if ( value_is_string ) 196 return FT_THROW( Invalid_Argument ); 197 #endif 198 199 prop = (FT_Prop_IncreaseXHeight*)value; 200 201 error = af_property_get_face_globals( prop->face, &globals, module ); 202 if ( !error ) 203 globals->increase_x_height = prop->limit; 204 205 return error; 206 } 207 #ifdef AF_CONFIG_OPTION_USE_WARPER 208 else if ( !ft_strcmp( property_name, "warping" ) ) 209 { 210 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES 211 if ( value_is_string ) 212 { 213 const char* s = (const char*)value; 214 long w = ft_strtol( s, NULL, 10 ); 215 216 217 if ( w == 0 ) 218 module->warping = 0; 219 else if ( w == 1 ) 220 module->warping = 1; 221 else 222 return FT_THROW( Invalid_Argument ); 223 } 224 else 225 #endif 226 { 227 FT_Bool* warping = (FT_Bool*)value; 228 229 230 module->warping = *warping; 231 } 232 233 return error; 234 } 235 #endif /* AF_CONFIG_OPTION_USE_WARPER */ 236 else if ( !ft_strcmp( property_name, "darkening-parameters" ) ) 237 { 238 FT_Int* darken_params; 239 FT_Int x1, y1, x2, y2, x3, y3, x4, y4; 240 241 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES 242 FT_Int dp[8]; 243 244 245 if ( value_is_string ) 246 { 247 const char* s = (const char*)value; 248 char* ep; 249 int i; 250 251 252 /* eight comma-separated numbers */ 253 for ( i = 0; i < 7; i++ ) 254 { 255 dp[i] = (FT_Int)ft_strtol( s, &ep, 10 ); 256 if ( *ep != ',' || s == ep ) 257 return FT_THROW( Invalid_Argument ); 258 259 s = ep + 1; 260 } 261 262 dp[7] = (FT_Int)ft_strtol( s, &ep, 10 ); 263 if ( !( *ep == '\0' || *ep == ' ' ) || s == ep ) 264 return FT_THROW( Invalid_Argument ); 265 266 darken_params = dp; 267 } 268 else 269 #endif 270 darken_params = (FT_Int*)value; 271 272 x1 = darken_params[0]; 273 y1 = darken_params[1]; 274 x2 = darken_params[2]; 275 y2 = darken_params[3]; 276 x3 = darken_params[4]; 277 y3 = darken_params[5]; 278 x4 = darken_params[6]; 279 y4 = darken_params[7]; 280 281 if ( x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || 282 y1 < 0 || y2 < 0 || y3 < 0 || y4 < 0 || 283 x1 > x2 || x2 > x3 || x3 > x4 || 284 y1 > 500 || y2 > 500 || y3 > 500 || y4 > 500 ) 285 return FT_THROW( Invalid_Argument ); 286 287 module->darken_params[0] = x1; 288 module->darken_params[1] = y1; 289 module->darken_params[2] = x2; 290 module->darken_params[3] = y2; 291 module->darken_params[4] = x3; 292 module->darken_params[5] = y3; 293 module->darken_params[6] = x4; 294 module->darken_params[7] = y4; 295 296 return error; 297 } 298 else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) 299 { 300 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES 301 if ( value_is_string ) 302 { 303 const char* s = (const char*)value; 304 long nsd = ft_strtol( s, NULL, 10 ); 305 306 307 if ( nsd == 0 ) 308 module->no_stem_darkening = 0; 309 else if ( nsd == 1 ) 310 module->no_stem_darkening = 1; 311 else 312 return FT_THROW( Invalid_Argument ); 313 } 314 else 315 #endif 316 { 317 FT_Bool* no_stem_darkening = (FT_Bool*)value; 318 319 320 module->no_stem_darkening = *no_stem_darkening; 321 } 322 323 return error; 324 } 325 326 FT_TRACE0(( "af_property_set: missing property `%s'\n", 327 property_name )); 328 return FT_THROW( Missing_Property ); 329 } 330 331 332 static FT_Error af_property_get(FT_Module ft_module,const char * property_name,void * value)333 af_property_get( FT_Module ft_module, 334 const char* property_name, 335 void* value ) 336 { 337 FT_Error error = FT_Err_Ok; 338 AF_Module module = (AF_Module)ft_module; 339 FT_UInt fallback_style = module->fallback_style; 340 FT_UInt default_script = module->default_script; 341 #ifdef AF_CONFIG_OPTION_USE_WARPER 342 FT_Bool warping = module->warping; 343 #endif 344 345 346 if ( !ft_strcmp( property_name, "glyph-to-script-map" ) ) 347 { 348 FT_Prop_GlyphToScriptMap* prop = (FT_Prop_GlyphToScriptMap*)value; 349 AF_FaceGlobals globals; 350 351 352 error = af_property_get_face_globals( prop->face, &globals, module ); 353 if ( !error ) 354 prop->map = globals->glyph_styles; 355 356 return error; 357 } 358 else if ( !ft_strcmp( property_name, "fallback-script" ) ) 359 { 360 FT_UInt* val = (FT_UInt*)value; 361 362 AF_StyleClass style_class = AF_STYLE_CLASSES_GET[fallback_style]; 363 364 365 *val = style_class->script; 366 367 return error; 368 } 369 else if ( !ft_strcmp( property_name, "default-script" ) ) 370 { 371 FT_UInt* val = (FT_UInt*)value; 372 373 374 *val = default_script; 375 376 return error; 377 } 378 else if ( !ft_strcmp( property_name, "increase-x-height" ) ) 379 { 380 FT_Prop_IncreaseXHeight* prop = (FT_Prop_IncreaseXHeight*)value; 381 AF_FaceGlobals globals; 382 383 384 error = af_property_get_face_globals( prop->face, &globals, module ); 385 if ( !error ) 386 prop->limit = globals->increase_x_height; 387 388 return error; 389 } 390 #ifdef AF_CONFIG_OPTION_USE_WARPER 391 else if ( !ft_strcmp( property_name, "warping" ) ) 392 { 393 FT_Bool* val = (FT_Bool*)value; 394 395 396 *val = warping; 397 398 return error; 399 } 400 #endif /* AF_CONFIG_OPTION_USE_WARPER */ 401 else if ( !ft_strcmp( property_name, "darkening-parameters" ) ) 402 { 403 FT_Int* darken_params = module->darken_params; 404 FT_Int* val = (FT_Int*)value; 405 406 407 val[0] = darken_params[0]; 408 val[1] = darken_params[1]; 409 val[2] = darken_params[2]; 410 val[3] = darken_params[3]; 411 val[4] = darken_params[4]; 412 val[5] = darken_params[5]; 413 val[6] = darken_params[6]; 414 val[7] = darken_params[7]; 415 416 return error; 417 } 418 else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) 419 { 420 FT_Bool no_stem_darkening = module->no_stem_darkening; 421 FT_Bool* val = (FT_Bool*)value; 422 423 424 *val = no_stem_darkening; 425 426 return error; 427 } 428 429 FT_TRACE0(( "af_property_get: missing property `%s'\n", 430 property_name )); 431 return FT_THROW( Missing_Property ); 432 } 433 434 435 FT_DEFINE_SERVICE_PROPERTIESREC( 436 af_service_properties, 437 438 (FT_Properties_SetFunc)af_property_set, /* set_property */ 439 (FT_Properties_GetFunc)af_property_get ) /* get_property */ 440 441 442 FT_DEFINE_SERVICEDESCREC1( 443 af_services, 444 445 FT_SERVICE_ID_PROPERTIES, &AF_SERVICE_PROPERTIES_GET ) 446 447 FT_CALLBACK_DEF(FT_Module_Interface)448 FT_CALLBACK_DEF( FT_Module_Interface ) 449 af_get_interface( FT_Module module, 450 const char* module_interface ) 451 { 452 /* AF_SERVICES_GET dereferences `library' in PIC mode */ 453 #ifdef FT_CONFIG_OPTION_PIC 454 FT_Library library; 455 456 457 if ( !module ) 458 return NULL; 459 library = module->library; 460 if ( !library ) 461 return NULL; 462 #else 463 FT_UNUSED( module ); 464 #endif 465 466 return ft_service_list_lookup( AF_SERVICES_GET, module_interface ); 467 } 468 469 470 FT_CALLBACK_DEF( FT_Error ) af_autofitter_init(FT_Module ft_module)471 af_autofitter_init( FT_Module ft_module ) /* AF_Module */ 472 { 473 AF_Module module = (AF_Module)ft_module; 474 475 476 module->fallback_style = AF_STYLE_FALLBACK; 477 module->default_script = AF_SCRIPT_DEFAULT; 478 #ifdef AF_CONFIG_OPTION_USE_WARPER 479 module->warping = 0; 480 #endif 481 module->no_stem_darkening = TRUE; 482 483 module->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; 484 module->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; 485 module->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2; 486 module->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2; 487 module->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3; 488 module->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3; 489 module->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; 490 module->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; 491 492 return FT_Err_Ok; 493 } 494 495 496 FT_CALLBACK_DEF( void ) af_autofitter_done(FT_Module ft_module)497 af_autofitter_done( FT_Module ft_module ) /* AF_Module */ 498 { 499 FT_UNUSED( ft_module ); 500 501 #ifdef FT_DEBUG_AUTOFIT 502 if ( _af_debug_hints_rec->memory ) 503 af_glyph_hints_done( _af_debug_hints_rec ); 504 #endif 505 } 506 507 508 FT_CALLBACK_DEF( FT_Error ) af_autofitter_load_glyph(AF_Module module,FT_GlyphSlot slot,FT_Size size,FT_UInt glyph_index,FT_Int32 load_flags)509 af_autofitter_load_glyph( AF_Module module, 510 FT_GlyphSlot slot, 511 FT_Size size, 512 FT_UInt glyph_index, 513 FT_Int32 load_flags ) 514 { 515 FT_Error error = FT_Err_Ok; 516 FT_Memory memory = module->root.library->memory; 517 518 #ifdef FT_DEBUG_AUTOFIT 519 520 /* in debug mode, we use a global object that survives this routine */ 521 522 AF_GlyphHints hints = _af_debug_hints_rec; 523 AF_LoaderRec loader[1]; 524 525 FT_UNUSED( size ); 526 527 528 if ( hints->memory ) 529 af_glyph_hints_done( hints ); 530 531 af_glyph_hints_init( hints, memory ); 532 af_loader_init( loader, hints ); 533 534 error = af_loader_load_glyph( loader, module, slot->face, 535 glyph_index, load_flags ); 536 537 #ifdef FT_DEBUG_LEVEL_TRACE 538 if ( ft_trace_levels[FT_COMPONENT] ) 539 { 540 #endif 541 af_glyph_hints_dump_points( hints, 0 ); 542 af_glyph_hints_dump_segments( hints, 0 ); 543 af_glyph_hints_dump_edges( hints, 0 ); 544 #ifdef FT_DEBUG_LEVEL_TRACE 545 } 546 #endif 547 548 af_loader_done( loader ); 549 550 return error; 551 552 #else /* !FT_DEBUG_AUTOFIT */ 553 554 AF_GlyphHintsRec hints[1]; 555 AF_LoaderRec loader[1]; 556 557 FT_UNUSED( size ); 558 559 560 af_glyph_hints_init( hints, memory ); 561 af_loader_init( loader, hints ); 562 563 error = af_loader_load_glyph( loader, module, slot->face, 564 glyph_index, load_flags ); 565 566 af_loader_done( loader ); 567 af_glyph_hints_done( hints ); 568 569 return error; 570 571 #endif /* !FT_DEBUG_AUTOFIT */ 572 } 573 574 575 FT_DEFINE_AUTOHINTER_INTERFACE( 576 af_autofitter_interface, 577 578 NULL, /* reset_face */ 579 NULL, /* get_global_hints */ 580 NULL, /* done_global_hints */ 581 (FT_AutoHinter_GlyphLoadFunc)af_autofitter_load_glyph ) /* load_glyph */ 582 583 584 FT_DEFINE_MODULE( 585 autofit_module_class, 586 587 FT_MODULE_HINTER, 588 sizeof ( AF_ModuleRec ), 589 590 "autofitter", 591 0x10000L, /* version 1.0 of the autofitter */ 592 0x20000L, /* requires FreeType 2.0 or above */ 593 594 (const void*)&AF_INTERFACE_GET, 595 596 (FT_Module_Constructor)af_autofitter_init, /* module_init */ 597 (FT_Module_Destructor) af_autofitter_done, /* module_done */ 598 (FT_Module_Requester) af_get_interface /* get_interface */ 599 ) 600 601 602 /* END */ 603