Imported Upstream version 2.10.4
[platform/upstream/freetype2.git] / src / pcf / pcfdrivr.c
1 /*  pcfdrivr.c
2
3     FreeType font driver for pcf files
4
5     Copyright (C) 2000-2004, 2006-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
29 #include <freetype/internal/ftdebug.h>
30 #include <freetype/internal/ftstream.h>
31 #include <freetype/internal/ftobjs.h>
32 #include <freetype/ftgzip.h>
33 #include <freetype/ftlzw.h>
34 #include <freetype/ftbzip2.h>
35 #include <freetype/fterrors.h>
36 #include <freetype/ftbdf.h>
37 #include <freetype/ttnameid.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  pcfread
48
49 #include <freetype/internal/services/svbdf.h>
50 #include <freetype/internal/services/svfntfmt.h>
51 #include <freetype/internal/services/svprop.h>
52 #include <freetype/ftdriver.h>
53
54
55   /**************************************************************************
56    *
57    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
58    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
59    * messages during execution.
60    */
61 #undef  FT_COMPONENT
62 #define FT_COMPONENT  pcfdriver
63
64
65   /*
66    * This file uses X11 terminology for PCF data; an `encoding' in X11 speak
67    * is the same as a `character code' in FreeType speak.
68    */
69   typedef struct  PCF_CMapRec_
70   {
71     FT_CMapRec  root;
72     PCF_Enc     enc;
73
74   } PCF_CMapRec, *PCF_CMap;
75
76
77   FT_CALLBACK_DEF( FT_Error )
78   pcf_cmap_init( FT_CMap     pcfcmap,   /* PCF_CMap */
79                  FT_Pointer  init_data )
80   {
81     PCF_CMap  cmap = (PCF_CMap)pcfcmap;
82     PCF_Face  face = (PCF_Face)FT_CMAP_FACE( pcfcmap );
83
84     FT_UNUSED( init_data );
85
86
87     cmap->enc = &face->enc;
88
89     return FT_Err_Ok;
90   }
91
92
93   FT_CALLBACK_DEF( void )
94   pcf_cmap_done( FT_CMap  pcfcmap )         /* PCF_CMap */
95   {
96     PCF_CMap  cmap = (PCF_CMap)pcfcmap;
97
98
99     cmap->enc = NULL;
100   }
101
102
103   FT_CALLBACK_DEF( FT_UInt )
104   pcf_cmap_char_index( FT_CMap    pcfcmap,  /* PCF_CMap */
105                        FT_UInt32  charcode )
106   {
107     PCF_CMap   cmap = (PCF_CMap)pcfcmap;
108     PCF_Enc    enc  = cmap->enc;
109     FT_UShort  charcodeRow;
110     FT_UShort  charcodeCol;
111
112
113     if ( charcode > (FT_UInt32)( enc->lastRow  * 256 + enc->lastCol  ) ||
114          charcode < (FT_UInt32)( enc->firstRow * 256 + enc->firstCol ) )
115       return 0;
116
117     charcodeRow = (FT_UShort)( charcode >> 8 );
118     charcodeCol = (FT_UShort)( charcode & 0xFF );
119
120     if ( charcodeCol < enc->firstCol ||
121          charcodeCol > enc->lastCol  )
122       return 0;
123
124     return (FT_UInt)enc->offset[( charcodeRow - enc->firstRow ) *
125                                   ( enc->lastCol - enc->firstCol + 1 ) +
126                                 charcodeCol - enc->firstCol];
127   }
128
129
130   FT_CALLBACK_DEF( FT_UInt )
131   pcf_cmap_char_next( FT_CMap    pcfcmap,   /* PCF_CMap */
132                       FT_UInt32  *acharcode )
133   {
134     PCF_CMap   cmap      = (PCF_CMap)pcfcmap;
135     PCF_Enc    enc       = cmap->enc;
136     FT_UInt32  charcode  = *acharcode;
137     FT_UShort  charcodeRow;
138     FT_UShort  charcodeCol;
139     FT_UInt    result = 0;
140
141
142     while ( charcode < (FT_UInt32)( enc->lastRow * 256 + enc->lastCol ) )
143     {
144       charcode++;
145
146       if ( charcode < (FT_UInt32)( enc->firstRow * 256 + enc->firstCol ) )
147         charcode = (FT_UInt32)( enc->firstRow * 256 + enc->firstCol );
148
149       charcodeRow = (FT_UShort)( charcode >> 8 );
150       charcodeCol = (FT_UShort)( charcode & 0xFF );
151
152       if ( charcodeCol < enc->firstCol )
153         charcodeCol = enc->firstCol;
154       else if ( charcodeCol > enc->lastCol )
155       {
156         charcodeRow++;
157         charcodeCol = enc->firstCol;
158       }
159
160       charcode = (FT_UInt32)( charcodeRow * 256 + charcodeCol );
161
162       result = (FT_UInt)enc->offset[( charcodeRow - enc->firstRow ) *
163                                       ( enc->lastCol - enc->firstCol + 1 ) +
164                                     charcodeCol - enc->firstCol];
165       if ( result != 0xFFFFU )
166         break;
167     }
168
169     *acharcode = charcode;
170
171     return result;
172   }
173
174
175   static
176   const FT_CMap_ClassRec  pcf_cmap_class =
177   {
178     sizeof ( PCF_CMapRec ),
179     pcf_cmap_init,
180     pcf_cmap_done,
181     pcf_cmap_char_index,
182     pcf_cmap_char_next,
183
184     NULL, NULL, NULL, NULL, NULL
185   };
186
187
188   FT_CALLBACK_DEF( void )
189   PCF_Face_Done( FT_Face  pcfface )         /* PCF_Face */
190   {
191     PCF_Face   face = (PCF_Face)pcfface;
192     FT_Memory  memory;
193
194
195     if ( !face )
196       return;
197
198     memory = FT_FACE_MEMORY( face );
199
200     FT_FREE( face->metrics );
201     FT_FREE( face->enc.offset );
202
203     /* free properties */
204     if ( face->properties )
205     {
206       FT_Int  i;
207
208
209       for ( i = 0; i < face->nprops; i++ )
210       {
211         PCF_Property  prop = &face->properties[i];
212
213
214         if ( prop )
215         {
216           FT_FREE( prop->name );
217           if ( prop->isString )
218             FT_FREE( prop->value.atom );
219         }
220       }
221
222       FT_FREE( face->properties );
223     }
224
225     FT_FREE( face->toc.tables );
226     FT_FREE( pcfface->family_name );
227     FT_FREE( pcfface->style_name );
228     FT_FREE( pcfface->available_sizes );
229     FT_FREE( face->charset_encoding );
230     FT_FREE( face->charset_registry );
231
232     /* close compressed stream if any */
233     if ( pcfface->stream == &face->comp_stream )
234     {
235       FT_Stream_Close( &face->comp_stream );
236       pcfface->stream = face->comp_source;
237     }
238   }
239
240
241   FT_CALLBACK_DEF( FT_Error )
242   PCF_Face_Init( FT_Stream      stream,
243                  FT_Face        pcfface,        /* PCF_Face */
244                  FT_Int         face_index,
245                  FT_Int         num_params,
246                  FT_Parameter*  params )
247   {
248     PCF_Face  face  = (PCF_Face)pcfface;
249     FT_Error  error;
250
251     FT_UNUSED( num_params );
252     FT_UNUSED( params );
253
254
255     FT_TRACE2(( "PCF driver\n" ));
256
257     error = pcf_load_font( stream, face, face_index );
258     if ( error )
259     {
260       PCF_Face_Done( pcfface );
261
262 #if defined( FT_CONFIG_OPTION_USE_ZLIB )  || \
263     defined( FT_CONFIG_OPTION_USE_LZW )   || \
264     defined( FT_CONFIG_OPTION_USE_BZIP2 )
265
266 #ifdef FT_CONFIG_OPTION_USE_ZLIB
267       {
268         FT_Error  error2;
269
270
271         /* this didn't work, try gzip support! */
272         FT_TRACE2(( "  ... try gzip stream\n" ));
273         error2 = FT_Stream_OpenGzip( &face->comp_stream, stream );
274         if ( FT_ERR_EQ( error2, Unimplemented_Feature ) )
275           goto Fail;
276
277         error = error2;
278       }
279 #endif /* FT_CONFIG_OPTION_USE_ZLIB */
280
281 #ifdef FT_CONFIG_OPTION_USE_LZW
282       if ( error )
283       {
284         FT_Error  error3;
285
286
287         /* this didn't work, try LZW support! */
288         FT_TRACE2(( "  ... try LZW stream\n" ));
289         error3 = FT_Stream_OpenLZW( &face->comp_stream, stream );
290         if ( FT_ERR_EQ( error3, Unimplemented_Feature ) )
291           goto Fail;
292
293         error = error3;
294       }
295 #endif /* FT_CONFIG_OPTION_USE_LZW */
296
297 #ifdef FT_CONFIG_OPTION_USE_BZIP2
298       if ( error )
299       {
300         FT_Error  error4;
301
302
303         /* this didn't work, try Bzip2 support! */
304         FT_TRACE2(( "  ... try Bzip2 stream\n" ));
305         error4 = FT_Stream_OpenBzip2( &face->comp_stream, stream );
306         if ( FT_ERR_EQ( error4, Unimplemented_Feature ) )
307           goto Fail;
308
309         error = error4;
310       }
311 #endif /* FT_CONFIG_OPTION_USE_BZIP2 */
312
313       if ( error )
314         goto Fail;
315
316       face->comp_source = stream;
317       pcfface->stream   = &face->comp_stream;
318
319       stream = pcfface->stream;
320
321       error = pcf_load_font( stream, face, face_index );
322       if ( error )
323         goto Fail;
324
325 #else /* !(FT_CONFIG_OPTION_USE_ZLIB ||
326            FT_CONFIG_OPTION_USE_LZW ||
327            FT_CONFIG_OPTION_USE_BZIP2) */
328
329       goto Fail;
330
331 #endif
332     }
333
334     /* PCF cannot have multiple faces in a single font file.
335      * XXX: A non-zero face_index is already an invalid argument, but
336      *      Type1, Type42 drivers have a convention to return
337      *      an invalid argument error when the font could be
338      *      opened by the specified driver.
339      */
340     if ( face_index < 0 )
341       goto Exit;
342     else if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 )
343     {
344       FT_ERROR(( "PCF_Face_Init: invalid face index\n" ));
345       PCF_Face_Done( pcfface );
346       return FT_THROW( Invalid_Argument );
347     }
348
349     /* set up charmap */
350     {
351       FT_String  *charset_registry = face->charset_registry;
352       FT_String  *charset_encoding = face->charset_encoding;
353       FT_Bool     unicode_charmap  = 0;
354
355
356       if ( charset_registry && charset_encoding )
357       {
358         char*  s = charset_registry;
359
360
361         /* Uh, oh, compare first letters manually to avoid dependency
362            on locales. */
363         if ( ( s[0] == 'i' || s[0] == 'I' ) &&
364              ( s[1] == 's' || s[1] == 'S' ) &&
365              ( s[2] == 'o' || s[2] == 'O' ) )
366         {
367           s += 3;
368           if ( !ft_strcmp( s, "10646" )                      ||
369                ( !ft_strcmp( s, "8859" ) &&
370                  !ft_strcmp( face->charset_encoding, "1" ) ) )
371             unicode_charmap = 1;
372           /* another name for ASCII */
373           else if ( !ft_strcmp( s, "646.1991" )                 &&
374                     !ft_strcmp( face->charset_encoding, "IRV" ) )
375             unicode_charmap = 1;
376         }
377       }
378
379       {
380         FT_CharMapRec  charmap;
381
382
383         charmap.face        = FT_FACE( face );
384         charmap.encoding    = FT_ENCODING_NONE;
385         /* initial platform/encoding should indicate unset status? */
386         charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
387         charmap.encoding_id = TT_APPLE_ID_DEFAULT;
388
389         if ( unicode_charmap )
390         {
391           charmap.encoding    = FT_ENCODING_UNICODE;
392           charmap.platform_id = TT_PLATFORM_MICROSOFT;
393           charmap.encoding_id = TT_MS_ID_UNICODE_CS;
394         }
395
396         error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL );
397       }
398     }
399
400   Exit:
401     return error;
402
403   Fail:
404     FT_TRACE2(( "  not a PCF file\n" ));
405     PCF_Face_Done( pcfface );
406     error = FT_THROW( Unknown_File_Format );  /* error */
407     goto Exit;
408   }
409
410
411   FT_CALLBACK_DEF( FT_Error )
412   PCF_Size_Select( FT_Size   size,
413                    FT_ULong  strike_index )
414   {
415     PCF_Accel  accel = &( (PCF_Face)size->face )->accel;
416
417
418     FT_Select_Metrics( size->face, strike_index );
419
420     size->metrics.ascender    =  accel->fontAscent * 64;
421     size->metrics.descender   = -accel->fontDescent * 64;
422     size->metrics.max_advance =  accel->maxbounds.characterWidth * 64;
423
424     return FT_Err_Ok;
425   }
426
427
428   FT_CALLBACK_DEF( FT_Error )
429   PCF_Size_Request( FT_Size          size,
430                     FT_Size_Request  req )
431   {
432     PCF_Face         face  = (PCF_Face)size->face;
433     FT_Bitmap_Size*  bsize = size->face->available_sizes;
434     FT_Error         error = FT_ERR( Invalid_Pixel_Size );
435     FT_Long          height;
436
437
438     height = FT_REQUEST_HEIGHT( req );
439     height = ( height + 32 ) >> 6;
440
441     switch ( req->type )
442     {
443     case FT_SIZE_REQUEST_TYPE_NOMINAL:
444       if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) )
445         error = FT_Err_Ok;
446       break;
447
448     case FT_SIZE_REQUEST_TYPE_REAL_DIM:
449       if ( height == ( face->accel.fontAscent +
450                        face->accel.fontDescent ) )
451         error = FT_Err_Ok;
452       break;
453
454     default:
455       error = FT_THROW( Unimplemented_Feature );
456       break;
457     }
458
459     if ( error )
460       return error;
461     else
462       return PCF_Size_Select( size, 0 );
463   }
464
465
466   FT_CALLBACK_DEF( FT_Error )
467   PCF_Glyph_Load( FT_GlyphSlot  slot,
468                   FT_Size       size,
469                   FT_UInt       glyph_index,
470                   FT_Int32      load_flags )
471   {
472     PCF_Face    face   = (PCF_Face)FT_SIZE_FACE( size );
473     FT_Stream   stream;
474     FT_Error    error  = FT_Err_Ok;
475     FT_Bitmap*  bitmap = &slot->bitmap;
476     PCF_Metric  metric;
477     FT_ULong    bytes;
478
479
480     FT_TRACE1(( "PCF_Glyph_Load: glyph index %d\n", glyph_index ));
481
482     if ( !face )
483     {
484       error = FT_THROW( Invalid_Face_Handle );
485       goto Exit;
486     }
487
488     if ( glyph_index >= (FT_UInt)face->root.num_glyphs )
489     {
490       error = FT_THROW( Invalid_Argument );
491       goto Exit;
492     }
493
494     stream = face->root.stream;
495
496     metric = face->metrics + glyph_index;
497
498     bitmap->rows       = (unsigned int)( metric->ascent +
499                                          metric->descent );
500     bitmap->width      = (unsigned int)( metric->rightSideBearing -
501                                          metric->leftSideBearing );
502     bitmap->num_grays  = 1;
503     bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
504
505     switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) )
506     {
507     case 1:
508       bitmap->pitch = (int)( ( bitmap->width + 7 ) >> 3 );
509       break;
510
511     case 2:
512       bitmap->pitch = (int)( ( ( bitmap->width + 15 ) >> 4 ) << 1 );
513       break;
514
515     case 4:
516       bitmap->pitch = (int)( ( ( bitmap->width + 31 ) >> 5 ) << 2 );
517       break;
518
519     case 8:
520       bitmap->pitch = (int)( ( ( bitmap->width + 63 ) >> 6 ) << 3 );
521       break;
522
523     default:
524       return FT_THROW( Invalid_File_Format );
525     }
526
527     slot->format      = FT_GLYPH_FORMAT_BITMAP;
528     slot->bitmap_left = metric->leftSideBearing;
529     slot->bitmap_top  = metric->ascent;
530
531     slot->metrics.horiAdvance  = (FT_Pos)( metric->characterWidth * 64 );
532     slot->metrics.horiBearingX = (FT_Pos)( metric->leftSideBearing * 64 );
533     slot->metrics.horiBearingY = (FT_Pos)( metric->ascent * 64 );
534     slot->metrics.width        = (FT_Pos)( ( metric->rightSideBearing -
535                                              metric->leftSideBearing ) * 64 );
536     slot->metrics.height       = (FT_Pos)( bitmap->rows * 64 );
537
538     ft_synthesize_vertical_metrics( &slot->metrics,
539                                     ( face->accel.fontAscent +
540                                       face->accel.fontDescent ) * 64 );
541
542     if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY )
543       goto Exit;
544
545     /* XXX: to do: are there cases that need repadding the bitmap? */
546     bytes = (FT_ULong)bitmap->pitch * bitmap->rows;
547
548     error = ft_glyphslot_alloc_bitmap( slot, (FT_ULong)bytes );
549     if ( error )
550       goto Exit;
551
552     if ( FT_STREAM_SEEK( metric->bits )          ||
553          FT_STREAM_READ( bitmap->buffer, bytes ) )
554       goto Exit;
555
556     if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst )
557       BitOrderInvert( bitmap->buffer, bytes );
558
559     if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) !=
560            PCF_BIT_ORDER( face->bitmapsFormat )  ) )
561     {
562       switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) )
563       {
564       case 1:
565         break;
566
567       case 2:
568         TwoByteSwap( bitmap->buffer, bytes );
569         break;
570
571       case 4:
572         FourByteSwap( bitmap->buffer, bytes );
573         break;
574       }
575     }
576
577   Exit:
578     return error;
579   }
580
581
582   /*
583    *
584    * BDF SERVICE
585    *
586    */
587
588   static FT_Error
589   pcf_get_bdf_property( PCF_Face          face,
590                         const char*       prop_name,
591                         BDF_PropertyRec  *aproperty )
592   {
593     PCF_Property  prop;
594
595
596     prop = pcf_find_property( face, prop_name );
597     if ( prop )
598     {
599       if ( prop->isString )
600       {
601         aproperty->type   = BDF_PROPERTY_TYPE_ATOM;
602         aproperty->u.atom = prop->value.atom;
603       }
604       else
605       {
606         if ( prop->value.l > 0x7FFFFFFFL          ||
607              prop->value.l < ( -1 - 0x7FFFFFFFL ) )
608         {
609           FT_TRACE1(( "pcf_get_bdf_property:"
610                       " too large integer 0x%lx is truncated\n",
611                       prop->value.l ));
612         }
613
614         /*
615          * The PCF driver loads all properties as signed integers.
616          * This really doesn't seem to be a problem, because this is
617          * sufficient for any meaningful values.
618          */
619         aproperty->type      = BDF_PROPERTY_TYPE_INTEGER;
620         aproperty->u.integer = (FT_Int32)prop->value.l;
621       }
622
623       return FT_Err_Ok;
624     }
625
626     return FT_THROW( Invalid_Argument );
627   }
628
629
630   static FT_Error
631   pcf_get_charset_id( PCF_Face      face,
632                       const char*  *acharset_encoding,
633                       const char*  *acharset_registry )
634   {
635     *acharset_encoding = face->charset_encoding;
636     *acharset_registry = face->charset_registry;
637
638     return FT_Err_Ok;
639   }
640
641
642   static const FT_Service_BDFRec  pcf_service_bdf =
643   {
644     (FT_BDF_GetCharsetIdFunc)pcf_get_charset_id,     /* get_charset_id */
645     (FT_BDF_GetPropertyFunc) pcf_get_bdf_property    /* get_property   */
646   };
647
648
649   /*
650    * PROPERTY SERVICE
651    *
652    */
653   static FT_Error
654   pcf_property_set( FT_Module    module,         /* PCF_Driver */
655                     const char*  property_name,
656                     const void*  value,
657                     FT_Bool      value_is_string )
658   {
659 #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
660
661     FT_Error    error  = FT_Err_Ok;
662     PCF_Driver  driver = (PCF_Driver)module;
663
664 #ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
665     FT_UNUSED( value_is_string );
666 #endif
667
668
669     if ( !ft_strcmp( property_name, "no-long-family-names" ) )
670     {
671 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
672       if ( value_is_string )
673       {
674         const char*  s   = (const char*)value;
675         long         lfn = ft_strtol( s, NULL, 10 );
676
677
678         if ( lfn == 0 )
679           driver->no_long_family_names = 0;
680         else if ( lfn == 1 )
681           driver->no_long_family_names = 1;
682         else
683           return FT_THROW( Invalid_Argument );
684       }
685       else
686 #endif
687       {
688         FT_Bool*  no_long_family_names = (FT_Bool*)value;
689
690
691         driver->no_long_family_names = *no_long_family_names;
692       }
693
694       return error;
695     }
696
697 #else /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
698
699     FT_UNUSED( module );
700     FT_UNUSED( value );
701     FT_UNUSED( value_is_string );
702 #ifndef FT_DEBUG_LEVEL_TRACE
703     FT_UNUSED( property_name );
704 #endif
705
706 #endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
707
708     FT_TRACE0(( "pcf_property_set: missing property `%s'\n",
709                 property_name ));
710     return FT_THROW( Missing_Property );
711   }
712
713
714   static FT_Error
715   pcf_property_get( FT_Module    module,         /* PCF_Driver */
716                     const char*  property_name,
717                     const void*  value )
718   {
719 #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
720
721     FT_Error    error  = FT_Err_Ok;
722     PCF_Driver  driver = (PCF_Driver)module;
723
724
725     if ( !ft_strcmp( property_name, "no-long-family-names" ) )
726     {
727       FT_Bool   no_long_family_names = driver->no_long_family_names;
728       FT_Bool*  val                  = (FT_Bool*)value;
729
730
731       *val = no_long_family_names;
732
733       return error;
734     }
735
736 #else /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
737
738     FT_UNUSED( module );
739     FT_UNUSED( value );
740 #ifndef FT_DEBUG_LEVEL_TRACE
741     FT_UNUSED( property_name );
742 #endif
743
744 #endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
745
746     FT_TRACE0(( "pcf_property_get: missing property `%s'\n",
747                 property_name ));
748     return FT_THROW( Missing_Property );
749   }
750
751
752   FT_DEFINE_SERVICE_PROPERTIESREC(
753     pcf_service_properties,
754
755     (FT_Properties_SetFunc)pcf_property_set,      /* set_property */
756     (FT_Properties_GetFunc)pcf_property_get )     /* get_property */
757
758
759   /*
760    *
761    * SERVICE LIST
762    *
763    */
764
765   static const FT_ServiceDescRec  pcf_services[] =
766   {
767     { FT_SERVICE_ID_BDF,         &pcf_service_bdf },
768     { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_PCF },
769     { FT_SERVICE_ID_PROPERTIES,  &pcf_service_properties },
770     { NULL, NULL }
771   };
772
773
774   FT_CALLBACK_DEF( FT_Module_Interface )
775   pcf_driver_requester( FT_Module    module,
776                         const char*  name )
777   {
778     FT_UNUSED( module );
779
780     return ft_service_list_lookup( pcf_services, name );
781   }
782
783
784   FT_CALLBACK_DEF( FT_Error )
785   pcf_driver_init( FT_Module  module )      /* PCF_Driver */
786   {
787 #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
788     PCF_Driver  driver = (PCF_Driver)module;
789
790
791     driver->no_long_family_names = 0;
792 #else
793     FT_UNUSED( module );
794 #endif
795
796     return FT_Err_Ok;
797   }
798
799
800   FT_CALLBACK_DEF( void )
801   pcf_driver_done( FT_Module  module )      /* PCF_Driver */
802   {
803     FT_UNUSED( module );
804   }
805
806
807   FT_CALLBACK_TABLE_DEF
808   const FT_Driver_ClassRec  pcf_driver_class =
809   {
810     {
811       FT_MODULE_FONT_DRIVER        |
812       FT_MODULE_DRIVER_NO_OUTLINES,
813
814       sizeof ( PCF_DriverRec ),
815       "pcf",
816       0x10000L,
817       0x20000L,
818
819       NULL,   /* module-specific interface */
820
821       pcf_driver_init,          /* FT_Module_Constructor  module_init   */
822       pcf_driver_done,          /* FT_Module_Destructor   module_done   */
823       pcf_driver_requester      /* FT_Module_Requester    get_interface */
824     },
825
826     sizeof ( PCF_FaceRec ),
827     sizeof ( FT_SizeRec ),
828     sizeof ( FT_GlyphSlotRec ),
829
830     PCF_Face_Init,              /* FT_Face_InitFunc  init_face */
831     PCF_Face_Done,              /* FT_Face_DoneFunc  done_face */
832     NULL,                       /* FT_Size_InitFunc  init_size */
833     NULL,                       /* FT_Size_DoneFunc  done_size */
834     NULL,                       /* FT_Slot_InitFunc  init_slot */
835     NULL,                       /* FT_Slot_DoneFunc  done_slot */
836
837     PCF_Glyph_Load,             /* FT_Slot_LoadFunc  load_glyph */
838
839     NULL,                       /* FT_Face_GetKerningFunc   get_kerning  */
840     NULL,                       /* FT_Face_AttachFunc       attach_file  */
841     NULL,                       /* FT_Face_GetAdvancesFunc  get_advances */
842
843     PCF_Size_Request,           /* FT_Size_RequestFunc  request_size */
844     PCF_Size_Select             /* FT_Size_SelectFunc   select_size  */
845   };
846
847
848 /* END */