1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 // This file is available under and governed by the GNU General Public 26 // License version 2 only, as published by the Free Software Foundation. 27 // However, the following notice accompanied the original version of this 28 // file: 29 // 30 /* 31 * Copyright © 2009 Red Hat, Inc. 32 * Copyright © 2009 Keith Stribley 33 * Copyright © 2015 Google, Inc. 34 * 35 * This is part of HarfBuzz, a text shaping library. 36 * 37 * Permission is hereby granted, without written agreement and without 38 * license or royalty fees, to use, copy, modify, and distribute this 39 * software and its documentation for any purpose, provided that the 40 * above copyright notice and the following two paragraphs appear in 41 * all copies of this software. 42 * 43 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 44 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 45 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 46 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 47 * DAMAGE. 48 * 49 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 50 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 51 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 52 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 53 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 54 * 55 * Red Hat Author(s): Behdad Esfahbod 56 * Google Author(s): Behdad Esfahbod 57 */ 58 59 #include "hb-private.hh" 60 61 #include "hb-ft.h" 62 63 #include "hb-font-private.hh" 64 65 #include FT_ADVANCES_H 66 #include FT_TRUETYPE_TABLES_H 67 68 69 70 #ifndef HB_DEBUG_FT 71 #define HB_DEBUG_FT (HB_DEBUG+0) 72 #endif 73 74 75 /* TODO: 76 * 77 * In general, this file does a fine job of what it's supposed to do. 78 * There are, however, things that need more work: 79 * 80 * - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy. 81 * Have not investigated. 82 * 83 * - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything 84 * would work fine. However, we also abuse this API for performing in font-space, 85 * but don't pass the correct flags to FreeType. We just abuse the no-hinting mode 86 * for that, such that no rounding etc happens. As such, we don't set ppem, and 87 * pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale 88 * ourselves, like we do in uniscribe, etc. 89 * 90 * - We don't handle / allow for emboldening / obliqueing. 91 * 92 * - In the future, we should add constructors to create fonts in font space? 93 * 94 * - FT_Load_Glyph() is exteremely costly. Do something about it? 95 */ 96 97 98 struct hb_ft_font_t 99 { 100 FT_Face ft_face; 101 int load_flags; 102 bool unref; /* Whether to destroy ft_face when done. */ 103 }; 104 105 static hb_ft_font_t * 106 _hb_ft_font_create (FT_Face ft_face, bool unref) 107 { 108 hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t)); 109 110 if (unlikely (!ft_font)) 111 return NULL; 112 113 ft_font->ft_face = ft_face; 114 ft_font->unref = unref; 115 116 ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; 117 118 return ft_font; 119 } 120 121 static void 122 _hb_ft_font_destroy (hb_ft_font_t *ft_font) 123 { 124 if (ft_font->unref) 125 FT_Done_Face (ft_font->ft_face); 126 127 free (ft_font); 128 } 129 130 /** 131 * hb_ft_font_set_load_flags: 132 * @font: 133 * @load_flags: 134 * 135 * 136 * 137 * Since: 1.0.5 138 **/ 139 void 140 hb_ft_font_set_load_flags (hb_font_t *font, int load_flags) 141 { 142 if (font->immutable) 143 return; 144 145 if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) 146 return; 147 148 hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; 149 150 ft_font->load_flags = load_flags; 151 } 152 153 /** 154 * hb_ft_font_get_load_flags: 155 * @font: 156 * 157 * 158 * 159 * Return value: 160 * Since: 1.0.5 161 **/ 162 int 163 hb_ft_font_get_load_flags (hb_font_t *font) 164 { 165 if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) 166 return 0; 167 168 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; 169 170 return ft_font->load_flags; 171 } 172 173 FT_Face 174 hb_ft_font_get_face (hb_font_t *font) 175 { 176 if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) 177 return NULL; 178 179 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; 180 181 return ft_font->ft_face; 182 } 183 184 185 186 static hb_bool_t 187 hb_ft_get_glyph (hb_font_t *font HB_UNUSED, 188 void *font_data, 189 hb_codepoint_t unicode, 190 hb_codepoint_t variation_selector, 191 hb_codepoint_t *glyph, 192 void *user_data HB_UNUSED) 193 194 { 195 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 196 unsigned int g; 197 198 if (likely (!variation_selector)) 199 g = FT_Get_Char_Index (ft_font->ft_face, unicode); 200 else 201 g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector); 202 203 if (unlikely (!g)) 204 return false; 205 206 *glyph = g; 207 return true; 208 } 209 210 static hb_position_t 211 hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED, 212 void *font_data, 213 hb_codepoint_t glyph, 214 void *user_data HB_UNUSED) 215 { 216 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 217 FT_Fixed v; 218 219 if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v))) 220 return 0; 221 222 if (font->x_scale < 0) 223 v = -v; 224 225 return (v + (1<<9)) >> 10; 226 } 227 228 static hb_position_t 229 hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED, 230 void *font_data, 231 hb_codepoint_t glyph, 232 void *user_data HB_UNUSED) 233 { 234 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 235 FT_Fixed v; 236 237 if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v))) 238 return 0; 239 240 if (font->y_scale < 0) 241 v = -v; 242 243 /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates 244 * have a Y growing upward. Hence the extra negation. */ 245 return (-v + (1<<9)) >> 10; 246 } 247 248 static hb_bool_t 249 hb_ft_get_glyph_h_origin (hb_font_t *font HB_UNUSED, 250 void *font_data HB_UNUSED, 251 hb_codepoint_t glyph HB_UNUSED, 252 hb_position_t *x HB_UNUSED, 253 hb_position_t *y HB_UNUSED, 254 void *user_data HB_UNUSED) 255 { 256 /* We always work in the horizontal coordinates. */ 257 return true; 258 } 259 260 static hb_bool_t 261 hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED, 262 void *font_data, 263 hb_codepoint_t glyph, 264 hb_position_t *x, 265 hb_position_t *y, 266 void *user_data HB_UNUSED) 267 { 268 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 269 FT_Face ft_face = ft_font->ft_face; 270 271 if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) 272 return false; 273 274 /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates 275 * have a Y growing upward. Hence the extra negation. */ 276 *x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX; 277 *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY); 278 279 if (font->x_scale < 0) 280 *x = -*x; 281 if (font->y_scale < 0) 282 *y = -*y; 283 284 return true; 285 } 286 287 static hb_position_t 288 hb_ft_get_glyph_h_kerning (hb_font_t *font, 289 void *font_data, 290 hb_codepoint_t left_glyph, 291 hb_codepoint_t right_glyph, 292 void *user_data HB_UNUSED) 293 { 294 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 295 FT_Vector kerningv; 296 297 FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED; 298 if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv)) 299 return 0; 300 301 return kerningv.x; 302 } 303 304 static hb_position_t 305 hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED, 306 void *font_data HB_UNUSED, 307 hb_codepoint_t top_glyph HB_UNUSED, 308 hb_codepoint_t bottom_glyph HB_UNUSED, 309 void *user_data HB_UNUSED) 310 { 311 /* FreeType API doesn't support vertical kerning */ 312 return 0; 313 } 314 315 static hb_bool_t 316 hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED, 317 void *font_data, 318 hb_codepoint_t glyph, 319 hb_glyph_extents_t *extents, 320 void *user_data HB_UNUSED) 321 { 322 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 323 FT_Face ft_face = ft_font->ft_face; 324 325 if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) 326 return false; 327 328 extents->x_bearing = ft_face->glyph->metrics.horiBearingX; 329 extents->y_bearing = ft_face->glyph->metrics.horiBearingY; 330 extents->width = ft_face->glyph->metrics.width; 331 extents->height = -ft_face->glyph->metrics.height; 332 return true; 333 } 334 335 static hb_bool_t 336 hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED, 337 void *font_data, 338 hb_codepoint_t glyph, 339 unsigned int point_index, 340 hb_position_t *x, 341 hb_position_t *y, 342 void *user_data HB_UNUSED) 343 { 344 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 345 FT_Face ft_face = ft_font->ft_face; 346 347 if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) 348 return false; 349 350 if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)) 351 return false; 352 353 if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points)) 354 return false; 355 356 *x = ft_face->glyph->outline.points[point_index].x; 357 *y = ft_face->glyph->outline.points[point_index].y; 358 359 return true; 360 } 361 362 static hb_bool_t 363 hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED, 364 void *font_data, 365 hb_codepoint_t glyph, 366 char *name, unsigned int size, 367 void *user_data HB_UNUSED) 368 { 369 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 370 371 hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size); 372 if (ret && (size && !*name)) 373 ret = false; 374 375 return ret; 376 } 377 378 static hb_bool_t 379 hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED, 380 void *font_data, 381 const char *name, int len, /* -1 means nul-terminated */ 382 hb_codepoint_t *glyph, 383 void *user_data HB_UNUSED) 384 { 385 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 386 FT_Face ft_face = ft_font->ft_face; 387 388 if (len < 0) 389 *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name); 390 else { 391 /* Make a nul-terminated version. */ 392 char buf[128]; 393 len = MIN (len, (int) sizeof (buf) - 1); 394 strncpy (buf, name, len); 395 buf[len] = '\0'; 396 *glyph = FT_Get_Name_Index (ft_face, buf); 397 } 398 399 if (*glyph == 0) 400 { 401 /* Check whether the given name was actually the name of glyph 0. */ 402 char buf[128]; 403 if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) && 404 len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len)) 405 return true; 406 } 407 408 return *glyph != 0; 409 } 410 411 412 static void 413 _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref) 414 { 415 static const hb_font_funcs_t ft_ffuncs = { 416 HB_OBJECT_HEADER_STATIC, 417 418 true, /* immutable */ 419 420 { 421 #define HB_FONT_FUNC_IMPLEMENT(name) hb_ft_get_##name, 422 HB_FONT_FUNCS_IMPLEMENT_CALLBACKS 423 #undef HB_FONT_FUNC_IMPLEMENT 424 } 425 }; 426 427 hb_font_set_funcs (font, 428 const_cast<hb_font_funcs_t *> (&ft_ffuncs), 429 _hb_ft_font_create (ft_face, unref), 430 (hb_destroy_func_t) _hb_ft_font_destroy); 431 } 432 433 434 static hb_blob_t * 435 reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) 436 { 437 FT_Face ft_face = (FT_Face) user_data; 438 FT_Byte *buffer; 439 FT_ULong length = 0; 440 FT_Error error; 441 442 /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */ 443 444 error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length); 445 if (error) 446 return NULL; 447 448 buffer = (FT_Byte *) malloc (length); 449 if (buffer == NULL) 450 return NULL; 451 452 error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length); 453 if (error) 454 return NULL; 455 456 return hb_blob_create ((const char *) buffer, length, 457 HB_MEMORY_MODE_WRITABLE, 458 buffer, free); 459 } 460 461 /** 462 * hb_ft_face_create: 463 * @ft_face: (destroy destroy) (scope notified): 464 * @destroy: 465 * 466 * 467 * 468 * Return value: (transfer full): 469 * Since: 0.9.2 470 **/ 471 hb_face_t * 472 hb_ft_face_create (FT_Face ft_face, 473 hb_destroy_func_t destroy) 474 { 475 hb_face_t *face; 476 477 if (ft_face->stream->read == NULL) { 478 hb_blob_t *blob; 479 480 blob = hb_blob_create ((const char *) ft_face->stream->base, 481 (unsigned int) ft_face->stream->size, 482 HB_MEMORY_MODE_READONLY, 483 ft_face, destroy); 484 face = hb_face_create (blob, ft_face->face_index); 485 hb_blob_destroy (blob); 486 } else { 487 face = hb_face_create_for_tables (reference_table, ft_face, destroy); 488 } 489 490 hb_face_set_index (face, ft_face->face_index); 491 hb_face_set_upem (face, ft_face->units_per_EM); 492 493 return face; 494 } 495 496 /** 497 * hb_ft_face_create_referenced: 498 * @ft_face: 499 * 500 * 501 * 502 * Return value: (transfer full): 503 * Since: 0.9.38 504 **/ 505 hb_face_t * 506 hb_ft_face_create_referenced (FT_Face ft_face) 507 { 508 FT_Reference_Face (ft_face); 509 return hb_ft_face_create (ft_face, (hb_destroy_func_t) FT_Done_Face); 510 } 511 512 static void 513 hb_ft_face_finalize (FT_Face ft_face) 514 { 515 hb_face_destroy ((hb_face_t *) ft_face->generic.data); 516 } 517 518 /** 519 * hb_ft_face_create_cached: 520 * @ft_face: 521 * 522 * 523 * 524 * Return value: (transfer full): 525 * Since: 0.9.2 526 **/ 527 hb_face_t * 528 hb_ft_face_create_cached (FT_Face ft_face) 529 { 530 if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize)) 531 { 532 if (ft_face->generic.finalizer) 533 ft_face->generic.finalizer (ft_face); 534 535 ft_face->generic.data = hb_ft_face_create (ft_face, NULL); 536 ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize; 537 } 538 539 return hb_face_reference ((hb_face_t *) ft_face->generic.data); 540 } 541 542 543 /** 544 * hb_ft_font_create: 545 * @ft_face: (destroy destroy) (scope notified): 546 * @destroy: 547 * 548 * 549 * 550 * Return value: (transfer full): 551 * Since: 0.9.2 552 **/ 553 hb_font_t * 554 hb_ft_font_create (FT_Face ft_face, 555 hb_destroy_func_t destroy) 556 { 557 hb_font_t *font; 558 hb_face_t *face; 559 560 face = hb_ft_face_create (ft_face, destroy); 561 font = hb_font_create (face); 562 hb_face_destroy (face); 563 _hb_ft_font_set_funcs (font, ft_face, false); 564 hb_font_set_scale (font, 565 (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16), 566 (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16)); 567 #if 0 /* hb-ft works in no-hinting model */ 568 hb_font_set_ppem (font, 569 ft_face->size->metrics.x_ppem, 570 ft_face->size->metrics.y_ppem); 571 #endif 572 573 return font; 574 } 575 576 /** 577 * hb_ft_font_create_referenced: 578 * @ft_face: 579 * 580 * 581 * 582 * Return value: (transfer full): 583 * Since: 0.9.38 584 **/ 585 hb_font_t * 586 hb_ft_font_create_referenced (FT_Face ft_face) 587 { 588 FT_Reference_Face (ft_face); 589 return hb_ft_font_create (ft_face, (hb_destroy_func_t) FT_Done_Face); 590 } 591 592 593 /* Thread-safe, lock-free, FT_Library */ 594 595 static FT_Library ft_library; 596 597 #ifdef HB_USE_ATEXIT 598 static 599 void free_ft_library (void) 600 { 601 FT_Done_FreeType (ft_library); 602 } 603 #endif 604 605 static FT_Library 606 get_ft_library (void) 607 { 608 retry: 609 FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library); 610 611 if (unlikely (!library)) 612 { 613 /* Not found; allocate one. */ 614 if (FT_Init_FreeType (&library)) 615 return NULL; 616 617 if (!hb_atomic_ptr_cmpexch (&ft_library, NULL, library)) { 618 FT_Done_FreeType (library); 619 goto retry; 620 } 621 622 #ifdef HB_USE_ATEXIT 623 atexit (free_ft_library); /* First person registers atexit() callback. */ 624 #endif 625 } 626 627 return library; 628 } 629 630 static void 631 _release_blob (FT_Face ft_face) 632 { 633 hb_blob_destroy ((hb_blob_t *) ft_face->generic.data); 634 } 635 636 void 637 hb_ft_font_set_funcs (hb_font_t *font) 638 { 639 hb_blob_t *blob = hb_face_reference_blob (font->face); 640 unsigned int blob_length; 641 const char *blob_data = hb_blob_get_data (blob, &blob_length); 642 if (unlikely (!blob_length)) 643 DEBUG_MSG (FT, font, "Font face has empty blob"); 644 645 FT_Face ft_face = NULL; 646 FT_Error err = FT_New_Memory_Face (get_ft_library (), 647 (const FT_Byte *) blob_data, 648 blob_length, 649 hb_face_get_index (font->face), 650 &ft_face); 651 652 if (unlikely (err)) { 653 hb_blob_destroy (blob); 654 DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed"); 655 return; 656 } 657 658 FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE); 659 660 FT_Set_Char_Size (ft_face, 661 abs (font->x_scale), abs (font->y_scale), 662 0, 0); 663 #if 0 664 font->x_ppem * 72 * 64 / font->x_scale, 665 font->y_ppem * 72 * 64 / font->y_scale); 666 #endif 667 if (font->x_scale < 0 || font->y_scale < 0) 668 { 669 FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0, 670 0, font->y_scale < 0 ? -1 : +1}; 671 FT_Set_Transform (ft_face, &matrix, NULL); 672 } 673 674 ft_face->generic.data = blob; 675 ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob; 676 677 _hb_ft_font_set_funcs (font, ft_face, true); 678 hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); 679 }