• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * psmodule.c
4  *
5  *   psnames module implementation (body).
6  *
7  * Copyright (C) 1996-2022 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       FT_UInt32    value = 0;
159       const char*  p     = glyph_name;
160 
161 
162       for ( ; *p && *p != '.'; p++ )
163         ;
164 
165       /* now look up the glyph in the Adobe Glyph List;      */
166       /* `.notdef', `.null' and the empty name are short cut */
167       if ( p > glyph_name )
168       {
169         value = (FT_UInt32)ft_get_adobe_glyph_index( glyph_name, p );
170 
171         if ( *p == '.' )
172           value |= (FT_UInt32)VARIANT_BIT;
173       }
174 
175       return value;
176     }
177   }
178 
179 
180   /* ft_qsort callback to sort the unicode map */
181   FT_COMPARE_DEF( int )
compare_uni_maps(const void * a,const void * b)182   compare_uni_maps( const void*  a,
183                     const void*  b )
184   {
185     PS_UniMap*  map1 = (PS_UniMap*)a;
186     PS_UniMap*  map2 = (PS_UniMap*)b;
187     FT_UInt32   unicode1 = BASE_GLYPH( map1->unicode );
188     FT_UInt32   unicode2 = BASE_GLYPH( map2->unicode );
189 
190 
191     /* sort base glyphs before glyph variants */
192     if ( unicode1 == unicode2 )
193     {
194       if ( map1->unicode > map2->unicode )
195         return 1;
196       else if ( map1->unicode < map2->unicode )
197         return -1;
198       else
199         return 0;
200     }
201     else
202     {
203       if ( unicode1 > unicode2 )
204         return 1;
205       else if ( unicode1 < unicode2 )
206         return -1;
207       else
208         return 0;
209     }
210   }
211 
212 
213   /* support for extra glyphs not handled (well) in AGL; */
214   /* we add extra mappings for them if necessary         */
215 
216 #define EXTRA_GLYPH_LIST_SIZE  10
217 
218   static const FT_UInt32  ft_extra_glyph_unicodes[EXTRA_GLYPH_LIST_SIZE] =
219   {
220     /* WGL 4 */
221     0x0394,
222     0x03A9,
223     0x2215,
224     0x00AD,
225     0x02C9,
226     0x03BC,
227     0x2219,
228     0x00A0,
229     /* Romanian */
230     0x021A,
231     0x021B
232   };
233 
234   static const char  ft_extra_glyph_names[] =
235   {
236     'D','e','l','t','a',0,
237     'O','m','e','g','a',0,
238     'f','r','a','c','t','i','o','n',0,
239     'h','y','p','h','e','n',0,
240     'm','a','c','r','o','n',0,
241     'm','u',0,
242     'p','e','r','i','o','d','c','e','n','t','e','r','e','d',0,
243     's','p','a','c','e',0,
244     'T','c','o','m','m','a','a','c','c','e','n','t',0,
245     't','c','o','m','m','a','a','c','c','e','n','t',0
246   };
247 
248   static const FT_Int
249   ft_extra_glyph_name_offsets[EXTRA_GLYPH_LIST_SIZE] =
250   {
251      0,
252      6,
253     12,
254     21,
255     28,
256     35,
257     38,
258     53,
259     59,
260     72
261   };
262 
263 
264   static void
ps_check_extra_glyph_name(const char * gname,FT_UInt glyph,FT_UInt * extra_glyphs,FT_UInt * states)265   ps_check_extra_glyph_name( const char*  gname,
266                              FT_UInt      glyph,
267                              FT_UInt*     extra_glyphs,
268                              FT_UInt     *states )
269   {
270     FT_UInt  n;
271 
272 
273     for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ )
274     {
275       if ( ft_strcmp( ft_extra_glyph_names +
276                         ft_extra_glyph_name_offsets[n], gname ) == 0 )
277       {
278         if ( states[n] == 0 )
279         {
280           /* mark this extra glyph as a candidate for the cmap */
281           states[n]     = 1;
282           extra_glyphs[n] = glyph;
283         }
284 
285         return;
286       }
287     }
288   }
289 
290 
291   static void
ps_check_extra_glyph_unicode(FT_UInt32 uni_char,FT_UInt * states)292   ps_check_extra_glyph_unicode( FT_UInt32  uni_char,
293                                 FT_UInt   *states )
294   {
295     FT_UInt  n;
296 
297 
298     for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ )
299     {
300       if ( uni_char == ft_extra_glyph_unicodes[n] )
301       {
302         /* disable this extra glyph from being added to the cmap */
303         states[n] = 2;
304 
305         return;
306       }
307     }
308   }
309 
310 
311   /* Build a table that maps Unicode values to glyph indices. */
312   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)313   ps_unicodes_init( FT_Memory             memory,
314                     PS_Unicodes           table,
315                     FT_UInt               num_glyphs,
316                     PS_GetGlyphNameFunc   get_glyph_name,
317                     PS_FreeGlyphNameFunc  free_glyph_name,
318                     FT_Pointer            glyph_data )
319   {
320     FT_Error  error;
321 
322     FT_UInt  extra_glyph_list_states[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
323     FT_UInt  extra_glyphs[EXTRA_GLYPH_LIST_SIZE];
324 
325 
326     /* we first allocate the table */
327     table->num_maps = 0;
328 
329     if ( !FT_QNEW_ARRAY( table->maps, num_glyphs + EXTRA_GLYPH_LIST_SIZE ) )
330     {
331       FT_UInt     n;
332       FT_UInt     count;
333       PS_UniMap*  map;
334       FT_UInt32   uni_char;
335 
336 
337       map = table->maps;
338 
339       for ( n = 0; n < num_glyphs; n++ )
340       {
341         const char*  gname = get_glyph_name( glyph_data, n );
342 
343 
344         if ( gname && *gname )
345         {
346           ps_check_extra_glyph_name( gname, n,
347                                      extra_glyphs, extra_glyph_list_states );
348           uni_char = ps_unicode_value( gname );
349 
350           if ( BASE_GLYPH( uni_char ) != 0 )
351           {
352             ps_check_extra_glyph_unicode( uni_char,
353                                           extra_glyph_list_states );
354             map->unicode     = uni_char;
355             map->glyph_index = n;
356             map++;
357           }
358 
359           if ( free_glyph_name )
360             free_glyph_name( glyph_data, gname );
361         }
362       }
363 
364       for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ )
365       {
366         if ( extra_glyph_list_states[n] == 1 )
367         {
368           /* This glyph name has an additional representation. */
369           /* Add it to the cmap.                               */
370 
371           map->unicode     = ft_extra_glyph_unicodes[n];
372           map->glyph_index = extra_glyphs[n];
373           map++;
374         }
375       }
376 
377       /* now compress the table a bit */
378       count = (FT_UInt)( map - table->maps );
379 
380       if ( count == 0 )
381       {
382         /* No unicode chars here! */
383         FT_FREE( table->maps );
384         if ( !error )
385           error = FT_THROW( No_Unicode_Glyph_Name );
386       }
387       else
388       {
389         /* Reallocate if the number of used entries is much smaller. */
390         if ( count < num_glyphs / 2 )
391         {
392           FT_MEM_QRENEW_ARRAY( table->maps,
393                                num_glyphs + EXTRA_GLYPH_LIST_SIZE,
394                                count );
395           error = FT_Err_Ok;
396         }
397 
398         /* Sort the table in increasing order of unicode values, */
399         /* taking care of glyph variants.                        */
400         ft_qsort( table->maps, count, sizeof ( PS_UniMap ),
401                   compare_uni_maps );
402       }
403 
404       table->num_maps = count;
405     }
406 
407     return error;
408   }
409 
410 
411   static FT_UInt
ps_unicodes_char_index(PS_Unicodes table,FT_UInt32 unicode)412   ps_unicodes_char_index( PS_Unicodes  table,
413                           FT_UInt32    unicode )
414   {
415     PS_UniMap  *min, *max, *mid, *result = NULL;
416 
417 
418     /* Perform a binary search on the table. */
419 
420     min = table->maps;
421     max = min + table->num_maps - 1;
422 
423     while ( min <= max )
424     {
425       FT_UInt32  base_glyph;
426 
427 
428       mid = min + ( ( max - min ) >> 1 );
429 
430       if ( mid->unicode == unicode )
431       {
432         result = mid;
433         break;
434       }
435 
436       base_glyph = BASE_GLYPH( mid->unicode );
437 
438       if ( base_glyph == unicode )
439         result = mid; /* remember match but continue search for base glyph */
440 
441       if ( min == max )
442         break;
443 
444       if ( base_glyph < unicode )
445         min = mid + 1;
446       else
447         max = mid - 1;
448     }
449 
450     if ( result )
451       return result->glyph_index;
452     else
453       return 0;
454   }
455 
456 
457   static FT_UInt32
ps_unicodes_char_next(PS_Unicodes table,FT_UInt32 * unicode)458   ps_unicodes_char_next( PS_Unicodes  table,
459                          FT_UInt32   *unicode )
460   {
461     FT_UInt    result    = 0;
462     FT_UInt32  char_code = *unicode + 1;
463 
464 
465     {
466       FT_UInt     min = 0;
467       FT_UInt     max = table->num_maps;
468       FT_UInt     mid;
469       PS_UniMap*  map;
470       FT_UInt32   base_glyph;
471 
472 
473       while ( min < max )
474       {
475         mid = min + ( ( max - min ) >> 1 );
476         map = table->maps + mid;
477 
478         if ( map->unicode == char_code )
479         {
480           result = map->glyph_index;
481           goto Exit;
482         }
483 
484         base_glyph = BASE_GLYPH( map->unicode );
485 
486         if ( base_glyph == char_code )
487           result = map->glyph_index;
488 
489         if ( base_glyph < char_code )
490           min = mid + 1;
491         else
492           max = mid;
493       }
494 
495       if ( result )
496         goto Exit;               /* we have a variant glyph */
497 
498       /* we didn't find it; check whether we have a map just above it */
499       char_code = 0;
500 
501       if ( min < table->num_maps )
502       {
503         map       = table->maps + min;
504         result    = map->glyph_index;
505         char_code = BASE_GLYPH( map->unicode );
506       }
507     }
508 
509   Exit:
510     *unicode = char_code;
511     return result;
512   }
513 
514 
515 #endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
516 
517 
518   static const char*
ps_get_macintosh_name(FT_UInt name_index)519   ps_get_macintosh_name( FT_UInt  name_index )
520   {
521     if ( name_index >= FT_NUM_MAC_NAMES )
522       name_index = 0;
523 
524     return ft_standard_glyph_names + ft_mac_names[name_index];
525   }
526 
527 
528   static const char*
ps_get_standard_strings(FT_UInt sid)529   ps_get_standard_strings( FT_UInt  sid )
530   {
531     if ( sid >= FT_NUM_SID_NAMES )
532       return 0;
533 
534     return ft_standard_glyph_names + ft_sid_names[sid];
535   }
536 
537 
538 #ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
539 
540   FT_DEFINE_SERVICE_PSCMAPSREC(
541     pscmaps_interface,
542 
543     (PS_Unicode_ValueFunc)     ps_unicode_value,        /* unicode_value         */
544     (PS_Unicodes_InitFunc)     ps_unicodes_init,        /* unicodes_init         */
545     (PS_Unicodes_CharIndexFunc)ps_unicodes_char_index,  /* unicodes_char_index   */
546     (PS_Unicodes_CharNextFunc) ps_unicodes_char_next,   /* 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 
555 #else
556 
557   FT_DEFINE_SERVICE_PSCMAPSREC(
558     pscmaps_interface,
559 
560     NULL,                                               /* unicode_value         */
561     NULL,                                               /* unicodes_init         */
562     NULL,                                               /* unicodes_char_index   */
563     NULL,                                               /* unicodes_char_next    */
564 
565     (PS_Macintosh_NameFunc)    ps_get_macintosh_name,   /* macintosh_name        */
566     (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, /* adobe_std_strings     */
567 
568     t1_standard_encoding,                               /* adobe_std_encoding    */
569     t1_expert_encoding                                  /* adobe_expert_encoding */
570   )
571 
572 #endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
573 
574 
575   FT_DEFINE_SERVICEDESCREC1(
576     pscmaps_services,
577 
578     FT_SERVICE_ID_POSTSCRIPT_CMAPS, &pscmaps_interface )
579 
580 
581   static FT_Pointer
psnames_get_service(FT_Module module,const char * service_id)582   psnames_get_service( FT_Module    module,
583                        const char*  service_id )
584   {
585     FT_UNUSED( module );
586 
587     return ft_service_list_lookup( pscmaps_services, service_id );
588   }
589 
590 #endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
591 
592 
593 #ifndef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
594 #define PUT_PS_NAMES_SERVICE( a )  NULL
595 #else
596 #define PUT_PS_NAMES_SERVICE( a )  a
597 #endif
598 
599   FT_DEFINE_MODULE(
600     psnames_module_class,
601 
602     0,  /* this is not a font driver, nor a renderer */
603     sizeof ( FT_ModuleRec ),
604 
605     "psnames",  /* driver name                         */
606     0x10000L,   /* driver version                      */
607     0x20000L,   /* driver requires FreeType 2 or above */
608 
609     PUT_PS_NAMES_SERVICE(
610       (void*)&pscmaps_interface ),   /* module specific interface */
611 
612     (FT_Module_Constructor)NULL,                                       /* module_init   */
613     (FT_Module_Destructor) NULL,                                       /* module_done   */
614     (FT_Module_Requester)  PUT_PS_NAMES_SERVICE( psnames_get_service ) /* get_interface */
615   )
616 
617 
618 /* END */
619