1 /**************************************************************************** 2 * 3 * afmodule.c 4 * 5 * Auto-fitter module implementation (body). 6 * 7 * Copyright (C) 2003-2023 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 static 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 AF_Script* 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 = (AF_Script*)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 ( 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_TRACE2(( "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 AF_Script* 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 = (AF_Script*)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 else if ( !ft_strcmp( property_name, "darkening-parameters" ) ) 194 { 195 FT_Int* darken_params; 196 FT_Int x1, y1, x2, y2, x3, y3, x4, y4; 197 198 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES 199 FT_Int dp[8]; 200 201 202 if ( value_is_string ) 203 { 204 const char* s = (const char*)value; 205 char* ep; 206 int i; 207 208 209 /* eight comma-separated numbers */ 210 for ( i = 0; i < 7; i++ ) 211 { 212 dp[i] = (FT_Int)ft_strtol( s, &ep, 10 ); 213 if ( *ep != ',' || s == ep ) 214 return FT_THROW( Invalid_Argument ); 215 216 s = ep + 1; 217 } 218 219 dp[7] = (FT_Int)ft_strtol( s, &ep, 10 ); 220 if ( !( *ep == '\0' || *ep == ' ' ) || s == ep ) 221 return FT_THROW( Invalid_Argument ); 222 223 darken_params = dp; 224 } 225 else 226 #endif 227 darken_params = (FT_Int*)value; 228 229 x1 = darken_params[0]; 230 y1 = darken_params[1]; 231 x2 = darken_params[2]; 232 y2 = darken_params[3]; 233 x3 = darken_params[4]; 234 y3 = darken_params[5]; 235 x4 = darken_params[6]; 236 y4 = darken_params[7]; 237 238 if ( x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || 239 y1 < 0 || y2 < 0 || y3 < 0 || y4 < 0 || 240 x1 > x2 || x2 > x3 || x3 > x4 || 241 y1 > 500 || y2 > 500 || y3 > 500 || y4 > 500 ) 242 return FT_THROW( Invalid_Argument ); 243 244 module->darken_params[0] = x1; 245 module->darken_params[1] = y1; 246 module->darken_params[2] = x2; 247 module->darken_params[3] = y2; 248 module->darken_params[4] = x3; 249 module->darken_params[5] = y3; 250 module->darken_params[6] = x4; 251 module->darken_params[7] = y4; 252 253 return error; 254 } 255 else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) 256 { 257 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES 258 if ( value_is_string ) 259 { 260 const char* s = (const char*)value; 261 long nsd = ft_strtol( s, NULL, 10 ); 262 263 264 if ( !nsd ) 265 module->no_stem_darkening = FALSE; 266 else 267 module->no_stem_darkening = TRUE; 268 } 269 else 270 #endif 271 { 272 FT_Bool* no_stem_darkening = (FT_Bool*)value; 273 274 275 module->no_stem_darkening = *no_stem_darkening; 276 } 277 278 return error; 279 } 280 281 FT_TRACE2(( "af_property_set: missing property `%s'\n", 282 property_name )); 283 return FT_THROW( Missing_Property ); 284 } 285 286 287 static FT_Error af_property_get(FT_Module ft_module,const char * property_name,void * value)288 af_property_get( FT_Module ft_module, 289 const char* property_name, 290 void* value ) 291 { 292 FT_Error error = FT_Err_Ok; 293 AF_Module module = (AF_Module)ft_module; 294 295 296 if ( !ft_strcmp( property_name, "glyph-to-script-map" ) ) 297 { 298 FT_Prop_GlyphToScriptMap* prop = (FT_Prop_GlyphToScriptMap*)value; 299 AF_FaceGlobals globals; 300 301 302 error = af_property_get_face_globals( prop->face, &globals, module ); 303 if ( !error ) 304 prop->map = globals->glyph_styles; 305 306 return error; 307 } 308 else if ( !ft_strcmp( property_name, "fallback-script" ) ) 309 { 310 AF_Script* val = (AF_Script*)value; 311 312 AF_StyleClass style_class = af_style_classes[module->fallback_style]; 313 314 315 *val = style_class->script; 316 317 return error; 318 } 319 else if ( !ft_strcmp( property_name, "default-script" ) ) 320 { 321 AF_Script* val = (AF_Script*)value; 322 323 324 *val = module->default_script; 325 326 return error; 327 } 328 else if ( !ft_strcmp( property_name, "increase-x-height" ) ) 329 { 330 FT_Prop_IncreaseXHeight* prop = (FT_Prop_IncreaseXHeight*)value; 331 AF_FaceGlobals globals; 332 333 334 error = af_property_get_face_globals( prop->face, &globals, module ); 335 if ( !error ) 336 prop->limit = globals->increase_x_height; 337 338 return error; 339 } 340 else if ( !ft_strcmp( property_name, "darkening-parameters" ) ) 341 { 342 FT_Int* darken_params = module->darken_params; 343 FT_Int* val = (FT_Int*)value; 344 345 346 val[0] = darken_params[0]; 347 val[1] = darken_params[1]; 348 val[2] = darken_params[2]; 349 val[3] = darken_params[3]; 350 val[4] = darken_params[4]; 351 val[5] = darken_params[5]; 352 val[6] = darken_params[6]; 353 val[7] = darken_params[7]; 354 355 return error; 356 } 357 else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) 358 { 359 FT_Bool no_stem_darkening = module->no_stem_darkening; 360 FT_Bool* val = (FT_Bool*)value; 361 362 363 *val = no_stem_darkening; 364 365 return error; 366 } 367 368 FT_TRACE2(( "af_property_get: missing property `%s'\n", 369 property_name )); 370 return FT_THROW( Missing_Property ); 371 } 372 373 374 FT_DEFINE_SERVICE_PROPERTIESREC( 375 af_service_properties, 376 377 (FT_Properties_SetFunc)af_property_set, /* set_property */ 378 (FT_Properties_GetFunc)af_property_get ) /* get_property */ 379 380 381 FT_DEFINE_SERVICEDESCREC1( 382 af_services, 383 384 FT_SERVICE_ID_PROPERTIES, &af_service_properties ) 385 386 FT_CALLBACK_DEF(FT_Module_Interface)387 FT_CALLBACK_DEF( FT_Module_Interface ) 388 af_get_interface( FT_Module module, 389 const char* module_interface ) 390 { 391 FT_UNUSED( module ); 392 393 return ft_service_list_lookup( af_services, module_interface ); 394 } 395 396 397 FT_CALLBACK_DEF( FT_Error ) af_autofitter_init(FT_Module ft_module)398 af_autofitter_init( FT_Module ft_module ) /* AF_Module */ 399 { 400 AF_Module module = (AF_Module)ft_module; 401 402 403 module->fallback_style = AF_STYLE_FALLBACK; 404 module->default_script = AF_SCRIPT_DEFAULT; 405 module->no_stem_darkening = TRUE; 406 407 module->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; 408 module->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; 409 module->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2; 410 module->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2; 411 module->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3; 412 module->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3; 413 module->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; 414 module->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; 415 416 return FT_Err_Ok; 417 } 418 419 420 FT_CALLBACK_DEF( void ) af_autofitter_done(FT_Module ft_module)421 af_autofitter_done( FT_Module ft_module ) /* AF_Module */ 422 { 423 FT_UNUSED( ft_module ); 424 425 #ifdef FT_DEBUG_AUTOFIT 426 if ( af_debug_hints_rec_->memory ) 427 af_glyph_hints_done( af_debug_hints_rec_ ); 428 #endif 429 } 430 431 432 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)433 af_autofitter_load_glyph( AF_Module module, 434 FT_GlyphSlot slot, 435 FT_Size size, 436 FT_UInt glyph_index, 437 FT_Int32 load_flags ) 438 { 439 FT_Error error = FT_Err_Ok; 440 FT_Memory memory = module->root.library->memory; 441 442 #ifdef FT_DEBUG_AUTOFIT 443 444 /* in debug mode, we use a global object that survives this routine */ 445 446 AF_GlyphHints hints = af_debug_hints_rec_; 447 AF_LoaderRec loader[1]; 448 449 FT_UNUSED( size ); 450 451 452 if ( hints->memory ) 453 af_glyph_hints_done( hints ); 454 455 af_glyph_hints_init( hints, memory ); 456 af_loader_init( loader, hints ); 457 458 error = af_loader_load_glyph( loader, module, slot->face, 459 glyph_index, load_flags ); 460 461 #ifdef FT_DEBUG_LEVEL_TRACE 462 if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] ) 463 { 464 #endif 465 af_glyph_hints_dump_points( hints, 0 ); 466 af_glyph_hints_dump_segments( hints, 0 ); 467 af_glyph_hints_dump_edges( hints, 0 ); 468 #ifdef FT_DEBUG_LEVEL_TRACE 469 } 470 #endif 471 472 af_loader_done( loader ); 473 474 return error; 475 476 #else /* !FT_DEBUG_AUTOFIT */ 477 478 AF_GlyphHintsRec hints[1]; 479 AF_LoaderRec loader[1]; 480 481 FT_UNUSED( size ); 482 483 484 af_glyph_hints_init( hints, memory ); 485 af_loader_init( loader, hints ); 486 487 error = af_loader_load_glyph( loader, module, slot->face, 488 glyph_index, load_flags ); 489 490 af_loader_done( loader ); 491 af_glyph_hints_done( hints ); 492 493 return error; 494 495 #endif /* !FT_DEBUG_AUTOFIT */ 496 } 497 498 499 FT_DEFINE_AUTOHINTER_INTERFACE( 500 af_autofitter_interface, 501 502 NULL, /* reset_face */ 503 NULL, /* get_global_hints */ 504 NULL, /* done_global_hints */ 505 (FT_AutoHinter_GlyphLoadFunc)af_autofitter_load_glyph /* load_glyph */ 506 ) 507 508 FT_DEFINE_MODULE( 509 autofit_module_class, 510 511 FT_MODULE_HINTER, 512 sizeof ( AF_ModuleRec ), 513 514 "autofitter", 515 0x10000L, /* version 1.0 of the autofitter */ 516 0x20000L, /* requires FreeType 2.0 or above */ 517 518 (const void*)&af_autofitter_interface, 519 520 (FT_Module_Constructor)af_autofitter_init, /* module_init */ 521 (FT_Module_Destructor) af_autofitter_done, /* module_done */ 522 (FT_Module_Requester) af_get_interface /* get_interface */ 523 ) 524 525 526 /* END */ 527