update for HEAD-2003050101
[reactos.git] / lib / freetype / src / bdf / bdfdrivr.c
1 /*  bdfdrivr.c
2
3     FreeType font driver for bdf files
4
5     Copyright (C) 2001-2002 by
6     Francesco Zappa Nardelli
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 THE SOFTWARE.
25 */
26
27 #include <ft2build.h>
28
29 #include FT_INTERNAL_DEBUG_H
30 #include FT_INTERNAL_STREAM_H
31 #include FT_INTERNAL_OBJECTS_H
32 #include FT_BDF_H
33
34 #include "bdf.h"
35 #include "bdfdrivr.h"
36
37 #include "bdferror.h"
38
39
40   /*************************************************************************/
41   /*                                                                       */
42   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
43   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
44   /* messages during execution.                                            */
45   /*                                                                       */
46 #undef  FT_COMPONENT
47 #define FT_COMPONENT  trace_bdfdriver
48
49
50   typedef struct  BDF_CMapRec_
51   {
52     FT_CMapRec        cmap;
53     FT_UInt           num_encodings;
54     BDF_encoding_el*  encodings;
55
56   } BDF_CMapRec, *BDF_CMap;
57
58
59   FT_CALLBACK_DEF( FT_Error )
60   bdf_cmap_init( BDF_CMap  cmap )
61   {
62     BDF_Face  face = (BDF_Face)FT_CMAP_FACE( cmap );
63
64
65     cmap->num_encodings = face->bdffont->glyphs_used;
66     cmap->encodings     = face->en_table;
67
68     return FT_Err_Ok;
69   }
70
71
72   FT_CALLBACK_DEF( void )
73   bdf_cmap_done( BDF_CMap  cmap )
74   {
75     cmap->encodings     = NULL;
76     cmap->num_encodings = 0;
77   }
78
79
80   FT_CALLBACK_DEF( FT_UInt )
81   bdf_cmap_char_index( BDF_CMap   cmap,
82                        FT_UInt32  charcode )
83   {
84     BDF_encoding_el*  encodings = cmap->encodings;
85     FT_UInt           min, max, mid;
86     FT_UInt           result = 0;
87
88
89     min = 0;
90     max = cmap->num_encodings;
91
92     while ( min < max )
93     {
94       FT_UInt32  code;
95
96
97       mid  = ( min + max ) >> 1;
98       code = encodings[mid].enc;
99
100       if ( charcode == code )
101       {
102         result = encodings[mid].glyph + 1;
103         break;
104       }
105
106       if ( charcode < code )
107         max = mid;
108       else
109         min = mid + 1;
110     }
111
112     return result;
113   }
114
115
116   FT_CALLBACK_DEF( FT_UInt )
117   bdf_cmap_char_next( BDF_CMap    cmap,
118                       FT_UInt32  *acharcode )
119   {
120     BDF_encoding_el*  encodings = cmap->encodings;
121     FT_UInt           min, max, mid;
122     FT_UInt32         charcode = *acharcode + 1;
123     FT_UInt           result   = 0;
124
125
126     min = 0;
127     max = cmap->num_encodings;
128
129     while ( min < max )
130     {
131       FT_UInt32  code;
132
133
134       mid  = ( min + max ) >> 1;
135       code = encodings[mid].enc;
136
137       if ( charcode == code )
138       {
139         result = encodings[mid].glyph + 1;
140         goto Exit;
141       }
142
143       if ( charcode < code )
144         max = mid;
145       else
146         min = mid + 1;
147     }
148
149     charcode = 0;
150     if ( min < cmap->num_encodings )
151     {
152       charcode = encodings[min].enc;
153       result   = encodings[min].glyph + 1;
154     }
155
156   Exit:
157     *acharcode = charcode;
158     return result;
159   }
160
161
162   FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec  bdf_cmap_class =
163   {
164     sizeof( BDF_CMapRec ),
165     (FT_CMap_InitFunc)     bdf_cmap_init,
166     (FT_CMap_DoneFunc)     bdf_cmap_done,
167     (FT_CMap_CharIndexFunc)bdf_cmap_char_index,
168     (FT_CMap_CharNextFunc) bdf_cmap_char_next
169   };
170
171
172
173
174   FT_CALLBACK_DEF( FT_Error )
175   BDF_Face_Done( BDF_Face  face )
176   {
177     FT_Memory  memory = FT_FACE_MEMORY( face );
178
179
180     bdf_free_font( face->bdffont );
181
182     FT_FREE( face->en_table );
183
184     FT_FREE( face->charset_encoding );
185     FT_FREE( face->charset_registry );
186     FT_FREE( face->root.family_name );
187
188     FT_FREE( face->root.available_sizes );
189
190     FT_FREE( face->bdffont );
191
192     FT_TRACE4(( "BDF_Face_Done: done face\n" ));
193
194     return BDF_Err_Ok;
195   }
196
197
198   FT_CALLBACK_DEF( FT_Error )
199   BDF_Face_Init( FT_Stream      stream,
200                  BDF_Face       face,
201                  FT_Int         face_index,
202                  FT_Int         num_params,
203                  FT_Parameter*  params )
204   {
205     FT_Error       error  = BDF_Err_Ok;
206     FT_Memory      memory = FT_FACE_MEMORY( face );
207
208     bdf_font_t*    font;
209     bdf_options_t  options;
210
211     FT_UNUSED( num_params );
212     FT_UNUSED( params );
213     FT_UNUSED( face_index );
214
215
216     if ( FT_STREAM_SEEK( 0 ) )
217       goto Exit;
218
219     options.correct_metrics = 1;   /* FZ XXX: options semantics */
220     options.keep_unencoded  = 1;
221     options.keep_comments   = 0;
222     options.font_spacing    = BDF_PROPORTIONAL;
223
224     error = bdf_load_font( stream, memory, &options, &font );
225     if ( error == BDF_Err_Missing_Startfont_Field )
226     {
227       FT_TRACE2(( "[not a valid BDF file]\n" ));
228       goto Fail;
229     }
230     else if ( error )
231       goto Exit;
232
233     /* we have a bdf font: let's construct the face object */
234     face->bdffont = font;
235     {
236       FT_Face          root = FT_FACE( face );
237       bdf_property_t*  prop = NULL;
238
239
240       FT_TRACE4(( "number of glyphs: %d (%d)\n",
241                   font->glyphs_size,
242                   font->glyphs_used ));
243       FT_TRACE4(( "number of unencoded glyphs: %d (%d)\n",
244                   font->unencoded_size,
245                   font->unencoded_used ));
246
247       root->num_faces  = 1;
248       root->face_index = 0;
249       root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
250                          FT_FACE_FLAG_HORIZONTAL  |
251                          FT_FACE_FLAG_FAST_GLYPHS;
252
253       prop = bdf_get_font_property( font, (char *)"SPACING" );
254       if ( prop != NULL )
255         if ( prop->format == BDF_ATOM )
256           if ( prop->value.atom != NULL )
257             if ( ( *(prop->value.atom) == 'M' ) ||
258                  ( *(prop->value.atom) == 'C' ) )
259               root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
260
261       /* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL   */
262       /* FZ XXX: I need a font to implement this */
263
264       root->style_flags = 0;
265       prop = bdf_get_font_property( font, (char *)"SLANT" );
266       if ( prop != NULL )
267         if ( prop->format == BDF_ATOM )
268           if ( prop->value.atom != NULL )
269             if ( ( *(prop->value.atom) == 'O' ) ||
270                  ( *(prop->value.atom) == 'I' ) )
271               root->style_flags |= FT_STYLE_FLAG_ITALIC;
272
273       prop = bdf_get_font_property( font, (char *)"WEIGHT_NAME" );
274       if ( prop != NULL )
275         if ( prop->format == BDF_ATOM )
276           if ( prop->value.atom != NULL )
277             if ( *(prop->value.atom) == 'B' )
278               root->style_flags |= FT_STYLE_FLAG_BOLD;
279
280       prop = bdf_get_font_property( font, (char *)"FAMILY_NAME" );
281       if ( ( prop != NULL ) && ( prop->value.atom != NULL ) )
282       {
283         int  l = ft_strlen( prop->value.atom ) + 1;
284
285
286         if ( FT_NEW_ARRAY( root->family_name, l ) )
287           goto Exit;
288         ft_strcpy( root->family_name, prop->value.atom );
289       }
290       else
291         root->family_name = 0;
292
293       root->style_name = (char *)"Regular";
294       if ( root->style_flags & FT_STYLE_FLAG_BOLD )
295       {
296         if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
297           root->style_name = (char *)"Bold Italic";
298         else
299           root->style_name = (char *)"Bold";
300       }
301       else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
302         root->style_name = (char *)"Italic";
303
304       root->num_glyphs = font->glyphs_size;     /* unencoded included */
305
306       root->num_fixed_sizes = 1;
307       if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
308         goto Exit;
309
310       prop = bdf_get_font_property( font, (char *)"AVERAGE_WIDTH" );
311       if ( ( prop != NULL ) && ( prop->value.int32 >= 10 ) )
312         root->available_sizes->width = (short)( prop->value.int32 / 10 );
313
314       prop = bdf_get_font_property( font, (char *)"PIXEL_SIZE" );
315       if ( prop != NULL )
316         root->available_sizes->height = (short) prop->value.int32;
317       else
318       {
319         prop = bdf_get_font_property( font, (char *)"POINT_SIZE" );
320         if ( prop != NULL )
321         {
322           bdf_property_t  *yres;
323
324
325           yres = bdf_get_font_property( font, (char *)"RESOLUTION_Y" );
326           if ( yres != NULL )
327           {
328             FT_TRACE4(( "POINT_SIZE: %d  RESOLUTION_Y: %d\n",
329                         prop->value.int32, yres->value.int32 ));
330             root->available_sizes->height =
331               (FT_Short)( prop->value.int32 * yres->value.int32 / 720 );
332           }
333         }
334       }
335
336       if ( root->available_sizes->width == 0 )
337       {
338         if ( root->available_sizes->height == 0 )
339         {
340           /* some fonts have broken SIZE declaration (jiskan24.bdf) */
341           FT_ERROR(( "BDF_Face_Init: reading size\n" ));
342           root->available_sizes->width = (FT_Short)font->point_size;
343         }
344         else
345           root->available_sizes->width = root->available_sizes->height;
346       }
347       if ( root->available_sizes->height == 0 )
348           root->available_sizes->height = root->available_sizes->width;
349
350       /* encoding table */
351       {
352         bdf_glyph_t*   cur = font->glyphs;
353         unsigned long  n;
354
355
356         if ( FT_NEW_ARRAY( face->en_table, font->glyphs_size ) )
357           goto Exit;
358
359         for ( n = 0; n < font->glyphs_size; n++ )
360         {
361           (face->en_table[n]).enc = cur[n].encoding;
362           FT_TRACE4(( "idx %d, val 0x%lX\n", n, cur[n].encoding ));
363           (face->en_table[n]).glyph = (FT_Short)n;
364         }
365       }
366
367       /* charmaps */
368       {
369         bdf_property_t  *charset_registry = 0, *charset_encoding = 0;
370         FT_Bool          unicode_charmap  = 0;
371
372
373         charset_registry =
374           bdf_get_font_property( font, (char *)"CHARSET_REGISTRY" );
375         charset_encoding =
376           bdf_get_font_property( font, (char *)"CHARSET_ENCODING" );
377         if ( ( charset_registry != NULL ) && ( charset_encoding != NULL ) )
378         {
379           if ( ( charset_registry->format == BDF_ATOM ) &&
380                ( charset_encoding->format == BDF_ATOM ) &&
381                ( charset_registry->value.atom != NULL ) &&
382                ( charset_encoding->value.atom != NULL ) )
383           {
384             if ( FT_NEW_ARRAY( face->charset_encoding,
385                                strlen( charset_encoding->value.atom ) + 1 ) )
386               goto Exit;
387             if ( FT_NEW_ARRAY( face->charset_registry,
388                                strlen( charset_registry->value.atom ) + 1 ) )
389               goto Exit;
390             ft_strcpy( face->charset_registry, charset_registry->value.atom );
391             ft_strcpy( face->charset_encoding, charset_encoding->value.atom );
392             if ( !ft_strcmp( face->charset_registry, "ISO10646" )     ||
393                  ( !ft_strcmp( face->charset_registry, "ISO8859" ) &&
394                    !ft_strcmp( face->charset_encoding, "1" )       )  )
395               unicode_charmap = 1;
396
397             {
398               FT_CharMapRec  charmap;
399
400
401               charmap.face        = FT_FACE( face );
402               charmap.encoding    = FT_ENCODING_NONE;
403               charmap.platform_id = 0;
404               charmap.encoding_id = 0;
405
406               if ( unicode_charmap )
407               {
408                 charmap.encoding    = FT_ENCODING_UNICODE;
409                 charmap.platform_id = 3;
410                 charmap.encoding_id = 1;
411               }
412
413               error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
414
415 #if 0
416               /* Select default charmap */
417               if (root->num_charmaps)
418                 root->charmap = root->charmaps[0];
419 #endif
420             }
421
422             goto Exit;
423           }
424         }
425
426         /* otherwise assume Adobe standard encoding */
427
428         {
429           FT_CharMapRec  charmap;
430
431
432           charmap.face        = FT_FACE( face );
433           charmap.encoding    = FT_ENCODING_ADOBE_STANDARD;
434           charmap.platform_id = 7;
435           charmap.encoding_id = 0;
436
437           error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
438
439           /* Select default charmap */
440           if (root->num_charmaps)
441             root->charmap = root->charmaps[0];
442         }
443       }
444     }
445
446   Exit:
447     return error;
448
449   Fail:
450     BDF_Face_Done( face );
451     return BDF_Err_Unknown_File_Format;
452   }
453
454
455   static FT_Error
456   BDF_Set_Pixel_Size( FT_Size  size )
457   {
458     BDF_Face  face = (BDF_Face)FT_SIZE_FACE( size );
459     FT_Face   root = FT_FACE( face );
460
461
462     FT_TRACE4(( "rec %d - pres %d\n",
463                 size->metrics.y_ppem, root->available_sizes->height ));
464
465     if ( size->metrics.y_ppem == root->available_sizes->height )
466     {
467       size->metrics.ascender  = face->bdffont->bbx.ascent << 6;
468       size->metrics.descender = face->bdffont->bbx.descent * ( -64 );
469       size->metrics.height    = face->bdffont->bbx.height << 6;
470
471       return BDF_Err_Ok;
472     }
473     else
474       return BDF_Err_Invalid_Pixel_Size;
475   }
476
477
478   static FT_Error
479   BDF_Glyph_Load( FT_GlyphSlot  slot,
480                   FT_Size       size,
481                   FT_UInt       glyph_index,
482                   FT_Int32      load_flags )
483   {
484     BDF_Face        face   = (BDF_Face)FT_SIZE_FACE( size );
485     FT_Error        error  = BDF_Err_Ok;
486     FT_Bitmap*      bitmap = &slot->bitmap;
487     bdf_glyph_t     glyph;
488     int             bpp    = face->bdffont->bpp;
489     int             i, j, count;
490     unsigned char   *p, *pp;
491
492     FT_UNUSED( load_flags );
493
494
495     if ( !face )
496     {
497       error = BDF_Err_Invalid_Argument;
498       goto Exit;
499     }
500
501     if ( glyph_index > 0 )
502       glyph_index--;
503
504     /* slot, bitmap => freetype, glyph => bdflib */
505     glyph = face->bdffont->glyphs[glyph_index];
506
507     bitmap->rows  = glyph.bbx.height;
508     bitmap->width = glyph.bbx.width;
509
510     if ( bpp == 1 )
511     {
512       bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
513       bitmap->pitch      = glyph.bpr;
514
515      /* note: we don't allocate a new array to hold the bitmap, we */
516      /*       can simply point to it                               */
517       ft_glyphslot_set_bitmap( slot, glyph.bitmap );
518     }
519     else
520     {
521       /* blow up pixmap to have 8 bits per pixel */
522       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
523       bitmap->pitch      = bitmap->width;
524
525       error = ft_glyphslot_alloc_bitmap( slot, bitmap->rows * bitmap->pitch );
526       if ( error )
527         goto Exit;
528
529       switch ( bpp )
530       {
531       case 2:
532         bitmap->num_grays = 4;
533
534         count = 0;
535         p     = glyph.bitmap;
536
537         for ( i = 0; i < bitmap->rows; i++ )
538         {
539           pp = p;
540
541           /* get the full bytes */
542           for ( j = 0; j < ( bitmap->width >> 2 ); j++ )
543           {
544             bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0xC0 ) >> 6 );
545             bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0x30 ) >> 4 );
546             bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0x0C ) >> 2 );
547             bitmap->buffer[count++] = (FT_Byte)(   *pp & 0x03 );
548
549             pp++;
550           }
551
552           /* get remaining pixels (if any) */
553           switch ( bitmap->width & 3 )
554           {
555           case 3:
556             bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0xC0 ) >> 6 );
557             /* fall through */
558           case 2:
559             bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0x30 ) >> 4 );
560             /* fall through */
561           case 1:
562             bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0x0C ) >> 2 );
563             /* fall through */
564           case 0:
565             break;
566           }
567
568           p += glyph.bpr;
569         }
570         break;
571
572       case 4:
573         bitmap->num_grays = 16;
574
575         count = 0;
576         p     = glyph.bitmap;
577
578         for ( i = 0; i < bitmap->rows; i++ )
579         {
580           pp = p;
581
582           /* get the full bytes */
583           for ( j = 0; j < ( bitmap->width >> 1 ); j++ )
584           {
585             bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0xF0 ) >> 4 );
586             bitmap->buffer[count++] = (FT_Byte)(   *pp & 0x0F );
587
588             pp++;
589           }
590
591           /* get remaining pixel (if any) */
592           switch ( bitmap->width & 1 )
593           {
594           case 1:
595             bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0xF0 ) >> 4 );
596             /* fall through */
597           case 0:
598             break;
599           }
600
601           p += glyph.bpr;
602         }
603         break;
604
605       case 8:
606         bitmap->num_grays = 256;
607
608         FT_MEM_COPY( bitmap->buffer, glyph.bitmap,
609                      bitmap->rows * bitmap->pitch );
610         break;
611       }
612     }
613
614     slot->bitmap_left = 0;
615     slot->bitmap_top  = glyph.bbx.ascent;
616
617     /* FZ XXX: TODO: vertical metrics */
618     slot->metrics.horiAdvance  = glyph.dwidth << 6;
619     slot->metrics.horiBearingX = glyph.bbx.x_offset << 6;
620     slot->metrics.horiBearingY = ( glyph.bbx.y_offset +
621                                    glyph.bbx.height ) << 6;
622     slot->metrics.width        = bitmap->width << 6;
623     slot->metrics.height       = bitmap->rows << 6;
624
625     slot->linearHoriAdvance = (FT_Fixed)glyph.dwidth << 16;
626     slot->format            = FT_GLYPH_FORMAT_BITMAP;
627
628   Exit:
629     return error;
630   }
631
632
633   static FT_Error
634   bdf_get_bdf_property( BDF_Face          face,
635                         const char*       prop_name,
636                         BDF_PropertyRec  *aproperty )
637   {
638     bdf_property_t*  prop;
639
640     FT_ASSERT( face && face->bdffont );
641
642     prop = bdf_get_font_property( face->bdffont, (char*)prop_name );
643     if ( prop != NULL )
644     {
645       switch ( prop->format )
646       {
647         case BDF_ATOM:
648           aproperty->type   = BDF_PROPERTY_TYPE_ATOM;
649           aproperty->u.atom = prop->value.atom;
650           break;
651
652         case BDF_INTEGER:
653           aproperty->type      = BDF_PROPERTY_TYPE_INTEGER;
654           aproperty->u.integer = prop->value.int32;
655           break;
656
657         case BDF_CARDINAL:
658           aproperty->type       = BDF_PROPERTY_TYPE_CARDINAL;
659           aproperty->u.cardinal = prop->value.card32;
660           break;
661
662         default:
663           goto Fail;
664       }
665       return 0;
666     }
667   Fail:
668     return FT_Err_Invalid_Argument;
669   }
670
671
672   static FT_Module_Interface
673   bdf_driver_requester( FT_Module    module,
674                         const char*  name )
675   {
676     FT_UNUSED( module );
677
678     if ( name && ft_strcmp( name, "get_bdf_property" ) == 0 )
679       return (FT_Module_Interface) bdf_get_bdf_property;
680
681     return NULL;
682   }
683
684
685   FT_CALLBACK_TABLE_DEF
686   const FT_Driver_ClassRec  bdf_driver_class =
687   {
688     {
689       ft_module_font_driver,
690       sizeof ( FT_DriverRec ),
691
692       "bdf",
693       0x10000L,
694       0x20000L,
695
696       0,
697
698       (FT_Module_Constructor)0,
699       (FT_Module_Destructor) 0,
700       (FT_Module_Requester)  bdf_driver_requester
701     },
702
703     sizeof ( BDF_FaceRec ),
704     sizeof ( FT_SizeRec ),
705     sizeof ( FT_GlyphSlotRec ),
706
707     (FT_Face_InitFunc)        BDF_Face_Init,
708     (FT_Face_DoneFunc)        BDF_Face_Done,
709     (FT_Size_InitFunc)        0,
710     (FT_Size_DoneFunc)        0,
711     (FT_Slot_InitFunc)        0,
712     (FT_Slot_DoneFunc)        0,
713
714     (FT_Size_ResetPointsFunc) BDF_Set_Pixel_Size,
715     (FT_Size_ResetPixelsFunc) BDF_Set_Pixel_Size,
716
717     (FT_Slot_LoadFunc)        BDF_Glyph_Load,
718
719     (FT_Face_GetKerningFunc)  0,
720     (FT_Face_AttachFunc)      0,
721     (FT_Face_GetAdvancesFunc) 0
722   };
723
724
725 /* END */