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 | |
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 <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 | |