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