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