1/***************************************************************************/
2/*                                                                         */
3/*  psmodule.c                                                             */
4/*                                                                         */
5/*    PSNames module implementation (body).                                */
6/*                                                                         */
7/*  Copyright 1996-2003, 2005-2008, 2012, 2013 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 <ft2build.h>
20#include FT_INTERNAL_DEBUG_H
21#include FT_INTERNAL_OBJECTS_H
22#include FT_SERVICE_POSTSCRIPT_CMAPS_H
23
24#include "psmodule.h"
25#include "pstables.h"
26
27#include "psnamerr.h"
28#include "pspic.h"
29
30
31#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
32
33
34#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
35
36
37#define VARIANT_BIT         0x80000000UL
38#define BASE_GLYPH( code )  ( (FT_UInt32)( (code) & ~VARIANT_BIT ) )
39
40
41  /* Return the Unicode value corresponding to a given glyph.  Note that */
42  /* we do deal with glyph variants by detecting a non-initial dot in    */
43  /* the name, as in `A.swash' or `e.final'; in this case, the           */
44  /* VARIANT_BIT is set in the return value.                             */
45  /*                                                                     */
46  static FT_UInt32
47  ps_unicode_value( const char*  glyph_name )
48  {
49    /* If the name begins with `uni', then the glyph name may be a */
50    /* hard-coded unicode character code.                          */
51    if ( glyph_name[0] == 'u' &&
52         glyph_name[1] == 'n' &&
53         glyph_name[2] == 'i' )
54    {
55      /* determine whether the next four characters following are */
56      /* hexadecimal.                                             */
57
58      /* XXX: Add code to deal with ligatures, i.e. glyph names like */
59      /*      `uniXXXXYYYYZZZZ'...                                   */
60
61      FT_Int       count;
62      FT_UInt32    value = 0;
63      const char*  p     = glyph_name + 3;
64
65
66      for ( count = 4; count > 0; count--, p++ )
67      {
68        char          c = *p;
69        unsigned int  d;
70
71
72        d = (unsigned char)c - '0';
73        if ( d >= 10 )
74        {
75          d = (unsigned char)c - 'A';
76          if ( d >= 6 )
77            d = 16;
78          else
79            d += 10;
80        }
81
82        /* Exit if a non-uppercase hexadecimal character was found   */
83        /* -- this also catches character codes below `0' since such */
84        /* negative numbers cast to `unsigned int' are far too big.  */
85        if ( d >= 16 )
86          break;
87
88        value = ( value << 4 ) + d;
89      }
90
91      /* there must be exactly four hex digits */
92      if ( count == 0 )
93      {
94        if ( *p == '\0' )
95          return value;
96        if ( *p == '.' )
97          return (FT_UInt32)( value | VARIANT_BIT );
98      }
99    }
100
101    /* If the name begins with `u', followed by four to six uppercase */
102    /* hexadecimal digits, it is a hard-coded unicode character code. */
103    if ( glyph_name[0] == 'u' )
104    {
105      FT_Int       count;
106      FT_UInt32    value = 0;
107      const char*  p     = glyph_name + 1;
108
109
110      for ( count = 6; count > 0; count--, p++ )
111      {
112        char          c = *p;
113        unsigned int  d;
114
115
116        d = (unsigned char)c - '0';
117        if ( d >= 10 )
118        {
119          d = (unsigned char)c - 'A';
120          if ( d >= 6 )
121            d = 16;
122          else
123            d += 10;
124        }
125
126        if ( d >= 16 )
127          break;
128
129        value = ( value << 4 ) + d;
130      }
131
132      if ( count <= 2 )
133      {
134        if ( *p == '\0' )
135          return value;
136        if ( *p == '.' )
137          return (FT_UInt32)( value | VARIANT_BIT );
138      }
139    }
140
141    /* Look for a non-initial dot in the glyph name in order to */
142    /* find variants like `A.swash', `e.final', etc.            */
143    {
144      const char*  p   = glyph_name;
145      const char*  dot = NULL;
146
147
148      for ( ; *p; p++ )
149      {
150        if ( *p == '.' && p > glyph_name )
151        {
152          dot = p;
153          break;
154        }
155      }
156
157      /* now look up the glyph in the Adobe Glyph List */
158      if ( !dot )
159        return (FT_UInt32)ft_get_adobe_glyph_index( glyph_name, p );
160      else
161        return (FT_UInt32)( ft_get_adobe_glyph_index( glyph_name, dot ) |
162                            VARIANT_BIT );
163    }
164  }
165
166
167  /* ft_qsort callback to sort the unicode map */
168  FT_CALLBACK_DEF( int )
169  compare_uni_maps( const void*  a,
170                    const void*  b )
171  {
172    PS_UniMap*  map1 = (PS_UniMap*)a;
173    PS_UniMap*  map2 = (PS_UniMap*)b;
174    FT_UInt32   unicode1 = BASE_GLYPH( map1->unicode );
175    FT_UInt32   unicode2 = BASE_GLYPH( map2->unicode );
176
177
178    /* sort base glyphs before glyph variants */
179    if ( unicode1 == unicode2 )
180    {
181      if ( map1->unicode > map2->unicode )
182        return 1;
183      else if ( map1->unicode < map2->unicode )
184        return -1;
185      else
186        return 0;
187    }
188    else
189    {
190      if ( unicode1 > unicode2 )
191        return 1;
192      else if ( unicode1 < unicode2 )
193        return -1;
194      else
195        return 0;
196    }
197  }
198
199
200  /* support for extra glyphs not handled (well) in AGL; */
201  /* we add extra mappings for them if necessary         */
202
203#define EXTRA_GLYPH_LIST_SIZE  10
204
205  static const FT_UInt32  ft_extra_glyph_unicodes[EXTRA_GLYPH_LIST_SIZE] =
206  {
207    /* WGL 4 */
208    0x0394,
209    0x03A9,
210    0x2215,
211    0x00AD,
212    0x02C9,
213    0x03BC,
214    0x2219,
215    0x00A0,
216    /* Romanian */
217    0x021A,
218    0x021B
219  };
220
221  static const char  ft_extra_glyph_names[] =
222  {
223    'D','e','l','t','a',0,
224    'O','m','e','g','a',0,
225    'f','r','a','c','t','i','o','n',0,
226    'h','y','p','h','e','n',0,
227    'm','a','c','r','o','n',0,
228    'm','u',0,
229    'p','e','r','i','o','d','c','e','n','t','e','r','e','d',0,
230    's','p','a','c','e',0,
231    'T','c','o','m','m','a','a','c','c','e','n','t',0,
232    't','c','o','m','m','a','a','c','c','e','n','t',0
233  };
234
235  static const FT_Int
236  ft_extra_glyph_name_offsets[EXTRA_GLYPH_LIST_SIZE] =
237  {
238     0,
239     6,
240    12,
241    21,
242    28,
243    35,
244    38,
245    53,
246    59,
247    72
248  };
249
250
251  static void
252  ps_check_extra_glyph_name( const char*  gname,
253                             FT_UInt      glyph,
254                             FT_UInt*     extra_glyphs,
255                             FT_UInt     *states )
256  {
257    FT_UInt  n;
258
259
260    for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ )
261    {
262      if ( ft_strcmp( ft_extra_glyph_names +
263                        ft_extra_glyph_name_offsets[n], gname ) == 0 )
264      {
265        if ( states[n] == 0 )
266        {
267          /* mark this extra glyph as a candidate for the cmap */
268          states[n]     = 1;
269          extra_glyphs[n] = glyph;
270        }
271
272        return;
273      }
274    }
275  }
276
277
278  static void
279  ps_check_extra_glyph_unicode( FT_UInt32  uni_char,
280                                FT_UInt   *states )
281  {
282    FT_UInt  n;
283
284
285    for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ )
286    {
287      if ( uni_char == ft_extra_glyph_unicodes[n] )
288      {
289        /* disable this extra glyph from being added to the cmap */
290        states[n] = 2;
291
292        return;
293      }
294    }
295  }
296
297
298  /* Build a table that maps Unicode values to glyph indices. */
299  static FT_Error
300  ps_unicodes_init( FT_Memory             memory,
301                    PS_Unicodes           table,
302                    FT_UInt               num_glyphs,
303                    PS_GetGlyphNameFunc   get_glyph_name,
304                    PS_FreeGlyphNameFunc  free_glyph_name,
305                    FT_Pointer            glyph_data )
306  {
307    FT_Error  error;
308
309    FT_UInt  extra_glyph_list_states[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
310    FT_UInt  extra_glyphs[EXTRA_GLYPH_LIST_SIZE];
311
312
313    /* we first allocate the table */
314    table->num_maps = 0;
315    table->maps     = 0;
316
317    if ( !FT_NEW_ARRAY( table->maps, num_glyphs + EXTRA_GLYPH_LIST_SIZE ) )
318    {
319      FT_UInt     n;
320      FT_UInt     count;
321      PS_UniMap*  map;
322      FT_UInt32   uni_char;
323
324
325      map = table->maps;
326
327      for ( n = 0; n < num_glyphs; n++ )
328      {
329        const char*  gname = get_glyph_name( glyph_data, n );
330
331
332        if ( gname )
333        {
334          ps_check_extra_glyph_name( gname, n,
335                                     extra_glyphs, extra_glyph_list_states );
336          uni_char = ps_unicode_value( gname );
337
338          if ( BASE_GLYPH( uni_char ) != 0 )
339          {
340            ps_check_extra_glyph_unicode( uni_char,
341                                          extra_glyph_list_states );
342            map->unicode     = uni_char;
343            map->glyph_index = n;
344            map++;
345          }
346
347          if ( free_glyph_name )
348            free_glyph_name( glyph_data, gname );
349        }
350      }
351
352      for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ )
353      {
354        if ( extra_glyph_list_states[n] == 1 )
355        {
356          /* This glyph name has an additional representation. */
357          /* Add it to the cmap.                               */
358
359          map->unicode     = ft_extra_glyph_unicodes[n];
360          map->glyph_index = extra_glyphs[n];
361          map++;
362        }
363      }
364
365      /* now compress the table a bit */
366      count = (FT_UInt)( map - table->maps );
367
368      if ( count == 0 )
369      {
370        /* No unicode chars here! */
371        FT_FREE( table->maps );
372        if ( !error )
373          error = FT_THROW( No_Unicode_Glyph_Name );
374      }
375      else
376      {
377        /* Reallocate if the number of used entries is much smaller. */
378        if ( count < num_glyphs / 2 )
379        {
380          (void)FT_RENEW_ARRAY( table->maps, num_glyphs, count );
381          error = FT_Err_Ok;
382        }
383
384        /* Sort the table in increasing order of unicode values, */
385        /* taking care of glyph variants.                        */
386        ft_qsort( table->maps, count, sizeof ( PS_UniMap ),
387                  compare_uni_maps );
388      }
389
390      table->num_maps = count;
391    }
392
393    return error;
394  }
395
396
397  static FT_UInt
398  ps_unicodes_char_index( PS_Unicodes  table,
399                          FT_UInt32    unicode )
400  {
401    PS_UniMap  *min, *max, *mid, *result = NULL;
402
403
404    /* Perform a binary search on the table. */
405
406    min = table->maps;
407    max = min + table->num_maps - 1;
408
409    while ( min <= max )
410    {
411      FT_UInt32  base_glyph;
412
413
414      mid = min + ( ( max - min ) >> 1 );
415
416      if ( mid->unicode == unicode )
417      {
418        result = mid;
419        break;
420      }
421
422      base_glyph = BASE_GLYPH( mid->unicode );
423
424      if ( base_glyph == unicode )
425        result = mid; /* remember match but continue search for base glyph */
426
427      if ( min == max )
428        break;
429
430      if ( base_glyph < unicode )
431        min = mid + 1;
432      else
433        max = mid - 1;
434    }
435
436    if ( result )
437      return result->glyph_index;
438    else
439      return 0;
440  }
441
442
443  static FT_UInt32
444  ps_unicodes_char_next( PS_Unicodes  table,
445                         FT_UInt32   *unicode )
446  {
447    FT_UInt    result    = 0;
448    FT_UInt32  char_code = *unicode + 1;
449
450
451    {
452      FT_UInt     min = 0;
453      FT_UInt     max = table->num_maps;
454      FT_UInt     mid;
455      PS_UniMap*  map;
456      FT_UInt32   base_glyph;
457
458
459      while ( min < max )
460      {
461        mid = min + ( ( max - min ) >> 1 );
462        map = table->maps + mid;
463
464        if ( map->unicode == char_code )
465        {
466          result = map->glyph_index;
467          goto Exit;
468        }
469
470        base_glyph = BASE_GLYPH( map->unicode );
471
472        if ( base_glyph == char_code )
473          result = map->glyph_index;
474
475        if ( base_glyph < char_code )
476          min = mid + 1;
477        else
478          max = mid;
479      }
480
481      if ( result )
482        goto Exit;               /* we have a variant glyph */
483
484      /* we didn't find it; check whether we have a map just above it */
485      char_code = 0;
486
487      if ( min < table->num_maps )
488      {
489        map       = table->maps + min;
490        result    = map->glyph_index;
491        char_code = BASE_GLYPH( map->unicode );
492      }
493    }
494
495  Exit:
496    *unicode = char_code;
497    return result;
498  }
499
500
501#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
502
503
504  static const char*
505  ps_get_macintosh_name( FT_UInt  name_index )
506  {
507    if ( name_index >= FT_NUM_MAC_NAMES )
508      name_index = 0;
509
510    return ft_standard_glyph_names + ft_mac_names[name_index];
511  }
512
513
514  static const char*
515  ps_get_standard_strings( FT_UInt  sid )
516  {
517    if ( sid >= FT_NUM_SID_NAMES )
518      return 0;
519
520    return ft_standard_glyph_names + ft_sid_names[sid];
521  }
522
523
524#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
525
526  FT_DEFINE_SERVICE_PSCMAPSREC(
527    pscmaps_interface,
528    (PS_Unicode_ValueFunc)     ps_unicode_value,
529    (PS_Unicodes_InitFunc)     ps_unicodes_init,
530    (PS_Unicodes_CharIndexFunc)ps_unicodes_char_index,
531    (PS_Unicodes_CharNextFunc) ps_unicodes_char_next,
532
533    (PS_Macintosh_NameFunc)    ps_get_macintosh_name,
534    (PS_Adobe_Std_StringsFunc) ps_get_standard_strings,
535
536    t1_standard_encoding,
537    t1_expert_encoding )
538
539#else
540
541  FT_DEFINE_SERVICE_PSCMAPSREC(
542    pscmaps_interface,
543    NULL,
544    NULL,
545    NULL,
546    NULL,
547
548    (PS_Macintosh_NameFunc)    ps_get_macintosh_name,
549    (PS_Adobe_Std_StringsFunc) ps_get_standard_strings,
550
551    t1_standard_encoding,
552    t1_expert_encoding )
553
554#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
555
556
557  FT_DEFINE_SERVICEDESCREC1(
558    pscmaps_services,
559    FT_SERVICE_ID_POSTSCRIPT_CMAPS, &PSCMAPS_INTERFACE_GET )
560
561
562  static FT_Pointer
563  psnames_get_service( FT_Module    module,
564                       const char*  service_id )
565  {
566    /* PSCMAPS_SERVICES_GET derefers `library' in PIC mode */
567#ifdef FT_CONFIG_OPTION_PIC
568    FT_Library  library;
569
570
571    if ( !module )
572      return NULL;
573    library = module->library;
574    if ( !library )
575      return NULL;
576#else
577    FT_UNUSED( module );
578#endif
579
580    return ft_service_list_lookup( PSCMAPS_SERVICES_GET, service_id );
581  }
582
583#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
584
585
586#ifndef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
587#define PUT_PS_NAMES_SERVICE( a )  NULL
588#else
589#define PUT_PS_NAMES_SERVICE( a )  a
590#endif
591
592  FT_DEFINE_MODULE(
593    psnames_module_class,
594
595    0,  /* this is not a font driver, nor a renderer */
596    sizeof ( FT_ModuleRec ),
597
598    "psnames",  /* driver name                         */
599    0x10000L,   /* driver version                      */
600    0x20000L,   /* driver requires FreeType 2 or above */
601
602    PUT_PS_NAMES_SERVICE(
603      (void*)&PSCMAPS_INTERFACE_GET ),   /* module specific interface */
604    (FT_Module_Constructor)NULL,
605    (FT_Module_Destructor) NULL,
606    (FT_Module_Requester)  PUT_PS_NAMES_SERVICE( psnames_get_service ) )
607
608
609/* END */
610