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