hb-ft.cc (48917B)
1 /* 2 * Copyright © 2009 Red Hat, Inc. 3 * Copyright © 2009 Keith Stribley 4 * Copyright © 2015 Google, Inc. 5 * 6 * This is part of HarfBuzz, a text shaping library. 7 * 8 * Permission is hereby granted, without written agreement and without 9 * license or royalty fees, to use, copy, modify, and distribute this 10 * software and its documentation for any purpose, provided that the 11 * above copyright notice and the following two paragraphs appear in 12 * all copies of this software. 13 * 14 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 15 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 17 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 18 * DAMAGE. 19 * 20 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 21 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 22 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 23 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 24 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 25 * 26 * Red Hat Author(s): Behdad Esfahbod 27 * Google Author(s): Behdad Esfahbod 28 */ 29 30 #include "hb.hh" 31 32 #ifdef HAVE_FREETYPE 33 34 #include "hb-ft.h" 35 36 #include "hb-cache.hh" 37 #include "hb-draw.hh" 38 #include "hb-font.hh" 39 #include "hb-machinery.hh" 40 #include "hb-ot-os2-table.hh" 41 #include "hb-ot-shaper-arabic-pua.hh" 42 #include "hb-paint.hh" 43 44 #include FT_MODULE_H 45 #include FT_ADVANCES_H 46 #include FT_MULTIPLE_MASTERS_H 47 #include FT_OUTLINE_H 48 #include FT_TRUETYPE_TABLES_H 49 #include FT_SYNTHESIS_H 50 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300 51 #include FT_COLOR_H 52 #endif 53 54 55 /** 56 * SECTION:hb-ft 57 * @title: hb-ft 58 * @short_description: FreeType integration 59 * @include: hb-ft.h 60 * 61 * Functions for using HarfBuzz with the FreeType library. 62 * 63 * HarfBuzz supports using FreeType to provide face and 64 * font data. 65 * 66 * <note>Note that FreeType is not thread-safe, therefore these 67 * functions are not thread-safe either.</note> 68 **/ 69 70 71 /* TODO: 72 * 73 * In general, this file does a fine job of what it's supposed to do. 74 * There are, however, things that need more work: 75 * 76 * - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything 77 * would work fine. However, we also abuse this API for performing in font-space, 78 * but don't pass the correct flags to FreeType. We just abuse the no-hinting mode 79 * for that, such that no rounding etc happens. As such, we don't set ppem, and 80 * pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale 81 * ourselves. 82 * 83 * - We don't handle / allow for emboldening / obliqueing. 84 * 85 * - In the future, we should add constructors to create fonts in font space? 86 */ 87 88 89 using hb_ft_advance_cache_t = hb_cache_t<16, 24, 8, false>; 90 91 struct hb_ft_font_t 92 { 93 int load_flags; 94 bool symbol; /* Whether selected cmap is symbol cmap. */ 95 bool unref; /* Whether to destroy ft_face when done. */ 96 bool transform; /* Whether to apply FT_Face's transform. */ 97 98 mutable hb_mutex_t lock; /* Protects members below. */ 99 FT_Face ft_face; 100 mutable hb_atomic_t<unsigned> cached_serial; 101 mutable hb_ft_advance_cache_t advance_cache; 102 }; 103 104 static hb_ft_font_t * 105 _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref) 106 { 107 hb_ft_font_t *ft_font = (hb_ft_font_t *) hb_calloc (1, sizeof (hb_ft_font_t)); 108 if (unlikely (!ft_font)) return nullptr; 109 110 ft_font->lock.init (); 111 ft_font->ft_face = ft_face; 112 ft_font->symbol = symbol; 113 ft_font->unref = unref; 114 115 ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; 116 117 ft_font->cached_serial = UINT_MAX; 118 new (&ft_font->advance_cache) hb_ft_advance_cache_t; 119 120 return ft_font; 121 } 122 123 static void 124 _hb_ft_face_destroy (void *data) 125 { 126 FT_Done_Face ((FT_Face) data); 127 } 128 129 static void 130 _hb_ft_font_destroy (void *data) 131 { 132 hb_ft_font_t *ft_font = (hb_ft_font_t *) data; 133 134 if (ft_font->unref) 135 _hb_ft_face_destroy (ft_font->ft_face); 136 137 ft_font->lock.fini (); 138 139 hb_free (ft_font); 140 } 141 142 143 /* hb_font changed, update FT_Face. */ 144 static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) 145 { 146 if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) 147 return; 148 149 hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; 150 151 float x_mult = 1.f, y_mult = 1.f; 152 153 if (font->x_scale < 0) x_mult = -x_mult; 154 if (font->y_scale < 0) y_mult = -y_mult; 155 156 if (FT_Set_Char_Size (ft_face, 157 abs (font->x_scale), abs (font->y_scale), 158 0, 0 159 #if 0 160 font->x_ppem * 72 * 64 / font->x_scale, 161 font->y_ppem * 72 * 64 / font->y_scale 162 #endif 163 ) && ft_face->num_fixed_sizes) 164 { 165 #ifdef HAVE_FT_GET_TRANSFORM 166 /* Bitmap font, eg. bitmap color emoji. */ 167 /* Pick largest size? */ 168 int x_scale = ft_face->available_sizes[ft_face->num_fixed_sizes - 1].x_ppem; 169 int y_scale = ft_face->available_sizes[ft_face->num_fixed_sizes - 1].y_ppem; 170 FT_Set_Char_Size (ft_face, 171 x_scale, y_scale, 172 0, 0); 173 174 /* This contains the sign that was previously in x_mult/y_mult. */ 175 x_mult = (float) font->x_scale / x_scale; 176 y_mult = (float) font->y_scale / y_scale; 177 #endif 178 } 179 else 180 { /* Shrug */ } 181 182 183 if (x_mult != 1.f || y_mult != 1.f) 184 { 185 FT_Matrix matrix = { (int) roundf (x_mult * (1<<16)), 0, 186 0, (int) roundf (y_mult * (1<<16))}; 187 FT_Set_Transform (ft_face, &matrix, nullptr); 188 ft_font->transform = true; 189 } 190 else 191 FT_Set_Transform (ft_face, nullptr, nullptr); 192 193 #if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR) 194 if (font->has_nonzero_coords) 195 { 196 unsigned int num_coords; 197 const float *coords = hb_font_get_var_coords_design (font, &num_coords); 198 FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed)); 199 if (ft_coords) 200 { 201 for (unsigned int i = 0; i < num_coords; i++) 202 ft_coords[i] = coords[i] * 65536.f; 203 FT_Set_Var_Design_Coordinates (ft_face, num_coords, ft_coords); 204 hb_free (ft_coords); 205 } 206 } 207 else if (font->num_coords) 208 { 209 // Some old versions of FreeType crash if we 210 // call this function on non-variable fonts. 211 FT_Set_Var_Design_Coordinates (ft_face, 0, nullptr); 212 } 213 #endif 214 } 215 216 /* Check if hb_font changed, update FT_Face. */ 217 static inline bool 218 _hb_ft_hb_font_check_changed (hb_font_t *font, 219 const hb_ft_font_t *ft_font) 220 { 221 if (font->serial != ft_font->cached_serial) 222 { 223 hb_lock_t lock (ft_font->lock); 224 _hb_ft_hb_font_changed (font, ft_font->ft_face); 225 ft_font->advance_cache.clear (); 226 ft_font->cached_serial.set_release (font->serial.get_acquire ()); 227 return true; 228 } 229 return false; 230 } 231 232 233 /** 234 * hb_ft_font_set_load_flags: 235 * @font: #hb_font_t to work upon 236 * @load_flags: The FreeType load flags to set 237 * 238 * Sets the FT_Load_Glyph load flags for the specified #hb_font_t. 239 * 240 * For more information, see 241 * <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx> 242 * 243 * This function works with #hb_font_t objects created by 244 * hb_ft_font_create() or hb_ft_font_create_referenced(). 245 * 246 * Since: 1.0.5 247 **/ 248 void 249 hb_ft_font_set_load_flags (hb_font_t *font, int load_flags) 250 { 251 if (hb_object_is_immutable (font)) 252 return; 253 254 if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) 255 return; 256 257 hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; 258 259 ft_font->load_flags = load_flags; 260 } 261 262 /** 263 * hb_ft_font_get_load_flags: 264 * @font: #hb_font_t to work upon 265 * 266 * Fetches the FT_Load_Glyph load flags of the specified #hb_font_t. 267 * 268 * For more information, see 269 * <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx> 270 * 271 * This function works with #hb_font_t objects created by 272 * hb_ft_font_create() or hb_ft_font_create_referenced(). 273 * 274 * Return value: FT_Load_Glyph flags found, or 0 275 * 276 * Since: 1.0.5 277 **/ 278 int 279 hb_ft_font_get_load_flags (hb_font_t *font) 280 { 281 if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) 282 return 0; 283 284 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; 285 286 return ft_font->load_flags; 287 } 288 289 /** 290 * hb_ft_font_get_ft_face: (skip) 291 * @font: #hb_font_t to work upon 292 * 293 * Fetches the FT_Face associated with the specified #hb_font_t 294 * font object. 295 * 296 * This function works with #hb_font_t objects created by 297 * hb_ft_font_create() or hb_ft_font_create_referenced(). 298 * 299 * Return value: (nullable): the FT_Face found or `NULL` 300 * 301 * Since: 10.4.0 302 **/ 303 FT_Face 304 hb_ft_font_get_ft_face (hb_font_t *font) 305 { 306 if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) 307 return nullptr; 308 309 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; 310 311 return ft_font->ft_face; 312 } 313 314 #ifndef HB_DISABLE_DEPRECATED 315 316 /** 317 * hb_ft_font_get_face: (skip) 318 * @font: #hb_font_t to work upon 319 * 320 * Fetches the FT_Face associated with the specified #hb_font_t 321 * font object. 322 * 323 * This function works with #hb_font_t objects created by 324 * hb_ft_font_create() or hb_ft_font_create_referenced(). 325 * 326 * Return value: (nullable): the FT_Face found or `NULL` 327 * 328 * Since: 0.9.2 329 * Deprecated: 10.4.0: Use hb_ft_font_get_ft_face() instead. 330 **/ 331 FT_Face 332 hb_ft_font_get_face (hb_font_t *font) 333 { 334 return hb_ft_font_get_ft_face (font); 335 } 336 337 #endif 338 339 /** 340 * hb_ft_font_lock_face: (skip) 341 * @font: #hb_font_t to work upon 342 * 343 * Gets the FT_Face associated with @font. 344 * 345 * This face will be kept around and access to the FT_Face object 346 * from other HarfBuzz API wil be blocked until you call hb_ft_font_unlock_face(). 347 * 348 * This function works with #hb_font_t objects created by 349 * hb_ft_font_create() or hb_ft_font_create_referenced(). 350 * 351 * Return value: (nullable) (transfer none): the FT_Face associated with @font or `NULL` 352 * Since: 2.6.5 353 **/ 354 FT_Face 355 hb_ft_font_lock_face (hb_font_t *font) 356 { 357 if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) 358 return nullptr; 359 360 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; 361 362 ft_font->lock.lock (); 363 364 return ft_font->ft_face; 365 } 366 367 /** 368 * hb_ft_font_unlock_face: (skip) 369 * @font: #hb_font_t to work upon 370 * 371 * Releases an FT_Face previously obtained with hb_ft_font_lock_face(). 372 * 373 * Since: 2.6.5 374 **/ 375 void 376 hb_ft_font_unlock_face (hb_font_t *font) 377 { 378 if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) 379 return; 380 381 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; 382 383 ft_font->lock.unlock (); 384 } 385 386 387 static hb_bool_t 388 hb_ft_get_nominal_glyph (hb_font_t *font, 389 void *font_data, 390 hb_codepoint_t unicode, 391 hb_codepoint_t *glyph, 392 void *user_data HB_UNUSED) 393 { 394 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 395 hb_lock_t lock (ft_font->lock); 396 unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode); 397 398 if (unlikely (!g)) 399 { 400 if (unlikely (ft_font->symbol)) 401 { 402 switch ((unsigned) font->face->table.OS2->get_font_page ()) { 403 case OT::OS2::font_page_t::FONT_PAGE_NONE: 404 if (unicode <= 0x00FFu) 405 /* For symbol-encoded OpenType fonts, we duplicate the 406 * U+F000..F0FF range at U+0000..U+00FF. That's what 407 * Windows seems to do, and that's hinted about at: 408 * https://docs.microsoft.com/en-us/typography/opentype/spec/recom 409 * under "Non-Standard (Symbol) Fonts". */ 410 g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode); 411 break; 412 #ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK 413 case OT::OS2::font_page_t::FONT_PAGE_SIMP_ARABIC: 414 g = FT_Get_Char_Index (ft_font->ft_face, _hb_arabic_pua_simp_map (unicode)); 415 break; 416 case OT::OS2::font_page_t::FONT_PAGE_TRAD_ARABIC: 417 g = FT_Get_Char_Index (ft_font->ft_face, _hb_arabic_pua_trad_map (unicode)); 418 break; 419 #endif 420 default: 421 break; 422 } 423 if (!g) 424 return false; 425 } 426 else 427 return false; 428 } 429 430 *glyph = g; 431 return true; 432 } 433 434 static unsigned int 435 hb_ft_get_nominal_glyphs (hb_font_t *font HB_UNUSED, 436 void *font_data, 437 unsigned int count, 438 const hb_codepoint_t *first_unicode, 439 unsigned int unicode_stride, 440 hb_codepoint_t *first_glyph, 441 unsigned int glyph_stride, 442 void *user_data HB_UNUSED) 443 { 444 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 445 hb_lock_t lock (ft_font->lock); 446 unsigned int done; 447 for (done = 0; 448 done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode)); 449 done++) 450 { 451 first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride); 452 first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); 453 } 454 /* We don't need to do ft_font->symbol dance here, since HB calls the singular 455 * nominal_glyph() for what we don't handle here. */ 456 return done; 457 } 458 459 460 static hb_bool_t 461 hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED, 462 void *font_data, 463 hb_codepoint_t unicode, 464 hb_codepoint_t variation_selector, 465 hb_codepoint_t *glyph, 466 void *user_data HB_UNUSED) 467 { 468 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 469 hb_lock_t lock (ft_font->lock); 470 unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector); 471 472 if (unlikely (!g)) 473 return false; 474 475 *glyph = g; 476 return true; 477 } 478 479 static void 480 hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, 481 unsigned count, 482 const hb_codepoint_t *first_glyph, 483 unsigned glyph_stride, 484 hb_position_t *first_advance, 485 unsigned advance_stride, 486 void *user_data HB_UNUSED) 487 { 488 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 489 _hb_ft_hb_font_check_changed (font, ft_font); 490 491 hb_lock_t lock (ft_font->lock); 492 FT_Face ft_face = ft_font->ft_face; 493 int load_flags = ft_font->load_flags; 494 float x_mult; 495 #ifdef HAVE_FT_GET_TRANSFORM 496 if (ft_font->transform) 497 { 498 FT_Matrix matrix; 499 FT_Get_Transform (ft_face, &matrix, nullptr); 500 x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; 501 x_mult *= font->x_scale < 0 ? -1 : +1; 502 } 503 else 504 #endif 505 { 506 x_mult = font->x_scale < 0 ? -1 : +1; 507 } 508 509 for (unsigned int i = 0; i < count; i++) 510 { 511 FT_Fixed v = 0; 512 hb_codepoint_t glyph = *first_glyph; 513 514 unsigned int cv; 515 if (ft_font->advance_cache.get (glyph, &cv)) 516 v = cv; 517 else 518 { 519 FT_Get_Advance (ft_face, glyph, load_flags, &v); 520 /* Work around bug that FreeType seems to return negative advance 521 * for variable-set fonts if x_scale is negative! */ 522 v = abs (v); 523 v = (int) (v * x_mult + (1<<9)) >> 10; 524 ft_font->advance_cache.set (glyph, v); 525 } 526 527 *first_advance = v; 528 first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); 529 first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); 530 } 531 } 532 533 #ifndef HB_NO_VERTICAL 534 static hb_position_t 535 hb_ft_get_glyph_v_advance (hb_font_t *font, 536 void *font_data, 537 hb_codepoint_t glyph, 538 void *user_data HB_UNUSED) 539 { 540 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 541 _hb_ft_hb_font_check_changed (font, ft_font); 542 543 hb_lock_t lock (ft_font->lock); 544 FT_Fixed v; 545 float y_mult; 546 #ifdef HAVE_FT_GET_TRANSFORM 547 if (ft_font->transform) 548 { 549 FT_Matrix matrix; 550 FT_Get_Transform (ft_font->ft_face, &matrix, nullptr); 551 y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; 552 y_mult *= font->y_scale < 0 ? -1 : +1; 553 } 554 else 555 #endif 556 { 557 y_mult = font->y_scale < 0 ? -1 : +1; 558 } 559 560 if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v))) 561 return 0; 562 563 /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates 564 * have a Y growing upward. Hence the extra negation. */ 565 v = ((-v + (1<<9)) >> 10); 566 567 return (hb_position_t) (y_mult * v); 568 } 569 #endif 570 571 #ifndef HB_NO_VERTICAL 572 static hb_bool_t 573 hb_ft_get_glyph_v_origin (hb_font_t *font, 574 void *font_data, 575 hb_codepoint_t glyph, 576 hb_position_t *x, 577 hb_position_t *y, 578 void *user_data HB_UNUSED) 579 { 580 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 581 _hb_ft_hb_font_check_changed (font, ft_font); 582 583 hb_lock_t lock (ft_font->lock); 584 FT_Face ft_face = ft_font->ft_face; 585 float x_mult, y_mult; 586 #ifdef HAVE_FT_GET_TRANSFORM 587 if (ft_font->transform) 588 { 589 FT_Matrix matrix; 590 FT_Get_Transform (ft_face, &matrix, nullptr); 591 x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; 592 x_mult *= font->x_scale < 0 ? -1 : +1; 593 y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; 594 y_mult *= font->y_scale < 0 ? -1 : +1; 595 } 596 else 597 #endif 598 { 599 x_mult = font->x_scale < 0 ? -1 : +1; 600 y_mult = font->y_scale < 0 ? -1 : +1; 601 } 602 603 if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) 604 return false; 605 606 /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates 607 * have a Y growing upward. Hence the extra negation. */ 608 *x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX; 609 *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY); 610 611 *x = (hb_position_t) (x_mult * *x); 612 *y = (hb_position_t) (y_mult * *y); 613 614 return true; 615 } 616 #endif 617 618 #ifndef HB_NO_OT_SHAPE_FALLBACK 619 static hb_position_t 620 hb_ft_get_glyph_h_kerning (hb_font_t *font, 621 void *font_data, 622 hb_codepoint_t left_glyph, 623 hb_codepoint_t right_glyph, 624 void *user_data HB_UNUSED) 625 { 626 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 627 _hb_ft_hb_font_check_changed (font, ft_font); 628 629 hb_lock_t lock (ft_font->lock); 630 FT_Vector kerningv; 631 632 FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED; 633 if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv)) 634 return 0; 635 636 return kerningv.x; 637 } 638 #endif 639 640 static bool 641 hb_ft_is_colr_glyph (hb_font_t *font, 642 void *font_data, 643 hb_codepoint_t gid) 644 { 645 #ifndef HB_NO_PAINT 646 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300 647 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 648 FT_Face ft_face = ft_font->ft_face; 649 650 651 /* COLRv1 */ 652 FT_OpaquePaint paint = {0}; 653 if (FT_Get_Color_Glyph_Paint (ft_face, gid, 654 FT_COLOR_NO_ROOT_TRANSFORM, 655 &paint)) 656 return true; 657 658 /* COLRv0 */ 659 FT_LayerIterator iterator; 660 FT_UInt layer_glyph_index; 661 FT_UInt layer_color_index; 662 iterator.p = NULL; 663 if (FT_Get_Color_Glyph_Layer (ft_face, 664 gid, 665 &layer_glyph_index, 666 &layer_color_index, 667 &iterator)) 668 return true; 669 #endif 670 #endif 671 672 return false; 673 } 674 675 static hb_bool_t 676 hb_ft_get_glyph_extents (hb_font_t *font, 677 void *font_data, 678 hb_codepoint_t glyph, 679 hb_glyph_extents_t *extents, 680 void *user_data HB_UNUSED) 681 { 682 // FreeType doesn't return COLR glyph extents. 683 if (hb_ft_is_colr_glyph (font, font_data, glyph)) 684 return false; 685 686 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 687 _hb_ft_hb_font_check_changed (font, ft_font); 688 689 hb_lock_t lock (ft_font->lock); 690 FT_Face ft_face = ft_font->ft_face; 691 float x_mult, y_mult; 692 693 #ifdef HAVE_FT_GET_TRANSFORM 694 if (ft_font->transform) 695 { 696 FT_Matrix matrix; 697 FT_Get_Transform (ft_face, &matrix, nullptr); 698 x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; 699 x_mult *= font->x_scale < 0 ? -1 : +1; 700 y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; 701 y_mult *= font->y_scale < 0 ? -1 : +1; 702 } 703 else 704 #endif 705 { 706 x_mult = font->x_scale < 0 ? -1 : +1; 707 y_mult = font->y_scale < 0 ? -1 : +1; 708 } 709 710 if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) 711 return false; 712 713 /* Copied from hb_font_t::scale_glyph_extents. */ 714 715 float x1 = x_mult * ft_face->glyph->metrics.horiBearingX; 716 float y1 = y_mult * ft_face->glyph->metrics.horiBearingY; 717 float x2 = x1 + x_mult * ft_face->glyph->metrics.width; 718 float y2 = y1 + y_mult * -ft_face->glyph->metrics.height; 719 720 extents->x_bearing = roundf (x1); 721 extents->y_bearing = roundf (y1); 722 extents->width = roundf (x2) - extents->x_bearing; 723 extents->height = roundf (y2) - extents->y_bearing; 724 725 return true; 726 } 727 728 static hb_bool_t 729 hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED, 730 void *font_data, 731 hb_codepoint_t glyph, 732 unsigned int point_index, 733 hb_position_t *x, 734 hb_position_t *y, 735 void *user_data HB_UNUSED) 736 { 737 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 738 _hb_ft_hb_font_check_changed (font, ft_font); 739 740 hb_lock_t lock (ft_font->lock); 741 FT_Face ft_face = ft_font->ft_face; 742 743 if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) 744 return false; 745 746 if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)) 747 return false; 748 749 if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points)) 750 return false; 751 752 *x = ft_face->glyph->outline.points[point_index].x; 753 *y = ft_face->glyph->outline.points[point_index].y; 754 755 return true; 756 } 757 758 static hb_bool_t 759 hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED, 760 void *font_data, 761 hb_codepoint_t glyph, 762 char *name, unsigned int size, 763 void *user_data HB_UNUSED) 764 { 765 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 766 hb_lock_t lock (ft_font->lock); 767 FT_Face ft_face = ft_font->ft_face; 768 769 hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size); 770 if (ret && (size && !*name)) 771 ret = false; 772 773 return ret; 774 } 775 776 static hb_bool_t 777 hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED, 778 void *font_data, 779 const char *name, int len, /* -1 means nul-terminated */ 780 hb_codepoint_t *glyph, 781 void *user_data HB_UNUSED) 782 { 783 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 784 hb_lock_t lock (ft_font->lock); 785 FT_Face ft_face = ft_font->ft_face; 786 787 if (len < 0) 788 *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name); 789 else { 790 /* Make a nul-terminated version. */ 791 char buf[128]; 792 len = hb_min (len, (int) sizeof (buf) - 1); 793 strncpy (buf, name, len); 794 buf[len] = '\0'; 795 *glyph = FT_Get_Name_Index (ft_face, buf); 796 } 797 798 if (*glyph == 0) 799 { 800 /* Check whether the given name was actually the name of glyph 0. */ 801 char buf[128]; 802 if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) && 803 len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len)) 804 return true; 805 } 806 807 return *glyph != 0; 808 } 809 810 static hb_bool_t 811 hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, 812 void *font_data, 813 hb_font_extents_t *metrics, 814 void *user_data HB_UNUSED) 815 { 816 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 817 _hb_ft_hb_font_check_changed (font, ft_font); 818 819 hb_lock_t lock (ft_font->lock); 820 FT_Face ft_face = ft_font->ft_face; 821 float y_mult; 822 #ifdef HAVE_FT_GET_TRANSFORM 823 if (ft_font->transform) 824 { 825 FT_Matrix matrix; 826 FT_Get_Transform (ft_face, &matrix, nullptr); 827 y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; 828 y_mult *= font->y_scale < 0 ? -1 : +1; 829 } 830 else 831 #endif 832 { 833 y_mult = font->y_scale < 0 ? -1 : +1; 834 } 835 836 if (ft_face->units_per_EM != 0) 837 { 838 metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale); 839 metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale); 840 metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender); 841 } 842 else 843 { 844 /* Bitmap-only font, eg. color bitmap font. */ 845 metrics->ascender = ft_face->size->metrics.ascender; 846 metrics->descender = ft_face->size->metrics.descender; 847 metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender); 848 } 849 850 metrics->ascender = (hb_position_t) (y_mult * metrics->ascender); 851 metrics->descender = (hb_position_t) (y_mult * metrics->descender); 852 metrics->line_gap = (hb_position_t) (y_mult * metrics->line_gap); 853 854 return true; 855 } 856 857 #ifndef HB_NO_DRAW 858 859 static int 860 _hb_ft_move_to (const FT_Vector *to, 861 void *arg) 862 { 863 hb_draw_session_t *drawing = (hb_draw_session_t *) arg; 864 drawing->move_to (to->x, to->y); 865 return FT_Err_Ok; 866 } 867 868 static int 869 _hb_ft_line_to (const FT_Vector *to, 870 void *arg) 871 { 872 hb_draw_session_t *drawing = (hb_draw_session_t *) arg; 873 drawing->line_to (to->x, to->y); 874 return FT_Err_Ok; 875 } 876 877 static int 878 _hb_ft_conic_to (const FT_Vector *control, 879 const FT_Vector *to, 880 void *arg) 881 { 882 hb_draw_session_t *drawing = (hb_draw_session_t *) arg; 883 drawing->quadratic_to (control->x, control->y, 884 to->x, to->y); 885 return FT_Err_Ok; 886 } 887 888 static int 889 _hb_ft_cubic_to (const FT_Vector *control1, 890 const FT_Vector *control2, 891 const FT_Vector *to, 892 void *arg) 893 { 894 hb_draw_session_t *drawing = (hb_draw_session_t *) arg; 895 drawing->cubic_to (control1->x, control1->y, 896 control2->x, control2->y, 897 to->x, to->y); 898 return FT_Err_Ok; 899 } 900 901 static hb_bool_t 902 hb_ft_draw_glyph_or_fail (hb_font_t *font, 903 void *font_data, 904 hb_codepoint_t glyph, 905 hb_draw_funcs_t *draw_funcs, void *draw_data, 906 void *user_data HB_UNUSED) 907 { 908 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 909 _hb_ft_hb_font_check_changed (font, ft_font); 910 911 hb_lock_t lock (ft_font->lock); 912 FT_Face ft_face = ft_font->ft_face; 913 914 if (unlikely (FT_Load_Glyph (ft_face, glyph, 915 FT_LOAD_NO_BITMAP | ft_font->load_flags))) 916 return false; 917 918 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) 919 return false; 920 921 const FT_Outline_Funcs outline_funcs = { 922 _hb_ft_move_to, 923 _hb_ft_line_to, 924 _hb_ft_conic_to, 925 _hb_ft_cubic_to, 926 0, /* shift */ 927 0, /* delta */ 928 }; 929 930 hb_draw_session_t draw_session {draw_funcs, draw_data}; 931 932 FT_Outline_Decompose (&ft_face->glyph->outline, 933 &outline_funcs, 934 &draw_session); 935 936 return true; 937 } 938 #endif 939 940 #ifndef HB_NO_PAINT 941 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300 942 943 #include "hb-ft-colr.hh" 944 945 static hb_bool_t 946 hb_ft_paint_glyph_or_fail (hb_font_t *font, 947 void *font_data, 948 hb_codepoint_t gid, 949 hb_paint_funcs_t *paint_funcs, void *paint_data, 950 unsigned int palette_index, 951 hb_color_t foreground, 952 void *user_data) 953 { 954 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 955 _hb_ft_hb_font_check_changed (font, ft_font); 956 957 hb_lock_t lock (ft_font->lock); 958 FT_Face ft_face = ft_font->ft_face; 959 960 FT_Long load_flags = ft_font->load_flags | FT_LOAD_COLOR; 961 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21301 962 load_flags |= FT_LOAD_NO_SVG; 963 #endif 964 965 /* We release the lock before calling into glyph callbacks, such that 966 * eg. draw API can call back into the face.*/ 967 968 if (unlikely (FT_Load_Glyph (ft_face, gid, load_flags))) 969 return false; 970 971 if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) 972 { 973 if (hb_ft_paint_glyph_colr (font, font_data, gid, 974 paint_funcs, paint_data, 975 palette_index, foreground, 976 user_data)) 977 return true; 978 979 // Outline glyph 980 return false; 981 } 982 983 auto *glyph = ft_face->glyph; 984 if (glyph->format == FT_GLYPH_FORMAT_BITMAP) 985 { 986 bool ret = false; 987 auto &bitmap = glyph->bitmap; 988 if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) 989 { 990 if (bitmap.pitch != (signed) bitmap.width * 4) 991 return ret; 992 993 ft_font->lock.unlock (); 994 995 hb_blob_t *blob = hb_blob_create ((const char *) bitmap.buffer, 996 bitmap.pitch * bitmap.rows, 997 HB_MEMORY_MODE_DUPLICATE, 998 nullptr, nullptr); 999 1000 hb_glyph_extents_t extents; 1001 if (!font->get_glyph_extents (gid, &extents, false)) 1002 goto out; 1003 1004 if (paint_funcs->image (paint_data, 1005 blob, 1006 bitmap.width, 1007 bitmap.rows, 1008 HB_PAINT_IMAGE_FORMAT_BGRA, 1009 0.f, 1010 &extents)) 1011 ret = true; 1012 1013 out: 1014 hb_blob_destroy (blob); 1015 ft_font->lock.lock (); 1016 } 1017 1018 return ret; 1019 } 1020 return false; 1021 } 1022 #endif 1023 #endif 1024 1025 1026 static inline void free_static_ft_funcs (); 1027 1028 static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t> 1029 { 1030 static hb_font_funcs_t *create () 1031 { 1032 hb_font_funcs_t *funcs = hb_font_funcs_create (); 1033 1034 hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr); 1035 hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr); 1036 hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr); 1037 1038 hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr); 1039 hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr); 1040 1041 #ifndef HB_NO_VERTICAL 1042 hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr); 1043 hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr); 1044 #endif 1045 1046 #ifndef HB_NO_OT_SHAPE_FALLBACK 1047 hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr); 1048 #endif 1049 hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr); 1050 hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr); 1051 hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr); 1052 hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr); 1053 1054 #ifndef HB_NO_DRAW 1055 hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_ft_draw_glyph_or_fail, nullptr, nullptr); 1056 #endif 1057 1058 #ifndef HB_NO_PAINT 1059 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300 1060 hb_font_funcs_set_paint_glyph_or_fail_func (funcs, hb_ft_paint_glyph_or_fail, nullptr, nullptr); 1061 #endif 1062 #endif 1063 1064 hb_font_funcs_make_immutable (funcs); 1065 1066 hb_atexit (free_static_ft_funcs); 1067 1068 return funcs; 1069 } 1070 } static_ft_funcs; 1071 1072 static inline 1073 void free_static_ft_funcs () 1074 { 1075 static_ft_funcs.free_instance (); 1076 } 1077 1078 static hb_font_funcs_t * 1079 _hb_ft_get_font_funcs () 1080 { 1081 return static_ft_funcs.get_unconst (); 1082 } 1083 1084 static void 1085 _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref) 1086 { 1087 bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL; 1088 1089 hb_ft_font_t *ft_font = _hb_ft_font_create (ft_face, symbol, unref); 1090 if (unlikely (!ft_font)) return; 1091 1092 hb_font_set_funcs (font, 1093 _hb_ft_get_font_funcs (), 1094 ft_font, 1095 _hb_ft_font_destroy); 1096 } 1097 1098 1099 static hb_blob_t * 1100 _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) 1101 { 1102 FT_Face ft_face = (FT_Face) user_data; 1103 FT_Byte *buffer; 1104 FT_ULong length = 0; 1105 FT_Error error; 1106 1107 /* In new FreeType, a tag value of 1 loads the SFNT table directory. Reject it. */ 1108 if (tag == 1) 1109 return nullptr; 1110 1111 /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */ 1112 1113 error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length); 1114 if (error) 1115 return nullptr; 1116 1117 buffer = (FT_Byte *) hb_malloc (length); 1118 if (!buffer) 1119 return nullptr; 1120 1121 error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length); 1122 if (error) 1123 { 1124 hb_free (buffer); 1125 return nullptr; 1126 } 1127 1128 return hb_blob_create ((const char *) buffer, length, 1129 HB_MEMORY_MODE_WRITABLE, 1130 buffer, hb_free); 1131 } 1132 1133 static unsigned 1134 _hb_ft_get_table_tags (const hb_face_t *face HB_UNUSED, 1135 unsigned int start_offset, 1136 unsigned int *table_count, 1137 hb_tag_t *table_tags, 1138 void *user_data) 1139 { 1140 FT_Face ft_face = (FT_Face) user_data; 1141 1142 FT_ULong population = 0; 1143 FT_Sfnt_Table_Info (ft_face, 1144 0, // table_index; ignored 1145 nullptr, 1146 &population); 1147 1148 if (!table_count) 1149 return population; 1150 else 1151 *table_count = 0; 1152 1153 if (unlikely (start_offset >= population)) 1154 return population; 1155 1156 unsigned end_offset = hb_min (start_offset + *table_count, (unsigned) population); 1157 if (unlikely (end_offset < start_offset)) 1158 return population; 1159 1160 *table_count = end_offset - start_offset; 1161 for (unsigned i = start_offset; i < end_offset; i++) 1162 { 1163 FT_ULong tag = 0, length; 1164 FT_Sfnt_Table_Info (ft_face, i, &tag, &length); 1165 table_tags[i - start_offset] = tag; 1166 } 1167 1168 return population; 1169 } 1170 1171 1172 /** 1173 * hb_ft_face_create: 1174 * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon 1175 * @destroy: (nullable): A callback to call when the face object is not needed anymore 1176 * 1177 * Creates an #hb_face_t face object from the specified FT_Face. 1178 * 1179 * Note that this is using the FT_Face object just to get at the underlying 1180 * font data, and fonts created from the returned #hb_face_t will use the native 1181 * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them. 1182 * 1183 * This variant of the function does not provide any life-cycle management. 1184 * 1185 * Most client programs should use hb_ft_face_create_referenced() 1186 * (or, perhaps, hb_ft_face_create_cached()) instead. 1187 * 1188 * If you know you have valid reasons not to use hb_ft_face_create_referenced(), 1189 * then it is the client program's responsibility to destroy @ft_face 1190 * after the #hb_face_t face object has been destroyed. 1191 * 1192 * Return value: (transfer full): the new #hb_face_t face object 1193 * 1194 * Since: 0.9.2 1195 **/ 1196 hb_face_t * 1197 hb_ft_face_create (FT_Face ft_face, 1198 hb_destroy_func_t destroy) 1199 { 1200 hb_face_t *face; 1201 1202 if (!ft_face->stream->read) { 1203 hb_blob_t *blob; 1204 1205 blob = hb_blob_create ((const char *) ft_face->stream->base, 1206 (unsigned int) ft_face->stream->size, 1207 HB_MEMORY_MODE_READONLY, 1208 ft_face, destroy); 1209 face = hb_face_create (blob, ft_face->face_index); 1210 hb_blob_destroy (blob); 1211 } else { 1212 face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy); 1213 hb_face_set_get_table_tags_func (face, _hb_ft_get_table_tags, ft_face, nullptr); 1214 } 1215 1216 hb_face_set_index (face, ft_face->face_index); 1217 hb_face_set_upem (face, ft_face->units_per_EM); 1218 1219 return face; 1220 } 1221 1222 /** 1223 * hb_ft_face_create_referenced: 1224 * @ft_face: FT_Face to work upon 1225 * 1226 * Creates an #hb_face_t face object from the specified FT_Face. 1227 * 1228 * Note that this is using the FT_Face object just to get at the underlying 1229 * font data, and fonts created from the returned #hb_face_t will use the native 1230 * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them. 1231 * 1232 * This is the preferred variant of the hb_ft_face_create* 1233 * function family, because it calls FT_Reference_Face() on @ft_face, 1234 * ensuring that @ft_face remains alive as long as the resulting 1235 * #hb_face_t face object remains alive. Also calls FT_Done_Face() 1236 * when the #hb_face_t face object is destroyed. 1237 * 1238 * Use this version unless you know you have good reasons not to. 1239 * 1240 * Return value: (transfer full): the new #hb_face_t face object 1241 * 1242 * Since: 0.9.38 1243 **/ 1244 hb_face_t * 1245 hb_ft_face_create_referenced (FT_Face ft_face) 1246 { 1247 FT_Reference_Face (ft_face); 1248 return hb_ft_face_create (ft_face, _hb_ft_face_destroy); 1249 } 1250 1251 static void 1252 hb_ft_face_finalize (void *arg) 1253 { 1254 FT_Face ft_face = (FT_Face) arg; 1255 hb_face_destroy ((hb_face_t *) ft_face->generic.data); 1256 } 1257 1258 /** 1259 * hb_ft_face_create_cached: 1260 * @ft_face: FT_Face to work upon 1261 * 1262 * Creates an #hb_face_t face object from the specified FT_Face. 1263 * 1264 * Note that this is using the FT_Face object just to get at the underlying 1265 * font data, and fonts created from the returned #hb_face_t will use the native 1266 * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them. 1267 * 1268 * This variant of the function caches the newly created #hb_face_t 1269 * face object, using the @generic pointer of @ft_face. Subsequent function 1270 * calls that are passed the same @ft_face parameter will have the same 1271 * #hb_face_t returned to them, and that #hb_face_t will be correctly 1272 * reference counted. 1273 * 1274 * However, client programs are still responsible for destroying 1275 * @ft_face after the last #hb_face_t face object has been destroyed. 1276 * 1277 * Return value: (transfer full): the new #hb_face_t face object 1278 * 1279 * Since: 0.9.2 1280 **/ 1281 hb_face_t * 1282 hb_ft_face_create_cached (FT_Face ft_face) 1283 { 1284 if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != hb_ft_face_finalize)) 1285 { 1286 if (ft_face->generic.finalizer) 1287 ft_face->generic.finalizer (ft_face); 1288 1289 ft_face->generic.data = hb_ft_face_create (ft_face, nullptr); 1290 ft_face->generic.finalizer = hb_ft_face_finalize; 1291 } 1292 1293 return hb_face_reference ((hb_face_t *) ft_face->generic.data); 1294 } 1295 1296 /** 1297 * hb_ft_font_create: 1298 * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon 1299 * @destroy: (nullable): A callback to call when the font object is not needed anymore 1300 * 1301 * Creates an #hb_font_t font object from the specified FT_Face. 1302 * 1303 * <note>Note: You must set the face size on @ft_face before calling 1304 * hb_ft_font_create() on it. HarfBuzz assumes size is always set and will 1305 * access `size` member of FT_Face unconditionally.</note> 1306 * 1307 * This variant of the function does not provide any life-cycle management. 1308 * 1309 * Most client programs should use hb_ft_font_create_referenced() 1310 * instead. 1311 * 1312 * If you know you have valid reasons not to use hb_ft_font_create_referenced(), 1313 * then it is the client program's responsibility to destroy @ft_face 1314 * only after the #hb_font_t font object has been destroyed. 1315 * 1316 * HarfBuzz will use the @destroy callback on the #hb_font_t font object 1317 * if it is supplied when you use this function. However, even if @destroy 1318 * is provided, it is the client program's responsibility to destroy @ft_face, 1319 * and it is the client program's responsibility to ensure that @ft_face is 1320 * destroyed only after the #hb_font_t font object has been destroyed. 1321 * 1322 * Return value: (transfer full): the new #hb_font_t font object 1323 * 1324 * Since: 0.9.2 1325 **/ 1326 hb_font_t * 1327 hb_ft_font_create (FT_Face ft_face, 1328 hb_destroy_func_t destroy) 1329 { 1330 hb_font_t *font; 1331 hb_face_t *face; 1332 1333 face = hb_ft_face_create (ft_face, destroy); 1334 font = hb_font_create (face); 1335 hb_face_destroy (face); 1336 _hb_ft_font_set_funcs (font, ft_face, false); 1337 hb_ft_font_changed (font); 1338 return font; 1339 } 1340 1341 /** 1342 * hb_ft_font_changed: 1343 * @font: #hb_font_t to work upon 1344 * 1345 * Refreshes the state of @font when the underlying FT_Face has changed. 1346 * This function should be called after changing the size or 1347 * variation-axis settings on the FT_Face. 1348 * 1349 * Since: 1.0.5 1350 **/ 1351 void 1352 hb_ft_font_changed (hb_font_t *font) 1353 { 1354 if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) 1355 return; 1356 1357 hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; 1358 1359 FT_Face ft_face = ft_font->ft_face; 1360 1361 hb_font_set_scale (font, 1362 (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16), 1363 (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16)); 1364 #if 0 /* hb-ft works in no-hinting model */ 1365 hb_font_set_ppem (font, 1366 ft_face->size->metrics.x_ppem, 1367 ft_face->size->metrics.y_ppem); 1368 #endif 1369 1370 #if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR) 1371 FT_MM_Var *mm_var = nullptr; 1372 if (!FT_Get_MM_Var (ft_face, &mm_var)) 1373 { 1374 FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (mm_var->num_axis, sizeof (FT_Fixed)); 1375 int *coords = (int *) hb_calloc (mm_var->num_axis, sizeof (int)); 1376 if (coords && ft_coords) 1377 { 1378 if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords)) 1379 { 1380 bool nonzero = false; 1381 1382 for (unsigned int i = 0; i < mm_var->num_axis; ++i) 1383 { 1384 coords[i] = (ft_coords[i] + 2) >> 2; 1385 nonzero = nonzero || coords[i]; 1386 } 1387 1388 if (nonzero) 1389 hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis); 1390 else 1391 hb_font_set_var_coords_normalized (font, nullptr, 0); 1392 } 1393 } 1394 hb_free (coords); 1395 hb_free (ft_coords); 1396 #ifdef HAVE_FT_DONE_MM_VAR 1397 FT_Done_MM_Var (ft_face->glyph->library, mm_var); 1398 #else 1399 hb_free (mm_var); 1400 #endif 1401 } 1402 #endif 1403 1404 ft_font->advance_cache.clear (); 1405 ft_font->cached_serial = font->serial; 1406 } 1407 1408 /** 1409 * hb_ft_hb_font_changed: 1410 * @font: #hb_font_t to work upon 1411 * 1412 * Refreshes the state of the underlying FT_Face of @font when the hb_font_t 1413 * @font has changed. 1414 * This function should be called after changing the size or 1415 * variation-axis settings on the @font. 1416 * This call is fast if nothing has changed on @font. 1417 * 1418 * Note that as of version 11.0.0, calling this function is not necessary, 1419 * as HarfBuzz will automatically detect changes to the font and update 1420 * the underlying FT_Face as needed. 1421 * 1422 * Return value: true if changed, false otherwise 1423 * 1424 * Since: 4.4.0 1425 **/ 1426 hb_bool_t 1427 hb_ft_hb_font_changed (hb_font_t *font) 1428 { 1429 if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) 1430 return false; 1431 1432 hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; 1433 1434 return _hb_ft_hb_font_check_changed (font, ft_font); 1435 } 1436 1437 /** 1438 * hb_ft_font_create_referenced: 1439 * @ft_face: FT_Face to work upon 1440 * 1441 * Creates an #hb_font_t font object from the specified FT_Face. 1442 * 1443 * <note>Note: You must set the face size on @ft_face before calling 1444 * hb_ft_font_create_referenced() on it. HarfBuzz assumes size is always set 1445 * and will access `size` member of FT_Face unconditionally.</note> 1446 * 1447 * This is the preferred variant of the hb_ft_font_create* 1448 * function family, because it calls FT_Reference_Face() on @ft_face, 1449 * ensuring that @ft_face remains alive as long as the resulting 1450 * #hb_font_t font object remains alive. 1451 * 1452 * Use this version unless you know you have good reasons not to. 1453 * 1454 * Return value: (transfer full): the new #hb_font_t font object 1455 * 1456 * Since: 0.9.38 1457 **/ 1458 hb_font_t * 1459 hb_ft_font_create_referenced (FT_Face ft_face) 1460 { 1461 FT_Reference_Face (ft_face); 1462 return hb_ft_font_create (ft_face, _hb_ft_face_destroy); 1463 } 1464 1465 1466 static void * _hb_ft_alloc (FT_Memory memory, long size) 1467 { return hb_malloc (size); } 1468 1469 static void _hb_ft_free (FT_Memory memory, void *block) 1470 { hb_free (block); } 1471 1472 static void * _hb_ft_realloc (FT_Memory memory, long cur_size, long new_size, void *block) 1473 { return hb_realloc (block, new_size); } 1474 1475 static FT_MemoryRec_ m = 1476 { 1477 nullptr, 1478 _hb_ft_alloc, 1479 _hb_ft_free, 1480 _hb_ft_realloc 1481 }; 1482 1483 static inline void free_static_ft_library (); 1484 1485 static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>, 1486 hb_ft_library_lazy_loader_t> 1487 { 1488 static FT_Library create () 1489 { 1490 FT_Library l; 1491 if (FT_New_Library (&m, &l)) 1492 return nullptr; 1493 1494 FT_Add_Default_Modules (l); 1495 FT_Set_Default_Properties (l); 1496 1497 hb_atexit (free_static_ft_library); 1498 1499 return l; 1500 } 1501 static void destroy (FT_Library l) 1502 { 1503 FT_Done_Library (l); 1504 } 1505 static FT_Library get_null () 1506 { 1507 return nullptr; 1508 } 1509 } static_ft_library; 1510 1511 static inline 1512 void free_static_ft_library () 1513 { 1514 static_ft_library.free_instance (); 1515 } 1516 1517 static FT_Library 1518 reference_ft_library () 1519 { 1520 FT_Library l = static_ft_library.get_unconst (); 1521 if (unlikely (FT_Reference_Library (l))) 1522 { 1523 DEBUG_MSG (FT, l, "FT_Reference_Library() failed"); 1524 return nullptr; 1525 } 1526 return l; 1527 } 1528 1529 static hb_user_data_key_t ft_library_key = {0}; 1530 1531 static void 1532 finalize_ft_library (void *arg) 1533 { 1534 FT_Face ft_face = (FT_Face) arg; 1535 FT_Done_Library ((FT_Library) ft_face->generic.data); 1536 } 1537 1538 static void 1539 destroy_ft_library (void *arg) 1540 { 1541 FT_Done_Library ((FT_Library) arg); 1542 } 1543 1544 /** 1545 * hb_ft_face_create_from_file_or_fail: 1546 * @file_name: A font filename 1547 * @index: The index of the face within the file 1548 * 1549 * Creates an #hb_face_t face object from the specified 1550 * font file and face index. 1551 * 1552 * This is similar in functionality to hb_face_create_from_file_or_fail(), 1553 * but uses the FreeType library for loading the font file. This can 1554 * be useful, for example, to load WOFF and WOFF2 font data. 1555 * 1556 * Return value: (transfer full): The new face object, or `NULL` if 1557 * no face is found at the specified index or the file cannot be read. 1558 * 1559 * Since: 10.1.0 1560 */ 1561 hb_face_t * 1562 hb_ft_face_create_from_file_or_fail (const char *file_name, 1563 unsigned int index) 1564 { 1565 FT_Library ft_library = reference_ft_library (); 1566 if (unlikely (!ft_library)) 1567 { 1568 DEBUG_MSG (FT, ft_library, "reference_ft_library failed"); 1569 return nullptr; 1570 } 1571 1572 FT_Face ft_face; 1573 if (unlikely (FT_New_Face (ft_library, 1574 file_name, 1575 index, 1576 &ft_face))) 1577 return nullptr; 1578 1579 hb_face_t *face = hb_ft_face_create_referenced (ft_face); 1580 FT_Done_Face (ft_face); 1581 1582 ft_face->generic.data = ft_library; 1583 ft_face->generic.finalizer = finalize_ft_library; 1584 1585 if (hb_face_is_immutable (face)) 1586 return nullptr; 1587 1588 return face; 1589 } 1590 1591 static hb_user_data_key_t ft_blob_key = {0}; 1592 1593 static void 1594 _destroy_blob (void *p) 1595 { 1596 hb_blob_destroy ((hb_blob_t *) p); 1597 } 1598 1599 /** 1600 * hb_ft_face_create_from_blob_or_fail: 1601 * @blob: A blob 1602 * @index: The index of the face within the blob 1603 * 1604 * Creates an #hb_face_t face object from the specified 1605 * font blob and face index. 1606 * 1607 * This is similar in functionality to hb_face_create_from_blob_or_fail(), 1608 * but uses the FreeType library for loading the font blob. This can 1609 * be useful, for example, to load WOFF and WOFF2 font data. 1610 * 1611 * Return value: (transfer full): The new face object, or `NULL` if 1612 * loading fails (eg. blob does not contain valid font data). 1613 * 1614 * Since: 11.0.0 1615 */ 1616 hb_face_t * 1617 hb_ft_face_create_from_blob_or_fail (hb_blob_t *blob, 1618 unsigned int index) 1619 { 1620 FT_Library ft_library = reference_ft_library (); 1621 if (unlikely (!ft_library)) 1622 { 1623 DEBUG_MSG (FT, ft_library, "reference_ft_library failed"); 1624 return nullptr; 1625 } 1626 1627 hb_blob_make_immutable (blob); 1628 unsigned blob_size; 1629 const char *blob_data = hb_blob_get_data (blob, &blob_size); 1630 1631 FT_Face ft_face; 1632 if (unlikely (FT_New_Memory_Face (ft_library, 1633 (const FT_Byte *) blob_data, 1634 blob_size, 1635 index, 1636 &ft_face))) 1637 return nullptr; 1638 1639 hb_face_t *face = hb_ft_face_create_referenced (ft_face); 1640 FT_Done_Face (ft_face); 1641 1642 ft_face->generic.data = ft_library; 1643 ft_face->generic.finalizer = finalize_ft_library; 1644 1645 if (hb_face_is_immutable (face)) 1646 return nullptr; 1647 1648 // Hook the blob to the hb_face_t, since FT_Face still needs it. 1649 hb_blob_reference (blob); 1650 if (!hb_face_set_user_data (face, &ft_blob_key, blob, _destroy_blob, true)) 1651 { 1652 hb_blob_destroy (blob); 1653 hb_face_destroy (face); 1654 return nullptr; 1655 } 1656 1657 return face; 1658 } 1659 1660 static void 1661 _release_blob (void *arg) 1662 { 1663 FT_Face ft_face = (FT_Face) arg; 1664 hb_blob_destroy ((hb_blob_t *) ft_face->generic.data); 1665 } 1666 1667 /** 1668 * hb_ft_font_set_funcs: 1669 * @font: #hb_font_t to work upon 1670 * 1671 * Configures the font-functions structure of the specified 1672 * #hb_font_t font object to use FreeType font functions. 1673 * 1674 * In particular, you can use this function to configure an 1675 * existing #hb_face_t face object for use with FreeType font 1676 * functions even if that #hb_face_t face object was initially 1677 * created with hb_face_create(), and therefore was not 1678 * initially configured to use FreeType font functions. 1679 * 1680 * An #hb_font_t object created with hb_ft_font_create() 1681 * is preconfigured for FreeType font functions and does not 1682 * require this function to be used. 1683 * 1684 * Note that if you modify the underlying #hb_font_t after 1685 * calling this function, you need to call hb_ft_hb_font_changed() 1686 * to update the underlying FT_Face. 1687 * 1688 * <note>Note: Internally, this function creates an FT_Face. 1689 * </note> 1690 * 1691 * Since: 1.0.5 1692 **/ 1693 void 1694 hb_ft_font_set_funcs (hb_font_t *font) 1695 { 1696 // In case of failure... 1697 hb_font_set_funcs (font, 1698 hb_font_funcs_get_empty (), 1699 nullptr, nullptr); 1700 1701 hb_blob_t *blob = hb_face_reference_blob (font->face); 1702 unsigned int blob_length; 1703 const char *blob_data = hb_blob_get_data (blob, &blob_length); 1704 if (unlikely (!blob_length)) 1705 DEBUG_MSG (FT, font, "Font face has empty blob"); 1706 1707 FT_Library ft_library = reference_ft_library (); 1708 if (unlikely (!ft_library)) 1709 { 1710 hb_blob_destroy (blob); 1711 DEBUG_MSG (FT, font, "reference_ft_library failed"); 1712 return; 1713 } 1714 1715 FT_Face ft_face = nullptr; 1716 if (unlikely (FT_New_Memory_Face (ft_library, 1717 (const FT_Byte *) blob_data, 1718 blob_length, 1719 hb_face_get_index (font->face), 1720 &ft_face))) 1721 { 1722 hb_blob_destroy (blob); 1723 DEBUG_MSG (FT, font, "FT_New_Memory_Face() failed"); 1724 return; 1725 } 1726 1727 if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL)) 1728 FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE); 1729 1730 // Hook the blob to the FT_Face 1731 ft_face->generic.data = blob; 1732 ft_face->generic.finalizer = _release_blob; 1733 1734 // And the FT_Library to the blob 1735 if (unlikely (!hb_blob_set_user_data (blob, &ft_library_key, ft_library, destroy_ft_library, true))) 1736 { 1737 DEBUG_MSG (FT, font, "hb_blob_set_user_data() failed"); 1738 FT_Done_Face (ft_face); 1739 return; 1740 } 1741 1742 _hb_ft_font_set_funcs (font, ft_face, true); 1743 hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); 1744 1745 _hb_ft_hb_font_changed (font, ft_face); 1746 } 1747 1748 #endif