1 /*  bdfdrivr.c
2 
3     FreeType font driver for bdf files
4 
5     Copyright (C) 2001-2008, 2011, 2013, 2014 by
6     Francesco Zappa Nardelli
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 THE SOFTWARE.
25 */
26 
27 #include <ft2build.h>
28 
29 #include FT_INTERNAL_DEBUG_H
30 #include FT_INTERNAL_STREAM_H
31 #include FT_INTERNAL_OBJECTS_H
32 #include FT_BDF_H
33 #include FT_TRUETYPE_IDS_H
34 
35 #include FT_SERVICE_BDF_H
36 #include FT_SERVICE_FONT_FORMAT_H
37 
38 #include "bdf.h"
39 #include "bdfdrivr.h"
40 
41 #include "bdferror.h"
42 
43 
44   /**************************************************************************
45    *
46    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
47    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
48    * messages during execution.
49    */
50 #undef  FT_COMPONENT
51 #define FT_COMPONENT  bdfdriver
52 
53 
54   typedef struct  BDF_CMapRec_
55   {
56     FT_CMapRec        cmap;
57     FT_ULong          num_encodings; /* ftobjs.h: FT_CMap->clazz->size */
58     BDF_encoding_el*  encodings;
59 
60   } BDF_CMapRec, *BDF_CMap;
61 
62 
63   FT_CALLBACK_DEF( FT_Error )
bdf_cmap_init(FT_CMap bdfcmap,FT_Pointer init_data)64   bdf_cmap_init( FT_CMap     bdfcmap,
65                  FT_Pointer  init_data )
66   {
67     BDF_CMap  cmap = (BDF_CMap)bdfcmap;
68     BDF_Face  face = (BDF_Face)FT_CMAP_FACE( cmap );
69     FT_UNUSED( init_data );
70 
71 
72     cmap->num_encodings = face->bdffont->glyphs_used;
73     cmap->encodings     = face->en_table;
74 
75     return FT_Err_Ok;
76   }
77 
78 
79   FT_CALLBACK_DEF( void )
bdf_cmap_done(FT_CMap bdfcmap)80   bdf_cmap_done( FT_CMap  bdfcmap )
81   {
82     BDF_CMap  cmap = (BDF_CMap)bdfcmap;
83 
84 
85     cmap->encodings     = NULL;
86     cmap->num_encodings = 0;
87   }
88 
89 
90   FT_CALLBACK_DEF( FT_UInt )
bdf_cmap_char_index(FT_CMap bdfcmap,FT_UInt32 charcode)91   bdf_cmap_char_index( FT_CMap    bdfcmap,
92                        FT_UInt32  charcode )
93   {
94     BDF_CMap          cmap      = (BDF_CMap)bdfcmap;
95     BDF_encoding_el*  encodings = cmap->encodings;
96     FT_ULong          min, max, mid; /* num_encodings */
97     FT_UShort         result    = 0; /* encodings->glyph */
98 
99 
100     min = 0;
101     max = cmap->num_encodings;
102     mid = ( min + max ) >> 1;
103 
104     while ( min < max )
105     {
106       FT_ULong  code;
107 
108 
109       if ( mid >= max || mid < min )
110         mid = ( min + max ) >> 1;
111 
112       code = encodings[mid].enc;
113 
114       if ( charcode == code )
115       {
116         /* increase glyph index by 1 --              */
117         /* we reserve slot 0 for the undefined glyph */
118         result = encodings[mid].glyph + 1;
119         break;
120       }
121 
122       if ( charcode < code )
123         max = mid;
124       else
125         min = mid + 1;
126 
127       /* prediction in a continuous block */
128       mid += charcode - code;
129     }
130 
131     return result;
132   }
133 
134 
135   FT_CALLBACK_DEF( FT_UInt )
bdf_cmap_char_next(FT_CMap bdfcmap,FT_UInt32 * acharcode)136   bdf_cmap_char_next( FT_CMap     bdfcmap,
137                       FT_UInt32  *acharcode )
138   {
139     BDF_CMap          cmap      = (BDF_CMap)bdfcmap;
140     BDF_encoding_el*  encodings = cmap->encodings;
141     FT_ULong          min, max, mid; /* num_encodings */
142     FT_UShort         result   = 0;  /* encodings->glyph */
143     FT_ULong          charcode = *acharcode + 1;
144 
145 
146     min = 0;
147     max = cmap->num_encodings;
148     mid = ( min + max ) >> 1;
149 
150     while ( min < max )
151     {
152       FT_ULong  code; /* same as BDF_encoding_el.enc */
153 
154 
155       if ( mid >= max || mid < min )
156         mid = ( min + max ) >> 1;
157 
158       code = encodings[mid].enc;
159 
160       if ( charcode == code )
161       {
162         /* increase glyph index by 1 --              */
163         /* we reserve slot 0 for the undefined glyph */
164         result = encodings[mid].glyph + 1;
165         goto Exit;
166       }
167 
168       if ( charcode < code )
169         max = mid;
170       else
171         min = mid + 1;
172 
173       /* prediction in a continuous block */
174       mid += charcode - code;
175     }
176 
177     charcode = 0;
178     if ( min < cmap->num_encodings )
179     {
180       charcode = encodings[min].enc;
181       result   = encodings[min].glyph + 1;
182     }
183 
184   Exit:
185     if ( charcode > 0xFFFFFFFFUL )
186     {
187       FT_TRACE1(( "bdf_cmap_char_next: charcode 0x%x > 32bit API" ));
188       *acharcode = 0;
189       /* XXX: result should be changed to indicate an overflow error */
190     }
191     else
192       *acharcode = (FT_UInt32)charcode;
193     return result;
194   }
195 
196 
197   static
198   const FT_CMap_ClassRec  bdf_cmap_class =
199   {
200     sizeof ( BDF_CMapRec ),
201     bdf_cmap_init,
202     bdf_cmap_done,
203     bdf_cmap_char_index,
204     bdf_cmap_char_next,
205 
206     NULL, NULL, NULL, NULL, NULL
207   };
208 
209 
210   static FT_Error
bdf_interpret_style(BDF_Face bdf)211   bdf_interpret_style( BDF_Face  bdf )
212   {
213     FT_Error         error  = FT_Err_Ok;
214     FT_Face          face   = FT_FACE( bdf );
215     FT_Memory        memory = face->memory;
216     bdf_font_t*      font   = bdf->bdffont;
217     bdf_property_t*  prop;
218 
219     const char*   strings[4] = { NULL, NULL, NULL, NULL };
220     size_t        lengths[4], nn, len;
221 
222 
223     face->style_flags = 0;
224 
225     prop = bdf_get_font_property( font, "SLANT" );
226     if ( prop && prop->format == BDF_ATOM                             &&
227          prop->value.atom                                             &&
228          ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
229            *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
230     {
231       face->style_flags |= FT_STYLE_FLAG_ITALIC;
232       strings[2] = ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' )
233                    ? "Oblique"
234                    : "Italic";
235     }
236 
237     prop = bdf_get_font_property( font, "WEIGHT_NAME" );
238     if ( prop && prop->format == BDF_ATOM                             &&
239          prop->value.atom                                             &&
240          ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
241     {
242       face->style_flags |= FT_STYLE_FLAG_BOLD;
243       strings[1] = "Bold";
244     }
245 
246     prop = bdf_get_font_property( font, "SETWIDTH_NAME" );
247     if ( prop && prop->format == BDF_ATOM                              &&
248          prop->value.atom && *(prop->value.atom)                       &&
249          !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
250       strings[3] = (const char *)(prop->value.atom);
251 
252     prop = bdf_get_font_property( font, "ADD_STYLE_NAME" );
253     if ( prop && prop->format == BDF_ATOM                              &&
254          prop->value.atom && *(prop->value.atom)                       &&
255          !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
256       strings[0] = (const char *)(prop->value.atom);
257 
258     for ( len = 0, nn = 0; nn < 4; nn++ )
259     {
260       lengths[nn] = 0;
261       if ( strings[nn] )
262       {
263         lengths[nn] = ft_strlen( strings[nn] );
264         len        += lengths[nn] + 1;
265       }
266     }
267 
268     if ( len == 0 )
269     {
270       strings[0] = "Regular";
271       lengths[0] = ft_strlen( strings[0] );
272       len        = lengths[0] + 1;
273     }
274 
275     {
276       char*  s;
277 
278 
279       if ( FT_ALLOC( face->style_name, len ) )
280         return error;
281 
282       s = face->style_name;
283 
284       for ( nn = 0; nn < 4; nn++ )
285       {
286         const char*  src = strings[nn];
287 
288 
289         len = lengths[nn];
290 
291         if ( !src )
292           continue;
293 
294         /* separate elements with a space */
295         if ( s != face->style_name )
296           *s++ = ' ';
297 
298         ft_memcpy( s, src, len );
299 
300         /* need to convert spaces to dashes for */
301         /* add_style_name and setwidth_name     */
302         if ( nn == 0 || nn == 3 )
303         {
304           size_t  mm;
305 
306 
307           for ( mm = 0; mm < len; mm++ )
308             if ( s[mm] == ' ' )
309               s[mm] = '-';
310         }
311 
312         s += len;
313       }
314       *s = 0;
315     }
316 
317     return error;
318   }
319 
320 
321   FT_CALLBACK_DEF( void )
BDF_Face_Done(FT_Face bdfface)322   BDF_Face_Done( FT_Face  bdfface )         /* BDF_Face */
323   {
324     BDF_Face   face = (BDF_Face)bdfface;
325     FT_Memory  memory;
326 
327 
328     if ( !face )
329       return;
330 
331     memory = FT_FACE_MEMORY( face );
332 
333     bdf_free_font( face->bdffont );
334 
335     FT_FREE( face->en_table );
336 
337     FT_FREE( face->charset_encoding );
338     FT_FREE( face->charset_registry );
339     FT_FREE( bdfface->family_name );
340     FT_FREE( bdfface->style_name );
341 
342     FT_FREE( bdfface->available_sizes );
343 
344     FT_FREE( face->bdffont );
345   }
346 
347 
348   FT_CALLBACK_DEF( FT_Error )
BDF_Face_Init(FT_Stream stream,FT_Face bdfface,FT_Int face_index,FT_Int num_params,FT_Parameter * params)349   BDF_Face_Init( FT_Stream      stream,
350                  FT_Face        bdfface,        /* BDF_Face */
351                  FT_Int         face_index,
352                  FT_Int         num_params,
353                  FT_Parameter*  params )
354   {
355     FT_Error       error  = FT_Err_Ok;
356     BDF_Face       face   = (BDF_Face)bdfface;
357     FT_Memory      memory = FT_FACE_MEMORY( face );
358 
359     bdf_font_t*    font = NULL;
360     bdf_options_t  options;
361 
362     FT_UNUSED( num_params );
363     FT_UNUSED( params );
364 
365 
366     FT_TRACE2(( "BDF driver\n" ));
367 
368     if ( FT_STREAM_SEEK( 0 ) )
369       goto Exit;
370 
371     options.correct_metrics = 1;   /* FZ XXX: options semantics */
372     options.keep_unencoded  = 1;
373     options.keep_comments   = 0;
374     options.font_spacing    = BDF_PROPORTIONAL;
375 
376     error = bdf_load_font( stream, memory, &options, &font );
377     if ( FT_ERR_EQ( error, Missing_Startfont_Field ) )
378     {
379       FT_TRACE2(( "  not a BDF file\n" ));
380       goto Fail;
381     }
382     else if ( error )
383       goto Exit;
384 
385     /* we have a bdf font: let's construct the face object */
386     face->bdffont = font;
387 
388     /* BDF cannot have multiple faces in a single font file.
389      * XXX: non-zero face_index is already invalid argument, but
390      *      Type1, Type42 driver has a convention to return
391      *      an invalid argument error when the font could be
392      *      opened by the specified driver.
393      */
394     if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 )
395     {
396       FT_ERROR(( "BDF_Face_Init: invalid face index\n" ));
397       BDF_Face_Done( bdfface );
398       return FT_THROW( Invalid_Argument );
399     }
400 
401     {
402       bdf_property_t*  prop = NULL;
403 
404 
405       FT_TRACE4(( "  number of glyphs: allocated %d (used %d)\n",
406                   font->glyphs_size,
407                   font->glyphs_used ));
408       FT_TRACE4(( "  number of unencoded glyphs: allocated %d (used %d)\n",
409                   font->unencoded_size,
410                   font->unencoded_used ));
411 
412       bdfface->num_faces  = 1;
413       bdfface->face_index = 0;
414 
415       bdfface->face_flags |= FT_FACE_FLAG_FIXED_SIZES |
416                              FT_FACE_FLAG_HORIZONTAL;
417 
418       prop = bdf_get_font_property( font, "SPACING" );
419       if ( prop && prop->format == BDF_ATOM                             &&
420            prop->value.atom                                             &&
421            ( *(prop->value.atom) == 'M' || *(prop->value.atom) == 'm' ||
422              *(prop->value.atom) == 'C' || *(prop->value.atom) == 'c' ) )
423         bdfface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
424 
425       /* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL   */
426       /* FZ XXX: I need a font to implement this */
427 
428       prop = bdf_get_font_property( font, "FAMILY_NAME" );
429       if ( prop && prop->value.atom )
430       {
431         if ( FT_STRDUP( bdfface->family_name, prop->value.atom ) )
432           goto Exit;
433       }
434       else
435         bdfface->family_name = NULL;
436 
437       if ( FT_SET_ERROR( bdf_interpret_style( face ) ) )
438         goto Exit;
439 
440       /* the number of glyphs (with one slot for the undefined glyph */
441       /* at position 0 and all unencoded glyphs)                     */
442       bdfface->num_glyphs = (FT_Long)( font->glyphs_size + 1 );
443 
444       bdfface->num_fixed_sizes = 1;
445       if ( FT_NEW_ARRAY( bdfface->available_sizes, 1 ) )
446         goto Exit;
447 
448       {
449         FT_Bitmap_Size*  bsize = bdfface->available_sizes;
450         FT_Short         resolution_x = 0, resolution_y = 0;
451         long             value;
452 
453 
454         FT_ZERO( bsize );
455 
456         /* sanity checks */
457         if ( font->font_ascent > 0x7FFF || font->font_ascent < -0x7FFF )
458         {
459           font->font_ascent = font->font_ascent < 0 ? -0x7FFF : 0x7FFF;
460           FT_TRACE0(( "BDF_Face_Init: clamping font ascent to value %d\n",
461                       font->font_ascent ));
462         }
463         if ( font->font_descent > 0x7FFF || font->font_descent < -0x7FFF )
464         {
465           font->font_descent = font->font_descent < 0 ? -0x7FFF : 0x7FFF;
466           FT_TRACE0(( "BDF_Face_Init: clamping font descent to value %d\n",
467                       font->font_descent ));
468         }
469 
470         bsize->height = (FT_Short)( font->font_ascent + font->font_descent );
471 
472         prop = bdf_get_font_property( font, "AVERAGE_WIDTH" );
473         if ( prop )
474         {
475 #ifdef FT_DEBUG_LEVEL_TRACE
476           if ( prop->value.l < 0 )
477             FT_TRACE0(( "BDF_Face_Init: negative average width\n" ));
478 #endif
479           if ( prop->value.l >    0x7FFFL * 10 - 5   ||
480                prop->value.l < -( 0x7FFFL * 10 - 5 ) )
481           {
482             bsize->width = 0x7FFF;
483             FT_TRACE0(( "BDF_Face_Init: clamping average width to value %d\n",
484                         bsize->width ));
485           }
486           else
487             bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) );
488         }
489         else
490         {
491           /* this is a heuristical value */
492           bsize->width = (FT_Short)FT_MulDiv( bsize->height, 2, 3 );
493         }
494 
495         prop = bdf_get_font_property( font, "POINT_SIZE" );
496         if ( prop )
497         {
498 #ifdef FT_DEBUG_LEVEL_TRACE
499           if ( prop->value.l < 0 )
500             FT_TRACE0(( "BDF_Face_Init: negative point size\n" ));
501 #endif
502           /* convert from 722.7 decipoints to 72 points per inch */
503           if ( prop->value.l >  0x504C2L || /* 0x7FFF * 72270/7200 */
504                prop->value.l < -0x504C2L )
505           {
506             bsize->size = 0x7FFF;
507             FT_TRACE0(( "BDF_Face_Init: clamping point size to value %d\n",
508                         bsize->size ));
509           }
510           else
511             bsize->size = FT_MulDiv( FT_ABS( prop->value.l ),
512                                      64 * 7200,
513                                      72270L );
514         }
515         else if ( font->point_size )
516         {
517           if ( font->point_size > 0x7FFF )
518           {
519             bsize->size = 0x7FFF;
520             FT_TRACE0(( "BDF_Face_Init: clamping point size to value %d\n",
521                         bsize->size ));
522           }
523           else
524             bsize->size = (FT_Pos)font->point_size << 6;
525         }
526         else
527         {
528           /* this is a heuristical value */
529           bsize->size = bsize->width * 64;
530         }
531 
532         prop = bdf_get_font_property( font, "PIXEL_SIZE" );
533         if ( prop )
534         {
535 #ifdef FT_DEBUG_LEVEL_TRACE
536           if ( prop->value.l < 0 )
537             FT_TRACE0(( "BDF_Face_Init: negative pixel size\n" ));
538 #endif
539           if ( prop->value.l > 0x7FFF || prop->value.l < -0x7FFF )
540           {
541             bsize->y_ppem = 0x7FFF << 6;
542             FT_TRACE0(( "BDF_Face_Init: clamping pixel size to value %d\n",
543                         bsize->y_ppem ));
544           }
545           else
546             bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6;
547         }
548 
549         prop = bdf_get_font_property( font, "RESOLUTION_X" );
550         if ( prop )
551           value = prop->value.l;
552         else
553           value = (long)font->resolution_x;
554         if ( value )
555         {
556 #ifdef FT_DEBUG_LEVEL_TRACE
557           if ( value < 0 )
558             FT_TRACE0(( "BDF_Face_Init: negative X resolution\n" ));
559 #endif
560           if ( value > 0x7FFF || value < -0x7FFF )
561           {
562             resolution_x = 0x7FFF;
563             FT_TRACE0(( "BDF_Face_Init: clamping X resolution to value %d\n",
564                         resolution_x ));
565           }
566           else
567             resolution_x = FT_ABS( (FT_Short)value );
568         }
569 
570         prop = bdf_get_font_property( font, "RESOLUTION_Y" );
571         if ( prop )
572           value = prop->value.l;
573         else
574           value = (long)font->resolution_y;
575         if ( value )
576         {
577 #ifdef FT_DEBUG_LEVEL_TRACE
578           if ( value < 0 )
579             FT_TRACE0(( "BDF_Face_Init: negative Y resolution\n" ));
580 #endif
581           if ( value > 0x7FFF || value < -0x7FFF )
582           {
583             resolution_y = 0x7FFF;
584             FT_TRACE0(( "BDF_Face_Init: clamping Y resolution to value %d\n",
585                         resolution_y ));
586           }
587           else
588             resolution_y = FT_ABS( (FT_Short)value );
589         }
590 
591         if ( bsize->y_ppem == 0 )
592         {
593           bsize->y_ppem = bsize->size;
594           if ( resolution_y )
595             bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 );
596         }
597         if ( resolution_x && resolution_y )
598           bsize->x_ppem = FT_MulDiv( bsize->y_ppem,
599                                      resolution_x,
600                                      resolution_y );
601         else
602           bsize->x_ppem = bsize->y_ppem;
603       }
604 
605       /* encoding table */
606       {
607         bdf_glyph_t*   cur = font->glyphs;
608         unsigned long  n;
609 
610 
611         if ( FT_NEW_ARRAY( face->en_table, font->glyphs_size ) )
612           goto Exit;
613 
614         face->default_glyph = 0;
615         for ( n = 0; n < font->glyphs_size; n++ )
616         {
617           (face->en_table[n]).enc = cur[n].encoding;
618           FT_TRACE4(( "  idx %d, val 0x%lX\n", n, cur[n].encoding ));
619           (face->en_table[n]).glyph = (FT_UShort)n;
620 
621           if ( cur[n].encoding == font->default_char )
622           {
623             if ( n < FT_UINT_MAX )
624               face->default_glyph = (FT_UInt)n;
625             else
626               FT_TRACE1(( "BDF_Face_Init:"
627                           " idx %d is too large for this system\n", n ));
628           }
629         }
630       }
631 
632       /* charmaps */
633       {
634         bdf_property_t  *charset_registry, *charset_encoding;
635         FT_Bool          unicode_charmap  = 0;
636 
637 
638         charset_registry =
639           bdf_get_font_property( font, "CHARSET_REGISTRY" );
640         charset_encoding =
641           bdf_get_font_property( font, "CHARSET_ENCODING" );
642         if ( charset_registry && charset_encoding )
643         {
644           if ( charset_registry->format == BDF_ATOM &&
645                charset_encoding->format == BDF_ATOM &&
646                charset_registry->value.atom         &&
647                charset_encoding->value.atom         )
648           {
649             const char*  s;
650 
651 
652             if ( FT_STRDUP( face->charset_encoding,
653                             charset_encoding->value.atom ) ||
654                  FT_STRDUP( face->charset_registry,
655                             charset_registry->value.atom ) )
656               goto Exit;
657 
658             /* Uh, oh, compare first letters manually to avoid dependency */
659             /* on locales.                                                */
660             s = face->charset_registry;
661             if ( ( s[0] == 'i' || s[0] == 'I' ) &&
662                  ( s[1] == 's' || s[1] == 'S' ) &&
663                  ( s[2] == 'o' || s[2] == 'O' ) )
664             {
665               s += 3;
666               if ( !ft_strcmp( s, "10646" )                      ||
667                    ( !ft_strcmp( s, "8859" ) &&
668                      !ft_strcmp( face->charset_encoding, "1" ) ) )
669                 unicode_charmap = 1;
670               /* another name for ASCII */
671               else if ( !ft_strcmp( s, "646.1991" )                 &&
672                         !ft_strcmp( face->charset_encoding, "IRV" ) )
673                 unicode_charmap = 1;
674             }
675 
676             {
677               FT_CharMapRec  charmap;
678 
679 
680               charmap.face        = FT_FACE( face );
681               charmap.encoding    = FT_ENCODING_NONE;
682               /* initial platform/encoding should indicate unset status? */
683               charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
684               charmap.encoding_id = TT_APPLE_ID_DEFAULT;
685 
686               if ( unicode_charmap )
687               {
688                 charmap.encoding    = FT_ENCODING_UNICODE;
689                 charmap.platform_id = TT_PLATFORM_MICROSOFT;
690                 charmap.encoding_id = TT_MS_ID_UNICODE_CS;
691               }
692 
693               error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
694             }
695 
696             goto Exit;
697           }
698         }
699 
700         /* otherwise assume Adobe standard encoding */
701 
702         {
703           FT_CharMapRec  charmap;
704 
705 
706           charmap.face        = FT_FACE( face );
707           charmap.encoding    = FT_ENCODING_ADOBE_STANDARD;
708           charmap.platform_id = TT_PLATFORM_ADOBE;
709           charmap.encoding_id = TT_ADOBE_ID_STANDARD;
710 
711           error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
712 
713           /* Select default charmap */
714           if ( bdfface->num_charmaps )
715             bdfface->charmap = bdfface->charmaps[0];
716         }
717       }
718     }
719 
720   Exit:
721     return error;
722 
723   Fail:
724     BDF_Face_Done( bdfface );
725     return FT_THROW( Unknown_File_Format );
726   }
727 
728 
729   FT_CALLBACK_DEF( FT_Error )
BDF_Size_Select(FT_Size size,FT_ULong strike_index)730   BDF_Size_Select( FT_Size   size,
731                    FT_ULong  strike_index )
732   {
733     bdf_font_t*  bdffont = ( (BDF_Face)size->face )->bdffont;
734 
735 
736     FT_Select_Metrics( size->face, strike_index );
737 
738     size->metrics.ascender    = bdffont->font_ascent * 64;
739     size->metrics.descender   = -bdffont->font_descent * 64;
740     size->metrics.max_advance = bdffont->bbx.width * 64;
741 
742     return FT_Err_Ok;
743   }
744 
745 
746   FT_CALLBACK_DEF( FT_Error )
BDF_Size_Request(FT_Size size,FT_Size_Request req)747   BDF_Size_Request( FT_Size          size,
748                     FT_Size_Request  req )
749   {
750     FT_Face          face    = size->face;
751     FT_Bitmap_Size*  bsize   = face->available_sizes;
752     bdf_font_t*      bdffont = ( (BDF_Face)face )->bdffont;
753     FT_Error         error   = FT_ERR( Invalid_Pixel_Size );
754     FT_Long          height;
755 
756 
757     height = FT_REQUEST_HEIGHT( req );
758     height = ( height + 32 ) >> 6;
759 
760     switch ( req->type )
761     {
762     case FT_SIZE_REQUEST_TYPE_NOMINAL:
763       if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) )
764         error = FT_Err_Ok;
765       break;
766 
767     case FT_SIZE_REQUEST_TYPE_REAL_DIM:
768       if ( height == ( bdffont->font_ascent +
769                        bdffont->font_descent ) )
770         error = FT_Err_Ok;
771       break;
772 
773     default:
774       error = FT_THROW( Unimplemented_Feature );
775       break;
776     }
777 
778     if ( error )
779       return error;
780     else
781       return BDF_Size_Select( size, 0 );
782   }
783 
784 
785 
786   FT_CALLBACK_DEF( FT_Error )
BDF_Glyph_Load(FT_GlyphSlot slot,FT_Size size,FT_UInt glyph_index,FT_Int32 load_flags)787   BDF_Glyph_Load( FT_GlyphSlot  slot,
788                   FT_Size       size,
789                   FT_UInt       glyph_index,
790                   FT_Int32      load_flags )
791   {
792     BDF_Face     bdf    = (BDF_Face)FT_SIZE_FACE( size );
793     FT_Face      face   = FT_FACE( bdf );
794     FT_Error     error  = FT_Err_Ok;
795     FT_Bitmap*   bitmap = &slot->bitmap;
796     bdf_glyph_t  glyph;
797     int          bpp    = bdf->bdffont->bpp;
798 
799     FT_UNUSED( load_flags );
800 
801 
802     if ( !face )
803     {
804       error = FT_THROW( Invalid_Face_Handle );
805       goto Exit;
806     }
807 
808     if ( glyph_index >= (FT_UInt)face->num_glyphs )
809     {
810       error = FT_THROW( Invalid_Argument );
811       goto Exit;
812     }
813 
814     FT_TRACE1(( "BDF_Glyph_Load: glyph index %d\n", glyph_index ));
815 
816     /* index 0 is the undefined glyph */
817     if ( glyph_index == 0 )
818       glyph_index = bdf->default_glyph;
819     else
820       glyph_index--;
821 
822     /* slot, bitmap => freetype, glyph => bdflib */
823     glyph = bdf->bdffont->glyphs[glyph_index];
824 
825     bitmap->rows  = glyph.bbx.height;
826     bitmap->width = glyph.bbx.width;
827     if ( glyph.bpr > FT_INT_MAX )
828       FT_TRACE1(( "BDF_Glyph_Load: too large pitch %d is truncated\n",
829                    glyph.bpr ));
830     bitmap->pitch = (int)glyph.bpr; /* same as FT_Bitmap.pitch */
831 
832     /* note: we don't allocate a new array to hold the bitmap; */
833     /*       we can simply point to it                         */
834     ft_glyphslot_set_bitmap( slot, glyph.bitmap );
835 
836     switch ( bpp )
837     {
838     case 1:
839       bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
840       break;
841     case 2:
842       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY2;
843       break;
844     case 4:
845       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY4;
846       break;
847     case 8:
848       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
849       bitmap->num_grays  = 256;
850       break;
851     }
852 
853     slot->format      = FT_GLYPH_FORMAT_BITMAP;
854     slot->bitmap_left = glyph.bbx.x_offset;
855     slot->bitmap_top  = glyph.bbx.ascent;
856 
857     slot->metrics.horiAdvance  = (FT_Pos)( glyph.dwidth * 64 );
858     slot->metrics.horiBearingX = (FT_Pos)( glyph.bbx.x_offset * 64 );
859     slot->metrics.horiBearingY = (FT_Pos)( glyph.bbx.ascent * 64 );
860     slot->metrics.width        = (FT_Pos)( bitmap->width * 64 );
861     slot->metrics.height       = (FT_Pos)( bitmap->rows * 64 );
862 
863     /*
864      * XXX DWIDTH1 and VVECTOR should be parsed and
865      * used here, provided such fonts do exist.
866      */
867     ft_synthesize_vertical_metrics( &slot->metrics,
868                                     bdf->bdffont->bbx.height * 64 );
869 
870   Exit:
871     return error;
872   }
873 
874 
875  /*
876   *
877   * BDF SERVICE
878   *
879   */
880 
881   static FT_Error
bdf_get_bdf_property(BDF_Face face,const char * prop_name,BDF_PropertyRec * aproperty)882   bdf_get_bdf_property( BDF_Face          face,
883                         const char*       prop_name,
884                         BDF_PropertyRec  *aproperty )
885   {
886     bdf_property_t*  prop;
887 
888 
889     FT_ASSERT( face && face->bdffont );
890 
891     prop = bdf_get_font_property( face->bdffont, prop_name );
892     if ( prop )
893     {
894       switch ( prop->format )
895       {
896       case BDF_ATOM:
897         aproperty->type   = BDF_PROPERTY_TYPE_ATOM;
898         aproperty->u.atom = prop->value.atom;
899         break;
900 
901       case BDF_INTEGER:
902         if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) )
903         {
904           FT_TRACE1(( "bdf_get_bdf_property:"
905                       " too large integer 0x%x is truncated\n" ));
906         }
907         aproperty->type      = BDF_PROPERTY_TYPE_INTEGER;
908         aproperty->u.integer = (FT_Int32)prop->value.l;
909         break;
910 
911       case BDF_CARDINAL:
912         if ( prop->value.ul > 0xFFFFFFFFUL )
913         {
914           FT_TRACE1(( "bdf_get_bdf_property:"
915                       " too large cardinal 0x%x is truncated\n" ));
916         }
917         aproperty->type       = BDF_PROPERTY_TYPE_CARDINAL;
918         aproperty->u.cardinal = (FT_UInt32)prop->value.ul;
919         break;
920 
921       default:
922         goto Fail;
923       }
924       return 0;
925     }
926 
927   Fail:
928     return FT_THROW( Invalid_Argument );
929   }
930 
931 
932   static FT_Error
bdf_get_charset_id(BDF_Face face,const char ** acharset_encoding,const char ** acharset_registry)933   bdf_get_charset_id( BDF_Face      face,
934                       const char*  *acharset_encoding,
935                       const char*  *acharset_registry )
936   {
937     *acharset_encoding = face->charset_encoding;
938     *acharset_registry = face->charset_registry;
939 
940     return 0;
941   }
942 
943 
944   static const FT_Service_BDFRec  bdf_service_bdf =
945   {
946     (FT_BDF_GetCharsetIdFunc)bdf_get_charset_id,       /* get_charset_id */
947     (FT_BDF_GetPropertyFunc) bdf_get_bdf_property      /* get_property   */
948   };
949 
950 
951  /*
952   *
953   * SERVICES LIST
954   *
955   */
956 
957   static const FT_ServiceDescRec  bdf_services[] =
958   {
959     { FT_SERVICE_ID_BDF,         &bdf_service_bdf },
960     { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_BDF },
961     { NULL, NULL }
962   };
963 
964 
965   FT_CALLBACK_DEF( FT_Module_Interface )
bdf_driver_requester(FT_Module module,const char * name)966   bdf_driver_requester( FT_Module    module,
967                         const char*  name )
968   {
969     FT_UNUSED( module );
970 
971     return ft_service_list_lookup( bdf_services, name );
972   }
973 
974 
975 
976   FT_CALLBACK_TABLE_DEF
977   const FT_Driver_ClassRec  bdf_driver_class =
978   {
979     {
980       FT_MODULE_FONT_DRIVER         |
981       FT_MODULE_DRIVER_NO_OUTLINES,
982       sizeof ( FT_DriverRec ),
983 
984       "bdf",
985       0x10000L,
986       0x20000L,
987 
988       NULL,    /* module-specific interface */
989 
990       NULL,                     /* FT_Module_Constructor  module_init   */
991       NULL,                     /* FT_Module_Destructor   module_done   */
992       bdf_driver_requester      /* FT_Module_Requester    get_interface */
993     },
994 
995     sizeof ( BDF_FaceRec ),
996     sizeof ( FT_SizeRec ),
997     sizeof ( FT_GlyphSlotRec ),
998 
999     BDF_Face_Init,              /* FT_Face_InitFunc  init_face */
1000     BDF_Face_Done,              /* FT_Face_DoneFunc  done_face */
1001     NULL,                       /* FT_Size_InitFunc  init_size */
1002     NULL,                       /* FT_Size_DoneFunc  done_size */
1003     NULL,                       /* FT_Slot_InitFunc  init_slot */
1004     NULL,                       /* FT_Slot_DoneFunc  done_slot */
1005 
1006     BDF_Glyph_Load,             /* FT_Slot_LoadFunc  load_glyph */
1007 
1008     NULL,                       /* FT_Face_GetKerningFunc   get_kerning  */
1009     NULL,                       /* FT_Face_AttachFunc       attach_file  */
1010     NULL,                       /* FT_Face_GetAdvancesFunc  get_advances */
1011 
1012     BDF_Size_Request,           /* FT_Size_RequestFunc  request_size */
1013     BDF_Size_Select             /* FT_Size_SelectFunc   select_size  */
1014   };
1015 
1016 
1017 /* END */
1018