• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************/
2 /*                                                                         */
3 /*  psmodule.c                                                             */
4 /*                                                                         */
5 /*    PSNames module implementation (body).                                */
6 /*                                                                         */
7 /*  Copyright 1996-2016 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
ps_unicode_value(const char * glyph_name)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 )
compare_uni_maps(const void * a,const void * b)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
ps_check_extra_glyph_name(const char * gname,FT_UInt glyph,FT_UInt * extra_glyphs,FT_UInt * states)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
ps_check_extra_glyph_unicode(FT_UInt32 uni_char,FT_UInt * states)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
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)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     = NULL;
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
ps_unicodes_char_index(PS_Unicodes table,FT_UInt32 unicode)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
ps_unicodes_char_next(PS_Unicodes table,FT_UInt32 * unicode)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*
ps_get_macintosh_name(FT_UInt name_index)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*
ps_get_standard_strings(FT_UInt sid)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,        /* unicode_value         */
529     (PS_Unicodes_InitFunc)     ps_unicodes_init,        /* unicodes_init         */
530     (PS_Unicodes_CharIndexFunc)ps_unicodes_char_index,  /* unicodes_char_index   */
531     (PS_Unicodes_CharNextFunc) ps_unicodes_char_next,   /* unicodes_char_next    */
532 
533     (PS_Macintosh_NameFunc)    ps_get_macintosh_name,   /* macintosh_name        */
534     (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, /* adobe_std_strings     */
535 
536     t1_standard_encoding,                               /* adobe_std_encoding    */
537     t1_expert_encoding )                                /* adobe_expert_encoding */
538 
539 #else
540 
541   FT_DEFINE_SERVICE_PSCMAPSREC(
542     pscmaps_interface,
543     NULL,                                               /* unicode_value         */
544     NULL,                                               /* unicodes_init         */
545     NULL,                                               /* unicodes_char_index   */
546     NULL,                                               /* unicodes_char_next    */
547 
548     (PS_Macintosh_NameFunc)    ps_get_macintosh_name,   /* macintosh_name        */
549     (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, /* adobe_std_strings     */
550 
551     t1_standard_encoding,                               /* adobe_std_encoding    */
552     t1_expert_encoding )                                /* adobe_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
psnames_get_service(FT_Module module,const char * service_id)563   psnames_get_service( FT_Module    module,
564                        const char*  service_id )
565   {
566     /* PSCMAPS_SERVICES_GET dereferences `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