ft.c (12450B)
1 /*========================================================================*\ 2 3 Copyright (c) 2013 Paul Vojta 4 5 Permission is hereby granted, free of charge, to any person obtaining a copy 6 of this software and associated documentation files (the "Software"), to 7 deal in the Software without restriction, including without limitation the 8 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9 sell copies of the Software, and to permit persons to whom the Software is 10 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 PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22 \*========================================================================*/ 23 24 /* 25 * FreeType (PostScript Type 1 and TrueType) font reading routines. 26 * Public routines are load_ft_font and read_ft_char. 27 */ 28 29 #include "font.h" /* struct font */ 30 #include "util.h" /* alloc_bitmap(), ROUNDUP, struct avl */ 31 #include "xdvi.h" 32 33 #include <ctype.h> /* isspace(), isdigit() */ 34 #include <err.h> 35 #include <math.h> 36 37 static FT_Library library = NULL; 38 39 static struct avl_enc *enc_head = NULL; 40 41 /* From xc/lib/X11/PutImage.c */ 42 43 #if !WORDS_BIGENDIAN 44 static const unsigned char reverse_byte[0x100] = { 45 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 46 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 47 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 48 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 49 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 50 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 51 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 52 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 53 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 54 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 55 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 56 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 57 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 58 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 59 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 60 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 61 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 62 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 63 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 64 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 65 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 66 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 67 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 68 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 69 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 70 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 71 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 72 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 73 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 74 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 75 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 76 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff 77 }; 78 #endif /* !WORDS_BIGENDIAN */ 79 80 81 /* 82 * FreeType I/O stream functions 83 */ 84 85 static unsigned long 86 xdvi_stream_read(stream, offset, buffer, count) 87 FT_Stream stream; 88 unsigned long offset; 89 unsigned char *buffer; 90 unsigned long count; 91 { 92 struct font *fontp; 93 94 fontp = ((struct ftfont *) stream->descriptor.pointer)->first_size; 95 open_font_file(fontp); 96 fseek(fontp->file, offset, SEEK_SET); 97 return (unsigned long) fread(buffer, 1, count, fontp->file); 98 } 99 100 static void 101 xdvi_stream_close(stream) 102 FT_Stream stream; 103 { 104 /* do nothing */ 105 } 106 107 108 /* 109 * Public routines 110 */ 111 112 static void 113 read_ft_char(struct font *fontp, unsigned char ch) 114 { 115 struct glyph *g; 116 FT_Face face; 117 FT_GlyphSlot slot; 118 int bytes_wide; 119 int err; 120 121 if (debug & DBG_PK) 122 printf("Loading FreeType char %d", ch); 123 124 /* 125 * Load it unscaled first, so that we can get a more accurate 126 * (non-hinted) value of the horizontal advance. 127 */ 128 129 g = &fontp->glyph[ch]; 130 face = fontp->ft->face; 131 FT_Activate_Size(fontp->size); 132 err = FT_Load_Glyph(face, g->addr, FT_LOAD_NO_SCALE); 133 if (err != 0) 134 errx(1, "FT_Load_Glyph: error = %d", err); 135 136 g->dvi_adv = face->glyph->metrics.horiAdvance * fontp->ft->expn 137 * fontp->spsize / face->units_per_EM + 0.5; 138 139 /* Now do the real loading. */ 140 141 err = FT_Load_Glyph(face, g->addr, FT_LOAD_RENDER | FT_LOAD_MONOCHROME); 142 if (err != 0) 143 errx(1, "FT_Load_Glyph: error = %d", err); 144 145 slot = face->glyph; 146 g->bitmap.w = slot->bitmap.width; 147 g->bitmap.h = slot->bitmap.rows; 148 149 if (debug & DBG_PK) 150 printf(", size=%dx%d, dvi_adv=%ld\n", g->bitmap.w, g->bitmap.h, 151 g->dvi_adv); 152 153 alloc_bitmap(&g->bitmap); 154 bytes_wide = ROUNDUP((int) g->bitmap.w, BMBITS) * BMBYTES; 155 156 if (slot->bitmap.width > 0) { 157 int i; 158 unsigned char *p; 159 BMUNIT *q; 160 161 p = slot->bitmap.buffer; 162 q = (BMUNIT *) g->bitmap.bits; 163 for (i = g->bitmap.h; i > 0; --i) { 164 #if WORDS_BIGENDIAN 165 memcpy(q, p, (slot->bitmap.width + 7) / 8); 166 #else 167 unsigned char *p1 = p; 168 BMUNIT *q1 = q; 169 BMUNIT data = 0; 170 int shift = 0; 171 int j; 172 173 for (j = (slot->bitmap.width + 7) / 8; j > 0; --j) { 174 if (shift >= BMBITS) { 175 *q1++ = data; 176 data = 0; 177 shift = 0; 178 } 179 data |= reverse_byte[*p1++] << shift; 180 shift += 8; 181 } 182 *q1 = data; 183 #endif 184 p += slot->bitmap.pitch; 185 *((char **) &q) += bytes_wide; 186 } 187 } 188 189 /* The offset of (-1,-1) is from comparing bitmaps of 'R' and 'a' 190 between cmr10.pfb and cmr10.300pk. */ 191 g->x = -1 - slot->bitmap_left; 192 g->y = slot->bitmap_top - 1; 193 } 194 195 /* 196 * Do the ScaleFont, etc. directives. 197 */ 198 199 static Boolean 200 set_transform(ftp, str) 201 struct ftfont *ftp; 202 const char *str; 203 { 204 double x = 1.0; 205 double y = 0.0; 206 207 for (;;) { 208 while (isspace(*str)) ++str; 209 if (*str == '\0') 210 break; 211 212 if (isdigit(*str) || *str == '.' || *str == '-') { 213 double arg = strtod(str, (char **) &str); 214 215 while (isspace(*str)) ++str; 216 217 if (memcmp(str, "ObliqueSlant", 12) == 0 218 && (isspace(str[12]) || str[12] == '\0')) { 219 arg = -tan(arg); 220 str += 12; 221 while (isspace(*str)) ++str; 222 } 223 224 if (memcmp(str, "SlantFont", 9) == 0 225 && (isspace(str[9]) || str[9] == '\0')) { 226 y += arg; 227 str += 9; 228 } 229 else if (memcmp(str, "ExtendFont", 10) == 0 230 && (isspace(str[10]) || str[10] == '\0')) { 231 x *= arg; 232 str += 10; 233 } 234 else return False; 235 } 236 else { /* other characters; presume encoding name */ 237 while (!isspace(*str) && *str != '\0') ++str; 238 while (isspace(*str)) ++str; 239 if (memcmp(str, "ReEncodeFont", 12) == 0 240 && (isspace(str[12]) || str[12] == '\0')) 241 str += 12; 242 else 243 return False; 244 } 245 } 246 247 if (x != 1.0 || y != 0.0) { 248 FT_Matrix mat; 249 250 mat.xx = (FT_Fixed) (x * 0x10000 + 0.5); 251 mat.xy = (FT_Fixed) (y * 0x10000 + 0.5); 252 mat.yx = 0; 253 mat.yy = 0x10000; 254 255 FT_Set_Transform(ftp->face, &mat, NULL); 256 ftp->expn = x; 257 } 258 259 return True; 260 } 261 262 263 /* 264 * When a document uses many freetype fonts, it can take a while to read 265 * them all (due mostly to disk access issues). So, we delay loading 266 * freetype fonts until they're needed. 267 * 268 * Therefore, this routine is not called until it is time to render a 269 * character from the font (see set_ft_char() in dvi-draw.c). 270 * 271 * It loads and sets up the font. 272 */ 273 274 Boolean 275 load_ft_font(fontp) 276 struct font *fontp; 277 { 278 struct ftfont *ftp; 279 struct avl_t1 *t1p; 280 struct font *fontp2; 281 FT_Face face; 282 FT_Size size; 283 int err; 284 const char *path; 285 FILE *f; 286 287 ftp = fontp->ft; 288 t1p = ftp->t1; 289 fontp2 = ftp->first_size; 290 291 if (t1p->bad) { 292 if (debug & DBG_OPEN) 293 printf("Font %s was flagged as bad; skipping (size %d)\n", 294 fontp->fontname, (int) (fontp->fsize + 0.5)); 295 return False; 296 } 297 298 face = ftp->face; 299 if (face != NULL) { /* if this face is already in use */ 300 err = FT_New_Size(face, &size); 301 if (err != 0) { 302 warnx("Could not load FreeType font '%s' at %d", 303 fontp->fontname, (int) (fontp->fsize + 0.5)); 304 warnx("FreeType FT_New_Size error = %d.", err); 305 warnx("Will try pixel version instead."); 306 warnx("Please see the FreeType documentation for details about this."); 307 return False; 308 } 309 } 310 else { 311 FT_Open_Args args; 312 313 f = open_t1_font(t1p, &path); 314 if (f == NULL) 315 return False; 316 317 if (library == NULL) { 318 err = FT_Init_FreeType(&library); 319 if (err != 0) { 320 warnx("Could not initialize FreeType library"); 321 warnx("FreeType FT_Init_FreeType error = %d.", err); 322 warnx("Turning off use of FreeType."); 323 warnx("Please see the FreeType documentation for details about this."); 324 free((char *) path); 325 fclose(f); 326 return False; 327 } 328 } 329 330 fontp2->filename = path; 331 fontp2->file = f; 332 333 fseek(f, 0L, SEEK_END); 334 ftp->stream.size = ftell(f); 335 fseek(f, 0L, SEEK_SET); /* this might not be necessary */ 336 337 ftp->stream.descriptor.pointer = ftp; 338 ftp->stream.read = xdvi_stream_read; 339 ftp->stream.close = xdvi_stream_close; 340 341 args.flags = FT_OPEN_STREAM; 342 args.stream = &ftp->stream; 343 err = FT_Open_Face(library, &args, 0, &face); 344 if (err != 0) { 345 warnx("Could not load FreeType font '%s'", fontp->fontname); 346 warnx("FreeType FT_Open_Face error = %d.", err); 347 warnx("Will try pixel version instead."); 348 warnx("Please see the FreeType documentation for details about this."); 349 free((char *) path); 350 fclose(f); 351 fontp2->file = NULL; 352 fontp2->filename = NULL; 353 return False; 354 } 355 ftp->face = face; 356 357 if (!FT_IS_SCALABLE(face)) { 358 warnx("Font '%s' is not scalable.", fontp->fontname); 359 FT_Done_Face(face); 360 free((char *) path); 361 fclose(f); 362 fontp2->file = NULL; 363 fontp2->filename = NULL; 364 return False; 365 } 366 367 ftp->expn = 1.0; 368 if (t1p->addinfo != NULL) 369 if (!set_transform(ftp, t1p->addinfo)) { 370 FT_Done_Face(face); 371 free((char *) path); 372 fclose(f); 373 fontp2->file = NULL; 374 fontp2->filename = NULL; 375 return False; 376 } 377 378 if (face->charmap == NULL) { 379 if (face->num_charmaps > 0) { 380 if ((debug & DBG_PK) && face->num_charmaps > 1) 381 printf("Choosing the first of %d charmaps.\n", 382 face->num_charmaps); 383 } 384 FT_Set_Charmap(face, face->charmaps[0]); 385 } 386 else if (face->charmap->encoding == ft_encoding_unicode 387 && FT_Select_Charmap(face, ft_encoding_adobe_custom) != 0 388 && FT_Select_Charmap(face, ft_encoding_adobe_standard) != 0 389 && FT_Select_Charmap(face, ft_encoding_adobe_expert) != 0) { 390 if (debug & DBG_PK) 391 puts("Using unicode charmap for font."); 392 warnx("Using unicode charmap"); /* ||| */ 393 } 394 395 ftp->enc = NULL; 396 if (t1p->encname != NULL) { /* if there's an encoding */ 397 struct avl_enc *encp; 398 399 encp = (struct avl_enc *) avladd(t1p->encname, 400 strlen(t1p->encname), 401 (struct avl **) &enc_head, sizeof *encp); 402 if (encp->key == t1p->encname) /* if new record */ 403 read_encoding(encp); 404 if (encp->valid) 405 ftp->enc = encp; 406 } 407 408 size = face->size; 409 } 410 411 /* Get character indices (store them in addr) */ 412 413 if (debug & DBG_PK) 414 printf("Character indices for %s:\n", fontp->fontname); 415 416 FT_Activate_Size(size); 417 418 err = FT_Set_Char_Size(face, 419 (int) (fontp->spsize * (72<<6) / (pixels_per_inch << 16) + 0.5), 0, 420 pixels_per_inch, pixels_per_inch); 421 if (err != 0) 422 errx(1, "FT_Set_Char_Size: error = %d", err); 423 424 /* Look for already-computed character indices */ 425 for (fontp2 = ftp->first_size;; fontp2 = fontp2->next_size) { 426 int i; 427 428 if (fontp2 == NULL) { /* if not found */ 429 struct avl_enc *encp = ftp->enc; 430 431 for (i = 0; i < 256; ++i) { 432 int ci; 433 434 if (encp == NULL) 435 ci = FT_Get_Char_Index(face, i); 436 else { 437 const char *glyphname = encp->vec[i]; 438 439 if (glyphname == NULL) 440 ci = 0; 441 else 442 ci = FT_Get_Name_Index(face, 443 (FT_String *) glyphname); 444 } 445 446 fontp->glyph[i].addr = ci; 447 if (debug & DBG_PK) 448 printf("%3d->%3d%s", i, ci, (i + 1) % 8 ? " " : "\n"); 449 } 450 break; 451 } 452 if (fontp2->size != NULL) { /* found the information */ 453 for (i = 0; i < 256; ++i) 454 fontp->glyph[i].addr = fontp2->glyph[i].addr; 455 break; 456 } 457 } 458 459 fontp->size = size; /* it needed to be NULL in the above loop */ 460 fontp->read_char = read_ft_char; 461 462 return True; 463 }