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