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_QALLOC( 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( bdfface->available_sizes ) )
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         /* sanity checks */
455         if ( font->font_ascent > 0x7FFF || font->font_ascent < -0x7FFF )
456         {
457           font->font_ascent = font->font_ascent < 0 ? -0x7FFF : 0x7FFF;
458           FT_TRACE0(( "BDF_Face_Init: clamping font ascent to value %ld\n",
459                       font->font_ascent ));
460         }
461         if ( font->font_descent > 0x7FFF || font->font_descent < -0x7FFF )
462         {
463           font->font_descent = font->font_descent < 0 ? -0x7FFF : 0x7FFF;
464           FT_TRACE0(( "BDF_Face_Init: clamping font descent to value %ld\n",
465                       font->font_descent ));
466         }
467 
468         bsize->height = (FT_Short)( font->font_ascent + font->font_descent );
469 
470         prop = bdf_get_font_property( font, "AVERAGE_WIDTH" );
471         if ( prop )
472         {
473 #ifdef FT_DEBUG_LEVEL_TRACE
474           if ( prop->value.l < 0 )
475             FT_TRACE0(( "BDF_Face_Init: negative average width\n" ));
476 #endif
477           if ( prop->value.l >    0x7FFFL * 10 - 5   ||
478                prop->value.l < -( 0x7FFFL * 10 - 5 ) )
479           {
480             bsize->width = 0x7FFF;
481             FT_TRACE0(( "BDF_Face_Init: clamping average width to value %d\n",
482                         bsize->width ));
483           }
484           else
485             bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) );
486         }
487         else
488         {
489           /* this is a heuristical value */
490           bsize->width = ( bsize->height * 2 + 1 ) / 3;
491         }
492 
493         prop = bdf_get_font_property( font, "POINT_SIZE" );
494         if ( prop )
495         {
496 #ifdef FT_DEBUG_LEVEL_TRACE
497           if ( prop->value.l < 0 )
498             FT_TRACE0(( "BDF_Face_Init: negative point size\n" ));
499 #endif
500           /* convert from 722.7 decipoints to 72 points per inch */
501           if ( prop->value.l >  0x504C2L || /* 0x7FFF * 72270/7200 */
502                prop->value.l < -0x504C2L )
503           {
504             bsize->size = 0x7FFF;
505             FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n",
506                         bsize->size ));
507           }
508           else
509             bsize->size = FT_MulDiv( FT_ABS( prop->value.l ),
510                                      64 * 7200,
511                                      72270L );
512         }
513         else if ( font->point_size )
514         {
515           if ( font->point_size > 0x7FFF )
516           {
517             bsize->size = 0x7FFF;
518             FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n",
519                         bsize->size ));
520           }
521           else
522             bsize->size = (FT_Pos)font->point_size << 6;
523         }
524         else
525         {
526           /* this is a heuristical value */
527           bsize->size = bsize->width * 64;
528         }
529 
530         prop = bdf_get_font_property( font, "PIXEL_SIZE" );
531         if ( prop )
532         {
533 #ifdef FT_DEBUG_LEVEL_TRACE
534           if ( prop->value.l < 0 )
535             FT_TRACE0(( "BDF_Face_Init: negative pixel size\n" ));
536 #endif
537           if ( prop->value.l > 0x7FFF || prop->value.l < -0x7FFF )
538           {
539             bsize->y_ppem = 0x7FFF << 6;
540             FT_TRACE0(( "BDF_Face_Init: clamping pixel size to value %ld\n",
541                         bsize->y_ppem ));
542           }
543           else
544             bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6;
545         }
546 
547         prop = bdf_get_font_property( font, "RESOLUTION_X" );
548         if ( prop )
549           value = prop->value.l;
550         else
551           value = (long)font->resolution_x;
552         if ( value )
553         {
554 #ifdef FT_DEBUG_LEVEL_TRACE
555           if ( value < 0 )
556             FT_TRACE0(( "BDF_Face_Init: negative X resolution\n" ));
557 #endif
558           if ( value > 0x7FFF || value < -0x7FFF )
559           {
560             resolution_x = 0x7FFF;
561             FT_TRACE0(( "BDF_Face_Init: clamping X resolution to value %d\n",
562                         resolution_x ));
563           }
564           else
565             resolution_x = FT_ABS( (FT_Short)value );
566         }
567 
568         prop = bdf_get_font_property( font, "RESOLUTION_Y" );
569         if ( prop )
570           value = prop->value.l;
571         else
572           value = (long)font->resolution_y;
573         if ( value )
574         {
575 #ifdef FT_DEBUG_LEVEL_TRACE
576           if ( value < 0 )
577             FT_TRACE0(( "BDF_Face_Init: negative Y resolution\n" ));
578 #endif
579           if ( value > 0x7FFF || value < -0x7FFF )
580           {
581             resolution_y = 0x7FFF;
582             FT_TRACE0(( "BDF_Face_Init: clamping Y resolution to value %d\n",
583                         resolution_y ));
584           }
585           else
586             resolution_y = FT_ABS( (FT_Short)value );
587         }
588 
589         if ( bsize->y_ppem == 0 )
590         {
591           bsize->y_ppem = bsize->size;
592           if ( resolution_y )
593             bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 );
594         }
595         if ( resolution_x && resolution_y )
596           bsize->x_ppem = FT_MulDiv( bsize->y_ppem,
597                                      resolution_x,
598                                      resolution_y );
599         else
600           bsize->x_ppem = bsize->y_ppem;
601       }
602 
603       /* encoding table */
604       {
605         bdf_glyph_t*   cur = font->glyphs;
606         unsigned long  n;
607 
608 
609         if ( FT_QNEW_ARRAY( face->en_table, font->glyphs_size ) )
610           goto Exit;
611 
612         face->default_glyph = 0;
613         for ( n = 0; n < font->glyphs_size; n++ )
614         {
615           (face->en_table[n]).enc = cur[n].encoding;
616           FT_TRACE4(( "  idx %ld, val 0x%lX\n", n, cur[n].encoding ));
617           (face->en_table[n]).glyph = (FT_UShort)n;
618 
619           if ( cur[n].encoding == font->default_char )
620           {
621             if ( n < FT_UINT_MAX )
622               face->default_glyph = (FT_UInt)n;
623             else
624               FT_TRACE1(( "BDF_Face_Init:"
625                           " idx %ld is too large for this system\n", n ));
626           }
627         }
628       }
629 
630       /* charmaps */
631       {
632         bdf_property_t  *charset_registry, *charset_encoding;
633         FT_Bool          unicode_charmap  = 0;
634 
635 
636         charset_registry =
637           bdf_get_font_property( font, "CHARSET_REGISTRY" );
638         charset_encoding =
639           bdf_get_font_property( font, "CHARSET_ENCODING" );
640         if ( charset_registry && charset_encoding )
641         {
642           if ( charset_registry->format == BDF_ATOM &&
643                charset_encoding->format == BDF_ATOM &&
644                charset_registry->value.atom         &&
645                charset_encoding->value.atom         )
646           {
647             const char*  s;
648 
649 
650             if ( FT_STRDUP( face->charset_encoding,
651                             charset_encoding->value.atom ) ||
652                  FT_STRDUP( face->charset_registry,
653                             charset_registry->value.atom ) )
654               goto Exit;
655 
656             /* Uh, oh, compare first letters manually to avoid dependency */
657             /* on locales.                                                */
658             s = face->charset_registry;
659             if ( ( s[0] == 'i' || s[0] == 'I' ) &&
660                  ( s[1] == 's' || s[1] == 'S' ) &&
661                  ( s[2] == 'o' || s[2] == 'O' ) )
662             {
663               s += 3;
664               if ( !ft_strcmp( s, "10646" )                      ||
665                    ( !ft_strcmp( s, "8859" ) &&
666                      !ft_strcmp( face->charset_encoding, "1" ) ) )
667                 unicode_charmap = 1;
668               /* another name for ASCII */
669               else if ( !ft_strcmp( s, "646.1991" )                 &&
670                         !ft_strcmp( face->charset_encoding, "IRV" ) )
671                 unicode_charmap = 1;
672             }
673 
674             {
675               FT_CharMapRec  charmap;
676 
677 
678               charmap.face        = FT_FACE( face );
679               charmap.encoding    = FT_ENCODING_NONE;
680               /* initial platform/encoding should indicate unset status? */
681               charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
682               charmap.encoding_id = TT_APPLE_ID_DEFAULT;
683 
684               if ( unicode_charmap )
685               {
686                 charmap.encoding    = FT_ENCODING_UNICODE;
687                 charmap.platform_id = TT_PLATFORM_MICROSOFT;
688                 charmap.encoding_id = TT_MS_ID_UNICODE_CS;
689               }
690 
691               error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
692             }
693 
694             goto Exit;
695           }
696         }
697 
698         /* otherwise assume Adobe standard encoding */
699 
700         {
701           FT_CharMapRec  charmap;
702 
703 
704           charmap.face        = FT_FACE( face );
705           charmap.encoding    = FT_ENCODING_ADOBE_STANDARD;
706           charmap.platform_id = TT_PLATFORM_ADOBE;
707           charmap.encoding_id = TT_ADOBE_ID_STANDARD;
708 
709           error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
710 
711           /* Select default charmap */
712           if ( bdfface->num_charmaps )
713             bdfface->charmap = bdfface->charmaps[0];
714         }
715       }
716     }
717 
718   Exit:
719     return error;
720 
721   Fail:
722     BDF_Face_Done( bdfface );
723     return FT_THROW( Unknown_File_Format );
724   }
725 
726 
727   FT_CALLBACK_DEF( FT_Error )
BDF_Size_Select(FT_Size size,FT_ULong strike_index)728   BDF_Size_Select( FT_Size   size,
729                    FT_ULong  strike_index )
730   {
731     bdf_font_t*  bdffont = ( (BDF_Face)size->face )->bdffont;
732 
733 
734     FT_Select_Metrics( size->face, strike_index );
735 
736     size->metrics.ascender    = bdffont->font_ascent * 64;
737     size->metrics.descender   = -bdffont->font_descent * 64;
738     size->metrics.max_advance = bdffont->bbx.width * 64;
739 
740     return FT_Err_Ok;
741   }
742 
743 
744   FT_CALLBACK_DEF( FT_Error )
BDF_Size_Request(FT_Size size,FT_Size_Request req)745   BDF_Size_Request( FT_Size          size,
746                     FT_Size_Request  req )
747   {
748     FT_Face          face    = size->face;
749     FT_Bitmap_Size*  bsize   = face->available_sizes;
750     bdf_font_t*      bdffont = ( (BDF_Face)face )->bdffont;
751     FT_Error         error   = FT_ERR( Invalid_Pixel_Size );
752     FT_Long          height;
753 
754 
755     height = FT_REQUEST_HEIGHT( req );
756     height = ( height + 32 ) >> 6;
757 
758     switch ( req->type )
759     {
760     case FT_SIZE_REQUEST_TYPE_NOMINAL:
761       if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) )
762         error = FT_Err_Ok;
763       break;
764 
765     case FT_SIZE_REQUEST_TYPE_REAL_DIM:
766       if ( height == ( bdffont->font_ascent +
767                        bdffont->font_descent ) )
768         error = FT_Err_Ok;
769       break;
770 
771     default:
772       error = FT_THROW( Unimplemented_Feature );
773       break;
774     }
775 
776     if ( error )
777       return error;
778     else
779       return BDF_Size_Select( size, 0 );
780   }
781 
782 
783 
784   FT_CALLBACK_DEF( FT_Error )
BDF_Glyph_Load(FT_GlyphSlot slot,FT_Size size,FT_UInt glyph_index,FT_Int32 load_flags)785   BDF_Glyph_Load( FT_GlyphSlot  slot,
786                   FT_Size       size,
787                   FT_UInt       glyph_index,
788                   FT_Int32      load_flags )
789   {
790     BDF_Face     bdf    = (BDF_Face)FT_SIZE_FACE( size );
791     FT_Face      face   = FT_FACE( bdf );
792     FT_Error     error  = FT_Err_Ok;
793     FT_Bitmap*   bitmap = &slot->bitmap;
794     bdf_glyph_t  glyph;
795     int          bpp    = bdf->bdffont->bpp;
796 
797     FT_UNUSED( load_flags );
798 
799 
800     if ( !face )
801     {
802       error = FT_THROW( Invalid_Face_Handle );
803       goto Exit;
804     }
805 
806     if ( glyph_index >= (FT_UInt)face->num_glyphs )
807     {
808       error = FT_THROW( Invalid_Argument );
809       goto Exit;
810     }
811 
812     FT_TRACE1(( "BDF_Glyph_Load: glyph index %d\n", glyph_index ));
813 
814     /* index 0 is the undefined glyph */
815     if ( glyph_index == 0 )
816       glyph_index = bdf->default_glyph;
817     else
818       glyph_index--;
819 
820     /* slot, bitmap => freetype, glyph => bdflib */
821     glyph = bdf->bdffont->glyphs[glyph_index];
822 
823     bitmap->rows  = glyph.bbx.height;
824     bitmap->width = glyph.bbx.width;
825     if ( glyph.bpr > FT_INT_MAX )
826       FT_TRACE1(( "BDF_Glyph_Load: too large pitch %ld is truncated\n",
827                    glyph.bpr ));
828     bitmap->pitch = (int)glyph.bpr; /* same as FT_Bitmap.pitch */
829 
830     /* note: we don't allocate a new array to hold the bitmap; */
831     /*       we can simply point to it                         */
832     ft_glyphslot_set_bitmap( slot, glyph.bitmap );
833 
834     switch ( bpp )
835     {
836     case 1:
837       bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
838       break;
839     case 2:
840       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY2;
841       break;
842     case 4:
843       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY4;
844       break;
845     case 8:
846       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
847       bitmap->num_grays  = 256;
848       break;
849     }
850 
851     slot->format      = FT_GLYPH_FORMAT_BITMAP;
852     slot->bitmap_left = glyph.bbx.x_offset;
853     slot->bitmap_top  = glyph.bbx.ascent;
854 
855     slot->metrics.horiAdvance  = (FT_Pos)( glyph.dwidth * 64 );
856     slot->metrics.horiBearingX = (FT_Pos)( glyph.bbx.x_offset * 64 );
857     slot->metrics.horiBearingY = (FT_Pos)( glyph.bbx.ascent * 64 );
858     slot->metrics.width        = (FT_Pos)( bitmap->width * 64 );
859     slot->metrics.height       = (FT_Pos)( bitmap->rows * 64 );
860 
861     /*
862      * XXX DWIDTH1 and VVECTOR should be parsed and
863      * used here, provided such fonts do exist.
864      */
865     ft_synthesize_vertical_metrics( &slot->metrics,
866                                     bdf->bdffont->bbx.height * 64 );
867 
868   Exit:
869     return error;
870   }
871 
872 
873  /*
874   *
875   * BDF SERVICE
876   *
877   */
878 
879   static FT_Error
bdf_get_bdf_property(BDF_Face face,const char * prop_name,BDF_PropertyRec * aproperty)880   bdf_get_bdf_property( BDF_Face          face,
881                         const char*       prop_name,
882                         BDF_PropertyRec  *aproperty )
883   {
884     bdf_property_t*  prop;
885 
886 
887     FT_ASSERT( face && face->bdffont );
888 
889     prop = bdf_get_font_property( face->bdffont, prop_name );
890     if ( prop )
891     {
892       switch ( prop->format )
893       {
894       case BDF_ATOM:
895         aproperty->type   = BDF_PROPERTY_TYPE_ATOM;
896         aproperty->u.atom = prop->value.atom;
897         break;
898 
899       case BDF_INTEGER:
900         if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) )
901         {
902           FT_TRACE1(( "bdf_get_bdf_property:"
903                       " too large integer 0x%lx is truncated\n",
904                       prop->value.l ));
905         }
906         aproperty->type      = BDF_PROPERTY_TYPE_INTEGER;
907         aproperty->u.integer = (FT_Int32)prop->value.l;
908         break;
909 
910       case BDF_CARDINAL:
911         if ( prop->value.ul > 0xFFFFFFFFUL )
912         {
913           FT_TRACE1(( "bdf_get_bdf_property:"
914                       " too large cardinal 0x%lx is truncated\n",
915                       prop->value.ul ));
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