update for HEAD-2003050101
[reactos.git] / lib / freetype / src / pcf / pcfdriver.c
1 /*  pcfdriver.c
2
3     FreeType font driver for pcf files
4
5     Copyright (C) 2000-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
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_ERRORS_H
35 #include FT_BDF_H
36
37 #include "pcf.h"
38 #include "pcfdriver.h"
39 #include "pcfutil.h"
40 #include "pcfread.h"
41
42 #include "pcferror.h"
43
44 #undef  FT_COMPONENT
45 #define FT_COMPONENT  trace_pcfread
46
47
48   typedef struct  PCF_CMapRec_
49   {
50     FT_CMapRec    cmap;
51     FT_UInt       num_encodings;
52     PCF_Encoding  encodings;
53
54   } PCF_CMapRec, *PCF_CMap;
55
56
57   FT_CALLBACK_DEF( FT_Error )
58   pcf_cmap_init( PCF_CMap  cmap )
59   {
60     PCF_Face  face = (PCF_Face)FT_CMAP_FACE( cmap );
61
62
63     cmap->num_encodings = (FT_UInt)face->nencodings;
64     cmap->encodings     = face->encodings;
65
66     return FT_Err_Ok;
67   }
68
69
70   FT_CALLBACK_DEF( void )
71   pcf_cmap_done( PCF_CMap  cmap )
72   {
73     cmap->encodings     = NULL;
74     cmap->num_encodings = 0;
75   }
76
77
78   FT_CALLBACK_DEF( FT_UInt )
79   pcf_cmap_char_index( PCF_CMap   cmap,
80                        FT_UInt32  charcode )
81   {
82     PCF_Encoding  encodings = cmap->encodings;
83     FT_UInt       min, max, mid;
84     FT_UInt       result = 0;
85
86
87     min = 0;
88     max = cmap->num_encodings;
89
90     while ( min < max )
91     {
92       FT_UInt32  code;
93
94
95       mid  = ( min + max ) >> 1;
96       code = encodings[mid].enc;
97
98       if ( charcode == code )
99       {
100         result = encodings[mid].glyph + 1;
101         break;
102       }
103
104       if ( charcode < code )
105         max = mid;
106       else
107         min = mid + 1;
108     }
109
110     return result;
111   }
112
113
114   FT_CALLBACK_DEF( FT_UInt )
115   pcf_cmap_char_next( PCF_CMap    cmap,
116                       FT_UInt32  *acharcode )
117   {
118     PCF_Encoding  encodings = cmap->encodings;
119     FT_UInt       min, max, mid;
120     FT_UInt32     charcode = *acharcode + 1;
121     FT_UInt       result   = 0;
122
123
124     min = 0;
125     max = cmap->num_encodings;
126
127     while ( min < max )
128     {
129       FT_UInt32  code;
130
131
132       mid  = ( min + max ) >> 1;
133       code = encodings[mid].enc;
134
135       if ( charcode == code )
136       {
137         result = encodings[mid].glyph + 1;
138         goto Exit;
139       }
140
141       if ( charcode < code )
142         max = mid;
143       else
144         min = mid + 1;
145     }
146
147     charcode = 0;
148     if ( min < cmap->num_encodings )
149     {
150       charcode = encodings[min].enc;
151       result   = encodings[min].glyph + 1;
152     }
153
154   Exit:
155     *acharcode = charcode;
156     return result;
157   }
158
159
160   FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec  pcf_cmap_class =
161   {
162     sizeof( PCF_CMapRec ),
163     (FT_CMap_InitFunc)     pcf_cmap_init,
164     (FT_CMap_DoneFunc)     pcf_cmap_done,
165     (FT_CMap_CharIndexFunc)pcf_cmap_char_index,
166     (FT_CMap_CharNextFunc) pcf_cmap_char_next
167   };
168
169
170   /*************************************************************************/
171   /*                                                                       */
172   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
173   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
174   /* messages during execution.                                            */
175   /*                                                                       */
176 #undef  FT_COMPONENT
177 #define FT_COMPONENT  trace_pcfdriver
178
179
180   FT_CALLBACK_DEF( FT_Error )
181   PCF_Face_Done( PCF_Face  face )
182   {
183     FT_Memory  memory = FT_FACE_MEMORY( face );
184
185
186     FT_FREE( face->encodings );
187     FT_FREE( face->metrics );
188
189     /* free properties */
190     {
191       PCF_Property  prop = face->properties;
192       FT_Int        i;
193
194
195       for ( i = 0; i < face->nprops; i++ )
196       {
197         prop = &face->properties[i];
198
199         FT_FREE( prop->name );
200         if ( prop->isString )
201           FT_FREE( prop->value );
202       }
203
204       FT_FREE( face->properties );
205     }
206
207     FT_FREE( face->toc.tables );
208     FT_FREE( face->root.family_name );
209     FT_FREE( face->root.available_sizes );
210     FT_FREE( face->charset_encoding );
211     FT_FREE( face->charset_registry );
212
213     FT_TRACE4(( "PCF_Face_Done: done face\n" ));
214
215     /* close gzip stream if any */
216     if ( face->root.stream == &face->gzip_stream )
217     {
218       FT_Stream_Close( &face->gzip_stream );
219       face->root.stream = face->gzip_source;
220     }
221
222     return PCF_Err_Ok;
223   }
224
225
226   FT_CALLBACK_DEF( FT_Error )
227   PCF_Face_Init( FT_Stream      stream,
228                  PCF_Face       face,
229                  FT_Int         face_index,
230                  FT_Int         num_params,
231                  FT_Parameter*  params )
232   {
233     FT_Error  error = PCF_Err_Ok;
234
235     FT_UNUSED( num_params );
236     FT_UNUSED( params );
237     FT_UNUSED( face_index );
238
239
240     error = pcf_load_font( stream, face );
241     if ( error )
242     {
243       FT_Error  error2;
244
245       /* this didn't work, try gzip support !! */
246       error2 = FT_Stream_OpenGzip( &face->gzip_stream, stream );
247       if ( error2 == FT_Err_Unimplemented_Feature )
248         goto Fail;
249
250       error = error2;
251       if ( error )
252         goto Fail;
253
254       face->gzip_source = stream;
255       face->root.stream = &face->gzip_stream;
256
257       stream = face->root.stream;
258
259       error = pcf_load_font( stream, face );
260       if ( error )
261         goto Fail;
262     }
263
264     /* set-up charmap */
265     {
266       FT_String  *charset_registry, *charset_encoding;
267       FT_Bool     unicode_charmap  = 0;
268
269
270       charset_registry = face->charset_registry;
271       charset_encoding = face->charset_encoding;
272
273       if ( ( charset_registry != NULL ) &&
274            ( charset_encoding != NULL ) )
275       {
276         if ( !ft_strcmp( face->charset_registry, "ISO10646" )     ||
277              ( !ft_strcmp( face->charset_registry, "ISO8859" ) &&
278                !ft_strcmp( face->charset_encoding, "1" )       )  )
279           unicode_charmap = 1;
280       }
281
282       {
283         FT_CharMapRec  charmap;
284
285
286         charmap.face        = FT_FACE( face );
287         charmap.encoding    = FT_ENCODING_NONE;
288         charmap.platform_id = 0;
289         charmap.encoding_id = 0;
290
291         if ( unicode_charmap )
292         {
293           charmap.encoding    = FT_ENCODING_UNICODE;
294           charmap.platform_id = 3;
295           charmap.encoding_id = 1;
296         }
297
298         error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL );
299
300 #if 0
301         /* Select default charmap */
302         if (face->root.num_charmaps)
303           face->root.charmap = face->root.charmaps[0];
304 #endif
305       }
306     }
307
308   Exit:
309     return error;
310
311   Fail:
312     FT_TRACE2(( "[not a valid PCF file]\n" ));
313     error = PCF_Err_Unknown_File_Format;  /* error */
314     goto Exit;
315   }
316
317
318   static FT_Error
319   PCF_Set_Pixel_Size( FT_Size  size )
320   {
321     PCF_Face face = (PCF_Face)FT_SIZE_FACE( size );
322
323
324     FT_TRACE4(( "rec %d - pres %d\n", size->metrics.y_ppem,
325                                       face->root.available_sizes->height ));
326
327     if ( size->metrics.y_ppem == face->root.available_sizes->height )
328     {
329       size->metrics.ascender    = face->accel.fontAscent << 6;
330       size->metrics.descender   = face->accel.fontDescent * (-64);
331 #if 0
332       size->metrics.height      = face->accel.maxbounds.ascent << 6;
333 #endif
334       size->metrics.height      = size->metrics.ascender -
335                                   size->metrics.descender;
336
337       size->metrics.max_advance = face->accel.maxbounds.characterWidth << 6;
338
339       return PCF_Err_Ok;
340     }
341     else
342     {
343       FT_TRACE4(( "size WRONG\n" ));
344       return PCF_Err_Invalid_Pixel_Size;
345     }
346   }
347
348
349   static FT_Error
350   PCF_Glyph_Load( FT_GlyphSlot  slot,
351                   FT_Size       size,
352                   FT_UInt       glyph_index,
353                   FT_Int32      load_flags )
354   {
355     PCF_Face    face   = (PCF_Face)FT_SIZE_FACE( size );
356     FT_Stream   stream = face->root.stream;
357     FT_Error    error  = PCF_Err_Ok;
358     FT_Bitmap*  bitmap = &slot->bitmap;
359     PCF_Metric  metric;
360     int         bytes;
361
362     FT_UNUSED( load_flags );
363
364
365     FT_TRACE4(( "load_glyph %d ---", glyph_index ));
366
367     if ( !face )
368     {
369       error = PCF_Err_Invalid_Argument;
370       goto Exit;
371     }
372
373     if ( glyph_index > 0 )
374       glyph_index--;
375
376     metric = face->metrics + glyph_index;
377
378     bitmap->rows       = metric->ascent + metric->descent;
379     bitmap->width      = metric->rightSideBearing - metric->leftSideBearing;
380     bitmap->num_grays  = 1;
381     bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
382
383     FT_TRACE6(( "BIT_ORDER %d ; BYTE_ORDER %d ; GLYPH_PAD %d\n",
384                   PCF_BIT_ORDER( face->bitmapsFormat ),
385                   PCF_BYTE_ORDER( face->bitmapsFormat ),
386                   PCF_GLYPH_PAD( face->bitmapsFormat ) ));
387
388     switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) )
389     {
390     case 1:
391       bitmap->pitch = ( bitmap->width + 7 ) >> 3;
392       break;
393
394     case 2:
395       bitmap->pitch = ( ( bitmap->width + 15 ) >> 4 ) << 1;
396       break;
397
398     case 4:
399       bitmap->pitch = ( ( bitmap->width + 31 ) >> 5 ) << 2;
400       break;
401
402     case 8:
403       bitmap->pitch = ( ( bitmap->width + 63 ) >> 6 ) << 3;
404       break;
405
406     default:
407       return PCF_Err_Invalid_File_Format;
408     }
409
410     /* XXX: to do: are there cases that need repadding the bitmap? */
411     bytes = bitmap->pitch * bitmap->rows;
412
413     error = ft_glyphslot_alloc_bitmap( slot, bytes );
414     if ( error )
415       goto Exit;
416
417     if ( FT_STREAM_SEEK( metric->bits )          ||
418          FT_STREAM_READ( bitmap->buffer, bytes ) )
419       goto Exit;
420
421     if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst )
422       BitOrderInvert( bitmap->buffer, bytes );
423
424     if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) !=
425            PCF_BIT_ORDER( face->bitmapsFormat )  ) )
426     {
427       switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) )
428       {
429       case 1:
430         break;
431
432       case 2:
433         TwoByteSwap( bitmap->buffer, bytes );
434         break;
435
436       case 4:
437         FourByteSwap( bitmap->buffer, bytes );
438         break;
439       }
440     }
441
442     slot->bitmap_left = metric->leftSideBearing;
443     slot->bitmap_top  = metric->ascent;
444
445     slot->metrics.horiAdvance  = metric->characterWidth << 6 ;
446     slot->metrics.horiBearingX = metric->leftSideBearing << 6 ;
447     slot->metrics.horiBearingY = metric->ascent << 6 ;
448     slot->metrics.width        = ( metric->rightSideBearing -
449                                    metric->leftSideBearing ) << 6;
450     slot->metrics.height       = bitmap->rows << 6;
451
452     slot->linearHoriAdvance = (FT_Fixed)bitmap->width << 16;
453     slot->format            = FT_GLYPH_FORMAT_BITMAP;
454
455     FT_TRACE4(( " --- ok\n" ));
456
457   Exit:
458     return error;
459   }
460
461
462   static FT_Error
463   pcf_get_bdf_property( PCF_Face          face,
464                         const char*       prop_name,
465                         BDF_PropertyRec  *aproperty )
466   {
467     PCF_Property   prop;
468
469     prop = pcf_find_property( face, prop_name );
470     if ( prop != NULL )
471     {
472       if ( prop->isString )
473       {
474         aproperty->type   = BDF_PROPERTY_TYPE_ATOM;
475         aproperty->u.atom = prop->value.atom;
476       }
477       else
478       {
479        /* apparently, the PCF driver loads all properties as signed integers !
480         * this really doesn't seem to be a problem, because this is
481         * sufficient for any meaningful values
482         */
483         aproperty->type      = BDF_PROPERTY_TYPE_INTEGER;
484         aproperty->u.integer = prop->value.integer;
485       }
486       return 0;
487     }
488     return FT_Err_Invalid_Argument;
489   }
490
491
492   static FT_Module_Interface
493   pcf_driver_requester( FT_Module    module,
494                         const char*  name )
495   {
496     FT_UNUSED( module );
497
498     if ( name && ft_strcmp( name, "get_bdf_property" ) == 0 )
499       return (FT_Module_Interface) pcf_get_bdf_property;
500
501     return NULL;
502   }
503
504
505   FT_CALLBACK_TABLE_DEF
506   const FT_Driver_ClassRec  pcf_driver_class =
507   {
508     {
509       ft_module_font_driver,
510       sizeof ( FT_DriverRec ),
511
512       "pcf",
513       0x10000L,
514       0x20000L,
515
516       0,
517
518       (FT_Module_Constructor)0,
519       (FT_Module_Destructor) 0,
520       (FT_Module_Requester)  pcf_driver_requester
521     },
522
523     sizeof( PCF_FaceRec ),
524     sizeof( FT_SizeRec ),
525     sizeof( FT_GlyphSlotRec ),
526
527     (FT_Face_InitFunc)        PCF_Face_Init,
528     (FT_Face_DoneFunc)        PCF_Face_Done,
529     (FT_Size_InitFunc)        0,
530     (FT_Size_DoneFunc)        0,
531     (FT_Slot_InitFunc)        0,
532     (FT_Slot_DoneFunc)        0,
533
534     (FT_Size_ResetPointsFunc) PCF_Set_Pixel_Size,
535     (FT_Size_ResetPixelsFunc) PCF_Set_Pixel_Size,
536
537     (FT_Slot_LoadFunc)        PCF_Glyph_Load,
538
539     (FT_Face_GetKerningFunc)  0,
540     (FT_Face_AttachFunc)      0,
541     (FT_Face_GetAdvancesFunc) 0
542   };
543
544
545 /* END */