The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

load_font.c in libbirdfont/OpenFontFormat

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of libbirdfont/OpenFontFormat/load_font.c.
Revert "Use better names when loading the name table"
1 /* 2 Copyright (C) 2013 2014 2015 Johan Mattsson 3 4 This library is free software; you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 3 of the 7 License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 */ 14 15 #include <assert.h> 16 #include <glib.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <stdlib.h> 20 #include <ft2build.h> 21 #include <ttnameid.h> 22 #include FT_FREETYPE_H 23 #include FT_GLYPH_H 24 #include FT_OPENTYPE_VALIDATE_H 25 #include FT_TRUETYPE_TABLES_H 26 #include FT_SFNT_NAMES_H 27 28 /** Error codes. */ 29 #define OK 0 30 31 /** Point flags. */ 32 #define QUADRATIC_OFF_CURVE 0 33 #define ON_CURVE 1 34 #define CUBIC_CURVE 2 35 #define DOUBLE_CURVE 4 36 #define HIDDEN_CURVE 8 37 38 typedef struct FontFace { 39 FT_Face face; 40 FT_Library library; 41 } FontFace; 42 43 /** Convert units per em in font file format to the BirdFont format. */ 44 double get_units (double units_per_em) { 45 return 100.0 / units_per_em; 46 } 47 48 /** @return a non zero value if the point is a part of two off curve 49 * points with a hidden on curve point in between. 50 */ 51 guint is_double_curve (char flag) { 52 return flag & DOUBLE_CURVE; 53 } 54 55 /** @return a non zero value if the point is a cubic off curve point. */ 56 guint is_cubic (char flag) { 57 return flag & CUBIC_CURVE && (flag & ON_CURVE) == 0; 58 } 59 60 /** @return a non zero value if the point is a quadratic off curve point. */ 61 guint is_quadratic (char flag) { 62 return (flag & CUBIC_CURVE) == 0 && (flag & ON_CURVE) == 0; 63 } 64 65 /** @return a non zero value if the point is a on curve point */ 66 guint is_line (char flag) { 67 return flag & ON_CURVE; 68 } 69 70 /** @return a non zero value if the point is a hidden on curve point */ 71 guint is_hidden (char flag) { 72 return flag & HIDDEN_CURVE; 73 } 74 75 /** Convert every second hidden curve to a double curve and keep 76 * other points as on curve points. 77 */ 78 void set_double_curves (char* flag, int length) { 79 int i; 80 guint double_curve = FALSE; 81 82 for (i = 1; i < length; i++) { 83 if (is_line (flag[i])) { 84 double_curve = FALSE; 85 } else if (is_hidden (flag[i])) { 86 if (!double_curve) { 87 if (is_quadratic (flag[i - 1]) && is_quadratic (flag[i + 1])) { 88 flag[i - 1] = DOUBLE_CURVE; 89 flag[i] = HIDDEN_CURVE; 90 flag[i + 1] = DOUBLE_CURVE; 91 double_curve = TRUE; 92 } else { 93 flag[i] = ON_CURVE; 94 double_curve = FALSE; 95 } 96 } else { 97 flag[i] = ON_CURVE; 98 double_curve = FALSE; 99 } 100 } 101 // ignore off curve points 102 } 103 } 104 105 /** @return half the distance between two points. */ 106 double half_way (double prev, double current) { 107 return prev + ((current - prev) / 2.0); 108 } 109 110 /** Remove hidden points. 111 * @return length after removal 112 */ 113 double remove_hidden_points (FT_Vector* points, char* flags, guint length, guint capacity) { 114 int k; 115 int l; 116 117 l = 0; 118 for (k = 0; k < length; k++) { 119 if (!is_hidden (flags[k])) { 120 points[l] = points[k]; 121 flags[l] = flags[k]; 122 l++; 123 } 124 } 125 126 for (k = l; k < capacity; k++) { 127 points[l].x = 0; 128 points[l].y = 0; 129 flags[l] = 0; 130 } 131 132 return l; 133 } 134 135 /** Add extra point where two ore more off curve points follow each other. */ 136 void create_contour (guint unicode, FT_Vector* points, char* flags, int* length, FT_Vector** new_points, char** new_flags, int* err) { 137 // This function has been tested with many fonts. ElsieSwashCaps-Regular 138 // is one of the more interesting fonts I have seen. 139 int i; 140 int j; 141 guint prev_is_curve; 142 guint first_is_curve = FALSE; 143 guint first_normal_off_curve = FALSE; 144 double x = 0; 145 double y = 0; 146 FT_Vector* p; 147 char* f; 148 int len = *length; 149 150 *new_points = malloc (4 * len * sizeof (FT_Vector)); 151 *new_flags = malloc (4 * len * sizeof (char)); 152 153 p = *new_points; 154 f = *new_flags; 155 156 for (i = 0; i < 4 * len; i++) { 157 p[i].x = 0; 158 p[i].y = 0; 159 f[i] = 0; 160 } 161 162 if (len == 0) { 163 return; 164 } 165 166 prev_is_curve = is_quadratic (flags[len - 1]); 167 168 j = 0; 169 i = 0; 170 171 if (len > 2 && is_quadratic (flags[0]) && is_quadratic (flags[1])) { 172 p[j].x = half_way (points[0].x, points[1].x); 173 p[j].y = half_way (points[0].y, points[1].y); 174 175 f[j] = ON_CURVE; 176 prev_is_curve = FALSE; 177 first_is_curve = TRUE; 178 j++; 179 i++; 180 } 181 182 if (len > 2 && is_quadratic (flags[0]) && !is_quadratic (flags[1])) { // first point is of curve but it is not part of a double curve 183 first_normal_off_curve = TRUE; 184 } 185 186 while (i < len) { 187 if (is_quadratic (flags[i])) { 188 if (prev_is_curve && j != 0) { 189 // add a new point if half way between two off curve points 190 x = half_way (points[i].x, p[j - 1].x); 191 y = half_way (points[i].y, p[j - 1].y); 192 193 p[j].x = x; 194 p[j].y = y; 195 196 f[j] = HIDDEN_CURVE; 197 198 j++; 199 } 200 201 f[j] = QUADRATIC_OFF_CURVE; 202 prev_is_curve = TRUE; 203 } else if (is_line (flags[i])) { 204 prev_is_curve = FALSE; 205 f[j] = ON_CURVE; 206 } else if (is_cubic (flags[i])) { 207 prev_is_curve = FALSE; 208 f[j] = CUBIC_CURVE; 209 } else { 210 g_warning ("WARNING invalid point flags: %d index: %d.\n", flags[i], i); 211 prev_is_curve = FALSE; 212 f[j] = ON_CURVE; 213 } 214 215 p[j] = points[i]; 216 j++; 217 i++; 218 } 219 220 // last to first point 221 if (first_is_curve && !prev_is_curve && is_quadratic (flags[i])) { 222 p[j] = points[i]; 223 f[j] = QUADRATIC_OFF_CURVE; 224 j++; 225 i++; 226 227 p[j].x = half_way (p[j - 1].x, points[0].x); 228 p[j].y = half_way (p[j - 1].y, points[0].y); 229 f[j] = ON_CURVE; // FIXME 230 prev_is_curve = FALSE; 231 j++; 232 i++; 233 234 p[j] = points[0]; 235 f[j] = QUADRATIC_OFF_CURVE; 236 j++; 237 i++; 238 239 p[j] = p[0]; 240 f[j] = f[0]; 241 j++; 242 } else if (first_is_curve && !prev_is_curve && is_line (flags[i])) { 243 p[j] = points[i]; 244 f[j] = ON_CURVE; 245 j++; 246 i++; 247 248 p[j] = points[0]; 249 f[j] = QUADRATIC_OFF_CURVE; 250 j++; 251 i++; 252 253 p[j] = p[0]; 254 f[j] = f[0]; 255 j++; 256 } else if (first_is_curve && prev_is_curve && is_quadratic (flags[i])) { 257 x = half_way (p[j - 1].x, points[i].x); 258 y = half_way (p[j - 1].y, points[i].y); 259 p[j].x = x; 260 p[j].y = y; 261 f[j] = HIDDEN_CURVE; 262 j++; 263 264 p[j] = points[i]; 265 f[j] = flags[i]; 266 j++; 267 i++; 268 269 p[j].x = half_way (p[j - 1].x, points[0].x); 270 p[j].y = half_way (p[j - 1].y, points[0].y); 271 f[j] = HIDDEN_CURVE; 272 prev_is_curve = FALSE; 273 274 j++; 275 i++; 276 277 p[j] = points[0]; 278 f[j] = QUADRATIC_OFF_CURVE; 279 j++; 280 281 p[j] = p[0]; 282 f[j] = ON_CURVE; 283 j++; 284 285 prev_is_curve = TRUE; 286 } else if (prev_is_curve && (flags[0] & ON_CURVE) == 0) { 287 if (is_quadratic (f[j - 1]) && is_quadratic (flags[i])) { 288 x = half_way (p[j - 1].x, points[i].x); 289 y = half_way (p[j - 1].y, points[i].y); 290 p[j].x = x; 291 p[j].y = y; 292 f[j] = HIDDEN_CURVE; 293 j++; 294 } 295 296 p[j] = points[i]; 297 if (is_line (flags[i])) { 298 f[j] = ON_CURVE; 299 } else { 300 f[j] = QUADRATIC_OFF_CURVE; 301 } 302 j++; 303 304 if (is_quadratic (f[0]) && is_quadratic (flags[0])) { 305 x = half_way (p[j - 1].x, points[0].x); 306 y = half_way (p[j - 1].y, points[0].y); 307 p[j].x = x; 308 p[j].y = y; 309 f[j] = HIDDEN_CURVE; 310 j++; 311 } 312 313 x = points[0].x; 314 y = points[0].y; 315 316 p[j].x = x; 317 p[j].y = y; 318 319 f[j] = QUADRATIC_OFF_CURVE; 320 j++; 321 } else if (prev_is_curve && is_quadratic (flags[i])) { 322 x = p[j - 1].x + ((points[i].x - p[j - 1].x) / 2.0); 323 y = p[j - 1].y + ((points[i].y - p[j - 1].y) / 2.0); 324 p[j].x = x; 325 p[j].y = y; 326 f[j] = HIDDEN_CURVE; 327 j++; 328 329 p[j] = points[i]; 330 f[j] = QUADRATIC_OFF_CURVE; 331 j++; 332 i++; 333 334 if (is_quadratic (f[0])) { 335 x = half_way (p[j - 1].x, points[i].x); 336 y = half_way (p[j - 1].y, points[i].y); 337 p[j].x = x; 338 p[j].y = y; 339 f[j] = HIDDEN_CURVE; 340 j++; 341 342 p[j] = p[0]; 343 f[j] = f[0]; 344 j++; 345 } else { 346 p[j] = p[0]; 347 f[j] = f[0]; 348 j++; 349 } 350 351 prev_is_curve = TRUE; 352 } else { 353 p[j] = points[i]; 354 if (is_quadratic (flags[i])) 355 f[j] = QUADRATIC_OFF_CURVE; 356 else 357 f[j] = ON_CURVE; 358 j++; 359 360 p[j] = p[0]; 361 if (is_quadratic (flags[i])) 362 f[j] = QUADRATIC_OFF_CURVE; 363 else 364 f[j] = ON_CURVE; 365 j++; 366 } 367 368 set_double_curves (f, j); 369 *length = remove_hidden_points (p, f, j, 2 * len); 370 } 371 372 /** Get path data in .bf format. See BirdFontFile.get_point_data () for 373 * format specification. 374 */ 375 GString* get_bf_contour_data (guint unicode, FT_Vector* points, char* flags, int length, double units_per_em, int* err) { 376 GString* bf = g_string_new (""); 377 GString* contour; 378 int i = 0; 379 FT_Vector* new_points; 380 char* new_flags; 381 double x0, x1, x2; 382 double y0, y1, y2; 383 gchar coordinate_buffer[80]; 384 gchar* coordinate = (gchar*) &coordinate_buffer; 385 double units = get_units (units_per_em); 386 guint prev_is_curve; 387 388 if (length == 0) { 389 return bf; 390 } 391 392 create_contour (unicode, points, flags, &length, &new_points, &new_flags, err); 393 394 x0 = new_points[0].x * units; 395 y0 = new_points[0].y * units; 396 397 g_string_printf (bf, "S "); 398 399 g_ascii_formatd (coordinate, 80, "%f", x0); 400 g_string_append (bf, coordinate); 401 g_string_append (bf, ","); 402 403 g_ascii_formatd (coordinate, 80, "%f", y0); 404 g_string_append (bf, coordinate); 405 406 i = 1; 407 while (i < length) { 408 contour = g_string_new (""); 409 410 if (is_hidden (new_flags[i])) { 411 // Skip it 412 g_string_append (contour, ""); 413 i++; 414 } else if (is_cubic (new_flags[i])) { 415 x0 = new_points[i].x * units; 416 y0 = new_points[i].y * units; 417 x1 = new_points[i+1].x * units; 418 y1 = new_points[i+1].y * units; 419 x2 = new_points[i+2].x * units; 420 y2 = new_points[i+2].y * units; 421 422 g_string_printf (contour, " C "); 423 424 g_ascii_formatd (coordinate, 80, "%f", x0); 425 g_string_append (contour, coordinate); 426 g_string_append (contour, ","); 427 428 g_ascii_formatd (coordinate, 80, "%f", y0); 429 g_string_append (contour, coordinate); 430 g_string_append (contour, " "); 431 432 g_ascii_formatd (coordinate, 80, "%f", x1); 433 g_string_append (contour, coordinate); 434 g_string_append (contour, ","); 435 436 g_ascii_formatd (coordinate, 80, "%f", y1); 437 g_string_append (contour, coordinate); 438 g_string_append (contour, " "); 439 440 g_ascii_formatd (coordinate, 80, "%f", x2); 441 g_string_append (contour, coordinate); 442 g_string_append (contour, ","); 443 444 g_ascii_formatd (coordinate, 80, "%f", y2); 445 g_string_append (contour, coordinate); 446 447 i += 3; 448 } else if (is_double_curve (new_flags[i])) { 449 x0 = new_points[i].x * units; 450 y0 = new_points[i].y * units; 451 x1 = new_points[i+1].x * units; 452 y1 = new_points[i+1].y * units; 453 x2 = new_points[i+2].x * units; 454 y2 = new_points[i+2].y * units; 455 456 g_string_printf (contour, " D "); 457 458 g_ascii_formatd (coordinate, 80, "%f", x0); 459 g_string_append (contour, coordinate); 460 g_string_append (contour, ","); 461 462 g_ascii_formatd (coordinate, 80, "%f", y0); 463 g_string_append (contour, coordinate); 464 g_string_append (contour, " "); 465 466 g_ascii_formatd (coordinate, 80, "%f", x1); 467 g_string_append (contour, coordinate); 468 g_string_append (contour, ","); 469 470 g_ascii_formatd (coordinate, 80, "%f", y1); 471 g_string_append (contour, coordinate); 472 g_string_append (contour, " "); 473 474 g_ascii_formatd (coordinate, 80, "%f", x2); 475 g_string_append (contour, coordinate); 476 g_string_append (contour, ","); 477 478 g_ascii_formatd (coordinate, 80, "%f", y2); 479 g_string_append (contour, coordinate); 480 481 i += 3; 482 } else if (is_quadratic (new_flags[i])) { 483 x0 = new_points[i].x * units; 484 y0 = new_points[i].y * units; 485 x1 = new_points[i+1].x * units; 486 y1 = new_points[i+1].y * units; 487 488 g_string_printf (contour, " Q "); 489 490 g_ascii_formatd (coordinate, 80, "%f", x0); 491 g_string_append (contour, coordinate); 492 g_string_append (contour, ","); 493 494 g_ascii_formatd (coordinate, 80, "%f", y0); 495 g_string_append (contour, coordinate); 496 g_string_append (contour, " "); 497 498 g_ascii_formatd (coordinate, 80, "%f", x1); 499 g_string_append (contour, coordinate); 500 g_string_append (contour, ","); 501 502 g_ascii_formatd (coordinate, 80, "%f", y1); 503 g_string_append (contour, coordinate); 504 505 i += 2; 506 } else if (is_line (new_flags[i])) { 507 x0 = new_points[i].x * units; 508 y0 = new_points[i].y * units; 509 510 g_string_printf (contour, " L "); 511 512 g_ascii_formatd (coordinate, 80, "%f", x0); 513 g_string_append (contour, coordinate); 514 g_string_append (contour, ","); 515 516 g_ascii_formatd (coordinate, 80, "%f", y0); 517 g_string_append (contour, coordinate); 518 519 i += 1; 520 } else { 521 contour = g_string_new (""); 522 g_warning ("WARNING Can't parse outline.\n"); 523 *err = 1; 524 i++; 525 } 526 527 g_string_append (bf, contour->str); 528 g_string_free (contour, TRUE); 529 } 530 531 free (new_points); 532 free (new_flags); 533 534 return bf; 535 } 536 537 /** Get path element in .bf format. */ 538 GString* get_bf_path (guint unicode, FT_Face face, double units_per_em, int* err) { 539 GString* bf = g_string_new (""); 540 GString* contour; 541 FT_Error error; 542 int i; 543 int start; 544 int end; 545 546 if (face->glyph->outline.n_points == 0) { 547 return bf; 548 } 549 550 start = 0; 551 for (i = 0; i < face->glyph->outline.n_contours; i++) { 552 end = face->glyph->outline.contours [i]; 553 contour = get_bf_contour_data (unicode, face->glyph->outline.points + start, face->glyph->outline.tags + start, end - start, units_per_em, err); 554 g_string_append_printf (bf, "\t\t<path data=\"%s\" />\n", contour->str); 555 g_string_free (contour, TRUE); 556 start = face->glyph->outline.contours [i] + 1; 557 } 558 559 return bf; 560 } 561 562 FontFace* open_font (const char* file) { 563 FT_Library library = NULL; 564 FT_Face face = NULL; 565 int error; 566 FontFace* font; 567 568 error = FT_Init_FreeType (&library); 569 if (error != OK) { 570 printf ("Freetype init error %d.\n", error); 571 return NULL; 572 } 573 574 error = FT_New_Face (library, file, 0, &face); 575 if (error) { 576 if (FT_Done_FreeType (library) != 0) { 577 g_warning ("Can't close freetype."); 578 } 579 580 g_warning ("Freetype font face error %d\n", error); 581 return NULL; 582 } 583 584 font = malloc (sizeof (FontFace)); 585 font->face = face; 586 font->library = library; 587 588 error = FT_Select_Charmap (face , FT_ENCODING_UNICODE); 589 if (error) { 590 g_warning ("Freetype can not use Unicode, error: %d\n", error); 591 close_ft_font (font); 592 return NULL; 593 } 594 595 return font; 596 } 597 598 void close_ft_font (FontFace* font) { 599 if (font != NULL) { 600 if (font->face != NULL) { 601 if (FT_Done_Face (font->face) != 0) { 602 g_warning ("Can't close font."); 603 } 604 font->face = NULL; 605 } 606 607 if (font->library != NULL) { 608 if (FT_Done_FreeType (font->library) != 0) { 609 g_warning ("Can't close freetype."); 610 } 611 font->library = NULL; 612 } 613 614 free (font); 615 } 616 } 617 618 GString* load_glyph (FontFace* font, guint unicode) { 619 GString* glyph; 620 GString* paths; 621 int err = OK; 622 int gid; 623 FT_ULong charcode = (FT_ULong) unicode; 624 double units; 625 gchar line_position_buffer[80]; 626 gchar* line_position = (gchar*) &line_position_buffer; 627 FT_Error error; 628 629 if (font == NULL || font->face == NULL || font->library == NULL) { 630 printf ("WARNING No font in load_glyph"); 631 return NULL; 632 } 633 634 gid = FT_Get_Char_Index (font->face, charcode); 635 636 if (gid == 0) { 637 return NULL; 638 } 639 640 units = get_units (font->face->units_per_EM); 641 642 glyph = g_string_new ("<font>"); 643 644 g_string_append_printf (glyph, "<horizontal>\n"); 645 646 g_ascii_formatd (line_position, 80, "%f", font->face->ascender * units); 647 g_string_append_printf (glyph, "\t<top_limit>%s</top_limit>\n", line_position); 648 649 g_string_append_printf (glyph, "\t<base_line>0</base_line>\n"); 650 651 g_ascii_formatd (line_position, 80, "%f", font->face->descender * units); 652 g_string_append_printf (glyph, "\t<bottom_limit>%s</bottom_limit>\n", line_position); 653 654 g_string_append_printf (glyph, "</horizontal>\n"); 655 656 error = FT_Load_Glyph(font->face, gid, FT_LOAD_DEFAULT | FT_LOAD_NO_SCALE); 657 658 if (error != 0) { 659 printf ("WARNING Failed to load glyph."); 660 g_string_free (glyph, TRUE); 661 return NULL; 662 } 663 664 paths = get_bf_path (unicode, font->face, font->face->units_per_EM, &err); 665 666 if (err != OK) { 667 printf ("WARNING Can't load glyph."); 668 g_string_free (glyph, TRUE); 669 g_string_free (paths, TRUE); 670 return NULL; 671 } 672 673 g_string_append_printf (glyph, "<collection unicode=\"U+%x\">\n", (guint)charcode); 674 g_string_append_printf (glyph, "\t<selected id=\"0\" />\n"); 675 g_string_append_printf (glyph, "\t<glyph id=\"0\" left=\"%f\" right=\"%f\">\n", 676 0.0, font->face->glyph->metrics.horiAdvance * units); 677 678 g_string_append_printf (glyph, "%s", paths->str); 679 g_string_append_printf (glyph, "%s", "\t</glyph>"); 680 g_string_append_printf (glyph, "%s", "\t</collection>"); 681 g_string_append_printf (glyph, "%s", "</font>"); 682 683 g_string_free (paths, TRUE); 684 685 if (err != OK) { 686 g_warning ("Can't load glyph data."); 687 } 688 689 return glyph; 690 } 691 692 /** Get char code for a glyph. 693 * @gid glyph id 694 * @return character code 695 */ 696 FT_ULong get_charcode (FT_Face face, FT_UInt gid) { 697 FT_ULong charcode; 698 FT_UInt gindex; 699 700 // TODO: find the lookup function in freetype 701 702 charcode = FT_Get_First_Char (face, &gindex); 703 while (gindex != 0) { 704 charcode = FT_Get_Next_Char (face, charcode, &gindex); 705 if (gindex == gid) { 706 return charcode; 707 } 708 } 709 710 g_warning ("Can not find unicode value for gid %d.", gid); 711 return 0; 712 } 713 714 /** Height of letter. */ 715 int get_height (FT_Face face, guint unichar) { 716 int error; 717 FT_ULong charcode = (FT_ULong) unichar; 718 FT_UInt index = FT_Get_Char_Index (face, charcode); 719 720 error = FT_Load_Glyph (face, index, FT_LOAD_DEFAULT | FT_LOAD_NO_SCALE); 721 if (error) { 722 g_warning ("Failed to obtain height. (%d)\n", error); 723 return 0; 724 } 725 726 return (int) face->glyph->metrics.height; 727 } 728 729 /** Height of lower case letters. */ 730 int get_xheight (FT_Face face) { 731 return get_height (face, 'x'); 732 } 733 734 /** Height of upper case letters. */ 735 int get_top (FT_Face face) { 736 return get_height (face, 'X'); 737 } 738 /** Obtain descender. */ 739 int get_descender (FT_Face face) { 740 int error; 741 FT_BBox bbox; 742 FT_ULong charcode = (FT_ULong) 'g'; 743 FT_UInt index = FT_Get_Char_Index (face, charcode); 744 FT_Glyph glyph; 745 746 error = FT_Load_Glyph (face, index, FT_LOAD_DEFAULT | FT_LOAD_NO_SCALE); 747 if (error) { 748 g_warning ("Failed to obtain descender. (%d)\n", error); 749 return 0; 750 } 751 752 FT_Get_Glyph (face->glyph, &glyph); 753 FT_Glyph_Get_CBox (glyph, FT_GLYPH_BBOX_UNSCALED, &bbox); 754 755 return (int) bbox.yMin; 756 } 757 758 /** Append name table data to a gstring. */ 759 void append_description (GString* str, FT_SfntName* name_table_data) { 760 gchar* utf8_str; 761 gsize read, written; 762 GError* error = NULL; 763 764 if (name_table_data->encoding_id == 0 && name_table_data->platform_id == 1) { // mac roman 765 utf8_str = g_convert (name_table_data->string, name_table_data->string_len, "utf-8", "macintosh", &read, &written, &error); 766 767 if (error == NULL) { 768 g_string_append (str, g_markup_escape_text (utf8_str, -1)); 769 g_free (utf8_str); 770 } else { 771 g_warning ("Error in append_description: %s\n", error->message); 772 g_error_free (error); 773 } 774 } else if (name_table_data->encoding_id == 1 && name_table_data->platform_id == 3) { // windows unicode 775 utf8_str = g_convert (name_table_data->string, name_table_data->string_len, "utf-8", "ucs-2be", &read, &written, &error); 776 777 if (error == NULL) { 778 g_string_append (str, g_markup_escape_text (utf8_str, -1)); 779 g_free (utf8_str); 780 } else { 781 g_warning ("Error in append_description: %s\n", error->message); 782 g_error_free (error); 783 } 784 } else { 785 g_warning ("Encoding %u is not supported.\n", name_table_data->encoding_id); 786 } 787 } 788 789 /** Convert font to bf format. 790 * @param face freetype font face 791 * @param err error code 792 * @return xml representation of a bf font 793 */ 794 GString* get_bf_font (FT_Face face, char* file, int* err) { 795 GString* bf = g_string_new (""); 796 GString* bf_data; 797 gchar* kerning; 798 GString* glyph; 799 FT_Error error; 800 FT_Long i; 801 FT_ULong charcode; 802 FT_UInt gid; 803 FT_SfntName name_table_data; 804 double units_per_em; 805 double units; 806 gchar line_position_buffer[80]; 807 gchar* line_position = (gchar*) &line_position_buffer; 808 809 *err = OK; 810 811 units_per_em = face->units_per_EM; 812 units = get_units (units_per_em); 813 814 if (face == NULL) { 815 return bf; 816 } 817 818 g_string_append (bf, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n"); 819 g_string_append (bf, "<font>\n"); 820 821 g_string_append_printf (bf, "<postscript_name>%s</postscript_name>\n", g_markup_escape_text (FT_Get_Postscript_Name(face), -1)); 822 g_string_append_printf (bf, "<name>%s</name>\n", g_markup_escape_text (face->family_name, -1)); 823 824 if (face->style_name != NULL) { 825 g_string_append_printf (bf, "<subfamily>%s</subfamily>\n", g_markup_escape_text (face->style_name, -1)); 826 } 827 828 if (FT_Get_Sfnt_Name (face, TT_NAME_ID_FULL_NAME, &name_table_data) == 0) { // full name 829 g_string_append (bf, "<full_name>"); 830 append_description (bf, &name_table_data); 831 g_string_append (bf, "</full_name>\n"); 832 } 833 834 if (FT_Get_Sfnt_Name (face, TT_NAME_ID_UNIQUE_ID, &name_table_data) == 0) { // unique identifier 835 g_string_append (bf, "<unique_identifier>"); 836 append_description (bf, &name_table_data); 837 g_string_append (bf, "</unique_identifier>\n"); 838 } 839 840 if (FT_Get_Sfnt_Name (face, TT_NAME_ID_UNIQUE_ID, &name_table_data) == 0) { // version 841 g_string_append (bf, "<version>"); 842 append_description (bf, &name_table_data); 843 g_string_append (bf, "</version>\n"); 844 } 845 846 // FIXME: for some fonts will this return entry 0 (copyright) 847 if (FT_Get_Sfnt_Name (face, TT_NAME_ID_DESCRIPTION, &name_table_data) == 0) { // description 848 g_string_append (bf, "<description>"); 849 append_description (bf, &name_table_data); 850 g_string_append (bf, "</description>\n"); 851 } 852 853 if (FT_Get_Sfnt_Name (face, TT_NAME_ID_COPYRIGHT, &name_table_data) == 0) { // copyright 854 g_string_append (bf, "<copyright>"); 855 append_description (bf, &name_table_data); 856 g_string_append (bf, "</copyright>\n"); 857 } 858 859 g_string_append_printf (bf, "<backup>%s</backup>\n", g_markup_escape_text (file, -1)); 860 861 862 g_string_append_printf (bf, "<horizontal>\n"); 863 864 g_ascii_formatd (line_position, 80, "%f", face->ascender * units); 865 g_string_append_printf (bf, "\t<top_limit>%s</top_limit>\n", line_position); 866 867 g_ascii_formatd (line_position, 80, "%f", get_top (face) * units); 868 g_string_append_printf (bf, "\t<top_position>%s</top_position>\n", line_position); 869 870 g_ascii_formatd (line_position, 80, "%f", get_xheight (face) * units); 871 g_string_append_printf (bf, "\t<x-height>%s</x-height>\n", line_position); 872 873 g_string_append_printf (bf, "\t<base_line>0</base_line>\n"); 874 875 g_ascii_formatd (line_position, 80, "%f", get_descender (face) * units); 876 g_string_append_printf (bf, "\t<bottom_position>%s</bottom_position>\n", line_position); 877 878 g_ascii_formatd (line_position, 80, "%f", face->descender * units); 879 g_string_append_printf (bf, "\t<bottom_limit>%s</bottom_limit>\n", line_position); 880 881 g_string_append_printf (bf, "</horizontal>\n"); 882 883 // space character 884 gid = FT_Get_Char_Index (face, ' '); 885 if (gid != 0) { 886 FT_Load_Glyph(face, gid, FT_LOAD_DEFAULT | FT_LOAD_NO_SCALE); 887 g_string_append_printf (bf, "<collection unicode=\"U+20\">\n"); 888 g_string_append_printf (bf, "\t<glyph left=\"%f\" right=\"%f\" selected=\"true\">\n", 0.0, face->glyph->metrics.horiAdvance * units); 889 890 bf_data = get_bf_path (charcode, face, units_per_em, err); 891 g_string_append (bf, bf_data->str); 892 893 g_string_append (bf, "\t</glyph>\n"); 894 g_string_append_printf (bf, "</collection>\n"); 895 } 896 897 // glyph outlines 898 for (i = 0; i < face->num_glyphs; i++) { 899 error = FT_Load_Glyph (face, i, FT_LOAD_DEFAULT | FT_LOAD_NO_SCALE); 900 if (error) { 901 g_warning ("Freetype failed to load glyph %d.\n", (int)i); 902 g_warning ("FT_Load_Glyph error %d\n", error); 903 *err = 1; 904 return bf; 905 } 906 907 if (face->glyph->format != ft_glyph_format_outline) { 908 g_warning ("Freetype error no outline found in glyph.\n"); 909 *err = 1; 910 return bf; 911 } 912 913 charcode = get_charcode (face, i); 914 glyph = g_string_new (""); 915 916 if (charcode > 32) { // not control character 917 g_string_append_printf (glyph, "<collection unicode=\"U+%x\">\n", (guint)charcode); 918 g_string_append_printf (glyph, "\t<glyph left=\"%f\" right=\"%f\" selected=\"true\">\n", 0.0, face->glyph->metrics.horiAdvance * units); 919 920 bf_data = get_bf_path (charcode, face, units_per_em, err); 921 g_string_append (glyph, bf_data->str); 922 923 g_string_append (glyph, "\t</glyph>\n"); 924 g_string_append_printf (glyph, "</collection>\n"); 925 } else { 926 g_warning ("Ignoring control character, %d.", (guint)charcode); 927 } 928 929 g_string_append (bf, glyph->str); 930 g_string_free (glyph, TRUE); 931 } 932 933 bird_font_open_font_format_reader_append_kerning (bf, file); 934 935 g_string_append (bf, "</font>\n"); 936 937 return bf; 938 } 939 940 /** Load typeface with freetype2 and return the result as a bf font. 941 * Parameter err will be set to non zero vaule if an error occurs. 942 */ 943 GString* load_freetype_font (char* file, int* err) { 944 GString* bf = NULL; 945 946 FT_Library library; 947 FT_Face face; 948 int error; 949 FT_Glyph glyph; 950 FT_UInt glyph_index; 951 952 error = FT_Init_FreeType (&library); 953 if (error != OK) { 954 g_warning ("Freetype init error %d.\n", error); 955 *err = error; 956 return bf; 957 } 958 959 error = FT_New_Face (library, file, 0, &face); 960 if (error) { 961 g_warning ("Freetype font face error %d\n", error); 962 *err = error; 963 return bf; 964 } 965 966 error = FT_Select_Charmap (face , FT_ENCODING_UNICODE); 967 if (error) { 968 g_warning ("Freetype can not use Unicode, error: %d\n", error); 969 *err = error; 970 return bf; 971 } 972 973 error = FT_Set_Char_Size (face, 0, 800, 300, 300); 974 if (error) { 975 g_warning ("Freetype FT_Set_Char_Size failed, error: %d.\n", error); 976 *err = error; 977 return bf; 978 } 979 980 bf = get_bf_font (face, file, &error); 981 if (error != OK) { 982 g_warning ("Failed to parse font.\n"); 983 *err = error; 984 return bf; 985 } 986 987 FT_Done_Face ( face ); 988 FT_Done_FreeType( library ); 989 990 *err = OK; 991 return bf; 992 } 993 994