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