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