tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hb-coretext.cc (18341B)


      1 /*
      2 * Copyright © 2012,2013  Mozilla Foundation.
      3 * Copyright © 2012,2013  Google, Inc.
      4 *
      5 *  This is part of HarfBuzz, a text shaping library.
      6 *
      7 * Permission is hereby granted, without written agreement and without
      8 * license or royalty fees, to use, copy, modify, and distribute this
      9 * software and its documentation for any purpose, provided that the
     10 * above copyright notice and the following two paragraphs appear in
     11 * all copies of this software.
     12 *
     13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     17 * DAMAGE.
     18 *
     19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     21 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     24 *
     25 * Mozilla Author(s): Jonathan Kew
     26 * Google Author(s): Behdad Esfahbod
     27 */
     28 
     29 #include "hb.hh"
     30 
     31 #ifdef HAVE_CORETEXT
     32 
     33 #include "hb-shaper-impl.hh"
     34 
     35 #include "hb-coretext.hh"
     36 
     37 
     38 /**
     39 * SECTION:hb-coretext
     40 * @title: hb-coretext
     41 * @short_description: CoreText integration
     42 * @include: hb-coretext.h
     43 *
     44 * Functions for using HarfBuzz with the CoreText fonts.
     45 **/
     46 
     47 static void
     48 release_table_data (void *user_data)
     49 {
     50  CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
     51  CFRelease(cf_data);
     52 }
     53 
     54 static hb_blob_t *
     55 _hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
     56 {
     57  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
     58  CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
     59  if (unlikely (!cf_data))
     60    return nullptr;
     61 
     62  const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
     63  const size_t length = CFDataGetLength (cf_data);
     64  if (!data || !length)
     65  {
     66    CFRelease (cf_data);
     67    return nullptr;
     68  }
     69 
     70  return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
     71 		 reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
     72 		 release_table_data);
     73 }
     74 
     75 static unsigned
     76 _hb_cg_get_table_tags (const hb_face_t *face HB_UNUSED,
     77 	       unsigned int start_offset,
     78 	       unsigned int *table_count,
     79 	       hb_tag_t *table_tags,
     80 	       void *user_data)
     81 {
     82  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
     83 
     84  CTFontRef ct_font = create_ct_font (cg_font, (CGFloat) HB_CORETEXT_DEFAULT_FONT_SIZE);
     85 
     86  auto arr = CTFontCopyAvailableTables (ct_font, kCTFontTableOptionNoOptions);
     87 
     88  unsigned population = (unsigned) CFArrayGetCount (arr);
     89  unsigned end_offset;
     90 
     91  if (!table_count)
     92    goto done;
     93 
     94  if (unlikely (start_offset >= population))
     95  {
     96    *table_count = 0;
     97    goto done;
     98  }
     99 
    100  end_offset = start_offset + *table_count;
    101  if (unlikely (end_offset < start_offset))
    102  {
    103    *table_count = 0;
    104    goto done;
    105  }
    106  end_offset= hb_min (end_offset, (unsigned) population);
    107 
    108  *table_count = end_offset - start_offset;
    109  for (unsigned i = start_offset; i < end_offset; i++)
    110  {
    111    CTFontTableTag tag = (CTFontTableTag)(uintptr_t) CFArrayGetValueAtIndex (arr, i);
    112    table_tags[i - start_offset] = tag;
    113  }
    114 
    115 done:
    116  CFRelease (arr);
    117  CFRelease (ct_font);
    118  return population;
    119 }
    120 
    121 static void
    122 _hb_cg_font_release (void *data)
    123 {
    124  CGFontRelease ((CGFontRef) data);
    125 }
    126 
    127 
    128 static CTFontDescriptorRef
    129 get_last_resort_font_desc ()
    130 {
    131  // TODO Handle allocation failures?
    132  CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
    133  CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
    134 				   (const void **) &last_resort,
    135 				   1,
    136 				   &kCFTypeArrayCallBacks);
    137  CFRelease (last_resort);
    138  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
    139 					   (const void **) &kCTFontCascadeListAttribute,
    140 					   (const void **) &cascade_list,
    141 					   1,
    142 					   &kCFTypeDictionaryKeyCallBacks,
    143 					   &kCFTypeDictionaryValueCallBacks);
    144  CFRelease (cascade_list);
    145 
    146  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
    147  CFRelease (attributes);
    148  return font_desc;
    149 }
    150 
    151 static void
    152 release_data (void *info, const void *data, size_t size)
    153 {
    154  assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
    155   hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
    156 
    157  hb_blob_destroy ((hb_blob_t *) info);
    158 }
    159 
    160 CGFontRef
    161 create_cg_font (CFArrayRef ct_font_desc_array, unsigned int named_instance_index)
    162 {
    163  if (named_instance_index == 0)
    164  {
    165    // Default instance. We don't know which one is it. Return the first one.
    166    // We will set the correct variations on it later.
    167  }
    168  else
    169    named_instance_index--;
    170  auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > (CFIndex) named_instance_index) ?
    171 	      (CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, (CFIndex) named_instance_index) : nullptr;
    172  if (unlikely (!ct_font_desc))
    173  {
    174    CFRelease (ct_font_desc_array);
    175    return nullptr;
    176  }
    177  auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr;
    178  CFRelease (ct_font_desc_array);
    179  if (unlikely (!ct_font))
    180    return nullptr;
    181 
    182  auto cg_font = ct_font ? CTFontCopyGraphicsFont (ct_font, nullptr) : nullptr;
    183  CFRelease (ct_font);
    184 
    185  return cg_font;
    186 }
    187 
    188 CGFontRef
    189 create_cg_font (hb_blob_t *blob, unsigned int index)
    190 {
    191  hb_blob_make_immutable (blob);
    192  unsigned int blob_length;
    193  const char *blob_data = hb_blob_get_data (blob, &blob_length);
    194  if (unlikely (!blob_length))
    195    DEBUG_MSG (CORETEXT, blob, "Empty blob");
    196 
    197  unsigned ttc_index = index & 0xFFFF;
    198  unsigned named_instance_index = index >> 16;
    199 
    200  if (ttc_index != 0)
    201  {
    202    DEBUG_MSG (CORETEXT, blob, "TTC index %u not supported", ttc_index);
    203    return nullptr; // CoreText does not support TTCs
    204  }
    205 
    206  if (unlikely (named_instance_index != 0))
    207  {
    208    // https://github.com/harfbuzz/harfbuzz/issues/5300
    209    // https://github.com/harfbuzz/harfbuzz/issues/5354
    210 #if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) || \
    211    (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) || \
    212    (defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED >= 110000) || \
    213    (defined(__WATCH_OS_VERSION_MIN_REQUIRED) && __WATCH_OS_VERSION_MIN_REQUIRED >= 40000) || \
    214    (defined(__MACCATALYST_VERSION_MIN_REQUIRED) && __MACCATALYST_VERSION_MIN_REQUIRED >= 130100) || \
    215    (defined(__VISION_OS_VERSION_MIN_REQUIRED) && __VISION_OS_VERSION_MIN_REQUIRED >= 10000)
    216    auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromData (CFDataCreate (kCFAllocatorDefault, (const UInt8 *) blob_data, blob_length));
    217    if (likely (ct_font_desc_array))
    218      return create_cg_font (ct_font_desc_array, named_instance_index);
    219 #endif
    220    return nullptr;
    221  }
    222 
    223  hb_blob_reference (blob);
    224  CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
    225  CGFontRef cg_font = nullptr;
    226  if (likely (provider))
    227  {
    228    cg_font = CGFontCreateWithDataProvider (provider);
    229    if (unlikely (!cg_font))
    230      DEBUG_MSG (CORETEXT, blob, "CGFontCreateWithDataProvider() failed");
    231    CGDataProviderRelease (provider);
    232  }
    233  return cg_font;
    234 }
    235 
    236 CGFontRef
    237 create_cg_font (hb_face_t *face)
    238 {
    239  CGFontRef cg_font = nullptr;
    240  if (face->destroy == _hb_cg_font_release)
    241    cg_font = CGFontRetain ((CGFontRef) face->user_data);
    242  else
    243  {
    244    hb_blob_t *blob = hb_face_reference_blob (face);
    245    cg_font = create_cg_font (blob, face->index);
    246    hb_blob_destroy (blob);
    247  }
    248  return cg_font;
    249 }
    250 
    251 CTFontRef
    252 create_ct_font (CGFontRef cg_font, CGFloat font_size)
    253 {
    254  CTFontRef ct_font = nullptr;
    255 
    256  /* CoreText does not enable trak table usage / tracking when creating a CTFont
    257   * using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
    258   * to be through the CTFontCreateUIFontForLanguage call. */
    259  CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
    260  if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
    261      CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
    262  {
    263 #if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
    264 # define kCTFontUIFontSystem kCTFontSystemFontType
    265 # define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
    266 #endif
    267    CTFontUIFontType font_type = kCTFontUIFontSystem;
    268    if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
    269      font_type = kCTFontUIFontEmphasizedSystem;
    270 
    271    ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
    272    CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
    273    if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
    274    {
    275      CFRelease(ct_font);
    276      ct_font = nullptr;
    277    }
    278    CFRelease (ct_result_name);
    279  }
    280  CFRelease (cg_postscript_name);
    281 
    282  if (!ct_font)
    283    ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
    284 
    285  if (unlikely (!ct_font)) {
    286    DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
    287    return nullptr;
    288  }
    289 
    290  /* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
    291   * bug indicate that the cascade list reconfiguration occasionally causes
    292   * crashes in CoreText on OS X 10.9, thus let's skip this step on older
    293   * operating system versions. Except for the emoji font, where _not_
    294   * reconfiguring the cascade list causes CoreText crashes. For details, see
    295   * crbug.com/549610 */
    296  // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
    297 #pragma GCC diagnostic push
    298 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    299  if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
    300 #pragma GCC diagnostic pop
    301    CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
    302    bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
    303    CFRelease (fontName);
    304    if (!isEmojiFont)
    305      return ct_font;
    306  }
    307 
    308  CFURLRef original_url = nullptr;
    309 #if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
    310  ATSFontRef atsFont;
    311  FSRef fsref;
    312  OSStatus status;
    313  atsFont = CTFontGetPlatformFont (ct_font, NULL);
    314  status = ATSFontGetFileReference (atsFont, &fsref);
    315  if (status == noErr)
    316    original_url = CFURLCreateFromFSRef (NULL, &fsref);
    317 #else
    318  original_url = (CFURLRef) CTFontCopyAttribute (ct_font, kCTFontURLAttribute);
    319 #endif
    320 
    321  /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
    322   * font fallback which we don't need anyway. */
    323  {
    324    CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
    325    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
    326    CFRelease (last_resort_font_desc);
    327    if (new_ct_font)
    328    {
    329      /* The CTFontCreateCopyWithAttributes call fails to stay on the same font
    330       * when reconfiguring the cascade list and may switch to a different font
    331       * when there are fonts that go by the same name, since the descriptor is
    332       * just name and size.
    333       *
    334       * Avoid reconfiguring the cascade lists if the new font is outside the
    335       * system locations that we cannot access from the sandboxed renderer
    336       * process in Blink. This can be detected by the new file URL location
    337       * that the newly found font points to. */
    338      CFURLRef new_url = nullptr;
    339 #if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
    340      atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
    341      status = ATSFontGetFileReference (atsFont, &fsref);
    342      if (status == noErr)
    343 new_url = CFURLCreateFromFSRef (NULL, &fsref);
    344 #else
    345      new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
    346 #endif
    347      // Keep reconfigured font if URL cannot be retrieved (seems to be the case
    348      // on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
    349      if (!original_url || !new_url || CFEqual (original_url, new_url)) {
    350 CFRelease (ct_font);
    351 ct_font = new_ct_font;
    352      } else {
    353 CFRelease (new_ct_font);
    354 DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
    355      }
    356      if (new_url)
    357 CFRelease (new_url);
    358    }
    359    else
    360      DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
    361  }
    362 
    363  if (original_url)
    364    CFRelease (original_url);
    365  return ct_font;
    366 }
    367 
    368 /**
    369 * hb_coretext_face_create:
    370 * @cg_font: The CGFontRef to work upon
    371 *
    372 * Creates an #hb_face_t face object from the specified
    373 * CGFontRef.
    374 *
    375 * Return value: (transfer full): The new face object
    376 *
    377 * Since: 0.9.10
    378 */
    379 hb_face_t *
    380 hb_coretext_face_create (CGFontRef cg_font)
    381 {
    382  hb_face_t *face = hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
    383  hb_face_set_get_table_tags_func (face, _hb_cg_get_table_tags, cg_font, nullptr);
    384  return face;
    385 }
    386 
    387 /**
    388 * hb_coretext_face_create_from_file_or_fail:
    389 * @file_name: A font filename
    390 * @index: The index of the face within the file
    391 *
    392 * Creates an #hb_face_t face object from the specified
    393 * font file and face index.
    394 *
    395 * This is similar in functionality to hb_face_create_from_file_or_fail(),
    396 * but uses the CoreText library for loading the font file.
    397 *
    398 * Return value: (transfer full): The new face object, or `NULL` if
    399 * no face is found at the specified index or the file cannot be read.
    400 *
    401 * Since: 10.1.0
    402 */
    403 hb_face_t *
    404 hb_coretext_face_create_from_file_or_fail (const char   *file_name,
    405 				   unsigned int  index)
    406 {
    407  auto url = CFURLCreateFromFileSystemRepresentation (nullptr,
    408 					      (const UInt8 *) file_name,
    409 					      strlen (file_name),
    410 					      false);
    411  if (unlikely (!url))
    412    return nullptr;
    413 
    414  auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromURL (url);
    415  if (unlikely (!ct_font_desc_array))
    416  {
    417    CFRelease (url);
    418    return nullptr;
    419  }
    420 
    421  unsigned ttc_index = index & 0xFFFF;
    422  unsigned named_instance_index = index >> 16;
    423 
    424  if (ttc_index != 0)
    425  {
    426    DEBUG_MSG (CORETEXT, nullptr, "TTC index %u not supported", ttc_index);
    427    return nullptr; // CoreText does not support TTCs
    428  }
    429 
    430  auto cg_font = create_cg_font (ct_font_desc_array, named_instance_index);
    431  CFRelease (url);
    432 
    433  hb_face_t *face = hb_coretext_face_create (cg_font);
    434  CFRelease (cg_font);
    435  if (unlikely (hb_face_is_immutable (face)))
    436    return nullptr;
    437 
    438  hb_face_set_index (face, index);
    439 
    440  return face;
    441 }
    442 
    443 /**
    444 * hb_coretext_face_create_from_blob_or_fail:
    445 * @blob: A blob containing the font data
    446 * @index: The index of the face within the blob
    447 *
    448 * Creates an #hb_face_t face object from the specified
    449 * blob and face index.
    450 *
    451 * This is similar in functionality to hb_face_create_from_blob_or_fail(),
    452 * but uses the CoreText library for loading the font data.
    453 *
    454 * Return value: (transfer full): The new face object, or `NULL` if
    455 * no face is found at the specified index or the blob cannot be read.
    456 *
    457 * Since: 11.0.0
    458 */
    459 hb_face_t *
    460 hb_coretext_face_create_from_blob_or_fail (hb_blob_t    *blob,
    461 				   unsigned int  index)
    462 {
    463  auto cg_font = create_cg_font (blob, index);
    464  if (unlikely (!cg_font))
    465    return nullptr;
    466 
    467  hb_face_t *face = hb_coretext_face_create (cg_font);
    468  CFRelease (cg_font);
    469  if (unlikely (hb_face_is_immutable (face)))
    470    return nullptr;
    471 
    472  hb_face_set_index (face, index);
    473 
    474  return face;
    475 }
    476 
    477 /**
    478 * hb_coretext_face_get_cg_font:
    479 * @face: The #hb_face_t to work upon
    480 *
    481 * Fetches the CGFontRef associated with an #hb_face_t
    482 * face object
    483 *
    484 * Return value: the CGFontRef found
    485 *
    486 * Since: 0.9.10
    487 */
    488 CGFontRef
    489 hb_coretext_face_get_cg_font (hb_face_t *face)
    490 {
    491  return (CGFontRef) (const void *) face->data.coretext;
    492 }
    493 
    494 /**
    495 * hb_coretext_font_create:
    496 * @ct_font: The CTFontRef to work upon
    497 *
    498 * Creates an #hb_font_t font object from the specified
    499 * CTFontRef.
    500 *
    501 * The created font uses the default font functions implemented
    502 * natively by HarfBuzz. If you want to use the CoreText font functions
    503 * instead (rarely needed), you can do so by calling
    504 * by hb_coretext_font_set_funcs().
    505 *
    506 * Return value: (transfer full): The new font object
    507 *
    508 * Since: 1.7.2
    509 **/
    510 hb_font_t *
    511 hb_coretext_font_create (CTFontRef ct_font)
    512 {
    513  CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, nullptr);
    514  hb_face_t *face = hb_coretext_face_create (cg_font);
    515  CFRelease (cg_font);
    516  hb_font_t *font = hb_font_create (face);
    517  hb_face_destroy (face);
    518 
    519  if (unlikely (hb_object_is_immutable (font)))
    520    return font;
    521 
    522  hb_font_set_ptem (font, CTFontGetSize (ct_font));
    523 
    524  /* Copy font variations */
    525  CFDictionaryRef variations = CTFontCopyVariation (ct_font);
    526  if (variations)
    527  {
    528    hb_vector_t<hb_variation_t> vars;
    529    hb_vector_t<CFTypeRef> keys;
    530    hb_vector_t<CFTypeRef> values;
    531 
    532    CFIndex count = CFDictionaryGetCount (variations);
    533    if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count)))
    534      goto done;
    535 
    536    // Fetch them one by one and collect in a vector of our own.
    537    CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ);
    538    for (CFIndex i = 0; i < count; i++)
    539    {
    540      int tag;
    541      float value;
    542      CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag);
    543      CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value);
    544 
    545      hb_variation_t var = {tag, value};
    546      vars.push (var);
    547    }
    548    hb_font_set_variations (font, vars.arrayZ, vars.length);
    549 
    550 done:
    551    CFRelease (variations);
    552  }
    553 
    554  /* Let there be dragons here... */
    555  font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
    556 
    557  // https://github.com/harfbuzz/harfbuzz/pull/4895#issuecomment-2408471254
    558  //hb_coretext_font_set_funcs (font);
    559 
    560  return font;
    561 }
    562 
    563 /**
    564 * hb_coretext_font_get_ct_font:
    565 * @font: #hb_font_t to work upon
    566 *
    567 * Fetches the CTFontRef associated with the specified
    568 * #hb_font_t font object.
    569 *
    570 * Return value: the CTFontRef found
    571 *
    572 * Since: 0.9.10
    573 */
    574 CTFontRef
    575 hb_coretext_font_get_ct_font (hb_font_t *font)
    576 {
    577  return (CTFontRef) (const void *) font->data.coretext;
    578 }
    579 
    580 
    581 #endif