Git init
[framework/graphics/freetype.git] / src / pcf / pcfdrivr.c
1 /*  pcfdrivr.c
2
3     FreeType font driver for pcf files
4
5     Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009 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 <ft2build.h>
29
30 #include FT_INTERNAL_DEBUG_H
31 #include FT_INTERNAL_STREAM_H
32 #include FT_INTERNAL_OBJECTS_H
33 #include FT_GZIP_H
34 #include FT_LZW_H
35 #include FT_ERRORS_H
36 #include FT_BDF_H
37 #include FT_TRUETYPE_IDS_H 
38
39 #include "pcf.h"
40 #include "pcfdrivr.h"
41 #include "pcfread.h"
42
43 #include "pcferror.h"
44 #include "pcfutil.h"
45
46 #undef  FT_COMPONENT
47 #define FT_COMPONENT  trace_pcfread
48
49 #include FT_SERVICE_BDF_H
50 #include FT_SERVICE_XFREE86_NAME_H
51
52
53   /*************************************************************************/
54   /*                                                                       */
55   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
56   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
57   /* messages during execution.                                            */
58   /*                                                                       */
59 #undef  FT_COMPONENT
60 #define FT_COMPONENT  trace_pcfdriver
61
62
63   typedef struct  PCF_CMapRec_
64   {
65     FT_CMapRec    root;
66     FT_UInt       num_encodings;
67     PCF_Encoding  encodings;
68
69   } PCF_CMapRec, *PCF_CMap;
70
71
72   FT_CALLBACK_DEF( FT_Error )
73   pcf_cmap_init( FT_CMap     pcfcmap,   /* PCF_CMap */
74                  FT_Pointer  init_data )
75   {
76     PCF_CMap  cmap = (PCF_CMap)pcfcmap;
77     PCF_Face  face = (PCF_Face)FT_CMAP_FACE( pcfcmap );
78
79     FT_UNUSED( init_data );
80
81
82     cmap->num_encodings = (FT_UInt)face->nencodings;
83     cmap->encodings     = face->encodings;
84
85     return PCF_Err_Ok;
86   }
87
88
89   FT_CALLBACK_DEF( void )
90   pcf_cmap_done( FT_CMap  pcfcmap )         /* PCF_CMap */
91   {
92     PCF_CMap  cmap = (PCF_CMap)pcfcmap;
93
94
95     cmap->encodings     = NULL;
96     cmap->num_encodings = 0;
97   }
98
99
100   FT_CALLBACK_DEF( FT_UInt )
101   pcf_cmap_char_index( FT_CMap    pcfcmap,  /* PCF_CMap */
102                        FT_UInt32  charcode )
103   {
104     PCF_CMap      cmap      = (PCF_CMap)pcfcmap;
105     PCF_Encoding  encodings = cmap->encodings;
106     FT_UInt       min, max, mid;
107     FT_UInt       result    = 0;
108
109
110     min = 0;
111     max = cmap->num_encodings;
112
113     while ( min < max )
114     {
115       FT_ULong  code;
116
117
118       mid  = ( min + max ) >> 1;
119       code = encodings[mid].enc;
120
121       if ( charcode == code )
122       {
123         result = encodings[mid].glyph + 1;
124         break;
125       }
126
127       if ( charcode < code )
128         max = mid;
129       else
130         min = mid + 1;
131     }
132
133     return result;
134   }
135
136
137   FT_CALLBACK_DEF( FT_UInt )
138   pcf_cmap_char_next( FT_CMap    pcfcmap,   /* PCF_CMap */
139                       FT_UInt32  *acharcode )
140   {
141     PCF_CMap      cmap      = (PCF_CMap)pcfcmap;
142     PCF_Encoding  encodings = cmap->encodings;
143     FT_UInt       min, max, mid;
144     FT_ULong      charcode  = *acharcode + 1;
145     FT_UInt       result    = 0;
146
147
148     min = 0;
149     max = cmap->num_encodings;
150
151     while ( min < max )
152     {
153       FT_ULong  code;
154
155
156       mid  = ( min + max ) >> 1;
157       code = encodings[mid].enc;
158
159       if ( charcode == code )
160       {
161         result = encodings[mid].glyph + 1;
162         goto Exit;
163       }
164
165       if ( charcode < code )
166         max = mid;
167       else
168         min = mid + 1;
169     }
170
171     charcode = 0;
172     if ( min < cmap->num_encodings )
173     {
174       charcode = encodings[min].enc;
175       result   = encodings[min].glyph + 1;
176     }
177
178   Exit:
179     if ( charcode > 0xFFFFFFFFUL )
180     {
181       FT_TRACE1(( "pcf_cmap_char_next: charcode 0x%x > 32bit API" ));
182       *acharcode = 0;
183       /* XXX: result should be changed to indicate an overflow error */
184     }
185     else
186       *acharcode = (FT_UInt32)charcode;
187     return result;
188   }
189
190
191   FT_CALLBACK_TABLE_DEF
192   const FT_CMap_ClassRec  pcf_cmap_class =
193   {
194     sizeof ( PCF_CMapRec ),
195     pcf_cmap_init,
196     pcf_cmap_done,
197     pcf_cmap_char_index,
198     pcf_cmap_char_next,
199
200     NULL, NULL, NULL, NULL, NULL
201   };
202
203
204   FT_CALLBACK_DEF( void )
205   PCF_Face_Done( FT_Face  pcfface )         /* PCF_Face */
206   {
207     PCF_Face   face = (PCF_Face)pcfface;
208     FT_Memory  memory;
209
210
211     if ( !face )
212       return;
213
214     memory = FT_FACE_MEMORY( face );
215
216     FT_FREE( face->encodings );
217     FT_FREE( face->metrics );
218
219     /* free properties */
220     {
221       PCF_Property  prop;
222       FT_Int        i;
223
224
225       if ( face->properties )
226       {
227         for ( i = 0; i < face->nprops; i++ )
228         {
229           prop = &face->properties[i];
230
231           if ( prop )
232           {
233             FT_FREE( prop->name );
234             if ( prop->isString )
235               FT_FREE( prop->value.atom );
236           }
237         }
238       }
239       FT_FREE( face->properties );
240     }
241
242     FT_FREE( face->toc.tables );
243     FT_FREE( pcfface->family_name );
244     FT_FREE( pcfface->style_name );
245     FT_FREE( pcfface->available_sizes );
246     FT_FREE( face->charset_encoding );
247     FT_FREE( face->charset_registry );
248
249     FT_TRACE4(( "PCF_Face_Done: done face\n" ));
250
251     /* close gzip/LZW stream if any */
252     if ( pcfface->stream == &face->gzip_stream )
253     {
254       FT_Stream_Close( &face->gzip_stream );
255       pcfface->stream = face->gzip_source;
256     }
257   }
258
259
260   FT_CALLBACK_DEF( FT_Error )
261   PCF_Face_Init( FT_Stream      stream,
262                  FT_Face        pcfface,        /* PCF_Face */
263                  FT_Int         face_index,
264                  FT_Int         num_params,
265                  FT_Parameter*  params )
266   {
267     PCF_Face  face  = (PCF_Face)pcfface;
268     FT_Error  error = PCF_Err_Ok;
269
270     FT_UNUSED( num_params );
271     FT_UNUSED( params );
272     FT_UNUSED( face_index );
273
274
275     error = pcf_load_font( stream, face );
276     if ( error )
277     {
278       PCF_Face_Done( pcfface );
279
280 #if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \
281     defined( FT_CONFIG_OPTION_USE_LZW )
282
283 #ifdef FT_CONFIG_OPTION_USE_ZLIB
284       {
285         FT_Error  error2;
286
287
288         /* this didn't work, try gzip support! */
289         error2 = FT_Stream_OpenGzip( &face->gzip_stream, stream );
290         if ( FT_ERROR_BASE( error2 ) == FT_Err_Unimplemented_Feature )
291           goto Fail;
292
293         error = error2;
294       }
295 #endif /* FT_CONFIG_OPTION_USE_ZLIB */
296
297 #ifdef FT_CONFIG_OPTION_USE_LZW
298       if ( error )
299       {
300         FT_Error  error3;
301
302
303         /* this didn't work, try LZW support! */
304         error3 = FT_Stream_OpenLZW( &face->gzip_stream, stream );
305         if ( FT_ERROR_BASE( error3 ) == FT_Err_Unimplemented_Feature )
306           goto Fail;
307
308         error = error3;
309       }
310 #endif /* FT_CONFIG_OPTION_USE_LZW */
311
312       if ( error )
313         goto Fail;
314
315       face->gzip_source = stream;
316       pcfface->stream   = &face->gzip_stream;
317
318       stream = pcfface->stream;
319
320       error = pcf_load_font( stream, face );
321       if ( error )
322         goto Fail;
323
324 #else /* !(FT_CONFIG_OPTION_USE_ZLIB || FT_CONFIG_OPTION_USE_LZW) */
325
326       goto Fail;
327
328 #endif
329     }
330
331     /* set up charmap */
332     {
333       FT_String  *charset_registry = face->charset_registry;
334       FT_String  *charset_encoding = face->charset_encoding;
335       FT_Bool     unicode_charmap  = 0;
336
337
338       if ( charset_registry && charset_encoding )
339       {
340         char*  s = charset_registry;
341
342
343         /* Uh, oh, compare first letters manually to avoid dependency
344            on locales. */
345         if ( ( s[0] == 'i' || s[0] == 'I' ) &&
346              ( s[1] == 's' || s[1] == 'S' ) &&
347              ( s[2] == 'o' || s[2] == 'O' ) )
348         {
349           s += 3;
350           if ( !ft_strcmp( s, "10646" )                      ||
351                ( !ft_strcmp( s, "8859" ) &&
352                  !ft_strcmp( face->charset_encoding, "1" ) ) )
353           unicode_charmap = 1;
354         }
355       }
356
357       {
358         FT_CharMapRec  charmap;
359
360
361         charmap.face        = FT_FACE( face );
362         charmap.encoding    = FT_ENCODING_NONE;
363         /* initial platform/encoding should indicate unset status? */
364         charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
365         charmap.encoding_id = TT_APPLE_ID_DEFAULT;
366
367         if ( unicode_charmap )
368         {
369           charmap.encoding    = FT_ENCODING_UNICODE;
370           charmap.platform_id = TT_PLATFORM_MICROSOFT;
371           charmap.encoding_id = TT_MS_ID_UNICODE_CS;
372         }
373
374         error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL );
375
376 #if 0
377         /* Select default charmap */
378         if ( pcfface->num_charmaps )
379           pcfface->charmap = pcfface->charmaps[0];
380 #endif
381       }
382     }
383
384   Exit:
385     return error;
386
387   Fail:
388     FT_TRACE2(( "[not a valid PCF file]\n" ));
389     PCF_Face_Done( pcfface );
390     error = PCF_Err_Unknown_File_Format;  /* error */
391     goto Exit;
392   }
393
394
395   FT_CALLBACK_DEF( FT_Error )
396   PCF_Size_Select( FT_Size   size,
397                    FT_ULong  strike_index )
398   {
399     PCF_Accel  accel = &( (PCF_Face)size->face )->accel;
400
401
402     FT_Select_Metrics( size->face, strike_index );
403
404     size->metrics.ascender    =  accel->fontAscent << 6;
405     size->metrics.descender   = -accel->fontDescent << 6;
406     size->metrics.max_advance =  accel->maxbounds.characterWidth << 6;
407
408     return PCF_Err_Ok;
409   }
410
411
412   FT_CALLBACK_DEF( FT_Error )
413   PCF_Size_Request( FT_Size          size,
414                     FT_Size_Request  req )
415   {
416     PCF_Face         face  = (PCF_Face)size->face;
417     FT_Bitmap_Size*  bsize = size->face->available_sizes;
418     FT_Error         error = PCF_Err_Invalid_Pixel_Size;
419     FT_Long          height;
420
421
422     height = FT_REQUEST_HEIGHT( req );
423     height = ( height + 32 ) >> 6;
424
425     switch ( req->type )
426     {
427     case FT_SIZE_REQUEST_TYPE_NOMINAL:
428       if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) )
429         error = PCF_Err_Ok;
430       break;
431
432     case FT_SIZE_REQUEST_TYPE_REAL_DIM:
433       if ( height == ( face->accel.fontAscent +
434                        face->accel.fontDescent ) )
435         error = PCF_Err_Ok;
436       break;
437
438     default:
439       error = PCF_Err_Unimplemented_Feature;
440       break;
441     }
442
443     if ( error )
444       return error;
445     else
446       return PCF_Size_Select( size, 0 );
447   }
448
449
450   FT_CALLBACK_DEF( FT_Error )
451   PCF_Glyph_Load( FT_GlyphSlot  slot,
452                   FT_Size       size,
453                   FT_UInt       glyph_index,
454                   FT_Int32      load_flags )
455   {
456     PCF_Face    face   = (PCF_Face)FT_SIZE_FACE( size );
457     FT_Stream   stream;
458     FT_Error    error  = PCF_Err_Ok;
459     FT_Bitmap*  bitmap = &slot->bitmap;
460     PCF_Metric  metric;
461     FT_Offset   bytes;
462
463     FT_UNUSED( load_flags );
464
465
466     FT_TRACE4(( "load_glyph %d ---", glyph_index ));
467
468     if ( !face || glyph_index >= (FT_UInt)face->root.num_glyphs )
469     {
470       error = PCF_Err_Invalid_Argument;
471       goto Exit;
472     }
473
474     stream = face->root.stream;
475
476     if ( glyph_index > 0 )
477       glyph_index--;
478
479     metric = face->metrics + glyph_index;
480
481     bitmap->rows       = metric->ascent + metric->descent;
482     bitmap->width      = metric->rightSideBearing - metric->leftSideBearing;
483     bitmap->num_grays  = 1;
484     bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
485
486     FT_TRACE6(( "BIT_ORDER %d ; BYTE_ORDER %d ; GLYPH_PAD %d\n",
487                   PCF_BIT_ORDER( face->bitmapsFormat ),
488                   PCF_BYTE_ORDER( face->bitmapsFormat ),
489                   PCF_GLYPH_PAD( face->bitmapsFormat ) ));
490
491     switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) )
492     {
493     case 1:
494       bitmap->pitch = ( bitmap->width + 7 ) >> 3;
495       break;
496
497     case 2:
498       bitmap->pitch = ( ( bitmap->width + 15 ) >> 4 ) << 1;
499       break;
500
501     case 4:
502       bitmap->pitch = ( ( bitmap->width + 31 ) >> 5 ) << 2;
503       break;
504
505     case 8:
506       bitmap->pitch = ( ( bitmap->width + 63 ) >> 6 ) << 3;
507       break;
508
509     default:
510       return PCF_Err_Invalid_File_Format;
511     }
512
513     /* XXX: to do: are there cases that need repadding the bitmap? */
514     bytes = bitmap->pitch * bitmap->rows;
515
516     error = ft_glyphslot_alloc_bitmap( slot, bytes );
517     if ( error )
518       goto Exit;
519
520     if ( FT_STREAM_SEEK( metric->bits )          ||
521          FT_STREAM_READ( bitmap->buffer, bytes ) )
522       goto Exit;
523
524     if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst )
525       BitOrderInvert( bitmap->buffer, bytes );
526
527     if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) !=
528            PCF_BIT_ORDER( face->bitmapsFormat )  ) )
529     {
530       switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) )
531       {
532       case 1:
533         break;
534
535       case 2:
536         TwoByteSwap( bitmap->buffer, bytes );
537         break;
538
539       case 4:
540         FourByteSwap( bitmap->buffer, bytes );
541         break;
542       }
543     }
544
545     slot->format      = FT_GLYPH_FORMAT_BITMAP;
546     slot->bitmap_left = metric->leftSideBearing;
547     slot->bitmap_top  = metric->ascent;
548
549     slot->metrics.horiAdvance  = metric->characterWidth << 6;
550     slot->metrics.horiBearingX = metric->leftSideBearing << 6;
551     slot->metrics.horiBearingY = metric->ascent << 6;
552     slot->metrics.width        = ( metric->rightSideBearing -
553                                    metric->leftSideBearing ) << 6;
554     slot->metrics.height       = bitmap->rows << 6;
555
556     ft_synthesize_vertical_metrics( &slot->metrics,
557                                     ( face->accel.fontAscent +
558                                       face->accel.fontDescent ) << 6 );
559
560     FT_TRACE4(( " --- ok\n" ));
561
562   Exit:
563     return error;
564   }
565
566
567  /*
568   *
569   *  BDF SERVICE
570   *
571   */
572
573   static FT_Error
574   pcf_get_bdf_property( PCF_Face          face,
575                         const char*       prop_name,
576                         BDF_PropertyRec  *aproperty )
577   {
578     PCF_Property  prop;
579
580
581     prop = pcf_find_property( face, prop_name );
582     if ( prop != NULL )
583     {
584       if ( prop->isString )
585       {
586         aproperty->type   = BDF_PROPERTY_TYPE_ATOM;
587         aproperty->u.atom = prop->value.atom;
588       }
589       else
590       {
591         if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) )
592         {
593           FT_TRACE1(( "pcf_get_bdf_property: " ));
594           FT_TRACE1(( "too large integer 0x%x is truncated\n" ));
595         }
596         /* Apparently, the PCF driver loads all properties as signed integers!
597          * This really doesn't seem to be a problem, because this is
598          * sufficient for any meaningful values.
599          */
600         aproperty->type      = BDF_PROPERTY_TYPE_INTEGER;
601         aproperty->u.integer = (FT_Int32)prop->value.l;
602       }
603       return 0;
604     }
605
606     return PCF_Err_Invalid_Argument;
607   }
608
609
610   static FT_Error
611   pcf_get_charset_id( PCF_Face      face,
612                       const char*  *acharset_encoding,
613                       const char*  *acharset_registry )
614   {
615     *acharset_encoding = face->charset_encoding;
616     *acharset_registry = face->charset_registry;
617
618     return 0;
619   }
620
621
622   static const FT_Service_BDFRec  pcf_service_bdf =
623   {
624     (FT_BDF_GetCharsetIdFunc)pcf_get_charset_id,
625     (FT_BDF_GetPropertyFunc) pcf_get_bdf_property
626   };
627
628
629  /*
630   *
631   *  SERVICE LIST
632   *
633   */
634
635   static const FT_ServiceDescRec  pcf_services[] =
636   {
637     { FT_SERVICE_ID_BDF,       &pcf_service_bdf },
638     { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_PCF },
639     { NULL, NULL }
640   };
641
642
643   FT_CALLBACK_DEF( FT_Module_Interface )
644   pcf_driver_requester( FT_Module    module,
645                         const char*  name )
646   {
647     FT_UNUSED( module );
648
649     return ft_service_list_lookup( pcf_services, name );
650   }
651
652
653   FT_CALLBACK_TABLE_DEF
654   const FT_Driver_ClassRec  pcf_driver_class =
655   {
656     {
657       FT_MODULE_FONT_DRIVER        |
658       FT_MODULE_DRIVER_NO_OUTLINES,
659       sizeof ( FT_DriverRec ),
660
661       "pcf",
662       0x10000L,
663       0x20000L,
664
665       0,
666
667       0,
668       0,
669       pcf_driver_requester
670     },
671
672     sizeof ( PCF_FaceRec ),
673     sizeof ( FT_SizeRec ),
674     sizeof ( FT_GlyphSlotRec ),
675
676     PCF_Face_Init,
677     PCF_Face_Done,
678     0,                      /* FT_Size_InitFunc */
679     0,                      /* FT_Size_DoneFunc */
680     0,                      /* FT_Slot_InitFunc */
681     0,                      /* FT_Slot_DoneFunc */
682
683 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
684     ft_stub_set_char_sizes,
685     ft_stub_set_pixel_sizes,
686 #endif
687     PCF_Glyph_Load,
688
689     0,                      /* FT_Face_GetKerningFunc  */
690     0,                      /* FT_Face_AttachFunc      */
691     0,                      /* FT_Face_GetAdvancesFunc */
692
693     PCF_Size_Request,
694     PCF_Size_Select
695   };
696
697
698 /* END */