xref: /aosp_15_r20/external/freetype/src/autofit/afmodule.c (revision 63949dbd25bcc50c4e1178497ff9e9574d44fc5a)
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