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