1/* bdfdrivr.c
2
3 FreeType font driver for bdf files
4
5 Copyright (C) 2001-2008, 2011, 2013, 2014 by
6 Francesco Zappa Nardelli
7
8Permission is hereby granted, free of charge, to any person obtaining a copy
9of this software and associated documentation files (the "Software"), to deal
10in the Software without restriction, including without limitation the rights
11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12copies of the Software, and to permit persons to whom the Software is
13furnished to do so, subject to the following conditions:
14
15The above copyright notice and this permission notice shall be included in
16all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24THE SOFTWARE.
25*/
26
27
28#include <freetype/internal/ftdebug.h>
29#include <freetype/internal/ftstream.h>
30#include <freetype/internal/ftobjs.h>
31#include <freetype/ftbdf.h>
32#include <freetype/ttnameid.h>
33
34#include <freetype/internal/services/svbdf.h>
35#include <freetype/internal/services/svfntfmt.h>
36
37#include "bdf.h"
38#include "bdfdrivr.h"
39
40#include "bdferror.h"
41
42
43 /**************************************************************************
44 *
45 * The macro FT_COMPONENT is used in trace mode. It is an implicit
46 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
47 * messages during execution.
48 */
49#undef FT_COMPONENT
50#define FT_COMPONENT bdfdriver
51
52
53 typedef struct BDF_CMapRec_
54 {
55 FT_CMapRec cmap;
56 FT_ULong num_encodings; /* ftobjs.h: FT_CMap->clazz->size */
57 BDF_encoding_el* encodings;
58
59 } BDF_CMapRec, *BDF_CMap;
60
61
62 FT_CALLBACK_DEF( FT_Error )
63 bdf_cmap_init( FT_CMap bdfcmap,
64 FT_Pointer init_data )
65 {
66 BDF_CMap cmap = (BDF_CMap)bdfcmap;
67 BDF_Face face = (BDF_Face)FT_CMAP_FACE( cmap );
68 FT_UNUSED( init_data );
69
70
71 cmap->num_encodings = face->bdffont->glyphs_used;
72 cmap->encodings = face->en_table;
73
74 return FT_Err_Ok;
75 }
76
77
78 FT_CALLBACK_DEF( void )
79 bdf_cmap_done( FT_CMap bdfcmap )
80 {
81 BDF_CMap cmap = (BDF_CMap)bdfcmap;
82
83
84 cmap->encodings = NULL;
85 cmap->num_encodings = 0;
86 }
87
88
89 FT_CALLBACK_DEF( FT_UInt )
90 bdf_cmap_char_index( FT_CMap bdfcmap,
91 FT_UInt32 charcode )
92 {
93 BDF_CMap cmap = (BDF_CMap)bdfcmap;
94 BDF_encoding_el* encodings = cmap->encodings;
95 FT_UShort result = 0; /* encodings->glyph */
96
97 FT_ULong min = 0;
98 FT_ULong max = cmap->num_encodings;
99 FT_ULong mid = ( min + max ) >> 1;
100
101
102 while ( min < max )
103 {
104 FT_ULong code = encodings[mid].enc;
105
106
107 if ( charcode == code )
108 {
109 /* increase glyph index by 1 -- */
110 /* we reserve slot 0 for the undefined glyph */
111 result = encodings[mid].glyph + 1;
112 break;
113 }
114
115 if ( charcode < code )
116 max = mid;
117 else
118 min = mid + 1;
119
120 /* reasonable prediction in a continuous block */
121 mid += charcode - code;
122 if ( mid >= max || mid < min )
123 mid = ( min + max ) >> 1;
124 }
125
126 return result;
127 }
128
129
130 FT_CALLBACK_DEF( FT_UInt )
131 bdf_cmap_char_next( FT_CMap bdfcmap,
132 FT_UInt32 *acharcode )
133 {
134 BDF_CMap cmap = (BDF_CMap)bdfcmap;
135 BDF_encoding_el* encodings = cmap->encodings;
136 FT_UShort result = 0; /* encodings->glyph */
137 FT_ULong charcode = *acharcode + 1;
138
139 FT_ULong min = 0;
140 FT_ULong max = cmap->num_encodings;
141 FT_ULong mid = ( min + max ) >> 1;
142
143
144 while ( min < max )
145 {
146 FT_ULong code = encodings[mid].enc;
147
148
149 if ( charcode == code )
150 {
151 /* increase glyph index by 1 -- */
152 /* we reserve slot 0 for the undefined glyph */
153 result = encodings[mid].glyph + 1;
154 goto Exit;
155 }
156
157 if ( charcode < code )
158 max = mid;
159 else
160 min = mid + 1;
161
162 /* prediction in a continuous block */
163 mid += charcode - code;
164 if ( mid >= max || mid < min )
165 mid = ( min + max ) >> 1;
166 }
167
168 charcode = 0;
169 if ( min < cmap->num_encodings )
170 {
171 charcode = encodings[min].enc;
172 result = encodings[min].glyph + 1;
173 }
174
175 Exit:
176 if ( charcode > 0xFFFFFFFFUL )
177 {
178 FT_TRACE1(( "bdf_cmap_char_next: charcode 0x%lx > 32bit API",
179 charcode ));
180 *acharcode = 0;
181 /* XXX: result should be changed to indicate an overflow error */
182 }
183 else
184 *acharcode = (FT_UInt32)charcode;
185 return result;
186 }
187
188
189 static
190 const FT_CMap_ClassRec bdf_cmap_class =
191 {
192 sizeof ( BDF_CMapRec ),
193 bdf_cmap_init,
194 bdf_cmap_done,
195 bdf_cmap_char_index,
196 bdf_cmap_char_next,
197
198 NULL, NULL, NULL, NULL, NULL
199 };
200
201
202 static FT_Error
203 bdf_interpret_style( BDF_Face bdf )
204 {
205 FT_Error error = FT_Err_Ok;
206 FT_Face face = FT_FACE( bdf );
207 FT_Memory memory = face->memory;
208 bdf_font_t* font = bdf->bdffont;
209 bdf_property_t* prop;
210
211 const char* strings[4] = { NULL, NULL, NULL, NULL };
212 size_t lengths[4], nn, len;
213
214
215 face->style_flags = 0;
216
217 prop = bdf_get_font_property( font, "SLANT" );
218 if ( prop && prop->format == BDF_ATOM &&
219 prop->value.atom &&
220 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
221 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
222 {
223 face->style_flags |= FT_STYLE_FLAG_ITALIC;
224 strings[2] = ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' )
225 ? "Oblique"
226 : "Italic";
227 }
228
229 prop = bdf_get_font_property( font, "WEIGHT_NAME" );
230 if ( prop && prop->format == BDF_ATOM &&
231 prop->value.atom &&
232 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
233 {
234 face->style_flags |= FT_STYLE_FLAG_BOLD;
235 strings[1] = "Bold";
236 }
237
238 prop = bdf_get_font_property( font, "SETWIDTH_NAME" );
239 if ( prop && prop->format == BDF_ATOM &&
240 prop->value.atom && *(prop->value.atom) &&
241 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
242 strings[3] = (const char *)(prop->value.atom);
243
244 prop = bdf_get_font_property( font, "ADD_STYLE_NAME" );
245 if ( prop && prop->format == BDF_ATOM &&
246 prop->value.atom && *(prop->value.atom) &&
247 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
248 strings[0] = (const char *)(prop->value.atom);
249
250 for ( len = 0, nn = 0; nn < 4; nn++ )
251 {
252 lengths[nn] = 0;
253 if ( strings[nn] )
254 {
255 lengths[nn] = ft_strlen( strings[nn] );
256 len += lengths[nn] + 1;
257 }
258 }
259
260 if ( len == 0 )
261 {
262 strings[0] = "Regular";
263 lengths[0] = ft_strlen( strings[0] );
264 len = lengths[0] + 1;
265 }
266
267 {
268 char* s;
269
270
271 if ( FT_QALLOC( face->style_name, len ) )
272 return error;
273
274 s = face->style_name;
275
276 for ( nn = 0; nn < 4; nn++ )
277 {
278 const char* src = strings[nn];
279
280
281 len = lengths[nn];
282
283 if ( !src )
284 continue;
285
286 /* separate elements with a space */
287 if ( s != face->style_name )
288 *s++ = ' ';
289
290 ft_memcpy( s, src, len );
291
292 /* need to convert spaces to dashes for */
293 /* add_style_name and setwidth_name */
294 if ( nn == 0 || nn == 3 )
295 {
296 size_t mm;
297
298
299 for ( mm = 0; mm < len; mm++ )
300 if ( s[mm] == ' ' )
301 s[mm] = '-';
302 }
303
304 s += len;
305 }
306 *s = 0;
307 }
308
309 return error;
310 }
311
312
313 FT_CALLBACK_DEF( void )
314 BDF_Face_Done( FT_Face face ) /* BDF_Face */
315 {
316 BDF_Face bdfface = (BDF_Face)face;
317 FT_Memory memory;
318
319
320 if ( !face )
321 return;
322
323 memory = FT_FACE_MEMORY( face );
324
325 bdf_free_font( bdfface->bdffont );
326
327 FT_FREE( bdfface->en_table );
328
329 FT_FREE( bdfface->charset_encoding );
330 FT_FREE( bdfface->charset_registry );
331 FT_FREE( face->family_name );
332 FT_FREE( face->style_name );
333
334 FT_FREE( face->available_sizes );
335
336 FT_FREE( bdfface->bdffont );
337 }
338
339
340 FT_CALLBACK_DEF( FT_Error )
341 BDF_Face_Init( FT_Stream stream,
342 FT_Face face, /* BDF_Face */
343 FT_Int face_index,
344 FT_Int num_params,
345 FT_Parameter* params )
346 {
347 FT_Error error = FT_Err_Ok;
348 BDF_Face bdfface = (BDF_Face)face;
349 FT_Memory memory = FT_FACE_MEMORY( face );
350
351 bdf_font_t* font = NULL;
352 bdf_options_t options;
353
354 FT_UNUSED( num_params );
355 FT_UNUSED( params );
356
357
358 FT_TRACE2(( "BDF driver\n" ));
359
360 if ( FT_STREAM_SEEK( 0 ) )
361 goto Exit;
362
363 options.correct_metrics = 1; /* FZ XXX: options semantics */
364 options.keep_unencoded = 1;
365 options.keep_comments = 0;
366 options.font_spacing = BDF_PROPORTIONAL;
367
368 error = bdf_load_font( stream, memory, &options, &font );
369 if ( FT_ERR_EQ( error, Missing_Startfont_Field ) )
370 {
371 FT_TRACE2(( " not a BDF file\n" ));
372 goto Fail;
373 }
374 else if ( error )
375 goto Exit;
376
377 /* we have a bdf font: let's construct the face object */
378 bdfface->bdffont = font;
379
380 /* BDF cannot have multiple faces in a single font file.
381 * XXX: non-zero face_index is already invalid argument, but
382 * Type1, Type42 driver has a convention to return
383 * an invalid argument error when the font could be
384 * opened by the specified driver.
385 */
386 if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 )
387 {
388 FT_ERROR(( "BDF_Face_Init: invalid face index\n" ));
389 BDF_Face_Done( face );
390 return FT_THROW( Invalid_Argument );
391 }
392
393 {
394 bdf_property_t* prop = NULL;
395
396
397 FT_TRACE4(( " number of glyphs: allocated %ld (used %ld)\n",
398 font->glyphs_size,
399 font->glyphs_used ));
400 FT_TRACE4(( " number of unencoded glyphs: allocated %ld (used %ld)\n",
401 font->unencoded_size,
402 font->unencoded_used ));
403
404 face->num_faces = 1;
405 face->face_index = 0;
406
407 face->face_flags |= FT_FACE_FLAG_FIXED_SIZES |
408 FT_FACE_FLAG_HORIZONTAL;
409
410 prop = bdf_get_font_property( font, "SPACING" );
411 if ( prop && prop->format == BDF_ATOM &&
412 prop->value.atom &&
413 ( *(prop->value.atom) == 'M' || *(prop->value.atom) == 'm' ||
414 *(prop->value.atom) == 'C' || *(prop->value.atom) == 'c' ) )
415 face->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
416
417 /* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL */
418 /* FZ XXX: I need a font to implement this */
419
420 prop = bdf_get_font_property( font, "FAMILY_NAME" );
421 if ( prop && prop->value.atom )
422 {
423 if ( FT_STRDUP( face->family_name, prop->value.atom ) )
424 goto Exit;
425 }
426 else
427 face->family_name = NULL;
428
429 if ( FT_SET_ERROR( bdf_interpret_style( bdfface ) ) )
430 goto Exit;
431
432 /* the number of glyphs (with one slot for the undefined glyph */
433 /* at position 0 and all unencoded glyphs) */
434 face->num_glyphs = (FT_Long)( font->glyphs_size + 1 );
435
436 face->num_fixed_sizes = 1;
437 if ( FT_NEW( face->available_sizes ) )
438 goto Exit;
439
440 {
441 FT_Bitmap_Size* bsize = face->available_sizes;
442 FT_Short resolution_x = 0;
443 FT_Short resolution_y = 0;
444 long value;
445
446
447 /* sanity checks */
448 if ( font->font_ascent > 0x7FFF || font->font_ascent < -0x7FFF )
449 {
450 font->font_ascent = font->font_ascent < 0 ? -0x7FFF : 0x7FFF;
451 FT_TRACE0(( "BDF_Face_Init: clamping font ascent to value %ld\n",
452 font->font_ascent ));
453 }
454 if ( font->font_descent > 0x7FFF || font->font_descent < -0x7FFF )
455 {
456 font->font_descent = font->font_descent < 0 ? -0x7FFF : 0x7FFF;
457 FT_TRACE0(( "BDF_Face_Init: clamping font descent to value %ld\n",
458 font->font_descent ));
459 }
460
461 bsize->height = (FT_Short)( font->font_ascent + font->font_descent );
462
463 prop = bdf_get_font_property( font, "AVERAGE_WIDTH" );
464 if ( prop )
465 {
466#ifdef FT_DEBUG_LEVEL_TRACE
467 if ( prop->value.l < 0 )
468 FT_TRACE0(( "BDF_Face_Init: negative average width\n" ));
469#endif
470 if ( prop->value.l > 0x7FFFL * 10 - 5 ||
471 prop->value.l < -( 0x7FFFL * 10 - 5 ) )
472 {
473 bsize->width = 0x7FFF;
474 FT_TRACE0(( "BDF_Face_Init: clamping average width to value %d\n",
475 bsize->width ));
476 }
477 else
478 bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) );
479 }
480 else
481 {
482 /* this is a heuristical value */
483 bsize->width = ( bsize->height * 2 + 1 ) / 3;
484 }
485
486 prop = bdf_get_font_property( font, "POINT_SIZE" );
487 if ( prop )
488 {
489#ifdef FT_DEBUG_LEVEL_TRACE
490 if ( prop->value.l < 0 )
491 FT_TRACE0(( "BDF_Face_Init: negative point size\n" ));
492#endif
493 /* convert from 722.7 decipoints to 72 points per inch */
494 if ( prop->value.l > 0x504C2L || /* 0x7FFF * 72270/7200 */
495 prop->value.l < -0x504C2L )
496 {
497 bsize->size = 0x7FFF;
498 FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n",
499 bsize->size ));
500 }
501 else
502 bsize->size = FT_MulDiv( FT_ABS( prop->value.l ),
503 64 * 7200,
504 72270L );
505 }
506 else if ( font->point_size )
507 {
508 if ( font->point_size > 0x7FFF )
509 {
510 bsize->size = 0x7FFF;
511 FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n",
512 bsize->size ));
513 }
514 else
515 bsize->size = (FT_Pos)font->point_size << 6;
516 }
517 else
518 {
519 /* this is a heuristical value */
520 bsize->size = bsize->width * 64;
521 }
522
523 prop = bdf_get_font_property( font, "PIXEL_SIZE" );
524 if ( prop )
525 {
526#ifdef FT_DEBUG_LEVEL_TRACE
527 if ( prop->value.l < 0 )
528 FT_TRACE0(( "BDF_Face_Init: negative pixel size\n" ));
529#endif
530 if ( prop->value.l > 0x7FFF || prop->value.l < -0x7FFF )
531 {
532 bsize->y_ppem = 0x7FFF << 6;
533 FT_TRACE0(( "BDF_Face_Init: clamping pixel size to value %ld\n",
534 bsize->y_ppem ));
535 }
536 else
537 bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6;
538 }
539
540 prop = bdf_get_font_property( font, "RESOLUTION_X" );
541 if ( prop )
542 value = prop->value.l;
543 else
544 value = (long)font->resolution_x;
545 if ( value )
546 {
547#ifdef FT_DEBUG_LEVEL_TRACE
548 if ( value < 0 )
549 FT_TRACE0(( "BDF_Face_Init: negative X resolution\n" ));
550#endif
551 if ( value > 0x7FFF || value < -0x7FFF )
552 {
553 resolution_x = 0x7FFF;
554 FT_TRACE0(( "BDF_Face_Init: clamping X resolution to value %d\n",
555 resolution_x ));
556 }
557 else
558 resolution_x = FT_ABS( (FT_Short)value );
559 }
560
561 prop = bdf_get_font_property( font, "RESOLUTION_Y" );
562 if ( prop )
563 value = prop->value.l;
564 else
565 value = (long)font->resolution_y;
566 if ( value )
567 {
568#ifdef FT_DEBUG_LEVEL_TRACE
569 if ( value < 0 )
570 FT_TRACE0(( "BDF_Face_Init: negative Y resolution\n" ));
571#endif
572 if ( value > 0x7FFF || value < -0x7FFF )
573 {
574 resolution_y = 0x7FFF;
575 FT_TRACE0(( "BDF_Face_Init: clamping Y resolution to value %d\n",
576 resolution_y ));
577 }
578 else
579 resolution_y = FT_ABS( (FT_Short)value );
580 }
581
582 if ( bsize->y_ppem == 0 )
583 {
584 bsize->y_ppem = bsize->size;
585 if ( resolution_y )
586 bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 );
587 }
588 if ( resolution_x && resolution_y )
589 bsize->x_ppem = FT_MulDiv( bsize->y_ppem,
590 resolution_x,
591 resolution_y );
592 else
593 bsize->x_ppem = bsize->y_ppem;
594 }
595
596 /* encoding table */
597 {
598 bdf_glyph_t* cur = font->glyphs;
599 unsigned long n;
600
601
602 if ( FT_QNEW_ARRAY( bdfface->en_table, font->glyphs_size ) )
603 goto Exit;
604
605 bdfface->default_glyph = 0;
606 for ( n = 0; n < font->glyphs_size; n++ )
607 {
608 (bdfface->en_table[n]).enc = cur[n].encoding;
609 FT_TRACE4(( " idx %ld, val 0x%lX\n", n, cur[n].encoding ));
610 (bdfface->en_table[n]).glyph = (FT_UShort)n;
611
612 if ( cur[n].encoding == font->default_char )
613 {
614 if ( n < FT_UINT_MAX )
615 bdfface->default_glyph = (FT_UInt)n;
616 else
617 FT_TRACE1(( "BDF_Face_Init:"
618 " idx %ld is too large for this system\n", n ));
619 }
620 }
621 }
622
623 /* charmaps */
624 {
625 bdf_property_t *charset_registry, *charset_encoding;
626 FT_Bool unicode_charmap = 0;
627
628
629 charset_registry =
630 bdf_get_font_property( font, "CHARSET_REGISTRY" );
631 charset_encoding =
632 bdf_get_font_property( font, "CHARSET_ENCODING" );
633 if ( charset_registry && charset_encoding )
634 {
635 if ( charset_registry->format == BDF_ATOM &&
636 charset_encoding->format == BDF_ATOM &&
637 charset_registry->value.atom &&
638 charset_encoding->value.atom )
639 {
640 const char* s;
641
642
643 if ( FT_STRDUP( bdfface->charset_encoding,
644 charset_encoding->value.atom ) ||
645 FT_STRDUP( bdfface->charset_registry,
646 charset_registry->value.atom ) )
647 goto Exit;
648
649 /* Uh, oh, compare first letters manually to avoid dependency */
650 /* on locales. */
651 s = bdfface->charset_registry;
652 if ( ( s[0] == 'i' || s[0] == 'I' ) &&
653 ( s[1] == 's' || s[1] == 'S' ) &&
654 ( s[2] == 'o' || s[2] == 'O' ) )
655 {
656 s += 3;
657 if ( !ft_strcmp( s, "10646" ) ||
658 ( !ft_strcmp( s, "8859" ) &&
659 !ft_strcmp( bdfface->charset_encoding, "1" ) ) )
660 unicode_charmap = 1;
661 /* another name for ASCII */
662 else if ( !ft_strcmp( s, "646.1991" ) &&
663 !ft_strcmp( bdfface->charset_encoding, "IRV" ) )
664 unicode_charmap = 1;
665 }
666
667 {
668 FT_CharMapRec charmap;
669
670
671 charmap.face = face;
672 charmap.encoding = FT_ENCODING_NONE;
673 /* initial platform/encoding should indicate unset status? */
674 charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
675 charmap.encoding_id = TT_APPLE_ID_DEFAULT;
676
677 if ( unicode_charmap )
678 {
679 charmap.encoding = FT_ENCODING_UNICODE;
680 charmap.platform_id = TT_PLATFORM_MICROSOFT;
681 charmap.encoding_id = TT_MS_ID_UNICODE_CS;
682 }
683
684 error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
685 }
686
687 goto Exit;
688 }
689 }
690
691 /* otherwise assume Adobe standard encoding */
692
693 {
694 FT_CharMapRec charmap;
695
696
697 charmap.face = face;
698 charmap.encoding = FT_ENCODING_ADOBE_STANDARD;
699 charmap.platform_id = TT_PLATFORM_ADOBE;
700 charmap.encoding_id = TT_ADOBE_ID_STANDARD;
701
702 error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
703
704 /* Select default charmap */
705 if ( face->num_charmaps )
706 face->charmap = face->charmaps[0];
707 }
708 }
709 }
710
711 Exit:
712 return error;
713
714 Fail:
715 BDF_Face_Done( face );
716 return FT_THROW( Unknown_File_Format );
717 }
718
719
720 FT_CALLBACK_DEF( FT_Error )
721 BDF_Size_Select( FT_Size size,
722 FT_ULong strike_index )
723 {
724 bdf_font_t* bdffont = ( (BDF_Face)size->face )->bdffont;
725
726
727 FT_Select_Metrics( size->face, strike_index );
728
729 size->metrics.ascender = bdffont->font_ascent * 64;
730 size->metrics.descender = -bdffont->font_descent * 64;
731 size->metrics.max_advance = bdffont->bbx.width * 64;
732
733 return FT_Err_Ok;
734 }
735
736
737 FT_CALLBACK_DEF( FT_Error )
738 BDF_Size_Request( FT_Size size,
739 FT_Size_Request req )
740 {
741 FT_Face face = size->face;
742 FT_Bitmap_Size* bsize = face->available_sizes;
743 bdf_font_t* bdffont = ( (BDF_Face)face )->bdffont;
744 FT_Error error = FT_ERR( Invalid_Pixel_Size );
745 FT_Long height;
746
747
748 height = FT_REQUEST_HEIGHT( req );
749 height = ( height + 32 ) >> 6;
750
751 switch ( req->type )
752 {
753 case FT_SIZE_REQUEST_TYPE_NOMINAL:
754 if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) )
755 error = FT_Err_Ok;
756 break;
757
758 case FT_SIZE_REQUEST_TYPE_REAL_DIM:
759 if ( height == ( bdffont->font_ascent +
760 bdffont->font_descent ) )
761 error = FT_Err_Ok;
762 break;
763
764 default:
765 error = FT_THROW( Unimplemented_Feature );
766 break;
767 }
768
769 if ( error )
770 return error;
771 else
772 return BDF_Size_Select( size, 0 );
773 }
774
775
776
777 FT_CALLBACK_DEF( FT_Error )
778 BDF_Glyph_Load( FT_GlyphSlot slot,
779 FT_Size size,
780 FT_UInt glyph_index,
781 FT_Int32 load_flags )
782 {
783 BDF_Face bdf = (BDF_Face)FT_SIZE_FACE( size );
784 FT_Face face = FT_FACE( bdf );
785 FT_Error error = FT_Err_Ok;
786 FT_Bitmap* bitmap = &slot->bitmap;
787 bdf_glyph_t glyph;
788 int bpp = bdf->bdffont->bpp;
789
790 FT_UNUSED( load_flags );
791
792
793 if ( !face )
794 {
795 error = FT_THROW( Invalid_Face_Handle );
796 goto Exit;
797 }
798
799 if ( glyph_index >= (FT_UInt)face->num_glyphs )
800 {
801 error = FT_THROW( Invalid_Argument );
802 goto Exit;
803 }
804
805 FT_TRACE1(( "BDF_Glyph_Load: glyph index %d\n", glyph_index ));
806
807 /* index 0 is the undefined glyph */
808 if ( glyph_index == 0 )
809 glyph_index = bdf->default_glyph;
810 else
811 glyph_index--;
812
813 /* slot, bitmap => freetype, glyph => bdflib */
814 glyph = bdf->bdffont->glyphs[glyph_index];
815
816 bitmap->rows = glyph.bbx.height;
817 bitmap->width = glyph.bbx.width;
818 if ( glyph.bpr > FT_INT_MAX )
819 FT_TRACE1(( "BDF_Glyph_Load: too large pitch %ld is truncated\n",
820 glyph.bpr ));
821 bitmap->pitch = (int)glyph.bpr; /* same as FT_Bitmap.pitch */
822
823 /* note: we don't allocate a new array to hold the bitmap; */
824 /* we can simply point to it */
825 ft_glyphslot_set_bitmap( slot, glyph.bitmap );
826
827 switch ( bpp )
828 {
829 case 1:
830 bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
831 break;
832 case 2:
833 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY2;
834 break;
835 case 4:
836 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY4;
837 break;
838 case 8:
839 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
840 bitmap->num_grays = 256;
841 break;
842 }
843
844 slot->format = FT_GLYPH_FORMAT_BITMAP;
845 slot->bitmap_left = glyph.bbx.x_offset;
846 slot->bitmap_top = glyph.bbx.ascent;
847
848 slot->metrics.horiAdvance = (FT_Pos)( glyph.dwidth * 64 );
849 slot->metrics.horiBearingX = (FT_Pos)( glyph.bbx.x_offset * 64 );
850 slot->metrics.horiBearingY = (FT_Pos)( glyph.bbx.ascent * 64 );
851 slot->metrics.width = (FT_Pos)( bitmap->width * 64 );
852 slot->metrics.height = (FT_Pos)( bitmap->rows * 64 );
853
854 /*
855 * XXX DWIDTH1 and VVECTOR should be parsed and
856 * used here, provided such fonts do exist.
857 */
858 ft_synthesize_vertical_metrics( &slot->metrics,
859 bdf->bdffont->bbx.height * 64 );
860
861 Exit:
862 return error;
863 }
864
865
866 /*
867 *
868 * BDF SERVICE
869 *
870 */
871
872 FT_CALLBACK_DEF( FT_Error )
873 bdf_get_bdf_property( FT_Face face, /* BDF_Face */
874 const char* prop_name,
875 BDF_PropertyRec *aproperty )
876 {
877 BDF_Face bdfface = (BDF_Face)face;
878 bdf_property_t* prop;
879
880
881 FT_ASSERT( bdfface && bdfface->bdffont );
882
883 prop = bdf_get_font_property( bdfface->bdffont, prop_name );
884 if ( prop )
885 {
886 switch ( prop->format )
887 {
888 case BDF_ATOM:
889 aproperty->type = BDF_PROPERTY_TYPE_ATOM;
890 aproperty->u.atom = prop->value.atom;
891 break;
892
893 case BDF_INTEGER:
894 if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) )
895 {
896 FT_TRACE1(( "bdf_get_bdf_property:"
897 " too large integer 0x%lx is truncated\n",
898 prop->value.l ));
899 }
900 aproperty->type = BDF_PROPERTY_TYPE_INTEGER;
901 aproperty->u.integer = (FT_Int32)prop->value.l;
902 break;
903
904 case BDF_CARDINAL:
905 if ( prop->value.ul > 0xFFFFFFFFUL )
906 {
907 FT_TRACE1(( "bdf_get_bdf_property:"
908 " too large cardinal 0x%lx is truncated\n",
909 prop->value.ul ));
910 }
911 aproperty->type = BDF_PROPERTY_TYPE_CARDINAL;
912 aproperty->u.cardinal = (FT_UInt32)prop->value.ul;
913 break;
914
915 default:
916 goto Fail;
917 }
918 return 0;
919 }
920
921 Fail:
922 return FT_THROW( Invalid_Argument );
923 }
924
925
926 FT_CALLBACK_DEF( FT_Error )
927 bdf_get_charset_id( FT_Face face, /* BDF_Face */
928 const char* *acharset_encoding,
929 const char* *acharset_registry )
930 {
931 BDF_Face bdfface = (BDF_Face)face;
932
933
934 *acharset_encoding = bdfface->charset_encoding;
935 *acharset_registry = bdfface->charset_registry;
936
937 return 0;
938 }
939
940
941 static const FT_Service_BDFRec bdf_service_bdf =
942 {
943 (FT_BDF_GetCharsetIdFunc)bdf_get_charset_id, /* get_charset_id */
944 (FT_BDF_GetPropertyFunc) bdf_get_bdf_property /* get_property */
945 };
946
947
948 /*
949 *
950 * SERVICES LIST
951 *
952 */
953
954 static const FT_ServiceDescRec bdf_services[] =
955 {
956 { FT_SERVICE_ID_BDF, &bdf_service_bdf },
957 { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_BDF },
958 { NULL, NULL }
959 };
960
961
962 FT_CALLBACK_DEF( FT_Module_Interface )
963 bdf_driver_requester( FT_Module module,
964 const char* name )
965 {
966 FT_UNUSED( module );
967
968 return ft_service_list_lookup( bdf_services, name );
969 }
970
971
972 FT_CALLBACK_TABLE_DEF
973 const FT_Driver_ClassRec bdf_driver_class =
974 {
975 {
976 FT_MODULE_FONT_DRIVER |
977 FT_MODULE_DRIVER_NO_OUTLINES,
978 sizeof ( FT_DriverRec ),
979
980 "bdf",
981 0x10000L,
982 0x20000L,
983
984 NULL, /* module-specific interface */
985
986 NULL, /* FT_Module_Constructor module_init */
987 NULL, /* FT_Module_Destructor module_done */
988 bdf_driver_requester /* FT_Module_Requester get_interface */
989 },
990
991 sizeof ( BDF_FaceRec ),
992 sizeof ( FT_SizeRec ),
993 sizeof ( FT_GlyphSlotRec ),
994
995 BDF_Face_Init, /* FT_Face_InitFunc init_face */
996 BDF_Face_Done, /* FT_Face_DoneFunc done_face */
997 NULL, /* FT_Size_InitFunc init_size */
998 NULL, /* FT_Size_DoneFunc done_size */
999 NULL, /* FT_Slot_InitFunc init_slot */
1000 NULL, /* FT_Slot_DoneFunc done_slot */
1001
1002 BDF_Glyph_Load, /* FT_Slot_LoadFunc load_glyph */
1003
1004 NULL, /* FT_Face_GetKerningFunc get_kerning */
1005 NULL, /* FT_Face_AttachFunc attach_file */
1006 NULL, /* FT_Face_GetAdvancesFunc get_advances */
1007
1008 BDF_Size_Request, /* FT_Size_RequestFunc request_size */
1009 BDF_Size_Select /* FT_Size_SelectFunc select_size */
1010 };
1011
1012
1013/* END */
1014