David Turner | 993a8d0 | 2002-05-18 12:03:43 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2000 Computing Research Labs, New Mexico State University |
| 3 | * Copyright 2001 Francesco Zappa Nardelli |
| 4 | * |
| 5 | * Permission is hereby granted, free of charge, to any person obtaining a |
| 6 | * copy of this software and associated documentation files (the "Software"), |
| 7 | * to deal in the Software without restriction, including without limitation |
| 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 9 | * and/or sell copies of the Software, and to permit persons to whom the |
| 10 | * Software is furnished to do so, subject to the following conditions: |
| 11 | * |
| 12 | * The above copyright notice and this permission notice shall be included in |
| 13 | * all copies or substantial portions of the Software. |
| 14 | * |
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 18 | * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY |
| 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT |
| 20 | * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR |
| 21 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 22 | */ |
| 23 | |
| 24 | /* |
| 25 | static char rcsid[] = "$Id$"; |
| 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 | |
| 34 | #include "bdf.h" |
| 35 | |
| 36 | #include "bdferror.h" |
| 37 | |
| 38 | #undef MAX |
| 39 | #define MAX(h, i) ((h) > (i) ? (h) : (i)) |
| 40 | |
| 41 | #undef MIN |
| 42 | #define MIN(l, o) ((l) < (o) ? (l) : (o)) |
| 43 | |
| 44 | /************************************************************************** |
| 45 | * |
| 46 | * Masks used for checking different bits per pixel cases. |
| 47 | * |
| 48 | **************************************************************************/ |
| 49 | |
| 50 | static const unsigned char onebpp[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; |
| 51 | static const unsigned char twobpp[] = { 0xc0, 0x30, 0x0c, 0x03 }; |
| 52 | static const unsigned char fourbpp[] = { 0xf0, 0x0f }; |
| 53 | static const unsigned char eightbpp[] = { 0xff }; |
| 54 | |
| 55 | /************************************************************************** |
| 56 | * |
| 57 | * Default BDF font options. |
| 58 | * |
| 59 | **************************************************************************/ |
| 60 | |
| 61 | static const bdf_options_t _bdf_opts = |
| 62 | { |
| 63 | 1, /* Hint TTF glyphs. */ |
| 64 | 1, /* Correct metrics. */ |
| 65 | 1, /* Preserve unencoded glyphs. */ |
| 66 | 1, /* Preserve comments. */ |
| 67 | 1, /* Pad character-cells. */ |
| 68 | BDF_PROPORTIONAL, /* Default spacing. */ |
| 69 | 12, /* Default point size. */ |
| 70 | 0, /* Default horizontal resolution. */ |
| 71 | 0, /* Default vertical resolution. */ |
| 72 | 1, /* Bits per pixel. */ |
| 73 | BDF_UNIX_EOL, /* Line separator. */ |
| 74 | }; |
| 75 | |
| 76 | /************************************************************************** |
| 77 | * |
| 78 | * Builtin BDF font properties. |
| 79 | * |
| 80 | **************************************************************************/ |
| 81 | |
| 82 | /* |
| 83 | * List of most properties that might appear in a font. Doesn't include the |
| 84 | * RAW_* and AXIS_* properties in X11R6 polymorphic fonts. |
| 85 | */ |
| 86 | static const bdf_property_t _bdf_properties[] = |
| 87 | { |
| 88 | {"ADD_STYLE_NAME", BDF_ATOM, 1}, |
| 89 | {"AVERAGE_WIDTH", BDF_INTEGER, 1}, |
| 90 | {"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1}, |
| 91 | {"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1}, |
| 92 | {"CAP_HEIGHT", BDF_INTEGER, 1}, |
| 93 | {"CHARSET_COLLECTIONS", BDF_ATOM, 1}, |
| 94 | {"CHARSET_ENCODING", BDF_ATOM, 1}, |
| 95 | {"CHARSET_REGISTRY", BDF_ATOM, 1}, |
| 96 | {"COMMENT", BDF_ATOM, 1}, |
| 97 | {"COPYRIGHT", BDF_ATOM, 1}, |
| 98 | {"DEFAULT_CHAR", BDF_CARDINAL, 1}, |
| 99 | {"DESTINATION", BDF_CARDINAL, 1}, |
| 100 | {"DEVICE_FONT_NAME", BDF_ATOM, 1}, |
| 101 | {"END_SPACE", BDF_INTEGER, 1}, |
| 102 | {"FACE_NAME", BDF_ATOM, 1}, |
| 103 | {"FAMILY_NAME", BDF_ATOM, 1}, |
| 104 | {"FIGURE_WIDTH", BDF_INTEGER, 1}, |
| 105 | {"FONT", BDF_ATOM, 1}, |
| 106 | {"FONTNAME_REGISTRY", BDF_ATOM, 1}, |
| 107 | {"FONT_ASCENT", BDF_INTEGER, 1}, |
| 108 | {"FONT_DESCENT", BDF_INTEGER, 1}, |
| 109 | {"FOUNDRY", BDF_ATOM, 1}, |
| 110 | {"FULL_NAME", BDF_ATOM, 1}, |
| 111 | {"ITALIC_ANGLE", BDF_INTEGER, 1}, |
| 112 | {"MAX_SPACE", BDF_INTEGER, 1}, |
| 113 | {"MIN_SPACE", BDF_INTEGER, 1}, |
| 114 | {"NORM_SPACE", BDF_INTEGER, 1}, |
| 115 | {"NOTICE", BDF_ATOM, 1}, |
| 116 | {"PIXEL_SIZE", BDF_INTEGER, 1}, |
| 117 | {"POINT_SIZE", BDF_INTEGER, 1}, |
| 118 | {"QUAD_WIDTH", BDF_INTEGER, 1}, |
| 119 | {"RAW_ASCENT", BDF_INTEGER, 1}, |
| 120 | {"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1}, |
| 121 | {"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1}, |
| 122 | {"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1}, |
| 123 | {"RAW_CAP_HEIGHT", BDF_INTEGER, 1}, |
| 124 | {"RAW_DESCENT", BDF_INTEGER, 1}, |
| 125 | {"RAW_END_SPACE", BDF_INTEGER, 1}, |
| 126 | {"RAW_FIGURE_WIDTH", BDF_INTEGER, 1}, |
| 127 | {"RAW_MAX_SPACE", BDF_INTEGER, 1}, |
| 128 | {"RAW_MIN_SPACE", BDF_INTEGER, 1}, |
| 129 | {"RAW_NORM_SPACE", BDF_INTEGER, 1}, |
| 130 | {"RAW_PIXEL_SIZE", BDF_INTEGER, 1}, |
| 131 | {"RAW_POINT_SIZE", BDF_INTEGER, 1}, |
| 132 | {"RAW_PIXELSIZE", BDF_INTEGER, 1}, |
| 133 | {"RAW_POINTSIZE", BDF_INTEGER, 1}, |
| 134 | {"RAW_QUAD_WIDTH", BDF_INTEGER, 1}, |
| 135 | {"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1}, |
| 136 | {"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1}, |
| 137 | {"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1}, |
| 138 | {"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1}, |
| 139 | {"RAW_SUBSCRIPT_X", BDF_INTEGER, 1}, |
| 140 | {"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1}, |
| 141 | {"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1}, |
| 142 | {"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1}, |
| 143 | {"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1}, |
| 144 | {"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1}, |
| 145 | {"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1}, |
| 146 | {"RAW_X_HEIGHT", BDF_INTEGER, 1}, |
| 147 | {"RELATIVE_SETWIDTH", BDF_CARDINAL, 1}, |
| 148 | {"RELATIVE_WEIGHT", BDF_CARDINAL, 1}, |
| 149 | {"RESOLUTION", BDF_INTEGER, 1}, |
| 150 | {"RESOLUTION_X", BDF_CARDINAL, 1}, |
| 151 | {"RESOLUTION_Y", BDF_CARDINAL, 1}, |
| 152 | {"SETWIDTH_NAME", BDF_ATOM, 1}, |
| 153 | {"SLANT", BDF_ATOM, 1}, |
| 154 | {"SMALL_CAP_SIZE", BDF_INTEGER, 1}, |
| 155 | {"SPACING", BDF_ATOM, 1}, |
| 156 | {"STRIKEOUT_ASCENT", BDF_INTEGER, 1}, |
| 157 | {"STRIKEOUT_DESCENT", BDF_INTEGER, 1}, |
| 158 | {"SUBSCRIPT_SIZE", BDF_INTEGER, 1}, |
| 159 | {"SUBSCRIPT_X", BDF_INTEGER, 1}, |
| 160 | {"SUBSCRIPT_Y", BDF_INTEGER, 1}, |
| 161 | {"SUPERSCRIPT_SIZE", BDF_INTEGER, 1}, |
| 162 | {"SUPERSCRIPT_X", BDF_INTEGER, 1}, |
| 163 | {"SUPERSCRIPT_Y", BDF_INTEGER, 1}, |
| 164 | {"UNDERLINE_POSITION", BDF_INTEGER, 1}, |
| 165 | {"UNDERLINE_THICKNESS", BDF_INTEGER, 1}, |
| 166 | {"WEIGHT", BDF_CARDINAL, 1}, |
| 167 | {"WEIGHT_NAME", BDF_ATOM, 1}, |
| 168 | {"X_HEIGHT", BDF_INTEGER, 1}, |
| 169 | {"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1}, |
| 170 | {"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1}, |
| 171 | }; |
| 172 | |
| 173 | static const FT_ULong _num_bdf_properties = FT_NUM_ELEMENT(_bdf_properties); |
| 174 | |
| 175 | /* |
| 176 | * User defined properties. |
| 177 | */ |
| 178 | /*static bdf_property_t *user_props; |
| 179 | static unsigned long nuser_props = 0;*/ |
| 180 | |
| 181 | /************************************************************************** |
| 182 | * |
| 183 | * Hash table utilities for the properties. |
| 184 | * |
| 185 | **************************************************************************/ |
| 186 | |
| 187 | #define INITIAL_HT_SIZE 241 |
| 188 | |
| 189 | typedef void (*hash_free_func)(hashnode node); |
| 190 | |
| 191 | static hashnode* |
| 192 | hash_bucket(char *key, hashtable *ht) |
| 193 | { |
| 194 | char* kp = key; |
| 195 | unsigned long res = 0; |
| 196 | hashnode* bp = ht->table, *ndp; |
| 197 | |
| 198 | /* |
| 199 | * Mocklisp hash function. |
| 200 | */ |
| 201 | while (*kp) |
| 202 | res = (res << 5) - res + *kp++; |
| 203 | |
| 204 | ndp = bp + (res % ht->size); |
| 205 | while (*ndp) |
| 206 | { |
| 207 | kp = (*ndp)->key; |
| 208 | |
| 209 | if (kp[0] == key[0] && ft_strcmp(kp, key) == 0) |
| 210 | break; |
| 211 | |
| 212 | ndp--; |
| 213 | if (ndp < bp) |
| 214 | ndp = bp + (ht->size - 1); |
| 215 | } |
| 216 | return ndp; |
| 217 | } |
| 218 | |
| 219 | |
| 220 | static FT_Error |
| 221 | hash_rehash ( hashtable* ht, |
| 222 | FT_Memory memory ) |
| 223 | { |
| 224 | hashnode *obp = ht->table, *bp, *nbp; |
| 225 | int i, sz = ht->size; |
| 226 | FT_Error error; |
| 227 | |
| 228 | ht->size <<= 1; |
| 229 | ht->limit = ht->size / 3; |
| 230 | |
| 231 | if ( FT_NEW_ARRAY( ht->table , ht->size ) ) |
| 232 | return error; |
| 233 | |
| 234 | for (i = 0, bp = obp; i < sz; i++, bp++) |
| 235 | { |
| 236 | if (*bp) |
| 237 | { |
| 238 | nbp = hash_bucket((*bp)->key, ht); |
| 239 | *nbp = *bp; |
| 240 | } |
| 241 | } |
| 242 | FT_FREE(obp); |
| 243 | |
| 244 | return FT_Err_Ok; |
| 245 | } |
| 246 | |
| 247 | |
| 248 | static FT_Error |
| 249 | hash_init ( hashtable* ht, |
| 250 | FT_Memory memory ) |
| 251 | { |
| 252 | int sz = INITIAL_HT_SIZE; |
| 253 | FT_Error error; |
| 254 | |
| 255 | ht->size = sz; |
| 256 | ht->limit = sz / 3; |
| 257 | ht->used = 0; |
| 258 | |
| 259 | if ( FT_NEW_ARRAY( ht->table, size ) ) |
| 260 | return error; |
| 261 | |
| 262 | return FT_Err_Ok; |
| 263 | } |
| 264 | |
| 265 | |
| 266 | static void |
| 267 | hash_free( hashtable* ht, |
| 268 | FT_Memory memory ) |
| 269 | { |
| 270 | /* FT_Error error; */ |
| 271 | |
| 272 | if ( ht != 0 ) |
| 273 | { |
| 274 | int i, sz = ht->size; |
| 275 | hashnode* bp = ht->table; |
| 276 | |
| 277 | for (i = 0; i < sz; i++, bp++) |
| 278 | { |
| 279 | if (*bp) |
| 280 | FT_FREE(*bp); |
| 281 | } |
| 282 | if (sz > 0) |
| 283 | FT_FREE(ht->table); |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | |
| 288 | static FT_Error |
| 289 | hash_insert ( char* key, |
| 290 | void* data, |
| 291 | hashtable* ht, |
| 292 | FT_Memory memory ) |
| 293 | { |
| 294 | FT_Error error = FT_Err_Ok; |
| 295 | hashnode nn, *bp = hash_bucket(key, ht); |
| 296 | |
| 297 | nn = *bp; |
| 298 | if (!nn) |
| 299 | { |
| 300 | if ( FT_NEW( nn ) ) |
| 301 | return error; |
| 302 | |
| 303 | *bp = nn; |
| 304 | nn->key = key; |
| 305 | nn->data = data; |
| 306 | |
| 307 | if (ht->used >= ht->limit) |
| 308 | error = hash_rehash(ht, memory); |
| 309 | |
| 310 | ht->used++; |
| 311 | } |
| 312 | else |
| 313 | nn->data = data; |
| 314 | |
| 315 | return error; |
| 316 | } |
| 317 | |
| 318 | |
| 319 | static hashnode |
| 320 | hash_lookup(char *key, hashtable *ht) |
| 321 | { |
| 322 | hashnode *np = hash_bucket(key, ht); |
| 323 | return *np; |
| 324 | } |
| 325 | |
| 326 | #ifdef 0 |
| 327 | static void |
| 328 | hash_delete(char *name, hashtable *ht , FT_Memory memory) |
| 329 | { |
| 330 | hashnode *hp; |
| 331 | /* FT_Error error; */ |
| 332 | |
| 333 | hp = hash_bucket(name, ht); |
| 334 | FT_FREE( *hp ); |
| 335 | } |
| 336 | #endif |
| 337 | |
| 338 | /* |
| 339 | * The builtin property table. |
| 340 | */ |
| 341 | /*static hashtable proptbl; */ /* XXX eliminate this */ |
| 342 | |
| 343 | |
| 344 | |
| 345 | /************************************************************************** |
| 346 | * |
| 347 | * Utility types and functions. |
| 348 | * |
| 349 | **************************************************************************/ |
| 350 | |
| 351 | /* |
| 352 | * Function type for parsing lines of a BDF font. |
| 353 | */ |
| 354 | typedef int (*_bdf_line_func_t)( char* line, |
| 355 | unsigned long linelen, |
| 356 | unsigned long lineno, |
| 357 | void* call_data, |
| 358 | void* client_data ); |
| 359 | |
| 360 | /* |
| 361 | * List structure for splitting lines into fields. |
| 362 | */ |
| 363 | typedef struct |
| 364 | { |
| 365 | char** field; |
| 366 | unsigned long size; |
| 367 | unsigned long used; |
| 368 | char* bfield; |
| 369 | unsigned long bsize; |
| 370 | unsigned long bused; |
| 371 | |
| 372 | } _bdf_list_t; |
| 373 | |
| 374 | |
| 375 | /* |
| 376 | * Structure used while loading BDF fonts. |
| 377 | */ |
| 378 | typedef struct |
| 379 | { |
| 380 | unsigned long flags; |
| 381 | unsigned long cnt; |
| 382 | unsigned long row; |
| 383 | unsigned long bpr; |
| 384 | short minlb; |
| 385 | short maxlb; |
| 386 | short maxrb; |
| 387 | short maxas; |
| 388 | short maxds; |
| 389 | short rbearing; |
| 390 | char* glyph_name; |
| 391 | long glyph_enc; |
| 392 | bdf_font_t* font; |
| 393 | bdf_options_t* opts; |
| 394 | void* client_data; |
| 395 | bdf_callback_t callback; |
| 396 | bdf_callback_struct_t cb; |
| 397 | unsigned long have[2048]; |
| 398 | _bdf_list_t list; |
| 399 | |
| 400 | FT_Memory memory; |
| 401 | |
| 402 | } _bdf_parse_t; |
| 403 | |
| 404 | #define setsbit(m, cc) (m[(cc) >> 3] |= (1 << ((cc) & 7))) |
| 405 | #define sbitset(m, cc) (m[(cc) >> 3] & (1 << ((cc) & 7))) |
| 406 | |
| 407 | /* |
| 408 | * An empty string for empty fields. |
| 409 | */ |
| 410 | static const char empty[1] = { 0 }; /* XXX eliminate this */ |
| 411 | |
| 412 | /* |
| 413 | * Assume the line is NULL terminated and that the `list' parameter was |
| 414 | * initialized the first time it was used. |
| 415 | */ |
| 416 | static FT_Error |
| 417 | _bdf_split ( char* separators, |
| 418 | char* line, |
| 419 | unsigned long linelen, |
| 420 | _bdf_list_t* list, |
| 421 | FT_Memory memory ) |
| 422 | { |
| 423 | int mult, final_empty; |
| 424 | char *sp, *ep, *end; |
| 425 | unsigned char seps[32]; |
| 426 | FT_Error error; |
| 427 | |
| 428 | /* |
| 429 | * Initialize the list. |
| 430 | */ |
| 431 | list->used = list->bused = 0; |
| 432 | |
| 433 | /* |
| 434 | * If the line is empty, then simply return. |
| 435 | */ |
| 436 | if ( linelen == 0 || line[0] == 0 ) |
| 437 | return FT_Err_Ok; |
| 438 | |
| 439 | /* |
| 440 | * If the `separators' parameter is NULL or empty, split the list into |
| 441 | * individual bytes. |
| 442 | */ |
| 443 | if ( separators == 0 || *separators == 0 ) |
| 444 | { |
| 445 | if ( linelen > list->bsize ) |
| 446 | { |
| 447 | if ( list->bsize ) |
| 448 | { |
| 449 | if ( FT_ALLOC ( list->bfield , linelen) ) |
| 450 | return error; |
| 451 | } |
| 452 | else |
| 453 | { |
| 454 | if ( FT_REALLOC ( list->bfield , list->bsize, linelen) ) |
| 455 | return error; |
| 456 | } |
| 457 | list->bsize = linelen; |
| 458 | } |
| 459 | list->bused = linelen; |
| 460 | |
| 461 | FT_MEM_COPY (list->bfield, line, linelen); |
| 462 | return FT_Err_Ok; |
| 463 | } |
| 464 | |
| 465 | /* |
| 466 | * Prepare the separator bitmap. |
| 467 | */ |
| 468 | FT_MEM_ZERO( seps, 32 ); |
| 469 | |
| 470 | /* |
| 471 | * If the very last character of the separator string is a plus, then set |
| 472 | * the `mult' flag to indicate that multiple separators should be |
| 473 | * collapsed into one. |
| 474 | */ |
| 475 | for ( mult = 0, sp = separators; sp && *sp; sp++ ) |
| 476 | { |
| 477 | if ( sp[0] == '+' && sp[1] == 0) |
| 478 | mult = 1; |
| 479 | else |
| 480 | setsbit( seps, sp[0] ); |
| 481 | } |
| 482 | |
| 483 | /* |
| 484 | * Break the line up into fields. |
| 485 | */ |
| 486 | final_empty = 0; |
| 487 | sp = ep = line; |
| 488 | end = sp + linelen; |
| 489 | for ( ; sp < end && *sp;) |
| 490 | { |
| 491 | /* |
| 492 | * Collect everything that is not a separator. |
| 493 | */ |
| 494 | for ( ; *ep && !sbitset( seps, *ep ); ep++ ) ; |
| 495 | |
| 496 | /* |
| 497 | * Resize the list if necessary. |
| 498 | */ |
| 499 | if ( list->used == list->size ) |
| 500 | { |
| 501 | if ( list->size == 0 ) |
| 502 | { |
| 503 | if ( FT_NEW_ARRAY( list->field , 5) ) |
| 504 | return error; |
| 505 | } |
| 506 | else |
| 507 | { |
| 508 | if ( FT_RENEW_ARRAY( list->field , list->size, list->size+5 ) |
| 509 | return error; |
| 510 | } |
| 511 | list->size += 5; |
| 512 | } |
| 513 | |
| 514 | /* |
| 515 | * Assign the field appropriately. |
| 516 | */ |
| 517 | list->field[ list->used++ ] = (ep > sp) ? sp : empty; |
| 518 | |
| 519 | sp = ep; |
| 520 | if (mult) |
| 521 | { |
| 522 | /* |
| 523 | * If multiple separators should be collapsed, do it now by |
| 524 | * setting all the separator characters to 0. |
| 525 | */ |
| 526 | for ( ; *ep && sbitset(seps, *ep); ep++ ) |
| 527 | *ep = 0; |
| 528 | |
| 529 | } |
| 530 | else if (*ep != 0) |
| 531 | { |
| 532 | /* |
| 533 | * Don't collapse multiple separators by making them 0, so just |
| 534 | * make the one encountered 0. |
| 535 | */ |
| 536 | *ep++ = 0; |
| 537 | } |
| 538 | |
| 539 | final_empty = ( ep > sp && *ep == 0 ); |
| 540 | sp = ep; |
| 541 | } |
| 542 | |
| 543 | /* |
| 544 | * Finally, NULL terminate the list. |
| 545 | */ |
| 546 | if ( list->used + final_empty + 1 >= list->size ) |
| 547 | { |
| 548 | if ( list->used == list->size ) |
| 549 | { |
| 550 | if ( list->size == 0 ) |
| 551 | { |
| 552 | if ( FT_NEW_ARRAY( list->field, 5 ) ) |
| 553 | return error; |
| 554 | } |
| 555 | else |
| 556 | { |
| 557 | if ( FT_RENEW_ARRAY( list->field , list->size, list->size+5 ) ) |
| 558 | return error; |
| 559 | } |
| 560 | list->size += 5; |
| 561 | } |
| 562 | } |
| 563 | |
| 564 | if (final_empty) |
| 565 | list->field[ list->used++ ] = empty; |
| 566 | |
| 567 | if ( list->used == list->size ) |
| 568 | { |
| 569 | if ( list->size == 0 ) |
| 570 | { |
| 571 | if ( FT_NEW_ARRAY( list->field , 5 ) ) |
| 572 | return error; |
| 573 | } |
| 574 | else |
| 575 | { |
| 576 | if ( FT_NEW_ARRAY( list->field, list->size, list->size + 5 ) ) |
| 577 | return error; |
| 578 | } |
| 579 | list->size += 5; |
| 580 | } |
| 581 | list->field[ list->used ] = 0; |
| 582 | |
| 583 | return FT_Err_Ok; |
| 584 | } |
| 585 | |
| 586 | |
| 587 | static void |
| 588 | _bdf_shift( unsigned long n, |
| 589 | _bdf_list_t* list) |
| 590 | { |
| 591 | unsigned long i, u; |
| 592 | |
| 593 | if ( list == 0 || list->used == 0 || n == 0 ) |
| 594 | return; |
| 595 | |
| 596 | if ( n >= list->used ) |
| 597 | { |
| 598 | list->used = 0; |
| 599 | return; |
| 600 | } |
| 601 | for ( u = n, i = 0; u < list->used; i++, u++ ) |
| 602 | list->field[i] = list->field[u]; |
| 603 | |
| 604 | list->used -= n; |
| 605 | } |
| 606 | |
| 607 | |
| 608 | static char* |
| 609 | _bdf_join( int c, |
| 610 | unsigned long* len, |
| 611 | _bdf_list_t* list) |
| 612 | { |
| 613 | unsigned long i, j; |
| 614 | char *fp, *dp; |
| 615 | |
| 616 | if ( list == 0 || list->used == 0 ) |
| 617 | return 0; |
| 618 | |
| 619 | *len = 0; |
| 620 | |
| 621 | dp = list->field[0]; |
| 622 | |
| 623 | for ( i = j = 0; i < list->used; i++ ) |
| 624 | { |
| 625 | fp = list->field[i]; |
| 626 | while (*fp) |
| 627 | dp[j++] = *fp++; |
| 628 | |
| 629 | if (i + 1 < list->used) |
| 630 | dp[j++] = c; |
| 631 | } |
| 632 | dp[j] = 0; |
| 633 | |
| 634 | *len = j; |
| 635 | return dp; |
| 636 | } |
| 637 | |
| 638 | /* |
| 639 | * High speed file reader that passes each line to a callback. |
| 640 | */ |
| 641 | int ftreadstream( FT_Stream stream, |
| 642 | char* buffer, |
| 643 | int count ) |
| 644 | { |
| 645 | int read_bytes; |
| 646 | int pos = stream->pos; |
| 647 | |
| 648 | if ( pos >= stream->size ) |
| 649 | { |
| 650 | FT_ERROR(( "FT_Read_Stream_At:" )); |
| 651 | FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n", |
| 652 | pos, stream->size )); |
| 653 | return 0; |
| 654 | } |
| 655 | |
| 656 | if ( stream->read ) |
| 657 | read_bytes = stream->read( stream, pos, buffer, count ); |
| 658 | else |
| 659 | { |
| 660 | read_bytes = stream->size - pos; |
| 661 | if ( read_bytes > count ) |
| 662 | read_bytes = count; |
| 663 | |
| 664 | ft_memcpy( buffer, stream->base + pos, read_bytes ); |
| 665 | } |
| 666 | |
| 667 | stream->pos = pos + read_bytes; |
| 668 | |
| 669 | return read_bytes; |
| 670 | } |
| 671 | |
| 672 | static int |
| 673 | _bdf_readstream( FT_Stream stream, |
| 674 | _bdf_line_func_t callback, |
| 675 | void* client_data, |
| 676 | unsigned long* lno) |
| 677 | { |
| 678 | _bdf_line_func_t cb; |
| 679 | unsigned long lineno; |
| 680 | int n, res, done, refill, bytes, hold; |
| 681 | char *ls, *le, *pp, *pe, *hp; |
| 682 | char buf[65536]; |
| 683 | |
| 684 | if (callback == 0) |
| 685 | return -1; |
| 686 | |
| 687 | cb = callback; |
| 688 | lineno = 1; |
| 689 | buf[0] = 0; |
| 690 | res = done = 0; |
| 691 | pp = ls = le = buf; |
| 692 | bytes = 65536; |
| 693 | |
| 694 | while ( !done && (n = ftreadstream(stream, pp, bytes)) > 0 ) |
| 695 | { |
| 696 | /* |
| 697 | * Determine the new end of the buffer pages. |
| 698 | */ |
| 699 | pe = pp + n; |
| 700 | |
| 701 | for (refill = 0; done == 0 && refill == 0; ) |
| 702 | { |
| 703 | while (le < pe && *le != '\n' && *le != '\r') |
| 704 | le++; |
| 705 | |
| 706 | if (le == pe) |
| 707 | { |
| 708 | /* |
| 709 | * Hit the end of the last page in the buffer. Need to find |
| 710 | * out how many pages to shift and how many pages need to be |
| 711 | * read in. Adjust the line start and end pointers down to |
| 712 | * point to the right places in the pages. |
| 713 | */ |
| 714 | pp = buf + (((ls - buf) >> 13) << 13); |
| 715 | n = pp - buf; |
| 716 | ls -= n; |
| 717 | le -= n; |
| 718 | n = pe - pp; |
| 719 | (void) ft_memcpy(buf, pp, n); |
| 720 | pp = buf + n; |
| 721 | bytes = 65536 - n; |
| 722 | refill = 1; |
| 723 | } |
| 724 | else |
| 725 | { |
| 726 | /* |
| 727 | * Temporarily NULL terminate the line. |
| 728 | */ |
| 729 | hp = le; |
| 730 | hold = *le; |
| 731 | *le = 0; |
| 732 | |
| 733 | if (callback && *ls != '#' && *ls != 0x1a && le > ls && |
| 734 | (res = (*cb)(ls, le - ls, lineno, (void *) &cb, |
| 735 | client_data)) != 0) |
| 736 | done = 1; |
| 737 | else { |
| 738 | ls = ++le; |
| 739 | /* |
| 740 | * Handle the case of DOS crlf sequences. |
| 741 | */ |
| 742 | if (le < pe && hold == '\n' && *le =='\r') |
| 743 | ls = ++le; |
| 744 | } |
| 745 | |
| 746 | /* |
| 747 | * Increment the line number. |
| 748 | */ |
| 749 | lineno++; |
| 750 | |
| 751 | /* |
| 752 | * Restore the character at the end of the line. |
| 753 | */ |
| 754 | *hp = hold; |
| 755 | } |
| 756 | } |
| 757 | } |
| 758 | *lno = lineno; |
| 759 | return res; |
| 760 | } |
| 761 | |
| 762 | |
| 763 | FT_LOCAL_DEF( void ) |
| 764 | _bdf_memmove(char *dest, char *src, unsigned long bytes) |
| 765 | { |
| 766 | long i, j; |
| 767 | |
| 768 | i = (long) bytes; |
| 769 | j = i & 7; |
| 770 | i = (i + 7) >> 3; |
| 771 | |
| 772 | /* |
| 773 | * Do a memmove using Ye Olde Duff's Device for efficiency. |
| 774 | */ |
| 775 | if (src < dest) { |
| 776 | src += bytes; |
| 777 | dest += bytes; |
| 778 | |
| 779 | switch (j) { |
| 780 | case 0: do { |
| 781 | *--dest = *--src; |
| 782 | case 7: *--dest = *--src; |
| 783 | case 6: *--dest = *--src; |
| 784 | case 5: *--dest = *--src; |
| 785 | case 4: *--dest = *--src; |
| 786 | case 3: *--dest = *--src; |
| 787 | case 2: *--dest = *--src; |
| 788 | case 1: *--dest = *--src; |
| 789 | } while (--i > 0); |
| 790 | } |
| 791 | } else if (src > dest) { |
| 792 | switch (j) { |
| 793 | case 0: do { |
| 794 | *dest++ = *src++; |
| 795 | case 7: *dest++ = *src++; |
| 796 | case 6: *dest++ = *src++; |
| 797 | case 5: *dest++ = *src++; |
| 798 | case 4: *dest++ = *src++; |
| 799 | case 3: *dest++ = *src++; |
| 800 | case 2: *dest++ = *src++; |
| 801 | case 1: *dest++ = *src++; |
| 802 | } while (--i > 0); |
| 803 | } |
| 804 | } |
| 805 | } |
| 806 | |
| 807 | static const unsigned char a2i[128] = { |
| 808 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 809 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 810 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 811 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 812 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00, |
| 813 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, |
| 814 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 815 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 816 | 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 817 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 818 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
| 819 | }; |
| 820 | |
| 821 | static const unsigned char odigits[32] = { |
| 822 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, |
| 823 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 824 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 825 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 826 | }; |
| 827 | |
| 828 | static const unsigned char ddigits[32] = { |
| 829 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, |
| 830 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 831 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 832 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 833 | }; |
| 834 | |
| 835 | static const unsigned char hdigits[32] = { |
| 836 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, |
| 837 | 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, |
| 838 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 839 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 840 | }; |
| 841 | |
| 842 | #define isdigok(m, d) (m[(d) >> 3] & (1 << ((d) & 7))) |
| 843 | |
| 844 | /* |
| 845 | * Routine to convert an ASCII string into an unsigned long integer. |
| 846 | */ |
| 847 | static unsigned long |
| 848 | _bdf_atoul(char *s, char **end, int base) |
| 849 | { |
| 850 | unsigned long v; |
| 851 | unsigned char *dmap; |
| 852 | |
| 853 | if (s == 0 || *s == 0) |
| 854 | return 0; |
| 855 | |
| 856 | /* |
| 857 | * Make sure the radix is something recognizable. Default to 10. |
| 858 | */ |
| 859 | switch (base) |
| 860 | { |
| 861 | case 8: dmap = odigits; break; |
| 862 | case 16: dmap = hdigits; break; |
| 863 | default: base = 10; dmap = ddigits; break; |
| 864 | } |
| 865 | |
| 866 | /* |
| 867 | * Check for the special hex prefix. |
| 868 | */ |
| 869 | if ( s[0] == '0' && ( s[1] == 'x' || s[1] == 'X')) |
| 870 | { |
| 871 | base = 16; |
| 872 | dmap = hdigits; |
| 873 | s += 2; |
| 874 | } |
| 875 | |
| 876 | for ( v = 0; isdigok(dmap, *s); s++ ) |
| 877 | v = (v * base) + a2i[(int) *s]; |
| 878 | |
| 879 | if (end != 0) |
| 880 | *end = s; |
| 881 | |
| 882 | return v; |
| 883 | } |
| 884 | |
| 885 | |
| 886 | /* |
| 887 | * Routine to convert an ASCII string into an signed long integer. |
| 888 | */ |
| 889 | static long |
| 890 | _bdf_atol(char *s, char **end, int base) |
| 891 | { |
| 892 | long v, neg; |
| 893 | unsigned char *dmap; |
| 894 | |
| 895 | if (s == 0 || *s == 0) |
| 896 | return 0; |
| 897 | |
| 898 | /* |
| 899 | * Make sure the radix is something recognizable. Default to 10. |
| 900 | */ |
| 901 | switch (base) { |
| 902 | case 8: dmap = odigits; break; |
| 903 | case 16: dmap = hdigits; break; |
| 904 | default: base = 10; dmap = ddigits; break; |
| 905 | } |
| 906 | |
| 907 | /* |
| 908 | * Check for a minus sign. |
| 909 | */ |
| 910 | neg = 0; |
| 911 | if (*s == '-') { |
| 912 | s++; |
| 913 | neg = 1; |
| 914 | } |
| 915 | |
| 916 | /* |
| 917 | * Check for the special hex prefix. |
| 918 | */ |
| 919 | if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) { |
| 920 | base = 16; |
| 921 | dmap = hdigits; |
| 922 | s += 2; |
| 923 | } |
| 924 | |
| 925 | for (v = 0; isdigok(dmap, *s); s++) |
| 926 | v = (v * base) + a2i[(int) *s]; |
| 927 | |
| 928 | if (end != 0) |
| 929 | *end = s; |
| 930 | |
| 931 | return (!neg) ? v : -v; |
| 932 | } |
| 933 | |
| 934 | |
| 935 | /* |
| 936 | * Routine to convert an ASCII string into an signed short integer. |
| 937 | */ |
| 938 | static short |
| 939 | _bdf_atos(char *s, char **end, int base) |
| 940 | { |
| 941 | short v, neg; |
| 942 | unsigned char *dmap; |
| 943 | |
| 944 | if (s == 0 || *s == 0) |
| 945 | return 0; |
| 946 | |
| 947 | /* |
| 948 | * Make sure the radix is something recognizable. Default to 10. |
| 949 | */ |
| 950 | switch (base) { |
| 951 | case 8: dmap = odigits; break; |
| 952 | case 16: dmap = hdigits; break; |
| 953 | default: base = 10; dmap = ddigits; break; |
| 954 | } |
| 955 | |
| 956 | /* |
| 957 | * Check for a minus. |
| 958 | */ |
| 959 | neg = 0; |
| 960 | if (*s == '-') { |
| 961 | s++; |
| 962 | neg = 1; |
| 963 | } |
| 964 | |
| 965 | /* |
| 966 | * Check for the special hex prefix. |
| 967 | */ |
| 968 | if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) { |
| 969 | base = 16; |
| 970 | dmap = hdigits; |
| 971 | s += 2; |
| 972 | } |
| 973 | |
| 974 | for (v = 0; isdigok(dmap, *s); s++) |
| 975 | v = (v * base) + a2i[(int) *s]; |
| 976 | |
| 977 | if (end != 0) |
| 978 | *end = s; |
| 979 | |
| 980 | return (!neg) ? v : -v; |
| 981 | } |
| 982 | |
| 983 | /* |
| 984 | * Routine to compare two glyphs by encoding so they can be sorted. |
| 985 | */ |
| 986 | static int |
| 987 | by_encoding(const void *a, const void *b) |
| 988 | { |
| 989 | bdf_glyph_t *c1, *c2; |
| 990 | |
| 991 | c1 = (bdf_glyph_t *) a; |
| 992 | c2 = (bdf_glyph_t *) b; |
| 993 | if (c1->encoding < c2->encoding) |
| 994 | return -1; |
| 995 | else if (c1->encoding > c2->encoding) |
| 996 | return 1; |
| 997 | return 0; |
| 998 | } |
| 999 | |
| 1000 | |
| 1001 | |
| 1002 | static FT_Error |
| 1003 | bdf_create_property( char* name, |
| 1004 | int format, |
| 1005 | bdf_font_t* font ) |
| 1006 | { |
| 1007 | unsigned long n; |
| 1008 | bdf_property_t* p; |
| 1009 | FT_Memory memory = font->memory; |
| 1010 | FT_Error error; |
| 1011 | |
| 1012 | /* |
| 1013 | * First check to see if the property has |
| 1014 | * already been added or not. If it has, then |
| 1015 | * simply ignore it. |
| 1016 | */ |
| 1017 | if ( hash_lookup( name, &(font->proptbl)) ) |
| 1018 | return FT_Err_Ok; |
| 1019 | |
| 1020 | if (font->nuser_props == 0) |
| 1021 | { |
| 1022 | if ( FT_NEW( font->user_props ) ) |
| 1023 | return error; |
| 1024 | } |
| 1025 | else |
| 1026 | { |
| 1027 | if ( FT_RENEW_ARRAY( font->user_props, font->nuser_props, |
| 1028 | (font->nuser_props + 1) ) ) |
| 1029 | return error; |
| 1030 | } |
| 1031 | |
| 1032 | p = font->user_props + font->nuser_props; |
| 1033 | |
| 1034 | FT_ZERO( p ); |
| 1035 | |
| 1036 | n = (unsigned long) (ft_strlen(name) + 1); |
| 1037 | |
| 1038 | if ( FT_ALLOC ( p->name , n) ) |
| 1039 | return error; |
| 1040 | |
| 1041 | FT_MEM_COPY(p->name, name, n); |
| 1042 | p->format = format; |
| 1043 | p->builtin = 0; |
| 1044 | |
| 1045 | n = _num_bdf_properties + font->nuser_props; |
| 1046 | |
| 1047 | error = hash_insert(p->name, (void *) n, &(font->proptbl) , memory); |
| 1048 | if (error) return error; |
| 1049 | |
| 1050 | font->nuser_props++; |
| 1051 | return FT_Err_Ok; |
| 1052 | } |
| 1053 | |
| 1054 | |
| 1055 | FT_LOCAL_DEF( bdf_property_t* ) |
| 1056 | bdf_get_property(char *name, bdf_font_t *font) |
| 1057 | { |
| 1058 | hashnode hn; |
| 1059 | unsigned long propid; |
| 1060 | |
| 1061 | if (name == 0 || *name == 0) |
| 1062 | return 0; |
| 1063 | |
| 1064 | if ((hn = hash_lookup(name, &(font->proptbl))) == 0) |
| 1065 | return 0; |
| 1066 | |
| 1067 | propid = (unsigned long) hn->data; |
| 1068 | if (propid >= _num_bdf_properties) |
| 1069 | return font->user_props + (propid - _num_bdf_properties); |
| 1070 | |
| 1071 | return _bdf_properties + propid; |
| 1072 | } |
| 1073 | |
| 1074 | |
| 1075 | /************************************************************************** |
| 1076 | * |
| 1077 | * BDF font file parsing flags and functions. |
| 1078 | * |
| 1079 | **************************************************************************/ |
| 1080 | |
| 1081 | /* |
| 1082 | * Parse flags. |
| 1083 | */ |
| 1084 | #define _BDF_START 0x0001 |
| 1085 | #define _BDF_FONT_NAME 0x0002 |
| 1086 | #define _BDF_SIZE 0x0004 |
| 1087 | #define _BDF_FONT_BBX 0x0008 |
| 1088 | #define _BDF_PROPS 0x0010 |
| 1089 | #define _BDF_GLYPHS 0x0020 |
| 1090 | #define _BDF_GLYPH 0x0040 |
| 1091 | #define _BDF_ENCODING 0x0080 |
| 1092 | #define _BDF_SWIDTH 0x0100 |
| 1093 | #define _BDF_DWIDTH 0x0200 |
| 1094 | #define _BDF_BBX 0x0400 |
| 1095 | #define _BDF_BITMAP 0x0800 |
| 1096 | |
| 1097 | #define _BDF_SWIDTH_ADJ 0x1000 |
| 1098 | |
| 1099 | #define _BDF_GLYPH_BITS (_BDF_GLYPH|_BDF_ENCODING|_BDF_SWIDTH|\ |
| 1100 | _BDF_DWIDTH|_BDF_BBX|_BDF_BITMAP) |
| 1101 | |
| 1102 | #define _BDF_GLYPH_WIDTH_CHECK 0x40000000 |
| 1103 | #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000 |
| 1104 | |
| 1105 | /* |
| 1106 | * Auto correction messages. |
| 1107 | */ |
| 1108 | #define ACMSG1 "FONT_ASCENT property missing. Added \"FONT_ASCENT %hd\"." |
| 1109 | #define ACMSG2 "FONT_DESCENT property missing. Added \"FONT_DESCENT %hd\"." |
| 1110 | #define ACMSG3 "Font width != actual width. Old: %hd New: %hd." |
| 1111 | #define ACMSG4 "Font left bearing != actual left bearing. Old: %hd New: %hd." |
| 1112 | #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd." |
| 1113 | #define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd." |
| 1114 | #define ACMSG7 "Font height != actual height. Old: %hd New: %hd." |
| 1115 | #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made." |
| 1116 | #define ACMSG9 "SWIDTH field missing at line %ld. Set automatically." |
| 1117 | #define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width." |
| 1118 | #define ACMSG11 "SIZE bits per pixel field adjusted to %hd." |
| 1119 | #define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded." |
| 1120 | #define ACMSG13 "Glyph %ld extra rows removed." |
| 1121 | #define ACMSG14 "Glyph %ld extra columns removed." |
| 1122 | #define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found." |
| 1123 | |
| 1124 | /* |
| 1125 | * Error messages. |
| 1126 | */ |
| 1127 | #define ERRMSG1 "[line %ld] Missing \"%s\" line." |
| 1128 | #define ERRMSG2 "[line %ld] Font header corrupted or missing fields." |
| 1129 | #define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields." |
| 1130 | |
| 1131 | static FT_Error |
| 1132 | _bdf_add_acmsg ( bdf_font_t* font, |
| 1133 | char* msg, |
| 1134 | unsigned long len ) |
| 1135 | { |
| 1136 | char* cp; |
| 1137 | FT_Memory memory = font->memory; |
| 1138 | FT_Error error; |
| 1139 | |
| 1140 | if ( font->acmsgs_len == 0 ) |
| 1141 | { |
| 1142 | if ( FT_ALLOC ( font->acmsgs , len + 1 ) ) |
| 1143 | return error; |
| 1144 | } |
| 1145 | else |
| 1146 | { |
| 1147 | if ( FT_REALLOC ( font->acmsgs , font->acmsgs_len , |
| 1148 | font->acmsgs_len + len + 1 ) ) |
| 1149 | return error; |
| 1150 | } |
| 1151 | |
| 1152 | cp = font->acmsgs + font->acmsgs_len; |
| 1153 | FT_MEM_COPY(cp, msg, len); |
| 1154 | cp += len; |
| 1155 | *cp++ = '\n'; |
| 1156 | font->acmsgs_len += len + 1; |
| 1157 | |
| 1158 | return FT_Err_Ok; |
| 1159 | } |
| 1160 | |
| 1161 | |
| 1162 | static FT_Error |
| 1163 | _bdf_add_comment ( bdf_font_t* font, |
| 1164 | char* comment, |
| 1165 | unsigned long len ) |
| 1166 | { |
| 1167 | char *cp; |
| 1168 | FT_Memory memory = font->memory; |
| 1169 | FT_Error error; |
| 1170 | |
| 1171 | if (font->comments_len == 0) { |
| 1172 | if ( FT_ALLOC ( font->comments , len + 1 ) ) |
| 1173 | return error; |
| 1174 | } |
| 1175 | else |
| 1176 | { |
| 1177 | if ( FT_REALLOC ( font->comments , font->comments_len, |
| 1178 | font->comments_len + len + 1) ) |
| 1179 | return error; |
| 1180 | } |
| 1181 | |
| 1182 | cp = font->comments + font->comments_len; |
| 1183 | FT_MEM_COPY(cp, comment, len); |
| 1184 | cp += len; |
| 1185 | *cp++ = '\n'; |
| 1186 | font->comments_len += len + 1; |
| 1187 | |
| 1188 | return FT_Err_Ok; |
| 1189 | } |
| 1190 | |
| 1191 | /* |
| 1192 | * Set the spacing from the font name if it exists, or set it to the default |
| 1193 | * specified in the options. |
| 1194 | */ |
| 1195 | static void |
| 1196 | _bdf_set_default_spacing( bdf_font_t* font, |
| 1197 | bdf_options_t* opts) |
| 1198 | { |
| 1199 | unsigned long len; |
| 1200 | char name[128]; |
| 1201 | _bdf_list_t list; |
| 1202 | FT_Memory memory; |
| 1203 | /* FT_Error error; */ |
| 1204 | |
| 1205 | if ( font == 0 || font->name == 0 || font->name[0] == 0 ) |
| 1206 | return; |
| 1207 | |
| 1208 | memory = font->memory; |
| 1209 | |
| 1210 | font->spacing = opts->font_spacing; |
| 1211 | |
| 1212 | len = (unsigned long) ( ft_strlen(font->name) + 1 ); |
| 1213 | (void) ft_memcpy(name, font->name, len); |
| 1214 | |
| 1215 | list.size = list.used = 0; |
| 1216 | _bdf_split("-", name, len, &list, memory); |
| 1217 | |
| 1218 | if (list.used == 15) { |
| 1219 | switch (list.field[11][0]) { |
| 1220 | case 'C': case 'c': font->spacing = BDF_CHARCELL; break; |
| 1221 | case 'M': case 'm': font->spacing = BDF_MONOWIDTH; break; |
| 1222 | case 'P': case 'p': font->spacing = BDF_PROPORTIONAL; break; |
| 1223 | } |
| 1224 | } |
| 1225 | if (list.size > 0) |
| 1226 | FT_FREE(list.field); |
| 1227 | } |
| 1228 | |
| 1229 | |
| 1230 | /* |
| 1231 | * Determine if the property is an atom or not. If it is, then clean it up so |
| 1232 | * the double quotes are removed if they exist. |
| 1233 | */ |
| 1234 | static int |
| 1235 | _bdf_is_atom( char* line, |
| 1236 | unsigned long linelen, |
| 1237 | char* *name, |
| 1238 | char* *value, |
| 1239 | bdf_font_t* font) |
| 1240 | { |
| 1241 | int hold; |
| 1242 | char *sp, *ep; |
| 1243 | bdf_property_t *p; |
| 1244 | |
| 1245 | *name = sp = ep = line; |
| 1246 | while (*ep && *ep != ' ' && *ep != '\t') |
| 1247 | ep++; |
| 1248 | |
| 1249 | hold = -1; |
| 1250 | if (*ep) |
| 1251 | { |
| 1252 | hold = *ep; |
| 1253 | *ep = 0; |
| 1254 | } |
| 1255 | |
| 1256 | p = bdf_get_property(sp, font); |
| 1257 | |
| 1258 | /* |
| 1259 | * Restore the character that was saved before any return can happen. |
| 1260 | */ |
| 1261 | if (hold != -1) |
| 1262 | *ep = hold; |
| 1263 | |
| 1264 | /* |
| 1265 | * If the propert exists and is not an atom, just return here. |
| 1266 | */ |
| 1267 | if (p && p->format != BDF_ATOM) |
| 1268 | return 0; |
| 1269 | |
| 1270 | /* |
| 1271 | * The property is an atom. Trim all leading and trailing whitespace and |
| 1272 | * double quotes for the atom value. |
| 1273 | */ |
| 1274 | sp = ep; |
| 1275 | ep = line + linelen; |
| 1276 | |
| 1277 | /* |
| 1278 | * Trim the leading whitespace if it exists. |
| 1279 | */ |
| 1280 | *sp++ = 0; |
| 1281 | while (*sp && (*sp == ' ' || *sp == '\t')) |
| 1282 | sp++; |
| 1283 | |
| 1284 | /* |
| 1285 | * Trim the leading double quote if it exists. |
| 1286 | */ |
| 1287 | if (*sp == '"') |
| 1288 | sp++; |
| 1289 | *value = sp; |
| 1290 | |
| 1291 | /* |
| 1292 | * Trim the trailing whitespace if it exists. |
| 1293 | */ |
| 1294 | while (ep > sp && (*(ep - 1) == ' ' || *(ep - 1) == '\t')) |
| 1295 | *--ep = 0; |
| 1296 | |
| 1297 | /* |
| 1298 | * Trim the trailing double quote if it exists. |
| 1299 | */ |
| 1300 | if (ep > sp && *(ep - 1) == '"') |
| 1301 | *--ep = 0; |
| 1302 | |
| 1303 | return 1; |
| 1304 | } |
| 1305 | |
| 1306 | |
| 1307 | static FT_Error |
| 1308 | _bdf_add_property ( bdf_font_t* font, |
| 1309 | char* name, |
| 1310 | char* value) |
| 1311 | { |
| 1312 | unsigned long propid; |
| 1313 | hashnode hn; |
| 1314 | int len; |
| 1315 | bdf_property_t *prop, *fp; |
| 1316 | FT_Memory memory = font->memory; |
| 1317 | FT_Error error; |
| 1318 | /* hashtable proptbl = font->proptbl; |
| 1319 | bdf_property_t *user_props = font->user_props; |
| 1320 | unsigned long nuser_props = font->nuser_props; |
| 1321 | */ |
| 1322 | |
| 1323 | /* |
| 1324 | * First, check to see if the property already exists in the font. |
| 1325 | */ |
| 1326 | if ((hn = hash_lookup(name, (hashtable *) font->internal)) != 0) { |
| 1327 | /* |
| 1328 | * The property already exists in the font, so simply replace |
| 1329 | * the value of the property with the current value. |
| 1330 | */ |
| 1331 | fp = font->props + (unsigned long) hn->data; |
| 1332 | |
| 1333 | switch (prop->format) |
| 1334 | { |
| 1335 | case BDF_ATOM: |
| 1336 | { |
| 1337 | /* |
| 1338 | * Delete the current atom if it exists. |
| 1339 | */ |
| 1340 | FT_FREE ( fp->value.atom ); |
| 1341 | |
| 1342 | if (value == 0) |
| 1343 | len = 1; |
| 1344 | else |
| 1345 | len = ft_strlen(value) + 1; |
| 1346 | if (len > 1) |
| 1347 | { |
| 1348 | if ( FT_ALLOC ( fp->value.atom , len ) ) |
| 1349 | return error; |
| 1350 | |
| 1351 | FT_MEM_COPY(fp->value.atom, value, len); |
| 1352 | } |
| 1353 | else |
| 1354 | fp->value.atom = 0; |
| 1355 | } |
| 1356 | break; |
| 1357 | |
| 1358 | case BDF_INTEGER: |
| 1359 | fp->value.int32 = _bdf_atol(value, 0, 10); |
| 1360 | break; |
| 1361 | |
| 1362 | case BDF_CARDINAL: |
| 1363 | fp->value.card32 = _bdf_atoul(value, 0, 10); |
| 1364 | break; |
| 1365 | |
| 1366 | default: |
| 1367 | ; |
| 1368 | } |
| 1369 | return FT_Err_Ok; |
| 1370 | } |
| 1371 | |
| 1372 | /* |
| 1373 | * See if this property type exists yet or not. If not, create it. |
| 1374 | */ |
| 1375 | hn = hash_lookup(name, &(font->proptbl)); |
| 1376 | if (hn == 0) { |
| 1377 | bdf_create_property(name, BDF_ATOM, font); |
| 1378 | hn = hash_lookup(name, &(font->proptbl)); |
| 1379 | } |
| 1380 | |
| 1381 | /* |
| 1382 | * Allocate another property if this is overflow. |
| 1383 | */ |
| 1384 | if (font->props_used == font->props_size) |
| 1385 | { |
| 1386 | if (font->props_size == 0) |
| 1387 | { |
| 1388 | if ( FT_NEW( font->props ) ) |
| 1389 | return error; |
| 1390 | } |
| 1391 | else |
| 1392 | { |
| 1393 | if ( FT_RENEW_ARRAY( font->props, font->props_size, |
| 1394 | (font->props_size + 1) ) ) |
| 1395 | return error; |
| 1396 | } |
| 1397 | fp = font->props + font->props_size; |
| 1398 | FT_ZERO( fp ); |
| 1399 | font->props_size++; |
| 1400 | } |
| 1401 | |
| 1402 | propid = (unsigned long) hn->data; |
| 1403 | if (propid >= _num_bdf_properties) |
| 1404 | prop = font->user_props + (propid - _num_bdf_properties); |
| 1405 | else |
| 1406 | prop = _bdf_properties + propid; |
| 1407 | |
| 1408 | fp = font->props + font->props_used; |
| 1409 | |
| 1410 | fp->name = prop->name; |
| 1411 | fp->format = prop->format; |
| 1412 | fp->builtin = prop->builtin; |
| 1413 | |
| 1414 | switch (prop->format) |
| 1415 | { |
| 1416 | case BDF_ATOM: |
| 1417 | { |
| 1418 | fp->value.atom = NULL; |
| 1419 | |
| 1420 | if ( value && value[0] != 0 ) |
| 1421 | { |
| 1422 | len = ft_strlen(value) + 1; |
| 1423 | |
| 1424 | if ( FT_ALLOC ( fp->value.atom , len ) ) |
| 1425 | return error; |
| 1426 | |
| 1427 | FT_MEM_COPY (fp->value.atom, value, len); |
| 1428 | } |
| 1429 | } |
| 1430 | break; |
| 1431 | |
| 1432 | case BDF_INTEGER: |
| 1433 | fp->value.int32 = _bdf_atol(value, 0, 10); |
| 1434 | break; |
| 1435 | |
| 1436 | case BDF_CARDINAL: |
| 1437 | fp->value.card32 = _bdf_atoul(value, 0, 10); |
| 1438 | break; |
| 1439 | |
| 1440 | default: |
| 1441 | ; |
| 1442 | } |
| 1443 | |
| 1444 | /* |
| 1445 | * If the property happens to be a comment, then it doesn't need |
| 1446 | * to be added to the internal hash table. |
| 1447 | */ |
| 1448 | if ( ft_memcmp(name, "COMMENT", 7) != 0 ) |
| 1449 | /* |
| 1450 | * Add the property to the font property table. |
| 1451 | */ |
| 1452 | hash_insert( fp->name, (void *) font->props_used, |
| 1453 | (hashtable *) font->internal, memory); |
| 1454 | |
| 1455 | font->props_used++; |
| 1456 | |
| 1457 | /* |
| 1458 | * Some special cases need to be handled here. The DEFAULT_CHAR property |
| 1459 | * needs to be located if it exists in the property list, the FONT_ASCENT |
| 1460 | * and FONT_DESCENT need to be assigned if they are present, and the |
| 1461 | * SPACING property should override the default spacing. |
| 1462 | */ |
| 1463 | if ( ft_memcmp(name, "DEFAULT_CHAR", 12) == 0 ) |
| 1464 | font->default_glyph = fp->value.int32; |
| 1465 | |
| 1466 | else if ( ft_memcmp(name, "FONT_ASCENT", 11) == 0 ) |
| 1467 | font->font_ascent = fp->value.int32; |
| 1468 | |
| 1469 | else if ( ft_memcmp(name, "FONT_DESCENT", 12) == 0 ) |
| 1470 | font->font_descent = fp->value.int32; |
| 1471 | |
| 1472 | else if ( ft_memcmp(name, "SPACING", 7) == 0 ) |
| 1473 | { |
| 1474 | if (fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P') |
| 1475 | font->spacing = BDF_PROPORTIONAL; |
| 1476 | |
| 1477 | else if (fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M') |
| 1478 | font->spacing = BDF_MONOWIDTH; |
| 1479 | |
| 1480 | else if (fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C') |
| 1481 | font->spacing = BDF_CHARCELL; |
| 1482 | } |
| 1483 | |
| 1484 | return FT_Err_Ok; |
| 1485 | } |
| 1486 | |
| 1487 | /* |
| 1488 | * Actually parse the glyph info and bitmaps. |
| 1489 | */ |
| 1490 | static int |
| 1491 | _bdf_parse_glyphs( char* line, |
| 1492 | unsigned long linelen, |
| 1493 | unsigned long lineno, |
| 1494 | void* call_data, |
| 1495 | void* client_data) |
| 1496 | { |
| 1497 | int c; |
| 1498 | char *s; |
| 1499 | unsigned char *bp; |
| 1500 | unsigned long i, slen, nibbles; |
| 1501 | double ps, rx, dw, sw; |
| 1502 | _bdf_line_func_t *next; |
| 1503 | _bdf_parse_t *p; |
| 1504 | bdf_glyph_t *glyph; |
| 1505 | bdf_font_t *font; |
| 1506 | char nbuf[128]; |
| 1507 | FT_Memory memory; |
| 1508 | FT_Error error; |
| 1509 | |
| 1510 | next = (_bdf_line_func_t *) call_data; |
| 1511 | p = (_bdf_parse_t *) client_data; |
| 1512 | |
| 1513 | font = p->font; |
| 1514 | memory = font->memory; |
| 1515 | |
| 1516 | /* |
| 1517 | * Check for a comment. |
| 1518 | */ |
| 1519 | if (ft_memcmp(line, "COMMENT", 7) == 0) { |
| 1520 | linelen -= 7; |
| 1521 | s = line + 7; |
| 1522 | if (*s != 0) { |
| 1523 | s++; |
| 1524 | linelen--; |
| 1525 | } |
| 1526 | _bdf_add_comment(p->font, s, linelen); |
| 1527 | return 0; |
| 1528 | } |
| 1529 | |
| 1530 | /* |
| 1531 | * The very first thing expected is the number of glyphs. |
| 1532 | */ |
| 1533 | if (!(p->flags & _BDF_GLYPHS)) { |
| 1534 | if (ft_memcmp(line, "CHARS", 5) != 0) { |
| 1535 | sprintf(nbuf, ERRMSG1, lineno, "CHARS"); |
| 1536 | _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf)); |
| 1537 | return BDF_MISSING_CHARS; |
| 1538 | } |
| 1539 | _bdf_split(" +", line, linelen, &p->list, memory); |
| 1540 | p->cnt = font->glyphs_size = _bdf_atoul(p->list.field[1], 0, 10); |
| 1541 | |
| 1542 | /* |
| 1543 | * Make sure the number of glyphs is non-zero. |
| 1544 | */ |
| 1545 | if (p->cnt == 0) |
| 1546 | font->glyphs_size = 64; |
| 1547 | |
| 1548 | if ( FT_ALLOC ( font->glyphs , sizeof(bdf_glyph_t) * |
| 1549 | font->glyphs_size ) ) |
| 1550 | return FT_Err_Out_Of_Memory; |
| 1551 | |
| 1552 | /* |
| 1553 | * Set up the callback to indicate the glyph loading is about to |
| 1554 | * begin. |
| 1555 | */ |
| 1556 | if (p->callback != 0) { |
| 1557 | p->cb.reason = BDF_LOAD_START; |
| 1558 | p->cb.total = p->cnt; |
| 1559 | p->cb.current = 0; |
| 1560 | (*p->callback)(&p->cb, p->client_data); |
| 1561 | } |
| 1562 | p->flags |= _BDF_GLYPHS; |
| 1563 | return 0; |
| 1564 | } |
| 1565 | |
| 1566 | /* |
| 1567 | * Check for the ENDFONT field. |
| 1568 | */ |
| 1569 | if (ft_memcmp(line, "ENDFONT", 7) == 0) { |
| 1570 | /* |
| 1571 | * Sort the glyphs by encoding. |
| 1572 | */ |
| 1573 | qsort((char *) font->glyphs, font->glyphs_used, sizeof(bdf_glyph_t), |
| 1574 | by_encoding); |
| 1575 | |
| 1576 | p->flags &= ~_BDF_START; |
| 1577 | return 0; |
| 1578 | } |
| 1579 | |
| 1580 | /* |
| 1581 | * Check for the ENDCHAR field. |
| 1582 | */ |
| 1583 | if (ft_memcmp(line, "ENDCHAR", 7) == 0) { |
| 1584 | /* |
| 1585 | * Set up and call the callback if it was passed. |
| 1586 | */ |
| 1587 | if (p->callback != 0) { |
| 1588 | p->cb.reason = BDF_LOADING; |
| 1589 | p->cb.total = font->glyphs_size; |
| 1590 | p->cb.current = font->glyphs_used; |
| 1591 | (*p->callback)(&p->cb, p->client_data); |
| 1592 | } |
| 1593 | p->glyph_enc = 0; |
| 1594 | p->flags &= ~_BDF_GLYPH_BITS; |
| 1595 | return 0; |
| 1596 | } |
| 1597 | |
| 1598 | /* |
| 1599 | * Check to see if a glyph is being scanned but should be ignored |
| 1600 | * because it is an unencoded glyph. |
| 1601 | */ |
| 1602 | if ((p->flags & _BDF_GLYPH) && |
| 1603 | p->glyph_enc == -1 && p->opts->keep_unencoded == 0) |
| 1604 | return 0; |
| 1605 | |
| 1606 | /* |
| 1607 | * Check for the STARTCHAR field. |
| 1608 | */ |
| 1609 | if (ft_memcmp(line, "STARTCHAR", 9) == 0) { |
| 1610 | /* |
| 1611 | * Set the character name in the parse info first until the |
| 1612 | * encoding can be checked for an unencoded character. |
| 1613 | */ |
| 1614 | if (p->glyph_name != 0) |
| 1615 | FT_FREE(p->glyph_name); |
| 1616 | _bdf_split(" +", line, linelen, &p->list,memory); |
| 1617 | _bdf_shift(1, &p->list); |
| 1618 | s = _bdf_join(' ', &slen, &p->list); |
| 1619 | if ( FT_ALLOC ( p->glyph_name , (slen + 1) ) ) |
| 1620 | return BDF_OUT_OF_MEMORY; |
| 1621 | FT_MEM_COPY(p->glyph_name, s, slen + 1); |
| 1622 | p->flags |= _BDF_GLYPH; |
| 1623 | return 0; |
| 1624 | } |
| 1625 | |
| 1626 | /* |
| 1627 | * Check for the ENCODING field. |
| 1628 | */ |
| 1629 | if (ft_memcmp(line, "ENCODING", 8) == 0) { |
| 1630 | if (!(p->flags & _BDF_GLYPH)) { |
| 1631 | /* |
| 1632 | * Missing STARTCHAR field. |
| 1633 | */ |
| 1634 | sprintf(nbuf, ERRMSG1, lineno, "STARTCHAR"); |
| 1635 | _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf)); |
| 1636 | return BDF_MISSING_STARTCHAR; |
| 1637 | } |
| 1638 | _bdf_split(" +", line, linelen, &p->list, memory); |
| 1639 | p->glyph_enc = _bdf_atol(p->list.field[1], 0, 10); |
| 1640 | |
| 1641 | /* |
| 1642 | * Check to see if this encoding has already been encountered. If it |
| 1643 | * has then change it to unencoded so it gets added if indicated. |
| 1644 | */ |
| 1645 | if (p->glyph_enc >= 0) { |
| 1646 | if (_bdf_glyph_modified(p->have, p->glyph_enc)) { |
| 1647 | /* |
| 1648 | * Add a message saying a glyph has been moved to the |
| 1649 | * unencoded area. |
| 1650 | */ |
| 1651 | sprintf(nbuf, ACMSG12, p->glyph_enc, p->glyph_name); |
| 1652 | _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf)); |
| 1653 | p->glyph_enc = -1; |
| 1654 | font->modified = 1; |
| 1655 | } else |
| 1656 | _bdf_set_glyph_modified(p->have, p->glyph_enc); |
| 1657 | } |
| 1658 | |
| 1659 | if (p->glyph_enc >= 0) { |
| 1660 | /* |
| 1661 | * Make sure there are enough glyphs allocated in case the |
| 1662 | * number of characters happen to be wrong. |
| 1663 | */ |
| 1664 | if (font->glyphs_used == font->glyphs_size) { |
| 1665 | if ( FT_REALLOC ( font->glyphs, |
| 1666 | sizeof(bdf_glyph_t) * font->glyphs_size, |
| 1667 | sizeof(bdf_glyph_t) * (font->glyphs_size + 64) ) ) |
| 1668 | return BDF_OUT_OF_MEMORY; |
| 1669 | FT_MEM_SET ((char *) (font->glyphs + font->glyphs_size), |
| 1670 | 0, sizeof(bdf_glyph_t) << 6); /* FZ inutile */ |
| 1671 | font->glyphs_size += 64; |
| 1672 | } |
| 1673 | |
| 1674 | glyph = font->glyphs + font->glyphs_used++; |
| 1675 | glyph->name = p->glyph_name; |
| 1676 | glyph->encoding = p->glyph_enc; |
| 1677 | |
| 1678 | /* |
| 1679 | * Reset the initial glyph info. |
| 1680 | */ |
| 1681 | p->glyph_name = 0; |
| 1682 | } else { |
| 1683 | /* |
| 1684 | * Unencoded glyph. Check to see if it should be added or not. |
| 1685 | */ |
| 1686 | if (p->opts->keep_unencoded != 0) { |
| 1687 | /* |
| 1688 | * Allocate the next unencoded glyph. |
| 1689 | */ |
| 1690 | if (font->unencoded_used == font->unencoded_size) { |
| 1691 | if (font->unencoded_size == 0) { |
| 1692 | if ( FT_ALLOC ( font->unencoded , sizeof(bdf_glyph_t) << 2 ) ) |
| 1693 | return BDF_OUT_OF_MEMORY; |
| 1694 | } |
| 1695 | else { |
| 1696 | if ( FT_REALLOC ( font->unencoded , |
| 1697 | sizeof(bdf_glyph_t) * font->unencoded_size, |
| 1698 | sizeof(bdf_glyph_t) * |
| 1699 | (font->unencoded_size + 4) ) ) |
| 1700 | return BDF_OUT_OF_MEMORY; |
| 1701 | } |
| 1702 | font->unencoded_size += 4; |
| 1703 | } |
| 1704 | |
| 1705 | glyph = font->unencoded + font->unencoded_used; |
| 1706 | glyph->name = p->glyph_name; |
| 1707 | glyph->encoding = font->unencoded_used++; |
| 1708 | } else |
| 1709 | /* |
| 1710 | * Free up the glyph name if the unencoded shouldn't be |
| 1711 | * kept. |
| 1712 | */ |
| 1713 | FT_FREE( p->glyph_name ); |
| 1714 | |
| 1715 | p->glyph_name = 0; |
| 1716 | } |
| 1717 | |
| 1718 | /* |
| 1719 | * Clear the flags that might be added when width and height are |
| 1720 | * checked for consistency. |
| 1721 | */ |
| 1722 | p->flags &= ~(_BDF_GLYPH_WIDTH_CHECK|_BDF_GLYPH_HEIGHT_CHECK); |
| 1723 | |
| 1724 | p->flags |= _BDF_ENCODING; |
| 1725 | return 0; |
| 1726 | } |
| 1727 | |
| 1728 | /* |
| 1729 | * Point at the glyph being constructed. |
| 1730 | */ |
| 1731 | if (p->glyph_enc == -1) |
| 1732 | glyph = font->unencoded + (font->unencoded_used - 1); |
| 1733 | else |
| 1734 | glyph = font->glyphs + (font->glyphs_used - 1); |
| 1735 | |
| 1736 | /* |
| 1737 | * Check to see if a bitmap is being constructed. |
| 1738 | */ |
| 1739 | if (p->flags & _BDF_BITMAP) { |
| 1740 | /* |
| 1741 | * If there are more rows than are specified in the glyph metrics, |
| 1742 | * ignore the remaining lines. |
| 1743 | */ |
| 1744 | if (p->row >= glyph->bbx.height) { |
| 1745 | if (!(p->flags & _BDF_GLYPH_HEIGHT_CHECK)) { |
| 1746 | sprintf(nbuf, ACMSG13, glyph->encoding); |
| 1747 | _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf)); |
| 1748 | p->flags |= _BDF_GLYPH_HEIGHT_CHECK; |
| 1749 | font->modified = 1; |
| 1750 | } |
| 1751 | return 0; |
| 1752 | } |
| 1753 | |
| 1754 | /* |
| 1755 | * Only collect the number of nibbles indicated by the glyph metrics. |
| 1756 | * If there are more columns, they are simply ignored. |
| 1757 | */ |
| 1758 | nibbles = p->bpr << 1; |
| 1759 | bp = glyph->bitmap + (p->row * p->bpr); |
| 1760 | for (i = 0, *bp = 0; i < nibbles; i++) { |
| 1761 | c = line[i]; |
| 1762 | *bp = (*bp << 4) + a2i[c]; |
| 1763 | if (i + 1 < nibbles && (i & 1)) |
| 1764 | *++bp = 0; |
| 1765 | } |
| 1766 | |
| 1767 | /* |
| 1768 | * If any line has extra columns, indicate they have been removed. |
| 1769 | */ |
| 1770 | if ((line[nibbles] == '0' || a2i[(int) line[nibbles]] != 0) && |
| 1771 | !(p->flags & _BDF_GLYPH_WIDTH_CHECK)) { |
| 1772 | sprintf(nbuf, ACMSG14, glyph->encoding); |
| 1773 | _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf)); |
| 1774 | p->flags |= _BDF_GLYPH_WIDTH_CHECK; |
| 1775 | font->modified = 1; |
| 1776 | } |
| 1777 | |
| 1778 | p->row++; |
| 1779 | return 0; |
| 1780 | } |
| 1781 | |
| 1782 | /* |
| 1783 | * Expect the SWIDTH (scalable width) field next. |
| 1784 | */ |
| 1785 | if (ft_memcmp(line, "SWIDTH", 6) == 0) { |
| 1786 | if (!(p->flags & _BDF_ENCODING)) { |
| 1787 | /* |
| 1788 | * Missing ENCODING field. |
| 1789 | */ |
| 1790 | sprintf(nbuf, ERRMSG1, lineno, "ENCODING"); |
| 1791 | _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf)); |
| 1792 | return BDF_MISSING_ENCODING; |
| 1793 | } |
| 1794 | _bdf_split(" +", line, linelen, &p->list, memory); |
| 1795 | glyph->swidth = _bdf_atoul(p->list.field[1], 0, 10); |
| 1796 | p->flags |= _BDF_SWIDTH; |
| 1797 | return 0; |
| 1798 | } |
| 1799 | |
| 1800 | /* |
| 1801 | * Expect the DWIDTH (scalable width) field next. |
| 1802 | */ |
| 1803 | if (ft_memcmp(line, "DWIDTH", 6) == 0) { |
| 1804 | _bdf_split(" +", line, linelen, &p->list,memory); |
| 1805 | glyph->dwidth = _bdf_atoul(p->list.field[1], 0, 10); |
| 1806 | |
| 1807 | if (!(p->flags & _BDF_SWIDTH)) { |
| 1808 | /* |
| 1809 | * Missing SWIDTH field. Add an auto correction message and set |
| 1810 | * the scalable width from the device width. |
| 1811 | */ |
| 1812 | sprintf(nbuf, ACMSG9, lineno); |
| 1813 | _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf)); |
| 1814 | ps = (double) font->point_size; |
| 1815 | rx = (double) font->resolution_x; |
| 1816 | dw = (double) glyph->dwidth; |
| 1817 | glyph->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx)); |
| 1818 | } |
| 1819 | |
| 1820 | p->flags |= _BDF_DWIDTH; |
| 1821 | return 0; |
| 1822 | } |
| 1823 | |
| 1824 | /* |
| 1825 | * Expect the BBX field next. |
| 1826 | */ |
| 1827 | if (ft_memcmp(line, "BBX", 3) == 0) { |
| 1828 | _bdf_split(" +", line, linelen, &p->list, memory); |
| 1829 | glyph->bbx.width = _bdf_atos(p->list.field[1], 0, 10); |
| 1830 | glyph->bbx.height = _bdf_atos(p->list.field[2], 0, 10); |
| 1831 | glyph->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10); |
| 1832 | glyph->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10); |
| 1833 | |
| 1834 | /* |
| 1835 | * Generate the ascent and descent of the character. |
| 1836 | */ |
| 1837 | glyph->bbx.ascent = glyph->bbx.height + glyph->bbx.y_offset; |
| 1838 | glyph->bbx.descent = -glyph->bbx.y_offset; |
| 1839 | |
| 1840 | /* |
| 1841 | * Determine the overall font bounding box as the characters are |
| 1842 | * loaded so corrections can be done later if indicated. |
| 1843 | */ |
| 1844 | p->maxas = MAX(glyph->bbx.ascent, p->maxas); |
| 1845 | p->maxds = MAX(glyph->bbx.descent, p->maxds); |
| 1846 | p->rbearing = glyph->bbx.width + glyph->bbx.x_offset; |
| 1847 | p->maxrb = MAX(p->rbearing, p->maxrb); |
| 1848 | p->minlb = MIN(glyph->bbx.x_offset, p->minlb); |
| 1849 | p->maxlb = MAX(glyph->bbx.x_offset, p->maxlb); |
| 1850 | |
| 1851 | if (!(p->flags & _BDF_DWIDTH)) { |
| 1852 | /* |
| 1853 | * Missing DWIDTH field. Add an auto correction message and set |
| 1854 | * the device width to the glyph width. |
| 1855 | */ |
| 1856 | sprintf(nbuf, ACMSG10, lineno); |
| 1857 | _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf)); |
| 1858 | glyph->dwidth = glyph->bbx.width; |
| 1859 | } |
| 1860 | |
| 1861 | /* |
| 1862 | * If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH |
| 1863 | * value if necessary. |
| 1864 | */ |
| 1865 | if (p->opts->correct_metrics != 0) { |
| 1866 | /* |
| 1867 | * Determine the point size of the glyph. |
| 1868 | */ |
| 1869 | ps = (double) font->point_size; |
| 1870 | rx = (double) font->resolution_x; |
| 1871 | dw = (double) glyph->dwidth; |
| 1872 | sw = (unsigned short) ((dw * 72000.0) / (ps * rx)); |
| 1873 | |
| 1874 | if (sw != glyph->swidth) { |
| 1875 | glyph->swidth = sw; |
| 1876 | if (p->glyph_enc == -1) |
| 1877 | _bdf_set_glyph_modified(font->umod, |
| 1878 | font->unencoded_used - 1); |
| 1879 | else |
| 1880 | _bdf_set_glyph_modified(font->nmod, glyph->encoding); |
| 1881 | p->flags |= _BDF_SWIDTH_ADJ; |
| 1882 | font->modified = 1; |
| 1883 | } |
| 1884 | } |
| 1885 | p->flags |= _BDF_BBX; |
| 1886 | return 0; |
| 1887 | } |
| 1888 | |
| 1889 | /* |
| 1890 | * And finally, gather up the bitmap. |
| 1891 | */ |
| 1892 | if (ft_memcmp(line, "BITMAP", 6) == 0) { |
| 1893 | if (!(p->flags & _BDF_BBX)) { |
| 1894 | /* |
| 1895 | * Missing BBX field. |
| 1896 | */ |
| 1897 | sprintf(nbuf, ERRMSG1, lineno, "BBX"); |
| 1898 | _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf)); |
| 1899 | return BDF_MISSING_BBX; |
| 1900 | } |
| 1901 | /* |
| 1902 | * Allocate enough space for the bitmap. |
| 1903 | */ |
| 1904 | p->bpr = ((glyph->bbx.width * p->font->bpp) + 7) >> 3; |
| 1905 | glyph->bytes = p->bpr * glyph->bbx.height; |
| 1906 | if ( FT_ALLOC ( glyph->bitmap , glyph->bytes ) ) |
| 1907 | return BDF_OUT_OF_MEMORY; |
| 1908 | p->row = 0; |
| 1909 | p->flags |= _BDF_BITMAP; |
| 1910 | return 0; |
| 1911 | } |
| 1912 | |
| 1913 | return BDF_INVALID_LINE; |
| 1914 | } |
| 1915 | |
| 1916 | /* |
| 1917 | * Load the font properties. |
| 1918 | */ |
| 1919 | static int |
| 1920 | _bdf_parse_properties(char *line, unsigned long linelen, unsigned long lineno, |
| 1921 | void *call_data, void *client_data) |
| 1922 | { |
| 1923 | unsigned long vlen; |
| 1924 | _bdf_line_func_t *next; |
| 1925 | _bdf_parse_t *p; |
| 1926 | char *name, *value, nbuf[128]; |
| 1927 | FT_Memory memory; |
| 1928 | |
| 1929 | next = (_bdf_line_func_t *) call_data; |
| 1930 | p = (_bdf_parse_t *) client_data; |
| 1931 | |
| 1932 | memory = p->font->memory; |
| 1933 | /* |
| 1934 | * Check for the end of the properties. |
| 1935 | */ |
| 1936 | if (ft_memcmp(line, "ENDPROPERTIES", 13) == 0) { |
| 1937 | /* |
| 1938 | * If the FONT_ASCENT or FONT_DESCENT properties have not been |
| 1939 | * encountered yet, then make sure they are added as properties and |
| 1940 | * make sure they are set from the font bounding box info. |
| 1941 | * |
| 1942 | * This is *always* done regardless of the options, because X11 |
| 1943 | * requires these two fields to compile fonts. |
| 1944 | */ |
| 1945 | if (bdf_get_font_property(p->font, "FONT_ASCENT") == 0) { |
| 1946 | p->font->font_ascent = p->font->bbx.ascent; |
| 1947 | sprintf(nbuf, "%hd", p->font->bbx.ascent); |
| 1948 | _bdf_add_property(p->font, "FONT_ASCENT", nbuf); |
| 1949 | sprintf(nbuf, ACMSG1, p->font->bbx.ascent); |
| 1950 | _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf)); |
| 1951 | p->font->modified = 1; |
| 1952 | } |
| 1953 | if (bdf_get_font_property(p->font, "FONT_DESCENT") == 0) { |
| 1954 | p->font->font_descent = p->font->bbx.descent; |
| 1955 | sprintf(nbuf, "%hd", p->font->bbx.descent); |
| 1956 | _bdf_add_property(p->font, "FONT_DESCENT", nbuf); |
| 1957 | sprintf(nbuf, ACMSG2, p->font->bbx.descent); |
| 1958 | _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf)); |
| 1959 | p->font->modified = 1; |
| 1960 | } |
| 1961 | p->flags &= ~_BDF_PROPS; |
| 1962 | *next = _bdf_parse_glyphs; |
| 1963 | return 0; |
| 1964 | } |
| 1965 | |
| 1966 | /* |
| 1967 | * Ignore the _XFREE86_GLYPH_RANGES properties. |
| 1968 | */ |
| 1969 | if (ft_memcmp(line, "_XFREE86_GLYPH_RANGES", 21) == 0) |
| 1970 | return 0; |
| 1971 | |
| 1972 | /* |
| 1973 | * Handle COMMENT fields and properties in a special way to preserve |
| 1974 | * the spacing. |
| 1975 | */ |
| 1976 | if (ft_memcmp(line, "COMMENT", 7) == 0) { |
| 1977 | name = value = line; |
| 1978 | value += 7; |
| 1979 | if (*value) |
| 1980 | *value++ = 0; |
| 1981 | _bdf_add_property(p->font, name, value); |
| 1982 | } else if (_bdf_is_atom(line, linelen, &name, &value, p->font)) |
| 1983 | _bdf_add_property(p->font, name, value); |
| 1984 | else { |
| 1985 | _bdf_split(" +", line, linelen, &p->list, memory); |
| 1986 | name = p->list.field[0]; |
| 1987 | _bdf_shift(1, &p->list); |
| 1988 | value = _bdf_join(' ', &vlen, &p->list); |
| 1989 | _bdf_add_property(p->font, name, value); |
| 1990 | } |
| 1991 | |
| 1992 | return 0; |
| 1993 | } |
| 1994 | |
| 1995 | /* |
| 1996 | * Load the font header. |
| 1997 | */ |
| 1998 | static int |
| 1999 | _bdf_parse_start(char *line, unsigned long linelen, unsigned long lineno, |
| 2000 | void *call_data, void *client_data) |
| 2001 | { |
| 2002 | unsigned long slen; |
| 2003 | _bdf_line_func_t *next; |
| 2004 | _bdf_parse_t *p; |
| 2005 | bdf_font_t *font; |
| 2006 | char *s, nbuf[128]; |
| 2007 | /* int test; */ |
| 2008 | FT_Memory memory; |
| 2009 | FT_Error error; |
| 2010 | |
| 2011 | next = (_bdf_line_func_t *) call_data; |
| 2012 | p = (_bdf_parse_t *) client_data; |
| 2013 | if (p->font) |
| 2014 | memory = p->font->memory; |
| 2015 | |
| 2016 | /* |
| 2017 | * Check for a comment. This is done to handle those fonts that have |
| 2018 | * comments before the STARTFONT line for some reason. |
| 2019 | */ |
| 2020 | if (ft_memcmp(line, "COMMENT", 7) == 0) { |
| 2021 | if (p->opts->keep_comments != 0 && p->font != 0) { |
| 2022 | linelen -= 7; |
| 2023 | s = line + 7; |
| 2024 | if (*s != 0) { |
| 2025 | s++; |
| 2026 | linelen--; |
| 2027 | } |
| 2028 | _bdf_add_comment(p->font, s, linelen); |
| 2029 | /* here font is not defined ! */ |
| 2030 | } |
| 2031 | return 0; |
| 2032 | } |
| 2033 | |
| 2034 | if (!(p->flags & _BDF_START)) { |
| 2035 | |
| 2036 | memory = p->memory; |
| 2037 | |
| 2038 | if (ft_memcmp(line, "STARTFONT", 9) != 0) |
| 2039 | /* |
| 2040 | * No STARTFONT field is a good indication of a problem. |
| 2041 | */ |
| 2042 | return BDF_MISSING_START; |
| 2043 | p->flags = _BDF_START; |
| 2044 | font = p->font = 0; |
| 2045 | |
| 2046 | if ( FT_ALLOC ( font, sizeof(bdf_font_t) ) ) |
| 2047 | return BDF_OUT_OF_MEMORY; |
| 2048 | p->font = font; |
| 2049 | |
| 2050 | font->memory = p->memory; |
| 2051 | p->memory = 0; |
| 2052 | |
| 2053 | /* if (font == 0) { |
| 2054 | fprintf(stderr,"failed font\n"); |
| 2055 | }*/ /* XXX */ |
| 2056 | |
| 2057 | { /* setup */ |
| 2058 | unsigned long i; |
| 2059 | bdf_property_t *prop; |
| 2060 | |
| 2061 | hash_init(&(font->proptbl), memory); |
| 2062 | for (i = 0, prop = _bdf_properties; |
| 2063 | i < _num_bdf_properties; i++, prop++) |
| 2064 | hash_insert(prop->name, (void *) i, &(font->proptbl) , memory); |
| 2065 | } |
| 2066 | |
| 2067 | if ( FT_ALLOC ( p->font->internal , sizeof(hashtable) ) ) |
| 2068 | return BDF_OUT_OF_MEMORY; |
| 2069 | hash_init((hashtable *) p->font->internal,memory); |
| 2070 | p->font->spacing = p->opts->font_spacing; |
| 2071 | p->font->default_glyph = -1; |
| 2072 | return 0; |
| 2073 | } |
| 2074 | |
| 2075 | /* |
| 2076 | * Check for the start of the properties. |
| 2077 | */ |
| 2078 | if (ft_memcmp(line, "STARTPROPERTIES", 15) == 0) { |
| 2079 | _bdf_split(" +", line, linelen, &p->list, memory); |
| 2080 | p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10); |
| 2081 | |
| 2082 | if ( FT_ALLOC ( p->font->props , (sizeof(bdf_property_t) * p->cnt) ) ) |
| 2083 | return BDF_OUT_OF_MEMORY; |
| 2084 | p->flags |= _BDF_PROPS; |
| 2085 | *next = _bdf_parse_properties; |
| 2086 | return 0; |
| 2087 | } |
| 2088 | |
| 2089 | /* |
| 2090 | * Check for the FONTBOUNDINGBOX field. |
| 2091 | */ |
| 2092 | if (ft_memcmp(line, "FONTBOUNDINGBOX", 15) == 0) { |
| 2093 | if (!(p->flags & _BDF_SIZE)) { |
| 2094 | /* |
| 2095 | * Missing the SIZE field. |
| 2096 | */ |
| 2097 | sprintf(nbuf, ERRMSG1, lineno, "SIZE"); |
| 2098 | _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf)); |
| 2099 | return BDF_MISSING_SIZE; |
| 2100 | } |
| 2101 | _bdf_split(" +", line, linelen, &p->list , memory); |
| 2102 | p->font->bbx.width = _bdf_atos(p->list.field[1], 0, 10); |
| 2103 | p->font->bbx.height = _bdf_atos(p->list.field[2], 0, 10); |
| 2104 | p->font->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10); |
| 2105 | p->font->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10); |
| 2106 | p->font->bbx.ascent = p->font->bbx.height + p->font->bbx.y_offset; |
| 2107 | p->font->bbx.descent = -p->font->bbx.y_offset; |
| 2108 | p->flags |= _BDF_FONT_BBX; |
| 2109 | return 0; |
| 2110 | } |
| 2111 | |
| 2112 | /* |
| 2113 | * The next thing to check for is the FONT field. |
| 2114 | */ |
| 2115 | if (ft_memcmp(line, "FONT", 4) == 0) { |
| 2116 | _bdf_split(" +", line, linelen, &p->list , memory); |
| 2117 | _bdf_shift(1, &p->list); |
| 2118 | s = _bdf_join(' ', &slen, &p->list); |
| 2119 | if ( FT_ALLOC ( p->font->name , slen + 1 ) ) |
| 2120 | return BDF_OUT_OF_MEMORY; |
| 2121 | (void) ft_memcpy(p->font->name, s, slen + 1); |
| 2122 | /* |
| 2123 | * If the font name is an XLFD name, set the spacing to the one in the |
| 2124 | * font name. If there is no spacing fall back on the default. |
| 2125 | */ |
| 2126 | _bdf_set_default_spacing(p->font, p->opts); |
| 2127 | p->flags |= _BDF_FONT_NAME; |
| 2128 | return 0; |
| 2129 | } |
| 2130 | |
| 2131 | /* |
| 2132 | * Check for the SIZE field. |
| 2133 | */ |
| 2134 | if (ft_memcmp(line, "SIZE", 4) == 0) { |
| 2135 | if (!(p->flags & _BDF_FONT_NAME)) { |
| 2136 | /* |
| 2137 | * Missing the FONT field. |
| 2138 | */ |
| 2139 | sprintf(nbuf, ERRMSG1, lineno, "FONT"); |
| 2140 | _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf)); |
| 2141 | return BDF_MISSING_FONTNAME; |
| 2142 | } |
| 2143 | _bdf_split(" +", line, linelen, &p->list, memory); |
| 2144 | p->font->point_size = _bdf_atoul(p->list.field[1], 0, 10); |
| 2145 | p->font->resolution_x = _bdf_atoul(p->list.field[2], 0, 10); |
| 2146 | p->font->resolution_y = _bdf_atoul(p->list.field[3], 0, 10); |
| 2147 | |
| 2148 | /* |
| 2149 | * Check for the bits per pixel field. |
| 2150 | */ |
| 2151 | if (p->list.used == 5) { |
| 2152 | p->font->bpp = _bdf_atos(p->list.field[4], 0, 10); |
| 2153 | if (p->font->bpp > 1 && (p->font->bpp & 1)) { |
| 2154 | /* |
| 2155 | * Move up to the next bits per pixel value if an odd number |
| 2156 | * is encountered. |
| 2157 | */ |
| 2158 | p->font->bpp++; |
| 2159 | if (p->font->bpp <= 4) { |
| 2160 | sprintf(nbuf, ACMSG11, p->font->bpp); |
| 2161 | _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf)); |
| 2162 | } |
| 2163 | } |
| 2164 | if (p->font->bpp > 4) { |
| 2165 | sprintf(nbuf, ACMSG11, p->font->bpp); |
| 2166 | _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf)); |
| 2167 | p->font->bpp = 4; |
| 2168 | } |
| 2169 | } else |
| 2170 | p->font->bpp = 1; |
| 2171 | |
| 2172 | p->flags |= _BDF_SIZE; |
| 2173 | return 0; |
| 2174 | } |
| 2175 | |
| 2176 | return BDF_INVALID_LINE; |
| 2177 | } |
| 2178 | |
| 2179 | /************************************************************************** |
| 2180 | * |
| 2181 | * API. |
| 2182 | * |
| 2183 | **************************************************************************/ |
| 2184 | |
| 2185 | |
| 2186 | FT_LOCAL_DEF( bdf_font_t* ) |
| 2187 | bdf_load_font( FT_Stream stream, |
| 2188 | FT_Memory extmemory, |
| 2189 | bdf_options_t* opts, |
| 2190 | bdf_callback_t callback, |
| 2191 | void* data) |
| 2192 | { |
| 2193 | int n; |
| 2194 | unsigned long lineno; |
| 2195 | char msgbuf[128]; |
| 2196 | _bdf_parse_t p; |
| 2197 | FT_Memory memory; |
| 2198 | FT_Error error; |
| 2199 | |
| 2200 | (void) ft_memset((char *) &p, 0, sizeof(_bdf_parse_t)); |
| 2201 | p.opts = (opts != 0) ? opts : &_bdf_opts; |
| 2202 | p.minlb = 32767; |
| 2203 | p.callback = callback; |
| 2204 | p.client_data = data; |
| 2205 | |
| 2206 | p.memory = extmemory; /* only during font creation */ |
| 2207 | |
| 2208 | n = _bdf_readstream(stream, _bdf_parse_start, (void *) &p, &lineno); |
| 2209 | |
| 2210 | if (p.font != 0) { |
| 2211 | /* |
| 2212 | * If the font is not proportional, set the fonts monowidth |
| 2213 | * field to the width of the font bounding box. |
| 2214 | */ |
| 2215 | memory = p.font->memory; |
| 2216 | |
| 2217 | if (p.font->spacing != BDF_PROPORTIONAL) |
| 2218 | p.font->monowidth = p.font->bbx.width; |
| 2219 | |
| 2220 | /* |
| 2221 | * If the number of glyphs loaded is not that of the original count, |
| 2222 | * indicate the difference. |
| 2223 | */ |
| 2224 | if (p.cnt != p.font->glyphs_used + p.font->unencoded_used) { |
| 2225 | sprintf(msgbuf, ACMSG15, p.cnt, |
| 2226 | p.font->glyphs_used + p.font->unencoded_used); |
| 2227 | _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf)); |
| 2228 | p.font->modified = 1; |
| 2229 | } |
| 2230 | |
| 2231 | /* |
| 2232 | * Once the font has been loaded, adjust the overall font metrics if |
| 2233 | * necessary. |
| 2234 | */ |
| 2235 | if (p.opts->correct_metrics != 0 && |
| 2236 | (p.font->glyphs_used > 0 || p.font->unencoded_used > 0)) { |
| 2237 | if (p.maxrb - p.minlb != p.font->bbx.width) { |
| 2238 | sprintf(msgbuf, ACMSG3, p.font->bbx.width, p.maxrb - p.minlb); |
| 2239 | _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf)); |
| 2240 | p.font->bbx.width = p.maxrb - p.minlb; |
| 2241 | p.font->modified = 1; |
| 2242 | } |
| 2243 | if (p.font->bbx.x_offset != p.minlb) { |
| 2244 | sprintf(msgbuf, ACMSG4, p.font->bbx.x_offset, p.minlb); |
| 2245 | _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf)); |
| 2246 | p.font->bbx.x_offset = p.minlb; |
| 2247 | p.font->modified = 1; |
| 2248 | } |
| 2249 | if (p.font->bbx.ascent != p.maxas) { |
| 2250 | sprintf(msgbuf, ACMSG5, p.font->bbx.ascent, p.maxas); |
| 2251 | _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf)); |
| 2252 | p.font->bbx.ascent = p.maxas; |
| 2253 | p.font->modified = 1; |
| 2254 | } |
| 2255 | if (p.font->bbx.descent != p.maxds) { |
| 2256 | sprintf(msgbuf, ACMSG6, p.font->bbx.descent, p.maxds); |
| 2257 | _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf)); |
| 2258 | p.font->bbx.descent = p.maxds; |
| 2259 | p.font->bbx.y_offset = -p.maxds; |
| 2260 | p.font->modified = 1; |
| 2261 | } |
| 2262 | if (p.maxas + p.maxds != p.font->bbx.height) { |
| 2263 | sprintf(msgbuf, ACMSG7, p.font->bbx.height, p.maxas + p.maxds); |
| 2264 | _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf)); |
| 2265 | } |
| 2266 | p.font->bbx.height = p.maxas + p.maxds; |
| 2267 | |
| 2268 | if (p.flags & _BDF_SWIDTH_ADJ) |
| 2269 | _bdf_add_acmsg(p.font, ACMSG8, ft_strlen(ACMSG8)); |
| 2270 | } |
| 2271 | } |
| 2272 | |
| 2273 | /* |
| 2274 | * Last, if an error happened during loading, handle the messages. |
| 2275 | */ |
| 2276 | if (n < 0 && callback != 0) { |
| 2277 | /* |
| 2278 | * An error was returned. Alert the client. |
| 2279 | */ |
| 2280 | p.cb.reason = BDF_ERROR; |
| 2281 | p.cb.errlineno = lineno; |
| 2282 | (*callback)(&p.cb, data); |
| 2283 | } else if (p.flags & _BDF_START) { |
| 2284 | if (p.font != 0) { |
| 2285 | /* |
| 2286 | * The ENDFONT field was never reached or did not exist. |
| 2287 | */ |
| 2288 | if (!(p.flags & _BDF_GLYPHS)) |
| 2289 | /* |
| 2290 | * Error happened while parsing header. |
| 2291 | */ |
| 2292 | sprintf(msgbuf, ERRMSG2, lineno); |
| 2293 | else |
| 2294 | /* |
| 2295 | * Error happened when parsing glyphs. |
| 2296 | */ |
| 2297 | sprintf(msgbuf, ERRMSG3, lineno); |
| 2298 | |
| 2299 | _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf)); |
| 2300 | } |
| 2301 | |
| 2302 | if (callback != 0) { |
| 2303 | p.cb.reason = BDF_ERROR; |
| 2304 | p.cb.errlineno = lineno; |
| 2305 | (*callback)(&p.cb, data); |
| 2306 | } |
| 2307 | } else if (callback != 0) { |
| 2308 | /* |
| 2309 | * This forces the progress bar to always finish. |
| 2310 | */ |
| 2311 | p.cb.current = p.cb.total; |
| 2312 | (*p.callback)(&p.cb, p.client_data); |
| 2313 | } |
| 2314 | |
| 2315 | /* |
| 2316 | * Free up the list used during the parsing. |
| 2317 | */ |
| 2318 | if (p.list.size > 0) |
| 2319 | FT_FREE( p.list.field ); |
| 2320 | |
| 2321 | if (p.font != 0) { |
| 2322 | /* |
| 2323 | * Make sure the comments are NULL terminated if they exist. |
| 2324 | */ |
| 2325 | memory = p.font->memory; |
| 2326 | |
| 2327 | if (p.font->comments_len > 0) { |
| 2328 | if ( FT_REALLOC ( p.font->comments , p.font->comments_len , |
| 2329 | p.font->comments_len + 1 ) ) |
| 2330 | return 0; |
| 2331 | p.font->comments[p.font->comments_len] = 0; |
| 2332 | } |
| 2333 | |
| 2334 | /* |
| 2335 | * Make sure the auto-correct messages are NULL terminated if they |
| 2336 | * exist. |
| 2337 | */ |
| 2338 | if (p.font->acmsgs_len > 0) { |
| 2339 | memory = p.font->memory; |
| 2340 | |
| 2341 | if ( FT_REALLOC ( p.font->acmsgs , p.font->acmsgs_len , |
| 2342 | p.font->acmsgs_len + 1 ) ) |
| 2343 | return 0; |
| 2344 | p.font->acmsgs[p.font->acmsgs_len] = 0; |
| 2345 | } |
| 2346 | } |
| 2347 | |
| 2348 | return p.font; |
| 2349 | } |
| 2350 | |
| 2351 | |
| 2352 | FT_LOCAL_DEF( void ) |
| 2353 | bdf_free_font( bdf_font_t *font ) |
| 2354 | { |
| 2355 | bdf_property_t *prop; |
| 2356 | unsigned long i; |
| 2357 | bdf_glyph_t *glyphs; |
| 2358 | FT_Memory memory; |
| 2359 | |
| 2360 | if (font == 0) |
| 2361 | return; |
| 2362 | |
| 2363 | memory = font->memory; |
| 2364 | |
| 2365 | if (font->name != 0) |
| 2366 | FT_FREE(font->name); |
| 2367 | |
| 2368 | /* |
| 2369 | * Free up the internal hash table of property names. |
| 2370 | */ |
| 2371 | if (font->internal) { |
| 2372 | hash_free((hashtable *) font->internal, memory); |
| 2373 | FT_FREE(font->internal); |
| 2374 | } |
| 2375 | /* |
| 2376 | * Free up the comment info. |
| 2377 | */ |
| 2378 | if (font->comments_len > 0) |
| 2379 | FT_FREE(font->comments); |
| 2380 | |
| 2381 | /* |
| 2382 | * Free up the auto-correction messages. |
| 2383 | */ |
| 2384 | if (font->acmsgs_len > 0) |
| 2385 | FT_FREE(font->acmsgs); |
| 2386 | |
| 2387 | /* |
| 2388 | * Free up the properties. |
| 2389 | */ |
| 2390 | for (i = 0; i < font->props_size; i++) { |
| 2391 | if (font->props[i].format == BDF_ATOM && font->props[i].value.atom) |
| 2392 | FT_FREE(font->props[i].value.atom); |
| 2393 | } |
| 2394 | |
| 2395 | if (font->props_size > 0 && font->props != 0) |
| 2396 | FT_FREE(font->props); |
| 2397 | |
| 2398 | /* |
| 2399 | * Free up the character info. |
| 2400 | */ |
| 2401 | for (i = 0, glyphs = font->glyphs; i < font->glyphs_used; i++, glyphs++) { |
| 2402 | if (glyphs->name) |
| 2403 | FT_FREE(glyphs->name); |
| 2404 | if (glyphs->bytes > 0 && glyphs->bitmap != 0) |
| 2405 | FT_FREE(glyphs->bitmap); |
| 2406 | } |
| 2407 | |
| 2408 | for (i = 0, glyphs = font->unencoded; i < font->unencoded_used; |
| 2409 | i++, glyphs++) { |
| 2410 | if (glyphs->name) |
| 2411 | FT_FREE(glyphs->name); |
| 2412 | if (glyphs->bytes > 0) |
| 2413 | FT_FREE(glyphs->bitmap); |
| 2414 | } |
| 2415 | |
| 2416 | if (font->glyphs_size > 0) |
| 2417 | FT_FREE( font->glyphs); |
| 2418 | |
| 2419 | if (font->unencoded_size > 0) |
| 2420 | FT_FREE( font->unencoded); |
| 2421 | |
| 2422 | /* |
| 2423 | * Free up the overflow storage if it was used. |
| 2424 | */ |
| 2425 | for (i = 0, glyphs = font->overflow.glyphs; i < font->overflow.glyphs_used; |
| 2426 | i++, glyphs++) { |
| 2427 | if (glyphs->name != 0) |
| 2428 | FT_FREE(glyphs->name); |
| 2429 | if (glyphs->bytes > 0) |
| 2430 | FT_FREE( glyphs->bitmap);; |
| 2431 | } |
| 2432 | if (font->overflow.glyphs_size > 0) |
| 2433 | FT_FREE(font->overflow.glyphs); |
| 2434 | |
| 2435 | /* bdf_cleanup */ |
| 2436 | hash_free(&(font->proptbl),memory); |
| 2437 | |
| 2438 | /* |
| 2439 | * Free up the user defined properties. |
| 2440 | */ |
| 2441 | for (prop = font->user_props, i = 0; i < font->nuser_props; i++, prop++) { |
| 2442 | FT_FREE(prop->name); |
| 2443 | if (prop->format == BDF_ATOM && prop->value.atom != 0) |
| 2444 | FT_FREE(prop->value.atom); |
| 2445 | } |
| 2446 | if (font->nuser_props > 0) |
| 2447 | FT_FREE(font->user_props); |
| 2448 | |
| 2449 | /*FREE( font);*/ /* XXX Fixme */ |
| 2450 | } |
| 2451 | |
| 2452 | |
| 2453 | |
| 2454 | FT_LOCAL_DEF( bdf_property_t* ) |
| 2455 | bdf_get_font_property( bdf_font_t* font, |
| 2456 | char* name) |
| 2457 | { |
| 2458 | hashnode hn; |
| 2459 | |
| 2460 | if (font == 0 || font->props_size == 0 || name == 0 || *name == 0) |
| 2461 | return 0; |
| 2462 | |
| 2463 | hn = hash_lookup(name, (hashtable *) font->internal); |
| 2464 | return (hn) ? (font->props + ((unsigned long) hn->data)) : 0; |
| 2465 | } |