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