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