xref: /aosp_15_r20/external/freetype/src/psnames/psmodule.c (revision 63949dbd25bcc50c4e1178497ff9e9574d44fc5a)
1 /****************************************************************************
2  *
3  * psmodule.c
4  *
5  *   psnames module implementation (body).
6  *
7  * Copyright (C) 1996-2023 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   FT_CALLBACK_DEF( 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   FT_CALLBACK_DEF( 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   FT_CALLBACK_DEF( 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  *result = NULL;
416     PS_UniMap  *min = table->maps;
417     PS_UniMap  *max = min + table->num_maps;
418     PS_UniMap  *mid = min + ( ( max - min ) >> 1 );
419 
420 
421     /* Perform a binary search on the table. */
422     while ( min < max )
423     {
424       FT_UInt32  base_glyph;
425 
426 
427       if ( mid->unicode == unicode )
428       {
429         result = mid;
430         break;
431       }
432 
433       base_glyph = BASE_GLYPH( mid->unicode );
434 
435       if ( base_glyph == unicode )
436         result = mid; /* remember match but continue search for base glyph */
437 
438       if ( base_glyph < unicode )
439         min = mid + 1;
440       else
441         max = mid;
442 
443       /* reasonable prediction in a continuous block */
444       mid += unicode - base_glyph;
445       if ( mid >= max || mid < min )
446         mid = min + ( ( max - min ) >> 1 );
447     }
448 
449     if ( result )
450       return result->glyph_index;
451     else
452       return 0;
453   }
454 
455 
456   FT_CALLBACK_DEF( FT_UInt )
ps_unicodes_char_next(PS_Unicodes table,FT_UInt32 * unicode)457   ps_unicodes_char_next( PS_Unicodes  table,
458                          FT_UInt32   *unicode )
459   {
460     FT_UInt    result    = 0;
461     FT_UInt32  char_code = *unicode + 1;
462 
463 
464     {
465       FT_UInt     min = 0;
466       FT_UInt     max = table->num_maps;
467       FT_UInt     mid = min + ( ( max - min ) >> 1 );
468       PS_UniMap*  map;
469       FT_UInt32   base_glyph;
470 
471 
472       while ( min < max )
473       {
474         map = table->maps + mid;
475 
476         if ( map->unicode == char_code )
477         {
478           result = map->glyph_index;
479           goto Exit;
480         }
481 
482         base_glyph = BASE_GLYPH( map->unicode );
483 
484         if ( base_glyph == char_code )
485           result = map->glyph_index;
486 
487         if ( base_glyph < char_code )
488           min = mid + 1;
489         else
490           max = mid;
491 
492         /* reasonable prediction in a continuous block */
493         mid += char_code - base_glyph;
494         if ( mid >= max || mid < min )
495           mid = min + ( max - min ) / 2;
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   FT_CALLBACK_DEF( 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   FT_CALLBACK_DEF( 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 
FT_DEFINE_SERVICE_PSCMAPSREC(pscmaps_interface,ps_unicode_value,ps_unicodes_init,ps_unicodes_char_index,ps_unicodes_char_next,ps_get_macintosh_name,ps_get_standard_strings,t1_standard_encoding,t1_expert_encoding)543   FT_DEFINE_SERVICE_PSCMAPSREC(
544     pscmaps_interface,
545 
546     ps_unicode_value,         /* PS_Unicode_ValueFunc      unicode_value         */
547     ps_unicodes_init,         /* PS_Unicodes_InitFunc      unicodes_init         */
548     ps_unicodes_char_index,   /* PS_Unicodes_CharIndexFunc unicodes_char_index   */
549     ps_unicodes_char_next,    /* PS_Unicodes_CharNextFunc  unicodes_char_next    */
550 
551     ps_get_macintosh_name,    /* PS_Macintosh_NameFunc     macintosh_name        */
552     ps_get_standard_strings,  /* PS_Adobe_Std_StringsFunc  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,                     /* PS_Unicode_ValueFunc      unicode_value         */
564     NULL,                     /* PS_Unicodes_InitFunc      unicodes_init         */
565     NULL,                     /* PS_Unicodes_CharIndexFunc unicodes_char_index   */
566     NULL,                     /* PS_Unicodes_CharNextFunc  unicodes_char_next    */
567 
568     ps_get_macintosh_name,    /* PS_Macintosh_NameFunc     macintosh_name        */
569     ps_get_standard_strings,  /* PS_Adobe_Std_StringsFunc  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
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     NULL,                                        /* FT_Module_Constructor module_init   */
616     NULL,                                        /* FT_Module_Destructor  module_done   */
617     PUT_PS_NAMES_SERVICE( psnames_get_service )  /* FT_Module_Requester   get_interface */
618   )
619 
620 
621 /* END */
622