1 /***************************************************************************/
2 /*                                                                         */
3 /*  afglobal.c                                                             */
4 /*                                                                         */
5 /*    Auto-fitter routines to compute global hinting values (body).        */
6 /*                                                                         */
7 /*  Copyright 2003-2017 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 "afranges.h"
21 #include "afshaper.h"
22 #include FT_INTERNAL_DEBUG_H
23 
24 
25   /*************************************************************************/
26   /*                                                                       */
27   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
28   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
29   /* messages during execution.                                            */
30   /*                                                                       */
31 #undef  FT_COMPONENT
32 #define FT_COMPONENT  trace_afglobal
33 
34 
35   /* get writing system specific header files */
36 #undef  WRITING_SYSTEM
37 #define WRITING_SYSTEM( ws, WS )  /* empty */
38 #include "afwrtsys.h"
39 
40 #include "aferrors.h"
41 #include "afpic.h"
42 
43 
44 #undef  SCRIPT
45 #define SCRIPT( s, S, d, h, H, ss )         \
46           AF_DEFINE_SCRIPT_CLASS(           \
47             af_ ## s ## _script_class,      \
48             AF_SCRIPT_ ## S,                \
49             af_ ## s ## _uniranges,         \
50             af_ ## s ## _nonbase_uniranges, \
51             AF_ ## H,                       \
52             ss )
53 
54 #include "afscript.h"
55 
56 
57 #undef  STYLE
58 #define STYLE( s, S, d, ws, sc, ss, c )  \
59           AF_DEFINE_STYLE_CLASS(         \
60             af_ ## s ## _style_class,    \
61             AF_STYLE_ ## S,              \
62             ws,                          \
63             sc,                          \
64             ss,                          \
65             c )
66 
67 #include "afstyles.h"
68 
69 
70 #ifndef FT_CONFIG_OPTION_PIC
71 
72 #undef  WRITING_SYSTEM
73 #define WRITING_SYSTEM( ws, WS )               \
74           &af_ ## ws ## _writing_system_class,
75 
76   FT_LOCAL_ARRAY_DEF( AF_WritingSystemClass )
77   af_writing_system_classes[] =
78   {
79 
80 #include "afwrtsys.h"
81 
82     NULL  /* do not remove */
83   };
84 
85 
86 #undef  SCRIPT
87 #define SCRIPT( s, S, d, h, H, ss )   \
88           &af_ ## s ## _script_class,
89 
90   FT_LOCAL_ARRAY_DEF( AF_ScriptClass )
91   af_script_classes[] =
92   {
93 
94 #include "afscript.h"
95 
96     NULL  /* do not remove */
97   };
98 
99 
100 #undef  STYLE
101 #define STYLE( s, S, d, ws, sc, ss, c ) \
102           &af_ ## s ## _style_class,
103 
104   FT_LOCAL_ARRAY_DEF( AF_StyleClass )
105   af_style_classes[] =
106   {
107 
108 #include "afstyles.h"
109 
110     NULL  /* do not remove */
111   };
112 
113 #endif /* !FT_CONFIG_OPTION_PIC */
114 
115 
116 #ifdef FT_DEBUG_LEVEL_TRACE
117 
118 #undef  STYLE
119 #define STYLE( s, S, d, ws, sc, ss, c )  #s,
120 
121   FT_LOCAL_ARRAY_DEF( char* )
122   af_style_names[] =
123   {
124 
125 #include "afstyles.h"
126 
127   };
128 
129 #endif /* FT_DEBUG_LEVEL_TRACE */
130 
131 
132   /* Compute the style index of each glyph within a given face. */
133 
134   static FT_Error
af_face_globals_compute_style_coverage(AF_FaceGlobals globals)135   af_face_globals_compute_style_coverage( AF_FaceGlobals  globals )
136   {
137     FT_Error    error;
138     FT_Face     face        = globals->face;
139     FT_CharMap  old_charmap = face->charmap;
140     FT_UShort*  gstyles     = globals->glyph_styles;
141     FT_UInt     ss;
142     FT_UInt     i;
143     FT_UInt     dflt        = ~0U; /* a non-valid value */
144 
145 
146     /* the value AF_STYLE_UNASSIGNED means `uncovered glyph' */
147     for ( i = 0; i < (FT_UInt)globals->glyph_count; i++ )
148       gstyles[i] = AF_STYLE_UNASSIGNED;
149 
150     error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
151     if ( error )
152     {
153       /*
154        * Ignore this error; we simply use the fallback style.
155        * XXX: Shouldn't we rather disable hinting?
156        */
157       error = FT_Err_Ok;
158       goto Exit;
159     }
160 
161     /* scan each style in a Unicode charmap */
162     for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ )
163     {
164       AF_StyleClass       style_class =
165                             AF_STYLE_CLASSES_GET[ss];
166       AF_ScriptClass      script_class =
167                             AF_SCRIPT_CLASSES_GET[style_class->script];
168       AF_Script_UniRange  range;
169 
170 
171       if ( !script_class->script_uni_ranges )
172         continue;
173 
174       /*
175        *  Scan all Unicode points in the range and set the corresponding
176        *  glyph style index.
177        */
178       if ( style_class->coverage == AF_COVERAGE_DEFAULT )
179       {
180         if ( (FT_UInt)style_class->script ==
181              globals->module->default_script )
182           dflt = ss;
183 
184         for ( range = script_class->script_uni_ranges;
185               range->first != 0;
186               range++ )
187         {
188           FT_ULong  charcode = range->first;
189           FT_UInt   gindex;
190 
191 
192           gindex = FT_Get_Char_Index( face, charcode );
193 
194           if ( gindex != 0                                                &&
195                gindex < (FT_ULong)globals->glyph_count                    &&
196                ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
197             gstyles[gindex] = (FT_UShort)ss;
198 
199           for (;;)
200           {
201             charcode = FT_Get_Next_Char( face, charcode, &gindex );
202 
203             if ( gindex == 0 || charcode > range->last )
204               break;
205 
206             if ( gindex < (FT_ULong)globals->glyph_count                    &&
207                  ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
208               gstyles[gindex] = (FT_UShort)ss;
209           }
210         }
211 
212         /* do the same for the script's non-base characters */
213         for ( range = script_class->script_uni_nonbase_ranges;
214               range->first != 0;
215               range++ )
216         {
217           FT_ULong  charcode = range->first;
218           FT_UInt   gindex;
219 
220 
221           gindex = FT_Get_Char_Index( face, charcode );
222 
223           if ( gindex != 0                                          &&
224                gindex < (FT_ULong)globals->glyph_count              &&
225                ( gstyles[gindex] & AF_STYLE_MASK ) == (FT_UShort)ss )
226             gstyles[gindex] |= AF_NONBASE;
227 
228           for (;;)
229           {
230             charcode = FT_Get_Next_Char( face, charcode, &gindex );
231 
232             if ( gindex == 0 || charcode > range->last )
233               break;
234 
235             if ( gindex < (FT_ULong)globals->glyph_count              &&
236                  ( gstyles[gindex] & AF_STYLE_MASK ) == (FT_UShort)ss )
237               gstyles[gindex] |= AF_NONBASE;
238           }
239         }
240       }
241       else
242       {
243         /* get glyphs not directly addressable by cmap */
244         af_shaper_get_coverage( globals, style_class, gstyles, 0 );
245       }
246     }
247 
248     /* handle the remaining default OpenType features ... */
249     for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ )
250     {
251       AF_StyleClass  style_class = AF_STYLE_CLASSES_GET[ss];
252 
253 
254       if ( style_class->coverage == AF_COVERAGE_DEFAULT )
255         af_shaper_get_coverage( globals, style_class, gstyles, 0 );
256     }
257 
258     /* ... and finally the default OpenType features of the default script */
259     af_shaper_get_coverage( globals, AF_STYLE_CLASSES_GET[dflt], gstyles, 1 );
260 
261     /* mark ASCII digits */
262     for ( i = 0x30; i <= 0x39; i++ )
263     {
264       FT_UInt  gindex = FT_Get_Char_Index( face, i );
265 
266 
267       if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count )
268         gstyles[gindex] |= AF_DIGIT;
269     }
270 
271   Exit:
272     /*
273      *  By default, all uncovered glyphs are set to the fallback style.
274      *  XXX: Shouldn't we disable hinting or do something similar?
275      */
276     if ( globals->module->fallback_style != AF_STYLE_UNASSIGNED )
277     {
278       FT_Long  nn;
279 
280 
281       for ( nn = 0; nn < globals->glyph_count; nn++ )
282       {
283         if ( ( gstyles[nn] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
284         {
285           gstyles[nn] &= ~AF_STYLE_MASK;
286           gstyles[nn] |= globals->module->fallback_style;
287         }
288       }
289     }
290 
291 #ifdef FT_DEBUG_LEVEL_TRACE
292 
293     FT_TRACE4(( "\n"
294                 "style coverage\n"
295                 "==============\n"
296                 "\n" ));
297 
298     for ( ss = 0; AF_STYLE_CLASSES_GET[ss]; ss++ )
299     {
300       AF_StyleClass  style_class = AF_STYLE_CLASSES_GET[ss];
301       FT_UInt        count       = 0;
302       FT_Long        idx;
303 
304 
305       FT_TRACE4(( "%s:\n", af_style_names[style_class->style] ));
306 
307       for ( idx = 0; idx < globals->glyph_count; idx++ )
308       {
309         if ( ( gstyles[idx] & AF_STYLE_MASK ) == style_class->style )
310         {
311           if ( !( count % 10 ) )
312             FT_TRACE4(( " " ));
313 
314           FT_TRACE4(( " %d", idx ));
315           count++;
316 
317           if ( !( count % 10 ) )
318             FT_TRACE4(( "\n" ));
319         }
320       }
321 
322       if ( !count )
323         FT_TRACE4(( "  (none)\n" ));
324       if ( count % 10 )
325         FT_TRACE4(( "\n" ));
326     }
327 
328 #endif /* FT_DEBUG_LEVEL_TRACE */
329 
330     FT_Set_Charmap( face, old_charmap );
331     return error;
332   }
333 
334 
335   FT_LOCAL_DEF( FT_Error )
af_face_globals_new(FT_Face face,AF_FaceGlobals * aglobals,AF_Module module)336   af_face_globals_new( FT_Face          face,
337                        AF_FaceGlobals  *aglobals,
338                        AF_Module        module )
339   {
340     FT_Error        error;
341     FT_Memory       memory;
342     AF_FaceGlobals  globals = NULL;
343 
344 
345     memory = face->memory;
346 
347     /* we allocate an AF_FaceGlobals structure together */
348     /* with the glyph_styles array                      */
349     if ( FT_ALLOC( globals,
350                    sizeof ( *globals ) +
351                      (FT_ULong)face->num_glyphs * sizeof ( FT_UShort ) ) )
352       goto Exit;
353 
354     globals->face                      = face;
355     globals->glyph_count               = face->num_glyphs;
356     /* right after the globals structure come the glyph styles */
357     globals->glyph_styles              = (FT_UShort*)( globals + 1 );
358     globals->module                    = module;
359     globals->stem_darkening_for_ppem   = 0;
360     globals->darken_x                  = 0;
361     globals->darken_y                  = 0;
362     globals->standard_vertical_width   = 0;
363     globals->standard_horizontal_width = 0;
364     globals->scale_down_factor         = 0;
365 
366 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
367     globals->hb_font = hb_ft_font_create( face, NULL );
368     globals->hb_buf  = hb_buffer_create();
369 #endif
370 
371     error = af_face_globals_compute_style_coverage( globals );
372     if ( error )
373     {
374       af_face_globals_free( globals );
375       globals = NULL;
376     }
377     else
378       globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX;
379 
380   Exit:
381     *aglobals = globals;
382     return error;
383   }
384 
385 
386   FT_LOCAL_DEF( void )
af_face_globals_free(AF_FaceGlobals globals)387   af_face_globals_free( AF_FaceGlobals  globals )
388   {
389     if ( globals )
390     {
391       FT_Memory  memory = globals->face->memory;
392       FT_UInt    nn;
393 
394 
395       for ( nn = 0; nn < AF_STYLE_MAX; nn++ )
396       {
397         if ( globals->metrics[nn] )
398         {
399           AF_StyleClass          style_class =
400             AF_STYLE_CLASSES_GET[nn];
401           AF_WritingSystemClass  writing_system_class =
402             AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system];
403 
404 
405           if ( writing_system_class->style_metrics_done )
406             writing_system_class->style_metrics_done( globals->metrics[nn] );
407 
408           FT_FREE( globals->metrics[nn] );
409         }
410       }
411 
412 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
413       hb_font_destroy( globals->hb_font );
414       hb_buffer_destroy( globals->hb_buf );
415 #endif
416 
417       /* no need to free `globals->glyph_styles'; */
418       /* it is part of the `globals' array        */
419       FT_FREE( globals );
420     }
421   }
422 
423 
424   FT_LOCAL_DEF( FT_Error )
af_face_globals_get_metrics(AF_FaceGlobals globals,FT_UInt gindex,FT_UInt options,AF_StyleMetrics * ametrics)425   af_face_globals_get_metrics( AF_FaceGlobals    globals,
426                                FT_UInt           gindex,
427                                FT_UInt           options,
428                                AF_StyleMetrics  *ametrics )
429   {
430     AF_StyleMetrics  metrics = NULL;
431 
432     AF_Style               style = (AF_Style)options;
433     AF_WritingSystemClass  writing_system_class;
434     AF_StyleClass          style_class;
435 
436     FT_Error  error = FT_Err_Ok;
437 
438 
439     if ( gindex >= (FT_ULong)globals->glyph_count )
440     {
441       error = FT_THROW( Invalid_Argument );
442       goto Exit;
443     }
444 
445     /* if we have a forced style (via `options'), use it, */
446     /* otherwise look into `glyph_styles' array           */
447     if ( style == AF_STYLE_NONE_DFLT || style + 1 >= AF_STYLE_MAX )
448       style = (AF_Style)( globals->glyph_styles[gindex] &
449                           AF_STYLE_UNASSIGNED           );
450 
451     style_class          = AF_STYLE_CLASSES_GET[style];
452     writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET
453                              [style_class->writing_system];
454 
455     metrics = globals->metrics[style];
456     if ( !metrics )
457     {
458       /* create the global metrics object if necessary */
459       FT_Memory  memory = globals->face->memory;
460 
461 
462       if ( FT_ALLOC( metrics, writing_system_class->style_metrics_size ) )
463         goto Exit;
464 
465       metrics->style_class = style_class;
466       metrics->globals     = globals;
467 
468       if ( writing_system_class->style_metrics_init )
469       {
470         error = writing_system_class->style_metrics_init( metrics,
471                                                           globals->face );
472         if ( error )
473         {
474           if ( writing_system_class->style_metrics_done )
475             writing_system_class->style_metrics_done( metrics );
476 
477           FT_FREE( metrics );
478           goto Exit;
479         }
480       }
481 
482       globals->metrics[style] = metrics;
483     }
484 
485   Exit:
486     *ametrics = metrics;
487 
488     return error;
489   }
490 
491 
492   FT_LOCAL_DEF( FT_Bool )
af_face_globals_is_digit(AF_FaceGlobals globals,FT_UInt gindex)493   af_face_globals_is_digit( AF_FaceGlobals  globals,
494                             FT_UInt         gindex )
495   {
496     if ( gindex < (FT_ULong)globals->glyph_count )
497       return (FT_Bool)( globals->glyph_styles[gindex] & AF_DIGIT );
498 
499     return (FT_Bool)0;
500   }
501 
502 
503 /* END */
504