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