hb-coretext-font.cc (16368B)
1 /* 2 * Copyright © 2024 Google, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Author(s): Behdad Esfahbod 25 */ 26 27 #include "hb.hh" 28 29 #ifdef HAVE_CORETEXT 30 31 #include "hb-coretext.hh" 32 #include "hb-aat-layout-trak-table.hh" 33 34 #include "hb-draw.hh" 35 #include "hb-font.hh" 36 #include "hb-machinery.hh" 37 38 #if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1080) \ 39 || (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 60000) \ 40 || (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 90000) 41 # define kCTFontOrientationDefault kCTFontDefaultOrientation 42 # define kCTFontOrientationHorizontal kCTFontHorizontalOrientation 43 # define kCTFontOrientationVertical kCTFontVerticalOrientation 44 #endif 45 46 #define MAX_GLYPHS 256u 47 48 static hb_bool_t 49 hb_coretext_get_nominal_glyph (hb_font_t *font, 50 void *font_data HB_UNUSED, 51 hb_codepoint_t unicode, 52 hb_codepoint_t *glyph, 53 void *user_data HB_UNUSED) 54 { 55 CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext; 56 57 UniChar ch[2]; 58 CGGlyph cg_glyph[2]; 59 unsigned count = 0; 60 61 if (unicode <= 0xFFFF) 62 { 63 ch[count++] = unicode; 64 } 65 else if (unicode <= 0x10FFFF) 66 { 67 ch[count++] = (unicode >> 10) + 0xD7C0; 68 ch[count++] = (unicode & 0x3FF) + 0xDC00; 69 } 70 else 71 ch[count++] = 0xFFFD; 72 73 if (CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, count)) 74 { 75 *glyph = cg_glyph[0]; 76 return true; 77 } 78 return false; 79 } 80 81 static unsigned int 82 hb_coretext_get_nominal_glyphs (hb_font_t *font, 83 void *font_data, 84 unsigned int count, 85 const hb_codepoint_t *first_unicode, 86 unsigned int unicode_stride, 87 hb_codepoint_t *first_glyph, 88 unsigned int glyph_stride, 89 void *user_data HB_UNUSED) 90 { 91 CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext; 92 93 // If any non-BMP codepoint is requested, use the slow path. 94 bool slow_path = false; 95 auto *unicode = first_unicode; 96 for (unsigned i = 0; i < count; i++) 97 { 98 if (*unicode > 0xFFFF) 99 { 100 slow_path = true; 101 break; 102 } 103 unicode = &StructAtOffset<const hb_codepoint_t> (unicode, unicode_stride); 104 } 105 106 if (unlikely (slow_path)) 107 { 108 for (unsigned i = 0; i < count; i++) 109 { 110 if (!hb_coretext_get_nominal_glyph (font, font_data, *first_unicode, first_glyph, nullptr)) 111 return i; 112 first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride); 113 first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride); 114 } 115 return count; 116 } 117 118 UniChar ch[MAX_GLYPHS]; 119 CGGlyph cg_glyph[MAX_GLYPHS]; 120 for (unsigned i = 0; i < count; i += MAX_GLYPHS) 121 { 122 unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i); 123 for (unsigned j = 0; j < c; j++) 124 { 125 ch[j] = *first_unicode; 126 first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride); 127 } 128 if (unlikely (!CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, c))) 129 { 130 // Use slow path partially and return at first failure. 131 for (unsigned j = 0; j < c; j++) 132 { 133 if (!hb_coretext_get_nominal_glyph (font, font_data, ch[j], first_glyph, nullptr)) 134 return i + j; 135 first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride); 136 } 137 } 138 for (unsigned j = 0; j < c; j++) 139 { 140 *first_glyph = cg_glyph[j]; 141 first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride); 142 } 143 } 144 145 return count; 146 } 147 148 static hb_bool_t 149 hb_coretext_get_variation_glyph (hb_font_t *font, 150 void *font_data HB_UNUSED, 151 hb_codepoint_t unicode, 152 hb_codepoint_t variation_selector, 153 hb_codepoint_t *glyph, 154 void *user_data HB_UNUSED) 155 { 156 CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext; 157 158 UniChar ch[4]; 159 CGGlyph cg_glyph[4]; 160 unsigned count = 0; 161 162 // Add Unicode, then variation selector. Ugly, but works. 163 // 164 if (unicode <= 0xFFFF) 165 ch[count++] = unicode; 166 else if (unicode <= 0x10FFFF) 167 { 168 ch[count++] = (unicode >> 10) + 0xD7C0; 169 ch[count++] = (unicode & 0x3FF) + 0xDC00; 170 } 171 else 172 ch[count++] = 0xFFFD; 173 174 if (variation_selector <= 0xFFFF) 175 ch[count++] = variation_selector; 176 else if (variation_selector <= 0x10FFFF) 177 { 178 ch[count++] = (variation_selector >> 10) + 0xD7C0; 179 ch[count++] = (variation_selector & 0x3FF) + 0xDC00; 180 } 181 else 182 ch[count++] = 0xFFFD; 183 184 CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, count); 185 186 // All except for first should be zero if we succeeded 187 for (unsigned i = 1; i < count; i++) 188 if (cg_glyph[i]) 189 return false; 190 191 // Humm. CoreText falls back to the default glyph if the variation selector 192 // is not supported. We cannot truly detect that case. So, in essence, 193 // we are always returning true here... 194 195 *glyph = cg_glyph[0]; 196 return true; 197 } 198 199 static void 200 hb_coretext_get_glyph_h_advances (hb_font_t* font, 201 void* font_data HB_UNUSED, 202 unsigned count, 203 const hb_codepoint_t *first_glyph, 204 unsigned glyph_stride, 205 hb_position_t *first_advance, 206 unsigned advance_stride, 207 void *user_data HB_UNUSED) 208 { 209 CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext; 210 211 CGFloat ct_font_size = CTFontGetSize (ct_font); 212 CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size; 213 hb_position_t tracking = font->face->table.trak->get_tracking (font, HB_DIRECTION_LTR, 0.f); 214 215 CGGlyph cg_glyph[MAX_GLYPHS]; 216 CGSize advances[MAX_GLYPHS]; 217 for (unsigned i = 0; i < count; i += MAX_GLYPHS) 218 { 219 unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i); 220 for (unsigned j = 0; j < c; j++) 221 { 222 cg_glyph[j] = *first_glyph; 223 first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride); 224 } 225 CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationHorizontal, cg_glyph, advances, c); 226 for (unsigned j = 0; j < c; j++) 227 { 228 *first_advance = round (advances[j].width * x_mult) - tracking; 229 first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride); 230 } 231 } 232 } 233 234 #ifndef HB_NO_VERTICAL 235 static void 236 hb_coretext_get_glyph_v_advances (hb_font_t* font, 237 void* font_data HB_UNUSED, 238 unsigned count, 239 const hb_codepoint_t *first_glyph, 240 unsigned glyph_stride, 241 hb_position_t *first_advance, 242 unsigned advance_stride, 243 void *user_data HB_UNUSED) 244 { 245 CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext; 246 247 CGFloat ct_font_size = CTFontGetSize (ct_font); 248 CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size; 249 hb_position_t tracking = font->face->table.trak->get_tracking (font, HB_DIRECTION_TTB, 0.f); 250 251 CGGlyph cg_glyph[MAX_GLYPHS]; 252 CGSize advances[MAX_GLYPHS]; 253 for (unsigned i = 0; i < count; i += MAX_GLYPHS) 254 { 255 unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i); 256 for (unsigned j = 0; j < c; j++) 257 { 258 cg_glyph[j] = *first_glyph; 259 first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride); 260 } 261 CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationVertical, cg_glyph, advances, c); 262 for (unsigned j = 0; j < c; j++) 263 { 264 *first_advance = round (advances[j].width * y_mult) - tracking; 265 first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride); 266 } 267 } 268 } 269 270 static hb_bool_t 271 hb_coretext_get_glyph_v_origin (hb_font_t *font, 272 void *font_data HB_UNUSED, 273 hb_codepoint_t glyph, 274 hb_position_t *x, 275 hb_position_t *y, 276 void *user_data HB_UNUSED) 277 { 278 CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext; 279 280 CGFloat ct_font_size = CTFontGetSize (ct_font); 281 CGFloat x_mult = (CGFloat) -font->x_scale / ct_font_size; 282 CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size; 283 284 const CGGlyph glyphs = glyph; 285 CGSize origin; 286 CTFontGetVerticalTranslationsForGlyphs (ct_font, &glyphs, &origin, 1); 287 288 *x = round (x_mult * origin.width); 289 *y = round (y_mult * origin.height); 290 291 return true; 292 } 293 #endif 294 295 static hb_bool_t 296 hb_coretext_get_glyph_extents (hb_font_t *font, 297 void *font_data HB_UNUSED, 298 hb_codepoint_t glyph, 299 hb_glyph_extents_t *extents, 300 void *user_data HB_UNUSED) 301 { 302 CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext; 303 304 CGFloat ct_font_size = CTFontGetSize (ct_font); 305 CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size; 306 CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size; 307 308 CGGlyph glyphs[1] = { glyph }; 309 CGRect bounds = ::CTFontGetBoundingRectsForGlyphs(ct_font, 310 kCTFontOrientationDefault, glyphs, NULL, 1); 311 312 extents->x_bearing = round (bounds.origin.x * x_mult); 313 extents->y_bearing = round ((bounds.origin.y + bounds.size.height) * y_mult); 314 extents->width = round (bounds.size.width * x_mult); 315 extents->height = round (bounds.origin.y * y_mult) - extents->y_bearing; 316 317 return true; 318 } 319 320 static hb_bool_t 321 hb_coretext_get_font_h_extents (hb_font_t *font, 322 void *font_data HB_UNUSED, 323 hb_font_extents_t *metrics, 324 void *user_data HB_UNUSED) 325 { 326 CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext; 327 328 CGFloat ct_font_size = CTFontGetSize (ct_font); 329 CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size; 330 331 metrics->ascender = round (CTFontGetAscent (ct_font) * y_mult); 332 metrics->descender = -round (CTFontGetDescent (ct_font) * y_mult); 333 metrics->line_gap = round (CTFontGetLeading (ct_font) * y_mult); 334 335 return true; 336 } 337 338 #ifndef HB_NO_DRAW 339 340 static void 341 ct_apply_func (void *info, const CGPathElement *element) 342 { 343 hb_draw_session_t *draws = (hb_draw_session_t *) info; 344 345 switch (element->type) 346 { 347 case kCGPathElementMoveToPoint: 348 draws->move_to (element->points[0].x, element->points[0].y); 349 break; 350 case kCGPathElementAddLineToPoint: 351 draws->line_to (element->points[0].x, element->points[0].y); 352 break; 353 case kCGPathElementAddQuadCurveToPoint: 354 draws->quadratic_to (element->points[0].x, element->points[0].y, 355 element->points[1].x, element->points[1].y); 356 break; 357 case kCGPathElementAddCurveToPoint: 358 draws->cubic_to (element->points[0].x, element->points[0].y, 359 element->points[1].x, element->points[1].y, 360 element->points[2].x, element->points[2].y); 361 break; 362 case kCGPathElementCloseSubpath: 363 draws->close_path (); 364 break; 365 } 366 } 367 368 static hb_bool_t 369 hb_coretext_draw_glyph_or_fail (hb_font_t *font, 370 void *font_data HB_UNUSED, 371 hb_codepoint_t glyph, 372 hb_draw_funcs_t *draw_funcs, void *draw_data, 373 void *user_data) 374 { 375 CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext; 376 377 CGFloat ct_font_size = CTFontGetSize (ct_font); 378 CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size; 379 CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size; 380 381 CGAffineTransform transform = CGAffineTransformIdentity; 382 transform = CGAffineTransformScale (transform, x_mult, y_mult); 383 384 CGPathRef path = CTFontCreatePathForGlyph (ct_font, glyph, &transform); 385 if (!path) 386 return false; 387 388 hb_draw_session_t drawing {draw_funcs, draw_data}; 389 390 CGPathApply (path, &drawing, ct_apply_func); 391 392 CFRelease (path); 393 394 return true; 395 } 396 #endif 397 398 static hb_bool_t 399 hb_coretext_get_glyph_name (hb_font_t *font, 400 void *font_data HB_UNUSED, 401 hb_codepoint_t glyph, 402 char *name, unsigned int size, 403 void *user_data HB_UNUSED) 404 { 405 CGFontRef cg_font = (CGFontRef) (const void *) font->face->data.coretext; 406 407 CGGlyph cg_glyph = glyph; 408 CFStringRef cf_name = CGFontCopyGlyphNameForGlyph (cg_font, cg_glyph); 409 if (!cf_name) 410 return false; 411 412 CFIndex len = CFStringGetLength (cf_name); 413 if (len > (CFIndex)size - 1) 414 len = (CFIndex)size - 1; 415 416 CFStringGetBytes (cf_name, CFRangeMake (0, len), 417 kCFStringEncodingUTF8, 0, false, 418 (UInt8 *) name, size, &len); 419 420 name[len] = '\0'; 421 422 CFRelease (cf_name); 423 424 return true; 425 } 426 427 static hb_bool_t 428 hb_coretext_get_glyph_from_name (hb_font_t *font, 429 void *font_data HB_UNUSED, 430 const char *name, int len, 431 hb_codepoint_t *glyph, 432 void *user_data HB_UNUSED) 433 { 434 CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext; 435 436 if (len == -1) 437 len = strlen (name); 438 439 CFStringRef cf_name = CFStringCreateWithBytes (kCFAllocatorDefault, 440 (const UInt8 *) name, len, 441 kCFStringEncodingUTF8, false); 442 CGGlyph cg_glyph = CTFontGetGlyphWithName (ct_font, cf_name); 443 *glyph = cg_glyph; 444 445 CFRelease (cf_name); 446 447 // TODO Return true for .notdef; hb-ft does that. 448 449 return cg_glyph != 0; 450 } 451 452 453 static inline void free_static_coretext_funcs (); 454 455 static struct hb_coretext_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_coretext_font_funcs_lazy_loader_t> 456 { 457 static hb_font_funcs_t *create () 458 { 459 hb_font_funcs_t *funcs = hb_font_funcs_create (); 460 461 hb_font_funcs_set_nominal_glyph_func (funcs, hb_coretext_get_nominal_glyph, nullptr, nullptr); 462 hb_font_funcs_set_nominal_glyphs_func (funcs, hb_coretext_get_nominal_glyphs, nullptr, nullptr); 463 hb_font_funcs_set_variation_glyph_func (funcs, hb_coretext_get_variation_glyph, nullptr, nullptr); 464 465 hb_font_funcs_set_font_h_extents_func (funcs, hb_coretext_get_font_h_extents, nullptr, nullptr); 466 hb_font_funcs_set_glyph_h_advances_func (funcs, hb_coretext_get_glyph_h_advances, nullptr, nullptr); 467 468 #ifndef HB_NO_VERTICAL 469 hb_font_funcs_set_glyph_v_advances_func (funcs, hb_coretext_get_glyph_v_advances, nullptr, nullptr); 470 hb_font_funcs_set_glyph_v_origin_func (funcs, hb_coretext_get_glyph_v_origin, nullptr, nullptr); 471 #endif 472 473 #ifndef HB_NO_DRAW 474 hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_coretext_draw_glyph_or_fail, nullptr, nullptr); 475 #endif 476 477 hb_font_funcs_set_glyph_extents_func (funcs, hb_coretext_get_glyph_extents, nullptr, nullptr); 478 479 #ifndef HB_NO_OT_FONT_GLYPH_NAMES 480 hb_font_funcs_set_glyph_name_func (funcs, hb_coretext_get_glyph_name, nullptr, nullptr); 481 hb_font_funcs_set_glyph_from_name_func (funcs, hb_coretext_get_glyph_from_name, nullptr, nullptr); 482 #endif 483 484 hb_font_funcs_make_immutable (funcs); 485 486 hb_atexit (free_static_coretext_funcs); 487 488 return funcs; 489 } 490 } static_coretext_funcs; 491 492 static inline 493 void free_static_coretext_funcs () 494 { 495 static_coretext_funcs.free_instance (); 496 } 497 498 static hb_font_funcs_t * 499 _hb_coretext_get_font_funcs () 500 { 501 return static_coretext_funcs.get_unconst (); 502 } 503 504 505 /** 506 * hb_coretext_font_set_funcs: 507 * @font: #hb_font_t to work upon 508 * 509 * Configures the font-functions structure of the specified 510 * #hb_font_t font object to use CoreText font functions. 511 * 512 * In particular, you can use this function to configure an 513 * existing #hb_face_t face object for use with CoreText font 514 * functions even if that #hb_face_t face object was initially 515 * created with hb_face_create(), and therefore was not 516 * initially configured to use CoreText font functions. 517 * 518 * <note>Note: Internally, this function creates a CTFont. 519 * </note> 520 * 521 * Since: 10.1.0 522 **/ 523 void 524 hb_coretext_font_set_funcs (hb_font_t *font) 525 { 526 CTFontRef ct_font = hb_coretext_font_get_ct_font (font); 527 if (unlikely (!ct_font)) 528 { 529 hb_font_set_funcs (font, 530 hb_font_funcs_get_empty (), 531 nullptr, nullptr); 532 return; 533 } 534 535 hb_font_set_funcs (font, 536 _hb_coretext_get_font_funcs (), 537 nullptr, nullptr); 538 } 539 540 #undef MAX_GLYPHS 541 542 #endif