src/java.desktop/share/native/libfontmanager/harfbuzz/hb-coretext.cc
changeset 48274 51772bf1fb0c
parent 47216 71c04702a3d5
child 50352 25db2c8f3cf8
equal deleted inserted replaced
48273:e2065f7505eb 48274:51772bf1fb0c
    25  * Mozilla Author(s): Jonathan Kew
    25  * Mozilla Author(s): Jonathan Kew
    26  * Google Author(s): Behdad Esfahbod
    26  * Google Author(s): Behdad Esfahbod
    27  */
    27  */
    28 
    28 
    29 #define HB_SHAPER coretext
    29 #define HB_SHAPER coretext
       
    30 
       
    31 #include "hb-private.hh"
       
    32 #include "hb-debug.hh"
    30 #include "hb-shaper-impl-private.hh"
    33 #include "hb-shaper-impl-private.hh"
    31 
    34 
    32 #include "hb-coretext.h"
    35 #include "hb-coretext.h"
    33 
    36 #include <math.h>
    34 
    37 
    35 #ifndef HB_DEBUG_CORETEXT
    38 /* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
    36 #define HB_DEBUG_CORETEXT (HB_DEBUG+0)
    39 #define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
    37 #endif
    40 
    38 
    41 static CGFloat
       
    42 coretext_font_size (float ptem)
       
    43 {
       
    44   /* CoreText points are CSS pixels (96 per inch),
       
    45    * NOT typographic points (72 per inch).
       
    46    *
       
    47    * https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
       
    48    */
       
    49   ptem *= 96.f / 72.f;
       
    50   return ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : ptem;
       
    51 }
    39 
    52 
    40 static void
    53 static void
    41 release_table_data (void *user_data)
    54 release_table_data (void *user_data)
    42 {
    55 {
    43   CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
    56   CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
    48 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
    61 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
    49 {
    62 {
    50   CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
    63   CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
    51   CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
    64   CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
    52   if (unlikely (!cf_data))
    65   if (unlikely (!cf_data))
    53     return NULL;
    66     return nullptr;
    54 
    67 
    55   const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
    68   const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
    56   const size_t length = CFDataGetLength (cf_data);
    69   const size_t length = CFDataGetLength (cf_data);
    57   if (!data || !length)
    70   if (!data || !length)
    58     return NULL;
    71     return nullptr;
    59 
    72 
    60   return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
    73   return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
    61                          reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
    74                          reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
    62                          release_table_data);
    75                          release_table_data);
    63 }
    76 }
    64 
    77 
       
    78 static void
       
    79 _hb_cg_font_release (void *data)
       
    80 {
       
    81   CGFontRelease ((CGFontRef) data);
       
    82 }
       
    83 
    65 hb_face_t *
    84 hb_face_t *
    66 hb_coretext_face_create (CGFontRef cg_font)
    85 hb_coretext_face_create (CGFontRef cg_font)
    67 {
    86 {
    68   return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease);
    87   return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
    69 }
    88 }
    70 
    89 
    71 
    90 HB_SHAPER_DATA_ENSURE_DEFINE(coretext, face)
    72 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
    91 HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(coretext, font,
    73 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
    92         fabs (CTFontGetSize((CTFontRef) data) - coretext_font_size (font->ptem)) <= .5
    74 
    93 )
    75 
    94 
    76 /*
    95 /*
    77  * shaper face data
    96  * shaper face data
    78  */
    97  */
    79 
    98 
   102 
   121 
   103 static void
   122 static void
   104 release_data (void *info, const void *data, size_t size)
   123 release_data (void *info, const void *data, size_t size)
   105 {
   124 {
   106   assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
   125   assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
   107           hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
   126           hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
   108 
   127 
   109   hb_blob_destroy ((hb_blob_t *) info);
   128   hb_blob_destroy ((hb_blob_t *) info);
   110 }
   129 }
   111 
   130 
   112 static CGFontRef
   131 static CGFontRef
   113 create_cg_font (hb_face_t *face)
   132 create_cg_font (hb_face_t *face)
   114 {
   133 {
   115   CGFontRef cg_font = NULL;
   134   CGFontRef cg_font = nullptr;
   116   if (face->destroy == (hb_destroy_func_t) CGFontRelease)
   135   if (face->destroy == _hb_cg_font_release)
   117   {
   136   {
   118     cg_font = CGFontRetain ((CGFontRef) face->user_data);
   137     cg_font = CGFontRetain ((CGFontRef) face->user_data);
   119   }
   138   }
   120   else
   139   else
   121   {
   140   {
   138 }
   157 }
   139 
   158 
   140 static CTFontRef
   159 static CTFontRef
   141 create_ct_font (CGFontRef cg_font, CGFloat font_size)
   160 create_ct_font (CGFontRef cg_font, CGFloat font_size)
   142 {
   161 {
   143   CTFontRef ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, NULL, NULL);
   162   CTFontRef ct_font = nullptr;
       
   163 
       
   164   /* CoreText does not enable trak table usage / tracking when creating a CTFont
       
   165    * using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
       
   166    * to be through the CTFontCreateUIFontForLanguage call. */
       
   167   CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
       
   168   if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
       
   169       CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
       
   170   {
       
   171     CTFontUIFontType font_type = kCTFontUIFontSystem;
       
   172     if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
       
   173       font_type = kCTFontUIFontEmphasizedSystem;
       
   174 
       
   175     ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
       
   176     CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
       
   177     if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
       
   178     {
       
   179       CFRelease(ct_font);
       
   180       ct_font = nullptr;
       
   181     }
       
   182     CFRelease (ct_result_name);
       
   183   }
       
   184   CFRelease (cg_postscript_name);
       
   185 
       
   186   if (!ct_font)
       
   187     ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
       
   188 
   144   if (unlikely (!ct_font)) {
   189   if (unlikely (!ct_font)) {
   145     DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
   190     DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
   146     return NULL;
   191     return nullptr;
   147   }
   192   }
   148 
   193 
   149   /* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
   194   /* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
   150    * bug indicate that the cascade list reconfiguration occasionally causes
   195    * bug indicate that the cascade list reconfiguration occasionally causes
   151    * crashes in CoreText on OS X 10.9, thus let's skip this step on older
   196    * crashes in CoreText on OS X 10.9, thus let's skip this step on older
   152    * operating system versions. Except for the emoji font, where _not_
   197    * operating system versions. Except for the emoji font, where _not_
   153    * reconfiguring the cascade list causes CoreText crashes. For details, see
   198    * reconfiguring the cascade list causes CoreText crashes. For details, see
   154    * crbug.com/549610 */
   199    * crbug.com/549610 */
   155   // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
   200   // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
   156   if (&CTGetCoreTextVersion != NULL && CTGetCoreTextVersion() < 0x00070000) {
   201   if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
   157     CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
   202     CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
   158     bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
   203     bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
   159     CFRelease (fontName);
   204     CFRelease (fontName);
   160     if (!isEmojiFont)
   205     if (!isEmojiFont)
   161       return ct_font;
   206       return ct_font;
   165 
   210 
   166   /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
   211   /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
   167    * font fallback which we don't need anyway. */
   212    * font fallback which we don't need anyway. */
   168   {
   213   {
   169     CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
   214     CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
   170     CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, NULL, last_resort_font_desc);
   215     CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
   171     CFRelease (last_resort_font_desc);
   216     CFRelease (last_resort_font_desc);
   172     if (new_ct_font)
   217     if (new_ct_font)
   173     {
   218     {
   174       /* The CTFontCreateCopyWithAttributes call fails to stay on the same font
   219       /* The CTFontCreateCopyWithAttributes call fails to stay on the same font
   175        * when reconfiguring the cascade list and may switch to a different font
   220        * when reconfiguring the cascade list and may switch to a different font
   200   if (original_url)
   245   if (original_url)
   201     CFRelease (original_url);
   246     CFRelease (original_url);
   202   return ct_font;
   247   return ct_font;
   203 }
   248 }
   204 
   249 
   205 struct hb_coretext_shaper_face_data_t {
       
   206   CGFontRef cg_font;
       
   207   CTFontRef ct_font;
       
   208 };
       
   209 
       
   210 hb_coretext_shaper_face_data_t *
   250 hb_coretext_shaper_face_data_t *
   211 _hb_coretext_shaper_face_data_create (hb_face_t *face)
   251 _hb_coretext_shaper_face_data_create (hb_face_t *face)
   212 {
   252 {
   213   hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
   253   CGFontRef cg_font = create_cg_font (face);
   214   if (unlikely (!data))
   254 
   215     return NULL;
   255   if (unlikely (!cg_font))
   216 
       
   217   data->cg_font = create_cg_font (face);
       
   218   if (unlikely (!data->cg_font))
       
   219   {
   256   {
   220     DEBUG_MSG (CORETEXT, face, "CGFont creation failed..");
   257     DEBUG_MSG (CORETEXT, face, "CGFont creation failed..");
   221     free (data);
   258     return nullptr;
   222     return NULL;
   259   }
   223   }
   260 
   224 
   261   return (hb_coretext_shaper_face_data_t *) cg_font;
   225   /* We use 36pt size instead of UPEM, because CoreText implements the 'trak' table,
       
   226    * which can make the font too tight at large sizes.  36pt should be a good semi-neutral
       
   227    * size.
       
   228    *
       
   229    * Since we always create CTFont at a fixed size, our CTFont lives in face_data
       
   230    * instead of font_data.  Which is good, because when people change scale on
       
   231    * hb_font_t, we won't need to update our CTFont. */
       
   232   data->ct_font = create_ct_font (data->cg_font, 36.);
       
   233   if (unlikely (!data->ct_font))
       
   234   {
       
   235     DEBUG_MSG (CORETEXT, face, "CTFont creation failed.");
       
   236     CFRelease (data->cg_font);
       
   237     free (data);
       
   238     return NULL;
       
   239   }
       
   240 
       
   241   return data;
       
   242 }
   262 }
   243 
   263 
   244 void
   264 void
   245 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
   265 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
   246 {
   266 {
   247   CFRelease (data->ct_font);
   267   CFRelease ((CGFontRef) data);
   248   CFRelease (data->cg_font);
       
   249   free (data);
       
   250 }
   268 }
   251 
   269 
   252 /*
   270 /*
   253  * Since: 0.9.10
   271  * Since: 0.9.10
   254  */
   272  */
   255 CGFontRef
   273 CGFontRef
   256 hb_coretext_face_get_cg_font (hb_face_t *face)
   274 hb_coretext_face_get_cg_font (hb_face_t *face)
   257 {
   275 {
   258   if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
   276   if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
   259   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
   277   return (CGFontRef) HB_SHAPER_DATA_GET (face);
   260   return face_data->cg_font;
       
   261 }
   278 }
   262 
   279 
   263 
   280 
   264 /*
   281 /*
   265  * shaper font data
   282  * shaper font data
   266  */
   283  */
   267 
   284 
   268 struct hb_coretext_shaper_font_data_t {};
       
   269 
       
   270 hb_coretext_shaper_font_data_t *
   285 hb_coretext_shaper_font_data_t *
   271 _hb_coretext_shaper_font_data_create (hb_font_t *font HB_UNUSED)
   286 _hb_coretext_shaper_font_data_create (hb_font_t *font)
   272 {
   287 {
   273   return (hb_coretext_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
   288   hb_face_t *face = font->face;
       
   289   if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
       
   290   CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
       
   291 
       
   292   CTFontRef ct_font = create_ct_font (cg_font, coretext_font_size (font->ptem));
       
   293 
       
   294   if (unlikely (!ct_font))
       
   295   {
       
   296     DEBUG_MSG (CORETEXT, font, "CGFont creation failed..");
       
   297     return nullptr;
       
   298   }
       
   299 
       
   300   return (hb_coretext_shaper_font_data_t *) ct_font;
   274 }
   301 }
   275 
   302 
   276 void
   303 void
   277 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
   304 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
   278 {
   305 {
       
   306   CFRelease ((CTFontRef) data);
   279 }
   307 }
   280 
   308 
   281 
   309 
   282 /*
   310 /*
   283  * shaper shape_plan data
   311  * shaper shape_plan data
   301 }
   329 }
   302 
   330 
   303 CTFontRef
   331 CTFontRef
   304 hb_coretext_font_get_ct_font (hb_font_t *font)
   332 hb_coretext_font_get_ct_font (hb_font_t *font)
   305 {
   333 {
   306   hb_face_t *face = font->face;
   334   if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return nullptr;
   307   if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
   335   return (CTFontRef)HB_SHAPER_DATA_GET (font);
   308   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
       
   309   return face_data->ct_font;
       
   310 }
   336 }
   311 
   337 
   312 
   338 
   313 /*
   339 /*
   314  * shaper
   340  * shaper
   321 
   347 
   322 struct active_feature_t {
   348 struct active_feature_t {
   323   feature_record_t rec;
   349   feature_record_t rec;
   324   unsigned int order;
   350   unsigned int order;
   325 
   351 
   326   static int cmp (const active_feature_t *a, const active_feature_t *b) {
   352   static int cmp (const void *pa, const void *pb) {
       
   353     const active_feature_t *a = (const active_feature_t *) pa;
       
   354     const active_feature_t *b = (const active_feature_t *) pb;
   327     return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
   355     return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
   328            a->order < b->order ? -1 : a->order > b->order ? 1 :
   356            a->order < b->order ? -1 : a->order > b->order ? 1 :
   329            a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
   357            a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
   330            0;
   358            0;
   331   }
   359   }
   337 struct feature_event_t {
   365 struct feature_event_t {
   338   unsigned int index;
   366   unsigned int index;
   339   bool start;
   367   bool start;
   340   active_feature_t feature;
   368   active_feature_t feature;
   341 
   369 
   342   static int cmp (const feature_event_t *a, const feature_event_t *b) {
   370   static int cmp (const void *pa, const void *pb) {
       
   371     const feature_event_t *a = (const feature_event_t *) pa;
       
   372     const feature_event_t *b = (const feature_event_t *) pb;
   343     return a->index < b->index ? -1 : a->index > b->index ? 1 :
   373     return a->index < b->index ? -1 : a->index > b->index ? 1 :
   344            a->start < b->start ? -1 : a->start > b->start ? 1 :
   374            a->start < b->start ? -1 : a->start > b->start ? 1 :
   345            active_feature_t::cmp (&a->feature, &b->feature);
   375            active_feature_t::cmp (&a->feature, &b->feature);
   346   }
   376   }
   347 };
   377 };
   536                     hb_buffer_t        *buffer,
   566                     hb_buffer_t        *buffer,
   537                     const hb_feature_t *features,
   567                     const hb_feature_t *features,
   538                     unsigned int        num_features)
   568                     unsigned int        num_features)
   539 {
   569 {
   540   hb_face_t *face = font->face;
   570   hb_face_t *face = font->face;
   541   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
   571   CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
   542 
   572   CTFontRef ct_font = (CTFontRef) HB_SHAPER_DATA_GET (font);
   543   CGFloat ct_font_size = CTFontGetSize (face_data->ct_font);
   573 
       
   574   CGFloat ct_font_size = CTFontGetSize (ct_font);
   544   CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
   575   CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
   545   CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
   576   CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
   546 
   577 
   547   /* Attach marks to their bases, to match the 'ot' shaper.
   578   /* Attach marks to their bases, to match the 'ot' shaper.
   548    * Adapted from hb-ot-shape:hb_form_clusters().
   579    * Adapted from hb-ot-shape:hb_form_clusters().
   639 
   670 
   640           /* TODO sort and resolve conflicting features? */
   671           /* TODO sort and resolve conflicting features? */
   641           /* active_features.qsort (); */
   672           /* active_features.qsort (); */
   642           for (unsigned int j = 0; j < active_features.len; j++)
   673           for (unsigned int j = 0; j < active_features.len; j++)
   643           {
   674           {
   644             CFStringRef keys[2] = {
   675             CFStringRef keys[] = {
   645               kCTFontFeatureTypeIdentifierKey,
   676               kCTFontFeatureTypeIdentifierKey,
   646               kCTFontFeatureSelectorIdentifierKey
   677               kCTFontFeatureSelectorIdentifierKey
   647             };
   678             };
   648             CFNumberRef values[2] = {
   679             CFNumberRef values[] = {
   649               CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
   680               CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
   650               CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
   681               CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
   651             };
   682             };
       
   683             static_assert ((ARRAY_LENGTH_CONST (keys) == ARRAY_LENGTH_CONST (values)), "");
   652             CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
   684             CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
   653                                                        (const void **) keys,
   685                                                        (const void **) keys,
   654                                                        (const void **) values,
   686                                                        (const void **) values,
   655                                                        2,
   687                                                        ARRAY_LENGTH (keys),
   656                                                        &kCFTypeDictionaryKeyCallBacks,
   688                                                        &kCFTypeDictionaryKeyCallBacks,
   657                                                        &kCFTypeDictionaryValueCallBacks);
   689                                                        &kCFTypeDictionaryValueCallBacks);
   658             CFRelease (values[0]);
   690             for (unsigned int i = 0; i < ARRAY_LENGTH (values); i++)
   659             CFRelease (values[1]);
   691               CFRelease (values[i]);
   660 
   692 
   661             CFArrayAppendValue (features_array, dict);
   693             CFArrayAppendValue (features_array, dict);
   662             CFRelease (dict);
   694             CFRelease (dict);
   663 
   695 
   664           }
   696           }
   672           CFRelease (features_array);
   704           CFRelease (features_array);
   673 
   705 
   674           CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
   706           CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
   675           CFRelease (attributes);
   707           CFRelease (attributes);
   676 
   708 
   677           range->font = CTFontCreateCopyWithAttributes (face_data->ct_font, 0.0, NULL, font_desc);
   709           range->font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, font_desc);
   678           CFRelease (font_desc);
   710           CFRelease (font_desc);
   679         }
   711         }
   680         else
   712         else
   681         {
   713         {
   682           range->font = NULL;
   714           range->font = nullptr;
   683         }
   715         }
   684 
   716 
   685         range->index_first = last_index;
   717         range->index_first = last_index;
   686         range->index_last  = event->index - 1;
   718         range->index_last  = event->index - 1;
   687 
   719 
   697         active_feature_t *feature = active_features.find (&event->feature);
   729         active_feature_t *feature = active_features.find (&event->feature);
   698         if (feature)
   730         if (feature)
   699           active_features.remove (feature - active_features.array);
   731           active_features.remove (feature - active_features.array);
   700       }
   732       }
   701     }
   733     }
   702 
       
   703     if (!range_records.len) /* No active feature found. */
       
   704       goto fail_features;
       
   705   }
   734   }
   706   else
   735   else
   707   {
   736   {
   708   fail_features:
   737   fail_features:
   709     num_features = 0;
   738     num_features = 0;
   750       log_clusters[chars_len++] = cluster; /* Surrogates. */
   779       log_clusters[chars_len++] = cluster; /* Surrogates. */
   751   }
   780   }
   752 
   781 
   753 #define FAIL(...) \
   782 #define FAIL(...) \
   754   HB_STMT_START { \
   783   HB_STMT_START { \
   755     DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
   784     DEBUG_MSG (CORETEXT, nullptr, __VA_ARGS__); \
   756     ret = false; \
   785     ret = false; \
   757     goto fail; \
   786     goto fail; \
   758   } HB_STMT_END;
   787   } HB_STMT_END;
   759 
   788 
   760   bool ret = true;
   789   bool ret = true;
   761   CFStringRef string_ref = NULL;
   790   CFStringRef string_ref = nullptr;
   762   CTLineRef line = NULL;
   791   CTLineRef line = nullptr;
   763 
   792 
   764   if (0)
   793   if (0)
   765   {
   794   {
   766 resize_and_retry:
   795 resize_and_retry:
   767     DEBUG_MSG (CORETEXT, buffer, "Buffer resize");
   796     DEBUG_MSG (CORETEXT, buffer, "Buffer resize");
   769      * string_ref (via attr_string).  We must release those before resizing buffer. */
   798      * string_ref (via attr_string).  We must release those before resizing buffer. */
   770     assert (string_ref);
   799     assert (string_ref);
   771     assert (line);
   800     assert (line);
   772     CFRelease (string_ref);
   801     CFRelease (string_ref);
   773     CFRelease (line);
   802     CFRelease (line);
   774     string_ref = NULL;
   803     string_ref = nullptr;
   775     line = NULL;
   804     line = nullptr;
   776 
   805 
   777     /* Get previous start-of-scratch-area, that we use later for readjusting
   806     /* Get previous start-of-scratch-area, that we use later for readjusting
   778      * our existing scratch arrays. */
   807      * our existing scratch arrays. */
   779     unsigned int old_scratch_used;
   808     unsigned int old_scratch_used;
   780     hb_buffer_t::scratch_buffer_t *old_scratch;
   809     hb_buffer_t::scratch_buffer_t *old_scratch;
   791     log_clusters = reinterpret_cast<unsigned int *> (((char *) scratch + ((char *) log_clusters - (char *) old_scratch)));
   820     log_clusters = reinterpret_cast<unsigned int *> (((char *) scratch + ((char *) log_clusters - (char *) old_scratch)));
   792     scratch += old_scratch_used;
   821     scratch += old_scratch_used;
   793     scratch_size -= old_scratch_used;
   822     scratch_size -= old_scratch_used;
   794   }
   823   }
   795   {
   824   {
   796     string_ref = CFStringCreateWithCharactersNoCopy (NULL,
   825     string_ref = CFStringCreateWithCharactersNoCopy (nullptr,
   797                                                      pchars, chars_len,
   826                                                      pchars, chars_len,
   798                                                      kCFAllocatorNull);
   827                                                      kCFAllocatorNull);
   799     if (unlikely (!string_ref))
   828     if (unlikely (!string_ref))
   800       FAIL ("CFStringCreateWithCharactersNoCopy failed");
   829       FAIL ("CFStringCreateWithCharactersNoCopy failed");
   801 
   830 
   829         CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
   858         CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
   830                                         kCTLanguageAttributeName, lang);
   859                                         kCTLanguageAttributeName, lang);
   831         CFRelease (lang);
   860         CFRelease (lang);
   832       }
   861       }
   833       CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
   862       CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
   834                                       kCTFontAttributeName, face_data->ct_font);
   863                                       kCTFontAttributeName, ct_font);
   835 
   864 
   836       if (num_features)
   865       if (num_features && range_records.len)
   837       {
   866       {
   838         unsigned int start = 0;
   867         unsigned int start = 0;
   839         range_record_t *last_range = &range_records[0];
   868         range_record_t *last_range = &range_records[0];
   840         for (unsigned int k = 0; k < chars_len; k++)
   869         for (unsigned int k = 0; k < chars_len; k++)
   841         {
   870         {
   857         }
   886         }
   858         if (start != chars_len && last_range->font)
   887         if (start != chars_len && last_range->font)
   859           CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start),
   888           CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start),
   860                                           kCTFontAttributeName, last_range->font);
   889                                           kCTFontAttributeName, last_range->font);
   861       }
   890       }
       
   891       /* Enable/disable kern if requested.
       
   892        *
       
   893        * Note: once kern is disabled, reenabling it doesn't currently seem to work in CoreText.
       
   894        */
       
   895       if (num_features)
       
   896       {
       
   897         unsigned int zeroint = 0;
       
   898         CFNumberRef zero = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &zeroint);
       
   899         for (unsigned int i = 0; i < num_features; i++)
       
   900         {
       
   901           const hb_feature_t &feature = features[i];
       
   902           if (feature.tag == HB_TAG('k','e','r','n') &&
       
   903               feature.start < chars_len && feature.start < feature.end)
       
   904           {
       
   905             CFRange feature_range = CFRangeMake (feature.start,
       
   906                                                  MIN (feature.end, chars_len) - feature.start);
       
   907             if (feature.value)
       
   908               CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName);
       
   909             else
       
   910               CFAttributedStringSetAttribute (attr_string, feature_range, kCTKernAttributeName, zero);
       
   911           }
       
   912         }
       
   913         CFRelease (zero);
       
   914       }
   862 
   915 
   863       int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
   916       int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
   864       CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
   917       CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
   865       CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
   918       CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
   866                                                     (const void **) &kCTTypesetterOptionForcedEmbeddingLevel,
   919                                                     (const void **) &kCTTypesetterOptionForcedEmbeddingLevel,
   867                                                     (const void **) &level_number,
   920                                                     (const void **) &level_number,
   868                                                     1,
   921                                                     1,
   869                                                     &kCFTypeDictionaryKeyCallBacks,
   922                                                     &kCFTypeDictionaryKeyCallBacks,
   870                                                     &kCFTypeDictionaryValueCallBacks);
   923                                                     &kCFTypeDictionaryValueCallBacks);
       
   924       CFRelease (level_number);
   871       if (unlikely (!options))
   925       if (unlikely (!options))
   872         FAIL ("CFDictionaryCreate failed");
   926         FAIL ("CFDictionaryCreate failed");
   873 
   927 
   874       CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options);
   928       CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options);
   875       CFRelease (options);
   929       CFRelease (options);
   883         FAIL ("CTTypesetterCreateLine failed");
   937         FAIL ("CTTypesetterCreateLine failed");
   884     }
   938     }
   885 
   939 
   886     CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
   940     CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
   887     unsigned int num_runs = CFArrayGetCount (glyph_runs);
   941     unsigned int num_runs = CFArrayGetCount (glyph_runs);
   888     DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs);
   942     DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
   889 
   943 
   890     buffer->len = 0;
   944     buffer->len = 0;
   891     uint32_t status_and = ~0, status_or = 0;
   945     uint32_t status_and = ~0, status_or = 0;
   892     double advances_so_far = 0;
   946     double advances_so_far = 0;
   893     /* For right-to-left runs, CoreText returns the glyphs positioned such that
   947     /* For right-to-left runs, CoreText returns the glyphs positioned such that
   909       CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i));
   963       CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i));
   910       CTRunStatus run_status = CTRunGetStatus (run);
   964       CTRunStatus run_status = CTRunGetStatus (run);
   911       status_or  |= run_status;
   965       status_or  |= run_status;
   912       status_and &= run_status;
   966       status_and &= run_status;
   913       DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
   967       DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
   914       double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
   968       double run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
   915       if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
   969       if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
   916           run_advance = -run_advance;
   970           run_advance = -run_advance;
   917       DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
   971       DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
   918 
   972 
   919       /* CoreText does automatic font fallback (AKA "cascading") for  characters
   973       /* CoreText does automatic font fallback (AKA "cascading") for  characters
   922        * one and fill in the buffer with .notdef glyphs instead of random glyph
   976        * one and fill in the buffer with .notdef glyphs instead of random glyph
   923        * indices from a different font.
   977        * indices from a different font.
   924        */
   978        */
   925       CFDictionaryRef attributes = CTRunGetAttributes (run);
   979       CFDictionaryRef attributes = CTRunGetAttributes (run);
   926       CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
   980       CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
   927       if (!CFEqual (run_ct_font, face_data->ct_font))
   981       if (!CFEqual (run_ct_font, ct_font))
   928       {
   982       {
   929         /* The run doesn't use our main font instance.  We have to figure out
   983         /* The run doesn't use our main font instance.  We have to figure out
   930          * whether font fallback happened, or this is just CoreText giving us
   984          * whether font fallback happened, or this is just CoreText giving us
   931          * another CTFont using the same underlying CGFont.  CoreText seems
   985          * another CTFont using the same underlying CGFont.  CoreText seems
   932          * to do that in a variety of situations, one of which being vertical
   986          * to do that in a variety of situations, one of which being vertical
   960         if (!matched)
  1014         if (!matched)
   961         {
  1015         {
   962           CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
  1016           CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
   963           if (run_cg_font)
  1017           if (run_cg_font)
   964           {
  1018           {
   965             matched = CFEqual (run_cg_font, face_data->cg_font);
  1019             matched = CFEqual (run_cg_font, cg_font);
   966             CFRelease (run_cg_font);
  1020             CFRelease (run_cg_font);
   967           }
  1021           }
   968         }
  1022         }
   969         if (!matched)
  1023         if (!matched)
   970         {
  1024         {
   971           CFStringRef font_ps_name = CTFontCopyName (face_data->ct_font, kCTFontPostScriptNameKey);
  1025           CFStringRef font_ps_name = CTFontCopyName (ct_font, kCTFontPostScriptNameKey);
   972           CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
  1026           CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
   973           CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
  1027           CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
   974           CFRelease (run_ps_name);
  1028           CFRelease (run_ps_name);
   975           CFRelease (font_ps_name);
  1029           CFRelease (font_ps_name);
   976           if (result == kCFCompareEqualTo)
  1030           if (result == kCFCompareEqualTo)
  1035 
  1089 
  1036       hb_glyph_info_t *run_info = buffer->info + buffer->len;
  1090       hb_glyph_info_t *run_info = buffer->info + buffer->len;
  1037 
  1091 
  1038       /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always
  1092       /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always
  1039        * succeed, and so copying data to our own buffer will be rare.  Reports
  1093        * succeed, and so copying data to our own buffer will be rare.  Reports
  1040        * have it that this changed in OS X 10.10 Yosemite, and NULL is returned
  1094        * have it that this changed in OS X 10.10 Yosemite, and nullptr is returned
  1041        * frequently.  At any rate, we can test that codepath by setting USE_PTR
  1095        * frequently.  At any rate, we can test that codepath by setting USE_PTR
  1042        * to false. */
  1096        * to false. */
  1043 
  1097 
  1044 #define USE_PTR true
  1098 #define USE_PTR true
  1045 
  1099 
  1051   scratch_size = scratch_size_saved; \
  1105   scratch_size = scratch_size_saved; \
  1052   scratch = scratch_saved;
  1106   scratch = scratch_saved;
  1053 
  1107 
  1054       { /* Setup glyphs */
  1108       { /* Setup glyphs */
  1055         SCRATCH_SAVE();
  1109         SCRATCH_SAVE();
  1056         const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL;
  1110         const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : nullptr;
  1057         if (!glyphs) {
  1111         if (!glyphs) {
  1058           ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry);
  1112           ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry);
  1059           CTRunGetGlyphs (run, range_all, glyph_buf);
  1113           CTRunGetGlyphs (run, range_all, glyph_buf);
  1060           glyphs = glyph_buf;
  1114           glyphs = glyph_buf;
  1061         }
  1115         }
  1062         const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : NULL;
  1116         const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : nullptr;
  1063         if (!string_indices) {
  1117         if (!string_indices) {
  1064           ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry);
  1118           ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry);
  1065           CTRunGetStringIndices (run, range_all, index_buf);
  1119           CTRunGetStringIndices (run, range_all, index_buf);
  1066           string_indices = index_buf;
  1120           string_indices = index_buf;
  1067         }
  1121         }
  1079          * Note that CoreText does not return advances for glyphs.  As such,
  1133          * Note that CoreText does not return advances for glyphs.  As such,
  1080          * for all but last glyph, we use the delta position to next glyph as
  1134          * for all but last glyph, we use the delta position to next glyph as
  1081          * advance (in the advance direction only), and for last glyph we set
  1135          * advance (in the advance direction only), and for last glyph we set
  1082          * whatever is needed to make the whole run's advance add up. */
  1136          * whatever is needed to make the whole run's advance add up. */
  1083         SCRATCH_SAVE();
  1137         SCRATCH_SAVE();
  1084         const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL;
  1138         const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : nullptr;
  1085         if (!positions) {
  1139         if (!positions) {
  1086           ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry);
  1140           ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry);
  1087           CTRunGetPositions (run, range_all, position_buf);
  1141           CTRunGetPositions (run, range_all, position_buf);
  1088           positions = position_buf;
  1142           positions = position_buf;
  1089         }
  1143         }
  1155       for (unsigned int i = 0; i < count; i++)
  1209       for (unsigned int i = 0; i < count; i++)
  1156       {
  1210       {
  1157         pos->x_advance = info->mask;
  1211         pos->x_advance = info->mask;
  1158         pos->x_offset = info->var1.i32;
  1212         pos->x_offset = info->var1.i32;
  1159         pos->y_offset = info->var2.i32;
  1213         pos->y_offset = info->var2.i32;
       
  1214 
       
  1215         info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
       
  1216 
  1160         info++, pos++;
  1217         info++, pos++;
  1161       }
  1218       }
  1162     else
  1219     else
  1163       for (unsigned int i = 0; i < count; i++)
  1220       for (unsigned int i = 0; i < count; i++)
  1164       {
  1221       {
  1165         pos->y_advance = info->mask;
  1222         pos->y_advance = info->mask;
  1166         pos->x_offset = info->var1.i32;
  1223         pos->x_offset = info->var1.i32;
  1167         pos->y_offset = info->var2.i32;
  1224         pos->y_offset = info->var2.i32;
       
  1225 
       
  1226         info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
       
  1227 
  1168         info++, pos++;
  1228         info++, pos++;
  1169       }
  1229       }
  1170 
  1230 
  1171     /* Fix up clusters so that we never return out-of-order indices;
  1231     /* Fix up clusters so that we never return out-of-order indices;
  1172      * if core text has reordered glyphs, we'll merge them to the
  1232      * if core text has reordered glyphs, we'll merge them to the
  1200         }
  1260         }
  1201       }
  1261       }
  1202     }
  1262     }
  1203   }
  1263   }
  1204 
  1264 
       
  1265   buffer->unsafe_to_break_all ();
       
  1266 
  1205 #undef FAIL
  1267 #undef FAIL
  1206 
  1268 
  1207 fail:
  1269 fail:
  1208   if (string_ref)
  1270   if (string_ref)
  1209     CFRelease (string_ref);
  1271     CFRelease (string_ref);
  1220 
  1282 
  1221 /*
  1283 /*
  1222  * AAT shaper
  1284  * AAT shaper
  1223  */
  1285  */
  1224 
  1286 
       
  1287 HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, face)
       
  1288 HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, font)
       
  1289 
  1225 /*
  1290 /*
  1226  * shaper face data
  1291  * shaper face data
  1227  */
  1292  */
  1228 
  1293 
  1229 struct hb_coretext_aat_shaper_face_data_t {};
  1294 struct hb_coretext_aat_shaper_face_data_t {};
  1230 
  1295 
  1231 hb_coretext_aat_shaper_face_data_t *
  1296 hb_coretext_aat_shaper_face_data_t *
  1232 _hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
  1297 _hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
  1233 {
  1298 {
  1234   hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT);
  1299   static const hb_tag_t tags[] = {HB_CORETEXT_TAG_MORX, HB_CORETEXT_TAG_MORT, HB_CORETEXT_TAG_KERX};
  1235   /* Umm, we just reference the table to check whether it exists.
  1300 
  1236    * Maybe add better API for this? */
  1301   for (unsigned int i = 0; i < ARRAY_LENGTH (tags); i++)
  1237   if (!hb_blob_get_length (mort_blob))
       
  1238   {
  1302   {
  1239     hb_blob_destroy (mort_blob);
  1303     hb_blob_t *blob = face->reference_table (tags[i]);
  1240     mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX);
  1304     if (hb_blob_get_length (blob))
  1241     if (!hb_blob_get_length (mort_blob))
       
  1242     {
  1305     {
  1243       hb_blob_destroy (mort_blob);
  1306       hb_blob_destroy (blob);
  1244       return NULL;
  1307       return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
  1245     }
  1308     }
  1246   }
  1309     hb_blob_destroy (blob);
  1247   hb_blob_destroy (mort_blob);
  1310   }
  1248 
  1311 
  1249   return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
  1312   return nullptr;
  1250 }
  1313 }
  1251 
  1314 
  1252 void
  1315 void
  1253 _hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
  1316 _hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
  1254 {
  1317 {
  1262 struct hb_coretext_aat_shaper_font_data_t {};
  1325 struct hb_coretext_aat_shaper_font_data_t {};
  1263 
  1326 
  1264 hb_coretext_aat_shaper_font_data_t *
  1327 hb_coretext_aat_shaper_font_data_t *
  1265 _hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
  1328 _hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
  1266 {
  1329 {
  1267   return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
  1330   return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
  1268 }
  1331 }
  1269 
  1332 
  1270 void
  1333 void
  1271 _hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
  1334 _hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
  1272 {
  1335 {