1 /**************************************************************************** 2 * 3 * afmodule.c 4 * 5 * Auto-fitter module implementation (body). 6 * 7 * Copyright (C) 2003-2022 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 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_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 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 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 FT_UInt fallback_style = module->fallback_style; 295 FT_UInt default_script = module->default_script; 296 297 298 if ( !ft_strcmp( property_name, "glyph-to-script-map" ) ) 299 { 300 FT_Prop_GlyphToScriptMap* prop = (FT_Prop_GlyphToScriptMap*)value; 301 AF_FaceGlobals globals; 302 303 304 error = af_property_get_face_globals( prop->face, &globals, module ); 305 if ( !error ) 306 prop->map = globals->glyph_styles; 307 308 return error; 309 } 310 else if ( !ft_strcmp( property_name, "fallback-script" ) ) 311 { 312 FT_UInt* val = (FT_UInt*)value; 313 314 AF_StyleClass style_class = af_style_classes[fallback_style]; 315 316 317 *val = style_class->script; 318 319 return error; 320 } 321 else if ( !ft_strcmp( property_name, "default-script" ) ) 322 { 323 FT_UInt* val = (FT_UInt*)value; 324 325 326 *val = default_script; 327 328 return error; 329 } 330 else if ( !ft_strcmp( property_name, "increase-x-height" ) ) 331 { 332 FT_Prop_IncreaseXHeight* prop = (FT_Prop_IncreaseXHeight*)value; 333 AF_FaceGlobals globals; 334 335 336 error = af_property_get_face_globals( prop->face, &globals, module ); 337 if ( !error ) 338 prop->limit = globals->increase_x_height; 339 340 return error; 341 } 342 else if ( !ft_strcmp( property_name, "darkening-parameters" ) ) 343 { 344 FT_Int* darken_params = module->darken_params; 345 FT_Int* val = (FT_Int*)value; 346 347 348 val[0] = darken_params[0]; 349 val[1] = darken_params[1]; 350 val[2] = darken_params[2]; 351 val[3] = darken_params[3]; 352 val[4] = darken_params[4]; 353 val[5] = darken_params[5]; 354 val[6] = darken_params[6]; 355 val[7] = darken_params[7]; 356 357 return error; 358 } 359 else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) 360 { 361 FT_Bool no_stem_darkening = module->no_stem_darkening; 362 FT_Bool* val = (FT_Bool*)value; 363 364 365 *val = no_stem_darkening; 366 367 return error; 368 } 369 370 FT_TRACE2(( "af_property_get: missing property `%s'\n", 371 property_name )); 372 return FT_THROW( Missing_Property ); 373 } 374 375 376 FT_DEFINE_SERVICE_PROPERTIESREC( 377 af_service_properties, 378 379 (FT_Properties_SetFunc)af_property_set, /* set_property */ 380 (FT_Properties_GetFunc)af_property_get ) /* get_property */ 381 382 383 FT_DEFINE_SERVICEDESCREC1( 384 af_services, 385 386 FT_SERVICE_ID_PROPERTIES, &af_service_properties ) 387 388 FT_CALLBACK_DEF(FT_Module_Interface)389 FT_CALLBACK_DEF( FT_Module_Interface ) 390 af_get_interface( FT_Module module, 391 const char* module_interface ) 392 { 393 FT_UNUSED( module ); 394 395 return ft_service_list_lookup( af_services, module_interface ); 396 } 397 398 399 FT_CALLBACK_DEF( FT_Error ) af_autofitter_init(FT_Module ft_module)400 af_autofitter_init( FT_Module ft_module ) /* AF_Module */ 401 { 402 AF_Module module = (AF_Module)ft_module; 403 404 405 module->fallback_style = AF_STYLE_FALLBACK; 406 module->default_script = AF_SCRIPT_DEFAULT; 407 module->no_stem_darkening = TRUE; 408 409 module->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; 410 module->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; 411 module->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2; 412 module->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2; 413 module->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3; 414 module->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3; 415 module->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; 416 module->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; 417 418 return FT_Err_Ok; 419 } 420 421 422 FT_CALLBACK_DEF( void ) af_autofitter_done(FT_Module ft_module)423 af_autofitter_done( FT_Module ft_module ) /* AF_Module */ 424 { 425 FT_UNUSED( ft_module ); 426 427 #ifdef FT_DEBUG_AUTOFIT 428 if ( _af_debug_hints_rec->memory ) 429 af_glyph_hints_done( _af_debug_hints_rec ); 430 #endif 431 } 432 433 434 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)435 af_autofitter_load_glyph( AF_Module module, 436 FT_GlyphSlot slot, 437 FT_Size size, 438 FT_UInt glyph_index, 439 FT_Int32 load_flags ) 440 { 441 FT_Error error = FT_Err_Ok; 442 FT_Memory memory = module->root.library->memory; 443 444 #ifdef FT_DEBUG_AUTOFIT 445 446 /* in debug mode, we use a global object that survives this routine */ 447 448 AF_GlyphHints hints = _af_debug_hints_rec; 449 AF_LoaderRec loader[1]; 450 451 FT_UNUSED( size ); 452 453 454 if ( hints->memory ) 455 af_glyph_hints_done( hints ); 456 457 af_glyph_hints_init( hints, memory ); 458 af_loader_init( loader, hints ); 459 460 error = af_loader_load_glyph( loader, module, slot->face, 461 glyph_index, load_flags ); 462 463 #ifdef FT_DEBUG_LEVEL_TRACE 464 if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] ) 465 { 466 #endif 467 af_glyph_hints_dump_points( hints, 0 ); 468 af_glyph_hints_dump_segments( hints, 0 ); 469 af_glyph_hints_dump_edges( hints, 0 ); 470 #ifdef FT_DEBUG_LEVEL_TRACE 471 } 472 #endif 473 474 af_loader_done( loader ); 475 476 return error; 477 478 #else /* !FT_DEBUG_AUTOFIT */ 479 480 AF_GlyphHintsRec hints[1]; 481 AF_LoaderRec loader[1]; 482 483 FT_UNUSED( size ); 484 485 486 af_glyph_hints_init( hints, memory ); 487 af_loader_init( loader, hints ); 488 489 error = af_loader_load_glyph( loader, module, slot->face, 490 glyph_index, load_flags ); 491 492 af_loader_done( loader ); 493 af_glyph_hints_done( hints ); 494 495 return error; 496 497 #endif /* !FT_DEBUG_AUTOFIT */ 498 } 499 500 501 FT_DEFINE_AUTOHINTER_INTERFACE( 502 af_autofitter_interface, 503 504 NULL, /* reset_face */ 505 NULL, /* get_global_hints */ 506 NULL, /* done_global_hints */ 507 (FT_AutoHinter_GlyphLoadFunc)af_autofitter_load_glyph /* load_glyph */ 508 ) 509 510 FT_DEFINE_MODULE( 511 autofit_module_class, 512 513 FT_MODULE_HINTER, 514 sizeof ( AF_ModuleRec ), 515 516 "autofitter", 517 0x10000L, /* version 1.0 of the autofitter */ 518 0x20000L, /* requires FreeType 2.0 or above */ 519 520 (const void*)&af_autofitter_interface, 521 522 (FT_Module_Constructor)af_autofitter_init, /* module_init */ 523 (FT_Module_Destructor) af_autofitter_done, /* module_done */ 524 (FT_Module_Requester) af_get_interface /* get_interface */ 525 ) 526 527 528 /* END */ 529