Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpcfread.c
Go to the documentation of this file.
00001 /* pcfread.c 00002 00003 FreeType font driver for pcf fonts 00004 00005 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 00006 2010 by 00007 Francesco Zappa Nardelli 00008 00009 Permission is hereby granted, free of charge, to any person obtaining a copy 00010 of this software and associated documentation files (the "Software"), to deal 00011 in the Software without restriction, including without limitation the rights 00012 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00013 copies of the Software, and to permit persons to whom the Software is 00014 furnished to do so, subject to the following conditions: 00015 00016 The above copyright notice and this permission notice shall be included in 00017 all copies or substantial portions of the Software. 00018 00019 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00020 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00021 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00022 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00023 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00024 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00025 THE SOFTWARE. 00026 */ 00027 00028 00029 #include <ft2build.h> 00030 00031 #include FT_INTERNAL_DEBUG_H 00032 #include FT_INTERNAL_STREAM_H 00033 #include FT_INTERNAL_OBJECTS_H 00034 00035 #include "pcf.h" 00036 #include "pcfread.h" 00037 00038 #include "pcferror.h" 00039 00040 00041 /*************************************************************************/ 00042 /* */ 00043 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 00044 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 00045 /* messages during execution. */ 00046 /* */ 00047 #undef FT_COMPONENT 00048 #define FT_COMPONENT trace_pcfread 00049 00050 00051 #ifdef FT_DEBUG_LEVEL_TRACE 00052 static const char* const tableNames[] = 00053 { 00054 "prop", "accl", "mtrcs", "bmps", "imtrcs", 00055 "enc", "swidth", "names", "accel" 00056 }; 00057 #endif 00058 00059 00060 static 00061 const FT_Frame_Field pcf_toc_header[] = 00062 { 00063 #undef FT_STRUCTURE 00064 #define FT_STRUCTURE PCF_TocRec 00065 00066 FT_FRAME_START( 8 ), 00067 FT_FRAME_ULONG_LE( version ), 00068 FT_FRAME_ULONG_LE( count ), 00069 FT_FRAME_END 00070 }; 00071 00072 00073 static 00074 const FT_Frame_Field pcf_table_header[] = 00075 { 00076 #undef FT_STRUCTURE 00077 #define FT_STRUCTURE PCF_TableRec 00078 00079 FT_FRAME_START( 16 ), 00080 FT_FRAME_ULONG_LE( type ), 00081 FT_FRAME_ULONG_LE( format ), 00082 FT_FRAME_ULONG_LE( size ), 00083 FT_FRAME_ULONG_LE( offset ), 00084 FT_FRAME_END 00085 }; 00086 00087 00088 static FT_Error 00089 pcf_read_TOC( FT_Stream stream, 00090 PCF_Face face ) 00091 { 00092 FT_Error error; 00093 PCF_Toc toc = &face->toc; 00094 PCF_Table tables; 00095 00096 FT_Memory memory = FT_FACE(face)->memory; 00097 FT_UInt n; 00098 00099 00100 if ( FT_STREAM_SEEK ( 0 ) || 00101 FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) ) 00102 return PCF_Err_Cannot_Open_Resource; 00103 00104 if ( toc->version != PCF_FILE_VERSION || 00105 toc->count > FT_ARRAY_MAX( face->toc.tables ) || 00106 toc->count == 0 ) 00107 return PCF_Err_Invalid_File_Format; 00108 00109 if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) ) 00110 return PCF_Err_Out_Of_Memory; 00111 00112 tables = face->toc.tables; 00113 for ( n = 0; n < toc->count; n++ ) 00114 { 00115 if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) 00116 goto Exit; 00117 tables++; 00118 } 00119 00120 /* Sort tables and check for overlaps. Because they are almost */ 00121 /* always ordered already, an in-place bubble sort with simultaneous */ 00122 /* boundary checking seems appropriate. */ 00123 tables = face->toc.tables; 00124 00125 for ( n = 0; n < toc->count - 1; n++ ) 00126 { 00127 FT_UInt i, have_change; 00128 00129 00130 have_change = 0; 00131 00132 for ( i = 0; i < toc->count - 1 - n; i++ ) 00133 { 00134 PCF_TableRec tmp; 00135 00136 00137 if ( tables[i].offset > tables[i + 1].offset ) 00138 { 00139 tmp = tables[i]; 00140 tables[i] = tables[i + 1]; 00141 tables[i + 1] = tmp; 00142 00143 have_change = 1; 00144 } 00145 00146 if ( ( tables[i].size > tables[i + 1].offset ) || 00147 ( tables[i].offset > tables[i + 1].offset - tables[i].size ) ) 00148 return PCF_Err_Invalid_Offset; 00149 } 00150 00151 if ( !have_change ) 00152 break; 00153 } 00154 00155 #ifdef FT_DEBUG_LEVEL_TRACE 00156 00157 { 00158 FT_UInt i, j; 00159 const char* name = "?"; 00160 00161 00162 FT_TRACE4(( "pcf_read_TOC:\n" )); 00163 00164 FT_TRACE4(( " number of tables: %ld\n", face->toc.count )); 00165 00166 tables = face->toc.tables; 00167 for ( i = 0; i < toc->count; i++ ) 00168 { 00169 for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); 00170 j++ ) 00171 if ( tables[i].type == (FT_UInt)( 1 << j ) ) 00172 name = tableNames[j]; 00173 00174 FT_TRACE4(( " %d: type=%s, format=0x%X, " 00175 "size=%ld (0x%lX), offset=%ld (0x%lX)\n", 00176 i, name, 00177 tables[i].format, 00178 tables[i].size, tables[i].size, 00179 tables[i].offset, tables[i].offset )); 00180 } 00181 } 00182 00183 #endif 00184 00185 return PCF_Err_Ok; 00186 00187 Exit: 00188 FT_FREE( face->toc.tables ); 00189 return error; 00190 } 00191 00192 00193 #define PCF_METRIC_SIZE 12 00194 00195 static 00196 const FT_Frame_Field pcf_metric_header[] = 00197 { 00198 #undef FT_STRUCTURE 00199 #define FT_STRUCTURE PCF_MetricRec 00200 00201 FT_FRAME_START( PCF_METRIC_SIZE ), 00202 FT_FRAME_SHORT_LE( leftSideBearing ), 00203 FT_FRAME_SHORT_LE( rightSideBearing ), 00204 FT_FRAME_SHORT_LE( characterWidth ), 00205 FT_FRAME_SHORT_LE( ascent ), 00206 FT_FRAME_SHORT_LE( descent ), 00207 FT_FRAME_SHORT_LE( attributes ), 00208 FT_FRAME_END 00209 }; 00210 00211 00212 static 00213 const FT_Frame_Field pcf_metric_msb_header[] = 00214 { 00215 #undef FT_STRUCTURE 00216 #define FT_STRUCTURE PCF_MetricRec 00217 00218 FT_FRAME_START( PCF_METRIC_SIZE ), 00219 FT_FRAME_SHORT( leftSideBearing ), 00220 FT_FRAME_SHORT( rightSideBearing ), 00221 FT_FRAME_SHORT( characterWidth ), 00222 FT_FRAME_SHORT( ascent ), 00223 FT_FRAME_SHORT( descent ), 00224 FT_FRAME_SHORT( attributes ), 00225 FT_FRAME_END 00226 }; 00227 00228 00229 #define PCF_COMPRESSED_METRIC_SIZE 5 00230 00231 static 00232 const FT_Frame_Field pcf_compressed_metric_header[] = 00233 { 00234 #undef FT_STRUCTURE 00235 #define FT_STRUCTURE PCF_Compressed_MetricRec 00236 00237 FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ), 00238 FT_FRAME_BYTE( leftSideBearing ), 00239 FT_FRAME_BYTE( rightSideBearing ), 00240 FT_FRAME_BYTE( characterWidth ), 00241 FT_FRAME_BYTE( ascent ), 00242 FT_FRAME_BYTE( descent ), 00243 FT_FRAME_END 00244 }; 00245 00246 00247 static FT_Error 00248 pcf_get_metric( FT_Stream stream, 00249 FT_ULong format, 00250 PCF_Metric metric ) 00251 { 00252 FT_Error error = PCF_Err_Ok; 00253 00254 00255 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 00256 { 00257 const FT_Frame_Field* fields; 00258 00259 00260 /* parsing normal metrics */ 00261 fields = PCF_BYTE_ORDER( format ) == MSBFirst 00262 ? pcf_metric_msb_header 00263 : pcf_metric_header; 00264 00265 /* the following sets `error' but doesn't return in case of failure */ 00266 (void)FT_STREAM_READ_FIELDS( fields, metric ); 00267 } 00268 else 00269 { 00270 PCF_Compressed_MetricRec compr; 00271 00272 00273 /* parsing compressed metrics */ 00274 if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) ) 00275 goto Exit; 00276 00277 metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 ); 00278 metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 ); 00279 metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 ); 00280 metric->ascent = (FT_Short)( compr.ascent - 0x80 ); 00281 metric->descent = (FT_Short)( compr.descent - 0x80 ); 00282 metric->attributes = 0; 00283 } 00284 00285 Exit: 00286 return error; 00287 } 00288 00289 00290 static FT_Error 00291 pcf_seek_to_table_type( FT_Stream stream, 00292 PCF_Table tables, 00293 FT_ULong ntables, /* same as PCF_Toc->count */ 00294 FT_ULong type, 00295 FT_ULong *aformat, 00296 FT_ULong *asize ) 00297 { 00298 FT_Error error = PCF_Err_Invalid_File_Format; 00299 FT_ULong i; 00300 00301 00302 for ( i = 0; i < ntables; i++ ) 00303 if ( tables[i].type == type ) 00304 { 00305 if ( stream->pos > tables[i].offset ) 00306 { 00307 error = PCF_Err_Invalid_Stream_Skip; 00308 goto Fail; 00309 } 00310 00311 if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) ) 00312 { 00313 error = PCF_Err_Invalid_Stream_Skip; 00314 goto Fail; 00315 } 00316 00317 *asize = tables[i].size; 00318 *aformat = tables[i].format; 00319 00320 return PCF_Err_Ok; 00321 } 00322 00323 Fail: 00324 *asize = 0; 00325 return error; 00326 } 00327 00328 00329 static FT_Bool 00330 pcf_has_table_type( PCF_Table tables, 00331 FT_ULong ntables, /* same as PCF_Toc->count */ 00332 FT_ULong type ) 00333 { 00334 FT_ULong i; 00335 00336 00337 for ( i = 0; i < ntables; i++ ) 00338 if ( tables[i].type == type ) 00339 return TRUE; 00340 00341 return FALSE; 00342 } 00343 00344 00345 #define PCF_PROPERTY_SIZE 9 00346 00347 static 00348 const FT_Frame_Field pcf_property_header[] = 00349 { 00350 #undef FT_STRUCTURE 00351 #define FT_STRUCTURE PCF_ParsePropertyRec 00352 00353 FT_FRAME_START( PCF_PROPERTY_SIZE ), 00354 FT_FRAME_LONG_LE( name ), 00355 FT_FRAME_BYTE ( isString ), 00356 FT_FRAME_LONG_LE( value ), 00357 FT_FRAME_END 00358 }; 00359 00360 00361 static 00362 const FT_Frame_Field pcf_property_msb_header[] = 00363 { 00364 #undef FT_STRUCTURE 00365 #define FT_STRUCTURE PCF_ParsePropertyRec 00366 00367 FT_FRAME_START( PCF_PROPERTY_SIZE ), 00368 FT_FRAME_LONG( name ), 00369 FT_FRAME_BYTE( isString ), 00370 FT_FRAME_LONG( value ), 00371 FT_FRAME_END 00372 }; 00373 00374 00375 FT_LOCAL_DEF( PCF_Property ) 00376 pcf_find_property( PCF_Face face, 00377 const FT_String* prop ) 00378 { 00379 PCF_Property properties = face->properties; 00380 FT_Bool found = 0; 00381 int i; 00382 00383 00384 for ( i = 0 ; i < face->nprops && !found; i++ ) 00385 { 00386 if ( !ft_strcmp( properties[i].name, prop ) ) 00387 found = 1; 00388 } 00389 00390 if ( found ) 00391 return properties + i - 1; 00392 else 00393 return NULL; 00394 } 00395 00396 00397 static FT_Error 00398 pcf_get_properties( FT_Stream stream, 00399 PCF_Face face ) 00400 { 00401 PCF_ParseProperty props = 0; 00402 PCF_Property properties; 00403 FT_ULong nprops, i; 00404 FT_ULong format, size; 00405 FT_Error error; 00406 FT_Memory memory = FT_FACE(face)->memory; 00407 FT_ULong string_size; 00408 FT_String* strings = 0; 00409 00410 00411 error = pcf_seek_to_table_type( stream, 00412 face->toc.tables, 00413 face->toc.count, 00414 PCF_PROPERTIES, 00415 &format, 00416 &size ); 00417 if ( error ) 00418 goto Bail; 00419 00420 if ( FT_READ_ULONG_LE( format ) ) 00421 goto Bail; 00422 00423 FT_TRACE4(( "pcf_get_properties:\n" )); 00424 00425 FT_TRACE4(( " format = %ld\n", format )); 00426 00427 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 00428 goto Bail; 00429 00430 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 00431 (void)FT_READ_ULONG( nprops ); 00432 else 00433 (void)FT_READ_ULONG_LE( nprops ); 00434 if ( error ) 00435 goto Bail; 00436 00437 FT_TRACE4(( " nprop = %d (truncate %d props)\n", 00438 (int)nprops, nprops - (int)nprops )); 00439 00440 nprops = (int)nprops; 00441 00442 /* rough estimate */ 00443 if ( nprops > size / PCF_PROPERTY_SIZE ) 00444 { 00445 error = PCF_Err_Invalid_Table; 00446 goto Bail; 00447 } 00448 00449 face->nprops = (int)nprops; 00450 00451 if ( FT_NEW_ARRAY( props, nprops ) ) 00452 goto Bail; 00453 00454 for ( i = 0; i < nprops; i++ ) 00455 { 00456 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 00457 { 00458 if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) 00459 goto Bail; 00460 } 00461 else 00462 { 00463 if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) 00464 goto Bail; 00465 } 00466 } 00467 00468 /* pad the property array */ 00469 /* */ 00470 /* clever here - nprops is the same as the number of odd-units read, */ 00471 /* as only isStringProp are odd length (Keith Packard) */ 00472 /* */ 00473 if ( nprops & 3 ) 00474 { 00475 i = 4 - ( nprops & 3 ); 00476 if ( FT_STREAM_SKIP( i ) ) 00477 { 00478 error = PCF_Err_Invalid_Stream_Skip; 00479 goto Bail; 00480 } 00481 } 00482 00483 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 00484 (void)FT_READ_ULONG( string_size ); 00485 else 00486 (void)FT_READ_ULONG_LE( string_size ); 00487 if ( error ) 00488 goto Bail; 00489 00490 FT_TRACE4(( " string_size = %ld\n", string_size )); 00491 00492 /* rough estimate */ 00493 if ( string_size > size - nprops * PCF_PROPERTY_SIZE ) 00494 { 00495 error = PCF_Err_Invalid_Table; 00496 goto Bail; 00497 } 00498 00499 if ( FT_NEW_ARRAY( strings, string_size ) ) 00500 goto Bail; 00501 00502 error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); 00503 if ( error ) 00504 goto Bail; 00505 00506 if ( FT_NEW_ARRAY( properties, nprops ) ) 00507 goto Bail; 00508 00509 face->properties = properties; 00510 00511 for ( i = 0; i < nprops; i++ ) 00512 { 00513 FT_Long name_offset = props[i].name; 00514 00515 00516 if ( ( name_offset < 0 ) || 00517 ( (FT_ULong)name_offset > string_size ) ) 00518 { 00519 error = PCF_Err_Invalid_Offset; 00520 goto Bail; 00521 } 00522 00523 if ( FT_STRDUP( properties[i].name, strings + name_offset ) ) 00524 goto Bail; 00525 00526 FT_TRACE4(( " %s:", properties[i].name )); 00527 00528 properties[i].isString = props[i].isString; 00529 00530 if ( props[i].isString ) 00531 { 00532 FT_Long value_offset = props[i].value; 00533 00534 00535 if ( ( value_offset < 0 ) || 00536 ( (FT_ULong)value_offset > string_size ) ) 00537 { 00538 error = PCF_Err_Invalid_Offset; 00539 goto Bail; 00540 } 00541 00542 if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) ) 00543 goto Bail; 00544 00545 FT_TRACE4(( " `%s'\n", properties[i].value.atom )); 00546 } 00547 else 00548 { 00549 properties[i].value.l = props[i].value; 00550 00551 FT_TRACE4(( " %d\n", properties[i].value.l )); 00552 } 00553 } 00554 00555 error = PCF_Err_Ok; 00556 00557 Bail: 00558 FT_FREE( props ); 00559 FT_FREE( strings ); 00560 00561 return error; 00562 } 00563 00564 00565 static FT_Error 00566 pcf_get_metrics( FT_Stream stream, 00567 PCF_Face face ) 00568 { 00569 FT_Error error = PCF_Err_Ok; 00570 FT_Memory memory = FT_FACE(face)->memory; 00571 FT_ULong format, size; 00572 PCF_Metric metrics = 0; 00573 FT_ULong nmetrics, i; 00574 00575 00576 error = pcf_seek_to_table_type( stream, 00577 face->toc.tables, 00578 face->toc.count, 00579 PCF_METRICS, 00580 &format, 00581 &size ); 00582 if ( error ) 00583 return error; 00584 00585 if ( FT_READ_ULONG_LE( format ) ) 00586 goto Bail; 00587 00588 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && 00589 !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) 00590 return PCF_Err_Invalid_File_Format; 00591 00592 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 00593 { 00594 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 00595 (void)FT_READ_ULONG( nmetrics ); 00596 else 00597 (void)FT_READ_ULONG_LE( nmetrics ); 00598 } 00599 else 00600 { 00601 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 00602 (void)FT_READ_USHORT( nmetrics ); 00603 else 00604 (void)FT_READ_USHORT_LE( nmetrics ); 00605 } 00606 if ( error ) 00607 return PCF_Err_Invalid_File_Format; 00608 00609 face->nmetrics = nmetrics; 00610 00611 if ( !nmetrics ) 00612 return PCF_Err_Invalid_Table; 00613 00614 FT_TRACE4(( "pcf_get_metrics:\n" )); 00615 00616 FT_TRACE4(( " number of metrics: %d\n", nmetrics )); 00617 00618 /* rough estimate */ 00619 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 00620 { 00621 if ( nmetrics > size / PCF_METRIC_SIZE ) 00622 return PCF_Err_Invalid_Table; 00623 } 00624 else 00625 { 00626 if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) 00627 return PCF_Err_Invalid_Table; 00628 } 00629 00630 if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) 00631 return PCF_Err_Out_Of_Memory; 00632 00633 metrics = face->metrics; 00634 for ( i = 0; i < nmetrics; i++ ) 00635 { 00636 error = pcf_get_metric( stream, format, metrics + i ); 00637 00638 metrics[i].bits = 0; 00639 00640 FT_TRACE5(( " idx %d: width=%d, " 00641 "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", 00642 i, 00643 ( metrics + i )->characterWidth, 00644 ( metrics + i )->leftSideBearing, 00645 ( metrics + i )->rightSideBearing, 00646 ( metrics + i )->ascent, 00647 ( metrics + i )->descent, 00648 ( metrics + i )->attributes )); 00649 00650 if ( error ) 00651 break; 00652 } 00653 00654 if ( error ) 00655 FT_FREE( face->metrics ); 00656 00657 Bail: 00658 return error; 00659 } 00660 00661 00662 static FT_Error 00663 pcf_get_bitmaps( FT_Stream stream, 00664 PCF_Face face ) 00665 { 00666 FT_Error error = PCF_Err_Ok; 00667 FT_Memory memory = FT_FACE(face)->memory; 00668 FT_Long* offsets; 00669 FT_Long bitmapSizes[GLYPHPADOPTIONS]; 00670 FT_ULong format, size; 00671 FT_ULong nbitmaps, i, sizebitmaps = 0; 00672 00673 00674 error = pcf_seek_to_table_type( stream, 00675 face->toc.tables, 00676 face->toc.count, 00677 PCF_BITMAPS, 00678 &format, 00679 &size ); 00680 if ( error ) 00681 return error; 00682 00683 error = FT_Stream_EnterFrame( stream, 8 ); 00684 if ( error ) 00685 return error; 00686 00687 format = FT_GET_ULONG_LE(); 00688 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 00689 nbitmaps = FT_GET_ULONG(); 00690 else 00691 nbitmaps = FT_GET_ULONG_LE(); 00692 00693 FT_Stream_ExitFrame( stream ); 00694 00695 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 00696 return PCF_Err_Invalid_File_Format; 00697 00698 FT_TRACE4(( "pcf_get_bitmaps:\n" )); 00699 00700 FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps )); 00701 00702 /* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */ 00703 if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics ) 00704 return PCF_Err_Invalid_File_Format; 00705 00706 if ( FT_NEW_ARRAY( offsets, nbitmaps ) ) 00707 return error; 00708 00709 for ( i = 0; i < nbitmaps; i++ ) 00710 { 00711 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 00712 (void)FT_READ_LONG( offsets[i] ); 00713 else 00714 (void)FT_READ_LONG_LE( offsets[i] ); 00715 00716 FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n", 00717 i, offsets[i], offsets[i] )); 00718 } 00719 if ( error ) 00720 goto Bail; 00721 00722 for ( i = 0; i < GLYPHPADOPTIONS; i++ ) 00723 { 00724 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 00725 (void)FT_READ_LONG( bitmapSizes[i] ); 00726 else 00727 (void)FT_READ_LONG_LE( bitmapSizes[i] ); 00728 if ( error ) 00729 goto Bail; 00730 00731 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; 00732 00733 FT_TRACE4(( " padding %d implies a size of %ld\n", i, bitmapSizes[i] )); 00734 } 00735 00736 FT_TRACE4(( " %d bitmaps, padding index %ld\n", 00737 nbitmaps, 00738 PCF_GLYPH_PAD_INDEX( format ) )); 00739 FT_TRACE4(( " bitmap size = %d\n", sizebitmaps )); 00740 00741 FT_UNUSED( sizebitmaps ); /* only used for debugging */ 00742 00743 for ( i = 0; i < nbitmaps; i++ ) 00744 { 00745 /* rough estimate */ 00746 if ( ( offsets[i] < 0 ) || 00747 ( (FT_ULong)offsets[i] > size ) ) 00748 { 00749 FT_TRACE0(( "pcf_get_bitmaps:" 00750 " invalid offset to bitmap data of glyph %d\n", i )); 00751 } 00752 else 00753 face->metrics[i].bits = stream->pos + offsets[i]; 00754 } 00755 00756 face->bitmapsFormat = format; 00757 00758 Bail: 00759 FT_FREE( offsets ); 00760 return error; 00761 } 00762 00763 00764 static FT_Error 00765 pcf_get_encodings( FT_Stream stream, 00766 PCF_Face face ) 00767 { 00768 FT_Error error = PCF_Err_Ok; 00769 FT_Memory memory = FT_FACE(face)->memory; 00770 FT_ULong format, size; 00771 int firstCol, lastCol; 00772 int firstRow, lastRow; 00773 int nencoding, encodingOffset; 00774 int i, j; 00775 PCF_Encoding tmpEncoding, encoding = 0; 00776 00777 00778 error = pcf_seek_to_table_type( stream, 00779 face->toc.tables, 00780 face->toc.count, 00781 PCF_BDF_ENCODINGS, 00782 &format, 00783 &size ); 00784 if ( error ) 00785 return error; 00786 00787 error = FT_Stream_EnterFrame( stream, 14 ); 00788 if ( error ) 00789 return error; 00790 00791 format = FT_GET_ULONG_LE(); 00792 00793 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 00794 { 00795 firstCol = FT_GET_SHORT(); 00796 lastCol = FT_GET_SHORT(); 00797 firstRow = FT_GET_SHORT(); 00798 lastRow = FT_GET_SHORT(); 00799 face->defaultChar = FT_GET_SHORT(); 00800 } 00801 else 00802 { 00803 firstCol = FT_GET_SHORT_LE(); 00804 lastCol = FT_GET_SHORT_LE(); 00805 firstRow = FT_GET_SHORT_LE(); 00806 lastRow = FT_GET_SHORT_LE(); 00807 face->defaultChar = FT_GET_SHORT_LE(); 00808 } 00809 00810 FT_Stream_ExitFrame( stream ); 00811 00812 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 00813 return PCF_Err_Invalid_File_Format; 00814 00815 FT_TRACE4(( "pdf_get_encodings:\n" )); 00816 00817 FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n", 00818 firstCol, lastCol, firstRow, lastRow )); 00819 00820 nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 ); 00821 00822 if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) ) 00823 return PCF_Err_Out_Of_Memory; 00824 00825 error = FT_Stream_EnterFrame( stream, 2 * nencoding ); 00826 if ( error ) 00827 goto Bail; 00828 00829 for ( i = 0, j = 0 ; i < nencoding; i++ ) 00830 { 00831 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 00832 encodingOffset = FT_GET_SHORT(); 00833 else 00834 encodingOffset = FT_GET_SHORT_LE(); 00835 00836 if ( encodingOffset != -1 ) 00837 { 00838 tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) + 00839 firstRow ) * 256 ) + 00840 ( ( i % ( lastCol - firstCol + 1 ) ) + 00841 firstCol ); 00842 00843 tmpEncoding[j].glyph = (FT_Short)encodingOffset; 00844 00845 FT_TRACE5(( " code %d (0x%04X): idx %d\n", 00846 tmpEncoding[j].enc, tmpEncoding[j].enc, 00847 tmpEncoding[j].glyph )); 00848 00849 j++; 00850 } 00851 } 00852 FT_Stream_ExitFrame( stream ); 00853 00854 if ( FT_NEW_ARRAY( encoding, j ) ) 00855 goto Bail; 00856 00857 for ( i = 0; i < j; i++ ) 00858 { 00859 encoding[i].enc = tmpEncoding[i].enc; 00860 encoding[i].glyph = tmpEncoding[i].glyph; 00861 } 00862 00863 face->nencodings = j; 00864 face->encodings = encoding; 00865 FT_FREE( tmpEncoding ); 00866 00867 return error; 00868 00869 Bail: 00870 FT_FREE( encoding ); 00871 FT_FREE( tmpEncoding ); 00872 return error; 00873 } 00874 00875 00876 static 00877 const FT_Frame_Field pcf_accel_header[] = 00878 { 00879 #undef FT_STRUCTURE 00880 #define FT_STRUCTURE PCF_AccelRec 00881 00882 FT_FRAME_START( 20 ), 00883 FT_FRAME_BYTE ( noOverlap ), 00884 FT_FRAME_BYTE ( constantMetrics ), 00885 FT_FRAME_BYTE ( terminalFont ), 00886 FT_FRAME_BYTE ( constantWidth ), 00887 FT_FRAME_BYTE ( inkInside ), 00888 FT_FRAME_BYTE ( inkMetrics ), 00889 FT_FRAME_BYTE ( drawDirection ), 00890 FT_FRAME_SKIP_BYTES( 1 ), 00891 FT_FRAME_LONG_LE ( fontAscent ), 00892 FT_FRAME_LONG_LE ( fontDescent ), 00893 FT_FRAME_LONG_LE ( maxOverlap ), 00894 FT_FRAME_END 00895 }; 00896 00897 00898 static 00899 const FT_Frame_Field pcf_accel_msb_header[] = 00900 { 00901 #undef FT_STRUCTURE 00902 #define FT_STRUCTURE PCF_AccelRec 00903 00904 FT_FRAME_START( 20 ), 00905 FT_FRAME_BYTE ( noOverlap ), 00906 FT_FRAME_BYTE ( constantMetrics ), 00907 FT_FRAME_BYTE ( terminalFont ), 00908 FT_FRAME_BYTE ( constantWidth ), 00909 FT_FRAME_BYTE ( inkInside ), 00910 FT_FRAME_BYTE ( inkMetrics ), 00911 FT_FRAME_BYTE ( drawDirection ), 00912 FT_FRAME_SKIP_BYTES( 1 ), 00913 FT_FRAME_LONG ( fontAscent ), 00914 FT_FRAME_LONG ( fontDescent ), 00915 FT_FRAME_LONG ( maxOverlap ), 00916 FT_FRAME_END 00917 }; 00918 00919 00920 static FT_Error 00921 pcf_get_accel( FT_Stream stream, 00922 PCF_Face face, 00923 FT_ULong type ) 00924 { 00925 FT_ULong format, size; 00926 FT_Error error = PCF_Err_Ok; 00927 PCF_Accel accel = &face->accel; 00928 00929 00930 error = pcf_seek_to_table_type( stream, 00931 face->toc.tables, 00932 face->toc.count, 00933 type, 00934 &format, 00935 &size ); 00936 if ( error ) 00937 goto Bail; 00938 00939 if ( FT_READ_ULONG_LE( format ) ) 00940 goto Bail; 00941 00942 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && 00943 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) 00944 goto Bail; 00945 00946 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 00947 { 00948 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) ) 00949 goto Bail; 00950 } 00951 else 00952 { 00953 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) ) 00954 goto Bail; 00955 } 00956 00957 error = pcf_get_metric( stream, 00958 format & ( ~PCF_FORMAT_MASK ), 00959 &(accel->minbounds) ); 00960 if ( error ) 00961 goto Bail; 00962 00963 error = pcf_get_metric( stream, 00964 format & ( ~PCF_FORMAT_MASK ), 00965 &(accel->maxbounds) ); 00966 if ( error ) 00967 goto Bail; 00968 00969 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) 00970 { 00971 error = pcf_get_metric( stream, 00972 format & ( ~PCF_FORMAT_MASK ), 00973 &(accel->ink_minbounds) ); 00974 if ( error ) 00975 goto Bail; 00976 00977 error = pcf_get_metric( stream, 00978 format & ( ~PCF_FORMAT_MASK ), 00979 &(accel->ink_maxbounds) ); 00980 if ( error ) 00981 goto Bail; 00982 } 00983 else 00984 { 00985 accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */ 00986 accel->ink_maxbounds = accel->maxbounds; 00987 } 00988 00989 Bail: 00990 return error; 00991 } 00992 00993 00994 static FT_Error 00995 pcf_interpret_style( PCF_Face pcf ) 00996 { 00997 FT_Error error = PCF_Err_Ok; 00998 FT_Face face = FT_FACE( pcf ); 00999 FT_Memory memory = face->memory; 01000 01001 PCF_Property prop; 01002 01003 size_t nn, len; 01004 char* strings[4] = { NULL, NULL, NULL, NULL }; 01005 size_t lengths[4]; 01006 01007 01008 face->style_flags = 0; 01009 01010 prop = pcf_find_property( pcf, "SLANT" ); 01011 if ( prop && prop->isString && 01012 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || 01013 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) 01014 { 01015 face->style_flags |= FT_STYLE_FLAG_ITALIC; 01016 strings[2] = ( *(prop->value.atom) == 'O' || 01017 *(prop->value.atom) == 'o' ) ? (char *)"Oblique" 01018 : (char *)"Italic"; 01019 } 01020 01021 prop = pcf_find_property( pcf, "WEIGHT_NAME" ); 01022 if ( prop && prop->isString && 01023 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) 01024 { 01025 face->style_flags |= FT_STYLE_FLAG_BOLD; 01026 strings[1] = (char *)"Bold"; 01027 } 01028 01029 prop = pcf_find_property( pcf, "SETWIDTH_NAME" ); 01030 if ( prop && prop->isString && 01031 *(prop->value.atom) && 01032 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 01033 strings[3] = (char *)(prop->value.atom); 01034 01035 prop = pcf_find_property( pcf, "ADD_STYLE_NAME" ); 01036 if ( prop && prop->isString && 01037 *(prop->value.atom) && 01038 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 01039 strings[0] = (char *)(prop->value.atom); 01040 01041 for ( len = 0, nn = 0; nn < 4; nn++ ) 01042 { 01043 lengths[nn] = 0; 01044 if ( strings[nn] ) 01045 { 01046 lengths[nn] = ft_strlen( strings[nn] ); 01047 len += lengths[nn] + 1; 01048 } 01049 } 01050 01051 if ( len == 0 ) 01052 { 01053 strings[0] = (char *)"Regular"; 01054 lengths[0] = ft_strlen( strings[0] ); 01055 len = lengths[0] + 1; 01056 } 01057 01058 { 01059 char* s; 01060 01061 01062 if ( FT_ALLOC( face->style_name, len ) ) 01063 return error; 01064 01065 s = face->style_name; 01066 01067 for ( nn = 0; nn < 4; nn++ ) 01068 { 01069 char* src = strings[nn]; 01070 01071 01072 len = lengths[nn]; 01073 01074 if ( src == NULL ) 01075 continue; 01076 01077 /* separate elements with a space */ 01078 if ( s != face->style_name ) 01079 *s++ = ' '; 01080 01081 ft_memcpy( s, src, len ); 01082 01083 /* need to convert spaces to dashes for */ 01084 /* add_style_name and setwidth_name */ 01085 if ( nn == 0 || nn == 3 ) 01086 { 01087 size_t mm; 01088 01089 01090 for ( mm = 0; mm < len; mm++ ) 01091 if (s[mm] == ' ') 01092 s[mm] = '-'; 01093 } 01094 01095 s += len; 01096 } 01097 *s = 0; 01098 } 01099 01100 return error; 01101 } 01102 01103 01104 FT_LOCAL_DEF( FT_Error ) 01105 pcf_load_font( FT_Stream stream, 01106 PCF_Face face ) 01107 { 01108 FT_Error error = PCF_Err_Ok; 01109 FT_Memory memory = FT_FACE(face)->memory; 01110 FT_Bool hasBDFAccelerators; 01111 01112 01113 error = pcf_read_TOC( stream, face ); 01114 if ( error ) 01115 goto Exit; 01116 01117 error = pcf_get_properties( stream, face ); 01118 if ( error ) 01119 goto Exit; 01120 01121 /* Use the old accelerators if no BDF accelerators are in the file. */ 01122 hasBDFAccelerators = pcf_has_table_type( face->toc.tables, 01123 face->toc.count, 01124 PCF_BDF_ACCELERATORS ); 01125 if ( !hasBDFAccelerators ) 01126 { 01127 error = pcf_get_accel( stream, face, PCF_ACCELERATORS ); 01128 if ( error ) 01129 goto Exit; 01130 } 01131 01132 /* metrics */ 01133 error = pcf_get_metrics( stream, face ); 01134 if ( error ) 01135 goto Exit; 01136 01137 /* bitmaps */ 01138 error = pcf_get_bitmaps( stream, face ); 01139 if ( error ) 01140 goto Exit; 01141 01142 /* encodings */ 01143 error = pcf_get_encodings( stream, face ); 01144 if ( error ) 01145 goto Exit; 01146 01147 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */ 01148 if ( hasBDFAccelerators ) 01149 { 01150 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS ); 01151 if ( error ) 01152 goto Exit; 01153 } 01154 01155 /* XXX: TO DO: inkmetrics and glyph_names are missing */ 01156 01157 /* now construct the face object */ 01158 { 01159 FT_Face root = FT_FACE( face ); 01160 PCF_Property prop; 01161 01162 01163 root->num_faces = 1; 01164 root->face_index = 0; 01165 root->face_flags = FT_FACE_FLAG_FIXED_SIZES | 01166 FT_FACE_FLAG_HORIZONTAL | 01167 FT_FACE_FLAG_FAST_GLYPHS; 01168 01169 if ( face->accel.constantWidth ) 01170 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 01171 01172 if ( ( error = pcf_interpret_style( face ) ) != 0 ) 01173 goto Exit; 01174 01175 prop = pcf_find_property( face, "FAMILY_NAME" ); 01176 if ( prop && prop->isString ) 01177 { 01178 if ( FT_STRDUP( root->family_name, prop->value.atom ) ) 01179 goto Exit; 01180 } 01181 else 01182 root->family_name = NULL; 01183 01184 /* 01185 * Note: We shift all glyph indices by +1 since we must 01186 * respect the convention that glyph 0 always corresponds 01187 * to the `missing glyph'. 01188 * 01189 * This implies bumping the number of `available' glyphs by 1. 01190 */ 01191 root->num_glyphs = face->nmetrics + 1; 01192 01193 root->num_fixed_sizes = 1; 01194 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) 01195 goto Exit; 01196 01197 { 01198 FT_Bitmap_Size* bsize = root->available_sizes; 01199 FT_Short resolution_x = 0, resolution_y = 0; 01200 01201 01202 FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) ); 01203 01204 #if 0 01205 bsize->height = face->accel.maxbounds.ascent << 6; 01206 #endif 01207 bsize->height = (FT_Short)( face->accel.fontAscent + 01208 face->accel.fontDescent ); 01209 01210 prop = pcf_find_property( face, "AVERAGE_WIDTH" ); 01211 if ( prop ) 01212 bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 ); 01213 else 01214 bsize->width = (FT_Short)( bsize->height * 2/3 ); 01215 01216 prop = pcf_find_property( face, "POINT_SIZE" ); 01217 if ( prop ) 01218 /* convert from 722.7 decipoints to 72 points per inch */ 01219 bsize->size = 01220 (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L ); 01221 01222 prop = pcf_find_property( face, "PIXEL_SIZE" ); 01223 if ( prop ) 01224 bsize->y_ppem = (FT_Short)prop->value.l << 6; 01225 01226 prop = pcf_find_property( face, "RESOLUTION_X" ); 01227 if ( prop ) 01228 resolution_x = (FT_Short)prop->value.l; 01229 01230 prop = pcf_find_property( face, "RESOLUTION_Y" ); 01231 if ( prop ) 01232 resolution_y = (FT_Short)prop->value.l; 01233 01234 if ( bsize->y_ppem == 0 ) 01235 { 01236 bsize->y_ppem = bsize->size; 01237 if ( resolution_y ) 01238 bsize->y_ppem = bsize->y_ppem * resolution_y / 72; 01239 } 01240 if ( resolution_x && resolution_y ) 01241 bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y; 01242 else 01243 bsize->x_ppem = bsize->y_ppem; 01244 } 01245 01246 /* set up charset */ 01247 { 01248 PCF_Property charset_registry = 0, charset_encoding = 0; 01249 01250 01251 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" ); 01252 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" ); 01253 01254 if ( charset_registry && charset_registry->isString && 01255 charset_encoding && charset_encoding->isString ) 01256 { 01257 if ( FT_STRDUP( face->charset_encoding, 01258 charset_encoding->value.atom ) || 01259 FT_STRDUP( face->charset_registry, 01260 charset_registry->value.atom ) ) 01261 goto Exit; 01262 } 01263 } 01264 } 01265 01266 Exit: 01267 if ( error ) 01268 { 01269 /* This is done to respect the behaviour of the original */ 01270 /* PCF font driver. */ 01271 error = PCF_Err_Invalid_File_Format; 01272 } 01273 01274 return error; 01275 } 01276 01277 01278 /* END */ Generated on Sat May 26 2012 04:32:46 for ReactOS by
1.7.6.1
|