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