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 )
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 )
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
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
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 )
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 )
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 )
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* )
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* )
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_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