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