1 /* pcfdriver.c 2 3 FreeType font driver for pcf files 4 5 Copyright (C) 2000-2001, 2002 by 6 Francesco Zappa Nardelli 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 */ 26 27 28 #include <ft2build.h> 29 30 #include FT_INTERNAL_DEBUG_H 31 #include FT_INTERNAL_STREAM_H 32 #include FT_INTERNAL_OBJECTS_H 33 #include FT_GZIP_H 34 #include FT_ERRORS_H 35 36 #include "pcf.h" 37 #include "pcfdriver.h" 38 #include "pcfutil.h" 39 40 #include "pcferror.h" 41 42 #undef FT_COMPONENT 43 #define FT_COMPONENT trace_pcfread 44 45 46 typedef struct PCF_CMapRec_ 47 { 48 FT_CMapRec cmap; 49 FT_UInt num_encodings; 50 PCF_Encoding encodings; 51 52 } PCF_CMapRec, *PCF_CMap; 53 54 55 FT_CALLBACK_DEF( FT_Error ) pcf_cmap_init(PCF_CMap cmap)56 pcf_cmap_init( PCF_CMap cmap ) 57 { 58 PCF_Face face = (PCF_Face)FT_CMAP_FACE( cmap ); 59 60 61 cmap->num_encodings = (FT_UInt)face->nencodings; 62 cmap->encodings = face->encodings; 63 64 return FT_Err_Ok; 65 } 66 67 68 FT_CALLBACK_DEF( void ) pcf_cmap_done(PCF_CMap cmap)69 pcf_cmap_done( PCF_CMap cmap ) 70 { 71 cmap->encodings = NULL; 72 cmap->num_encodings = 0; 73 } 74 75 76 FT_CALLBACK_DEF( FT_UInt ) pcf_cmap_char_index(PCF_CMap cmap,FT_UInt32 charcode)77 pcf_cmap_char_index( PCF_CMap cmap, 78 FT_UInt32 charcode ) 79 { 80 PCF_Encoding encodings = cmap->encodings; 81 FT_UInt min, max, mid; 82 FT_UInt result = 0; 83 84 85 min = 0; 86 max = cmap->num_encodings; 87 88 while ( min < max ) 89 { 90 FT_UInt32 code; 91 92 93 mid = ( min + max ) >> 1; 94 code = encodings[mid].enc; 95 96 if ( charcode == code ) 97 { 98 result = encodings[mid].glyph + 1; 99 break; 100 } 101 102 if ( charcode < code ) 103 max = mid; 104 else 105 min = mid + 1; 106 } 107 108 return result; 109 } 110 111 112 FT_CALLBACK_DEF( FT_UInt ) pcf_cmap_char_next(PCF_CMap cmap,FT_UInt32 * acharcode)113 pcf_cmap_char_next( PCF_CMap cmap, 114 FT_UInt32 *acharcode ) 115 { 116 PCF_Encoding encodings = cmap->encodings; 117 FT_UInt min, max, mid; 118 FT_UInt32 charcode = *acharcode + 1; 119 FT_UInt result = 0; 120 121 122 min = 0; 123 max = cmap->num_encodings; 124 125 while ( min < max ) 126 { 127 FT_UInt32 code; 128 129 130 mid = ( min + max ) >> 1; 131 code = encodings[mid].enc; 132 133 if ( charcode == code ) 134 { 135 result = encodings[mid].glyph + 1; 136 goto Exit; 137 } 138 139 if ( charcode < code ) 140 max = mid; 141 else 142 min = mid + 1; 143 } 144 145 charcode = 0; 146 if ( min < cmap->num_encodings ) 147 { 148 charcode = encodings[min].enc; 149 result = encodings[min].glyph + 1; 150 } 151 152 Exit: 153 *acharcode = charcode; 154 return result; 155 } 156 157 158 FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec pcf_cmap_class = 159 { 160 sizeof( PCF_CMapRec ), 161 (FT_CMap_InitFunc) pcf_cmap_init, 162 (FT_CMap_DoneFunc) pcf_cmap_done, 163 (FT_CMap_CharIndexFunc)pcf_cmap_char_index, 164 (FT_CMap_CharNextFunc) pcf_cmap_char_next 165 }; 166 167 168 /*************************************************************************/ 169 /* */ 170 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 171 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 172 /* messages during execution. */ 173 /* */ 174 #undef FT_COMPONENT 175 #define FT_COMPONENT trace_pcfdriver 176 177 178 FT_CALLBACK_DEF( FT_Error ) PCF_Face_Done(PCF_Face face)179 PCF_Face_Done( PCF_Face face ) 180 { 181 FT_Memory memory = FT_FACE_MEMORY( face ); 182 183 184 FT_FREE( face->encodings ); 185 FT_FREE( face->metrics ); 186 187 /* free properties */ 188 { 189 PCF_Property prop = face->properties; 190 FT_Int i; 191 192 193 for ( i = 0; i < face->nprops; i++ ) 194 { 195 prop = &face->properties[i]; 196 197 FT_FREE( prop->name ); 198 if ( prop->isString ) 199 FT_FREE( prop->value ); 200 } 201 202 FT_FREE( face->properties ); 203 } 204 205 FT_FREE( face->toc.tables ); 206 FT_FREE( face->root.family_name ); 207 FT_FREE( face->root.available_sizes ); 208 FT_FREE( face->charset_encoding ); 209 FT_FREE( face->charset_registry ); 210 211 FT_TRACE4(( "PCF_Face_Done: done face\n" )); 212 213 /* close gzip stream if any */ 214 if ( face->root.stream == &face->gzip_stream ) 215 { 216 FT_Stream_Close( &face->gzip_stream ); 217 face->root.stream = face->gzip_source; 218 } 219 220 return PCF_Err_Ok; 221 } 222 223 224 FT_CALLBACK_DEF( FT_Error ) PCF_Face_Init(FT_Stream stream,PCF_Face face,FT_Int face_index,FT_Int num_params,FT_Parameter * params)225 PCF_Face_Init( FT_Stream stream, 226 PCF_Face face, 227 FT_Int face_index, 228 FT_Int num_params, 229 FT_Parameter* params ) 230 { 231 FT_Error error = PCF_Err_Ok; 232 233 FT_UNUSED( num_params ); 234 FT_UNUSED( params ); 235 FT_UNUSED( face_index ); 236 237 238 error = pcf_load_font( stream, face ); 239 if ( error ) 240 { 241 FT_Error error2; 242 243 /* this didn't work, try gzip support !! */ 244 error2 = FT_Stream_OpenGzip( &face->gzip_stream, stream ); 245 if ( error2 == FT_Err_Unimplemented_Feature ) 246 goto Fail; 247 248 error = error2; 249 if ( error ) 250 goto Fail; 251 252 face->gzip_source = stream; 253 face->root.stream = &face->gzip_stream; 254 255 stream = face->root.stream; 256 257 error = pcf_load_font( stream, face ); 258 if ( error ) 259 goto Fail; 260 } 261 262 /* set-up charmap */ 263 { 264 FT_String *charset_registry, *charset_encoding; 265 FT_Bool unicode_charmap = 0; 266 267 268 charset_registry = face->charset_registry; 269 charset_encoding = face->charset_encoding; 270 271 if ( ( charset_registry != NULL ) && 272 ( charset_encoding != NULL ) ) 273 { 274 if ( !ft_strcmp( face->charset_registry, "ISO10646" ) || 275 ( !ft_strcmp( face->charset_registry, "ISO8859" ) && 276 !ft_strcmp( face->charset_encoding, "1" ) ) ) 277 unicode_charmap = 1; 278 } 279 280 { 281 FT_CharMapRec charmap; 282 283 284 charmap.face = FT_FACE( face ); 285 charmap.encoding = FT_ENCODING_NONE; 286 charmap.platform_id = 0; 287 charmap.encoding_id = 0; 288 289 if ( unicode_charmap ) 290 { 291 charmap.encoding = FT_ENCODING_UNICODE; 292 charmap.platform_id = 3; 293 charmap.encoding_id = 1; 294 } 295 296 error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL ); 297 298 #if 0 299 /* Select default charmap */ 300 if (face->root.num_charmaps) 301 face->root.charmap = face->root.charmaps[0]; 302 #endif 303 } 304 } 305 306 Exit: 307 return error; 308 309 Fail: 310 FT_TRACE2(( "[not a valid PCF file]\n" )); 311 error = PCF_Err_Unknown_File_Format; /* error */ 312 goto Exit; 313 } 314 315 316 static FT_Error PCF_Set_Pixel_Size(FT_Size size)317 PCF_Set_Pixel_Size( FT_Size size ) 318 { 319 PCF_Face face = (PCF_Face)FT_SIZE_FACE( size ); 320 321 322 FT_TRACE4(( "rec %d - pres %d\n", size->metrics.y_ppem, 323 face->root.available_sizes->height )); 324 325 if ( size->metrics.y_ppem == face->root.available_sizes->height ) 326 { 327 size->metrics.ascender = face->accel.fontAscent << 6; 328 size->metrics.descender = face->accel.fontDescent * (-64); 329 #if 0 330 size->metrics.height = face->accel.maxbounds.ascent << 6; 331 #endif 332 size->metrics.height = size->metrics.ascender - 333 size->metrics.descender; 334 335 size->metrics.max_advance = face->accel.maxbounds.characterWidth << 6; 336 337 return PCF_Err_Ok; 338 } 339 else 340 { 341 FT_TRACE4(( "size WRONG\n" )); 342 return PCF_Err_Invalid_Pixel_Size; 343 } 344 } 345 346 347 static FT_Error PCF_Glyph_Load(FT_GlyphSlot slot,FT_Size size,FT_UInt glyph_index,FT_Int32 load_flags)348 PCF_Glyph_Load( FT_GlyphSlot slot, 349 FT_Size size, 350 FT_UInt glyph_index, 351 FT_Int32 load_flags ) 352 { 353 PCF_Face face = (PCF_Face)FT_SIZE_FACE( size ); 354 FT_Stream stream = face->root.stream; 355 FT_Error error = PCF_Err_Ok; 356 FT_Memory memory = FT_FACE( face )->memory; 357 FT_Bitmap* bitmap = &slot->bitmap; 358 PCF_Metric metric; 359 int bytes; 360 361 FT_UNUSED( load_flags ); 362 363 364 FT_TRACE4(( "load_glyph %d ---", glyph_index )); 365 366 if ( !face ) 367 { 368 error = PCF_Err_Invalid_Argument; 369 goto Exit; 370 } 371 372 if ( glyph_index > 0 ) 373 glyph_index--; 374 375 metric = face->metrics + glyph_index; 376 377 bitmap->rows = metric->ascent + metric->descent; 378 bitmap->width = metric->rightSideBearing - metric->leftSideBearing; 379 bitmap->num_grays = 1; 380 bitmap->pixel_mode = FT_PIXEL_MODE_MONO; 381 382 FT_TRACE6(( "BIT_ORDER %d ; BYTE_ORDER %d ; GLYPH_PAD %d\n", 383 PCF_BIT_ORDER( face->bitmapsFormat ), 384 PCF_BYTE_ORDER( face->bitmapsFormat ), 385 PCF_GLYPH_PAD( face->bitmapsFormat ) )); 386 387 switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) ) 388 { 389 case 1: 390 bitmap->pitch = ( bitmap->width + 7 ) >> 3; 391 break; 392 393 case 2: 394 bitmap->pitch = ( ( bitmap->width + 15 ) >> 4 ) << 1; 395 break; 396 397 case 4: 398 bitmap->pitch = ( ( bitmap->width + 31 ) >> 5 ) << 2; 399 break; 400 401 case 8: 402 bitmap->pitch = ( ( bitmap->width + 63 ) >> 6 ) << 3; 403 break; 404 405 default: 406 return PCF_Err_Invalid_File_Format; 407 } 408 409 /* XXX: to do: are there cases that need repadding the bitmap? */ 410 bytes = bitmap->pitch * bitmap->rows; 411 412 if ( FT_ALLOC( bitmap->buffer, bytes ) ) 413 goto Exit; 414 415 if ( FT_STREAM_SEEK( metric->bits ) || 416 FT_STREAM_READ( bitmap->buffer, bytes ) ) 417 goto Exit; 418 419 if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst ) 420 BitOrderInvert( bitmap->buffer, bytes ); 421 422 if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) != 423 PCF_BIT_ORDER( face->bitmapsFormat ) ) ) 424 { 425 switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) ) 426 { 427 case 1: 428 break; 429 430 case 2: 431 TwoByteSwap( bitmap->buffer, bytes ); 432 break; 433 434 case 4: 435 FourByteSwap( bitmap->buffer, bytes ); 436 break; 437 } 438 } 439 440 slot->bitmap_left = metric->leftSideBearing; 441 slot->bitmap_top = metric->ascent; 442 443 slot->metrics.horiAdvance = metric->characterWidth << 6 ; 444 slot->metrics.horiBearingX = metric->leftSideBearing << 6 ; 445 slot->metrics.horiBearingY = metric->ascent << 6 ; 446 slot->metrics.width = ( metric->rightSideBearing - 447 metric->leftSideBearing ) << 6; 448 slot->metrics.height = bitmap->rows << 6; 449 450 slot->linearHoriAdvance = (FT_Fixed)bitmap->width << 16; 451 slot->format = FT_GLYPH_FORMAT_BITMAP; 452 slot->flags = FT_GLYPH_OWN_BITMAP; 453 454 FT_TRACE4(( " --- ok\n" )); 455 456 Exit: 457 return error; 458 } 459 460 461 FT_CALLBACK_TABLE_DEF 462 const FT_Driver_ClassRec pcf_driver_class = 463 { 464 { 465 ft_module_font_driver, 466 sizeof ( FT_DriverRec ), 467 468 "pcf", 469 0x10000L, 470 0x20000L, 471 472 0, 473 474 (FT_Module_Constructor)0, 475 (FT_Module_Destructor) 0, 476 (FT_Module_Requester) 0 477 }, 478 479 sizeof( PCF_FaceRec ), 480 sizeof( FT_SizeRec ), 481 sizeof( FT_GlyphSlotRec ), 482 483 (FT_Face_InitFunc) PCF_Face_Init, 484 (FT_Face_DoneFunc) PCF_Face_Done, 485 (FT_Size_InitFunc) 0, 486 (FT_Size_DoneFunc) 0, 487 (FT_Slot_InitFunc) 0, 488 (FT_Slot_DoneFunc) 0, 489 490 (FT_Size_ResetPointsFunc) PCF_Set_Pixel_Size, 491 (FT_Size_ResetPixelsFunc) PCF_Set_Pixel_Size, 492 493 (FT_Slot_LoadFunc) PCF_Glyph_Load, 494 495 (FT_Face_GetKerningFunc) 0, 496 (FT_Face_AttachFunc) 0, 497 (FT_Face_GetAdvancesFunc) 0 498 }; 499 500 501 /* END */ 502