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 
28 #include <freetype/internal/ftdebug.h>
29 #include <freetype/internal/ftstream.h>
30 #include <freetype/internal/ftobjs.h>
31 #include <freetype/ftbdf.h>
32 #include <freetype/ttnameid.h>
33 
34 #include <freetype/internal/services/svbdf.h>
35 #include <freetype/internal/services/svfntfmt.h>
36 
37 #include "bdf.h"
38 #include "bdfdrivr.h"
39 
40 #include "bdferror.h"
41 
42 
43   /**************************************************************************
44    *
45    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
46    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
47    * messages during execution.
48    */
49 #undef  FT_COMPONENT
50 #define FT_COMPONENT  bdfdriver
51 
52 
53   typedef struct  BDF_CMapRec_
54   {
55     FT_CMapRec        cmap;
56     FT_ULong          num_encodings; /* ftobjs.h: FT_CMap->clazz->size */
57     BDF_encoding_el*  encodings;
58 
59   } BDF_CMapRec, *BDF_CMap;
60 
61 
62   FT_CALLBACK_DEF( FT_Error )
bdf_cmap_init(FT_CMap bdfcmap,FT_Pointer init_data)63   bdf_cmap_init( FT_CMap     bdfcmap,
64                  FT_Pointer  init_data )
65   {
66     BDF_CMap  cmap = (BDF_CMap)bdfcmap;
67     BDF_Face  face = (BDF_Face)FT_CMAP_FACE( cmap );
68     FT_UNUSED( init_data );
69 
70 
71     cmap->num_encodings = face->bdffont->glyphs_used;
72     cmap->encodings     = face->en_table;
73 
74     return FT_Err_Ok;
75   }
76 
77 
78   FT_CALLBACK_DEF( void )
bdf_cmap_done(FT_CMap bdfcmap)79   bdf_cmap_done( FT_CMap  bdfcmap )
80   {
81     BDF_CMap  cmap = (BDF_CMap)bdfcmap;
82 
83 
84     cmap->encodings     = NULL;
85     cmap->num_encodings = 0;
86   }
87 
88 
89   FT_CALLBACK_DEF( FT_UInt )
bdf_cmap_char_index(FT_CMap bdfcmap,FT_UInt32 charcode)90   bdf_cmap_char_index( FT_CMap    bdfcmap,
91                        FT_UInt32  charcode )
92   {
93     BDF_CMap          cmap      = (BDF_CMap)bdfcmap;
94     BDF_encoding_el*  encodings = cmap->encodings;
95     FT_ULong          min, max, mid; /* num_encodings */
96     FT_UShort         result    = 0; /* encodings->glyph */
97 
98 
99     min = 0;
100     max = cmap->num_encodings;
101     mid = ( min + max ) >> 1;
102 
103     while ( min < max )
104     {
105       FT_ULong  code;
106 
107 
108       if ( mid >= max || mid < min )
109         mid = ( min + max ) >> 1;
110 
111       code = encodings[mid].enc;
112 
113       if ( charcode == code )
114       {
115         /* increase glyph index by 1 --              */
116         /* we reserve slot 0 for the undefined glyph */
117         result = encodings[mid].glyph + 1;
118         break;
119       }
120 
121       if ( charcode < code )
122         max = mid;
123       else
124         min = mid + 1;
125 
126       /* prediction in a continuous block */
127       mid += charcode - code;
128     }
129 
130     return result;
131   }
132 
133 
134   FT_CALLBACK_DEF( FT_UInt )
bdf_cmap_char_next(FT_CMap bdfcmap,FT_UInt32 * acharcode)135   bdf_cmap_char_next( FT_CMap     bdfcmap,
136                       FT_UInt32  *acharcode )
137   {
138     BDF_CMap          cmap      = (BDF_CMap)bdfcmap;
139     BDF_encoding_el*  encodings = cmap->encodings;
140     FT_ULong          min, max, mid; /* num_encodings */
141     FT_UShort         result   = 0;  /* encodings->glyph */
142     FT_ULong          charcode = *acharcode + 1;
143 
144 
145     min = 0;
146     max = cmap->num_encodings;
147     mid = ( min + max ) >> 1;
148 
149     while ( min < max )
150     {
151       FT_ULong  code; /* same as BDF_encoding_el.enc */
152 
153 
154       if ( mid >= max || mid < min )
155         mid = ( min + max ) >> 1;
156 
157       code = encodings[mid].enc;
158 
159       if ( charcode == code )
160       {
161         /* increase glyph index by 1 --              */
162         /* we reserve slot 0 for the undefined glyph */
163         result = encodings[mid].glyph + 1;
164         goto Exit;
165       }
166 
167       if ( charcode < code )
168         max = mid;
169       else
170         min = mid + 1;
171 
172       /* prediction in a continuous block */
173       mid += charcode - code;
174     }
175 
176     charcode = 0;
177     if ( min < cmap->num_encodings )
178     {
179       charcode = encodings[min].enc;
180       result   = encodings[min].glyph + 1;
181     }
182 
183   Exit:
184     if ( charcode > 0xFFFFFFFFUL )
185     {
186       FT_TRACE1(( "bdf_cmap_char_next: charcode 0x%lx > 32bit API",
187                   charcode ));
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 %ld (used %ld)\n",
406                   font->glyphs_size,
407                   font->glyphs_used ));
408       FT_TRACE4(( "  number of unencoded glyphs: allocated %ld (used %ld)\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 %ld\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 %ld\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 %ld\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 %ld\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 %ld\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 %ld, 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 %ld 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 %ld 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%lx is truncated\n",
906                       prop->value.l ));
907         }
908         aproperty->type      = BDF_PROPERTY_TYPE_INTEGER;
909         aproperty->u.integer = (FT_Int32)prop->value.l;
910         break;
911 
912       case BDF_CARDINAL:
913         if ( prop->value.ul > 0xFFFFFFFFUL )
914         {
915           FT_TRACE1(( "bdf_get_bdf_property:"
916                       " too large cardinal 0x%lx is truncated\n",
917                       prop->value.ul ));
918         }
919         aproperty->type       = BDF_PROPERTY_TYPE_CARDINAL;
920         aproperty->u.cardinal = (FT_UInt32)prop->value.ul;
921         break;
922 
923       default:
924         goto Fail;
925       }
926       return 0;
927     }
928 
929   Fail:
930     return FT_THROW( Invalid_Argument );
931   }
932 
933 
934   static FT_Error
bdf_get_charset_id(BDF_Face face,const char ** acharset_encoding,const char ** acharset_registry)935   bdf_get_charset_id( BDF_Face      face,
936                       const char*  *acharset_encoding,
937                       const char*  *acharset_registry )
938   {
939     *acharset_encoding = face->charset_encoding;
940     *acharset_registry = face->charset_registry;
941 
942     return 0;
943   }
944 
945 
946   static const FT_Service_BDFRec  bdf_service_bdf =
947   {
948     (FT_BDF_GetCharsetIdFunc)bdf_get_charset_id,       /* get_charset_id */
949     (FT_BDF_GetPropertyFunc) bdf_get_bdf_property      /* get_property   */
950   };
951 
952 
953  /*
954   *
955   * SERVICES LIST
956   *
957   */
958 
959   static const FT_ServiceDescRec  bdf_services[] =
960   {
961     { FT_SERVICE_ID_BDF,         &bdf_service_bdf },
962     { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_BDF },
963     { NULL, NULL }
964   };
965 
966 
967   FT_CALLBACK_DEF( FT_Module_Interface )
bdf_driver_requester(FT_Module module,const char * name)968   bdf_driver_requester( FT_Module    module,
969                         const char*  name )
970   {
971     FT_UNUSED( module );
972 
973     return ft_service_list_lookup( bdf_services, name );
974   }
975 
976 
977 
978   FT_CALLBACK_TABLE_DEF
979   const FT_Driver_ClassRec  bdf_driver_class =
980   {
981     {
982       FT_MODULE_FONT_DRIVER         |
983       FT_MODULE_DRIVER_NO_OUTLINES,
984       sizeof ( FT_DriverRec ),
985 
986       "bdf",
987       0x10000L,
988       0x20000L,
989 
990       NULL,    /* module-specific interface */
991 
992       NULL,                     /* FT_Module_Constructor  module_init   */
993       NULL,                     /* FT_Module_Destructor   module_done   */
994       bdf_driver_requester      /* FT_Module_Requester    get_interface */
995     },
996 
997     sizeof ( BDF_FaceRec ),
998     sizeof ( FT_SizeRec ),
999     sizeof ( FT_GlyphSlotRec ),
1000 
1001     BDF_Face_Init,              /* FT_Face_InitFunc  init_face */
1002     BDF_Face_Done,              /* FT_Face_DoneFunc  done_face */
1003     NULL,                       /* FT_Size_InitFunc  init_size */
1004     NULL,                       /* FT_Size_DoneFunc  done_size */
1005     NULL,                       /* FT_Slot_InitFunc  init_slot */
1006     NULL,                       /* FT_Slot_DoneFunc  done_slot */
1007 
1008     BDF_Glyph_Load,             /* FT_Slot_LoadFunc  load_glyph */
1009 
1010     NULL,                       /* FT_Face_GetKerningFunc   get_kerning  */
1011     NULL,                       /* FT_Face_AttachFunc       attach_file  */
1012     NULL,                       /* FT_Face_GetAdvancesFunc  get_advances */
1013 
1014     BDF_Size_Request,           /* FT_Size_RequestFunc  request_size */
1015     BDF_Size_Select             /* FT_Size_SelectFunc   select_size  */
1016   };
1017 
1018 
1019 /* END */
1020