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