read.c revision ea148d1d
1/* $XdotOrg: xc/programs/fonttosfnt/read.c,v 1.2 2004/04/23 19:54:32 eich Exp $ */ 2/* 3Copyright (c) 2002 by Juliusz Chroboczek 4 5Permission is hereby granted, free of charge, to any person obtaining a copy 6of this software and associated documentation files (the "Software"), to deal 7in the Software without restriction, including without limitation the rights 8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9copies of the Software, and to permit persons to whom the Software is 10furnished to do so, subject to the following conditions: 11 12The above copyright notice and this permission notice shall be included in 13all copies or substantial portions of the Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21THE SOFTWARE. 22*/ 23/* $XdotOrg: xc/programs/fonttosfnt/read.c,v 1.2 2004/04/23 19:54:32 eich Exp $ */ 24/* $XFree86: xc/programs/fonttosfnt/read.c,v 1.5 2003/12/19 02:05:39 dawes Exp $ */ 25 26#include <stdio.h> 27 28#include <ft2build.h> 29#include FT_FREETYPE_H 30#include FT_MODULE_H 31#include FT_BDF_H 32#include "X11/Xos.h" 33#include "fonttosfnt.h" 34#include "X11/fonts/fontenc.h" 35 36#define FLOOR2(x, y) ((x) >= 0 ? (x) / (y) : -(((-(x)) + (y) - 1) / (y))) 37#define CEIL2(x, y) (FLOOR2((x) + (y) - 1, (y))) 38#define FT_Pos_DOWN(x) (FLOOR2((x),64)) 39#define FT_Pos_UP(x) (CEIL2((x), 64)) 40#define MIN(x, y) (((x) <= (y)) ? (x) : (y)) 41#define STREAM_FILE(stream) ((FILE*)stream->descriptor.pointer) 42 43static int ft_inited = 0; 44static FT_Library ft_library; 45 46static int 47FT_Ensure_Inited(void) 48{ 49 int rc; 50 if(ft_inited) 51 return 0; 52 53 rc = FT_Init_FreeType(&ft_library); 54 if(rc != 0) 55 return rc; 56 57 ft_inited = 1; 58 return 0; 59} 60 61static unsigned long 62forwardRead(FT_Stream stream, unsigned long offset, unsigned char *buffer, 63 unsigned long count) { 64 unsigned char skip_buffer[BUFSIZ]; 65 unsigned long skip_count; 66 FILE *file = STREAM_FILE(stream); 67 68 /* We may be asked to skip forward, but by not doing so we increase our 69 chance of survival. */ 70 if(count == 0) 71 return ferror(file) == 0 ? 0 : 1; 72 73 if(offset < stream->pos) { 74 fprintf(stderr, "Cannot move backward in input stream.\n"); 75 return 0; 76 } 77 while((skip_count = MIN(BUFSIZ, offset - stream->pos))) { 78 if(fread(skip_buffer, sizeof(*skip_buffer), skip_count, file) < 79 skip_count) 80 return 0; 81 stream->pos += sizeof(*skip_buffer) * skip_count; 82 } 83 84 return (unsigned long)fread(buffer, sizeof(*buffer), count, file); 85} 86 87static void 88streamClose(FT_Stream stream) { 89 fclose(STREAM_FILE(stream)); 90 stream->descriptor.pointer = NULL; 91 stream->size = 0; 92} 93 94int 95readFile(char *filename, FontPtr font) 96{ 97 int j, k, index; 98 int rc; 99 FT_Open_Args input = { 0 }; 100 FT_Face face; 101 StrikePtr strike; 102 BitmapPtr bitmap; 103 int symbol = 0; 104 int force_unicode = 1; 105 char *encoding_name = NULL; 106 FontMapPtr mapping = NULL; 107 FontMapReversePtr reverse = NULL; 108 109 110 rc = FT_Ensure_Inited(); 111 if(rc != 0) 112 return rc; 113 114 if(filename != NULL) { 115 input.pathname = filename; 116 input.flags = FT_OPEN_PATHNAME; 117 } else { 118 input.flags = FT_OPEN_STREAM | FT_OPEN_DRIVER; 119 input.driver = FT_Get_Module(ft_library, "bdf"); 120 input.stream = calloc(1, sizeof(FT_StreamRec)); 121 if(input.stream == NULL) 122 return -1; 123 124 input.stream->size = 0x7FFFFFFF; 125 input.stream->descriptor.pointer = stdin; 126 input.stream->read = forwardRead; 127 input.stream->close = streamClose; 128 } 129 rc = FT_Open_Face(ft_library, &input, 0, &face); 130 if(rc != 0) { 131 fprintf(stderr, "Couldn't open face %s.\n", 132 filename ? filename : "<stdin>"); 133 return -1; 134 } 135 136 /* FreeType will insist on encodings which are simple subsets of unicode 137 * to be read as unicode regardless of what we call them. */ 138 for(j = 0; j < face->num_charmaps; ++j) { 139 if((face->charmaps[j]->encoding == ft_encoding_none) || 140 (face->charmaps[j]->encoding == ft_encoding_adobe_standard)) { 141 force_unicode = 0; 142 break; 143 } 144 } 145 146 encoding_name = faceEncoding(face); 147 if(encoding_name == NULL) { 148 symbol = 1; 149 } else if(strcasecmp(encoding_name, "iso10646-1") != 0) { 150 if(reencode_flag) 151 mapping = FontEncMapFind(encoding_name, 152 FONT_ENCODING_UNICODE, 0, 0, NULL); 153 if(mapping == NULL) { 154 symbol = 1; 155 } else { 156 reverse = FontMapReverse(mapping); 157 if(reverse == NULL) { 158 fprintf(stderr, "Couldn't reverse mapping.\n"); 159 return -1; 160 } 161 } 162 } 163 164 if(verbose_flag) { 165 fprintf(stderr, "%s %s %s: %d sizes%s\n", 166 filename ? filename : "<stdin>", 167 face->family_name, face->style_name, face->num_fixed_sizes, 168 symbol ? " (symbol)" : ""); 169 } 170 171 if(font->numNames == 0 && face->style_name && face->family_name) { 172 char *full_name, *unique_name; 173 BDF_PropertyRec prop; 174 int i; 175 if(strcmp(face->style_name, "Regular") == 0) 176 full_name = sprintf_alloc("%s", face->family_name); 177 else 178 full_name = sprintf_alloc("%s %s", 179 face->family_name, face->style_name); 180 181 /* The unique name doesn't actually need to be globally 182 unique; it only needs to be unique among all installed fonts on a 183 Windows system. We don't bother getting it quite right. */ 184 if(face->num_fixed_sizes <= 0) 185 unique_name = sprintf_alloc("%s "XVENDORNAMESHORT" bitmap", 186 full_name); 187 else if(face->available_sizes[0].width == 188 face->available_sizes[0].height) 189 unique_name = sprintf_alloc("%s "XVENDORNAMESHORT 190 " bitmap size %d", 191 full_name, 192 face->available_sizes[0].height); 193 else 194 unique_name = sprintf_alloc("%s "XVENDORNAMESHORT 195 " bitmap size %dx%d", 196 full_name, 197 face->available_sizes[0].width, 198 face->available_sizes[0].height); 199 200 font->names = malloc(10 * sizeof(FontNameEntryRec)); 201 if(font->names == NULL) { 202 fprintf(stderr, "Couldn't allocate names.\n"); 203 return -1; 204 } 205 i = 0; 206 207 rc = FT_Get_BDF_Property(face, "COPYRIGHT", &prop); 208 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) { 209 font->names[i].nid = 0; 210 font->names[i].size = 2 * strlen(prop.u.atom); 211 font->names[i].value = makeUTF16((char*)prop.u.atom); 212 i++; 213 } 214 215 font->names[i].nid = 1; 216 font->names[i].size = 2 * strlen(face->family_name); 217 font->names[i].value = makeUTF16(face->family_name); 218 i++; 219 220 font->names[i].nid = 2; 221 font->names[i].size = 2 * strlen(face->style_name); 222 font->names[i].value = makeUTF16(face->style_name); 223 i++; 224 225 font->names[i].nid = 3; 226 font->names[i].size = 2 * strlen(unique_name); 227 font->names[i].value = makeUTF16(unique_name); 228 i++; 229 230 font->names[i].nid = 4; 231 font->names[i].size = 2 * strlen(full_name); 232 font->names[i].value = makeUTF16(full_name); 233 i++; 234 235 font->names[i].nid = 5; 236 font->names[i].size = 2 * strlen("Version 0.0"); 237 font->names[i].value = makeUTF16("Version 0.0"); 238 i++; 239 240 rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop); 241 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) { 242 font->names[i].nid = 8; 243 font->names[i].size = 2 * strlen(prop.u.atom); 244 font->names[i].value = makeUTF16((char*)prop.u.atom); 245 i++; 246 } 247 248 font->names[i].nid = 10; 249 font->names[i].size = 2 * strlen(XVENDORNAMESHORT 250 " converted bitmap font"); 251 font->names[i].value = makeUTF16(XVENDORNAMESHORT 252 " converted bitmap font"); 253 i++; 254#ifdef __VENDORWEBSUPPORT__ 255 font->names[i].nid = 11; 256 font->names[i].size = 2 * strlen(__VENDORWEBSUPPORT__); 257 font->names[i].value = makeUTF16(__VENDORWEBSUPPORT__); 258 i++; 259#endif 260 font->numNames = i; 261 262 font->flags = faceFlags(face) | (symbol ? FACE_SYMBOL : 0); 263 font->weight = faceWeight(face); 264 font->width = faceWidth(face); 265 font->foundry = faceFoundry(face); 266 font->italicAngle = faceItalicAngle(face); 267 268 rc = FT_Get_BDF_Property(face, "UNDERLINE_POSITION", &prop); 269 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) 270 font->underlinePosition = 271 (double)prop.u.integer / face->available_sizes[0].height * 272 TWO_SIXTEENTH; 273 else 274 font->underlinePosition = 275 - 1.5 / face->available_sizes[0].height * TWO_SIXTEENTH; 276 277 rc = FT_Get_BDF_Property(face, "UNDERLINE_THICKNESS", &prop); 278 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) 279 font->underlineThickness = 280 (double)prop.u.integer / face->available_sizes[0].height * 281 TWO_SIXTEENTH; 282 else 283 font->underlineThickness = 284 1.0 / face->available_sizes[0].height * TWO_SIXTEENTH; 285 } 286 287 if(face->num_fixed_sizes == 0) { 288 fprintf(stderr, "No bitmaps in face.\n"); 289 return -1; 290 } 291 292 if((!symbol && !mapping) || force_unicode) { 293 rc = FT_Select_Charmap(face, ft_encoding_unicode); 294 } else { 295 rc = FT_Select_Charmap(face, ft_encoding_none); 296 if(rc != 0) { 297 /* BDF will default to Adobe Standard even for nonstandard 298 * encodings, so try that as a last resort. */ 299 rc = FT_Select_Charmap(face, ft_encoding_adobe_standard); 300 } 301 } 302 if(rc != 0) { 303 fprintf(stderr, "Couldn't select character map: %x.\n", rc); 304 return -1; 305 } 306 307 for(int i = 0; i < face->num_fixed_sizes; i++) { 308 if(verbose_flag) 309 fprintf(stderr, "size %d: %dx%d\n", 310 i, 311 (int)((face->available_sizes[i].x_ppem + 32) >> 6), 312 (int)((face->available_sizes[i].y_ppem + 32) >> 6)); 313 314 rc = FT_Set_Pixel_Sizes(face, 315 (face->available_sizes[i].x_ppem + 32) >> 6, 316 (face->available_sizes[i].y_ppem + 32) >> 6); 317 if(rc != 0) { 318 fprintf(stderr, "Couldn't set size.\n"); 319 return -1; 320 } 321 322 strike = makeStrike(font, 323 (face->available_sizes[i].x_ppem + 32) >> 6, 324 (face->available_sizes[i].y_ppem + 32) >> 6); 325 if(strike == NULL) { 326 fprintf(stderr, "Couldn't allocate strike.\n"); 327 return -1; 328 } 329 330 for(j = 0; j < FONT_CODES; j++) { 331 if(mapping) 332 k = reverse->reverse(j, reverse->data); 333 else 334 k = j; 335 if(k <= 0 && j != 0) 336 continue; 337 index = FT_Get_Char_Index(face, k); 338 if(j != 0 && index == 0) 339 continue; 340 rc = FT_Load_Glyph(face, index, 341 FT_LOAD_RENDER | FT_LOAD_MONOCHROME); 342 if(rc != 0) { 343 fprintf(stderr, "Couldn't load glyph for U+%04X (%d)\n", 344 j, index); 345 continue; 346 } 347 bitmap = makeBitmap(strike, j, 348 FT_Pos_UP(face->glyph->metrics.horiAdvance), 349 FT_Pos_DOWN(face->glyph->metrics.horiBearingX), 350 FT_Pos_DOWN(face->glyph->metrics.horiBearingY), 351 face->glyph->bitmap.width, 352 face->glyph->bitmap.rows, 353 face->glyph->bitmap.pitch, 354 face->glyph->bitmap.buffer, 355 crop_flag); 356 357 if(bitmap == NULL) { 358 fprintf(stderr, "Couldn't create bitmap.\n"); 359 return -1; 360 } 361 } 362 } 363 364 FT_Done_Face(face); 365 free(input.stream); 366 367 j = 0; 368 for(int i = 0; i < FONT_CODES; i++) { 369 int found = 0; 370 strike = font->strikes; 371 while(strike) { 372 bitmap = STRIKE_BITMAP(strike, i); 373 if(bitmap) { 374 bitmap->index = j; 375 found = 1; 376 } else { 377 if(i == 0) { 378 fprintf(stderr, 379 "Warning: no bitmap for the undefined glyph.\n"); 380 found = 1; 381 } 382 } 383 strike = strike->next; 384 } 385 if(found) 386 j++; 387 } 388 return 0; 389} 390