|
1 /* pcfread.c |
|
2 |
|
3 FreeType font driver for pcf fonts |
|
4 |
|
5 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, |
|
6 2010 by |
|
7 Francesco Zappa Nardelli |
|
8 |
|
9 Permission is hereby granted, free of charge, to any person obtaining a copy |
|
10 of this software and associated documentation files (the "Software"), to deal |
|
11 in the Software without restriction, including without limitation the rights |
|
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
13 copies of the Software, and to permit persons to whom the Software is |
|
14 furnished to do so, subject to the following conditions: |
|
15 |
|
16 The above copyright notice and this permission notice shall be included in |
|
17 all copies or substantial portions of the Software. |
|
18 |
|
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
25 THE SOFTWARE. |
|
26 */ |
|
27 |
|
28 |
|
29 #include <ft2build.h> |
|
30 |
|
31 #include FT_INTERNAL_DEBUG_H |
|
32 #include FT_INTERNAL_STREAM_H |
|
33 #include FT_INTERNAL_OBJECTS_H |
|
34 |
|
35 #include "pcf.h" |
|
36 #include "pcfread.h" |
|
37 |
|
38 #include "pcferror.h" |
|
39 |
|
40 |
|
41 /*************************************************************************/ |
|
42 /* */ |
|
43 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
|
44 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
|
45 /* messages during execution. */ |
|
46 /* */ |
|
47 #undef FT_COMPONENT |
|
48 #define FT_COMPONENT trace_pcfread |
|
49 |
|
50 |
|
51 #ifdef FT_DEBUG_LEVEL_TRACE |
|
52 static const char* const tableNames[] = |
|
53 { |
|
54 "prop", "accl", "mtrcs", "bmps", "imtrcs", |
|
55 "enc", "swidth", "names", "accel" |
|
56 }; |
|
57 #endif |
|
58 |
|
59 |
|
60 static |
|
61 const FT_Frame_Field pcf_toc_header[] = |
|
62 { |
|
63 #undef FT_STRUCTURE |
|
64 #define FT_STRUCTURE PCF_TocRec |
|
65 |
|
66 FT_FRAME_START( 8 ), |
|
67 FT_FRAME_ULONG_LE( version ), |
|
68 FT_FRAME_ULONG_LE( count ), |
|
69 FT_FRAME_END |
|
70 }; |
|
71 |
|
72 |
|
73 static |
|
74 const FT_Frame_Field pcf_table_header[] = |
|
75 { |
|
76 #undef FT_STRUCTURE |
|
77 #define FT_STRUCTURE PCF_TableRec |
|
78 |
|
79 FT_FRAME_START( 16 ), |
|
80 FT_FRAME_ULONG_LE( type ), |
|
81 FT_FRAME_ULONG_LE( format ), |
|
82 FT_FRAME_ULONG_LE( size ), |
|
83 FT_FRAME_ULONG_LE( offset ), |
|
84 FT_FRAME_END |
|
85 }; |
|
86 |
|
87 |
|
88 static FT_Error |
|
89 pcf_read_TOC( FT_Stream stream, |
|
90 PCF_Face face ) |
|
91 { |
|
92 FT_Error error; |
|
93 PCF_Toc toc = &face->toc; |
|
94 PCF_Table tables; |
|
95 |
|
96 FT_Memory memory = FT_FACE(face)->memory; |
|
97 FT_UInt n; |
|
98 |
|
99 |
|
100 if ( FT_STREAM_SEEK ( 0 ) || |
|
101 FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) ) |
|
102 return PCF_Err_Cannot_Open_Resource; |
|
103 |
|
104 if ( toc->version != PCF_FILE_VERSION || |
|
105 toc->count > FT_ARRAY_MAX( face->toc.tables ) || |
|
106 toc->count == 0 ) |
|
107 return PCF_Err_Invalid_File_Format; |
|
108 |
|
109 if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) ) |
|
110 return PCF_Err_Out_Of_Memory; |
|
111 |
|
112 tables = face->toc.tables; |
|
113 for ( n = 0; n < toc->count; n++ ) |
|
114 { |
|
115 if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) |
|
116 goto Exit; |
|
117 tables++; |
|
118 } |
|
119 |
|
120 /* Sort tables and check for overlaps. Because they are almost */ |
|
121 /* always ordered already, an in-place bubble sort with simultaneous */ |
|
122 /* boundary checking seems appropriate. */ |
|
123 tables = face->toc.tables; |
|
124 |
|
125 for ( n = 0; n < toc->count - 1; n++ ) |
|
126 { |
|
127 FT_UInt i, have_change; |
|
128 |
|
129 |
|
130 have_change = 0; |
|
131 |
|
132 for ( i = 0; i < toc->count - 1 - n; i++ ) |
|
133 { |
|
134 PCF_TableRec tmp; |
|
135 |
|
136 |
|
137 if ( tables[i].offset > tables[i + 1].offset ) |
|
138 { |
|
139 tmp = tables[i]; |
|
140 tables[i] = tables[i + 1]; |
|
141 tables[i + 1] = tmp; |
|
142 |
|
143 have_change = 1; |
|
144 } |
|
145 |
|
146 if ( ( tables[i].size > tables[i + 1].offset ) || |
|
147 ( tables[i].offset > tables[i + 1].offset - tables[i].size ) ) |
|
148 return PCF_Err_Invalid_Offset; |
|
149 } |
|
150 |
|
151 if ( !have_change ) |
|
152 break; |
|
153 } |
|
154 |
|
155 #ifdef FT_DEBUG_LEVEL_TRACE |
|
156 |
|
157 { |
|
158 FT_UInt i, j; |
|
159 const char* name = "?"; |
|
160 |
|
161 |
|
162 FT_TRACE4(( "pcf_read_TOC:\n" )); |
|
163 |
|
164 FT_TRACE4(( " number of tables: %ld\n", face->toc.count )); |
|
165 |
|
166 tables = face->toc.tables; |
|
167 for ( i = 0; i < toc->count; i++ ) |
|
168 { |
|
169 for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); |
|
170 j++ ) |
|
171 if ( tables[i].type == (FT_UInt)( 1 << j ) ) |
|
172 name = tableNames[j]; |
|
173 |
|
174 FT_TRACE4(( " %d: type=%s, format=0x%X, " |
|
175 "size=%ld (0x%lX), offset=%ld (0x%lX)\n", |
|
176 i, name, |
|
177 tables[i].format, |
|
178 tables[i].size, tables[i].size, |
|
179 tables[i].offset, tables[i].offset )); |
|
180 } |
|
181 } |
|
182 |
|
183 #endif |
|
184 |
|
185 return PCF_Err_Ok; |
|
186 |
|
187 Exit: |
|
188 FT_FREE( face->toc.tables ); |
|
189 return error; |
|
190 } |
|
191 |
|
192 |
|
193 #define PCF_METRIC_SIZE 12 |
|
194 |
|
195 static |
|
196 const FT_Frame_Field pcf_metric_header[] = |
|
197 { |
|
198 #undef FT_STRUCTURE |
|
199 #define FT_STRUCTURE PCF_MetricRec |
|
200 |
|
201 FT_FRAME_START( PCF_METRIC_SIZE ), |
|
202 FT_FRAME_SHORT_LE( leftSideBearing ), |
|
203 FT_FRAME_SHORT_LE( rightSideBearing ), |
|
204 FT_FRAME_SHORT_LE( characterWidth ), |
|
205 FT_FRAME_SHORT_LE( ascent ), |
|
206 FT_FRAME_SHORT_LE( descent ), |
|
207 FT_FRAME_SHORT_LE( attributes ), |
|
208 FT_FRAME_END |
|
209 }; |
|
210 |
|
211 |
|
212 static |
|
213 const FT_Frame_Field pcf_metric_msb_header[] = |
|
214 { |
|
215 #undef FT_STRUCTURE |
|
216 #define FT_STRUCTURE PCF_MetricRec |
|
217 |
|
218 FT_FRAME_START( PCF_METRIC_SIZE ), |
|
219 FT_FRAME_SHORT( leftSideBearing ), |
|
220 FT_FRAME_SHORT( rightSideBearing ), |
|
221 FT_FRAME_SHORT( characterWidth ), |
|
222 FT_FRAME_SHORT( ascent ), |
|
223 FT_FRAME_SHORT( descent ), |
|
224 FT_FRAME_SHORT( attributes ), |
|
225 FT_FRAME_END |
|
226 }; |
|
227 |
|
228 |
|
229 #define PCF_COMPRESSED_METRIC_SIZE 5 |
|
230 |
|
231 static |
|
232 const FT_Frame_Field pcf_compressed_metric_header[] = |
|
233 { |
|
234 #undef FT_STRUCTURE |
|
235 #define FT_STRUCTURE PCF_Compressed_MetricRec |
|
236 |
|
237 FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ), |
|
238 FT_FRAME_BYTE( leftSideBearing ), |
|
239 FT_FRAME_BYTE( rightSideBearing ), |
|
240 FT_FRAME_BYTE( characterWidth ), |
|
241 FT_FRAME_BYTE( ascent ), |
|
242 FT_FRAME_BYTE( descent ), |
|
243 FT_FRAME_END |
|
244 }; |
|
245 |
|
246 |
|
247 static FT_Error |
|
248 pcf_get_metric( FT_Stream stream, |
|
249 FT_ULong format, |
|
250 PCF_Metric metric ) |
|
251 { |
|
252 FT_Error error = PCF_Err_Ok; |
|
253 |
|
254 |
|
255 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) |
|
256 { |
|
257 const FT_Frame_Field* fields; |
|
258 |
|
259 |
|
260 /* parsing normal metrics */ |
|
261 fields = PCF_BYTE_ORDER( format ) == MSBFirst |
|
262 ? pcf_metric_msb_header |
|
263 : pcf_metric_header; |
|
264 |
|
265 /* the following sets `error' but doesn't return in case of failure */ |
|
266 (void)FT_STREAM_READ_FIELDS( fields, metric ); |
|
267 } |
|
268 else |
|
269 { |
|
270 PCF_Compressed_MetricRec compr; |
|
271 |
|
272 |
|
273 /* parsing compressed metrics */ |
|
274 if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) ) |
|
275 goto Exit; |
|
276 |
|
277 metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 ); |
|
278 metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 ); |
|
279 metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 ); |
|
280 metric->ascent = (FT_Short)( compr.ascent - 0x80 ); |
|
281 metric->descent = (FT_Short)( compr.descent - 0x80 ); |
|
282 metric->attributes = 0; |
|
283 } |
|
284 |
|
285 Exit: |
|
286 return error; |
|
287 } |
|
288 |
|
289 |
|
290 static FT_Error |
|
291 pcf_seek_to_table_type( FT_Stream stream, |
|
292 PCF_Table tables, |
|
293 FT_ULong ntables, /* same as PCF_Toc->count */ |
|
294 FT_ULong type, |
|
295 FT_ULong *aformat, |
|
296 FT_ULong *asize ) |
|
297 { |
|
298 FT_Error error = PCF_Err_Invalid_File_Format; |
|
299 FT_ULong i; |
|
300 |
|
301 |
|
302 for ( i = 0; i < ntables; i++ ) |
|
303 if ( tables[i].type == type ) |
|
304 { |
|
305 if ( stream->pos > tables[i].offset ) |
|
306 { |
|
307 error = PCF_Err_Invalid_Stream_Skip; |
|
308 goto Fail; |
|
309 } |
|
310 |
|
311 if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) ) |
|
312 { |
|
313 error = PCF_Err_Invalid_Stream_Skip; |
|
314 goto Fail; |
|
315 } |
|
316 |
|
317 *asize = tables[i].size; |
|
318 *aformat = tables[i].format; |
|
319 |
|
320 return PCF_Err_Ok; |
|
321 } |
|
322 |
|
323 Fail: |
|
324 *asize = 0; |
|
325 return error; |
|
326 } |
|
327 |
|
328 |
|
329 static FT_Bool |
|
330 pcf_has_table_type( PCF_Table tables, |
|
331 FT_ULong ntables, /* same as PCF_Toc->count */ |
|
332 FT_ULong type ) |
|
333 { |
|
334 FT_ULong i; |
|
335 |
|
336 |
|
337 for ( i = 0; i < ntables; i++ ) |
|
338 if ( tables[i].type == type ) |
|
339 return TRUE; |
|
340 |
|
341 return FALSE; |
|
342 } |
|
343 |
|
344 |
|
345 #define PCF_PROPERTY_SIZE 9 |
|
346 |
|
347 static |
|
348 const FT_Frame_Field pcf_property_header[] = |
|
349 { |
|
350 #undef FT_STRUCTURE |
|
351 #define FT_STRUCTURE PCF_ParsePropertyRec |
|
352 |
|
353 FT_FRAME_START( PCF_PROPERTY_SIZE ), |
|
354 FT_FRAME_LONG_LE( name ), |
|
355 FT_FRAME_BYTE ( isString ), |
|
356 FT_FRAME_LONG_LE( value ), |
|
357 FT_FRAME_END |
|
358 }; |
|
359 |
|
360 |
|
361 static |
|
362 const FT_Frame_Field pcf_property_msb_header[] = |
|
363 { |
|
364 #undef FT_STRUCTURE |
|
365 #define FT_STRUCTURE PCF_ParsePropertyRec |
|
366 |
|
367 FT_FRAME_START( PCF_PROPERTY_SIZE ), |
|
368 FT_FRAME_LONG( name ), |
|
369 FT_FRAME_BYTE( isString ), |
|
370 FT_FRAME_LONG( value ), |
|
371 FT_FRAME_END |
|
372 }; |
|
373 |
|
374 |
|
375 FT_LOCAL_DEF( PCF_Property ) |
|
376 pcf_find_property( PCF_Face face, |
|
377 const FT_String* prop ) |
|
378 { |
|
379 PCF_Property properties = face->properties; |
|
380 FT_Bool found = 0; |
|
381 int i; |
|
382 |
|
383 |
|
384 for ( i = 0 ; i < face->nprops && !found; i++ ) |
|
385 { |
|
386 if ( !ft_strcmp( properties[i].name, prop ) ) |
|
387 found = 1; |
|
388 } |
|
389 |
|
390 if ( found ) |
|
391 return properties + i - 1; |
|
392 else |
|
393 return NULL; |
|
394 } |
|
395 |
|
396 |
|
397 static FT_Error |
|
398 pcf_get_properties( FT_Stream stream, |
|
399 PCF_Face face ) |
|
400 { |
|
401 PCF_ParseProperty props = 0; |
|
402 PCF_Property properties; |
|
403 FT_ULong nprops, i; |
|
404 FT_ULong format, size; |
|
405 FT_Error error; |
|
406 FT_Memory memory = FT_FACE(face)->memory; |
|
407 FT_ULong string_size; |
|
408 FT_String* strings = 0; |
|
409 |
|
410 |
|
411 error = pcf_seek_to_table_type( stream, |
|
412 face->toc.tables, |
|
413 face->toc.count, |
|
414 PCF_PROPERTIES, |
|
415 &format, |
|
416 &size ); |
|
417 if ( error ) |
|
418 goto Bail; |
|
419 |
|
420 if ( FT_READ_ULONG_LE( format ) ) |
|
421 goto Bail; |
|
422 |
|
423 FT_TRACE4(( "pcf_get_properties:\n" )); |
|
424 |
|
425 FT_TRACE4(( " format = %ld\n", format )); |
|
426 |
|
427 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) |
|
428 goto Bail; |
|
429 |
|
430 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) |
|
431 (void)FT_READ_ULONG( nprops ); |
|
432 else |
|
433 (void)FT_READ_ULONG_LE( nprops ); |
|
434 if ( error ) |
|
435 goto Bail; |
|
436 |
|
437 FT_TRACE4(( " nprop = %d (truncate %d props)\n", |
|
438 (int)nprops, nprops - (int)nprops )); |
|
439 |
|
440 nprops = (int)nprops; |
|
441 |
|
442 /* rough estimate */ |
|
443 if ( nprops > size / PCF_PROPERTY_SIZE ) |
|
444 { |
|
445 error = PCF_Err_Invalid_Table; |
|
446 goto Bail; |
|
447 } |
|
448 |
|
449 face->nprops = (int)nprops; |
|
450 |
|
451 if ( FT_NEW_ARRAY( props, nprops ) ) |
|
452 goto Bail; |
|
453 |
|
454 for ( i = 0; i < nprops; i++ ) |
|
455 { |
|
456 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) |
|
457 { |
|
458 if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) |
|
459 goto Bail; |
|
460 } |
|
461 else |
|
462 { |
|
463 if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) |
|
464 goto Bail; |
|
465 } |
|
466 } |
|
467 |
|
468 /* pad the property array */ |
|
469 /* */ |
|
470 /* clever here - nprops is the same as the number of odd-units read, */ |
|
471 /* as only isStringProp are odd length (Keith Packard) */ |
|
472 /* */ |
|
473 if ( nprops & 3 ) |
|
474 { |
|
475 i = 4 - ( nprops & 3 ); |
|
476 if ( FT_STREAM_SKIP( i ) ) |
|
477 { |
|
478 error = PCF_Err_Invalid_Stream_Skip; |
|
479 goto Bail; |
|
480 } |
|
481 } |
|
482 |
|
483 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) |
|
484 (void)FT_READ_ULONG( string_size ); |
|
485 else |
|
486 (void)FT_READ_ULONG_LE( string_size ); |
|
487 if ( error ) |
|
488 goto Bail; |
|
489 |
|
490 FT_TRACE4(( " string_size = %ld\n", string_size )); |
|
491 |
|
492 /* rough estimate */ |
|
493 if ( string_size > size - nprops * PCF_PROPERTY_SIZE ) |
|
494 { |
|
495 error = PCF_Err_Invalid_Table; |
|
496 goto Bail; |
|
497 } |
|
498 |
|
499 if ( FT_NEW_ARRAY( strings, string_size ) ) |
|
500 goto Bail; |
|
501 |
|
502 error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); |
|
503 if ( error ) |
|
504 goto Bail; |
|
505 |
|
506 if ( FT_NEW_ARRAY( properties, nprops ) ) |
|
507 goto Bail; |
|
508 |
|
509 face->properties = properties; |
|
510 |
|
511 for ( i = 0; i < nprops; i++ ) |
|
512 { |
|
513 FT_Long name_offset = props[i].name; |
|
514 |
|
515 |
|
516 if ( ( name_offset < 0 ) || |
|
517 ( (FT_ULong)name_offset > string_size ) ) |
|
518 { |
|
519 error = PCF_Err_Invalid_Offset; |
|
520 goto Bail; |
|
521 } |
|
522 |
|
523 if ( FT_STRDUP( properties[i].name, strings + name_offset ) ) |
|
524 goto Bail; |
|
525 |
|
526 FT_TRACE4(( " %s:", properties[i].name )); |
|
527 |
|
528 properties[i].isString = props[i].isString; |
|
529 |
|
530 if ( props[i].isString ) |
|
531 { |
|
532 FT_Long value_offset = props[i].value; |
|
533 |
|
534 |
|
535 if ( ( value_offset < 0 ) || |
|
536 ( (FT_ULong)value_offset > string_size ) ) |
|
537 { |
|
538 error = PCF_Err_Invalid_Offset; |
|
539 goto Bail; |
|
540 } |
|
541 |
|
542 if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) ) |
|
543 goto Bail; |
|
544 |
|
545 FT_TRACE4(( " `%s'\n", properties[i].value.atom )); |
|
546 } |
|
547 else |
|
548 { |
|
549 properties[i].value.l = props[i].value; |
|
550 |
|
551 FT_TRACE4(( " %d\n", properties[i].value.l )); |
|
552 } |
|
553 } |
|
554 |
|
555 error = PCF_Err_Ok; |
|
556 |
|
557 Bail: |
|
558 FT_FREE( props ); |
|
559 FT_FREE( strings ); |
|
560 |
|
561 return error; |
|
562 } |
|
563 |
|
564 |
|
565 static FT_Error |
|
566 pcf_get_metrics( FT_Stream stream, |
|
567 PCF_Face face ) |
|
568 { |
|
569 FT_Error error = PCF_Err_Ok; |
|
570 FT_Memory memory = FT_FACE(face)->memory; |
|
571 FT_ULong format, size; |
|
572 PCF_Metric metrics = 0; |
|
573 FT_ULong nmetrics, i; |
|
574 |
|
575 |
|
576 error = pcf_seek_to_table_type( stream, |
|
577 face->toc.tables, |
|
578 face->toc.count, |
|
579 PCF_METRICS, |
|
580 &format, |
|
581 &size ); |
|
582 if ( error ) |
|
583 return error; |
|
584 |
|
585 if ( FT_READ_ULONG_LE( format ) ) |
|
586 goto Bail; |
|
587 |
|
588 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && |
|
589 !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) |
|
590 return PCF_Err_Invalid_File_Format; |
|
591 |
|
592 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) |
|
593 { |
|
594 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) |
|
595 (void)FT_READ_ULONG( nmetrics ); |
|
596 else |
|
597 (void)FT_READ_ULONG_LE( nmetrics ); |
|
598 } |
|
599 else |
|
600 { |
|
601 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) |
|
602 (void)FT_READ_USHORT( nmetrics ); |
|
603 else |
|
604 (void)FT_READ_USHORT_LE( nmetrics ); |
|
605 } |
|
606 if ( error ) |
|
607 return PCF_Err_Invalid_File_Format; |
|
608 |
|
609 face->nmetrics = nmetrics; |
|
610 |
|
611 if ( !nmetrics ) |
|
612 return PCF_Err_Invalid_Table; |
|
613 |
|
614 FT_TRACE4(( "pcf_get_metrics:\n" )); |
|
615 |
|
616 FT_TRACE4(( " number of metrics: %d\n", nmetrics )); |
|
617 |
|
618 /* rough estimate */ |
|
619 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) |
|
620 { |
|
621 if ( nmetrics > size / PCF_METRIC_SIZE ) |
|
622 return PCF_Err_Invalid_Table; |
|
623 } |
|
624 else |
|
625 { |
|
626 if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) |
|
627 return PCF_Err_Invalid_Table; |
|
628 } |
|
629 |
|
630 if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) |
|
631 return PCF_Err_Out_Of_Memory; |
|
632 |
|
633 metrics = face->metrics; |
|
634 for ( i = 0; i < nmetrics; i++ ) |
|
635 { |
|
636 error = pcf_get_metric( stream, format, metrics + i ); |
|
637 |
|
638 metrics[i].bits = 0; |
|
639 |
|
640 FT_TRACE5(( " idx %d: width=%d, " |
|
641 "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", |
|
642 i, |
|
643 ( metrics + i )->characterWidth, |
|
644 ( metrics + i )->leftSideBearing, |
|
645 ( metrics + i )->rightSideBearing, |
|
646 ( metrics + i )->ascent, |
|
647 ( metrics + i )->descent, |
|
648 ( metrics + i )->attributes )); |
|
649 |
|
650 if ( error ) |
|
651 break; |
|
652 } |
|
653 |
|
654 if ( error ) |
|
655 FT_FREE( face->metrics ); |
|
656 |
|
657 Bail: |
|
658 return error; |
|
659 } |
|
660 |
|
661 |
|
662 static FT_Error |
|
663 pcf_get_bitmaps( FT_Stream stream, |
|
664 PCF_Face face ) |
|
665 { |
|
666 FT_Error error = PCF_Err_Ok; |
|
667 FT_Memory memory = FT_FACE(face)->memory; |
|
668 FT_Long* offsets; |
|
669 FT_Long bitmapSizes[GLYPHPADOPTIONS]; |
|
670 FT_ULong format, size; |
|
671 FT_ULong nbitmaps, i, sizebitmaps = 0; |
|
672 |
|
673 |
|
674 error = pcf_seek_to_table_type( stream, |
|
675 face->toc.tables, |
|
676 face->toc.count, |
|
677 PCF_BITMAPS, |
|
678 &format, |
|
679 &size ); |
|
680 if ( error ) |
|
681 return error; |
|
682 |
|
683 error = FT_Stream_EnterFrame( stream, 8 ); |
|
684 if ( error ) |
|
685 return error; |
|
686 |
|
687 format = FT_GET_ULONG_LE(); |
|
688 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) |
|
689 nbitmaps = FT_GET_ULONG(); |
|
690 else |
|
691 nbitmaps = FT_GET_ULONG_LE(); |
|
692 |
|
693 FT_Stream_ExitFrame( stream ); |
|
694 |
|
695 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) |
|
696 return PCF_Err_Invalid_File_Format; |
|
697 |
|
698 FT_TRACE4(( "pcf_get_bitmaps:\n" )); |
|
699 |
|
700 FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps )); |
|
701 |
|
702 /* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */ |
|
703 if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics ) |
|
704 return PCF_Err_Invalid_File_Format; |
|
705 |
|
706 if ( FT_NEW_ARRAY( offsets, nbitmaps ) ) |
|
707 return error; |
|
708 |
|
709 for ( i = 0; i < nbitmaps; i++ ) |
|
710 { |
|
711 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) |
|
712 (void)FT_READ_LONG( offsets[i] ); |
|
713 else |
|
714 (void)FT_READ_LONG_LE( offsets[i] ); |
|
715 |
|
716 FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n", |
|
717 i, offsets[i], offsets[i] )); |
|
718 } |
|
719 if ( error ) |
|
720 goto Bail; |
|
721 |
|
722 for ( i = 0; i < GLYPHPADOPTIONS; i++ ) |
|
723 { |
|
724 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) |
|
725 (void)FT_READ_LONG( bitmapSizes[i] ); |
|
726 else |
|
727 (void)FT_READ_LONG_LE( bitmapSizes[i] ); |
|
728 if ( error ) |
|
729 goto Bail; |
|
730 |
|
731 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; |
|
732 |
|
733 FT_TRACE4(( " padding %d implies a size of %ld\n", i, bitmapSizes[i] )); |
|
734 } |
|
735 |
|
736 FT_TRACE4(( " %d bitmaps, padding index %ld\n", |
|
737 nbitmaps, |
|
738 PCF_GLYPH_PAD_INDEX( format ) )); |
|
739 FT_TRACE4(( " bitmap size = %d\n", sizebitmaps )); |
|
740 |
|
741 FT_UNUSED( sizebitmaps ); /* only used for debugging */ |
|
742 |
|
743 for ( i = 0; i < nbitmaps; i++ ) |
|
744 { |
|
745 /* rough estimate */ |
|
746 if ( ( offsets[i] < 0 ) || |
|
747 ( (FT_ULong)offsets[i] > size ) ) |
|
748 { |
|
749 FT_TRACE0(( "pcf_get_bitmaps:" |
|
750 " invalid offset to bitmap data of glyph %d\n", i )); |
|
751 } |
|
752 else |
|
753 face->metrics[i].bits = stream->pos + offsets[i]; |
|
754 } |
|
755 |
|
756 face->bitmapsFormat = format; |
|
757 |
|
758 Bail: |
|
759 FT_FREE( offsets ); |
|
760 return error; |
|
761 } |
|
762 |
|
763 |
|
764 static FT_Error |
|
765 pcf_get_encodings( FT_Stream stream, |
|
766 PCF_Face face ) |
|
767 { |
|
768 FT_Error error = PCF_Err_Ok; |
|
769 FT_Memory memory = FT_FACE(face)->memory; |
|
770 FT_ULong format, size; |
|
771 int firstCol, lastCol; |
|
772 int firstRow, lastRow; |
|
773 int nencoding, encodingOffset; |
|
774 int i, j; |
|
775 PCF_Encoding tmpEncoding, encoding = 0; |
|
776 |
|
777 |
|
778 error = pcf_seek_to_table_type( stream, |
|
779 face->toc.tables, |
|
780 face->toc.count, |
|
781 PCF_BDF_ENCODINGS, |
|
782 &format, |
|
783 &size ); |
|
784 if ( error ) |
|
785 return error; |
|
786 |
|
787 error = FT_Stream_EnterFrame( stream, 14 ); |
|
788 if ( error ) |
|
789 return error; |
|
790 |
|
791 format = FT_GET_ULONG_LE(); |
|
792 |
|
793 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) |
|
794 { |
|
795 firstCol = FT_GET_SHORT(); |
|
796 lastCol = FT_GET_SHORT(); |
|
797 firstRow = FT_GET_SHORT(); |
|
798 lastRow = FT_GET_SHORT(); |
|
799 face->defaultChar = FT_GET_SHORT(); |
|
800 } |
|
801 else |
|
802 { |
|
803 firstCol = FT_GET_SHORT_LE(); |
|
804 lastCol = FT_GET_SHORT_LE(); |
|
805 firstRow = FT_GET_SHORT_LE(); |
|
806 lastRow = FT_GET_SHORT_LE(); |
|
807 face->defaultChar = FT_GET_SHORT_LE(); |
|
808 } |
|
809 |
|
810 FT_Stream_ExitFrame( stream ); |
|
811 |
|
812 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) |
|
813 return PCF_Err_Invalid_File_Format; |
|
814 |
|
815 FT_TRACE4(( "pdf_get_encodings:\n" )); |
|
816 |
|
817 FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n", |
|
818 firstCol, lastCol, firstRow, lastRow )); |
|
819 |
|
820 nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 ); |
|
821 |
|
822 if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) ) |
|
823 return PCF_Err_Out_Of_Memory; |
|
824 |
|
825 error = FT_Stream_EnterFrame( stream, 2 * nencoding ); |
|
826 if ( error ) |
|
827 goto Bail; |
|
828 |
|
829 for ( i = 0, j = 0 ; i < nencoding; i++ ) |
|
830 { |
|
831 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) |
|
832 encodingOffset = FT_GET_SHORT(); |
|
833 else |
|
834 encodingOffset = FT_GET_SHORT_LE(); |
|
835 |
|
836 if ( encodingOffset != -1 ) |
|
837 { |
|
838 tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) + |
|
839 firstRow ) * 256 ) + |
|
840 ( ( i % ( lastCol - firstCol + 1 ) ) + |
|
841 firstCol ); |
|
842 |
|
843 tmpEncoding[j].glyph = (FT_Short)encodingOffset; |
|
844 |
|
845 FT_TRACE5(( " code %d (0x%04X): idx %d\n", |
|
846 tmpEncoding[j].enc, tmpEncoding[j].enc, |
|
847 tmpEncoding[j].glyph )); |
|
848 |
|
849 j++; |
|
850 } |
|
851 } |
|
852 FT_Stream_ExitFrame( stream ); |
|
853 |
|
854 if ( FT_NEW_ARRAY( encoding, j ) ) |
|
855 goto Bail; |
|
856 |
|
857 for ( i = 0; i < j; i++ ) |
|
858 { |
|
859 encoding[i].enc = tmpEncoding[i].enc; |
|
860 encoding[i].glyph = tmpEncoding[i].glyph; |
|
861 } |
|
862 |
|
863 face->nencodings = j; |
|
864 face->encodings = encoding; |
|
865 FT_FREE( tmpEncoding ); |
|
866 |
|
867 return error; |
|
868 |
|
869 Bail: |
|
870 FT_FREE( encoding ); |
|
871 FT_FREE( tmpEncoding ); |
|
872 return error; |
|
873 } |
|
874 |
|
875 |
|
876 static |
|
877 const FT_Frame_Field pcf_accel_header[] = |
|
878 { |
|
879 #undef FT_STRUCTURE |
|
880 #define FT_STRUCTURE PCF_AccelRec |
|
881 |
|
882 FT_FRAME_START( 20 ), |
|
883 FT_FRAME_BYTE ( noOverlap ), |
|
884 FT_FRAME_BYTE ( constantMetrics ), |
|
885 FT_FRAME_BYTE ( terminalFont ), |
|
886 FT_FRAME_BYTE ( constantWidth ), |
|
887 FT_FRAME_BYTE ( inkInside ), |
|
888 FT_FRAME_BYTE ( inkMetrics ), |
|
889 FT_FRAME_BYTE ( drawDirection ), |
|
890 FT_FRAME_SKIP_BYTES( 1 ), |
|
891 FT_FRAME_LONG_LE ( fontAscent ), |
|
892 FT_FRAME_LONG_LE ( fontDescent ), |
|
893 FT_FRAME_LONG_LE ( maxOverlap ), |
|
894 FT_FRAME_END |
|
895 }; |
|
896 |
|
897 |
|
898 static |
|
899 const FT_Frame_Field pcf_accel_msb_header[] = |
|
900 { |
|
901 #undef FT_STRUCTURE |
|
902 #define FT_STRUCTURE PCF_AccelRec |
|
903 |
|
904 FT_FRAME_START( 20 ), |
|
905 FT_FRAME_BYTE ( noOverlap ), |
|
906 FT_FRAME_BYTE ( constantMetrics ), |
|
907 FT_FRAME_BYTE ( terminalFont ), |
|
908 FT_FRAME_BYTE ( constantWidth ), |
|
909 FT_FRAME_BYTE ( inkInside ), |
|
910 FT_FRAME_BYTE ( inkMetrics ), |
|
911 FT_FRAME_BYTE ( drawDirection ), |
|
912 FT_FRAME_SKIP_BYTES( 1 ), |
|
913 FT_FRAME_LONG ( fontAscent ), |
|
914 FT_FRAME_LONG ( fontDescent ), |
|
915 FT_FRAME_LONG ( maxOverlap ), |
|
916 FT_FRAME_END |
|
917 }; |
|
918 |
|
919 |
|
920 static FT_Error |
|
921 pcf_get_accel( FT_Stream stream, |
|
922 PCF_Face face, |
|
923 FT_ULong type ) |
|
924 { |
|
925 FT_ULong format, size; |
|
926 FT_Error error = PCF_Err_Ok; |
|
927 PCF_Accel accel = &face->accel; |
|
928 |
|
929 |
|
930 error = pcf_seek_to_table_type( stream, |
|
931 face->toc.tables, |
|
932 face->toc.count, |
|
933 type, |
|
934 &format, |
|
935 &size ); |
|
936 if ( error ) |
|
937 goto Bail; |
|
938 |
|
939 if ( FT_READ_ULONG_LE( format ) ) |
|
940 goto Bail; |
|
941 |
|
942 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && |
|
943 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) |
|
944 goto Bail; |
|
945 |
|
946 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) |
|
947 { |
|
948 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) ) |
|
949 goto Bail; |
|
950 } |
|
951 else |
|
952 { |
|
953 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) ) |
|
954 goto Bail; |
|
955 } |
|
956 |
|
957 error = pcf_get_metric( stream, |
|
958 format & ( ~PCF_FORMAT_MASK ), |
|
959 &(accel->minbounds) ); |
|
960 if ( error ) |
|
961 goto Bail; |
|
962 |
|
963 error = pcf_get_metric( stream, |
|
964 format & ( ~PCF_FORMAT_MASK ), |
|
965 &(accel->maxbounds) ); |
|
966 if ( error ) |
|
967 goto Bail; |
|
968 |
|
969 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) |
|
970 { |
|
971 error = pcf_get_metric( stream, |
|
972 format & ( ~PCF_FORMAT_MASK ), |
|
973 &(accel->ink_minbounds) ); |
|
974 if ( error ) |
|
975 goto Bail; |
|
976 |
|
977 error = pcf_get_metric( stream, |
|
978 format & ( ~PCF_FORMAT_MASK ), |
|
979 &(accel->ink_maxbounds) ); |
|
980 if ( error ) |
|
981 goto Bail; |
|
982 } |
|
983 else |
|
984 { |
|
985 accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */ |
|
986 accel->ink_maxbounds = accel->maxbounds; |
|
987 } |
|
988 |
|
989 Bail: |
|
990 return error; |
|
991 } |
|
992 |
|
993 |
|
994 static FT_Error |
|
995 pcf_interpret_style( PCF_Face pcf ) |
|
996 { |
|
997 FT_Error error = PCF_Err_Ok; |
|
998 FT_Face face = FT_FACE( pcf ); |
|
999 FT_Memory memory = face->memory; |
|
1000 |
|
1001 PCF_Property prop; |
|
1002 |
|
1003 size_t nn, len; |
|
1004 char* strings[4] = { NULL, NULL, NULL, NULL }; |
|
1005 size_t lengths[4]; |
|
1006 |
|
1007 |
|
1008 face->style_flags = 0; |
|
1009 |
|
1010 prop = pcf_find_property( pcf, "SLANT" ); |
|
1011 if ( prop && prop->isString && |
|
1012 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || |
|
1013 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) |
|
1014 { |
|
1015 face->style_flags |= FT_STYLE_FLAG_ITALIC; |
|
1016 strings[2] = ( *(prop->value.atom) == 'O' || |
|
1017 *(prop->value.atom) == 'o' ) ? (char *)"Oblique" |
|
1018 : (char *)"Italic"; |
|
1019 } |
|
1020 |
|
1021 prop = pcf_find_property( pcf, "WEIGHT_NAME" ); |
|
1022 if ( prop && prop->isString && |
|
1023 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) |
|
1024 { |
|
1025 face->style_flags |= FT_STYLE_FLAG_BOLD; |
|
1026 strings[1] = (char *)"Bold"; |
|
1027 } |
|
1028 |
|
1029 prop = pcf_find_property( pcf, "SETWIDTH_NAME" ); |
|
1030 if ( prop && prop->isString && |
|
1031 *(prop->value.atom) && |
|
1032 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) |
|
1033 strings[3] = (char *)(prop->value.atom); |
|
1034 |
|
1035 prop = pcf_find_property( pcf, "ADD_STYLE_NAME" ); |
|
1036 if ( prop && prop->isString && |
|
1037 *(prop->value.atom) && |
|
1038 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) |
|
1039 strings[0] = (char *)(prop->value.atom); |
|
1040 |
|
1041 for ( len = 0, nn = 0; nn < 4; nn++ ) |
|
1042 { |
|
1043 lengths[nn] = 0; |
|
1044 if ( strings[nn] ) |
|
1045 { |
|
1046 lengths[nn] = ft_strlen( strings[nn] ); |
|
1047 len += lengths[nn] + 1; |
|
1048 } |
|
1049 } |
|
1050 |
|
1051 if ( len == 0 ) |
|
1052 { |
|
1053 strings[0] = (char *)"Regular"; |
|
1054 lengths[0] = ft_strlen( strings[0] ); |
|
1055 len = lengths[0] + 1; |
|
1056 } |
|
1057 |
|
1058 { |
|
1059 char* s; |
|
1060 |
|
1061 |
|
1062 if ( FT_ALLOC( face->style_name, len ) ) |
|
1063 return error; |
|
1064 |
|
1065 s = face->style_name; |
|
1066 |
|
1067 for ( nn = 0; nn < 4; nn++ ) |
|
1068 { |
|
1069 char* src = strings[nn]; |
|
1070 |
|
1071 |
|
1072 len = lengths[nn]; |
|
1073 |
|
1074 if ( src == NULL ) |
|
1075 continue; |
|
1076 |
|
1077 /* separate elements with a space */ |
|
1078 if ( s != face->style_name ) |
|
1079 *s++ = ' '; |
|
1080 |
|
1081 ft_memcpy( s, src, len ); |
|
1082 |
|
1083 /* need to convert spaces to dashes for */ |
|
1084 /* add_style_name and setwidth_name */ |
|
1085 if ( nn == 0 || nn == 3 ) |
|
1086 { |
|
1087 size_t mm; |
|
1088 |
|
1089 |
|
1090 for ( mm = 0; mm < len; mm++ ) |
|
1091 if (s[mm] == ' ') |
|
1092 s[mm] = '-'; |
|
1093 } |
|
1094 |
|
1095 s += len; |
|
1096 } |
|
1097 *s = 0; |
|
1098 } |
|
1099 |
|
1100 return error; |
|
1101 } |
|
1102 |
|
1103 |
|
1104 FT_LOCAL_DEF( FT_Error ) |
|
1105 pcf_load_font( FT_Stream stream, |
|
1106 PCF_Face face ) |
|
1107 { |
|
1108 FT_Error error = PCF_Err_Ok; |
|
1109 FT_Memory memory = FT_FACE(face)->memory; |
|
1110 FT_Bool hasBDFAccelerators; |
|
1111 |
|
1112 |
|
1113 error = pcf_read_TOC( stream, face ); |
|
1114 if ( error ) |
|
1115 goto Exit; |
|
1116 |
|
1117 error = pcf_get_properties( stream, face ); |
|
1118 if ( error ) |
|
1119 goto Exit; |
|
1120 |
|
1121 /* Use the old accelerators if no BDF accelerators are in the file. */ |
|
1122 hasBDFAccelerators = pcf_has_table_type( face->toc.tables, |
|
1123 face->toc.count, |
|
1124 PCF_BDF_ACCELERATORS ); |
|
1125 if ( !hasBDFAccelerators ) |
|
1126 { |
|
1127 error = pcf_get_accel( stream, face, PCF_ACCELERATORS ); |
|
1128 if ( error ) |
|
1129 goto Exit; |
|
1130 } |
|
1131 |
|
1132 /* metrics */ |
|
1133 error = pcf_get_metrics( stream, face ); |
|
1134 if ( error ) |
|
1135 goto Exit; |
|
1136 |
|
1137 /* bitmaps */ |
|
1138 error = pcf_get_bitmaps( stream, face ); |
|
1139 if ( error ) |
|
1140 goto Exit; |
|
1141 |
|
1142 /* encodings */ |
|
1143 error = pcf_get_encodings( stream, face ); |
|
1144 if ( error ) |
|
1145 goto Exit; |
|
1146 |
|
1147 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */ |
|
1148 if ( hasBDFAccelerators ) |
|
1149 { |
|
1150 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS ); |
|
1151 if ( error ) |
|
1152 goto Exit; |
|
1153 } |
|
1154 |
|
1155 /* XXX: TO DO: inkmetrics and glyph_names are missing */ |
|
1156 |
|
1157 /* now construct the face object */ |
|
1158 { |
|
1159 FT_Face root = FT_FACE( face ); |
|
1160 PCF_Property prop; |
|
1161 |
|
1162 |
|
1163 root->num_faces = 1; |
|
1164 root->face_index = 0; |
|
1165 root->face_flags = FT_FACE_FLAG_FIXED_SIZES | |
|
1166 FT_FACE_FLAG_HORIZONTAL | |
|
1167 FT_FACE_FLAG_FAST_GLYPHS; |
|
1168 |
|
1169 if ( face->accel.constantWidth ) |
|
1170 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; |
|
1171 |
|
1172 if ( ( error = pcf_interpret_style( face ) ) != 0 ) |
|
1173 goto Exit; |
|
1174 |
|
1175 prop = pcf_find_property( face, "FAMILY_NAME" ); |
|
1176 if ( prop && prop->isString ) |
|
1177 { |
|
1178 if ( FT_STRDUP( root->family_name, prop->value.atom ) ) |
|
1179 goto Exit; |
|
1180 } |
|
1181 else |
|
1182 root->family_name = NULL; |
|
1183 |
|
1184 /* |
|
1185 * Note: We shift all glyph indices by +1 since we must |
|
1186 * respect the convention that glyph 0 always corresponds |
|
1187 * to the `missing glyph'. |
|
1188 * |
|
1189 * This implies bumping the number of `available' glyphs by 1. |
|
1190 */ |
|
1191 root->num_glyphs = face->nmetrics + 1; |
|
1192 |
|
1193 root->num_fixed_sizes = 1; |
|
1194 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) |
|
1195 goto Exit; |
|
1196 |
|
1197 { |
|
1198 FT_Bitmap_Size* bsize = root->available_sizes; |
|
1199 FT_Short resolution_x = 0, resolution_y = 0; |
|
1200 |
|
1201 |
|
1202 FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) ); |
|
1203 |
|
1204 #if 0 |
|
1205 bsize->height = face->accel.maxbounds.ascent << 6; |
|
1206 #endif |
|
1207 bsize->height = (FT_Short)( face->accel.fontAscent + |
|
1208 face->accel.fontDescent ); |
|
1209 |
|
1210 prop = pcf_find_property( face, "AVERAGE_WIDTH" ); |
|
1211 if ( prop ) |
|
1212 bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 ); |
|
1213 else |
|
1214 bsize->width = (FT_Short)( bsize->height * 2/3 ); |
|
1215 |
|
1216 prop = pcf_find_property( face, "POINT_SIZE" ); |
|
1217 if ( prop ) |
|
1218 /* convert from 722.7 decipoints to 72 points per inch */ |
|
1219 bsize->size = |
|
1220 (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L ); |
|
1221 |
|
1222 prop = pcf_find_property( face, "PIXEL_SIZE" ); |
|
1223 if ( prop ) |
|
1224 bsize->y_ppem = (FT_Short)prop->value.l << 6; |
|
1225 |
|
1226 prop = pcf_find_property( face, "RESOLUTION_X" ); |
|
1227 if ( prop ) |
|
1228 resolution_x = (FT_Short)prop->value.l; |
|
1229 |
|
1230 prop = pcf_find_property( face, "RESOLUTION_Y" ); |
|
1231 if ( prop ) |
|
1232 resolution_y = (FT_Short)prop->value.l; |
|
1233 |
|
1234 if ( bsize->y_ppem == 0 ) |
|
1235 { |
|
1236 bsize->y_ppem = bsize->size; |
|
1237 if ( resolution_y ) |
|
1238 bsize->y_ppem = bsize->y_ppem * resolution_y / 72; |
|
1239 } |
|
1240 if ( resolution_x && resolution_y ) |
|
1241 bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y; |
|
1242 else |
|
1243 bsize->x_ppem = bsize->y_ppem; |
|
1244 } |
|
1245 |
|
1246 /* set up charset */ |
|
1247 { |
|
1248 PCF_Property charset_registry = 0, charset_encoding = 0; |
|
1249 |
|
1250 |
|
1251 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" ); |
|
1252 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" ); |
|
1253 |
|
1254 if ( charset_registry && charset_registry->isString && |
|
1255 charset_encoding && charset_encoding->isString ) |
|
1256 { |
|
1257 if ( FT_STRDUP( face->charset_encoding, |
|
1258 charset_encoding->value.atom ) || |
|
1259 FT_STRDUP( face->charset_registry, |
|
1260 charset_registry->value.atom ) ) |
|
1261 goto Exit; |
|
1262 } |
|
1263 } |
|
1264 } |
|
1265 |
|
1266 Exit: |
|
1267 if ( error ) |
|
1268 { |
|
1269 /* This is done to respect the behaviour of the original */ |
|
1270 /* PCF font driver. */ |
|
1271 error = PCF_Err_Invalid_File_Format; |
|
1272 } |
|
1273 |
|
1274 return error; |
|
1275 } |
|
1276 |
|
1277 |
|
1278 /* END */ |