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